facet_core/types/
mod.rs

1//! structs and vtable definitions used by Facet
2
3use core::alloc::Layout;
4use core::fmt;
5
6mod list;
7pub use list::*;
8
9mod map;
10pub use map::*;
11
12mod value;
13pub use value::*;
14
15mod option;
16pub use option::*;
17
18mod scalar_affinities;
19pub use scalar_affinities::*;
20
21use crate::{ConstTypeId, Facet};
22
23/// Schema for reflection of a type
24#[derive(Clone, Copy, Debug)]
25#[repr(C)]
26#[non_exhaustive]
27pub struct Shape {
28    /// Type ID
29    pub id: ConstTypeId,
30
31    /// Size, alignment
32    pub layout: Layout,
33
34    /// VTable for common operations. This is indirected because the vtable might
35    /// have different functions implemented based on generic type parameters:
36    /// HashMap<K, V> is not even constructible if `K` is not `Hash` + `Eq`.
37    pub vtable: &'static ValueVTable,
38
39    /// Details/contents of the value
40    pub def: Def,
41
42    /// Doc comments — if there's multiple lines, they're all concatenated
43    pub doc: &'static [&'static str],
44}
45
46impl Shape {
47    /// Checks if a shape has the given characteristic.
48    pub const fn is(&'static self, characteristic: Characteristic) -> bool {
49        match characteristic {
50            // Marker traits
51            Characteristic::Send => self.vtable.marker_traits.contains(MarkerTraits::SEND),
52            Characteristic::Sync => self.vtable.marker_traits.contains(MarkerTraits::SYNC),
53            Characteristic::Copy => self.vtable.marker_traits.contains(MarkerTraits::COPY),
54            Characteristic::Eq => self.vtable.marker_traits.contains(MarkerTraits::EQ),
55
56            // Functionality traits
57            Characteristic::Clone => self.vtable.clone_into.is_some(),
58            Characteristic::Debug => self.vtable.debug.is_some(),
59            Characteristic::PartialEq => self.vtable.eq.is_some(),
60            Characteristic::PartialOrd => self.vtable.partial_ord.is_some(),
61            Characteristic::Ord => self.vtable.ord.is_some(),
62            Characteristic::Hash => self.vtable.hash.is_some(),
63            Characteristic::Default => self.vtable.default_in_place.is_some(),
64        }
65    }
66
67    /// Check if this shape implements the Send trait
68    pub const fn is_send(&'static self) -> bool {
69        self.is(Characteristic::Send)
70    }
71
72    /// Check if this shape implements the Sync trait
73    pub const fn is_sync(&'static self) -> bool {
74        self.is(Characteristic::Sync)
75    }
76
77    /// Check if this shape implements the Copy trait
78    pub const fn is_copy(&'static self) -> bool {
79        self.is(Characteristic::Copy)
80    }
81
82    /// Check if this shape implements the Eq trait
83    pub const fn is_eq(&'static self) -> bool {
84        self.is(Characteristic::Eq)
85    }
86
87    /// Check if this shape implements the Clone trait
88    pub const fn is_clone(&'static self) -> bool {
89        self.is(Characteristic::Clone)
90    }
91
92    /// Check if this shape implements the Debug trait
93    pub const fn is_debug(&'static self) -> bool {
94        self.is(Characteristic::Debug)
95    }
96
97    /// Check if this shape implements the PartialEq trait
98    pub const fn is_partial_eq(&'static self) -> bool {
99        self.is(Characteristic::PartialEq)
100    }
101
102    /// Check if this shape implements the PartialOrd trait
103    pub const fn is_partial_ord(&'static self) -> bool {
104        self.is(Characteristic::PartialOrd)
105    }
106
107    /// Check if this shape implements the Ord trait
108    pub const fn is_ord(&'static self) -> bool {
109        self.is(Characteristic::Ord)
110    }
111
112    /// Check if this shape implements the Hash trait
113    pub const fn is_hash(&'static self) -> bool {
114        self.is(Characteristic::Hash)
115    }
116
117    /// Check if this shape implements the Default trait
118    pub const fn is_default(&'static self) -> bool {
119        self.is(Characteristic::Default)
120    }
121
122    /// Writes the name of this type to the given formatter
123    pub fn write_type_name(&self, f: &mut fmt::Formatter<'_>, opts: TypeNameOpts) -> fmt::Result {
124        (self.vtable.type_name)(f, opts)
125    }
126
127    /// Returns a builder for shape
128    pub const fn builder() -> ShapeBuilder {
129        ShapeBuilder::new()
130    }
131
132    /// Check if this shape is of the given type
133    pub fn is_type<Other: Facet>(&'static self) -> bool {
134        let l = self;
135        let r = Other::SHAPE;
136        l == r
137    }
138
139    /// Assert that this shape is of the given type, panicking if it's not
140    pub fn assert_type<Other: Facet>(&'static self) {
141        assert!(
142            self.is_type::<Other>(),
143            "Type mismatch: expected {}, found {self}",
144            Other::SHAPE,
145        );
146    }
147}
148
149/// Builder for [`Shape`]
150pub struct ShapeBuilder {
151    id: Option<ConstTypeId>,
152    layout: Option<Layout>,
153    vtable: Option<&'static ValueVTable>,
154    def: Option<Def>,
155    doc: &'static [&'static str],
156}
157
158impl ShapeBuilder {
159    /// Creates a new `ShapeBuilder` with all fields set to `None`.
160    #[allow(clippy::new_without_default)]
161    pub const fn new() -> Self {
162        Self {
163            id: None,
164            layout: None,
165            vtable: None,
166            def: None,
167            doc: &[],
168        }
169    }
170
171    /// Sets the id field of the `ShapeBuilder`.
172    #[inline]
173    pub const fn id(mut self, id: ConstTypeId) -> Self {
174        self.id = Some(id);
175        self
176    }
177
178    /// Sets the `layout` field of the `ShapeBuilder`.
179    #[inline]
180    pub const fn layout(mut self, layout: Layout) -> Self {
181        self.layout = Some(layout);
182        self
183    }
184
185    /// Sets the `vtable` field of the `ShapeBuilder`.
186    #[inline]
187    pub const fn vtable(mut self, vtable: &'static ValueVTable) -> Self {
188        self.vtable = Some(vtable);
189        self
190    }
191
192    /// Sets the `def` field of the `ShapeBuilder`.
193    #[inline]
194    pub const fn def(mut self, def: Def) -> Self {
195        self.def = Some(def);
196        self
197    }
198
199    /// Sets the `doc` field of the `ShapeBuilder`.
200    #[inline]
201    pub const fn doc(mut self, doc: &'static [&'static str]) -> Self {
202        self.doc = doc;
203        self
204    }
205
206    /// Builds a `Shape` from the `ShapeBuilder`.
207    ///
208    /// # Panics
209    ///
210    /// This method will panic if any of the required fields (`layout`, `vtable`, or `def`) are `None`.
211    #[inline]
212    pub const fn build(self) -> Shape {
213        Shape {
214            id: self.id.unwrap(),
215            layout: self.layout.unwrap(),
216            vtable: self.vtable.unwrap(),
217            def: self.def.unwrap(),
218            doc: self.doc,
219        }
220    }
221}
222
223impl PartialEq for Shape {
224    fn eq(&self, other: &Self) -> bool {
225        self.def == other.def && self.layout == other.layout
226    }
227}
228
229impl Eq for Shape {}
230
231impl core::hash::Hash for Shape {
232    fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
233        self.def.hash(state);
234        self.layout.hash(state);
235    }
236}
237
238impl Shape {
239    /// Check if this shape is of the given type
240    pub fn is_shape(&'static self, other: &'static Shape) -> bool {
241        self == other
242    }
243
244    /// Assert that this shape is equal to the given shape, panicking if it's not
245    pub fn assert_shape(&'static self, other: &'static Shape) {
246        assert!(
247            self.is_shape(other),
248            "Shape mismatch: expected {other}, found {self}",
249        );
250    }
251}
252
253// Helper struct to format the name for display
254impl core::fmt::Display for Shape {
255    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
256        (self.vtable.type_name)(f, TypeNameOpts::default())
257    }
258}
259
260impl Shape {
261    /// Heap-allocate a value of this shape
262    #[cfg(feature = "alloc")]
263    #[inline]
264    pub fn allocate(&self) -> crate::opaque::OpaqueUninit<'static> {
265        crate::opaque::OpaqueUninit::new(if self.layout.size() == 0 {
266            core::ptr::without_provenance_mut(self.layout.align())
267        } else {
268            // SAFETY: We have checked that layout's size is non-zero
269            unsafe { alloc::alloc::alloc(self.layout) }
270        })
271    }
272}
273
274/// Errors encountered when calling `field_by_index` or `field_by_name`
275#[derive(Debug, Copy, Clone, PartialEq, Eq)]
276#[non_exhaustive]
277pub enum FieldError {
278    /// `field_by_index` was called on a dynamic collection, that has no
279    /// static fields. a map doesn't have a "first field", it can only
280    /// associate by keys.
281    NoStaticFields,
282
283    /// `field_by_name` was called on a struct, and there is no static field
284    /// with the given key.
285    NoSuchStaticField,
286
287    /// `field_by_index` was called on a fixed-size collection (like a tuple,
288    /// a struct, or a fixed-size array) and the index was out of bounds.
289    IndexOutOfBounds,
290
291    /// `field_by_index` or `field_by_name` was called on a non-struct type.
292    NotAStruct,
293}
294
295impl core::error::Error for FieldError {}
296
297impl core::fmt::Display for FieldError {
298    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
299        match self {
300            FieldError::NoStaticFields => write!(f, "No static fields available"),
301            FieldError::NoSuchStaticField => write!(f, "No such static field"),
302            FieldError::IndexOutOfBounds => write!(f, "Index out of bounds"),
303            FieldError::NotAStruct => write!(f, "Not a struct"),
304        }
305    }
306}
307
308/// Common fields for struct-like types
309#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
310#[repr(C)]
311#[non_exhaustive]
312pub struct StructDef {
313    /// the kind of struct (e.g. struct, tuple struct, tuple)
314    pub kind: StructKind,
315
316    /// all fields, in declaration order (not necessarily in memory order)
317    pub fields: &'static [Field],
318}
319
320impl StructDef {
321    /// Returns a builder for StructDef
322    pub const fn builder() -> StructDefBuilder {
323        StructDefBuilder::new()
324    }
325}
326
327/// Builder for StructDef
328pub struct StructDefBuilder {
329    kind: Option<StructKind>,
330    fields: Option<&'static [Field]>,
331}
332
333impl StructDefBuilder {
334    /// Creates a new StructDefBuilder
335    #[allow(clippy::new_without_default)]
336    pub const fn new() -> Self {
337        Self {
338            kind: None,
339            fields: None,
340        }
341    }
342
343    /// Sets the kind for the StructDef
344    pub const fn kind(mut self, kind: StructKind) -> Self {
345        self.kind = Some(kind);
346        self
347    }
348
349    /// Sets the fields for the StructDef
350    pub const fn fields(mut self, fields: &'static [Field]) -> Self {
351        self.fields = Some(fields);
352        self
353    }
354
355    /// Builds the StructDef
356    pub const fn build(self) -> StructDef {
357        StructDef {
358            kind: self.kind.unwrap(),
359            fields: self.fields.unwrap(),
360        }
361    }
362}
363
364/// Describes the kind of struct (useful for deserializing)
365#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
366#[repr(C)]
367#[non_exhaustive]
368pub enum StructKind {
369    /// struct S { t0: T0, t1: T1 }
370    Struct,
371
372    /// struct TupleStruct(T0, T1);
373    TupleStruct,
374
375    /// struct UnitStruct;
376    Unit,
377
378    /// (T0, T1)
379    Tuple,
380}
381
382/// Describes a field in a struct or tuple
383#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
384#[repr(C)]
385#[non_exhaustive]
386pub struct Field {
387    /// key for the struct field (for tuples and tuple-structs, this is the 0-based index)
388    pub name: &'static str,
389
390    /// schema of the inner type
391    pub shape: &'static Shape,
392
393    /// offset of the field in the struct (obtained through `core::mem::offset_of`)
394    pub offset: usize,
395
396    /// flags for the field (e.g. sensitive, etc.)
397    pub flags: FieldFlags,
398
399    /// arbitrary attributes set via the derive macro
400    pub attributes: &'static [FieldAttribute],
401
402    /// doc comments
403    pub doc: &'static [&'static str],
404}
405
406impl Field {
407    /// Returns a builder for Field
408    pub const fn builder() -> FieldBuilder {
409        FieldBuilder::new()
410    }
411}
412
413/// Builder for Field
414pub struct FieldBuilder {
415    name: Option<&'static str>,
416    shape: Option<&'static Shape>,
417    offset: Option<usize>,
418    flags: Option<FieldFlags>,
419    attributes: &'static [FieldAttribute],
420    doc: &'static [&'static str],
421}
422
423/// An attribute that can be set on a field
424#[non_exhaustive]
425#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
426#[repr(C)]
427pub enum FieldAttribute {
428    /// Marks field as containing sensitive information
429    Sensitive,
430    /// Custom field attribute containing arbitrary text
431    Arbitrary(&'static str),
432}
433
434impl FieldBuilder {
435    /// Creates a new FieldBuilder
436    #[allow(clippy::new_without_default)]
437    pub const fn new() -> Self {
438        Self {
439            name: None,
440            shape: None,
441            offset: None,
442            flags: None,
443            attributes: &[],
444            doc: &[],
445        }
446    }
447
448    /// Sets the name for the Field
449    pub const fn name(mut self, name: &'static str) -> Self {
450        self.name = Some(name);
451        self
452    }
453
454    /// Sets the shape for the Field
455    pub const fn shape(mut self, shape: &'static Shape) -> Self {
456        self.shape = Some(shape);
457        self
458    }
459
460    /// Sets the offset for the Field
461    pub const fn offset(mut self, offset: usize) -> Self {
462        self.offset = Some(offset);
463        self
464    }
465
466    /// Sets the flags for the Field
467    pub const fn flags(mut self, flags: FieldFlags) -> Self {
468        self.flags = Some(flags);
469        self
470    }
471
472    /// Sets the attributes for the Field
473    pub const fn attributes(mut self, attributes: &'static [FieldAttribute]) -> Self {
474        self.attributes = attributes;
475        self
476    }
477
478    /// Sets the doc comments for the Field
479    pub const fn doc(mut self, doc: &'static [&'static str]) -> Self {
480        self.doc = doc;
481        self
482    }
483
484    /// Builds the Field
485    pub const fn build(self) -> Field {
486        Field {
487            name: self.name.unwrap(),
488            shape: self.shape.unwrap(),
489            offset: self.offset.unwrap(),
490            flags: match self.flags {
491                Some(flags) => flags,
492                None => FieldFlags::EMPTY,
493            },
494            attributes: self.attributes,
495            doc: self.doc,
496        }
497    }
498}
499
500bitflags::bitflags! {
501    /// Flags that can be applied to fields to modify their behavior
502    #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
503    pub struct FieldFlags: u64 {
504        /// An empty set of flags
505        const EMPTY = 0;
506
507        /// Flag indicating this field contains sensitive data that should not be displayed
508        const SENSITIVE = 1 << 0;
509    }
510}
511
512impl Default for FieldFlags {
513    #[inline(always)]
514    fn default() -> Self {
515        Self::EMPTY
516    }
517}
518
519impl core::fmt::Display for FieldFlags {
520    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
521        if self.is_empty() {
522            return write!(f, "none");
523        }
524
525        // Define a vector of flag entries: (flag, name)
526        let flags = [
527            (FieldFlags::SENSITIVE, "sensitive"),
528            // Future flags can be easily added here:
529            // (FieldFlags::SOME_FLAG, "some_flag"),
530            // (FieldFlags::ANOTHER_FLAG, "another_flag"),
531        ];
532
533        // Write all active flags with proper separators
534        let mut is_first = true;
535        for (flag, name) in flags {
536            if self.contains(flag) {
537                if !is_first {
538                    write!(f, ", ")?;
539                }
540                is_first = false;
541                write!(f, "{}", name)?;
542            }
543        }
544
545        Ok(())
546    }
547}
548
549/// Fields for map types
550#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
551#[repr(C)]
552#[non_exhaustive]
553pub struct MapDef {
554    /// vtable for interacting with the map
555    pub vtable: &'static MapVTable,
556    /// shape of the keys in the map
557    pub k: &'static Shape,
558    /// shape of the values in the map
559    pub v: &'static Shape,
560}
561
562impl MapDef {
563    /// Returns a builder for MapDef
564    pub const fn builder() -> MapDefBuilder {
565        MapDefBuilder::new()
566    }
567}
568
569/// Builder for MapDef
570pub struct MapDefBuilder {
571    vtable: Option<&'static MapVTable>,
572    k: Option<&'static Shape>,
573    v: Option<&'static Shape>,
574}
575
576impl MapDefBuilder {
577    /// Creates a new MapDefBuilder
578    #[allow(clippy::new_without_default)]
579    pub const fn new() -> Self {
580        Self {
581            vtable: None,
582            k: None,
583            v: None,
584        }
585    }
586
587    /// Sets the vtable for the MapDef
588    pub const fn vtable(mut self, vtable: &'static MapVTable) -> Self {
589        self.vtable = Some(vtable);
590        self
591    }
592
593    /// Sets the key shape for the MapDef
594    pub const fn k(mut self, k: &'static Shape) -> Self {
595        self.k = Some(k);
596        self
597    }
598
599    /// Sets the value shape for the MapDef
600    pub const fn v(mut self, v: &'static Shape) -> Self {
601        self.v = Some(v);
602        self
603    }
604
605    /// Builds the MapDef
606    pub const fn build(self) -> MapDef {
607        MapDef {
608            vtable: self.vtable.unwrap(),
609            k: self.k.unwrap(),
610            v: self.v.unwrap(),
611        }
612    }
613}
614
615/// Fields for list types
616#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
617#[repr(C)]
618#[non_exhaustive]
619pub struct ListDef {
620    /// vtable for interacting with the list
621    pub vtable: &'static ListVTable,
622    /// shape of the items in the list
623    pub t: &'static Shape,
624}
625
626impl ListDef {
627    /// Returns a builder for ListDef
628    pub const fn builder() -> ListDefBuilder {
629        ListDefBuilder::new()
630    }
631}
632
633/// Builder for ListDef
634pub struct ListDefBuilder {
635    vtable: Option<&'static ListVTable>,
636    t: Option<&'static Shape>,
637}
638
639impl ListDefBuilder {
640    /// Creates a new ListDefBuilder
641    #[allow(clippy::new_without_default)]
642    pub const fn new() -> Self {
643        Self {
644            vtable: None,
645            t: None,
646        }
647    }
648
649    /// Sets the vtable for the ListDef
650    pub const fn vtable(mut self, vtable: &'static ListVTable) -> Self {
651        self.vtable = Some(vtable);
652        self
653    }
654
655    /// Sets the item shape for the ListDef
656    pub const fn t(mut self, t: &'static Shape) -> Self {
657        self.t = Some(t);
658        self
659    }
660
661    /// Builds the ListDef
662    pub const fn build(self) -> ListDef {
663        ListDef {
664            vtable: self.vtable.unwrap(),
665            t: self.t.unwrap(),
666        }
667    }
668}
669
670/// Fields for option types
671#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
672#[repr(C)]
673#[non_exhaustive]
674pub struct OptionDef {
675    /// vtable for interacting with the option
676    pub vtable: &'static OptionVTable,
677    /// shape of the inner type of the option
678    pub t: &'static Shape,
679}
680
681impl OptionDef {
682    /// Returns a builder for OptionDef
683    pub const fn builder() -> OptionDefBuilder {
684        OptionDefBuilder::new()
685    }
686}
687
688/// Builder for OptionDef
689pub struct OptionDefBuilder {
690    vtable: Option<&'static OptionVTable>,
691    t: Option<&'static Shape>,
692}
693
694impl OptionDefBuilder {
695    /// Creates a new OptionDefBuilder
696    #[allow(clippy::new_without_default)]
697    pub const fn new() -> Self {
698        Self {
699            vtable: None,
700            t: None,
701        }
702    }
703
704    /// Sets the vtable for the OptionDef
705    pub const fn vtable(mut self, vtable: &'static OptionVTable) -> Self {
706        self.vtable = Some(vtable);
707        self
708    }
709
710    /// Sets the inner type shape for the OptionDef
711    pub const fn t(mut self, t: &'static Shape) -> Self {
712        self.t = Some(t);
713        self
714    }
715
716    /// Builds the OptionDef
717    pub const fn build(self) -> OptionDef {
718        OptionDef {
719            vtable: self.vtable.unwrap(),
720            t: self.t.unwrap(),
721        }
722    }
723}
724
725/// Fields for enum types
726#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
727#[repr(C)]
728#[non_exhaustive]
729pub struct EnumDef {
730    /// representation of the enum (u8, u16, etc.)
731    pub repr: EnumRepr,
732    /// all variants for this enum
733    pub variants: &'static [Variant],
734}
735
736impl EnumDef {
737    /// Returns a builder for EnumDef
738    pub const fn builder() -> EnumDefBuilder {
739        EnumDefBuilder::new()
740    }
741}
742
743/// Builder for EnumDef
744pub struct EnumDefBuilder {
745    repr: Option<EnumRepr>,
746    variants: Option<&'static [Variant]>,
747}
748
749impl EnumDefBuilder {
750    /// Creates a new EnumDefBuilder
751    #[allow(clippy::new_without_default)]
752    pub const fn new() -> Self {
753        Self {
754            repr: None,
755            variants: None,
756        }
757    }
758
759    /// Sets the representation for the EnumDef
760    pub const fn repr(mut self, repr: EnumRepr) -> Self {
761        self.repr = Some(repr);
762        self
763    }
764
765    /// Sets the variants for the EnumDef
766    pub const fn variants(mut self, variants: &'static [Variant]) -> Self {
767        self.variants = Some(variants);
768        self
769    }
770
771    /// Builds the EnumDef
772    pub const fn build(self) -> EnumDef {
773        EnumDef {
774            repr: self.repr.unwrap(),
775            variants: self.variants.unwrap(),
776        }
777    }
778}
779
780/// Describes a variant of an enum
781#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
782#[repr(C)]
783#[non_exhaustive]
784pub struct Variant {
785    /// Name of the variant
786    pub name: &'static str,
787
788    /// Discriminant value (if available)
789    pub discriminant: Option<i64>,
790
791    /// Kind of variant (unit, tuple, or struct)
792    pub kind: VariantKind,
793
794    /// Doc comment for the variant
795    pub doc: &'static [&'static str],
796}
797
798impl Variant {
799    /// Returns a builder for Variant
800    pub const fn builder() -> VariantBuilder {
801        VariantBuilder::new()
802    }
803}
804
805/// Builder for Variant
806pub struct VariantBuilder {
807    name: Option<&'static str>,
808    discriminant: Option<Option<i64>>,
809    kind: Option<VariantKind>,
810    doc: &'static [&'static str],
811}
812
813impl VariantBuilder {
814    /// Creates a new VariantBuilder
815    #[allow(clippy::new_without_default)]
816    pub const fn new() -> Self {
817        Self {
818            name: None,
819            discriminant: None,
820            kind: None,
821            doc: &[],
822        }
823    }
824
825    /// Sets the name for the Variant
826    pub const fn name(mut self, name: &'static str) -> Self {
827        self.name = Some(name);
828        self
829    }
830
831    /// Sets the discriminant for the Variant
832    pub const fn discriminant(mut self, discriminant: Option<i64>) -> Self {
833        self.discriminant = Some(discriminant);
834        self
835    }
836
837    /// Sets the kind for the Variant
838    pub const fn kind(mut self, kind: VariantKind) -> Self {
839        self.kind = Some(kind);
840        self
841    }
842
843    /// Sets the doc comment for the Variant
844    pub const fn doc(mut self, doc: &'static [&'static str]) -> Self {
845        self.doc = doc;
846        self
847    }
848
849    /// Builds the Variant
850    pub const fn build(self) -> Variant {
851        Variant {
852            name: self.name.unwrap(),
853            discriminant: self.discriminant.unwrap(),
854            kind: self.kind.unwrap(),
855            doc: self.doc,
856        }
857    }
858}
859
860/// Represents the different kinds of variants that can exist in a Rust enum
861#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
862#[repr(C)]
863#[non_exhaustive]
864pub enum VariantKind {
865    /// Unit variant (e.g., `None` in Option)
866    Unit,
867
868    /// Tuple variant with unnamed fields (e.g., `Some(T)` in Option)
869    Tuple {
870        /// List of fields contained in the tuple variant
871        fields: &'static [Field],
872    },
873
874    /// Struct variant with named fields (e.g., `Struct { field: T }`)
875    Struct {
876        /// List of fields contained in the struct variant
877        fields: &'static [Field],
878    },
879}
880
881/// All possible representations for Rust enums
882#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
883#[repr(C)]
884#[non_exhaustive]
885pub enum EnumRepr {
886    /// u8 representation (#[repr(u8)])
887    U8,
888    /// u16 representation (#[repr(u16)])
889    U16,
890    /// u32 representation (#[repr(u32)])
891    U32,
892    /// u64 representation (#[repr(u64)])
893    U64,
894    /// usize representation (#[repr(usize)])
895    USize,
896    /// i8 representation (#[repr(i8)])
897    I8,
898    /// i16 representation (#[repr(i16)])
899    I16,
900    /// i32 representation (#[repr(i32)])
901    I32,
902    /// i64 representation (#[repr(i64)])
903    I64,
904    /// isize representation (#[repr(isize)])
905    ISize,
906}
907
908/// Definition for scalar types
909#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
910#[repr(C)]
911#[non_exhaustive]
912pub struct ScalarDef {
913    /// Affinity of the scalar — is spiritually more like a number, more like a string, something else?
914    /// example: an IPv4 address is both. good luck.
915    pub affinity: ScalarAffinity,
916}
917
918impl ScalarDef {
919    /// Returns a builder for ScalarDef
920    pub const fn builder() -> ScalarDefBuilder {
921        ScalarDefBuilder::new()
922    }
923}
924
925/// Builder for ScalarDef
926#[derive(Default)]
927pub struct ScalarDefBuilder {
928    affinity: Option<ScalarAffinity>,
929}
930
931impl ScalarDefBuilder {
932    /// Creates a new ScalarDefBuilder
933    #[allow(clippy::new_without_default)]
934    pub const fn new() -> Self {
935        Self { affinity: None }
936    }
937
938    /// Sets the affinity for the ScalarDef
939    pub const fn affinity(mut self, affinity: ScalarAffinity) -> Self {
940        self.affinity = Some(affinity);
941        self
942    }
943
944    /// Builds the ScalarDef
945    pub const fn build(self) -> ScalarDef {
946        ScalarDef {
947            affinity: self.affinity.unwrap(),
948        }
949    }
950}
951
952/// The definition of a shape: is it more like a struct, a map, a list?
953#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
954#[repr(C)]
955#[non_exhaustive]
956pub enum Def {
957    /// Scalar — those don't have a def, they're not composed of other things.
958    /// You can interact with them through [`ValueVTable`].
959    ///
960    /// e.g. `u32`, `String`, `bool`, `SocketAddr`, etc.
961    Scalar(ScalarDef),
962
963    /// Various kinds of structs, see [`StructKind`]
964    ///
965    /// e.g. `struct Struct { field: u32 }`, `struct TupleStruct(u32, u32);`, `(u32, u32)`
966    Struct(StructDef),
967
968    /// Map — keys are dynamic (and strings, sorry), values are homogeneous
969    ///
970    /// e.g. `Map<String, T>`
971    Map(MapDef),
972
973    /// Ordered list of heterogenous values, variable size
974    ///
975    /// e.g. `Vec<T>`
976    List(ListDef),
977
978    /// Enum with variants
979    ///
980    /// e.g. `enum Enum { Variant1, Variant2 }`
981    Enum(EnumDef),
982
983    /// Option
984    ///
985    /// e.g. `Option<T>`
986    Option(OptionDef),
987}
988
989/// A characteristic a shape can have
990#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
991#[repr(C)]
992#[non_exhaustive]
993pub enum Characteristic {
994    // Marker traits
995    /// Implements Send
996    Send,
997
998    /// Implements Sync
999    Sync,
1000
1001    /// Implements Copy
1002    Copy,
1003
1004    /// Implements Eq
1005    Eq,
1006
1007    // Functionality traits
1008    /// Implements Clone
1009    Clone,
1010
1011    /// Implements Debug
1012    Debug,
1013
1014    /// Implements PartialEq
1015    PartialEq,
1016
1017    /// Implements PartialOrd
1018    PartialOrd,
1019
1020    /// Implements Ord
1021    Ord,
1022
1023    /// Implements Hash
1024    Hash,
1025
1026    /// Implements Default
1027    Default,
1028}
1029
1030impl Characteristic {
1031    /// Checks if all shapes have the given characteristic.
1032    pub const fn all(self, shapes: &'static [&'static Shape]) -> bool {
1033        let mut i = 0;
1034        while i < shapes.len() {
1035            if !shapes[i].is(self) {
1036                return false;
1037            }
1038            i += 1;
1039        }
1040        true
1041    }
1042
1043    /// Checks if any shape has the given characteristic.
1044    pub const fn any(self, shapes: &'static [&'static Shape]) -> bool {
1045        let mut i = 0;
1046        while i < shapes.len() {
1047            if shapes[i].is(self) {
1048                return true;
1049            }
1050            i += 1;
1051        }
1052        false
1053    }
1054
1055    /// Checks if none of the shapes have the given characteristic.
1056    pub const fn none(self, shapes: &'static [&'static Shape]) -> bool {
1057        let mut i = 0;
1058        while i < shapes.len() {
1059            if shapes[i].is(self) {
1060                return false;
1061            }
1062            i += 1;
1063        }
1064        true
1065    }
1066}