diff --git a/Cargo.lock b/Cargo.lock index 8eae47e..5bcb580 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7,8 +7,17 @@ name = "ctor" version = "0.2.9" dependencies = [ "libc-print", - "quote 1.0.36", - "syn 2.0.59", +] + +[[package]] +name = "ctor-codegen" +version = "0.1.0" +dependencies = [ + "libc-print", + "paste", + "proc-macro2 1.0.89", + "quote 1.0.37", + "syn 2.0.87", ] [[package]] @@ -59,6 +68,12 @@ dependencies = [ "libc", ] +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + [[package]] name = "proc-macro2" version = "0.4.30" @@ -70,9 +85,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.80" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a56dea16b0a29e94408b9aa5e2940a4eedbd128a1ba20e8f7ae60fd3d465af0e" +checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" dependencies = [ "unicode-ident", ] @@ -88,11 +103,11 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.36" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ - "proc-macro2 1.0.80", + "proc-macro2 1.0.89", ] [[package]] @@ -108,12 +123,12 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.59" +version = "2.0.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a6531ffc7b071655e4ce2e04bd464c4830bb585a61cabb96cf808f05172615a" +checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d" dependencies = [ - "proc-macro2 1.0.80", - "quote 1.0.36", + "proc-macro2 1.0.89", + "quote 1.0.37", "unicode-ident", ] @@ -129,9 +144,9 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.12" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" [[package]] name = "unicode-xid" diff --git a/Cargo.toml b/Cargo.toml index 0da24f2..29c782b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,2 +1,2 @@ [workspace] -members = [ "ctor", "dtor", "tests" ] +members = [ "ctor", "codegen", "dtor", "tests" ] diff --git a/README.md b/README.md index c2d34cb..eb83942 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,10 @@ Module initialization/teardown functions for Rust (like `__attribute__((construc This library currently requires **Rust > 1.31.0** at a minimum for the procedural macro support. -Idea inspired by [this code](https://github.com/neon-bindings/neon/blob/2277e943a619579c144c1da543874f4a7ec39879/src/lib.rs#L42) in the Neon project. +## Zero Dependency + +As of `ctor 0.3.0+`, `ctor` has no dependencies. The proc macro in this crate +inlines a helper declarative macro that does the majority of the work. ## Support @@ -108,3 +111,7 @@ The `#[dtor]` macro effectively creates a constructor that calls `libc::atexit` libc::atexit(dtor); } ``` + +## Inspiration + +Idea inspired by [this code](https://github.com/neon-bindings/neon/blob/2277e943a619579c144c1da543874f4a7ec39879/src/lib.rs#L42) in the Neon project. diff --git a/codegen/Cargo.toml b/codegen/Cargo.toml new file mode 100644 index 0000000..bb4e761 --- /dev/null +++ b/codegen/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "ctor-codegen" +version = "0.1.0" +authors = ["Matt Mastracci "] +edition = "2018" +publish = false + +[dependencies] +libc-print = "0.1.20" +syn = "2" +quote = "1" +proc-macro2 = "1" +paste = "1" diff --git a/codegen/README.md b/codegen/README.md new file mode 100644 index 0000000..55cb3cc --- /dev/null +++ b/codegen/README.md @@ -0,0 +1,4 @@ +# ctor codegen + +This project does the codegen to ensure that ctor builds without dependencies. We use +the `quote!` macro to generate a `TokenStream`, and then dump that into a source file. diff --git a/codegen/src/macros.rs b/codegen/src/macros.rs new file mode 100644 index 0000000..596655f --- /dev/null +++ b/codegen/src/macros.rs @@ -0,0 +1,190 @@ +crate::declare_macro!( + macro_rules! ctor_raw { + ($used:meta $($block:tt)+) => { + #[cfg(not(any( + target_os = "linux", + target_os = "android", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd", + target_os = "dragonfly", + target_os = "illumos", + target_os = "haiku", + target_vendor = "apple", + windows)))] + compile_error!("#[ctor] is not supported on the current target"); + + #[$used] + #[cfg_attr(any(target_os = "linux", target_os = "android"), link_section = ".init_array")] + #[cfg_attr(target_os = "freebsd", link_section = ".init_array")] + #[cfg_attr(target_os = "netbsd", link_section = ".init_array")] + #[cfg_attr(target_os = "openbsd", link_section = ".init_array")] + #[cfg_attr(target_os = "dragonfly", link_section = ".init_array")] + #[cfg_attr(target_os = "illumos", link_section = ".init_array")] + #[cfg_attr(target_os = "haiku", link_section = ".init_array")] + #[cfg_attr(target_vendor = "apple", link_section = "__DATA,__mod_init_func")] + #[cfg_attr(windows, link_section = ".CRT$XCU")] + $($block)+ + } + } +); + +crate::declare_macro!( + macro_rules! ctor_impl { + ( + fn + macros=$macros:ident + name=$name:ident + used=$used:meta + $(extra={ $($extra:item)+ })? + item={ + $( + #[$meta:meta] + )* + $vis:vis $(unsafe)? fn $ident:ident () $(-> $ret:ty)? $block:block + } + ) => { + $(#[$meta])* + #[allow(unused)] + $vis unsafe extern "C" fn $ident() $block + + #[doc(hidden)] + #[allow(unused, non_snake_case)] + mod $name { + super::$macros::ctor_raw!($used + #[allow(non_upper_case_globals, non_snake_case)] + #[doc(hidden)] + static $name: unsafe extern "C" fn() -> usize = + { + #[allow(non_snake_case)] + #[cfg_attr(any(target_os = "linux", target_os = "android"), link_section = ".text.startup")] + unsafe extern "C" fn $name() -> usize { super::$ident(); 0 } + + $name + }; + ); + + $( $($extra)+ )? + } + }; + + ( + static + macros=$macros:ident + name=$name:ident + used=$used:meta + item={ + $( + #[$meta:meta] + )* + $vis:vis static $ident:ident: $ty:ty = $expr:expr; + } + ) => { + + $(#[$meta])* + $vis static $ident: $name::Static<$ty> = $name::Static::<$ty> { + _storage: ::std::cell::UnsafeCell::new(None) + }; + + impl ::core::ops::Deref for $name::Static<$ty> { + type Target = $ty; + fn deref(&self) -> &'static $ty { + unsafe { + let ptr = self._storage.get(); + let val = (&*ptr).as_ref().unwrap(); + val + } + } + } + + $macros::ctor_impl!( + fn + macros=$macros + name=$name + used=$used + extra={ + #[doc(hidden)] + #[derive(Default)] + #[allow(non_camel_case_types)] + pub struct Static { + pub _storage: ::std::cell::UnsafeCell<::std::option::Option> + } + + unsafe impl std::marker::Sync for Static {} + } + item={ + #[allow(non_snake_case)] + fn $name() { + let val = Some($expr); + // Only write the value to `storage_ident` on startup + unsafe { + let ptr = $ident._storage.get(); + ::std::ptr::write(ptr, val); + } + } + } + ); + }; + + ( + dtor + macros=$macros:ident + name=$name:ident + used=$used:meta + item={ + $( + #[$meta:meta] + )* + $vis:vis $(unsafe)? fn $ident:ident () $(-> $ret:ty)? $block:block + } + ) => { + $(#[$meta])* + #[allow(unused)] + $vis unsafe extern "C" fn $ident() $block + + #[doc(hidden)] + #[allow(unused, non_snake_case)] + mod $name { + super::$macros::ctor_raw!($used + #[allow(non_upper_case_globals, non_snake_case)] + #[doc(hidden)] + static $name: unsafe extern "C" fn() -> usize = + { + #[allow(non_snake_case)] + #[cfg_attr(any(target_os = "linux", target_os = "android"), link_section = ".text.startup")] + unsafe extern "C" fn $name() -> usize { do_atexit(__dtor); 0 } + + $name + }; + ); + + #[cfg(not(target_vendor = "apple"))] + #[cfg_attr(any(target_os = "linux", target_os = "android"), link_section = ".text.exit")] + unsafe extern "C" fn __dtor() { super::$ident() } + #[cfg(target_vendor = "apple")] + unsafe extern "C" fn __dtor(_: *const u8) { super::$ident() } + + #[cfg(not(target_vendor = "apple"))] + #[inline(always)] + pub(super) unsafe fn do_atexit(cb: unsafe extern fn()) { + extern "C" { + fn atexit(cb: unsafe extern fn()); + } + atexit(cb); + } + + // For platforms that have __cxa_atexit, we register the dtor as scoped to dso_handle + #[cfg(target_vendor = "apple")] + #[inline(always)] + pub(super) unsafe fn do_atexit(cb: unsafe extern fn(_: *const u8)) { + extern "C" { + static __dso_handle: *const u8; + fn __cxa_atexit(cb: unsafe extern fn(_: *const u8), arg: *const u8, dso_handle: *const u8); + } + __cxa_atexit(cb, core::ptr::null(), __dso_handle); + } + + } + }; + } +); diff --git a/codegen/src/main.rs b/codegen/src/main.rs new file mode 100644 index 0000000..33c893b --- /dev/null +++ b/codegen/src/main.rs @@ -0,0 +1,170 @@ +use std::collections::HashMap; +use std::fmt::Write; + +pub mod macros; + +#[macro_export] +macro_rules! declare_macro { + (macro_rules ! $name:ident $($defn:tt)* ) => { + macro_rules! $name $($defn)* + + pub(crate) use $name; + + ::paste::paste!(pub fn [<$name _tokens>]() -> ::proc_macro2::TokenStream { + quote::quote! { + macro_rules! $name $($defn)* + + pub(crate) use $name; + } + }); + }; +} + +fn dump_tokens_recursive( + indent: &str, + w: &mut String, + tokens: ::proc_macro2::TokenStream, +) -> Result<(), std::fmt::Error> { + use ::proc_macro2::TokenTree::*; + let tt = "T"; + + if tokens.is_empty() { + writeln!(w, "{indent}TokenStream::new()")?; + } else { + writeln!(w, "{indent}TokenStream::from_iter([")?; + { + let indent = format!("{indent} "); + for token in tokens { + match token { + Ident(name) => { + let name = name.to_string(); + writeln!(w, r#"{indent}{tt}::Ident(Ident::new({name:?}, c())),"#)?; + } + Punct(punct) => { + let spacing = punct.spacing(); + let punct = punct.as_char(); + writeln!( + w, + r#"{indent}{tt}::Punct(Punct::new({punct:?}, {spacing:?})),"# + )?; + } + Literal(literal) => { + let literal = literal.to_string(); + if literal.starts_with('"') { + writeln!(w, "{indent}{tt}::Literal(Literal::string({literal})),")?; + } else { + writeln!( + w, + "{indent}{tt}::Literal(Literal::usize_unsuffixed({literal}))," + )?; + } + } + Group(group) => { + let delimiter = group.delimiter(); + writeln!(w, "{indent}{tt}::Group(Group::new({delimiter:?}, ")?; + dump_tokens_recursive(&format!("{indent} "), w, group.stream())?; + writeln!(w, "{indent})),")?; + } + } + } + } + writeln!(w, "{indent}])")?; + } + Ok(()) +} + +fn dump_tokens( + w: &mut String, + name: &str, + tokens: ::proc_macro2::TokenStream, +) -> Result<(), std::fmt::Error> { + writeln!(w, "pub fn {name}() -> TokenStream {{")?; + dump_tokens_recursive(" ", w, tokens).unwrap(); + writeln!(w, "}}")?; + writeln!(w)?; + Ok(()) +} + +fn generate_code() -> Result { + let mut s = String::with_capacity(16 * 1024); + writeln!(&mut s, "// This file is generated. Do not edit.")?; + writeln!(&mut s)?; + + writeln!(&mut s, "use proc_macro::*;")?; + writeln!(&mut s, "use proc_macro::TokenTree as T;")?; + writeln!(&mut s, "use proc_macro::Spacing::*;")?; + writeln!(&mut s, "use proc_macro::Delimiter::*;")?; + writeln!(&mut s, "use std::iter::FromIterator;")?; + writeln!(&mut s)?; + writeln!(&mut s, "fn c() -> Span {{ Span::call_site() }}")?; + writeln!(&mut s)?; + + dump_tokens(&mut s, "ctor", macros::ctor_impl_tokens())?; + dump_tokens(&mut s, "ctor_raw", macros::ctor_raw_tokens())?; + + Ok(s) +} + +macros::ctor_impl!( + fn + macros=macros + name=foo_impl + used=used + item={ + fn foo() { + + } + } +); + +macros::ctor_impl!( + static + macros=macros + name=static_impl + used=used + item={ + pub static STATIC_U8: u8 = { 1 }; + } +); + +macros::ctor_impl!( + dtor + macros=macros + name=dtor_impl + used=used + item={ + fn bar() { + + } + } +); + +mod module { + use super::*; + macros::ctor_impl!( + static + macros=macros + name=static_hash_impl + used=used + item={ + pub static STATIC_CTOR: HashMap = { + let mut m = HashMap::new(); + m.insert(0, "foo"); + m.insert(1, "bar"); + m.insert(2, "baz"); + m + }; + } + ); +} + +#[allow(unused)] +fn test_compiles() { + eprintln!("{:?}", *STATIC_U8); + eprintln!("{:?}", *module::STATIC_CTOR); +} + +fn main() { + let contents = generate_code().expect("Failed to generate code"); + std::fs::write("ctor/src/gen.rs", contents).expect("Failed to write code"); +} diff --git a/ctor/Cargo.toml b/ctor/Cargo.toml index ac9c3e8..9bae07c 100644 --- a/ctor/Cargo.toml +++ b/ctor/Cargo.toml @@ -15,14 +15,6 @@ travis-ci = { repository = "mmastrac/rust-ctor", branch = "master" } # For nightly users, used(linker) may be a better choice used_linker = [] -[dependencies] -quote = "1.0.20" - -[dependencies.syn] -version = "2.0.12" -features = ["full", "parsing", "printing", "proc-macro"] -default-features = false - [dev-dependencies] libc-print = "0.1.20" diff --git a/ctor/src/gen.rs b/ctor/src/gen.rs new file mode 100644 index 0000000..8266c24 --- /dev/null +++ b/ctor/src/gen.rs @@ -0,0 +1,1629 @@ +// This file is generated. Do not edit. + +use proc_macro::*; +use proc_macro::TokenTree as T; +use proc_macro::Spacing::*; +use proc_macro::Delimiter::*; +use std::iter::FromIterator; + +fn c() -> Span { Span::call_site() } + +pub fn ctor() -> TokenStream { + TokenStream::from_iter([ + T::Ident(Ident::new("macro_rules", c())), + T::Punct(Punct::new('!', Alone)), + T::Ident(Ident::new("ctor_impl", c())), + T::Group(Group::new(Brace, + TokenStream::from_iter([ + T::Group(Group::new(Parenthesis, + TokenStream::from_iter([ + T::Ident(Ident::new("fn", c())), + T::Ident(Ident::new("macros", c())), + T::Punct(Punct::new('=', Alone)), + T::Punct(Punct::new('$', Alone)), + T::Ident(Ident::new("macros", c())), + T::Punct(Punct::new(':', Alone)), + T::Ident(Ident::new("ident", c())), + T::Ident(Ident::new("name", c())), + T::Punct(Punct::new('=', Alone)), + T::Punct(Punct::new('$', Alone)), + T::Ident(Ident::new("name", c())), + T::Punct(Punct::new(':', Alone)), + T::Ident(Ident::new("ident", c())), + T::Ident(Ident::new("used", c())), + T::Punct(Punct::new('=', Alone)), + T::Punct(Punct::new('$', Alone)), + T::Ident(Ident::new("used", c())), + T::Punct(Punct::new(':', Alone)), + T::Ident(Ident::new("meta", c())), + T::Punct(Punct::new('$', Alone)), + T::Group(Group::new(Parenthesis, + TokenStream::from_iter([ + T::Ident(Ident::new("extra", c())), + T::Punct(Punct::new('=', Alone)), + T::Group(Group::new(Brace, + TokenStream::from_iter([ + T::Punct(Punct::new('$', Alone)), + T::Group(Group::new(Parenthesis, + TokenStream::from_iter([ + T::Punct(Punct::new('$', Alone)), + T::Ident(Ident::new("extra", c())), + T::Punct(Punct::new(':', Alone)), + T::Ident(Ident::new("item", c())), + ]) + )), + T::Punct(Punct::new('+', Alone)), + ]) + )), + ]) + )), + T::Punct(Punct::new('?', Alone)), + T::Ident(Ident::new("item", c())), + T::Punct(Punct::new('=', Alone)), + T::Group(Group::new(Brace, + TokenStream::from_iter([ + T::Punct(Punct::new('$', Alone)), + T::Group(Group::new(Parenthesis, + TokenStream::from_iter([ + T::Punct(Punct::new('#', Alone)), + T::Group(Group::new(Bracket, + TokenStream::from_iter([ + T::Punct(Punct::new('$', Alone)), + T::Ident(Ident::new("meta", c())), + T::Punct(Punct::new(':', Alone)), + T::Ident(Ident::new("meta", c())), + ]) + )), + ]) + )), + T::Punct(Punct::new('*', Alone)), + T::Punct(Punct::new('$', Alone)), + T::Ident(Ident::new("vis", c())), + T::Punct(Punct::new(':', Alone)), + T::Ident(Ident::new("vis", c())), + T::Punct(Punct::new('$', Alone)), + T::Group(Group::new(Parenthesis, + TokenStream::from_iter([ + T::Ident(Ident::new("unsafe", c())), + ]) + )), + T::Punct(Punct::new('?', Alone)), + T::Ident(Ident::new("fn", c())), + T::Punct(Punct::new('$', Alone)), + T::Ident(Ident::new("ident", c())), + T::Punct(Punct::new(':', Alone)), + T::Ident(Ident::new("ident", c())), + T::Group(Group::new(Parenthesis, + TokenStream::new() + )), + T::Punct(Punct::new('$', Alone)), + T::Group(Group::new(Parenthesis, + TokenStream::from_iter([ + T::Punct(Punct::new('-', Joint)), + T::Punct(Punct::new('>', Alone)), + T::Punct(Punct::new('$', Alone)), + T::Ident(Ident::new("ret", c())), + T::Punct(Punct::new(':', Alone)), + T::Ident(Ident::new("ty", c())), + ]) + )), + T::Punct(Punct::new('?', Alone)), + T::Punct(Punct::new('$', Alone)), + T::Ident(Ident::new("block", c())), + T::Punct(Punct::new(':', Alone)), + T::Ident(Ident::new("block", c())), + ]) + )), + ]) + )), + T::Punct(Punct::new('=', Joint)), + T::Punct(Punct::new('>', Alone)), + T::Group(Group::new(Brace, + TokenStream::from_iter([ + T::Punct(Punct::new('$', Alone)), + T::Group(Group::new(Parenthesis, + TokenStream::from_iter([ + T::Punct(Punct::new('#', Alone)), + T::Group(Group::new(Bracket, + TokenStream::from_iter([ + T::Punct(Punct::new('$', Alone)), + T::Ident(Ident::new("meta", c())), + ]) + )), + ]) + )), + T::Punct(Punct::new('*', Alone)), + T::Punct(Punct::new('#', Alone)), + T::Group(Group::new(Bracket, + TokenStream::from_iter([ + T::Ident(Ident::new("allow", c())), + T::Group(Group::new(Parenthesis, + TokenStream::from_iter([ + T::Ident(Ident::new("unused", c())), + ]) + )), + ]) + )), + T::Punct(Punct::new('$', Alone)), + T::Ident(Ident::new("vis", c())), + T::Ident(Ident::new("unsafe", c())), + T::Ident(Ident::new("extern", c())), + T::Literal(Literal::string("C")), + T::Ident(Ident::new("fn", c())), + T::Punct(Punct::new('$', Alone)), + T::Ident(Ident::new("ident", c())), + T::Group(Group::new(Parenthesis, + TokenStream::new() + )), + T::Punct(Punct::new('$', Alone)), + T::Ident(Ident::new("block", c())), + T::Punct(Punct::new('#', Alone)), + T::Group(Group::new(Bracket, + TokenStream::from_iter([ + T::Ident(Ident::new("doc", c())), + T::Group(Group::new(Parenthesis, + TokenStream::from_iter([ + T::Ident(Ident::new("hidden", c())), + ]) + )), + ]) + )), + T::Punct(Punct::new('#', Alone)), + T::Group(Group::new(Bracket, + TokenStream::from_iter([ + T::Ident(Ident::new("allow", c())), + T::Group(Group::new(Parenthesis, + TokenStream::from_iter([ + T::Ident(Ident::new("unused", c())), + T::Punct(Punct::new(',', Alone)), + T::Ident(Ident::new("non_snake_case", c())), + ]) + )), + ]) + )), + T::Ident(Ident::new("mod", c())), + T::Punct(Punct::new('$', Alone)), + T::Ident(Ident::new("name", c())), + T::Group(Group::new(Brace, + TokenStream::from_iter([ + T::Ident(Ident::new("super", c())), + T::Punct(Punct::new(':', Joint)), + T::Punct(Punct::new(':', Alone)), + T::Punct(Punct::new('$', Alone)), + T::Ident(Ident::new("macros", c())), + T::Punct(Punct::new(':', Joint)), + T::Punct(Punct::new(':', Alone)), + T::Ident(Ident::new("ctor_raw", c())), + T::Punct(Punct::new('!', Alone)), + T::Group(Group::new(Parenthesis, + TokenStream::from_iter([ + T::Punct(Punct::new('$', Alone)), + T::Ident(Ident::new("used", c())), + T::Punct(Punct::new('#', Alone)), + T::Group(Group::new(Bracket, + TokenStream::from_iter([ + T::Ident(Ident::new("allow", c())), + T::Group(Group::new(Parenthesis, + TokenStream::from_iter([ + T::Ident(Ident::new("non_upper_case_globals", c())), + T::Punct(Punct::new(',', Alone)), + T::Ident(Ident::new("non_snake_case", c())), + ]) + )), + ]) + )), + T::Punct(Punct::new('#', Alone)), + T::Group(Group::new(Bracket, + TokenStream::from_iter([ + T::Ident(Ident::new("doc", c())), + T::Group(Group::new(Parenthesis, + TokenStream::from_iter([ + T::Ident(Ident::new("hidden", c())), + ]) + )), + ]) + )), + T::Ident(Ident::new("static", c())), + T::Punct(Punct::new('$', Alone)), + T::Ident(Ident::new("name", c())), + T::Punct(Punct::new(':', Alone)), + T::Ident(Ident::new("unsafe", c())), + T::Ident(Ident::new("extern", c())), + T::Literal(Literal::string("C")), + T::Ident(Ident::new("fn", c())), + T::Group(Group::new(Parenthesis, + TokenStream::new() + )), + T::Punct(Punct::new('-', Joint)), + T::Punct(Punct::new('>', Alone)), + T::Ident(Ident::new("usize", c())), + T::Punct(Punct::new('=', Alone)), + T::Group(Group::new(Brace, + TokenStream::from_iter([ + T::Punct(Punct::new('#', Alone)), + T::Group(Group::new(Bracket, + TokenStream::from_iter([ + T::Ident(Ident::new("allow", c())), + T::Group(Group::new(Parenthesis, + TokenStream::from_iter([ + T::Ident(Ident::new("non_snake_case", c())), + ]) + )), + ]) + )), + T::Punct(Punct::new('#', Alone)), + T::Group(Group::new(Bracket, + TokenStream::from_iter([ + T::Ident(Ident::new("cfg_attr", c())), + T::Group(Group::new(Parenthesis, + TokenStream::from_iter([ + T::Ident(Ident::new("any", c())), + T::Group(Group::new(Parenthesis, + TokenStream::from_iter([ + T::Ident(Ident::new("target_os", c())), + T::Punct(Punct::new('=', Alone)), + T::Literal(Literal::string("linux")), + T::Punct(Punct::new(',', Alone)), + T::Ident(Ident::new("target_os", c())), + T::Punct(Punct::new('=', Alone)), + T::Literal(Literal::string("android")), + ]) + )), + T::Punct(Punct::new(',', Alone)), + T::Ident(Ident::new("link_section", c())), + T::Punct(Punct::new('=', Alone)), + T::Literal(Literal::string(".text.startup")), + ]) + )), + ]) + )), + T::Ident(Ident::new("unsafe", c())), + T::Ident(Ident::new("extern", c())), + T::Literal(Literal::string("C")), + T::Ident(Ident::new("fn", c())), + T::Punct(Punct::new('$', Alone)), + T::Ident(Ident::new("name", c())), + T::Group(Group::new(Parenthesis, + TokenStream::new() + )), + T::Punct(Punct::new('-', Joint)), + T::Punct(Punct::new('>', Alone)), + T::Ident(Ident::new("usize", c())), + T::Group(Group::new(Brace, + TokenStream::from_iter([ + T::Ident(Ident::new("super", c())), + T::Punct(Punct::new(':', Joint)), + T::Punct(Punct::new(':', Alone)), + T::Punct(Punct::new('$', Alone)), + T::Ident(Ident::new("ident", c())), + T::Group(Group::new(Parenthesis, + TokenStream::new() + )), + T::Punct(Punct::new(';', Alone)), + T::Literal(Literal::usize_unsuffixed(0)), + ]) + )), + T::Punct(Punct::new('$', Alone)), + T::Ident(Ident::new("name", c())), + ]) + )), + T::Punct(Punct::new(';', Alone)), + ]) + )), + T::Punct(Punct::new(';', Alone)), + T::Punct(Punct::new('$', Alone)), + T::Group(Group::new(Parenthesis, + TokenStream::from_iter([ + T::Punct(Punct::new('$', Alone)), + T::Group(Group::new(Parenthesis, + TokenStream::from_iter([ + T::Punct(Punct::new('$', Alone)), + T::Ident(Ident::new("extra", c())), + ]) + )), + T::Punct(Punct::new('+', Alone)), + ]) + )), + T::Punct(Punct::new('?', Alone)), + ]) + )), + ]) + )), + T::Punct(Punct::new(';', Alone)), + T::Group(Group::new(Parenthesis, + TokenStream::from_iter([ + T::Ident(Ident::new("static", c())), + T::Ident(Ident::new("macros", c())), + T::Punct(Punct::new('=', Alone)), + T::Punct(Punct::new('$', Alone)), + T::Ident(Ident::new("macros", c())), + T::Punct(Punct::new(':', Alone)), + T::Ident(Ident::new("ident", c())), + T::Ident(Ident::new("name", c())), + T::Punct(Punct::new('=', Alone)), + T::Punct(Punct::new('$', Alone)), + T::Ident(Ident::new("name", c())), + T::Punct(Punct::new(':', Alone)), + T::Ident(Ident::new("ident", c())), + T::Ident(Ident::new("used", c())), + T::Punct(Punct::new('=', Alone)), + T::Punct(Punct::new('$', Alone)), + T::Ident(Ident::new("used", c())), + T::Punct(Punct::new(':', Alone)), + T::Ident(Ident::new("meta", c())), + T::Ident(Ident::new("item", c())), + T::Punct(Punct::new('=', Alone)), + T::Group(Group::new(Brace, + TokenStream::from_iter([ + T::Punct(Punct::new('$', Alone)), + T::Group(Group::new(Parenthesis, + TokenStream::from_iter([ + T::Punct(Punct::new('#', Alone)), + T::Group(Group::new(Bracket, + TokenStream::from_iter([ + T::Punct(Punct::new('$', Alone)), + T::Ident(Ident::new("meta", c())), + T::Punct(Punct::new(':', Alone)), + T::Ident(Ident::new("meta", c())), + ]) + )), + ]) + )), + T::Punct(Punct::new('*', Alone)), + T::Punct(Punct::new('$', Alone)), + T::Ident(Ident::new("vis", c())), + T::Punct(Punct::new(':', Alone)), + T::Ident(Ident::new("vis", c())), + T::Ident(Ident::new("static", c())), + T::Punct(Punct::new('$', Alone)), + T::Ident(Ident::new("ident", c())), + T::Punct(Punct::new(':', Alone)), + T::Ident(Ident::new("ident", c())), + T::Punct(Punct::new(':', Alone)), + T::Punct(Punct::new('$', Alone)), + T::Ident(Ident::new("ty", c())), + T::Punct(Punct::new(':', Alone)), + T::Ident(Ident::new("ty", c())), + T::Punct(Punct::new('=', Alone)), + T::Punct(Punct::new('$', Alone)), + T::Ident(Ident::new("expr", c())), + T::Punct(Punct::new(':', Alone)), + T::Ident(Ident::new("expr", c())), + T::Punct(Punct::new(';', Alone)), + ]) + )), + ]) + )), + T::Punct(Punct::new('=', Joint)), + T::Punct(Punct::new('>', Alone)), + T::Group(Group::new(Brace, + TokenStream::from_iter([ + T::Punct(Punct::new('$', Alone)), + T::Group(Group::new(Parenthesis, + TokenStream::from_iter([ + T::Punct(Punct::new('#', Alone)), + T::Group(Group::new(Bracket, + TokenStream::from_iter([ + T::Punct(Punct::new('$', Alone)), + T::Ident(Ident::new("meta", c())), + ]) + )), + ]) + )), + T::Punct(Punct::new('*', Alone)), + T::Punct(Punct::new('$', Alone)), + T::Ident(Ident::new("vis", c())), + T::Ident(Ident::new("static", c())), + T::Punct(Punct::new('$', Alone)), + T::Ident(Ident::new("ident", c())), + T::Punct(Punct::new(':', Alone)), + T::Punct(Punct::new('$', Alone)), + T::Ident(Ident::new("name", c())), + T::Punct(Punct::new(':', Joint)), + T::Punct(Punct::new(':', Alone)), + T::Ident(Ident::new("Static", c())), + T::Punct(Punct::new('<', Alone)), + T::Punct(Punct::new('$', Alone)), + T::Ident(Ident::new("ty", c())), + T::Punct(Punct::new('>', Alone)), + T::Punct(Punct::new('=', Alone)), + T::Punct(Punct::new('$', Alone)), + T::Ident(Ident::new("name", c())), + T::Punct(Punct::new(':', Joint)), + T::Punct(Punct::new(':', Alone)), + T::Ident(Ident::new("Static", c())), + T::Punct(Punct::new(':', Joint)), + T::Punct(Punct::new(':', Alone)), + T::Punct(Punct::new('<', Alone)), + T::Punct(Punct::new('$', Alone)), + T::Ident(Ident::new("ty", c())), + T::Punct(Punct::new('>', Alone)), + T::Group(Group::new(Brace, + TokenStream::from_iter([ + T::Ident(Ident::new("_storage", c())), + T::Punct(Punct::new(':', Alone)), + T::Punct(Punct::new(':', Joint)), + T::Punct(Punct::new(':', Alone)), + T::Ident(Ident::new("std", c())), + T::Punct(Punct::new(':', Joint)), + T::Punct(Punct::new(':', Alone)), + T::Ident(Ident::new("cell", c())), + T::Punct(Punct::new(':', Joint)), + T::Punct(Punct::new(':', Alone)), + T::Ident(Ident::new("UnsafeCell", c())), + T::Punct(Punct::new(':', Joint)), + T::Punct(Punct::new(':', Alone)), + T::Ident(Ident::new("new", c())), + T::Group(Group::new(Parenthesis, + TokenStream::from_iter([ + T::Ident(Ident::new("None", c())), + ]) + )), + ]) + )), + T::Punct(Punct::new(';', Alone)), + T::Ident(Ident::new("impl", c())), + T::Punct(Punct::new(':', Joint)), + T::Punct(Punct::new(':', Alone)), + T::Ident(Ident::new("core", c())), + T::Punct(Punct::new(':', Joint)), + T::Punct(Punct::new(':', Alone)), + T::Ident(Ident::new("ops", c())), + T::Punct(Punct::new(':', Joint)), + T::Punct(Punct::new(':', Alone)), + T::Ident(Ident::new("Deref", c())), + T::Ident(Ident::new("for", c())), + T::Punct(Punct::new('$', Alone)), + T::Ident(Ident::new("name", c())), + T::Punct(Punct::new(':', Joint)), + T::Punct(Punct::new(':', Alone)), + T::Ident(Ident::new("Static", c())), + T::Punct(Punct::new('<', Alone)), + T::Punct(Punct::new('$', Alone)), + T::Ident(Ident::new("ty", c())), + T::Punct(Punct::new('>', Alone)), + T::Group(Group::new(Brace, + TokenStream::from_iter([ + T::Ident(Ident::new("type", c())), + T::Ident(Ident::new("Target", c())), + T::Punct(Punct::new('=', Alone)), + T::Punct(Punct::new('$', Alone)), + T::Ident(Ident::new("ty", c())), + T::Punct(Punct::new(';', Alone)), + T::Ident(Ident::new("fn", c())), + T::Ident(Ident::new("deref", c())), + T::Group(Group::new(Parenthesis, + TokenStream::from_iter([ + T::Punct(Punct::new('&', Alone)), + T::Ident(Ident::new("self", c())), + ]) + )), + T::Punct(Punct::new('-', Joint)), + T::Punct(Punct::new('>', Alone)), + T::Punct(Punct::new('&', Alone)), + T::Punct(Punct::new('\'', Joint)), + T::Ident(Ident::new("static", c())), + T::Punct(Punct::new('$', Alone)), + T::Ident(Ident::new("ty", c())), + T::Group(Group::new(Brace, + TokenStream::from_iter([ + T::Ident(Ident::new("unsafe", c())), + T::Group(Group::new(Brace, + TokenStream::from_iter([ + T::Ident(Ident::new("let", c())), + T::Ident(Ident::new("ptr", c())), + T::Punct(Punct::new('=', Alone)), + T::Ident(Ident::new("self", c())), + T::Punct(Punct::new('.', Alone)), + T::Ident(Ident::new("_storage", c())), + T::Punct(Punct::new('.', Alone)), + T::Ident(Ident::new("get", c())), + T::Group(Group::new(Parenthesis, + TokenStream::new() + )), + T::Punct(Punct::new(';', Alone)), + T::Ident(Ident::new("let", c())), + T::Ident(Ident::new("val", c())), + T::Punct(Punct::new('=', Alone)), + T::Group(Group::new(Parenthesis, + TokenStream::from_iter([ + T::Punct(Punct::new('&', Alone)), + T::Punct(Punct::new('*', Alone)), + T::Ident(Ident::new("ptr", c())), + ]) + )), + T::Punct(Punct::new('.', Alone)), + T::Ident(Ident::new("as_ref", c())), + T::Group(Group::new(Parenthesis, + TokenStream::new() + )), + T::Punct(Punct::new('.', Alone)), + T::Ident(Ident::new("unwrap", c())), + T::Group(Group::new(Parenthesis, + TokenStream::new() + )), + T::Punct(Punct::new(';', Alone)), + T::Ident(Ident::new("val", c())), + ]) + )), + ]) + )), + ]) + )), + T::Punct(Punct::new('$', Alone)), + T::Ident(Ident::new("macros", c())), + T::Punct(Punct::new(':', Joint)), + T::Punct(Punct::new(':', Alone)), + T::Ident(Ident::new("ctor_impl", c())), + T::Punct(Punct::new('!', Alone)), + T::Group(Group::new(Parenthesis, + TokenStream::from_iter([ + T::Ident(Ident::new("fn", c())), + T::Ident(Ident::new("macros", c())), + T::Punct(Punct::new('=', Alone)), + T::Punct(Punct::new('$', Alone)), + T::Ident(Ident::new("macros", c())), + T::Ident(Ident::new("name", c())), + T::Punct(Punct::new('=', Alone)), + T::Punct(Punct::new('$', Alone)), + T::Ident(Ident::new("name", c())), + T::Ident(Ident::new("used", c())), + T::Punct(Punct::new('=', Alone)), + T::Punct(Punct::new('$', Alone)), + T::Ident(Ident::new("used", c())), + T::Ident(Ident::new("extra", c())), + T::Punct(Punct::new('=', Alone)), + T::Group(Group::new(Brace, + TokenStream::from_iter([ + T::Punct(Punct::new('#', Alone)), + T::Group(Group::new(Bracket, + TokenStream::from_iter([ + T::Ident(Ident::new("doc", c())), + T::Group(Group::new(Parenthesis, + TokenStream::from_iter([ + T::Ident(Ident::new("hidden", c())), + ]) + )), + ]) + )), + T::Punct(Punct::new('#', Alone)), + T::Group(Group::new(Bracket, + TokenStream::from_iter([ + T::Ident(Ident::new("derive", c())), + T::Group(Group::new(Parenthesis, + TokenStream::from_iter([ + T::Ident(Ident::new("Default", c())), + ]) + )), + ]) + )), + T::Punct(Punct::new('#', Alone)), + T::Group(Group::new(Bracket, + TokenStream::from_iter([ + T::Ident(Ident::new("allow", c())), + T::Group(Group::new(Parenthesis, + TokenStream::from_iter([ + T::Ident(Ident::new("non_camel_case_types", c())), + ]) + )), + ]) + )), + T::Ident(Ident::new("pub", c())), + T::Ident(Ident::new("struct", c())), + T::Ident(Ident::new("Static", c())), + T::Punct(Punct::new('<', Alone)), + T::Ident(Ident::new("T", c())), + T::Punct(Punct::new('>', Alone)), + T::Group(Group::new(Brace, + TokenStream::from_iter([ + T::Ident(Ident::new("pub", c())), + T::Ident(Ident::new("_storage", c())), + T::Punct(Punct::new(':', Alone)), + T::Punct(Punct::new(':', Joint)), + T::Punct(Punct::new(':', Alone)), + T::Ident(Ident::new("std", c())), + T::Punct(Punct::new(':', Joint)), + T::Punct(Punct::new(':', Alone)), + T::Ident(Ident::new("cell", c())), + T::Punct(Punct::new(':', Joint)), + T::Punct(Punct::new(':', Alone)), + T::Ident(Ident::new("UnsafeCell", c())), + T::Punct(Punct::new('<', Alone)), + T::Punct(Punct::new(':', Joint)), + T::Punct(Punct::new(':', Alone)), + T::Ident(Ident::new("std", c())), + T::Punct(Punct::new(':', Joint)), + T::Punct(Punct::new(':', Alone)), + T::Ident(Ident::new("option", c())), + T::Punct(Punct::new(':', Joint)), + T::Punct(Punct::new(':', Alone)), + T::Ident(Ident::new("Option", c())), + T::Punct(Punct::new('<', Alone)), + T::Ident(Ident::new("T", c())), + T::Punct(Punct::new('>', Joint)), + T::Punct(Punct::new('>', Alone)), + ]) + )), + T::Ident(Ident::new("unsafe", c())), + T::Ident(Ident::new("impl", c())), + T::Punct(Punct::new('<', Alone)), + T::Ident(Ident::new("T", c())), + T::Punct(Punct::new('>', Alone)), + T::Ident(Ident::new("std", c())), + T::Punct(Punct::new(':', Joint)), + T::Punct(Punct::new(':', Alone)), + T::Ident(Ident::new("marker", c())), + T::Punct(Punct::new(':', Joint)), + T::Punct(Punct::new(':', Alone)), + T::Ident(Ident::new("Sync", c())), + T::Ident(Ident::new("for", c())), + T::Ident(Ident::new("Static", c())), + T::Punct(Punct::new('<', Alone)), + T::Ident(Ident::new("T", c())), + T::Punct(Punct::new('>', Alone)), + T::Group(Group::new(Brace, + TokenStream::new() + )), + ]) + )), + T::Ident(Ident::new("item", c())), + T::Punct(Punct::new('=', Alone)), + T::Group(Group::new(Brace, + TokenStream::from_iter([ + T::Punct(Punct::new('#', Alone)), + T::Group(Group::new(Bracket, + TokenStream::from_iter([ + T::Ident(Ident::new("allow", c())), + T::Group(Group::new(Parenthesis, + TokenStream::from_iter([ + T::Ident(Ident::new("non_snake_case", c())), + ]) + )), + ]) + )), + T::Ident(Ident::new("fn", c())), + T::Punct(Punct::new('$', Alone)), + T::Ident(Ident::new("name", c())), + T::Group(Group::new(Parenthesis, + TokenStream::new() + )), + T::Group(Group::new(Brace, + TokenStream::from_iter([ + T::Ident(Ident::new("let", c())), + T::Ident(Ident::new("val", c())), + T::Punct(Punct::new('=', Alone)), + T::Ident(Ident::new("Some", c())), + T::Group(Group::new(Parenthesis, + TokenStream::from_iter([ + T::Punct(Punct::new('$', Alone)), + T::Ident(Ident::new("expr", c())), + ]) + )), + T::Punct(Punct::new(';', Alone)), + T::Ident(Ident::new("unsafe", c())), + T::Group(Group::new(Brace, + TokenStream::from_iter([ + T::Ident(Ident::new("let", c())), + T::Ident(Ident::new("ptr", c())), + T::Punct(Punct::new('=', Alone)), + T::Punct(Punct::new('$', Alone)), + T::Ident(Ident::new("ident", c())), + T::Punct(Punct::new('.', Alone)), + T::Ident(Ident::new("_storage", c())), + T::Punct(Punct::new('.', Alone)), + T::Ident(Ident::new("get", c())), + T::Group(Group::new(Parenthesis, + TokenStream::new() + )), + T::Punct(Punct::new(';', Alone)), + T::Punct(Punct::new(':', Joint)), + T::Punct(Punct::new(':', Alone)), + T::Ident(Ident::new("std", c())), + T::Punct(Punct::new(':', Joint)), + T::Punct(Punct::new(':', Alone)), + T::Ident(Ident::new("ptr", c())), + T::Punct(Punct::new(':', Joint)), + T::Punct(Punct::new(':', Alone)), + T::Ident(Ident::new("write", c())), + T::Group(Group::new(Parenthesis, + TokenStream::from_iter([ + T::Ident(Ident::new("ptr", c())), + T::Punct(Punct::new(',', Alone)), + T::Ident(Ident::new("val", c())), + ]) + )), + T::Punct(Punct::new(';', Alone)), + ]) + )), + ]) + )), + ]) + )), + ]) + )), + T::Punct(Punct::new(';', Alone)), + ]) + )), + T::Punct(Punct::new(';', Alone)), + T::Group(Group::new(Parenthesis, + TokenStream::from_iter([ + T::Ident(Ident::new("dtor", c())), + T::Ident(Ident::new("macros", c())), + T::Punct(Punct::new('=', Alone)), + T::Punct(Punct::new('$', Alone)), + T::Ident(Ident::new("macros", c())), + T::Punct(Punct::new(':', Alone)), + T::Ident(Ident::new("ident", c())), + T::Ident(Ident::new("name", c())), + T::Punct(Punct::new('=', Alone)), + T::Punct(Punct::new('$', Alone)), + T::Ident(Ident::new("name", c())), + T::Punct(Punct::new(':', Alone)), + T::Ident(Ident::new("ident", c())), + T::Ident(Ident::new("used", c())), + T::Punct(Punct::new('=', Alone)), + T::Punct(Punct::new('$', Alone)), + T::Ident(Ident::new("used", c())), + T::Punct(Punct::new(':', Alone)), + T::Ident(Ident::new("meta", c())), + T::Ident(Ident::new("item", c())), + T::Punct(Punct::new('=', Alone)), + T::Group(Group::new(Brace, + TokenStream::from_iter([ + T::Punct(Punct::new('$', Alone)), + T::Group(Group::new(Parenthesis, + TokenStream::from_iter([ + T::Punct(Punct::new('#', Alone)), + T::Group(Group::new(Bracket, + TokenStream::from_iter([ + T::Punct(Punct::new('$', Alone)), + T::Ident(Ident::new("meta", c())), + T::Punct(Punct::new(':', Alone)), + T::Ident(Ident::new("meta", c())), + ]) + )), + ]) + )), + T::Punct(Punct::new('*', Alone)), + T::Punct(Punct::new('$', Alone)), + T::Ident(Ident::new("vis", c())), + T::Punct(Punct::new(':', Alone)), + T::Ident(Ident::new("vis", c())), + T::Punct(Punct::new('$', Alone)), + T::Group(Group::new(Parenthesis, + TokenStream::from_iter([ + T::Ident(Ident::new("unsafe", c())), + ]) + )), + T::Punct(Punct::new('?', Alone)), + T::Ident(Ident::new("fn", c())), + T::Punct(Punct::new('$', Alone)), + T::Ident(Ident::new("ident", c())), + T::Punct(Punct::new(':', Alone)), + T::Ident(Ident::new("ident", c())), + T::Group(Group::new(Parenthesis, + TokenStream::new() + )), + T::Punct(Punct::new('$', Alone)), + T::Group(Group::new(Parenthesis, + TokenStream::from_iter([ + T::Punct(Punct::new('-', Joint)), + T::Punct(Punct::new('>', Alone)), + T::Punct(Punct::new('$', Alone)), + T::Ident(Ident::new("ret", c())), + T::Punct(Punct::new(':', Alone)), + T::Ident(Ident::new("ty", c())), + ]) + )), + T::Punct(Punct::new('?', Alone)), + T::Punct(Punct::new('$', Alone)), + T::Ident(Ident::new("block", c())), + T::Punct(Punct::new(':', Alone)), + T::Ident(Ident::new("block", c())), + ]) + )), + ]) + )), + T::Punct(Punct::new('=', Joint)), + T::Punct(Punct::new('>', Alone)), + T::Group(Group::new(Brace, + TokenStream::from_iter([ + T::Punct(Punct::new('$', Alone)), + T::Group(Group::new(Parenthesis, + TokenStream::from_iter([ + T::Punct(Punct::new('#', Alone)), + T::Group(Group::new(Bracket, + TokenStream::from_iter([ + T::Punct(Punct::new('$', Alone)), + T::Ident(Ident::new("meta", c())), + ]) + )), + ]) + )), + T::Punct(Punct::new('*', Alone)), + T::Punct(Punct::new('#', Alone)), + T::Group(Group::new(Bracket, + TokenStream::from_iter([ + T::Ident(Ident::new("allow", c())), + T::Group(Group::new(Parenthesis, + TokenStream::from_iter([ + T::Ident(Ident::new("unused", c())), + ]) + )), + ]) + )), + T::Punct(Punct::new('$', Alone)), + T::Ident(Ident::new("vis", c())), + T::Ident(Ident::new("unsafe", c())), + T::Ident(Ident::new("extern", c())), + T::Literal(Literal::string("C")), + T::Ident(Ident::new("fn", c())), + T::Punct(Punct::new('$', Alone)), + T::Ident(Ident::new("ident", c())), + T::Group(Group::new(Parenthesis, + TokenStream::new() + )), + T::Punct(Punct::new('$', Alone)), + T::Ident(Ident::new("block", c())), + T::Punct(Punct::new('#', Alone)), + T::Group(Group::new(Bracket, + TokenStream::from_iter([ + T::Ident(Ident::new("doc", c())), + T::Group(Group::new(Parenthesis, + TokenStream::from_iter([ + T::Ident(Ident::new("hidden", c())), + ]) + )), + ]) + )), + T::Punct(Punct::new('#', Alone)), + T::Group(Group::new(Bracket, + TokenStream::from_iter([ + T::Ident(Ident::new("allow", c())), + T::Group(Group::new(Parenthesis, + TokenStream::from_iter([ + T::Ident(Ident::new("unused", c())), + T::Punct(Punct::new(',', Alone)), + T::Ident(Ident::new("non_snake_case", c())), + ]) + )), + ]) + )), + T::Ident(Ident::new("mod", c())), + T::Punct(Punct::new('$', Alone)), + T::Ident(Ident::new("name", c())), + T::Group(Group::new(Brace, + TokenStream::from_iter([ + T::Ident(Ident::new("super", c())), + T::Punct(Punct::new(':', Joint)), + T::Punct(Punct::new(':', Alone)), + T::Punct(Punct::new('$', Alone)), + T::Ident(Ident::new("macros", c())), + T::Punct(Punct::new(':', Joint)), + T::Punct(Punct::new(':', Alone)), + T::Ident(Ident::new("ctor_raw", c())), + T::Punct(Punct::new('!', Alone)), + T::Group(Group::new(Parenthesis, + TokenStream::from_iter([ + T::Punct(Punct::new('$', Alone)), + T::Ident(Ident::new("used", c())), + T::Punct(Punct::new('#', Alone)), + T::Group(Group::new(Bracket, + TokenStream::from_iter([ + T::Ident(Ident::new("allow", c())), + T::Group(Group::new(Parenthesis, + TokenStream::from_iter([ + T::Ident(Ident::new("non_upper_case_globals", c())), + T::Punct(Punct::new(',', Alone)), + T::Ident(Ident::new("non_snake_case", c())), + ]) + )), + ]) + )), + T::Punct(Punct::new('#', Alone)), + T::Group(Group::new(Bracket, + TokenStream::from_iter([ + T::Ident(Ident::new("doc", c())), + T::Group(Group::new(Parenthesis, + TokenStream::from_iter([ + T::Ident(Ident::new("hidden", c())), + ]) + )), + ]) + )), + T::Ident(Ident::new("static", c())), + T::Punct(Punct::new('$', Alone)), + T::Ident(Ident::new("name", c())), + T::Punct(Punct::new(':', Alone)), + T::Ident(Ident::new("unsafe", c())), + T::Ident(Ident::new("extern", c())), + T::Literal(Literal::string("C")), + T::Ident(Ident::new("fn", c())), + T::Group(Group::new(Parenthesis, + TokenStream::new() + )), + T::Punct(Punct::new('-', Joint)), + T::Punct(Punct::new('>', Alone)), + T::Ident(Ident::new("usize", c())), + T::Punct(Punct::new('=', Alone)), + T::Group(Group::new(Brace, + TokenStream::from_iter([ + T::Punct(Punct::new('#', Alone)), + T::Group(Group::new(Bracket, + TokenStream::from_iter([ + T::Ident(Ident::new("allow", c())), + T::Group(Group::new(Parenthesis, + TokenStream::from_iter([ + T::Ident(Ident::new("non_snake_case", c())), + ]) + )), + ]) + )), + T::Punct(Punct::new('#', Alone)), + T::Group(Group::new(Bracket, + TokenStream::from_iter([ + T::Ident(Ident::new("cfg_attr", c())), + T::Group(Group::new(Parenthesis, + TokenStream::from_iter([ + T::Ident(Ident::new("any", c())), + T::Group(Group::new(Parenthesis, + TokenStream::from_iter([ + T::Ident(Ident::new("target_os", c())), + T::Punct(Punct::new('=', Alone)), + T::Literal(Literal::string("linux")), + T::Punct(Punct::new(',', Alone)), + T::Ident(Ident::new("target_os", c())), + T::Punct(Punct::new('=', Alone)), + T::Literal(Literal::string("android")), + ]) + )), + T::Punct(Punct::new(',', Alone)), + T::Ident(Ident::new("link_section", c())), + T::Punct(Punct::new('=', Alone)), + T::Literal(Literal::string(".text.startup")), + ]) + )), + ]) + )), + T::Ident(Ident::new("unsafe", c())), + T::Ident(Ident::new("extern", c())), + T::Literal(Literal::string("C")), + T::Ident(Ident::new("fn", c())), + T::Punct(Punct::new('$', Alone)), + T::Ident(Ident::new("name", c())), + T::Group(Group::new(Parenthesis, + TokenStream::new() + )), + T::Punct(Punct::new('-', Joint)), + T::Punct(Punct::new('>', Alone)), + T::Ident(Ident::new("usize", c())), + T::Group(Group::new(Brace, + TokenStream::from_iter([ + T::Ident(Ident::new("do_atexit", c())), + T::Group(Group::new(Parenthesis, + TokenStream::from_iter([ + T::Ident(Ident::new("__dtor", c())), + ]) + )), + T::Punct(Punct::new(';', Alone)), + T::Literal(Literal::usize_unsuffixed(0)), + ]) + )), + T::Punct(Punct::new('$', Alone)), + T::Ident(Ident::new("name", c())), + ]) + )), + T::Punct(Punct::new(';', Alone)), + ]) + )), + T::Punct(Punct::new(';', Alone)), + T::Punct(Punct::new('#', Alone)), + T::Group(Group::new(Bracket, + TokenStream::from_iter([ + T::Ident(Ident::new("cfg", c())), + T::Group(Group::new(Parenthesis, + TokenStream::from_iter([ + T::Ident(Ident::new("not", c())), + T::Group(Group::new(Parenthesis, + TokenStream::from_iter([ + T::Ident(Ident::new("target_vendor", c())), + T::Punct(Punct::new('=', Alone)), + T::Literal(Literal::string("apple")), + ]) + )), + ]) + )), + ]) + )), + T::Punct(Punct::new('#', Alone)), + T::Group(Group::new(Bracket, + TokenStream::from_iter([ + T::Ident(Ident::new("cfg_attr", c())), + T::Group(Group::new(Parenthesis, + TokenStream::from_iter([ + T::Ident(Ident::new("any", c())), + T::Group(Group::new(Parenthesis, + TokenStream::from_iter([ + T::Ident(Ident::new("target_os", c())), + T::Punct(Punct::new('=', Alone)), + T::Literal(Literal::string("linux")), + T::Punct(Punct::new(',', Alone)), + T::Ident(Ident::new("target_os", c())), + T::Punct(Punct::new('=', Alone)), + T::Literal(Literal::string("android")), + ]) + )), + T::Punct(Punct::new(',', Alone)), + T::Ident(Ident::new("link_section", c())), + T::Punct(Punct::new('=', Alone)), + T::Literal(Literal::string(".text.exit")), + ]) + )), + ]) + )), + T::Ident(Ident::new("unsafe", c())), + T::Ident(Ident::new("extern", c())), + T::Literal(Literal::string("C")), + T::Ident(Ident::new("fn", c())), + T::Ident(Ident::new("__dtor", c())), + T::Group(Group::new(Parenthesis, + TokenStream::new() + )), + T::Group(Group::new(Brace, + TokenStream::from_iter([ + T::Ident(Ident::new("super", c())), + T::Punct(Punct::new(':', Joint)), + T::Punct(Punct::new(':', Alone)), + T::Punct(Punct::new('$', Alone)), + T::Ident(Ident::new("ident", c())), + T::Group(Group::new(Parenthesis, + TokenStream::new() + )), + ]) + )), + T::Punct(Punct::new('#', Alone)), + T::Group(Group::new(Bracket, + TokenStream::from_iter([ + T::Ident(Ident::new("cfg", c())), + T::Group(Group::new(Parenthesis, + TokenStream::from_iter([ + T::Ident(Ident::new("target_vendor", c())), + T::Punct(Punct::new('=', Alone)), + T::Literal(Literal::string("apple")), + ]) + )), + ]) + )), + T::Ident(Ident::new("unsafe", c())), + T::Ident(Ident::new("extern", c())), + T::Literal(Literal::string("C")), + T::Ident(Ident::new("fn", c())), + T::Ident(Ident::new("__dtor", c())), + T::Group(Group::new(Parenthesis, + TokenStream::from_iter([ + T::Ident(Ident::new("_", c())), + T::Punct(Punct::new(':', Alone)), + T::Punct(Punct::new('*', Alone)), + T::Ident(Ident::new("const", c())), + T::Ident(Ident::new("u8", c())), + ]) + )), + T::Group(Group::new(Brace, + TokenStream::from_iter([ + T::Ident(Ident::new("super", c())), + T::Punct(Punct::new(':', Joint)), + T::Punct(Punct::new(':', Alone)), + T::Punct(Punct::new('$', Alone)), + T::Ident(Ident::new("ident", c())), + T::Group(Group::new(Parenthesis, + TokenStream::new() + )), + ]) + )), + T::Punct(Punct::new('#', Alone)), + T::Group(Group::new(Bracket, + TokenStream::from_iter([ + T::Ident(Ident::new("cfg", c())), + T::Group(Group::new(Parenthesis, + TokenStream::from_iter([ + T::Ident(Ident::new("not", c())), + T::Group(Group::new(Parenthesis, + TokenStream::from_iter([ + T::Ident(Ident::new("target_vendor", c())), + T::Punct(Punct::new('=', Alone)), + T::Literal(Literal::string("apple")), + ]) + )), + ]) + )), + ]) + )), + T::Punct(Punct::new('#', Alone)), + T::Group(Group::new(Bracket, + TokenStream::from_iter([ + T::Ident(Ident::new("inline", c())), + T::Group(Group::new(Parenthesis, + TokenStream::from_iter([ + T::Ident(Ident::new("always", c())), + ]) + )), + ]) + )), + T::Ident(Ident::new("pub", c())), + T::Group(Group::new(Parenthesis, + TokenStream::from_iter([ + T::Ident(Ident::new("super", c())), + ]) + )), + T::Ident(Ident::new("unsafe", c())), + T::Ident(Ident::new("fn", c())), + T::Ident(Ident::new("do_atexit", c())), + T::Group(Group::new(Parenthesis, + TokenStream::from_iter([ + T::Ident(Ident::new("cb", c())), + T::Punct(Punct::new(':', Alone)), + T::Ident(Ident::new("unsafe", c())), + T::Ident(Ident::new("extern", c())), + T::Ident(Ident::new("fn", c())), + T::Group(Group::new(Parenthesis, + TokenStream::new() + )), + ]) + )), + T::Group(Group::new(Brace, + TokenStream::from_iter([ + T::Ident(Ident::new("extern", c())), + T::Literal(Literal::string("C")), + T::Group(Group::new(Brace, + TokenStream::from_iter([ + T::Ident(Ident::new("fn", c())), + T::Ident(Ident::new("atexit", c())), + T::Group(Group::new(Parenthesis, + TokenStream::from_iter([ + T::Ident(Ident::new("cb", c())), + T::Punct(Punct::new(':', Alone)), + T::Ident(Ident::new("unsafe", c())), + T::Ident(Ident::new("extern", c())), + T::Ident(Ident::new("fn", c())), + T::Group(Group::new(Parenthesis, + TokenStream::new() + )), + ]) + )), + T::Punct(Punct::new(';', Alone)), + ]) + )), + T::Ident(Ident::new("atexit", c())), + T::Group(Group::new(Parenthesis, + TokenStream::from_iter([ + T::Ident(Ident::new("cb", c())), + ]) + )), + T::Punct(Punct::new(';', Alone)), + ]) + )), + T::Punct(Punct::new('#', Alone)), + T::Group(Group::new(Bracket, + TokenStream::from_iter([ + T::Ident(Ident::new("cfg", c())), + T::Group(Group::new(Parenthesis, + TokenStream::from_iter([ + T::Ident(Ident::new("target_vendor", c())), + T::Punct(Punct::new('=', Alone)), + T::Literal(Literal::string("apple")), + ]) + )), + ]) + )), + T::Punct(Punct::new('#', Alone)), + T::Group(Group::new(Bracket, + TokenStream::from_iter([ + T::Ident(Ident::new("inline", c())), + T::Group(Group::new(Parenthesis, + TokenStream::from_iter([ + T::Ident(Ident::new("always", c())), + ]) + )), + ]) + )), + T::Ident(Ident::new("pub", c())), + T::Group(Group::new(Parenthesis, + TokenStream::from_iter([ + T::Ident(Ident::new("super", c())), + ]) + )), + T::Ident(Ident::new("unsafe", c())), + T::Ident(Ident::new("fn", c())), + T::Ident(Ident::new("do_atexit", c())), + T::Group(Group::new(Parenthesis, + TokenStream::from_iter([ + T::Ident(Ident::new("cb", c())), + T::Punct(Punct::new(':', Alone)), + T::Ident(Ident::new("unsafe", c())), + T::Ident(Ident::new("extern", c())), + T::Ident(Ident::new("fn", c())), + T::Group(Group::new(Parenthesis, + TokenStream::from_iter([ + T::Ident(Ident::new("_", c())), + T::Punct(Punct::new(':', Alone)), + T::Punct(Punct::new('*', Alone)), + T::Ident(Ident::new("const", c())), + T::Ident(Ident::new("u8", c())), + ]) + )), + ]) + )), + T::Group(Group::new(Brace, + TokenStream::from_iter([ + T::Ident(Ident::new("extern", c())), + T::Literal(Literal::string("C")), + T::Group(Group::new(Brace, + TokenStream::from_iter([ + T::Ident(Ident::new("static", c())), + T::Ident(Ident::new("__dso_handle", c())), + T::Punct(Punct::new(':', Alone)), + T::Punct(Punct::new('*', Alone)), + T::Ident(Ident::new("const", c())), + T::Ident(Ident::new("u8", c())), + T::Punct(Punct::new(';', Alone)), + T::Ident(Ident::new("fn", c())), + T::Ident(Ident::new("__cxa_atexit", c())), + T::Group(Group::new(Parenthesis, + TokenStream::from_iter([ + T::Ident(Ident::new("cb", c())), + T::Punct(Punct::new(':', Alone)), + T::Ident(Ident::new("unsafe", c())), + T::Ident(Ident::new("extern", c())), + T::Ident(Ident::new("fn", c())), + T::Group(Group::new(Parenthesis, + TokenStream::from_iter([ + T::Ident(Ident::new("_", c())), + T::Punct(Punct::new(':', Alone)), + T::Punct(Punct::new('*', Alone)), + T::Ident(Ident::new("const", c())), + T::Ident(Ident::new("u8", c())), + ]) + )), + T::Punct(Punct::new(',', Alone)), + T::Ident(Ident::new("arg", c())), + T::Punct(Punct::new(':', Alone)), + T::Punct(Punct::new('*', Alone)), + T::Ident(Ident::new("const", c())), + T::Ident(Ident::new("u8", c())), + T::Punct(Punct::new(',', Alone)), + T::Ident(Ident::new("dso_handle", c())), + T::Punct(Punct::new(':', Alone)), + T::Punct(Punct::new('*', Alone)), + T::Ident(Ident::new("const", c())), + T::Ident(Ident::new("u8", c())), + ]) + )), + T::Punct(Punct::new(';', Alone)), + ]) + )), + T::Ident(Ident::new("__cxa_atexit", c())), + T::Group(Group::new(Parenthesis, + TokenStream::from_iter([ + T::Ident(Ident::new("cb", c())), + T::Punct(Punct::new(',', Alone)), + T::Ident(Ident::new("core", c())), + T::Punct(Punct::new(':', Joint)), + T::Punct(Punct::new(':', Alone)), + T::Ident(Ident::new("ptr", c())), + T::Punct(Punct::new(':', Joint)), + T::Punct(Punct::new(':', Alone)), + T::Ident(Ident::new("null", c())), + T::Group(Group::new(Parenthesis, + TokenStream::new() + )), + T::Punct(Punct::new(',', Alone)), + T::Ident(Ident::new("__dso_handle", c())), + ]) + )), + T::Punct(Punct::new(';', Alone)), + ]) + )), + ]) + )), + ]) + )), + T::Punct(Punct::new(';', Alone)), + ]) + )), + T::Ident(Ident::new("pub", c())), + T::Group(Group::new(Parenthesis, + TokenStream::from_iter([ + T::Ident(Ident::new("crate", c())), + ]) + )), + T::Ident(Ident::new("use", c())), + T::Ident(Ident::new("ctor_impl", c())), + T::Punct(Punct::new(';', Alone)), + ]) +} + +pub fn ctor_raw() -> TokenStream { + TokenStream::from_iter([ + T::Ident(Ident::new("macro_rules", c())), + T::Punct(Punct::new('!', Alone)), + T::Ident(Ident::new("ctor_raw", c())), + T::Group(Group::new(Brace, + TokenStream::from_iter([ + T::Group(Group::new(Parenthesis, + TokenStream::from_iter([ + T::Punct(Punct::new('$', Alone)), + T::Ident(Ident::new("used", c())), + T::Punct(Punct::new(':', Alone)), + T::Ident(Ident::new("meta", c())), + T::Punct(Punct::new('$', Alone)), + T::Group(Group::new(Parenthesis, + TokenStream::from_iter([ + T::Punct(Punct::new('$', Alone)), + T::Ident(Ident::new("block", c())), + T::Punct(Punct::new(':', Alone)), + T::Ident(Ident::new("tt", c())), + ]) + )), + T::Punct(Punct::new('+', Alone)), + ]) + )), + T::Punct(Punct::new('=', Joint)), + T::Punct(Punct::new('>', Alone)), + T::Group(Group::new(Brace, + TokenStream::from_iter([ + T::Punct(Punct::new('#', Alone)), + T::Group(Group::new(Bracket, + TokenStream::from_iter([ + T::Ident(Ident::new("cfg", c())), + T::Group(Group::new(Parenthesis, + TokenStream::from_iter([ + T::Ident(Ident::new("not", c())), + T::Group(Group::new(Parenthesis, + TokenStream::from_iter([ + T::Ident(Ident::new("any", c())), + T::Group(Group::new(Parenthesis, + TokenStream::from_iter([ + T::Ident(Ident::new("target_os", c())), + T::Punct(Punct::new('=', Alone)), + T::Literal(Literal::string("linux")), + T::Punct(Punct::new(',', Alone)), + T::Ident(Ident::new("target_os", c())), + T::Punct(Punct::new('=', Alone)), + T::Literal(Literal::string("android")), + T::Punct(Punct::new(',', Alone)), + T::Ident(Ident::new("target_os", c())), + T::Punct(Punct::new('=', Alone)), + T::Literal(Literal::string("freebsd")), + T::Punct(Punct::new(',', Alone)), + T::Ident(Ident::new("target_os", c())), + T::Punct(Punct::new('=', Alone)), + T::Literal(Literal::string("netbsd")), + T::Punct(Punct::new(',', Alone)), + T::Ident(Ident::new("target_os", c())), + T::Punct(Punct::new('=', Alone)), + T::Literal(Literal::string("openbsd")), + T::Punct(Punct::new(',', Alone)), + T::Ident(Ident::new("target_os", c())), + T::Punct(Punct::new('=', Alone)), + T::Literal(Literal::string("dragonfly")), + T::Punct(Punct::new(',', Alone)), + T::Ident(Ident::new("target_os", c())), + T::Punct(Punct::new('=', Alone)), + T::Literal(Literal::string("illumos")), + T::Punct(Punct::new(',', Alone)), + T::Ident(Ident::new("target_os", c())), + T::Punct(Punct::new('=', Alone)), + T::Literal(Literal::string("haiku")), + T::Punct(Punct::new(',', Alone)), + T::Ident(Ident::new("target_vendor", c())), + T::Punct(Punct::new('=', Alone)), + T::Literal(Literal::string("apple")), + T::Punct(Punct::new(',', Alone)), + T::Ident(Ident::new("windows", c())), + ]) + )), + ]) + )), + ]) + )), + ]) + )), + T::Ident(Ident::new("compile_error", c())), + T::Punct(Punct::new('!', Alone)), + T::Group(Group::new(Parenthesis, + TokenStream::from_iter([ + T::Literal(Literal::string("#[ctor] is not supported on the current target")), + ]) + )), + T::Punct(Punct::new(';', Alone)), + T::Punct(Punct::new('#', Alone)), + T::Group(Group::new(Bracket, + TokenStream::from_iter([ + T::Punct(Punct::new('$', Alone)), + T::Ident(Ident::new("used", c())), + ]) + )), + T::Punct(Punct::new('#', Alone)), + T::Group(Group::new(Bracket, + TokenStream::from_iter([ + T::Ident(Ident::new("cfg_attr", c())), + T::Group(Group::new(Parenthesis, + TokenStream::from_iter([ + T::Ident(Ident::new("any", c())), + T::Group(Group::new(Parenthesis, + TokenStream::from_iter([ + T::Ident(Ident::new("target_os", c())), + T::Punct(Punct::new('=', Alone)), + T::Literal(Literal::string("linux")), + T::Punct(Punct::new(',', Alone)), + T::Ident(Ident::new("target_os", c())), + T::Punct(Punct::new('=', Alone)), + T::Literal(Literal::string("android")), + ]) + )), + T::Punct(Punct::new(',', Alone)), + T::Ident(Ident::new("link_section", c())), + T::Punct(Punct::new('=', Alone)), + T::Literal(Literal::string(".init_array")), + ]) + )), + ]) + )), + T::Punct(Punct::new('#', Alone)), + T::Group(Group::new(Bracket, + TokenStream::from_iter([ + T::Ident(Ident::new("cfg_attr", c())), + T::Group(Group::new(Parenthesis, + TokenStream::from_iter([ + T::Ident(Ident::new("target_os", c())), + T::Punct(Punct::new('=', Alone)), + T::Literal(Literal::string("freebsd")), + T::Punct(Punct::new(',', Alone)), + T::Ident(Ident::new("link_section", c())), + T::Punct(Punct::new('=', Alone)), + T::Literal(Literal::string(".init_array")), + ]) + )), + ]) + )), + T::Punct(Punct::new('#', Alone)), + T::Group(Group::new(Bracket, + TokenStream::from_iter([ + T::Ident(Ident::new("cfg_attr", c())), + T::Group(Group::new(Parenthesis, + TokenStream::from_iter([ + T::Ident(Ident::new("target_os", c())), + T::Punct(Punct::new('=', Alone)), + T::Literal(Literal::string("netbsd")), + T::Punct(Punct::new(',', Alone)), + T::Ident(Ident::new("link_section", c())), + T::Punct(Punct::new('=', Alone)), + T::Literal(Literal::string(".init_array")), + ]) + )), + ]) + )), + T::Punct(Punct::new('#', Alone)), + T::Group(Group::new(Bracket, + TokenStream::from_iter([ + T::Ident(Ident::new("cfg_attr", c())), + T::Group(Group::new(Parenthesis, + TokenStream::from_iter([ + T::Ident(Ident::new("target_os", c())), + T::Punct(Punct::new('=', Alone)), + T::Literal(Literal::string("openbsd")), + T::Punct(Punct::new(',', Alone)), + T::Ident(Ident::new("link_section", c())), + T::Punct(Punct::new('=', Alone)), + T::Literal(Literal::string(".init_array")), + ]) + )), + ]) + )), + T::Punct(Punct::new('#', Alone)), + T::Group(Group::new(Bracket, + TokenStream::from_iter([ + T::Ident(Ident::new("cfg_attr", c())), + T::Group(Group::new(Parenthesis, + TokenStream::from_iter([ + T::Ident(Ident::new("target_os", c())), + T::Punct(Punct::new('=', Alone)), + T::Literal(Literal::string("dragonfly")), + T::Punct(Punct::new(',', Alone)), + T::Ident(Ident::new("link_section", c())), + T::Punct(Punct::new('=', Alone)), + T::Literal(Literal::string(".init_array")), + ]) + )), + ]) + )), + T::Punct(Punct::new('#', Alone)), + T::Group(Group::new(Bracket, + TokenStream::from_iter([ + T::Ident(Ident::new("cfg_attr", c())), + T::Group(Group::new(Parenthesis, + TokenStream::from_iter([ + T::Ident(Ident::new("target_os", c())), + T::Punct(Punct::new('=', Alone)), + T::Literal(Literal::string("illumos")), + T::Punct(Punct::new(',', Alone)), + T::Ident(Ident::new("link_section", c())), + T::Punct(Punct::new('=', Alone)), + T::Literal(Literal::string(".init_array")), + ]) + )), + ]) + )), + T::Punct(Punct::new('#', Alone)), + T::Group(Group::new(Bracket, + TokenStream::from_iter([ + T::Ident(Ident::new("cfg_attr", c())), + T::Group(Group::new(Parenthesis, + TokenStream::from_iter([ + T::Ident(Ident::new("target_os", c())), + T::Punct(Punct::new('=', Alone)), + T::Literal(Literal::string("haiku")), + T::Punct(Punct::new(',', Alone)), + T::Ident(Ident::new("link_section", c())), + T::Punct(Punct::new('=', Alone)), + T::Literal(Literal::string(".init_array")), + ]) + )), + ]) + )), + T::Punct(Punct::new('#', Alone)), + T::Group(Group::new(Bracket, + TokenStream::from_iter([ + T::Ident(Ident::new("cfg_attr", c())), + T::Group(Group::new(Parenthesis, + TokenStream::from_iter([ + T::Ident(Ident::new("target_vendor", c())), + T::Punct(Punct::new('=', Alone)), + T::Literal(Literal::string("apple")), + T::Punct(Punct::new(',', Alone)), + T::Ident(Ident::new("link_section", c())), + T::Punct(Punct::new('=', Alone)), + T::Literal(Literal::string("__DATA,__mod_init_func")), + ]) + )), + ]) + )), + T::Punct(Punct::new('#', Alone)), + T::Group(Group::new(Bracket, + TokenStream::from_iter([ + T::Ident(Ident::new("cfg_attr", c())), + T::Group(Group::new(Parenthesis, + TokenStream::from_iter([ + T::Ident(Ident::new("windows", c())), + T::Punct(Punct::new(',', Alone)), + T::Ident(Ident::new("link_section", c())), + T::Punct(Punct::new('=', Alone)), + T::Literal(Literal::string(".CRT$XCU")), + ]) + )), + ]) + )), + T::Punct(Punct::new('$', Alone)), + T::Group(Group::new(Parenthesis, + TokenStream::from_iter([ + T::Punct(Punct::new('$', Alone)), + T::Ident(Ident::new("block", c())), + ]) + )), + T::Punct(Punct::new('+', Alone)), + ]) + )), + ]) + )), + T::Ident(Ident::new("pub", c())), + T::Group(Group::new(Parenthesis, + TokenStream::from_iter([ + T::Ident(Ident::new("crate", c())), + ]) + )), + T::Ident(Ident::new("use", c())), + T::Ident(Ident::new("ctor_raw", c())), + T::Punct(Punct::new(';', Alone)), + ]) +} + diff --git a/ctor/src/lib.rs b/ctor/src/lib.rs index 289df48..566f47d 100644 --- a/ctor/src/lib.rs +++ b/ctor/src/lib.rs @@ -28,36 +28,13 @@ // https://reviews.llvm.org/D45578 extern crate proc_macro; -extern crate syn; -#[macro_use] -extern crate quote; -use proc_macro::TokenStream; +use std::iter::FromIterator; -/// Attributes required to mark a function as a constructor. This may be exposed in the future if we determine -/// it to be stable. -#[doc(hidden)] -macro_rules! ctor_attributes { - () => { - // Linux/ELF: https://www.exploit-db.com/papers/13234 +use proc_macro::*; - // Mac details: https://blog.timac.org/2016/0716-constructor-and-destructor-attributes/ - - // Why .CRT$XCU on Windows? https://www.cnblogs.com/sunkang/archive/2011/05/24/2055635.html - // 'I'=C init, 'C'=C++ init, 'P'=Pre-terminators and 'T'=Terminators - quote!( - #[cfg_attr(any(target_os = "linux", target_os = "android"), link_section = ".init_array")] - #[cfg_attr(target_os = "freebsd", link_section = ".init_array")] - #[cfg_attr(target_os = "netbsd", link_section = ".init_array")] - #[cfg_attr(target_os = "openbsd", link_section = ".init_array")] - #[cfg_attr(target_os = "dragonfly", link_section = ".init_array")] - #[cfg_attr(target_os = "illumos", link_section = ".init_array")] - #[cfg_attr(target_os = "haiku", link_section = ".init_array")] - #[cfg_attr(target_vendor = "apple", link_section = "__DATA,__mod_init_func")] - #[cfg_attr(windows, link_section = ".CRT$XCU")] - ) - }; -} +#[rustfmt::skip] +mod gen; /// Marks a function or static variable as a library/executable constructor. /// This uses OS-specific linker sections to call a specific function at @@ -91,6 +68,7 @@ macro_rules! ctor_attributes { /// ```rust /// # #![cfg_attr(feature="used_linker", feature(used_with_arg))] /// # extern crate ctor; +/// # mod test { /// # use ctor::*; /// # use std::sync::atomic::{AtomicBool, Ordering}; /// static INITED: AtomicBool = AtomicBool::new(false); @@ -99,26 +77,29 @@ macro_rules! ctor_attributes { /// fn foo() { /// INITED.store(true, Ordering::SeqCst); /// } +/// # } /// ``` /// /// Initialize a `HashMap` at startup time: /// /// ```rust +/// # #![cfg_attr(feature="used_linker", feature(used_with_arg))] /// # extern crate ctor; +/// # mod test { /// # use std::collections::HashMap; /// # use ctor::*; /// #[ctor] -/// static STATIC_CTOR: HashMap = { +/// pub static STATIC_CTOR: HashMap = { /// let mut m = HashMap::new(); /// for i in 0..100 { /// m.insert(i, format!("x*100={}", i*100)); /// } /// m /// }; -/// +/// # } /// # pub fn main() { -/// # assert_eq!(STATIC_CTOR.len(), 100); -/// # assert_eq!(STATIC_CTOR[&20], "x*100=2000"); +/// # assert_eq!(test::STATIC_CTOR.len(), 100); +/// # assert_eq!(test::STATIC_CTOR[&20], "x*100=2000"); /// # } /// ``` /// @@ -145,146 +126,26 @@ macro_rules! ctor_attributes { /// }; /// ``` #[proc_macro_attribute] -pub fn ctor(_attribute: TokenStream, function: TokenStream) -> TokenStream { - let item: syn::Item = syn::parse_macro_input!(function); - if let syn::Item::Fn(function) = item { - validate_item("ctor", &function); - - let syn::ItemFn { - attrs, - block, - vis, - sig: - syn::Signature { - ident, - unsafety, - constness, - abi, - .. - }, - .. - } = function; - - let ctor_ident = - syn::parse_str::(format!("{}___rust_ctor___ctor", ident).as_ref()) - .expect("Unable to create identifier"); - - let tokens = ctor_attributes!(); - - let used = if cfg!(feature = "used_linker") { - quote!(#[used(linker)]) - } else { - quote!(#[used]) - }; - - let output = quote!( - #[cfg(not(any(target_os = "linux", target_os = "android", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd", target_os = "dragonfly", target_os = "illumos", target_os = "haiku", target_vendor = "apple", windows)))] - compile_error!("#[ctor] is not supported on the current target"); - - #(#attrs)* - #vis #unsafety extern #abi #constness fn #ident() #block - - #used - #[allow(non_upper_case_globals, non_snake_case)] - #[doc(hidden)] - #tokens - static #ctor_ident - : - unsafe extern "C" fn() -> usize = - { - #[allow(non_snake_case)] - #[cfg_attr(any(target_os = "linux", target_os = "android"), link_section = ".text.startup")] - unsafe extern "C" fn #ctor_ident() -> usize { #ident(); 0 }; - #ctor_ident - } - ; - ); - - // eprintln!("{}", output); - - output.into() - } else if let syn::Item::Static(var) = item { - let syn::ItemStatic { - ident, - mutability, - expr, - attrs, - ty, - vis, - .. - } = var; - - if matches!(mutability, syn::StaticMutability::Mut(_)) { - panic!("#[ctor]-annotated static objects must not be mutable"); - } - - if attrs.iter().any(|attr| { - attr.path() - .segments - .iter() - .any(|segment| segment.ident == "no_mangle") - }) { - panic!("#[ctor]-annotated static objects do not support #[no_mangle]"); - } - - let ctor_ident = - syn::parse_str::(format!("{}___rust_ctor___ctor", ident).as_ref()) - .expect("Unable to create identifier"); - let storage_ident = - syn::parse_str::(format!("{}___rust_ctor___storage", ident).as_ref()) - .expect("Unable to create identifier"); - - let tokens = ctor_attributes!(); - let output = quote!( - #[cfg(not(any(target_os = "linux", target_os = "android", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd", target_os = "dragonfly", target_os = "illumos", target_os = "haiku", target_vendor = "apple", windows)))] - compile_error!("#[ctor] is not supported on the current target"); - - // This is mutable, but only by this macro code! - static mut #storage_ident: Option<#ty> = None; - - #[doc(hidden)] - #[allow(non_camel_case_types)] - #vis struct #ident { - _data: ::core::marker::PhantomData - } - - #(#attrs)* - #vis static #ident: #ident<#ty> = #ident { - _data: ::core::marker::PhantomData::<#ty> - }; - - impl ::core::ops::Deref for #ident<#ty> { - type Target = #ty; - fn deref(&self) -> &'static #ty { - unsafe { - #storage_ident.as_ref().unwrap() - } +pub fn ctor(_attribute: TokenStream, item: TokenStream) -> TokenStream { + fn identify_item(item: TokenStream) -> (String, String) { + let mut ctor_type = String::new(); + for token in item { + if let TokenTree::Ident(ident) = token { + let ident = ident.to_string(); + if !ctor_type.is_empty() { + return (ident, ctor_type); + } + if ident == "fn" || ident == "static" { + ctor_type = ident; } } + } - #[used] - #[allow(non_upper_case_globals)] - #tokens - static #ctor_ident - : - unsafe extern "C" fn() = { - #[cfg_attr(any(target_os = "linux", target_os = "android"), link_section = ".text.startup")] - extern "C" fn initer() { - let val = Some(#expr); - // Only write the value to `storage_ident` on startup - unsafe { - #storage_ident = val; - } - }; initer } - ; - ); - - // eprintln!("{}", output); - - output.into() - } else { - panic!("#[ctor] items must be functions or static globals"); + panic!("#[ctor] may only be applied to `fn` or `static` items"); } + + let (name, ctor_type) = identify_item(item.clone()); + generate(&name, &ctor_type, item) } /// Marks a function as a library/executable destructor. This uses OS-specific @@ -297,6 +158,7 @@ pub fn ctor(_attribute: TokenStream, function: TokenStream) -> TokenStream { /// it allows you to use `stdout` in your handlers. /// /// ```rust +/// # #![cfg_attr(feature="used_linker", feature(used_with_arg))] /// # extern crate ctor; /// # use ctor::*; /// # fn main() {} @@ -307,107 +169,82 @@ pub fn ctor(_attribute: TokenStream, function: TokenStream) -> TokenStream { /// } /// ``` #[proc_macro_attribute] -pub fn dtor(_attribute: TokenStream, function: TokenStream) -> TokenStream { - let function: syn::ItemFn = syn::parse_macro_input!(function); - validate_item("dtor", &function); - - let syn::ItemFn { - attrs, - block, - vis, - sig: - syn::Signature { - ident, - unsafety, - constness, - abi, - .. - }, - .. - } = function; - - let mod_ident = syn::parse_str::(format!("{}___rust_dtor___mod", ident).as_ref()) - .expect("Unable to create identifier"); - - let dtor_ident = syn::parse_str::(format!("{}___rust_dtor___dtor", ident).as_ref()) - .expect("Unable to create identifier"); - - let tokens = ctor_attributes!(); - let output = quote!( - #[cfg(not(any(target_os = "linux", target_os = "android", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd", target_os = "dragonfly", target_os = "illumos", target_os = "haiku", target_vendor = "apple", windows)))] - compile_error!("#[dtor] is not supported on the current target"); - - #(#attrs)* - #vis #unsafety extern #abi #constness fn #ident() #block - - mod #mod_ident { - use super::#ident; - - // Note that we avoid a dep on the libc crate by linking directly to atexit functions - - #[cfg(not(target_vendor = "apple"))] - #[inline(always)] - unsafe fn do_atexit(cb: unsafe extern fn()) { - extern "C" { - fn atexit(cb: unsafe extern fn()); +pub fn dtor(_attribute: TokenStream, item: TokenStream) -> TokenStream { + fn identify_item(item: TokenStream) -> (String, String) { + let mut ctor_type = String::new(); + for token in item { + if let TokenTree::Ident(ident) = token { + let ident = ident.to_string(); + if !ctor_type.is_empty() { + return (ident, ctor_type); } - atexit(cb); - } - - // For platforms that have __cxa_atexit, we register the dtor as scoped to dso_handle - #[cfg(target_vendor = "apple")] - #[inline(always)] - unsafe fn do_atexit(cb: unsafe extern fn(_: *const u8)) { - extern "C" { - static __dso_handle: *const u8; - fn __cxa_atexit(cb: unsafe extern fn(_: *const u8), arg: *const u8, dso_handle: *const u8); + if ident == "fn" { + "dtor".clone_into(&mut ctor_type); } - __cxa_atexit(cb, core::ptr::null(), __dso_handle); } - - #[used] - #[allow(non_upper_case_globals)] - #tokens - static __dtor_export - : - unsafe extern "C" fn() = - { - #[cfg(not(target_vendor = "apple"))] - #[cfg_attr(any(target_os = "linux", target_os = "android"), link_section = ".text.exit")] - unsafe extern "C" fn #dtor_ident() { #ident() }; - #[cfg(target_vendor = "apple")] - unsafe extern "C" fn #dtor_ident(_: *const u8) { #ident() }; - #[cfg_attr(any(target_os = "linux", target_os = "android"), link_section = ".text.startup")] - unsafe extern fn __dtor_atexit() { - do_atexit(#dtor_ident); - }; - __dtor_atexit - }; } - ); - - // eprintln!("{}", output); - output.into() -} - -fn validate_item(typ: &str, item: &syn::ItemFn) { - let syn::ItemFn { vis, sig, .. } = item; - - // Ensure that visibility modifier is not present - match vis { - syn::Visibility::Inherited => {} - _ => panic!("#[{}] methods must not have visibility modifiers", typ), + panic!("#[dtor] may only be applied to `fn`items"); } - // No parameters allowed - if !sig.inputs.is_empty() { - panic!("#[{}] methods may not have parameters", typ); - } + let (name, ctor_type) = identify_item(item.clone()); + generate(&name, &ctor_type, item) +} - // No return type allowed - match sig.output { - syn::ReturnType::Default => {} - _ => panic!("#[{}] methods must not have return types", typ), - } +fn generate(name: &str, ctor_type: &str, item: TokenStream) -> TokenStream { + use proc_macro::TokenTree as T; + + let support_name = format!("__rust_ctor__{name}"); + let macros_name = format!("__rust_ctor_macros_{name}"); + TokenStream::from_iter([ + T::Ident(Ident::new(¯os_name, Span::call_site())), + T::Punct(Punct::new(':', Spacing::Joint)), + T::Punct(Punct::new(':', Spacing::Alone)), + T::Ident(Ident::new("ctor_impl", Span::call_site())), + T::Punct(Punct::new('!', Spacing::Alone)), + T::Group(Group::new( + Delimiter::Parenthesis, + TokenStream::from_iter([ + T::Ident(Ident::new(ctor_type, Span::call_site())), + T::Ident(Ident::new("macros", Span::call_site())), + T::Punct(Punct::new('=', Spacing::Alone)), + T::Ident(Ident::new(¯os_name, Span::call_site())), + T::Ident(Ident::new("name", Span::call_site())), + T::Punct(Punct::new('=', Spacing::Alone)), + T::Ident(Ident::new(&support_name, Span::call_site())), + T::Ident(Ident::new("used", Span::call_site())), + T::Punct(Punct::new('=', Spacing::Alone)), + T::Ident(Ident::new("used", Span::call_site())), + #[cfg(feature = "used_linker")] + T::Group(Group::new( + Delimiter::Parenthesis, + TokenStream::from_iter([T::Ident(Ident::new("linker", Span::call_site()))]), + )), + T::Ident(Ident::new("item", Span::call_site())), + T::Punct(Punct::new('=', Spacing::Alone)), + T::Group(Group::new(Delimiter::Brace, item)), + ]), + )), + T::Punct(Punct::new(';', Spacing::Alone)), + T::Punct(Punct::new('#', Spacing::Alone)), + T::Group(Group::new( + Delimiter::Bracket, + TokenStream::from_iter([ + T::Ident(Ident::new("allow", Span::call_site())), + T::Group(Group::new( + Delimiter::Parenthesis, + TokenStream::from_iter([T::Ident(Ident::new( + "non_snake_case", + Span::call_site(), + ))]), + )), + ]), + )), + T::Ident(Ident::new("mod", Span::call_site())), + T::Ident(Ident::new(¯os_name, Span::call_site())), + T::Group(Group::new( + Delimiter::Brace, + TokenStream::from_iter([gen::ctor(), gen::ctor_raw()]), + )), + ]) } diff --git a/dtor/src/lib.rs b/dtor/src/lib.rs index e69de29..8b13789 100644 --- a/dtor/src/lib.rs +++ b/dtor/src/lib.rs @@ -0,0 +1 @@ + diff --git a/tests/src/lib.rs b/tests/src/lib.rs index e70b126..81df703 100644 --- a/tests/src/lib.rs +++ b/tests/src/lib.rs @@ -38,8 +38,8 @@ mod test { #[test] fn test_initialized() { // Test to see that the ctor ran - assert_eq!(true, INITED.load(Ordering::SeqCst)); - assert_eq!(true, INITED_2.load(Ordering::SeqCst)); + assert!(INITED.load(Ordering::SeqCst)); + assert!(INITED_2.load(Ordering::SeqCst)); assert_eq!(*INITED_3, 42); } @@ -92,7 +92,7 @@ mod test { assert!( a == s || b == s || c == s || d == s, "s was unexpected:\n{}", - s.replace("\n", "\\n") + s.replace('\n', "\\n") ); } }