late_struct/
init.rs

1use std::{
2    alloc::Layout,
3    any::TypeId,
4    collections::HashMap,
5    sync::{Once, atomic::Ordering::*},
6};
7
8use crate::{RawLateFieldDescriptor, RawLateStructDescriptor};
9
10/// A marker type indicating that the layouts for all [`late_struct!`](super::late_struct)s
11/// throughout the compiled artifact have been determined at runtime.
12///
13/// This initialization process happens automatically upon the first instantiation of a
14/// [`LateInstance`](super::LateInstance). Indeed, you can use the [`init_token`](super::LateInstance::init_token)
15/// method of a `LateInstance` to obtain an instance of this struct for free.
16#[derive(Debug, Copy, Clone)]
17#[non_exhaustive]
18pub struct LateLayoutInitToken;
19
20impl Default for LateLayoutInitToken {
21    fn default() -> Self {
22        Self::new()
23    }
24}
25
26impl LateLayoutInitToken {
27    /// Resolves all late-initialized structures in the compiled artifact and returns a token
28    /// attesting to this fact. The late initialization process only happens once during the
29    /// program's lifetime.
30    ///
31    /// The late-initialization routine does not makes uncontrolled calls to user-controlled
32    /// functions.
33    pub fn new() -> Self {
34        static ONCE: Once = Once::new();
35
36        ONCE.call_once(|| {
37            use crate::late_macro_internals::{iter_late_fields, iter_late_structs};
38
39            let mut structs = HashMap::<
40                TypeId,
41                (
42                    &'static RawLateStructDescriptor,
43                    Vec<&'static RawLateFieldDescriptor>,
44                ),
45            >::new();
46
47            for entry in iter_late_structs() {
48                structs.insert(entry.struct_type, (entry.descriptor, Vec::new()));
49            }
50
51            for entry in iter_late_fields() {
52                structs
53                    .get_mut(&entry.struct_type)
54                    .unwrap()
55                    .1
56                    .push(entry.descriptor);
57            }
58
59            for (struct_desc, struct_fields) in structs.into_values() {
60                let struct_fields: &[_] = &*Box::leak(Box::from_iter(struct_fields));
61                let struct_fields_p = Box::leak(Box::new(struct_fields));
62
63                let mut overall_layout = Layout::new::<()>();
64
65                for (i, field) in struct_fields.iter().enumerate() {
66                    let (new_layout, offset) = overall_layout.extend(field.layout()).unwrap();
67                    field.index.store(i, Relaxed);
68                    field.offset.store(offset, Relaxed);
69                    overall_layout = new_layout;
70                }
71
72                struct_desc.size.store(overall_layout.size(), Relaxed);
73                struct_desc.align.store(overall_layout.align(), Relaxed);
74                struct_desc.fields.store(struct_fields_p, Relaxed);
75            }
76        });
77
78        Self
79    }
80
81    /// Unsafely asserts that the layout for all late-initialized structures in the compiled
82    /// artifact have already been resolved.
83    ///
84    /// Unless you have specific performance reasons to do so, you should probably be using
85    /// [`LateLayoutInitToken::new`].
86    ///
87    /// ## Safety
88    ///
89    /// Although this method cannot, by itself, cause undefined behavior, passing this object to a
90    /// method which expects the layout of late-initialized structure to already be resolved when
91    /// the layouts are not yet resolved could easily cause undefined behavior.
92    pub const unsafe fn new_unchecked() -> Self {
93        Self
94    }
95}