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
17use crate::Facet;
18
19#[derive(Clone, Copy, Debug)]
21#[non_exhaustive]
22pub struct Shape {
23 pub layout: Layout,
25
26 pub vtable: &'static ValueVTable,
30
31 pub def: Def,
33}
34
35impl Shape {
36 pub const fn is(&'static self, characteristic: Characteristic) -> bool {
38 match characteristic {
39 Characteristic::Send => self.vtable.marker_traits.contains(MarkerTraits::SEND),
41 Characteristic::Sync => self.vtable.marker_traits.contains(MarkerTraits::SYNC),
42 Characteristic::Copy => self.vtable.marker_traits.contains(MarkerTraits::COPY),
43 Characteristic::Eq => self.vtable.marker_traits.contains(MarkerTraits::EQ),
44
45 Characteristic::Clone => self.vtable.clone_into.is_some(),
47 Characteristic::Debug => self.vtable.debug.is_some(),
48 Characteristic::PartialEq => self.vtable.eq.is_some(),
49 Characteristic::PartialOrd => self.vtable.partial_ord.is_some(),
50 Characteristic::Ord => self.vtable.ord.is_some(),
51 Characteristic::Hash => self.vtable.hash.is_some(),
52 Characteristic::Default => self.vtable.default_in_place.is_some(),
53 }
54 }
55
56 pub const fn is_send(&'static self) -> bool {
58 self.is(Characteristic::Send)
59 }
60
61 pub const fn is_sync(&'static self) -> bool {
63 self.is(Characteristic::Sync)
64 }
65
66 pub const fn is_copy(&'static self) -> bool {
68 self.is(Characteristic::Copy)
69 }
70
71 pub const fn is_eq(&'static self) -> bool {
73 self.is(Characteristic::Eq)
74 }
75
76 pub const fn is_clone(&'static self) -> bool {
78 self.is(Characteristic::Clone)
79 }
80
81 pub const fn is_debug(&'static self) -> bool {
83 self.is(Characteristic::Debug)
84 }
85
86 pub const fn is_partial_eq(&'static self) -> bool {
88 self.is(Characteristic::PartialEq)
89 }
90
91 pub const fn is_partial_ord(&'static self) -> bool {
93 self.is(Characteristic::PartialOrd)
94 }
95
96 pub const fn is_ord(&'static self) -> bool {
98 self.is(Characteristic::Ord)
99 }
100
101 pub const fn is_hash(&'static self) -> bool {
103 self.is(Characteristic::Hash)
104 }
105
106 pub const fn is_default(&'static self) -> bool {
108 self.is(Characteristic::Default)
109 }
110
111 pub fn write_type_name(&self, f: &mut fmt::Formatter<'_>, opts: TypeNameOpts) -> fmt::Result {
113 (self.vtable.type_name)(f, opts)
114 }
115
116 pub const fn builder() -> ShapeBuilder {
118 ShapeBuilder::new()
119 }
120}
121
122pub struct ShapeBuilder {
124 layout: Option<Layout>,
125 vtable: Option<&'static ValueVTable>,
126 def: Option<Def>,
127}
128
129impl ShapeBuilder {
130 #[allow(clippy::new_without_default)]
132 pub const fn new() -> Self {
133 Self {
134 layout: None,
135 vtable: None,
136 def: None,
137 }
138 }
139
140 #[inline]
142 pub const fn layout(mut self, layout: Layout) -> Self {
143 self.layout = Some(layout);
144 self
145 }
146
147 #[inline]
149 pub const fn vtable(mut self, vtable: &'static ValueVTable) -> Self {
150 self.vtable = Some(vtable);
151 self
152 }
153
154 #[inline]
156 pub const fn def(mut self, def: Def) -> Self {
157 self.def = Some(def);
158 self
159 }
160
161 #[inline]
167 pub const fn build(self) -> Shape {
168 Shape {
169 layout: self.layout.unwrap(),
170 vtable: self.vtable.unwrap(),
171 def: self.def.unwrap(),
172 }
173 }
174}
175
176impl PartialEq for Shape {
177 fn eq(&self, other: &Self) -> bool {
178 self.def == other.def && self.layout == other.layout
179 }
180}
181
182impl Eq for Shape {}
183
184impl core::hash::Hash for Shape {
185 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
186 self.def.hash(state);
187 self.layout.hash(state);
188 }
189}
190
191impl Shape {
192 pub fn is_shape(&'static self, other: &'static Shape) -> bool {
194 self == other
195 }
196
197 pub fn assert_shape(&'static self, other: &'static Shape) {
199 assert!(
200 self.is_shape(other),
201 "Shape mismatch: expected {other}, found {self}",
202 );
203 }
204}
205
206impl core::fmt::Display for Shape {
208 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
209 (self.vtable.type_name)(f, TypeNameOpts::default())
210 }
211}
212
213impl Shape {
214 #[cfg(feature = "std")]
216 #[inline]
217 pub fn allocate(&self) -> crate::opaque::OpaqueUninit<'static> {
218 crate::opaque::OpaqueUninit::new(unsafe { std::alloc::alloc(self.layout) })
219 }
220}
221
222#[derive(Debug, Copy, Clone, PartialEq, Eq)]
224#[non_exhaustive]
225pub enum FieldError {
226 NoStaticFields,
230
231 NoSuchStaticField,
234
235 IndexOutOfBounds,
238
239 NotAStruct,
241}
242
243impl core::error::Error for FieldError {}
244
245impl core::fmt::Display for FieldError {
246 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
247 match self {
248 FieldError::NoStaticFields => write!(f, "No static fields available"),
249 FieldError::NoSuchStaticField => write!(f, "No such static field"),
250 FieldError::IndexOutOfBounds => write!(f, "Index out of bounds"),
251 FieldError::NotAStruct => write!(f, "Not a struct"),
252 }
253 }
254}
255
256#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
258#[non_exhaustive]
259pub struct StructDef {
260 pub kind: StructKind,
262
263 pub fields: &'static [Field],
265}
266
267impl StructDef {
268 pub const fn builder() -> StructDefBuilder {
270 StructDefBuilder::new()
271 }
272}
273
274pub struct StructDefBuilder {
276 kind: Option<StructKind>,
277 fields: Option<&'static [Field]>,
278}
279
280impl StructDefBuilder {
281 #[allow(clippy::new_without_default)]
283 pub const fn new() -> Self {
284 Self {
285 kind: None,
286 fields: None,
287 }
288 }
289
290 pub const fn kind(mut self, kind: StructKind) -> Self {
292 self.kind = Some(kind);
293 self
294 }
295
296 pub const fn fields(mut self, fields: &'static [Field]) -> Self {
298 self.fields = Some(fields);
299 self
300 }
301
302 pub const fn build(self) -> StructDef {
304 StructDef {
305 kind: self.kind.unwrap(),
306 fields: self.fields.unwrap(),
307 }
308 }
309}
310
311#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
313#[non_exhaustive]
314pub enum StructKind {
315 Struct,
317
318 TupleStruct,
320
321 Tuple,
323}
324
325#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
327#[non_exhaustive]
328pub struct Field {
329 pub name: &'static str,
331
332 pub shape: &'static Shape,
334
335 pub offset: usize,
337
338 pub flags: FieldFlags,
340
341 pub attributes: &'static [FieldAttribute],
343}
344
345impl Field {
346 pub const fn builder() -> FieldBuilder {
348 FieldBuilder::new()
349 }
350}
351
352pub struct FieldBuilder {
354 name: Option<&'static str>,
355 shape: Option<&'static Shape>,
356 offset: Option<usize>,
357 flags: Option<FieldFlags>,
358 attributes: &'static [FieldAttribute],
359}
360
361#[non_exhaustive]
363#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
364pub enum FieldAttribute {
365 Sensitive,
367 Arbitrary(&'static str),
369}
370
371impl FieldBuilder {
372 #[allow(clippy::new_without_default)]
374 pub const fn new() -> Self {
375 Self {
376 name: None,
377 shape: None,
378 offset: None,
379 flags: None,
380 attributes: &[],
381 }
382 }
383
384 pub const fn name(mut self, name: &'static str) -> Self {
386 self.name = Some(name);
387 self
388 }
389
390 pub const fn shape(mut self, shape: &'static Shape) -> Self {
392 self.shape = Some(shape);
393 self
394 }
395
396 pub const fn offset(mut self, offset: usize) -> Self {
398 self.offset = Some(offset);
399 self
400 }
401
402 pub const fn flags(mut self, flags: FieldFlags) -> Self {
404 self.flags = Some(flags);
405 self
406 }
407
408 pub const fn attributes(mut self, attributes: &'static [FieldAttribute]) -> Self {
410 self.attributes = attributes;
411 self
412 }
413
414 pub const fn build(self) -> Field {
416 Field {
417 name: self.name.unwrap(),
418 shape: self.shape.unwrap(),
419 offset: self.offset.unwrap(),
420 flags: match self.flags {
421 Some(flags) => flags,
422 None => FieldFlags::EMPTY,
423 },
424 attributes: self.attributes,
425 }
426 }
427}
428
429bitflags::bitflags! {
430 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
432 pub struct FieldFlags: u64 {
433 const EMPTY = 0;
435
436 const SENSITIVE = 1 << 0;
438 }
439}
440
441impl Default for FieldFlags {
442 #[inline(always)]
443 fn default() -> Self {
444 Self::EMPTY
445 }
446}
447
448impl core::fmt::Display for FieldFlags {
449 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
450 if self.is_empty() {
451 return write!(f, "none");
452 }
453
454 let flags = [
456 (FieldFlags::SENSITIVE, "sensitive"),
457 ];
461
462 let mut is_first = true;
464 for (flag, name) in flags {
465 if self.contains(flag) {
466 if !is_first {
467 write!(f, ", ")?;
468 }
469 is_first = false;
470 write!(f, "{}", name)?;
471 }
472 }
473
474 Ok(())
475 }
476}
477
478#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
480#[non_exhaustive]
481pub struct MapDef {
482 pub vtable: &'static MapVTable,
484 pub k: &'static Shape,
486 pub v: &'static Shape,
488}
489
490impl MapDef {
491 pub const fn builder() -> MapDefBuilder {
493 MapDefBuilder::new()
494 }
495}
496
497pub struct MapDefBuilder {
499 vtable: Option<&'static MapVTable>,
500 k: Option<&'static Shape>,
501 v: Option<&'static Shape>,
502}
503
504impl MapDefBuilder {
505 #[allow(clippy::new_without_default)]
507 pub const fn new() -> Self {
508 Self {
509 vtable: None,
510 k: None,
511 v: None,
512 }
513 }
514
515 pub const fn vtable(mut self, vtable: &'static MapVTable) -> Self {
517 self.vtable = Some(vtable);
518 self
519 }
520
521 pub const fn k(mut self, k: &'static Shape) -> Self {
523 self.k = Some(k);
524 self
525 }
526
527 pub const fn v(mut self, v: &'static Shape) -> Self {
529 self.v = Some(v);
530 self
531 }
532
533 pub const fn build(self) -> MapDef {
535 MapDef {
536 vtable: self.vtable.unwrap(),
537 k: self.k.unwrap(),
538 v: self.v.unwrap(),
539 }
540 }
541}
542
543#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
545#[non_exhaustive]
546pub struct ListDef {
547 pub vtable: &'static ListVTable,
549 pub t: &'static Shape,
551}
552
553impl ListDef {
554 pub const fn builder() -> ListDefBuilder {
556 ListDefBuilder::new()
557 }
558}
559
560pub struct ListDefBuilder {
562 vtable: Option<&'static ListVTable>,
563 t: Option<&'static Shape>,
564}
565
566impl ListDefBuilder {
567 #[allow(clippy::new_without_default)]
569 pub const fn new() -> Self {
570 Self {
571 vtable: None,
572 t: None,
573 }
574 }
575
576 pub const fn vtable(mut self, vtable: &'static ListVTable) -> Self {
578 self.vtable = Some(vtable);
579 self
580 }
581
582 pub const fn t(mut self, t: &'static Shape) -> Self {
584 self.t = Some(t);
585 self
586 }
587
588 pub const fn build(self) -> ListDef {
590 ListDef {
591 vtable: self.vtable.unwrap(),
592 t: self.t.unwrap(),
593 }
594 }
595}
596
597#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
599#[non_exhaustive]
600pub struct EnumDef {
601 pub repr: EnumRepr,
603 pub variants: &'static [Variant],
605}
606
607impl EnumDef {
608 pub const fn builder() -> EnumDefBuilder {
610 EnumDefBuilder::new()
611 }
612}
613
614pub struct EnumDefBuilder {
616 repr: Option<EnumRepr>,
617 variants: Option<&'static [Variant]>,
618}
619
620impl EnumDefBuilder {
621 #[allow(clippy::new_without_default)]
623 pub const fn new() -> Self {
624 Self {
625 repr: None,
626 variants: None,
627 }
628 }
629
630 pub const fn repr(mut self, repr: EnumRepr) -> Self {
632 self.repr = Some(repr);
633 self
634 }
635
636 pub const fn variants(mut self, variants: &'static [Variant]) -> Self {
638 self.variants = Some(variants);
639 self
640 }
641
642 pub const fn build(self) -> EnumDef {
644 EnumDef {
645 repr: self.repr.unwrap(),
646 variants: self.variants.unwrap(),
647 }
648 }
649}
650
651#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
653#[non_exhaustive]
654pub struct Variant {
655 pub name: &'static str,
657
658 pub discriminant: Option<i64>,
660
661 pub kind: VariantKind,
663}
664
665impl Variant {
666 pub const fn builder() -> VariantBuilder {
668 VariantBuilder::new()
669 }
670}
671
672pub struct VariantBuilder {
674 name: Option<&'static str>,
675 discriminant: Option<Option<i64>>,
676 kind: Option<VariantKind>,
677}
678
679impl VariantBuilder {
680 #[allow(clippy::new_without_default)]
682 pub const fn new() -> Self {
683 Self {
684 name: None,
685 discriminant: None,
686 kind: None,
687 }
688 }
689
690 pub const fn name(mut self, name: &'static str) -> Self {
692 self.name = Some(name);
693 self
694 }
695
696 pub const fn discriminant(mut self, discriminant: Option<i64>) -> Self {
698 self.discriminant = Some(discriminant);
699 self
700 }
701
702 pub const fn kind(mut self, kind: VariantKind) -> Self {
704 self.kind = Some(kind);
705 self
706 }
707
708 pub const fn build(self) -> Variant {
710 Variant {
711 name: self.name.unwrap(),
712 discriminant: self.discriminant.unwrap(),
713 kind: self.kind.unwrap(),
714 }
715 }
716}
717
718#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
720#[non_exhaustive]
721pub enum VariantKind {
722 Unit,
724
725 Tuple {
727 fields: &'static [Field],
729 },
730
731 Struct {
733 fields: &'static [Field],
735 },
736}
737
738#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
740#[non_exhaustive]
741pub enum EnumRepr {
742 Default,
744 U8,
746 U16,
748 U32,
750 U64,
752 USize,
754 I8,
756 I16,
758 I32,
760 I64,
762 ISize,
764}
765
766impl Default for EnumRepr {
767 fn default() -> Self {
768 Self::Default
769 }
770}
771
772#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
774pub struct ScalarId(u64);
775
776unsafe impl Facet for ScalarId {
777 const SHAPE: &'static Shape = &Shape::builder()
778 .layout(Layout::new::<Self>())
779 .vtable(crate::value_vtable!(String, |f, _opts| write!(
780 f,
781 "ScalarId"
782 )))
783 .def(Def::Scalar(
784 ScalarDef::builder()
785 .fully_qualified_type_name("facet_core::ScalarId")
786 .build(),
787 ))
788 .build();
789}
790
791impl ScalarId {
792 const fn from_fully_qualified_type_name(name: &'static str) -> Self {
793 let mut hash = 0u64;
795 let bytes = name.as_bytes();
796 let mut i = 0;
797 while i < bytes.len() {
798 hash = hash.wrapping_mul(31).wrapping_add(bytes[i] as u64);
799 i += 1;
800 }
801 Self(hash)
802 }
803}
804
805use crate::{shape_of, value_vtable};
806
807#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
809#[non_exhaustive]
810pub struct ScalarDef {
811 pub scalar_id: ScalarId,
813}
814
815unsafe impl Facet for ScalarDef {
816 const SHAPE: &'static Shape = &const {
817 static FIELDS: &[Field] = &[Field::builder()
818 .name("scalar_id")
819 .shape(shape_of(&|s: ScalarDef| s.scalar_id))
820 .offset(core::mem::offset_of!(ScalarDef, scalar_id))
821 .flags(FieldFlags::EMPTY)
822 .attributes(&[])
823 .build()];
824
825 Shape::builder()
826 .layout(core::alloc::Layout::new::<Self>())
827 .vtable(value_vtable!(ScalarDef, |f, _opts| f.write_str("ScalarDef")))
828 .def(Def::Struct(
829 StructDef::builder()
830 .kind(StructKind::Struct)
831 .fields(FIELDS)
832 .build(),
833 ))
834 .build()
835 };
836}
837
838impl ScalarDef {
839 pub const fn builder() -> ScalarDefBuilder {
841 ScalarDefBuilder::new()
842 }
843}
844
845#[derive(Default)]
847pub struct ScalarDefBuilder {
848 type_name: Option<&'static str>,
849}
850
851impl ScalarDefBuilder {
852 #[allow(clippy::new_without_default)]
854 pub const fn new() -> Self {
855 Self { type_name: None }
856 }
857
858 pub const fn fully_qualified_type_name(mut self, type_name: &'static str) -> Self {
860 self.type_name = Some(type_name);
861 self
862 }
863
864 pub const fn build(self) -> ScalarDef {
866 ScalarDef {
867 scalar_id: ScalarId::from_fully_qualified_type_name(self.type_name.unwrap()),
868 }
869 }
870}
871
872#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
874#[non_exhaustive]
875pub enum Def {
876 Scalar(ScalarDef),
881
882 Struct(StructDef),
886
887 Map(MapDef),
891
892 List(ListDef),
896
897 Enum(EnumDef),
901}
902
903#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
905#[non_exhaustive]
906pub enum Characteristic {
907 Send,
910
911 Sync,
913
914 Copy,
916
917 Eq,
919
920 Clone,
923
924 Debug,
926
927 PartialEq,
929
930 PartialOrd,
932
933 Ord,
935
936 Hash,
938
939 Default,
941}
942
943impl Characteristic {
944 pub const fn all(self, shapes: &'static [&'static Shape]) -> bool {
946 let mut i = 0;
947 while i < shapes.len() {
948 if !shapes[i].is(self) {
949 return false;
950 }
951 i += 1;
952 }
953 true
954 }
955
956 pub const fn any(self, shapes: &'static [&'static Shape]) -> bool {
958 let mut i = 0;
959 while i < shapes.len() {
960 if shapes[i].is(self) {
961 return true;
962 }
963 i += 1;
964 }
965 false
966 }
967
968 pub const fn none(self, shapes: &'static [&'static Shape]) -> bool {
970 let mut i = 0;
971 while i < shapes.len() {
972 if shapes[i].is(self) {
973 return false;
974 }
975 i += 1;
976 }
977 true
978 }
979}