facet_core/types/
mod.rs

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