1use crate::{
2 TypedPtrUninit,
3 ptr::{PtrConst, PtrMut, PtrUninit},
4};
5use bitflags::bitflags;
6use core::{cmp::Ordering, marker::PhantomData, mem};
7
8use crate::Shape;
9
10use super::UnsizedError;
11
12pub type TypeNameFn = fn(f: &mut core::fmt::Formatter, opts: TypeNameOpts) -> core::fmt::Result;
18
19#[non_exhaustive]
21#[derive(Clone, Copy)]
22pub struct TypeNameOpts {
23 pub recurse_ttl: isize,
27}
28
29impl Default for TypeNameOpts {
30 fn default() -> Self {
31 Self { recurse_ttl: -1 }
32 }
33}
34
35impl TypeNameOpts {
36 pub fn none() -> Self {
38 Self { recurse_ttl: 0 }
39 }
40
41 pub fn one() -> Self {
43 Self { recurse_ttl: 1 }
44 }
45
46 pub fn infinite() -> Self {
48 Self { recurse_ttl: -1 }
49 }
50
51 pub fn for_children(&self) -> Option<Self> {
59 match self.recurse_ttl.cmp(&0) {
60 Ordering::Greater => Some(Self {
61 recurse_ttl: self.recurse_ttl - 1,
62 }),
63 Ordering::Less => Some(Self {
64 recurse_ttl: self.recurse_ttl,
65 }),
66 Ordering::Equal => None,
67 }
68 }
69}
70
71pub type InvariantsFn = for<'mem> unsafe fn(value: PtrConst<'mem>) -> bool;
79pub type InvariantsFnTyped<T> = fn(value: &T) -> bool;
81
82pub type DropInPlaceFn = for<'mem> unsafe fn(value: PtrMut<'mem>) -> PtrUninit<'mem>;
92
93pub type CloneIntoFn =
101 for<'src, 'dst> unsafe fn(source: PtrConst<'src>, target: PtrUninit<'dst>) -> PtrMut<'dst>;
102pub type CloneIntoFnTyped<T> =
104 for<'src, 'dst> fn(source: &'src T, target: TypedPtrUninit<'dst, T>) -> &'dst mut T;
105
106pub type DefaultInPlaceFn = for<'mem> unsafe fn(target: PtrUninit<'mem>) -> PtrMut<'mem>;
113pub type DefaultInPlaceFnTyped<T> = for<'mem> fn(target: TypedPtrUninit<'mem, T>) -> &'mem mut T;
115
116pub type ParseFn =
128 for<'mem> unsafe fn(s: &str, target: PtrUninit<'mem>) -> Result<PtrMut<'mem>, ParseError>;
129pub type ParseFnTyped<T> =
133 for<'mem> fn(s: &str, target: TypedPtrUninit<'mem, T>) -> Result<&'mem mut T, ParseError>;
134
135#[non_exhaustive]
137#[derive(Debug)]
138pub enum ParseError {
139 Generic(&'static str),
141}
142
143impl core::fmt::Display for ParseError {
144 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
145 match self {
146 ParseError::Generic(msg) => write!(f, "Parse failed: {}", msg),
147 }
148 }
149}
150
151impl core::error::Error for ParseError {}
152
153pub type TryFromFn = for<'src, 'mem> unsafe fn(
161 source: PtrConst<'src>,
162 source_shape: &'static Shape,
163 target: PtrUninit<'mem>,
164) -> Result<PtrMut<'mem>, TryFromError>;
165pub type TryFromFnTyped<T> = for<'src, 'mem> fn(
167 source: &'src T,
168 source_shape: &'static Shape,
169 target: TypedPtrUninit<'mem, T>,
170) -> Result<&'mem mut T, TryFromError>;
171
172#[non_exhaustive]
174#[derive(Debug, PartialEq, Clone)]
175pub enum TryFromError {
176 Generic(&'static str),
178 Unimplemented,
180 UnsupportedSourceShape {
182 src_shape: &'static Shape,
184
185 expected: &'static [&'static Shape],
187 },
188 Unsized,
190}
191
192impl core::fmt::Display for TryFromError {
193 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
194 match self {
195 TryFromError::Generic(msg) => write!(f, "{}", msg),
196 TryFromError::Unimplemented => write!(
197 f,
198 "Shape doesn't implement any conversions (no try_from function)",
199 ),
200 TryFromError::UnsupportedSourceShape {
201 src_shape: source_shape,
202 expected,
203 } => {
204 write!(f, "Incompatible types: {} (expected one of ", source_shape)?;
205 for (index, sh) in expected.iter().enumerate() {
206 if index > 0 {
207 write!(f, ", ")?;
208 }
209 write!(f, "{}", sh)?;
210 }
211 write!(f, ")")?;
212 Ok(())
213 }
214 TryFromError::Unsized => write!(f, "Unsized type"),
215 }
216 }
217}
218
219impl core::error::Error for TryFromError {}
220
221impl From<UnsizedError> for TryFromError {
222 fn from(_value: UnsizedError) -> Self {
223 Self::Unsized
224 }
225}
226
227pub type TryIntoInnerFn = for<'src, 'dst> unsafe fn(
242 src_ptr: PtrConst<'src>,
243 dst: PtrUninit<'dst>,
244) -> Result<PtrMut<'dst>, TryIntoInnerError>;
245pub type TryIntoInnerFnTyped<T> = for<'src, 'dst> fn(
250 src_ptr: &'src T,
251 dst: TypedPtrUninit<'dst, T>,
252) -> Result<&'dst mut T, TryIntoInnerError>;
253
254#[non_exhaustive]
257#[derive(Debug, Clone, PartialEq, Eq)]
258pub enum TryIntoInnerError {
259 Unavailable,
262 Other(&'static str),
264}
265
266impl core::fmt::Display for TryIntoInnerError {
267 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
268 match self {
269 TryIntoInnerError::Unavailable => {
270 write!(f, "inner value is unavailable for extraction")
271 }
272 TryIntoInnerError::Other(msg) => write!(f, "{}", msg),
273 }
274 }
275}
276
277impl core::error::Error for TryIntoInnerError {}
278
279pub type TryBorrowInnerFn =
292 for<'src> unsafe fn(src_ptr: PtrConst<'src>) -> Result<PtrConst<'src>, TryBorrowInnerError>;
293pub type TryBorrowInnerFnTyped<T> =
298 for<'src> fn(src_ptr: &'src T) -> Result<&'src T, TryBorrowInnerError>;
299
300#[non_exhaustive]
303#[derive(Debug, Clone, PartialEq, Eq)]
304pub enum TryBorrowInnerError {
305 Unavailable,
308 Other(&'static str),
311}
312
313impl core::fmt::Display for TryBorrowInnerError {
314 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
315 match self {
316 TryBorrowInnerError::Unavailable => {
317 write!(f, "inner value is unavailable for borrowing")
318 }
319 TryBorrowInnerError::Other(msg) => {
320 write!(f, "{}", msg)
321 }
322 }
323 }
324}
325
326impl core::error::Error for TryBorrowInnerError {}
327
328pub type PartialEqFn = for<'l, 'r> unsafe fn(left: PtrConst<'l>, right: PtrConst<'r>) -> bool;
336pub type PartialEqFnTyped<T> = fn(left: &T, right: &T) -> bool;
338
339pub type PartialOrdFn =
345 for<'l, 'r> unsafe fn(left: PtrConst<'l>, right: PtrConst<'r>) -> Option<Ordering>;
346pub type PartialOrdFnTyped<T> = fn(left: &T, right: &T) -> Option<Ordering>;
348
349pub type CmpFn = for<'l, 'r> unsafe fn(left: PtrConst<'l>, right: PtrConst<'r>) -> Ordering;
355pub type CmpFnTyped<T> = fn(left: &T, right: &T) -> Ordering;
357
358pub type HashFn = for<'mem> unsafe fn(
367 value: PtrConst<'mem>,
368 hasher_this: PtrMut<'mem>,
369 hasher_write_fn: HasherWriteFn,
370);
371pub type HashFnTyped<T> =
373 for<'mem> fn(value: &'mem T, hasher_this: PtrMut<'mem>, hasher_write_fn: HasherWriteFn);
374
375pub type HasherWriteFn = for<'mem> unsafe fn(hasher_self: PtrMut<'mem>, bytes: &[u8]);
381pub type HasherWriteFnTyped<T> = for<'mem> fn(hasher_self: &'mem mut T, bytes: &[u8]);
383
384pub struct HasherProxy<'a> {
388 hasher_this: PtrMut<'a>,
389 hasher_write_fn: HasherWriteFn,
390}
391
392impl<'a> HasherProxy<'a> {
393 pub unsafe fn new(hasher_this: PtrMut<'a>, hasher_write_fn: HasherWriteFn) -> Self {
400 Self {
401 hasher_this,
402 hasher_write_fn,
403 }
404 }
405}
406
407impl core::hash::Hasher for HasherProxy<'_> {
408 fn finish(&self) -> u64 {
409 unimplemented!("finish is not needed for this implementation")
410 }
411 fn write(&mut self, bytes: &[u8]) {
412 unsafe { (self.hasher_write_fn)(self.hasher_this, bytes) }
413 }
414}
415
416bitflags! {
419 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
421 pub struct MarkerTraits: u8 {
422 const EQ = 1 << 0;
424 const SEND = 1 << 1;
426 const SYNC = 1 << 2;
428 const COPY = 1 << 3;
430 const UNPIN = 1 << 4;
432 }
433}
434
435pub type DisplayFn =
445 for<'mem> unsafe fn(value: PtrConst<'mem>, f: &mut core::fmt::Formatter) -> core::fmt::Result;
446pub type DisplayFnTyped<T> = fn(value: &T, f: &mut core::fmt::Formatter) -> core::fmt::Result;
450
451pub type DebugFn =
454 for<'mem> unsafe fn(value: PtrConst<'mem>, f: &mut core::fmt::Formatter) -> core::fmt::Result;
455pub type DebugFnTyped<T> = fn(value: &T, f: &mut core::fmt::Formatter) -> core::fmt::Result;
458
459#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
461#[repr(C)]
462#[non_exhaustive]
463pub struct ValueVTable {
464 pub type_name: TypeNameFn,
466 pub marker_traits: MarkerTraits,
470
471 pub drop_in_place: Option<DropInPlaceFn>,
473
474 pub invariants: Option<InvariantsFn>,
476
477 pub display: Option<DisplayFn>,
479
480 pub debug: Option<DebugFn>,
482
483 pub default_in_place: Option<DefaultInPlaceFn>,
485
486 pub clone_into: Option<CloneIntoFn>,
488
489 pub eq: Option<PartialEqFn>,
491
492 pub partial_ord: Option<PartialOrdFn>,
494
495 pub ord: Option<CmpFn>,
497
498 pub hash: Option<HashFn>,
500
501 pub parse: Option<ParseFn>,
503
504 pub try_from: Option<TryFromFn>,
516
517 pub try_into_inner: Option<TryIntoInnerFn>,
522
523 pub try_borrow_inner: Option<TryBorrowInnerFn>,
527}
528
529impl ValueVTable {
530 pub fn is_eq(&self) -> bool {
532 self.marker_traits.contains(MarkerTraits::EQ)
533 }
534
535 pub fn is_send(&self) -> bool {
537 self.marker_traits.contains(MarkerTraits::SEND)
538 }
539
540 pub fn is_sync(&self) -> bool {
542 self.marker_traits.contains(MarkerTraits::SYNC)
543 }
544
545 pub fn is_copy(&self) -> bool {
547 self.marker_traits.contains(MarkerTraits::COPY)
548 }
549
550 pub fn is_unpin(&self) -> bool {
552 self.marker_traits.contains(MarkerTraits::UNPIN)
553 }
554
555 pub const fn builder<T>() -> ValueVTableBuilder<T> {
557 ValueVTableBuilder::new()
558 }
559}
560
561#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
563pub struct VTableView<T>(&'static ValueVTable, PhantomData<T>);
564
565impl<'a, T: crate::Facet<'a>> VTableView<T> {
566 pub fn of() -> Self {
568 Self(T::SHAPE.vtable, PhantomData)
569 }
570
571 #[inline(always)]
573 pub fn type_name(self) -> TypeNameFn {
574 self.0.type_name
575 }
576
577 #[inline(always)]
579 pub fn invariants(self) -> Option<InvariantsFnTyped<T>> {
580 self.0.invariants.map(|invariants| unsafe {
581 mem::transmute::<InvariantsFn, InvariantsFnTyped<T>>(invariants)
582 })
583 }
584
585 #[inline(always)]
587 pub fn display(self) -> Option<DisplayFnTyped<T>> {
588 self.0
589 .display
590 .map(|display| unsafe { mem::transmute::<DisplayFn, DisplayFnTyped<T>>(display) })
591 }
592
593 #[inline(always)]
595 pub fn debug(self) -> Option<DebugFnTyped<T>> {
596 self.0
597 .debug
598 .map(|debug| unsafe { mem::transmute::<DebugFn, DebugFnTyped<T>>(debug) })
599 }
600
601 #[inline(always)]
603 pub fn default_in_place(self) -> Option<DefaultInPlaceFnTyped<T>> {
604 self.0.default_in_place.map(|default_in_place| unsafe {
605 mem::transmute::<DefaultInPlaceFn, DefaultInPlaceFnTyped<T>>(default_in_place)
606 })
607 }
608
609 #[inline(always)]
611 pub fn clone_into(self) -> Option<CloneIntoFnTyped<T>> {
612 self.0.clone_into.map(|clone_into| unsafe {
613 mem::transmute::<CloneIntoFn, CloneIntoFnTyped<T>>(clone_into)
614 })
615 }
616
617 #[inline(always)]
619 pub fn eq(self) -> Option<PartialEqFnTyped<T>> {
620 self.0
621 .eq
622 .map(|eq| unsafe { mem::transmute::<PartialEqFn, PartialEqFnTyped<T>>(eq) })
623 }
624
625 #[inline(always)]
627 pub fn partial_ord(self) -> Option<PartialOrdFnTyped<T>> {
628 self.0.partial_ord.map(|partial_ord| unsafe {
629 mem::transmute::<PartialOrdFn, PartialOrdFnTyped<T>>(partial_ord)
630 })
631 }
632
633 #[inline(always)]
635 pub fn ord(self) -> Option<CmpFnTyped<T>> {
636 self.0
637 .ord
638 .map(|ord| unsafe { mem::transmute::<CmpFn, CmpFnTyped<T>>(ord) })
639 }
640
641 #[inline(always)]
643 pub fn hash(self) -> Option<HashFnTyped<T>> {
644 self.0
645 .hash
646 .map(|hash| unsafe { mem::transmute::<HashFn, HashFnTyped<T>>(hash) })
647 }
648
649 #[inline(always)]
651 pub fn parse(self) -> Option<ParseFnTyped<T>> {
652 self.0
653 .parse
654 .map(|parse| unsafe { mem::transmute::<ParseFn, ParseFnTyped<T>>(parse) })
655 }
656
657 #[inline(always)]
669 pub fn try_from(self) -> Option<TryFromFnTyped<T>> {
670 self.0
671 .try_from
672 .map(|try_from| unsafe { mem::transmute::<TryFromFn, TryFromFnTyped<T>>(try_from) })
673 }
674
675 #[inline(always)]
680 pub fn try_into_inner(self) -> Option<TryIntoInnerFnTyped<T>> {
681 self.0.try_into_inner.map(|try_into_inner| unsafe {
682 mem::transmute::<TryIntoInnerFn, TryIntoInnerFnTyped<T>>(try_into_inner)
683 })
684 }
685
686 #[inline(always)]
690 pub fn try_borrow_inner(self) -> Option<TryBorrowInnerFnTyped<T>> {
691 self.0.try_borrow_inner.map(|try_borrow_inner| unsafe {
692 mem::transmute::<TryBorrowInnerFn, TryBorrowInnerFnTyped<T>>(try_borrow_inner)
693 })
694 }
695}
696
697pub struct ValueVTableBuilder<T> {
699 type_name: Option<TypeNameFn>,
700 display: Option<DisplayFnTyped<T>>,
701 debug: Option<DebugFnTyped<T>>,
702 default_in_place: Option<DefaultInPlaceFnTyped<T>>,
703 clone_into: Option<CloneIntoFnTyped<T>>,
704 marker_traits: MarkerTraits,
705 eq: Option<PartialEqFnTyped<T>>,
706 partial_ord: Option<PartialOrdFnTyped<T>>,
707 ord: Option<CmpFnTyped<T>>,
708 hash: Option<HashFnTyped<T>>,
709 drop_in_place: Option<DropInPlaceFn>,
710 invariants: Option<InvariantsFnTyped<T>>,
711 parse: Option<ParseFnTyped<T>>,
712 try_from: Option<TryFromFnTyped<T>>,
713 try_into_inner: Option<TryIntoInnerFnTyped<T>>,
714 try_borrow_inner: Option<TryBorrowInnerFnTyped<T>>,
715 _pd: PhantomData<T>,
716}
717
718impl<T> ValueVTableBuilder<T> {
719 #[allow(clippy::new_without_default)]
721 pub const fn new() -> Self {
722 Self {
723 type_name: None,
724 display: None,
725 debug: None,
726 default_in_place: None,
727 clone_into: None,
728 marker_traits: MarkerTraits::empty(),
729 eq: None,
730 partial_ord: None,
731 ord: None,
732 hash: None,
733 drop_in_place: None,
734 invariants: None,
735 parse: None,
736 try_from: None,
737 try_into_inner: None,
738 try_borrow_inner: None,
739 _pd: PhantomData,
740 }
741 }
742
743 pub const fn type_name(mut self, type_name: TypeNameFn) -> Self {
745 self.type_name = Some(type_name);
746 self
747 }
748
749 pub const fn display(mut self, display: DisplayFnTyped<T>) -> Self {
751 self.display = Some(display);
752 self
753 }
754
755 pub const fn display_maybe(mut self, display: Option<DisplayFnTyped<T>>) -> Self {
757 self.display = display;
758 self
759 }
760
761 pub const fn debug(mut self, debug: DebugFnTyped<T>) -> Self {
763 self.debug = Some(debug);
764 self
765 }
766
767 pub const fn debug_maybe(mut self, debug: Option<DebugFnTyped<T>>) -> Self {
769 self.debug = debug;
770 self
771 }
772
773 pub const fn default_in_place(mut self, default_in_place: DefaultInPlaceFnTyped<T>) -> Self {
775 self.default_in_place = Some(default_in_place);
776 self
777 }
778
779 pub const fn default_in_place_maybe(
781 mut self,
782 default_in_place: Option<DefaultInPlaceFnTyped<T>>,
783 ) -> Self {
784 self.default_in_place = default_in_place;
785 self
786 }
787
788 pub const fn clone_into(mut self, clone_into: CloneIntoFnTyped<T>) -> Self {
790 self.clone_into = Some(clone_into);
791 self
792 }
793
794 pub const fn clone_into_maybe(mut self, clone_into: Option<CloneIntoFnTyped<T>>) -> Self {
796 self.clone_into = clone_into;
797 self
798 }
799
800 pub const fn marker_traits(mut self, marker_traits: MarkerTraits) -> Self {
802 self.marker_traits = marker_traits;
803 self
804 }
805
806 pub const fn eq(mut self, eq: PartialEqFnTyped<T>) -> Self {
808 self.eq = Some(eq);
809 self
810 }
811
812 pub const fn eq_maybe(mut self, eq: Option<PartialEqFnTyped<T>>) -> Self {
814 self.eq = eq;
815 self
816 }
817
818 pub const fn partial_ord(mut self, partial_ord: PartialOrdFnTyped<T>) -> Self {
820 self.partial_ord = Some(partial_ord);
821 self
822 }
823
824 pub const fn partial_ord_maybe(mut self, partial_ord: Option<PartialOrdFnTyped<T>>) -> Self {
826 self.partial_ord = partial_ord;
827 self
828 }
829
830 pub const fn ord(mut self, ord: CmpFnTyped<T>) -> Self {
832 self.ord = Some(ord);
833 self
834 }
835
836 pub const fn ord_maybe(mut self, ord: Option<CmpFnTyped<T>>) -> Self {
838 self.ord = ord;
839 self
840 }
841
842 pub const fn hash(mut self, hash: HashFnTyped<T>) -> Self {
844 self.hash = Some(hash);
845 self
846 }
847
848 pub const fn hash_maybe(mut self, hash: Option<HashFnTyped<T>>) -> Self {
850 self.hash = hash;
851 self
852 }
853
854 pub const fn drop_in_place(mut self, drop_in_place: DropInPlaceFn) -> Self {
858 self.drop_in_place = Some(drop_in_place);
859 self
860 }
861
862 pub const fn invariants(mut self, invariants: InvariantsFnTyped<T>) -> Self {
864 self.invariants = Some(invariants);
865 self
866 }
867
868 pub const fn parse(mut self, parse: ParseFnTyped<T>) -> Self {
870 self.parse = Some(parse);
871 self
872 }
873
874 pub const fn parse_maybe(mut self, parse: Option<ParseFnTyped<T>>) -> Self {
876 self.parse = parse;
877 self
878 }
879
880 pub const fn try_from(mut self, try_from: TryFromFnTyped<T>) -> Self {
882 self.try_from = Some(try_from);
883 self
884 }
885
886 pub const fn try_into_inner(mut self, try_into_inner: TryIntoInnerFnTyped<T>) -> Self {
888 self.try_into_inner = Some(try_into_inner);
889 self
890 }
891
892 pub const fn try_borrow_inner(mut self, try_borrow_inner: TryBorrowInnerFnTyped<T>) -> Self {
894 self.try_borrow_inner = Some(try_borrow_inner);
895 self
896 }
897
898 pub const fn build(self) -> ValueVTable {
900 ValueVTable {
901 type_name: self.type_name.unwrap(),
902 marker_traits: self.marker_traits,
903 invariants: unsafe {
904 mem::transmute::<Option<InvariantsFnTyped<T>>, Option<InvariantsFn>>(
905 self.invariants,
906 )
907 },
908 display: unsafe {
909 mem::transmute::<Option<DisplayFnTyped<T>>, Option<DisplayFn>>(self.display)
910 },
911 debug: unsafe {
912 mem::transmute::<Option<DebugFnTyped<T>>, Option<DebugFn>>(self.debug)
913 },
914 default_in_place: unsafe {
915 mem::transmute::<Option<DefaultInPlaceFnTyped<T>>, Option<DefaultInPlaceFn>>(
916 self.default_in_place,
917 )
918 },
919 clone_into: unsafe {
920 mem::transmute::<Option<CloneIntoFnTyped<T>>, Option<CloneIntoFn>>(self.clone_into)
921 },
922 eq: unsafe {
923 mem::transmute::<Option<PartialEqFnTyped<T>>, Option<PartialEqFn>>(self.eq)
924 },
925 partial_ord: unsafe {
926 mem::transmute::<Option<PartialOrdFnTyped<T>>, Option<PartialOrdFn>>(
927 self.partial_ord,
928 )
929 },
930 ord: unsafe { mem::transmute::<Option<CmpFnTyped<T>>, Option<CmpFn>>(self.ord) },
931 hash: unsafe { mem::transmute::<Option<HashFnTyped<T>>, Option<HashFn>>(self.hash) },
932 parse: unsafe {
933 mem::transmute::<Option<ParseFnTyped<T>>, Option<ParseFn>>(self.parse)
934 },
935 try_from: unsafe {
936 mem::transmute::<Option<TryFromFnTyped<T>>, Option<TryFromFn>>(self.try_from)
937 },
938 try_into_inner: unsafe {
939 mem::transmute::<Option<TryIntoInnerFnTyped<T>>, Option<TryIntoInnerFn>>(
940 self.try_into_inner,
941 )
942 },
943 try_borrow_inner: unsafe {
944 mem::transmute::<Option<TryBorrowInnerFnTyped<T>>, Option<TryBorrowInnerFn>>(
945 self.try_borrow_inner,
946 )
947 },
948 drop_in_place: if let Some(drop_in_place) = self.drop_in_place {
949 Some(drop_in_place)
950 } else if mem::needs_drop::<T>() {
951 Some(|value| unsafe { value.drop_in_place::<T>() })
952 } else {
953 None
954 },
955 }
956 }
957}