1use 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#[derive(Clone, Copy, Debug)]
25#[repr(C)]
26#[non_exhaustive]
27pub struct Shape {
28 pub id: ConstTypeId,
30
31 pub layout: Layout,
33
34 pub vtable: &'static ValueVTable,
38
39 pub def: Def,
41
42 pub doc: &'static [&'static str],
44}
45
46impl Shape {
47 pub const fn is(&'static self, characteristic: Characteristic) -> bool {
49 match characteristic {
50 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 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 pub const fn is_send(&'static self) -> bool {
69 self.is(Characteristic::Send)
70 }
71
72 pub const fn is_sync(&'static self) -> bool {
74 self.is(Characteristic::Sync)
75 }
76
77 pub const fn is_copy(&'static self) -> bool {
79 self.is(Characteristic::Copy)
80 }
81
82 pub const fn is_eq(&'static self) -> bool {
84 self.is(Characteristic::Eq)
85 }
86
87 pub const fn is_clone(&'static self) -> bool {
89 self.is(Characteristic::Clone)
90 }
91
92 pub const fn is_debug(&'static self) -> bool {
94 self.is(Characteristic::Debug)
95 }
96
97 pub const fn is_partial_eq(&'static self) -> bool {
99 self.is(Characteristic::PartialEq)
100 }
101
102 pub const fn is_partial_ord(&'static self) -> bool {
104 self.is(Characteristic::PartialOrd)
105 }
106
107 pub const fn is_ord(&'static self) -> bool {
109 self.is(Characteristic::Ord)
110 }
111
112 pub const fn is_hash(&'static self) -> bool {
114 self.is(Characteristic::Hash)
115 }
116
117 pub const fn is_default(&'static self) -> bool {
119 self.is(Characteristic::Default)
120 }
121
122 pub fn write_type_name(&self, f: &mut fmt::Formatter<'_>, opts: TypeNameOpts) -> fmt::Result {
124 (self.vtable.type_name)(f, opts)
125 }
126
127 pub const fn builder() -> ShapeBuilder {
129 ShapeBuilder::new()
130 }
131
132 pub fn is_type<Other: Facet>(&'static self) -> bool {
134 let l = self;
135 let r = Other::SHAPE;
136 l == r
137 }
138
139 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
149pub 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 #[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 #[inline]
173 pub const fn id(mut self, id: ConstTypeId) -> Self {
174 self.id = Some(id);
175 self
176 }
177
178 #[inline]
180 pub const fn layout(mut self, layout: Layout) -> Self {
181 self.layout = Some(layout);
182 self
183 }
184
185 #[inline]
187 pub const fn vtable(mut self, vtable: &'static ValueVTable) -> Self {
188 self.vtable = Some(vtable);
189 self
190 }
191
192 #[inline]
194 pub const fn def(mut self, def: Def) -> Self {
195 self.def = Some(def);
196 self
197 }
198
199 #[inline]
201 pub const fn doc(mut self, doc: &'static [&'static str]) -> Self {
202 self.doc = doc;
203 self
204 }
205
206 #[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 pub fn is_shape(&'static self, other: &'static Shape) -> bool {
241 self == other
242 }
243
244 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
253impl 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 #[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 unsafe { alloc::alloc::alloc(self.layout) }
270 })
271 }
272}
273
274#[derive(Debug, Copy, Clone, PartialEq, Eq)]
276#[non_exhaustive]
277pub enum FieldError {
278 NoStaticFields,
282
283 NoSuchStaticField,
286
287 IndexOutOfBounds,
290
291 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#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
310#[repr(C)]
311#[non_exhaustive]
312pub struct StructDef {
313 pub kind: StructKind,
315
316 pub fields: &'static [Field],
318}
319
320impl StructDef {
321 pub const fn builder() -> StructDefBuilder {
323 StructDefBuilder::new()
324 }
325}
326
327pub struct StructDefBuilder {
329 kind: Option<StructKind>,
330 fields: Option<&'static [Field]>,
331}
332
333impl StructDefBuilder {
334 #[allow(clippy::new_without_default)]
336 pub const fn new() -> Self {
337 Self {
338 kind: None,
339 fields: None,
340 }
341 }
342
343 pub const fn kind(mut self, kind: StructKind) -> Self {
345 self.kind = Some(kind);
346 self
347 }
348
349 pub const fn fields(mut self, fields: &'static [Field]) -> Self {
351 self.fields = Some(fields);
352 self
353 }
354
355 pub const fn build(self) -> StructDef {
357 StructDef {
358 kind: self.kind.unwrap(),
359 fields: self.fields.unwrap(),
360 }
361 }
362}
363
364#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
366#[repr(C)]
367#[non_exhaustive]
368pub enum StructKind {
369 Struct,
371
372 TupleStruct,
374
375 Unit,
377
378 Tuple,
380}
381
382#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
384#[repr(C)]
385#[non_exhaustive]
386pub struct Field {
387 pub name: &'static str,
389
390 pub shape: &'static Shape,
392
393 pub offset: usize,
395
396 pub flags: FieldFlags,
398
399 pub attributes: &'static [FieldAttribute],
401
402 pub doc: &'static [&'static str],
404}
405
406impl Field {
407 pub const fn builder() -> FieldBuilder {
409 FieldBuilder::new()
410 }
411}
412
413pub 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#[non_exhaustive]
425#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
426#[repr(C)]
427pub enum FieldAttribute {
428 Sensitive,
430 Arbitrary(&'static str),
432}
433
434impl FieldBuilder {
435 #[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 pub const fn name(mut self, name: &'static str) -> Self {
450 self.name = Some(name);
451 self
452 }
453
454 pub const fn shape(mut self, shape: &'static Shape) -> Self {
456 self.shape = Some(shape);
457 self
458 }
459
460 pub const fn offset(mut self, offset: usize) -> Self {
462 self.offset = Some(offset);
463 self
464 }
465
466 pub const fn flags(mut self, flags: FieldFlags) -> Self {
468 self.flags = Some(flags);
469 self
470 }
471
472 pub const fn attributes(mut self, attributes: &'static [FieldAttribute]) -> Self {
474 self.attributes = attributes;
475 self
476 }
477
478 pub const fn doc(mut self, doc: &'static [&'static str]) -> Self {
480 self.doc = doc;
481 self
482 }
483
484 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 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
503 pub struct FieldFlags: u64 {
504 const EMPTY = 0;
506
507 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 let flags = [
527 (FieldFlags::SENSITIVE, "sensitive"),
528 ];
532
533 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#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
551#[repr(C)]
552#[non_exhaustive]
553pub struct MapDef {
554 pub vtable: &'static MapVTable,
556 pub k: &'static Shape,
558 pub v: &'static Shape,
560}
561
562impl MapDef {
563 pub const fn builder() -> MapDefBuilder {
565 MapDefBuilder::new()
566 }
567}
568
569pub struct MapDefBuilder {
571 vtable: Option<&'static MapVTable>,
572 k: Option<&'static Shape>,
573 v: Option<&'static Shape>,
574}
575
576impl MapDefBuilder {
577 #[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 pub const fn vtable(mut self, vtable: &'static MapVTable) -> Self {
589 self.vtable = Some(vtable);
590 self
591 }
592
593 pub const fn k(mut self, k: &'static Shape) -> Self {
595 self.k = Some(k);
596 self
597 }
598
599 pub const fn v(mut self, v: &'static Shape) -> Self {
601 self.v = Some(v);
602 self
603 }
604
605 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#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
617#[repr(C)]
618#[non_exhaustive]
619pub struct ListDef {
620 pub vtable: &'static ListVTable,
622 pub t: &'static Shape,
624}
625
626impl ListDef {
627 pub const fn builder() -> ListDefBuilder {
629 ListDefBuilder::new()
630 }
631}
632
633pub struct ListDefBuilder {
635 vtable: Option<&'static ListVTable>,
636 t: Option<&'static Shape>,
637}
638
639impl ListDefBuilder {
640 #[allow(clippy::new_without_default)]
642 pub const fn new() -> Self {
643 Self {
644 vtable: None,
645 t: None,
646 }
647 }
648
649 pub const fn vtable(mut self, vtable: &'static ListVTable) -> Self {
651 self.vtable = Some(vtable);
652 self
653 }
654
655 pub const fn t(mut self, t: &'static Shape) -> Self {
657 self.t = Some(t);
658 self
659 }
660
661 pub const fn build(self) -> ListDef {
663 ListDef {
664 vtable: self.vtable.unwrap(),
665 t: self.t.unwrap(),
666 }
667 }
668}
669
670#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
672#[repr(C)]
673#[non_exhaustive]
674pub struct OptionDef {
675 pub vtable: &'static OptionVTable,
677 pub t: &'static Shape,
679}
680
681impl OptionDef {
682 pub const fn builder() -> OptionDefBuilder {
684 OptionDefBuilder::new()
685 }
686}
687
688pub struct OptionDefBuilder {
690 vtable: Option<&'static OptionVTable>,
691 t: Option<&'static Shape>,
692}
693
694impl OptionDefBuilder {
695 #[allow(clippy::new_without_default)]
697 pub const fn new() -> Self {
698 Self {
699 vtable: None,
700 t: None,
701 }
702 }
703
704 pub const fn vtable(mut self, vtable: &'static OptionVTable) -> Self {
706 self.vtable = Some(vtable);
707 self
708 }
709
710 pub const fn t(mut self, t: &'static Shape) -> Self {
712 self.t = Some(t);
713 self
714 }
715
716 pub const fn build(self) -> OptionDef {
718 OptionDef {
719 vtable: self.vtable.unwrap(),
720 t: self.t.unwrap(),
721 }
722 }
723}
724
725#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
727#[repr(C)]
728#[non_exhaustive]
729pub struct EnumDef {
730 pub repr: EnumRepr,
732 pub variants: &'static [Variant],
734}
735
736impl EnumDef {
737 pub const fn builder() -> EnumDefBuilder {
739 EnumDefBuilder::new()
740 }
741}
742
743pub struct EnumDefBuilder {
745 repr: Option<EnumRepr>,
746 variants: Option<&'static [Variant]>,
747}
748
749impl EnumDefBuilder {
750 #[allow(clippy::new_without_default)]
752 pub const fn new() -> Self {
753 Self {
754 repr: None,
755 variants: None,
756 }
757 }
758
759 pub const fn repr(mut self, repr: EnumRepr) -> Self {
761 self.repr = Some(repr);
762 self
763 }
764
765 pub const fn variants(mut self, variants: &'static [Variant]) -> Self {
767 self.variants = Some(variants);
768 self
769 }
770
771 pub const fn build(self) -> EnumDef {
773 EnumDef {
774 repr: self.repr.unwrap(),
775 variants: self.variants.unwrap(),
776 }
777 }
778}
779
780#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
782#[repr(C)]
783#[non_exhaustive]
784pub struct Variant {
785 pub name: &'static str,
787
788 pub discriminant: Option<i64>,
790
791 pub kind: VariantKind,
793
794 pub doc: &'static [&'static str],
796}
797
798impl Variant {
799 pub const fn builder() -> VariantBuilder {
801 VariantBuilder::new()
802 }
803}
804
805pub 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 #[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 pub const fn name(mut self, name: &'static str) -> Self {
827 self.name = Some(name);
828 self
829 }
830
831 pub const fn discriminant(mut self, discriminant: Option<i64>) -> Self {
833 self.discriminant = Some(discriminant);
834 self
835 }
836
837 pub const fn kind(mut self, kind: VariantKind) -> Self {
839 self.kind = Some(kind);
840 self
841 }
842
843 pub const fn doc(mut self, doc: &'static [&'static str]) -> Self {
845 self.doc = doc;
846 self
847 }
848
849 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#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
862#[repr(C)]
863#[non_exhaustive]
864pub enum VariantKind {
865 Unit,
867
868 Tuple {
870 fields: &'static [Field],
872 },
873
874 Struct {
876 fields: &'static [Field],
878 },
879}
880
881#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
883#[repr(C)]
884#[non_exhaustive]
885pub enum EnumRepr {
886 U8,
888 U16,
890 U32,
892 U64,
894 USize,
896 I8,
898 I16,
900 I32,
902 I64,
904 ISize,
906}
907
908#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
910#[repr(C)]
911#[non_exhaustive]
912pub struct ScalarDef {
913 pub affinity: ScalarAffinity,
916}
917
918impl ScalarDef {
919 pub const fn builder() -> ScalarDefBuilder {
921 ScalarDefBuilder::new()
922 }
923}
924
925#[derive(Default)]
927pub struct ScalarDefBuilder {
928 affinity: Option<ScalarAffinity>,
929}
930
931impl ScalarDefBuilder {
932 #[allow(clippy::new_without_default)]
934 pub const fn new() -> Self {
935 Self { affinity: None }
936 }
937
938 pub const fn affinity(mut self, affinity: ScalarAffinity) -> Self {
940 self.affinity = Some(affinity);
941 self
942 }
943
944 pub const fn build(self) -> ScalarDef {
946 ScalarDef {
947 affinity: self.affinity.unwrap(),
948 }
949 }
950}
951
952#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
954#[repr(C)]
955#[non_exhaustive]
956pub enum Def {
957 Scalar(ScalarDef),
962
963 Struct(StructDef),
967
968 Map(MapDef),
972
973 List(ListDef),
977
978 Enum(EnumDef),
982
983 Option(OptionDef),
987}
988
989#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
991#[repr(C)]
992#[non_exhaustive]
993pub enum Characteristic {
994 Send,
997
998 Sync,
1000
1001 Copy,
1003
1004 Eq,
1006
1007 Clone,
1010
1011 Debug,
1013
1014 PartialEq,
1016
1017 PartialOrd,
1019
1020 Ord,
1022
1023 Hash,
1025
1026 Default,
1028}
1029
1030impl Characteristic {
1031 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 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 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}