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}