abi_stable/type_layout/
tl_data.rs

1use super::*;
2
3////////////////////////////////////////////////////////////////////////////////
4
5/// The parts of TLData that don't change based on generic parameters.
6#[repr(u8)]
7#[derive(Copy, Clone, StableAbi)]
8#[sabi(unsafe_sabi_opaque_fields)]
9pub enum MonoTLData {
10    ///
11    Primitive(TLPrimitive),
12    /// A type that's only compared for size and alignment.
13    Opaque,
14    ///
15    Struct {
16        ///
17        fields: CompTLFields,
18    },
19    ///
20    Union {
21        ///
22        fields: CompTLFields,
23    },
24    ///
25    Enum(MonoTLEnum),
26    ///
27    PrefixType(MonoTLPrefixType),
28}
29
30impl MonoTLData {
31    /// Teh `MonoTLData` for an empty struct.
32    pub const EMPTY: Self = MonoTLData::Struct {
33        fields: CompTLFields::EMPTY,
34    };
35
36    /// Constructs `MonoTLData::Struct` from a slice of its fields.
37    pub const fn struct_(fields: RSlice<'static, CompTLField>) -> Self {
38        MonoTLData::Struct {
39            fields: CompTLFields::from_fields(fields),
40        }
41    }
42
43    #[doc(hidden)]
44    pub const fn derive_struct(fields: CompTLFields) -> Self {
45        MonoTLData::Struct { fields }
46    }
47
48    /// Constructs `MonoTLData::Union` from a slice of its fields.
49    pub const fn union_(fields: RSlice<'static, CompTLField>) -> Self {
50        MonoTLData::Union {
51            fields: CompTLFields::from_fields(fields),
52        }
53    }
54
55    #[doc(hidden)]
56    pub const fn derive_union(fields: CompTLFields) -> Self {
57        MonoTLData::Union { fields }
58    }
59
60    /// Constructs a `MonoTLData::PrefixType`
61    pub const fn prefix_type(
62        first_suffix_field: usize,
63        conditional_prefix_fields: FieldConditionality,
64        fields: RSlice<'static, CompTLField>,
65    ) -> Self {
66        MonoTLData::PrefixType(MonoTLPrefixType {
67            first_suffix_field: first_suffix_field as u8,
68            conditional_prefix_fields,
69            fields: CompTLFields::from_fields(fields),
70        })
71    }
72
73    /// Constructs `MonoTLData::Struct` from a slice of its fields.
74    pub const fn struct_derive(fields: CompTLFields) -> Self {
75        MonoTLData::Struct { fields }
76    }
77
78    /// Constructs `MonoTLData::Union` from a slice of its fields.
79    pub const fn union_derive(fields: CompTLFields) -> Self {
80        MonoTLData::Union { fields }
81    }
82
83    /// Constructs a `MonoTLData::PrefixType`
84    pub const fn prefix_type_derive(
85        first_suffix_field: usize,
86        conditional_prefix_fields: u64,
87        fields: CompTLFields,
88    ) -> Self {
89        MonoTLData::PrefixType(MonoTLPrefixType {
90            first_suffix_field: first_suffix_field as u8,
91            conditional_prefix_fields: FieldConditionality::from_u64(conditional_prefix_fields),
92            fields,
93        })
94    }
95
96    /// Converts this into a `TLDataDiscriminant`,
97    /// allowing one to query which discriminant this is.
98    pub const fn as_discriminant(&self) -> TLDataDiscriminant {
99        match self {
100            MonoTLData::Primitive { .. } => TLDataDiscriminant::Primitive,
101            MonoTLData::Opaque { .. } => TLDataDiscriminant::Opaque,
102            MonoTLData::Struct { .. } => TLDataDiscriminant::Struct,
103            MonoTLData::Union { .. } => TLDataDiscriminant::Union,
104            MonoTLData::Enum { .. } => TLDataDiscriminant::Enum,
105            MonoTLData::PrefixType { .. } => TLDataDiscriminant::PrefixType,
106        }
107    }
108
109    pub(super) const fn to_primitive(self) -> Option<TLPrimitive> {
110        match self {
111            MonoTLData::Primitive(x) => Some(x),
112            _ => None,
113        }
114    }
115
116    /// Expands this `MonoTLData`.
117    ///
118    /// # Errors
119    ///
120    /// This returns a `MismatchedTLDataVariant` if `self` and `generic`
121    /// are variant of different names.
122    pub fn expand(
123        self,
124        generic: GenericTLData,
125        shared_vars: &'static SharedVars,
126    ) -> Result<TLData, MismatchedTLDataVariant> {
127        Ok(match (self, generic) {
128            (MonoTLData::Primitive(prim), GenericTLData::Primitive) => TLData::Primitive(prim),
129            (MonoTLData::Opaque, GenericTLData::Opaque) => TLData::Opaque,
130            (MonoTLData::Struct { fields }, GenericTLData::Struct) => TLData::Struct {
131                fields: fields.expand(shared_vars),
132            },
133            (MonoTLData::Union { fields }, GenericTLData::Union) => TLData::Union {
134                fields: fields.expand(shared_vars),
135            },
136            (MonoTLData::Enum(nongeneric), GenericTLData::Enum(generic)) => {
137                TLData::Enum(nongeneric.expand(generic, shared_vars))
138            }
139            (MonoTLData::PrefixType(nongeneric), GenericTLData::PrefixType(generic)) => {
140                TLData::PrefixType(nongeneric.expand(generic, shared_vars))
141            }
142            _ => {
143                return Err(MismatchedTLDataVariant {
144                    nongeneric: self.as_discriminant(),
145                    generic: generic.as_discriminant(),
146                })
147            }
148        })
149    }
150}
151
152///////////////////////////
153
154/// An error returned by `MonoTLData::expand` because
155/// the `GenericTLData` it tried to combine itself with was a different variant.
156#[derive(Debug, Clone)]
157pub struct MismatchedTLDataVariant {
158    nongeneric: TLDataDiscriminant,
159    generic: TLDataDiscriminant,
160}
161
162impl Display for MismatchedTLDataVariant {
163    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
164        writeln!(
165            f,
166            "Error combining TLData::{:?} and GenericTLData::{:?}",
167            self.nongeneric, self.generic,
168        )
169    }
170}
171
172///////////////////////////
173
174/// A discriminant-only version of TLData.
175#[repr(u8)]
176#[derive(Debug, Copy, Clone, PartialEq, Eq, StableAbi)]
177#[sabi(unsafe_sabi_opaque_fields)]
178pub enum TLDataDiscriminant {
179    ///
180    Primitive,
181    /// A type that's only compared for size and alignment.
182    Opaque,
183    ///
184    Struct,
185    ///
186    Union,
187    ///
188    Enum,
189    ///
190    PrefixType,
191}
192
193/////////////////////////////////////////////////////
194
195/// The part of TLData that can change based on generic parameters.
196#[repr(C)]
197#[derive(Copy, Clone, StableAbi)]
198#[sabi(unsafe_sabi_opaque_fields)]
199pub enum GenericTLData {
200    ///
201    Primitive,
202    /// A type that's only compared for size and alignment.
203    Opaque,
204    ///
205    Struct,
206    ///
207    Union,
208    ///
209    Enum(GenericTLEnum),
210    ///
211    PrefixType(GenericTLPrefixType),
212}
213
214impl GenericTLData {
215    /// Converts this into a `TLDataDiscriminant`,
216    /// allowing one to query which discriminant this is.
217    pub const fn as_discriminant(&self) -> TLDataDiscriminant {
218        match self {
219            GenericTLData::Primitive { .. } => TLDataDiscriminant::Primitive,
220            GenericTLData::Opaque { .. } => TLDataDiscriminant::Opaque,
221            GenericTLData::Struct { .. } => TLDataDiscriminant::Struct,
222            GenericTLData::Union { .. } => TLDataDiscriminant::Union,
223            GenericTLData::Enum { .. } => TLDataDiscriminant::Enum,
224            GenericTLData::PrefixType { .. } => TLDataDiscriminant::PrefixType,
225        }
226    }
227
228    #[doc(hidden)]
229    pub const fn prefix_type_derive(accessible_fields: FieldAccessibility) -> Self {
230        GenericTLData::PrefixType(GenericTLPrefixType { accessible_fields })
231    }
232}
233
234/////////////////////////////////////////////////////
235
236/// The interior of the type definition,
237/// describing whether the type is a primitive/enum/struct/union and its contents.
238#[derive(Debug, Copy, Clone, PartialEq, Eq)]
239pub enum TLData {
240    /// Types defined in the compiler.
241    Primitive(TLPrimitive),
242    /// The type can't be inspected,and has no properties other than size/alignment.
243    ///
244    /// When translated to C,this would be a struct with a single array field
245    /// whose element type is the alignment in this layout,
246    /// with the same byte length as this layout .
247    Opaque,
248    /// For structs.
249    Struct {
250        ///
251        fields: TLFields,
252    },
253    /// For unions.
254    Union {
255        ///
256        fields: TLFields,
257    },
258    /// For enums.
259    Enum(TLEnum),
260    /// vtables and modules that can be extended in minor versions.
261    PrefixType(TLPrefixType),
262}
263
264impl Display for TLData {
265    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
266        match self {
267            TLData::Primitive(prim) => {
268                writeln!(f, "Primitive:{:?}", prim)?;
269            }
270            TLData::Opaque => {
271                writeln!(f, "Opaque data")?;
272            }
273            TLData::Struct { fields } => {
274                writeln!(
275                    f,
276                    "Struct with Fields:\n{}",
277                    fields.to_string().left_padder(4)
278                )?;
279            }
280            TLData::Union { fields } => {
281                writeln!(
282                    f,
283                    "Union with Fields:\n{}",
284                    fields.to_string().left_padder(4)
285                )?;
286            }
287            TLData::Enum(enum_) => {
288                writeln!(f, "Enum:")?;
289                Display::fmt(enum_, f)?;
290            }
291            TLData::PrefixType(prefix) => {
292                writeln!(f, "Prefix type:")?;
293                Display::fmt(prefix, f)?;
294            }
295        }
296        Ok(())
297    }
298}