Skip to main content

link_section/
lib.rs

1#![doc = include_str!("../README.md")]
2#![allow(unsafe_code)]
3
4/// Declarative forms of the `#[section]` and `#[in_section(...)]` macros.
5///
6/// The declarative forms wrap and parse a proc_macro-like syntax like so, and
7/// are identical in expansion to the undecorated procedural macros. The
8/// declarative forms support the same attribute parameters as the procedural
9/// macros.
10pub mod declarative {
11    pub use crate::__in_section_parse as in_section;
12    pub use crate::__section_parse as section;
13}
14
15#[doc(hidden)]
16pub mod __support {
17    pub use crate::__add_section_link_attribute as add_section_link_attribute;
18    pub use crate::__def_section_name as def_section_name;
19    pub use crate::__get_section as get_section;
20    pub use crate::__in_section_crate as in_section_crate;
21    pub use crate::__in_section_parse as in_section_parse;
22    pub use crate::__section_parse as section_parse;
23
24    #[cfg(feature = "proc_macro")]
25    pub use link_section_proc_macro::hash;
26    #[cfg(feature = "proc_macro")]
27    pub use link_section_proc_macro::ident_concat;
28
29    /// Declares the section_name macro.
30    #[macro_export]
31    #[doc(hidden)]
32    macro_rules! __def_section_name {
33        (
34            {$(
35                $__section:ident $__type:ident => $__prefix:tt __ $__suffix:tt;
36            )*}
37            AUXILIARY = $__aux_sep:literal;
38            MAX_LENGTH = $__max_length:literal;
39            HASH_LENGTH = $__hash_length:literal;
40            VALID_SECTION_CHARS = $__valid_section_chars:literal;
41        ) => {
42            /// Internal macro for generating a section name.
43            #[macro_export]
44            #[doc(hidden)]
45            macro_rules! __section_name {
46                $(
47                    (raw $__section $__type $name:ident) => {
48                        concat!(concat! $__prefix, stringify!($name), concat! $__suffix);
49                    };
50                    (raw $__section $__type $name:ident $aux:ident) => {
51                        concat!(concat! $__prefix, stringify!($name), $__aux_sep, stringify!($aux), concat! $__suffix);
52                    };
53                    ($pattern:tt $__section $__type $name:ident) => {
54                        $crate::__support::hash!($pattern ($__prefix) $name ($__suffix) $__hash_length $__max_length $__valid_section_chars);
55                    };
56                    ($pattern:tt $__section $__type $name:ident $aux:ident) => {
57                        $crate::__support::hash!($pattern ($__prefix) ($name $__aux_sep $aux) ($__suffix) $__hash_length $__max_length $__valid_section_chars);
58                    };
59                )*
60                ($pattern:tt $unknown_section:ident $unknown_type:ident $name:ident) => {
61                    const _: () = {
62                        compile_error!("Unknown section type: `{}`/`{}`", stringify!($unknown_section), stringify!($unknown_type));
63                    };
64                };
65            }
66        };
67    }
68
69    #[cfg(feature = "proc_macro")]
70    #[doc(hidden)]
71    #[macro_export]
72    macro_rules! __add_section_link_attribute(
73        ($section:ident $type:ident $name:ident $($aux:ident)? #[$attr:ident = __] $item:item) => {
74            $crate::__section_name!(
75                (#[$attr = __] #[allow(unsafe_code)] $item)
76                $section $type $name $($aux)?
77            );
78        }
79    );
80
81    #[cfg(not(feature = "proc_macro"))]
82    #[doc(hidden)]
83    #[macro_export]
84    macro_rules! __add_section_link_attribute(
85        ($section:ident $type:ident $name:ident #[$attr:ident = __] $item:item) => {
86            #[$attr = $crate::__section_name!(
87                raw $section $type $name
88            )] $item
89        }
90    );
91
92    // \x01: "do not mangle" (ref https://github.com/rust-lang/rust-bindgen/issues/2935)
93    #[cfg(target_vendor = "apple")]
94    def_section_name! {
95        {
96            data bare =>    ("__DATA,") __ ();
97            code bare =>    ("__TEXT,") __ ();
98            data section => ("__DATA,") __ (",regular,no_dead_strip");
99            code section => ("__TEXT,") __ (",regular,no_dead_strip");
100            data start =>   ("\x01section$start$__DATA$") __ ();
101            data end =>     ("\x01section$end$__DATA$") __ ();
102        }
103        AUXILIARY = "_";
104        MAX_LENGTH = 16;
105        HASH_LENGTH = 6;
106        VALID_SECTION_CHARS = "_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
107    }
108
109    #[cfg(target_family = "wasm")]
110    def_section_name! {
111        {
112            data bare =>    (".data", ".link_section.") __ ();
113            data section => (".data", ".link_section.") __ ();
114            code bare =>    (".text", ".link_section.") __ ();
115            code section => (".text", ".link_section.") __ ();
116        }
117        AUXILIARY = ".";
118        MAX_LENGTH = 16;
119        HASH_LENGTH = 6;
120        VALID_SECTION_CHARS = "_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
121    }
122
123    #[cfg(all(
124        not(target_vendor = "apple"),
125        not(target_vendor = "pc"),
126        not(target_family = "wasm")
127    ))]
128    def_section_name! {
129        {
130            data bare =>    ("_data", "_link_section_") __ ();
131            data section => ("_data", "_link_section_") __ ();
132            data start =>   ("__start_", "_data", "_link_section_") __ ();
133            data end =>     ("__stop_", "_data", "_link_section_") __ ();
134            code bare =>    ("_text", "_link_section_") __ ();
135            code section => ("_text", "_link_section_") __ ();
136            code start =>   ("__start_", "_text", "_link_section_") __ ();
137            code end =>     ("__stop_", "_text", "_link_section_") __ ();
138        }
139        AUXILIARY = "_";
140        MAX_LENGTH = 64;
141        HASH_LENGTH = 10;
142        VALID_SECTION_CHARS = "_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
143    }
144
145    #[cfg(target_vendor = "pc")]
146    def_section_name! {
147        {
148            data bare =>    (".data", "$") __ ();
149            data section => (".data", "$") __ ("$b");
150            data start =>   (".data", "$") __ ("$a");
151            data end =>     (".data", "$") __ ("$c");
152            code bare =>    (".text", "$") __ ();
153            code section => (".text", "$") __ ("$b");
154            code start =>   (".text", "$") __ ("$a");
155            code end =>     (".text", "$") __ ("$c");
156        }
157        AUXILIARY = "$d$";
158        MAX_LENGTH = 64;
159        HASH_LENGTH = 10;
160        VALID_SECTION_CHARS = "_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
161    }
162
163    #[cfg(not(feature = "proc_macro"))]
164    #[doc(hidden)]
165    #[macro_export]
166    macro_rules! __declare_macro {
167        ($vis:vis $ident:ident $generic_macro:ident $args:tt) => {
168            /// Internal macro for parsing the section. This is exported with
169            /// the same name as the type below.
170            #[doc(hidden)]
171            $vis use $crate::$generic_macro as $ident;
172        };
173    }
174
175    #[cfg(feature = "proc_macro")]
176    #[doc(hidden)]
177    #[macro_export]
178    macro_rules! __declare_macro {
179        ($vis:vis $ident:ident $generic_macro:ident $args:tt) => {
180            $crate::__support::ident_concat!(
181                (#[macro_export]
182                #[doc(hidden)]
183                macro_rules!)  (__ $ident __link_section_private_macro__) ({
184                    ($passthru:tt) => {
185                        $crate::$generic_macro!($passthru $args);
186                    };
187                })
188            );
189
190            $crate::__support::ident_concat!(
191                (#[doc(hidden)] pub use) (__ $ident __link_section_private_macro__) (as $ident;)
192            );
193        }
194    }
195
196    /// Define a link section.
197    #[macro_export]
198    #[doc(hidden)]
199    macro_rules! __section_parse {
200        // Has a generic (note that $generic eats the trailing semicolon)
201        (#[section $($args:tt)*] $(#[$meta:meta])* $vis:vis static $ident:ident : $(:: $path_prefix:ident ::)? $($path:ident)::* < $($generic:tt)*) => {
202            $crate::__section_parse!(@parsed #[section $($args)*] $(#[$meta])* $vis static $ident: ( $(:: $path_prefix ::)? $($path)::* < $($generic)*) ( $($generic)* ) __in_section_helper_macro_generic);
203        };
204        // No generic
205        (#[section $($args:tt)*] $(#[$meta:meta])* $vis:vis static $ident:ident : $(:: $path_prefix:ident ::)? $($path:ident)::* ;) => {
206            $crate::__section_parse!(@parsed #[section $($args)*] $(#[$meta])* $vis static $ident: ( $(:: $path_prefix ::)? $($path)::* ;) ( () > ; ) __in_section_helper_macro_no_generic);
207        };
208        // Both end up here...
209        (@parsed #[section(aux = $name:ident, no_macro)] $(#[$meta:meta])* $vis:vis static $ident:ident : ($ty:ty ;) ( $generic_ty:ty > ; ) $generic_macro:ident) => {
210            $crate::__section_parse!(@generate #[section(aux = $name)] $(#[$meta])* $vis static $ident: $ty, $generic_ty, $generic_macro);
211        };
212        (@parsed #[section(no_macro)] $(#[$meta:meta])* $vis:vis static $ident:ident : ($ty:ty ;) ( $generic_ty:ty > ; ) $generic_macro:ident) => {
213            $crate::__section_parse!(@generate #[section] $(#[$meta])* $vis static $ident: $ty, $generic_ty, $generic_macro);
214        };
215        (@parsed #[section $($args:tt)*] $(#[$meta:meta])* $vis:vis static $ident:ident : ($ty:ty ;) ( $generic_ty:ty > ; ) $generic_macro:ident) => {
216            $crate::__declare_macro!($vis $ident $generic_macro ($($args)*));
217            $crate::__section_parse!(@generate #[section $($args)*] $(#[$meta])* $vis static $ident: $ty, $generic_ty, $generic_macro);
218        };
219        (@generate #[section $($args:tt)*] $(#[$meta:meta])* $vis:vis static $ident:ident : $ty:ty, $generic_ty:ty, __in_section_helper_macro_generic) => {
220            $crate::__section_parse!(@generate #[section $($args)*] $(#[$meta])* $vis static $ident: $ty, $generic_ty, __base_case__);
221
222            impl ::core::iter::IntoIterator for $ident {
223                type Item = &'static $generic_ty;
224                type IntoIter = ::core::slice::Iter<'static, $generic_ty>;
225                fn into_iter(self) -> Self::IntoIter {
226                    $ident.as_slice().iter()
227                }
228            }
229        };
230        (@generate #[section $($args:tt)*] $(#[$meta:meta])* $vis:vis static $ident:ident : $ty:ty, $generic_ty:ty, $generic_macro:ident) => {
231            $(#[$meta])*
232            #[allow(non_camel_case_types)]
233            $vis struct $ident;
234
235            impl $crate::__support::SectionItemType for $ident {
236                type Item = $generic_ty;
237            }
238
239            impl ::core::fmt::Debug for $ident {
240                fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
241                    ::core::ops::Deref::deref(self).fmt(f)
242                }
243            }
244
245            impl ::core::ops::Deref for $ident {
246                type Target = $ty;
247                fn deref(&self) -> &Self::Target {
248                    self.const_deref()
249                }
250            }
251
252            $crate::__section_parse!(@deref #[section $($args)*] $(#[$meta])* $vis static $ident: $ty, $generic_ty, __base_case__);
253        };
254        (@deref #[section] $(#[$meta:meta])* $vis:vis static $ident:ident : $ty:ty, $generic_ty:ty, __base_case__) => {
255            impl $ident {
256                /// Get a `const` reference to the underlying section. In
257                /// non-const contexts, `deref` is sufficient.
258                pub const fn const_deref(&self) -> &$ty {
259                    static SECTION: $ty = {
260                        let section = $crate::__support::get_section!(name=$ident, type=$generic_ty, aux=);
261                        let name = $crate::__section_name!(
262                            raw data bare $ident
263                        );
264                        unsafe { <$ty>::new(name, section.0, section.1) }
265                    };
266                    &SECTION
267                }
268            }
269        };
270        (@deref #[section(aux=$aux:ident)] $(#[$meta:meta])* $vis:vis static $ident:ident : $ty:ty, $generic_ty:ty, __base_case__) => {
271            impl $ident {
272                /// Get a `const` reference to the underlying section. In
273                /// non-const contexts, `deref` is sufficient.
274                pub const fn const_deref(&self) -> &$ty {
275                    static SECTION: $ty = {
276                        let section = $crate::__support::get_section!(name=$ident, type=$generic_ty, aux=$aux);
277                        let name = $crate::__section_name!(
278                            raw data bare $aux $ident // swap
279                        );
280                        unsafe { <$ty>::new(name, section.0, section.1) }
281                    };
282                    &SECTION
283                }
284            }
285        };
286    }
287
288    #[cfg(miri)]
289    mod section {
290        #[doc(hidden)]
291        #[macro_export]
292        macro_rules! __get_section {
293            (name=$ident:ident, type=$generic_ty:ty, aux=$($aux:ident)?) => {{
294                (std::ptr::null_mut(), std::ptr::null_mut())
295            }};
296        }
297
298        /// On Apple platforms, the linker provides a pointer to the start and end
299        /// of the section regardless of the section's name.
300        pub type SectionPtr<T> = *const ::core::marker::PhantomData<T>;
301    }
302
303    #[cfg(all(not(miri), target_family = "wasm"))]
304    mod section {
305        #[doc(hidden)]
306        #[macro_export]
307        macro_rules! __get_section {
308            (name=$ident:ident, type=$generic_ty:ty, aux=$($aux:ident)?) => {
309                {
310                    static __START: ::core::sync::atomic::AtomicPtr::<::core::marker::PhantomData<$generic_ty>> = unsafe {
311                        ::core::sync::atomic::AtomicPtr::<::core::marker::PhantomData<$generic_ty>>::new(::core::ptr::null_mut())
312                    };
313                    static __END: ::core::sync::atomic::AtomicPtr::<::core::marker::PhantomData<$generic_ty>> = unsafe {
314                        ::core::sync::atomic::AtomicPtr::<::core::marker::PhantomData<$generic_ty>>::new(::core::ptr::null_mut())
315                    };
316
317                    $crate::__support::ident_concat!((#[no_mangle]pub extern "C" fn) (register_link_section_ $ident) ((data_ptr: *const u8, data_len: usize) {
318                        unsafe {
319                            __START.store(data_ptr as *mut ::core::marker::PhantomData<$generic_ty>, ::core::sync::atomic::Ordering::Relaxed);
320                            __END.store(data_ptr.add(data_len) as *mut ::core::marker::PhantomData<$generic_ty>, ::core::sync::atomic::Ordering::Relaxed);
321                        }
322                    }));
323
324                    (&__START, &__END)
325                }
326            }
327        }
328
329        /// On WASM, we use an atomic pointer to the start and end of the
330        /// section. The host environment is responsible for registering the
331        /// section with the runtime.
332        pub type SectionPtr<T> =
333            &'static ::core::sync::atomic::AtomicPtr<::core::marker::PhantomData<T>>;
334    }
335
336    #[cfg(all(not(miri), target_vendor = "pc"))]
337    mod section {
338        #[doc(hidden)]
339        #[macro_export]
340        macro_rules! __get_section {
341            (name=$ident:ident, type=$generic_ty:ty, aux=$($aux:ident)?) => {
342                {
343                    $crate::__support::add_section_link_attribute!(
344                        data start $ident $($aux)?
345                        #[link_section = __]
346                        static __START: [$generic_ty; 0] = [];
347                    );
348                    $crate::__support::add_section_link_attribute!(
349                        data end $ident $($aux)?
350                        #[link_section = __]
351                        static __END: [$generic_ty; 0] = [];
352                    );
353
354                    (
355                        unsafe { &raw const __START as $crate::__support::SectionPtr<$generic_ty> },
356                        unsafe { &raw const __END as $crate::__support::SectionPtr<$generic_ty> },
357                    )
358                }
359            }
360        }
361
362        /// On Windows platforms we don't have start/end symbols, but we do have
363        /// section sorting so we drop a [T; 0] at the start and end of the
364        /// section.
365        pub type SectionPtr<T> = *const [T; 0];
366    }
367
368    #[cfg(all(not(miri), not(target_family = "wasm"), not(target_vendor = "pc")))]
369    mod section {
370        #[doc(hidden)]
371        #[macro_export]
372        macro_rules! __get_section {
373            (name=$ident:ident, type=$generic_ty:ty, aux=$($aux:ident)?) => {
374                {
375                    extern "C" {
376                        $crate::__support::add_section_link_attribute!(
377                            data start $ident $($aux)?
378                            #[link_name = __]
379                            static __START: $crate::__support::SectionPtr<$generic_ty>;
380                        );
381                    }
382                    extern "C" {
383                        $crate::__support::add_section_link_attribute!(
384                            data end $ident $($aux)?
385                            #[link_name = __]
386                            static __END: $crate::__support::SectionPtr<$generic_ty>;
387                        );
388                    }
389
390                    (
391                        unsafe { &raw const __START as $crate::__support::SectionPtr<$generic_ty> },
392                        unsafe { &raw const __END as $crate::__support::SectionPtr<$generic_ty> },
393                    )
394                }
395            }
396        }
397
398        /// On LLVM/GCC platforms we can use orphan sections with _start and
399        /// _end symbols.
400        pub type SectionPtr<T> = *const ::core::marker::PhantomData<T>;
401    }
402
403    /// Export a symbol into a link section.
404    #[macro_export]
405    #[doc(hidden)]
406    macro_rules! __in_section_parse {
407        // Needs to handle:
408        //  <name>
409        //  :: <name>
410        //  <path> :: <name>
411        //  :: <path> :: <name>
412        //  etc...
413        (#[in_section(unsafe, type = $stored_ty:ty, name = $ident:ident $( , aux = $aux:ident)?)] $($item:tt)*) => {
414            $crate::__support::in_section_crate!((type = $stored_ty), $ident, $($aux)?, $ident, ($($item)*));
415        };
416        (#[in_section(unsafe, name = $ident:ident $( , aux = $aux:ident)?)] $($item:tt)*) => {
417            $crate::__support::in_section_crate!(data, $ident, $($aux)?, $ident, ($($item)*));
418        };
419        (#[in_section( $($path:tt)* )] $($item:tt)*) => {
420            $crate::__support::in_section_parse!(path=[$($path)*] #[in_section($($path)*)] $($item)*);
421        };
422        (path=[$orig_path:path] #[in_section($name:ident)] $($item:tt)*) => {
423            $orig_path ! (
424                (v=0 (name=$name (path=[$orig_path] (item=($($item)*) ()))))
425            );
426        };
427        (path=[$orig_path:path] #[in_section(:: $($path:ident)::*)] $($item:tt)*) => {
428            $crate::__support::in_section_parse!(path=[$orig_path] #[in_section($($path)::*)] $($item)*);
429        };
430        (path=[$orig_path:path] #[in_section($prefix:ident :: $($path:ident)::*)] $($item:tt)*) => {
431            $crate::__support::in_section_parse!(path=[$orig_path] #[in_section($($path)::*)] $($item)*);
432        };
433    }
434
435    #[macro_export]
436    #[doc(hidden)]
437    macro_rules! __in_section_helper_macro_generic {
438        ((v=0 (name=$ident:ident (path=[$path:path] (item=$item:tt $rest:tt))))) => {
439            $crate::__support::in_section_crate!(section, $ident,, $path, $item);
440        };
441        ((v=0 (name=$ident:ident (path=[$path:path] (item=$item:tt $rest:tt)))) ((aux=$aux:ident)) )=> {
442            $crate::__support::in_section_crate!(section, $ident, $aux, $path, $item);
443        };
444        ((v=0 (name=$ident:ident (path=[$path:path] (item=$item:tt $rest:tt)))) () )=> {
445            $crate::__support::in_section_crate!(section, $ident,, $path, $item);
446        };
447        (v=$v:literal $rest:tt) => {
448            const _: () = {
449                compile_error!(concat!(
450                    "link-section: Unsupported version: `",
451                    stringify!($v),
452                    "`: ",
453                    stringify!($rest)
454                ));
455            };
456        };
457    }
458
459    #[macro_export]
460    #[doc(hidden)]
461    macro_rules! __in_section_helper_macro_no_generic {
462        ((v=0 (name=$ident:ident (path=[$path:path] (item=$item:tt $rest:tt))))) => {
463            $crate::__support::in_section_crate!(data, $ident,, $path, $item);
464        };
465        ((v=0 (name=$ident:ident (path=[$path:path] (item=$item:tt $rest:tt)))) ((aux=$aux:ident)) )=> {
466            $crate::__support::in_section_crate!(data, $ident, $aux, $path, $item);
467        };
468        ((v=0 (name=$ident:ident (path=[$path:path] (item=$item:tt $rest:tt)))) () )=> {
469            $crate::__support::in_section_crate!(data, $ident,, $path, $item);
470        };
471        (v=$v:literal $rest:tt) => {
472            const _: () = {
473                compile_error!(concat!(
474                    "link-section: Unsupported version: `",
475                    stringify!($v),
476                    "`: ",
477                    stringify!($rest)
478                ));
479            };
480        };
481    }
482
483    #[macro_export]
484    #[doc(hidden)]
485    #[allow(unknown_lints, edition_2024_expr_fragment_specifier)]
486    macro_rules! __in_section_crate {
487        (@type_select section $path:path, $item_ty:ty) => {
488            <$path as $crate::__support::SectionItemType>::Item
489        };
490        (@type_select data $path:path, $item_ty:ty) => {
491            $item_ty
492        };
493        (@type_select (type = $stored_ty:ty) $path:path, $item_ty:ty) => {
494            $stored_ty
495        };
496        ($type_source:tt, $ident:ident, $($aux:ident)?, $path:path, ($(#[$meta:meta])* $vis:vis fn $ident_fn:ident($($args:tt)*) $(-> $ret:ty)? $body:block)) => {
497            $crate::__add_section_link_attribute!(
498                data section $ident $($aux)?
499                #[link_section = __]
500                $(#[$meta])*
501                #[used]
502                #[allow(non_upper_case_globals)]
503                $vis static $ident_fn: $crate::__in_section_crate!(@type_select $type_source $path, fn($($args)*) $(-> $ret)?) =
504                    {
505                        $crate::__add_section_link_attribute!(
506                            code section $ident $($aux)?
507                            #[link_section = __]
508                            fn $ident_fn($($args)*) $(-> $ret)? $body
509                        );
510                        $ident_fn
511                    };
512            );
513        };
514        ($type_source:tt, $ident:ident, $($aux:ident)?, $path:path, ($(#[$meta:meta])* $vis:vis static _ : $ty:ty = $value:expr;)) => {
515            const _: () = {
516                $crate::__add_section_link_attribute!(
517                    data section $ident $($aux)?
518                    #[link_section = __]
519                    $(#[$meta])* #[used] $vis static ANONYMOUS: $crate::__in_section_crate!(@type_select $type_source $path, $ty) = $value;
520                );
521            };
522        };
523        ($type_source:tt, $ident:ident, $($aux:ident)?, $path:path, ($(#[$meta:meta])* $vis:vis static $ident_static:ident : $ty:ty = $value:expr;)) => {
524            $crate::__add_section_link_attribute!(
525                data section $ident $($aux)?
526                #[link_section = __]
527                $(#[$meta])* #[used] $vis static $ident_static: $crate::__in_section_crate!(@type_select $type_source $path, $ty) = $value;
528            );
529        };
530        (data, $ident:ident, $($aux:ident)?, $path:path, ($(#[$meta:meta])* $item:item)) => {
531            $crate::__add_section_link_attribute!(
532                data section $ident $($aux)?
533                #[link_section = __]
534                $(#[$meta])* #[used] $item
535            );
536        };
537    }
538
539    pub trait SectionItemType {
540        type Item;
541    }
542
543    impl<T> SectionItemType for super::TypedSection<T> {
544        type Item = T;
545    }
546
547    pub use section::SectionPtr;
548}
549
550/// Define a link section.
551///
552/// The definition site generates two items: a static section struct that is
553/// used to access the section, and a macro that is used to place items into the
554/// section. The macro is used by the [`in_section`] procedural macro.
555///
556/// # Attributes
557///
558/// - `no_macro`: Does not generate the submission macro at the definition site.
559///   This will require any associated [`in_section`] invocations to use the raw
560///   name of the section.
561/// - `aux = <name>`: Specifies that this section is an auxiliary section, and
562///   that the section is named `<name>+<aux>`.
563///
564/// # Example
565/// ```rust
566/// use link_section::{in_section, section};
567///
568/// #[section]
569/// pub static DATA_SECTION: link_section::Section;
570///
571/// #[in_section(DATA_SECTION)]
572/// pub fn data_function() {
573///     println!("data_function");
574/// }
575/// ```
576#[cfg(feature = "proc_macro")]
577pub use ::link_section_proc_macro::section;
578
579/// Place an item into a link section.
580///
581/// # Functions and typed sections
582///
583/// As a special case, since function declarations by themselves are not sized,
584/// functions in typed sections are split and stored as function pointers.
585#[cfg(feature = "proc_macro")]
586pub use ::link_section_proc_macro::in_section;
587
588/// An untyped link section that can be used to store any type. The underlying
589/// data is not enumerable.
590#[repr(C)]
591pub struct Section {
592    name: &'static str,
593    start: __support::SectionPtr<()>,
594    end: __support::SectionPtr<()>,
595}
596
597impl Section {
598    #[doc(hidden)]
599    pub const unsafe fn new(
600        name: &'static str,
601        start: __support::SectionPtr<()>,
602        end: __support::SectionPtr<()>,
603    ) -> Self {
604        Self { name, start, end }
605    }
606
607    /// The byte length of the section.
608    pub fn byte_len(&self) -> usize {
609        unsafe { (self.end_ptr() as *const u8).offset_from(self.start_ptr() as *const u8) as usize }
610    }
611}
612
613#[cfg(target_family = "wasm")]
614impl Section {
615    /// The start address of the section.
616    pub fn start_ptr(&self) -> *const () {
617        let ptr = self.start.load(::core::sync::atomic::Ordering::Relaxed) as *const ();
618        if ptr.is_null() {
619            panic!(
620                "Section {} was not initialized by the host environment",
621                self.name
622            );
623        }
624        ptr
625    }
626    /// The end address of the section.
627    pub fn end_ptr(&self) -> *const () {
628        let ptr = self.end.load(::core::sync::atomic::Ordering::Relaxed) as *const ();
629        if ptr.is_null() {
630            panic!(
631                "Section {} was not initialized by the host environment",
632                self.name
633            );
634        }
635        ptr
636    }
637}
638
639#[cfg(not(target_family = "wasm"))]
640impl Section {
641    /// The start address of the section.
642    pub fn start_ptr(&self) -> *const () {
643        self.start as *const ()
644    }
645    /// The end address of the section.
646    pub fn end_ptr(&self) -> *const () {
647        self.end as *const ()
648    }
649}
650
651impl ::core::fmt::Debug for Section {
652    fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
653        f.debug_struct("Section")
654            .field("name", &self.name)
655            .field("start", &self.start_ptr())
656            .field("end", &self.end_ptr())
657            .field("byte_len", &self.byte_len())
658            .finish()
659    }
660}
661
662unsafe impl Sync for Section {}
663unsafe impl Send for Section {}
664
665/// A typed link section that can be used to store any sized type. The
666/// underlying data is enumerable.
667#[repr(C)]
668pub struct TypedSection<T: 'static> {
669    name: &'static str,
670    start: __support::SectionPtr<T>,
671    end: __support::SectionPtr<T>,
672    _phantom: ::core::marker::PhantomData<T>,
673}
674
675#[cfg(target_family = "wasm")]
676impl<T: 'static> TypedSection<T> {
677    /// The start address of the section.
678    pub fn start_ptr(&self) -> *const T {
679        let ptr = self.start.load(::core::sync::atomic::Ordering::Relaxed) as *const T;
680        if ptr.is_null() {
681            panic!(
682                "TypedSection {} was not initialized by the host environment",
683                self.name
684            );
685        }
686        ptr
687    }
688
689    /// The end address of the section.
690    pub fn end_ptr(&self) -> *const T {
691        let ptr = self.end.load(::core::sync::atomic::Ordering::Relaxed) as *const T;
692        if ptr.is_null() {
693            panic!(
694                "TypedSection {} was not initialized by the host environment",
695                self.name
696            );
697        }
698        ptr
699    }
700}
701
702#[cfg(not(target_family = "wasm"))]
703impl<T: 'static> TypedSection<T> {
704    /// The start address of the section.
705    pub fn start_ptr(&self) -> *const T {
706        self.start as usize as *const T
707    }
708
709    /// The end address of the section.
710    pub fn end_ptr(&self) -> *const T {
711        self.end as *const T
712    }
713}
714
715// Non-const, shared functions (or functions that don't depend on the pointers)
716impl<T: 'static> TypedSection<T> {
717    #[doc(hidden)]
718    pub const unsafe fn new(
719        name: &'static str,
720        start: __support::SectionPtr<T>,
721        end: __support::SectionPtr<T>,
722    ) -> Self {
723        Self {
724            name,
725            start,
726            end,
727            _phantom: ::core::marker::PhantomData,
728        }
729    }
730
731    /// The stride of the typed section.
732    pub const fn stride(&self) -> usize {
733        assert!(
734            ::core::mem::size_of::<T>() > 0
735                && ::core::mem::size_of::<T>() * 2 == ::core::mem::size_of::<[T; 2]>()
736        );
737        ::core::mem::size_of::<T>()
738    }
739
740    /// The byte length of the section.
741    pub fn byte_len(&self) -> usize {
742        unsafe { (self.end_ptr() as *const u8).offset_from(self.start_ptr() as *const u8) as usize }
743    }
744
745    /// The number of elements in the section.
746    pub fn len(&self) -> usize {
747        self.byte_len() / self.stride()
748    }
749
750    /// True if the section is empty.
751    pub fn is_empty(&self) -> bool {
752        self.len() == 0
753    }
754
755    /// The section as a slice.
756    pub fn as_slice(&self) -> &[T] {
757        if self.is_empty() {
758            &[]
759        } else {
760            unsafe { ::core::slice::from_raw_parts(self.start_ptr(), self.len()) }
761        }
762    }
763
764    /// The offset of the item in the section, if it is in the section.
765    pub fn offset_of(&self, item: &T) -> Option<usize> {
766        let ptr = item as *const T;
767        if ptr < self.start_ptr() || ptr >= self.end_ptr() {
768            None
769        } else {
770            Some(unsafe { ptr.offset_from(self.start_ptr()) as usize })
771        }
772    }
773
774    /// The section as a mutable slice.
775    ///
776    /// # Safety
777    ///
778    /// This cannot be safely used and is _absolutely unsound_ if any other
779    /// slices are live.
780    #[allow(clippy::mut_from_ref)]
781    pub unsafe fn as_mut_slice(&self) -> &mut [T] {
782        if self.is_empty() {
783            &mut []
784        } else {
785            unsafe { ::core::slice::from_raw_parts_mut(self.start_ptr() as *mut T, self.len()) }
786        }
787    }
788}
789
790impl<'a, T> ::core::iter::IntoIterator for &'a TypedSection<T> {
791    type Item = &'a T;
792    type IntoIter = ::core::slice::Iter<'a, T>;
793    fn into_iter(self) -> Self::IntoIter {
794        self.as_slice().iter()
795    }
796}
797
798impl<T> ::core::ops::Deref for TypedSection<T> {
799    type Target = [T];
800    fn deref(&self) -> &Self::Target {
801        self.as_slice()
802    }
803}
804
805impl<T> ::core::fmt::Debug for TypedSection<T> {
806    fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
807        f.debug_struct("TypedSection")
808            .field("name", &self.name)
809            .field("start", &self.start_ptr())
810            .field("end", &self.end_ptr())
811            .field("len", &self.len())
812            .field("stride", &self.stride())
813            .finish()
814    }
815}
816
817unsafe impl<T> Sync for TypedSection<T> where T: Sync {}
818unsafe impl<T> Send for TypedSection<T> where T: Send {}