1use 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#[derive(Clone, Copy, Debug)]
24#[repr(C)]
25#[non_exhaustive]
26pub struct Shape {
27 pub id: ConstTypeId,
29
30 pub layout: Layout,
32
33 pub vtable: &'static ValueVTable,
37
38 pub def: Def,
40
41 pub doc: &'static [&'static str],
43}
44
45impl Shape {
46 pub const fn is(&'static self, characteristic: Characteristic) -> bool {
48 match characteristic {
49 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 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 pub const fn is_send(&'static self) -> bool {
68 self.is(Characteristic::Send)
69 }
70
71 pub const fn is_sync(&'static self) -> bool {
73 self.is(Characteristic::Sync)
74 }
75
76 pub const fn is_copy(&'static self) -> bool {
78 self.is(Characteristic::Copy)
79 }
80
81 pub const fn is_eq(&'static self) -> bool {
83 self.is(Characteristic::Eq)
84 }
85
86 pub const fn is_clone(&'static self) -> bool {
88 self.is(Characteristic::Clone)
89 }
90
91 pub const fn is_debug(&'static self) -> bool {
93 self.is(Characteristic::Debug)
94 }
95
96 pub const fn is_partial_eq(&'static self) -> bool {
98 self.is(Characteristic::PartialEq)
99 }
100
101 pub const fn is_partial_ord(&'static self) -> bool {
103 self.is(Characteristic::PartialOrd)
104 }
105
106 pub const fn is_ord(&'static self) -> bool {
108 self.is(Characteristic::Ord)
109 }
110
111 pub const fn is_hash(&'static self) -> bool {
113 self.is(Characteristic::Hash)
114 }
115
116 pub const fn is_default(&'static self) -> bool {
118 self.is(Characteristic::Default)
119 }
120
121 pub fn write_type_name(&self, f: &mut fmt::Formatter<'_>, opts: TypeNameOpts) -> fmt::Result {
123 (self.vtable.type_name)(f, opts)
124 }
125
126 pub const fn builder() -> ShapeBuilder {
128 ShapeBuilder::new()
129 }
130
131 pub fn is_type<Other: Facet>(&'static self) -> bool {
133 let l = self;
134 let r = Other::SHAPE;
135 l == r
136 }
137
138 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
148pub 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 #[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 #[inline]
172 pub const fn id(mut self, id: ConstTypeId) -> Self {
173 self.id = Some(id);
174 self
175 }
176
177 #[inline]
179 pub const fn layout(mut self, layout: Layout) -> Self {
180 self.layout = Some(layout);
181 self
182 }
183
184 #[inline]
186 pub const fn vtable(mut self, vtable: &'static ValueVTable) -> Self {
187 self.vtable = Some(vtable);
188 self
189 }
190
191 #[inline]
193 pub const fn def(mut self, def: Def) -> Self {
194 self.def = Some(def);
195 self
196 }
197
198 #[inline]
200 pub const fn doc(mut self, doc: &'static [&'static str]) -> Self {
201 self.doc = doc;
202 self
203 }
204
205 #[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 pub fn is_shape(&'static self, other: &'static Shape) -> bool {
240 self == other
241 }
242
243 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
252impl 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 #[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 unsafe { std::alloc::alloc(self.layout) }
269 })
270 }
271}
272
273#[derive(Debug, Copy, Clone, PartialEq, Eq)]
275#[non_exhaustive]
276pub enum FieldError {
277 NoStaticFields,
281
282 NoSuchStaticField,
285
286 IndexOutOfBounds,
289
290 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#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
309#[repr(C)]
310#[non_exhaustive]
311pub struct StructDef {
312 pub kind: StructKind,
314
315 pub fields: &'static [Field],
317}
318
319impl StructDef {
320 pub const fn builder() -> StructDefBuilder {
322 StructDefBuilder::new()
323 }
324}
325
326pub struct StructDefBuilder {
328 kind: Option<StructKind>,
329 fields: Option<&'static [Field]>,
330}
331
332impl StructDefBuilder {
333 #[allow(clippy::new_without_default)]
335 pub const fn new() -> Self {
336 Self {
337 kind: None,
338 fields: None,
339 }
340 }
341
342 pub const fn kind(mut self, kind: StructKind) -> Self {
344 self.kind = Some(kind);
345 self
346 }
347
348 pub const fn fields(mut self, fields: &'static [Field]) -> Self {
350 self.fields = Some(fields);
351 self
352 }
353
354 pub const fn build(self) -> StructDef {
356 StructDef {
357 kind: self.kind.unwrap(),
358 fields: self.fields.unwrap(),
359 }
360 }
361}
362
363#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
365#[repr(C)]
366#[non_exhaustive]
367pub enum StructKind {
368 Struct,
370
371 TupleStruct,
373
374 Unit,
376
377 Tuple,
379}
380
381#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
383#[repr(C)]
384#[non_exhaustive]
385pub struct Field {
386 pub name: &'static str,
388
389 pub shape: &'static Shape,
391
392 pub offset: usize,
394
395 pub flags: FieldFlags,
397
398 pub attributes: &'static [FieldAttribute],
400
401 pub doc: &'static [&'static str],
403}
404
405impl Field {
406 pub const fn builder() -> FieldBuilder {
408 FieldBuilder::new()
409 }
410}
411
412pub 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#[non_exhaustive]
424#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
425#[repr(C)]
426pub enum FieldAttribute {
427 Sensitive,
429 Arbitrary(&'static str),
431}
432
433impl FieldBuilder {
434 #[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 pub const fn name(mut self, name: &'static str) -> Self {
449 self.name = Some(name);
450 self
451 }
452
453 pub const fn shape(mut self, shape: &'static Shape) -> Self {
455 self.shape = Some(shape);
456 self
457 }
458
459 pub const fn offset(mut self, offset: usize) -> Self {
461 self.offset = Some(offset);
462 self
463 }
464
465 pub const fn flags(mut self, flags: FieldFlags) -> Self {
467 self.flags = Some(flags);
468 self
469 }
470
471 pub const fn attributes(mut self, attributes: &'static [FieldAttribute]) -> Self {
473 self.attributes = attributes;
474 self
475 }
476
477 pub const fn doc(mut self, doc: &'static [&'static str]) -> Self {
479 self.doc = doc;
480 self
481 }
482
483 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 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
502 pub struct FieldFlags: u64 {
503 const EMPTY = 0;
505
506 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 let flags = [
526 (FieldFlags::SENSITIVE, "sensitive"),
527 ];
531
532 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#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
550#[repr(C)]
551#[non_exhaustive]
552pub struct MapDef {
553 pub vtable: &'static MapVTable,
555 pub k: &'static Shape,
557 pub v: &'static Shape,
559}
560
561impl MapDef {
562 pub const fn builder() -> MapDefBuilder {
564 MapDefBuilder::new()
565 }
566}
567
568pub struct MapDefBuilder {
570 vtable: Option<&'static MapVTable>,
571 k: Option<&'static Shape>,
572 v: Option<&'static Shape>,
573}
574
575impl MapDefBuilder {
576 #[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 pub const fn vtable(mut self, vtable: &'static MapVTable) -> Self {
588 self.vtable = Some(vtable);
589 self
590 }
591
592 pub const fn k(mut self, k: &'static Shape) -> Self {
594 self.k = Some(k);
595 self
596 }
597
598 pub const fn v(mut self, v: &'static Shape) -> Self {
600 self.v = Some(v);
601 self
602 }
603
604 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#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
616#[repr(C)]
617#[non_exhaustive]
618pub struct ListDef {
619 pub vtable: &'static ListVTable,
621 pub t: &'static Shape,
623}
624
625impl ListDef {
626 pub const fn builder() -> ListDefBuilder {
628 ListDefBuilder::new()
629 }
630}
631
632pub struct ListDefBuilder {
634 vtable: Option<&'static ListVTable>,
635 t: Option<&'static Shape>,
636}
637
638impl ListDefBuilder {
639 #[allow(clippy::new_without_default)]
641 pub const fn new() -> Self {
642 Self {
643 vtable: None,
644 t: None,
645 }
646 }
647
648 pub const fn vtable(mut self, vtable: &'static ListVTable) -> Self {
650 self.vtable = Some(vtable);
651 self
652 }
653
654 pub const fn t(mut self, t: &'static Shape) -> Self {
656 self.t = Some(t);
657 self
658 }
659
660 pub const fn build(self) -> ListDef {
662 ListDef {
663 vtable: self.vtable.unwrap(),
664 t: self.t.unwrap(),
665 }
666 }
667}
668
669#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
671#[repr(C)]
672#[non_exhaustive]
673pub struct EnumDef {
674 pub repr: EnumRepr,
676 pub variants: &'static [Variant],
678}
679
680impl EnumDef {
681 pub const fn builder() -> EnumDefBuilder {
683 EnumDefBuilder::new()
684 }
685}
686
687pub struct EnumDefBuilder {
689 repr: Option<EnumRepr>,
690 variants: Option<&'static [Variant]>,
691}
692
693impl EnumDefBuilder {
694 #[allow(clippy::new_without_default)]
696 pub const fn new() -> Self {
697 Self {
698 repr: None,
699 variants: None,
700 }
701 }
702
703 pub const fn repr(mut self, repr: EnumRepr) -> Self {
705 self.repr = Some(repr);
706 self
707 }
708
709 pub const fn variants(mut self, variants: &'static [Variant]) -> Self {
711 self.variants = Some(variants);
712 self
713 }
714
715 pub const fn build(self) -> EnumDef {
717 EnumDef {
718 repr: self.repr.unwrap(),
719 variants: self.variants.unwrap(),
720 }
721 }
722}
723
724#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
726#[repr(C)]
727#[non_exhaustive]
728pub struct Variant {
729 pub name: &'static str,
731
732 pub discriminant: Option<i64>,
734
735 pub kind: VariantKind,
737
738 pub doc: &'static [&'static str],
740}
741
742impl Variant {
743 pub const fn builder() -> VariantBuilder {
745 VariantBuilder::new()
746 }
747}
748
749pub 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 #[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 pub const fn name(mut self, name: &'static str) -> Self {
771 self.name = Some(name);
772 self
773 }
774
775 pub const fn discriminant(mut self, discriminant: Option<i64>) -> Self {
777 self.discriminant = Some(discriminant);
778 self
779 }
780
781 pub const fn kind(mut self, kind: VariantKind) -> Self {
783 self.kind = Some(kind);
784 self
785 }
786
787 pub const fn doc(mut self, doc: &'static [&'static str]) -> Self {
789 self.doc = doc;
790 self
791 }
792
793 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#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
806#[repr(C)]
807#[non_exhaustive]
808pub enum VariantKind {
809 Unit,
811
812 Tuple {
814 fields: &'static [Field],
816 },
817
818 Struct {
820 fields: &'static [Field],
822 },
823}
824
825#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
827#[repr(C)]
828#[non_exhaustive]
829pub enum EnumRepr {
830 Default,
832 U8,
834 U16,
836 U32,
838 U64,
840 USize,
842 I8,
844 I16,
846 I32,
848 I64,
850 ISize,
852}
853
854impl Default for EnumRepr {
855 fn default() -> Self {
856 Self::Default
857 }
858}
859
860#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
862#[repr(C)]
863#[non_exhaustive]
864pub struct ScalarDef {
865 pub affinity: ScalarAffinity,
868}
869
870impl ScalarDef {
871 pub const fn builder() -> ScalarDefBuilder {
873 ScalarDefBuilder::new()
874 }
875}
876
877#[derive(Default)]
879pub struct ScalarDefBuilder {
880 affinity: Option<ScalarAffinity>,
881}
882
883impl ScalarDefBuilder {
884 #[allow(clippy::new_without_default)]
886 pub const fn new() -> Self {
887 Self { affinity: None }
888 }
889
890 pub const fn affinity(mut self, affinity: ScalarAffinity) -> Self {
892 self.affinity = Some(affinity);
893 self
894 }
895
896 pub const fn build(self) -> ScalarDef {
898 ScalarDef {
899 affinity: self.affinity.unwrap(),
900 }
901 }
902}
903
904#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
906#[repr(C)]
907#[non_exhaustive]
908pub enum Def {
909 Scalar(ScalarDef),
914
915 Struct(StructDef),
919
920 Map(MapDef),
924
925 List(ListDef),
929
930 Enum(EnumDef),
934}
935
936#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
938#[repr(C)]
939#[non_exhaustive]
940pub enum Characteristic {
941 Send,
944
945 Sync,
947
948 Copy,
950
951 Eq,
953
954 Clone,
957
958 Debug,
960
961 PartialEq,
963
964 PartialOrd,
966
967 Ord,
969
970 Hash,
972
973 Default,
975}
976
977impl Characteristic {
978 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 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 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}