Skip to main content

facet_core/types/ty/
mod.rs

1use core::fmt;
2
3use super::*;
4
5mod field;
6pub use field::*;
7
8mod proxy;
9pub use proxy::*;
10
11mod opaque_adapter;
12pub use opaque_adapter::*;
13
14mod struct_;
15pub use struct_::*;
16
17mod enum_;
18pub use enum_::*;
19
20mod union_;
21pub use union_::*;
22
23mod primitive;
24pub use primitive::*;
25
26mod sequence;
27pub use sequence::*;
28
29mod user;
30pub use user::*;
31
32mod pointer;
33pub use pointer::*;
34
35/// The definition of a shape in accordance to rust reference:
36///
37/// See <https://doc.rust-lang.org/reference/types.html>
38#[derive(Clone, Copy, Debug)]
39#[repr(C)]
40pub enum Type {
41    /// Undefined type - used as default in ShapeBuilder.
42    Undefined,
43    /// Built-in primitive.
44    Primitive(PrimitiveType),
45    /// Sequence (array, slice).
46    Sequence(SequenceType),
47    /// User-defined type (struct, enum, union).
48    User(UserType),
49    /// Pointer type (reference, raw, function pointer).
50    Pointer(PointerType),
51}
52
53impl Type {
54    /// Returns the kind of this type as a string, for use in `DeclId` computation.
55    ///
56    /// This is used when auto-computing `DeclId` for foreign generic types.
57    #[inline]
58    pub const fn kind_str(&self) -> &'static str {
59        match self {
60            Type::Undefined => "undefined",
61            Type::Primitive(_) => "primitive",
62            Type::Sequence(s) => match s {
63                SequenceType::Array(_) => "array",
64                SequenceType::Slice(_) => "slice",
65            },
66            Type::User(u) => match u {
67                UserType::Struct(_) => "struct",
68                UserType::Enum(_) => "enum",
69                UserType::Union(_) => "union",
70                UserType::Opaque => "opaque",
71            },
72            Type::Pointer(p) => match p {
73                PointerType::Reference(_) => "ref",
74                PointerType::Raw(_) => "ptr",
75                PointerType::Function(_) => "fn",
76            },
77        }
78    }
79
80    /// Create a builder for a struct type.
81    ///
82    /// # Example
83    /// ```ignore
84    /// let ty = Type::struct_builder(StructKind::Struct, &FIELDS)
85    ///     .repr(Repr::c())
86    ///     .build();
87    /// ```
88    #[inline]
89    pub const fn struct_builder(kind: StructKind, fields: &'static [Field]) -> TypeStructBuilder {
90        TypeStructBuilder(StructTypeBuilder::new(kind, fields))
91    }
92
93    /// Create a builder for an enum type.
94    ///
95    /// # Example
96    /// ```ignore
97    /// let ty = Type::enum_builder(EnumRepr::U8, &VARIANTS)
98    ///     .repr(Repr::c())
99    ///     .build();
100    /// ```
101    #[inline]
102    pub const fn enum_builder(
103        enum_repr: EnumRepr,
104        variants: &'static [Variant],
105    ) -> TypeEnumBuilder {
106        TypeEnumBuilder(EnumTypeBuilder::new(enum_repr, variants))
107    }
108
109    /// Create a builder for a union type.
110    ///
111    /// # Example
112    /// ```ignore
113    /// let ty = Type::union_builder(&FIELDS)
114    ///     .repr(Repr::c())
115    ///     .build();
116    /// ```
117    #[inline]
118    pub const fn union_builder(fields: &'static [Field]) -> TypeUnionBuilder {
119        TypeUnionBuilder(UnionTypeBuilder::new(fields))
120    }
121}
122
123/// Builder that produces `Type::User(UserType::Struct(...))`.
124#[derive(Clone, Copy, Debug)]
125pub struct TypeStructBuilder(StructTypeBuilder);
126
127impl TypeStructBuilder {
128    /// Set the representation for the struct type.
129    #[inline]
130    pub const fn repr(self, repr: Repr) -> Self {
131        Self(self.0.repr(repr))
132    }
133
134    /// Build the final `Type`.
135    #[inline]
136    pub const fn build(self) -> Type {
137        Type::User(UserType::Struct(self.0.build()))
138    }
139}
140
141/// Builder that produces `Type::User(UserType::Enum(...))`.
142#[derive(Clone, Copy, Debug)]
143pub struct TypeEnumBuilder(EnumTypeBuilder);
144
145impl TypeEnumBuilder {
146    /// Set the representation for the enum type.
147    #[inline]
148    pub const fn repr(self, repr: Repr) -> Self {
149        Self(self.0.repr(repr))
150    }
151
152    /// Build the final `Type`.
153    #[inline]
154    pub const fn build(self) -> Type {
155        Type::User(UserType::Enum(self.0.build()))
156    }
157}
158
159/// Builder that produces `Type::User(UserType::Union(...))`.
160#[derive(Clone, Copy, Debug)]
161pub struct TypeUnionBuilder(UnionTypeBuilder);
162
163impl TypeUnionBuilder {
164    /// Set the representation for the union type.
165    #[inline]
166    pub const fn repr(self, repr: Repr) -> Self {
167        Self(self.0.repr(repr))
168    }
169
170    /// Build the final `Type`.
171    #[inline]
172    pub const fn build(self) -> Type {
173        Type::User(UserType::Union(self.0.build()))
174    }
175}
176
177// This implementation of `Display` is user-facing output, where the users are developers.
178// It is intended to show structure up to a certain depth, but for readability and brevity,
179// some complicated types have custom formatting surrounded by guillemet characters
180// (`«` and `»`) to indicate divergence from AST.
181impl fmt::Display for Type {
182    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
183        match self {
184            Type::Undefined => {
185                write!(f, "Undefined")?;
186            }
187            Type::Primitive(_) => {
188                // Defer to `Debug`, which correctly produces the intended formatting.
189                write!(f, "{self:?}")?;
190            }
191            Type::Sequence(SequenceType::Array(ArrayType { t, n })) => {
192                write!(f, "Sequence(Array(«[{t}; {n}]»))")?;
193            }
194            Type::Sequence(SequenceType::Slice(SliceType { t })) => {
195                write!(f, "Sequence(Slice(«&[{t}]»))")?;
196            }
197            Type::User(UserType::Struct(struct_type)) => {
198                struct __Display<'a>(&'a StructType);
199                impl fmt::Display for __Display<'_> {
200                    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
201                        write!(f, "«")?;
202                        write!(f, "kind: {:?}", self.0.kind)?;
203                        // Field count for `TupleStruct` and `Tuple`, and field names for `Struct`.
204                        // For `Unit`, we don't show anything.
205                        if let StructKind::Struct = self.0.kind {
206                            write!(f, ", fields: (")?;
207                            let mut fields_iter = self.0.fields.iter();
208                            if let Some(field) = fields_iter.next() {
209                                write!(f, "{}", field.name)?;
210                                for field in fields_iter {
211                                    write!(f, ", {}", field.name)?;
212                                }
213                            }
214                            write!(f, ")")?;
215                        } else if let StructKind::TupleStruct | StructKind::Tuple = self.0.kind {
216                            write!(f, ", fields: {}", self.0.fields.len())?;
217                        }
218                        // Only show the `#[repr(_)]` if it's not `Rust` (unless it's `repr(packed)`).
219                        if let BaseRepr::C = self.0.repr.base {
220                            if self.0.repr.packed {
221                                // If there are multiple `repr` hints, display as a parenthesized list.
222                                write!(f, ", repr: (C, packed)")?;
223                            } else {
224                                write!(f, ", repr: C")?;
225                            }
226                        } else if let BaseRepr::Transparent = self.0.repr.base {
227                            write!(f, ", repr: transparent")?;
228                            // Verbatim compiler error:
229                            assert!(
230                                !self.0.repr.packed,
231                                "transparent struct cannot have other repr hints"
232                            );
233                        } else if self.0.repr.packed {
234                            // This is potentially meaningless, but we'll show it anyway.
235                            // In this circumstance, you can assume it's `repr(Rust)`.
236                            write!(f, ", repr: packed")?;
237                        }
238                        write!(f, "»")
239                    }
240                }
241                let show_struct = __Display(struct_type);
242                write!(f, "User(Struct({show_struct}))")?;
243            }
244            Type::User(UserType::Enum(enum_type)) => {
245                struct __Display<'a>(&'a EnumType);
246                impl<'a> fmt::Display for __Display<'a> {
247                    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
248                        write!(f, "«")?;
249                        write!(f, "variants: (")?;
250                        let mut variants_iter = self.0.variants.iter();
251                        if let Some(variant) = variants_iter.next() {
252                            write!(f, "{}", variant.name)?;
253                            for variant in variants_iter {
254                                write!(f, ", {}", variant.name)?;
255                            }
256                        }
257                        write!(f, ")")?;
258                        // Only show the `#[repr(_)]` if it's not `Rust`.
259                        if let BaseRepr::C = self.0.repr.base {
260                            // TODO: `EnumRepr` should probably be optional, and contain the fields of `Repr`.
261                            // I think it is wrong to have both `Repr` and `EnumRepr` in the same type,
262                            // since that allows constructing impossible states.
263                            let repr_ty = match self.0.enum_repr {
264                                EnumRepr::Rust => unreachable!(
265                                    "default Rust repr is not valid for `repr(C)` enums"
266                                ),
267                                EnumRepr::RustNPO => unreachable!(
268                                    "null-pointer optimization is only valid for `repr(Rust)`"
269                                ),
270                                EnumRepr::U8 => "u8",
271                                EnumRepr::U16 => "u16",
272                                EnumRepr::U32 => "u32",
273                                EnumRepr::U64 => "u64",
274                                EnumRepr::USize => "usize",
275                                EnumRepr::I8 => "i8",
276                                EnumRepr::I16 => "i16",
277                                EnumRepr::I32 => "i32",
278                                EnumRepr::I64 => "i64",
279                                EnumRepr::ISize => "isize",
280                            };
281                            // If there are multiple `repr` hints, display as a parenthesized list.
282                            write!(f, ", repr: (C, {repr_ty})")?;
283                        } else if let BaseRepr::Transparent = self.0.repr.base {
284                            // Extra variant hints are not supported for `repr(transparent)`.
285                            write!(f, ", repr: transparent")?;
286                        }
287                        // Verbatim compiler error:
288                        assert!(
289                            !self.0.repr.packed,
290                            "attribute should be applied to a struct or union"
291                        );
292                        write!(f, "»")
293                    }
294                }
295                let show_enum = __Display(enum_type);
296                write!(f, "User(Enum({show_enum}))")?;
297            }
298            Type::User(UserType::Union(union_type)) => {
299                struct __Display<'a>(&'a UnionType);
300                impl<'a> fmt::Display for __Display<'a> {
301                    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
302                        write!(f, "«")?;
303                        write!(f, "fields: (")?;
304                        let mut fields_iter = self.0.fields.iter();
305                        if let Some(field) = fields_iter.next() {
306                            write!(f, "{}", field.name)?;
307                            for field in fields_iter {
308                                write!(f, ", {}", field.name)?;
309                            }
310                        }
311                        write!(f, ")")?;
312                        // Only show the `#[repr(_)]` if it's not `Rust` (unless it's `repr(packed)`).
313                        if let BaseRepr::C = self.0.repr.base {
314                            if self.0.repr.packed {
315                                // If there are multiple `repr` hints, display as a parenthesized list.
316                                write!(f, ", repr: (C, packed)")?;
317                            } else {
318                                write!(f, ", repr: C")?;
319                            }
320                        } else if let BaseRepr::Transparent = self.0.repr.base {
321                            // Nothing needs to change if `transparent_unions` is stabilized.
322                            // <https://github.com/rust-lang/rust/issues/60405>
323                            write!(f, ", repr: transparent")?;
324                            // Verbatim compiler error:
325                            assert!(
326                                !self.0.repr.packed,
327                                "transparent union cannot have other repr hints"
328                            );
329                        } else if self.0.repr.packed {
330                            // Here `Rust` is displayed because a lint asks you to specify explicitly,
331                            // despite the fact that `repr(Rust)` is the default.
332                            write!(f, ", repr: (Rust, packed)")?;
333                        }
334                        write!(f, "»")?;
335                        Ok(())
336                    }
337                }
338                let show_union = __Display(union_type);
339                write!(f, "User(Union({show_union}))")?;
340            }
341            Type::User(UserType::Opaque) => {
342                write!(f, "User(Opaque)")?;
343            }
344            Type::Pointer(PointerType::Reference(ptr_type)) => {
345                let show_ref = if ptr_type.mutable { "&mut " } else { "&" };
346                let target = ptr_type.target();
347                write!(f, "Pointer(Reference(«{show_ref}{target}»))")?;
348            }
349            Type::Pointer(PointerType::Raw(ptr_type)) => {
350                let show_raw = if ptr_type.mutable { "*mut " } else { "*const " };
351                let target = ptr_type.target();
352                write!(f, "Pointer(Raw(«{show_raw}{target}»))")?;
353            }
354            Type::Pointer(PointerType::Function(fn_ptr_def)) => {
355                struct __Display<'a>(&'a FunctionPointerDef);
356                impl fmt::Display for __Display<'_> {
357                    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
358                        write!(f, "«")?;
359                        write!(f, "fn(")?;
360                        let mut args_iter = self.0.parameters.iter();
361                        if let Some(arg) = args_iter.next() {
362                            write!(f, "{arg}")?;
363                            for arg in args_iter {
364                                write!(f, ", {arg}")?;
365                            }
366                        }
367                        let ret_ty = self.0.return_type;
368                        write!(f, ") -> {ret_ty}")?;
369                        write!(f, "»")?;
370                        Ok(())
371                    }
372                }
373                let show_fn = __Display(fn_ptr_def);
374                write!(f, "Pointer(Function({show_fn}))")?;
375            }
376        }
377        Ok(())
378    }
379}