1use bitflags::bitflags;
2use core::cmp::Ordering;
3use facet_opaque::{Opaque, OpaqueConst, OpaqueUninit};
4
5use crate::Shape;
6
7pub type TypeNameFn = fn(f: &mut core::fmt::Formatter, opts: TypeNameOpts) -> core::fmt::Result;
13
14#[non_exhaustive]
16#[derive(Clone, Copy)]
17pub struct TypeNameOpts {
18 pub recurse_ttl: isize,
22}
23
24impl Default for TypeNameOpts {
25 fn default() -> Self {
26 Self { recurse_ttl: -1 }
27 }
28}
29
30impl TypeNameOpts {
31 pub fn none() -> Self {
33 Self { recurse_ttl: 0 }
34 }
35
36 pub fn one() -> Self {
38 Self { recurse_ttl: 1 }
39 }
40
41 pub fn infinite() -> Self {
43 Self { recurse_ttl: -1 }
44 }
45
46 pub fn for_children(&self) -> Option<Self> {
54 match self.recurse_ttl.cmp(&0) {
55 Ordering::Greater => Some(Self {
56 recurse_ttl: self.recurse_ttl - 1,
57 }),
58 Ordering::Less => Some(Self {
59 recurse_ttl: self.recurse_ttl,
60 }),
61 Ordering::Equal => None,
62 }
63 }
64}
65
66pub type DropInPlaceFn = for<'mem> unsafe fn(value: Opaque<'mem>);
74
75pub const fn drop_in_place_fn_for<T>() -> Option<DropInPlaceFn> {
77 Some(|value: Opaque<'_>| unsafe {
78 value.drop_in_place::<T>();
79 })
80}
81
82pub type CloneIntoFn = for<'src, 'dst> unsafe fn(
90 source: OpaqueConst<'src>,
91 target: OpaqueUninit<'dst>,
92) -> Opaque<'dst>;
93
94pub const fn clone_into_fn_for<T: Clone>() -> Option<CloneIntoFn> {
96 Some(|source: OpaqueConst<'_>, target: OpaqueUninit<'_>| unsafe {
97 let source_val = source.as_ref::<T>();
98 target.write(source_val.clone())
99 })
100}
101
102pub type DefaultInPlaceFn = for<'mem> unsafe fn(target: OpaqueUninit<'mem>) -> Opaque<'mem>;
109
110pub const fn default_in_place_fn_for<T: Default>() -> Option<DefaultInPlaceFn> {
112 Some(|target: OpaqueUninit<'_>| unsafe { target.write(T::default()) })
113}
114
115pub type ParseFn =
127 for<'mem> unsafe fn(s: &str, target: OpaqueUninit<'mem>) -> Result<Opaque<'mem>, ParseError>;
128
129pub const fn parse_fn_for<T: core::str::FromStr>() -> Option<ParseFn> {
131 Some(|s: &str, target: OpaqueUninit<'_>| unsafe {
132 match s.parse::<T>() {
133 Ok(value) => Ok(target.write(value)),
134 Err(_) => Err(ParseError::Generic("failed to parse string")),
135 }
136 })
137}
138
139#[non_exhaustive]
141#[derive(Debug)]
142pub enum ParseError {
143 Generic(&'static str),
145}
146
147impl core::fmt::Display for ParseError {
148 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
149 match self {
150 ParseError::Generic(msg) => write!(f, "Parse failed: {}", msg),
151 }
152 }
153}
154
155impl core::error::Error for ParseError {}
156
157pub type TryFromFn = for<'src, 'mem> unsafe fn(
165 source: OpaqueConst<'src>,
166 target: OpaqueUninit<'mem>,
167) -> Result<Opaque<'mem>, TryFromError>;
168
169#[non_exhaustive]
171#[derive(Debug)]
172pub enum TryFromError {
173 Generic(&'static str),
175 Unimplemented(&'static Shape),
177 Incompatible {
179 source: &'static Shape,
181 target: &'static Shape,
183 },
184}
185
186impl core::fmt::Display for TryFromError {
187 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
188 match self {
189 TryFromError::Generic(msg) => write!(f, "Conversion failed: {}", msg),
190 TryFromError::Unimplemented(shape) => write!(
191 f,
192 "Conversion failed: Shape {} doesn't implement any conversions (no try_from function)",
193 shape
194 ),
195 TryFromError::Incompatible { source, target } => write!(
196 f,
197 "Conversion failed: Cannot convert from shape {} to shape {}",
198 source, target
199 ),
200 }
201 }
202}
203
204impl core::error::Error for TryFromError {}
205
206pub type PartialEqFn = for<'l, 'r> unsafe fn(left: OpaqueConst<'l>, right: OpaqueConst<'r>) -> bool;
214
215pub const fn partial_eq_fn_for<T: PartialEq>() -> Option<PartialEqFn> {
217 Some(|left: OpaqueConst<'_>, right: OpaqueConst<'_>| -> bool {
218 let left_val = unsafe { left.as_ref::<T>() };
219 let right_val = unsafe { right.as_ref::<T>() };
220 left_val == right_val
221 })
222}
223
224pub type PartialOrdFn =
230 for<'l, 'r> unsafe fn(left: OpaqueConst<'l>, right: OpaqueConst<'r>) -> Option<Ordering>;
231
232pub const fn partial_ord_fn_for<T: PartialOrd>() -> Option<PartialOrdFn> {
234 Some(
235 |left: OpaqueConst<'_>, right: OpaqueConst<'_>| -> Option<Ordering> {
236 let left_val = unsafe { left.as_ref::<T>() };
237 let right_val = unsafe { right.as_ref::<T>() };
238 left_val.partial_cmp(right_val)
239 },
240 )
241}
242
243pub type CmpFn = for<'l, 'r> unsafe fn(left: OpaqueConst<'l>, right: OpaqueConst<'r>) -> Ordering;
249
250pub const fn cmp_fn_for<T: Ord>() -> Option<CmpFn> {
252 Some(
253 |left: OpaqueConst<'_>, right: OpaqueConst<'_>| -> Ordering {
254 let left_val = unsafe { left.as_ref::<T>() };
255 let right_val = unsafe { right.as_ref::<T>() };
256 left_val.cmp(right_val)
257 },
258 )
259}
260
261pub type HashFn = for<'mem> unsafe fn(
270 value: OpaqueConst<'mem>,
271 hasher_this: Opaque<'mem>,
272 hasher_write_fn: HasherWriteFn,
273);
274
275pub const fn hash_fn_for<T: core::hash::Hash>() -> Option<HashFn> {
277 Some(
278 |value: OpaqueConst<'_>, hasher_this: Opaque<'_>, hasher_write_fn: HasherWriteFn| unsafe {
279 let val = value.as_ref::<T>();
280 val.hash(&mut HasherProxy::new(hasher_this, hasher_write_fn));
281 },
282 )
283}
284
285pub type HasherWriteFn = for<'mem> unsafe fn(hasher_self: Opaque<'mem>, bytes: &[u8]);
291
292pub struct HasherProxy<'a> {
306 hasher_this: Opaque<'a>,
307 hasher_write_fn: HasherWriteFn,
308}
309
310impl<'a> HasherProxy<'a> {
311 pub unsafe fn new(hasher_this: Opaque<'a>, hasher_write_fn: HasherWriteFn) -> Self {
318 Self {
319 hasher_this,
320 hasher_write_fn,
321 }
322 }
323}
324
325impl core::hash::Hasher for HasherProxy<'_> {
326 fn finish(&self) -> u64 {
327 unimplemented!("finish is not needed for this implementation")
328 }
329 fn write(&mut self, bytes: &[u8]) {
330 unsafe { (self.hasher_write_fn)(self.hasher_this, bytes) }
331 }
332}
333
334bitflags! {
337 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
339 pub struct MarkerTraits: u8 {
340 const EQ = 1 << 0;
342 const SEND = 1 << 1;
344 const SYNC = 1 << 2;
346 const COPY = 1 << 3;
348 }
349}
350
351pub type DisplayFn = for<'mem> unsafe fn(
361 value: OpaqueConst<'mem>,
362 f: &mut core::fmt::Formatter,
363) -> core::fmt::Result;
364
365pub const fn display_fn_for<T: core::fmt::Display>() -> Option<DisplayFn> {
367 Some(
368 |value: OpaqueConst<'_>, f: &mut core::fmt::Formatter| -> core::fmt::Result {
369 let val = unsafe { value.as_ref::<T>() };
370 write!(f, "{val}")
371 },
372 )
373}
374
375pub type DebugFn = for<'mem> unsafe fn(
382 value: OpaqueConst<'mem>,
383 f: &mut core::fmt::Formatter,
384) -> core::fmt::Result;
385
386pub const fn debug_fn_for<T: core::fmt::Debug>() -> Option<DebugFn> {
388 Some(
389 |value: OpaqueConst<'_>, f: &mut core::fmt::Formatter| -> core::fmt::Result {
390 let val = unsafe { value.as_ref::<T>() };
391 write!(f, "{val:?}")
392 },
393 )
394}
395
396#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
398#[non_exhaustive]
399pub struct ValueVTable {
400 pub type_name: TypeNameFn,
402
403 pub display: Option<DisplayFn>,
405
406 pub debug: Option<DebugFn>,
408
409 pub default_in_place: Option<DefaultInPlaceFn>,
411
412 pub clone_into: Option<CloneIntoFn>,
414
415 pub marker_traits: MarkerTraits,
419
420 pub eq: Option<PartialEqFn>,
422
423 pub partial_ord: Option<PartialOrdFn>,
425
426 pub ord: Option<CmpFn>,
428
429 pub hash: Option<HashFn>,
431
432 pub drop_in_place: Option<DropInPlaceFn>,
434
435 pub parse: Option<ParseFn>,
437
438 pub try_from: Option<TryFromFn>,
440}
441
442impl ValueVTable {
443 pub fn is_eq(&self) -> bool {
445 self.marker_traits.contains(MarkerTraits::EQ)
446 }
447
448 pub fn is_send(&self) -> bool {
450 self.marker_traits.contains(MarkerTraits::SEND)
451 }
452
453 pub fn is_sync(&self) -> bool {
455 self.marker_traits.contains(MarkerTraits::SYNC)
456 }
457
458 pub fn is_copy(&self) -> bool {
460 self.marker_traits.contains(MarkerTraits::COPY)
461 }
462
463 pub const fn builder() -> ValueVTableBuilder {
465 ValueVTableBuilder::new()
466 }
467}
468
469pub struct ValueVTableBuilder {
471 type_name: Option<TypeNameFn>,
472 display: Option<DisplayFn>,
473 debug: Option<DebugFn>,
474 default_in_place: Option<DefaultInPlaceFn>,
475 clone_into: Option<CloneIntoFn>,
476 marker_traits: MarkerTraits,
477 eq: Option<PartialEqFn>,
478 partial_ord: Option<PartialOrdFn>,
479 ord: Option<CmpFn>,
480 hash: Option<HashFn>,
481 drop_in_place: Option<DropInPlaceFn>,
482 parse: Option<ParseFn>,
483 try_from: Option<TryFromFn>,
484}
485
486impl ValueVTableBuilder {
487 #[allow(clippy::new_without_default)]
489 pub const fn new() -> Self {
490 Self {
491 type_name: None,
492 display: None,
493 debug: None,
494 default_in_place: None,
495 clone_into: None,
496 marker_traits: MarkerTraits::empty(),
497 eq: None,
498 partial_ord: None,
499 ord: None,
500 hash: None,
501 drop_in_place: None,
502 parse: None,
503 try_from: None,
504 }
505 }
506
507 pub const fn type_name(mut self, type_name: TypeNameFn) -> Self {
509 self.type_name = Some(type_name);
510 self
511 }
512
513 pub const fn display(mut self, display: DisplayFn) -> Self {
515 self.display = Some(display);
516 self
517 }
518
519 pub const fn display_maybe(mut self, display: Option<DisplayFn>) -> Self {
521 self.display = display;
522 self
523 }
524
525 pub const fn debug(mut self, debug: DebugFn) -> Self {
527 self.debug = Some(debug);
528 self
529 }
530
531 pub const fn debug_maybe(mut self, debug: Option<DebugFn>) -> Self {
533 self.debug = debug;
534 self
535 }
536
537 pub const fn default_in_place(mut self, default_in_place: DefaultInPlaceFn) -> Self {
539 self.default_in_place = Some(default_in_place);
540 self
541 }
542
543 pub const fn default_in_place_maybe(
545 mut self,
546 default_in_place: Option<DefaultInPlaceFn>,
547 ) -> Self {
548 self.default_in_place = default_in_place;
549 self
550 }
551
552 pub const fn clone_into(mut self, clone_into: CloneIntoFn) -> Self {
554 self.clone_into = Some(clone_into);
555 self
556 }
557
558 pub const fn clone_into_maybe(mut self, clone_into: Option<CloneIntoFn>) -> Self {
560 self.clone_into = clone_into;
561 self
562 }
563
564 pub const fn marker_traits(mut self, marker_traits: MarkerTraits) -> Self {
566 self.marker_traits = marker_traits;
567 self
568 }
569
570 pub const fn eq(mut self, eq: PartialEqFn) -> Self {
572 self.eq = Some(eq);
573 self
574 }
575
576 pub const fn eq_maybe(mut self, eq: Option<PartialEqFn>) -> Self {
578 self.eq = eq;
579 self
580 }
581
582 pub const fn partial_ord(mut self, partial_ord: PartialOrdFn) -> Self {
584 self.partial_ord = Some(partial_ord);
585 self
586 }
587
588 pub const fn partial_ord_maybe(mut self, partial_ord: Option<PartialOrdFn>) -> Self {
590 self.partial_ord = partial_ord;
591 self
592 }
593
594 pub const fn ord(mut self, ord: CmpFn) -> Self {
596 self.ord = Some(ord);
597 self
598 }
599
600 pub const fn ord_maybe(mut self, ord: Option<CmpFn>) -> Self {
602 self.ord = ord;
603 self
604 }
605
606 pub const fn hash(mut self, hash: HashFn) -> Self {
608 self.hash = Some(hash);
609 self
610 }
611
612 pub const fn hash_maybe(mut self, hash: Option<HashFn>) -> Self {
614 self.hash = hash;
615 self
616 }
617
618 pub const fn drop_in_place(mut self, drop_in_place: DropInPlaceFn) -> Self {
620 self.drop_in_place = Some(drop_in_place);
621 self
622 }
623
624 pub const fn drop_in_place_maybe(mut self, drop_in_place: Option<DropInPlaceFn>) -> Self {
626 self.drop_in_place = drop_in_place;
627 self
628 }
629
630 pub const fn parse(mut self, parse: ParseFn) -> Self {
632 self.parse = Some(parse);
633 self
634 }
635
636 pub const fn parse_maybe(mut self, parse: Option<ParseFn>) -> Self {
638 self.parse = parse;
639 self
640 }
641
642 pub const fn try_from(mut self, try_from: TryFromFn) -> Self {
644 self.try_from = Some(try_from);
645 self
646 }
647
648 pub const fn try_from_maybe(mut self, try_from: Option<TryFromFn>) -> Self {
650 self.try_from = try_from;
651 self
652 }
653
654 pub const fn build(self) -> ValueVTable {
656 ValueVTable {
657 type_name: self.type_name.unwrap(),
658 display: self.display,
659 debug: self.debug,
660 default_in_place: self.default_in_place,
661 clone_into: self.clone_into,
662 marker_traits: self.marker_traits,
663 eq: self.eq,
664 partial_ord: self.partial_ord,
665 ord: self.ord,
666 hash: self.hash,
667 drop_in_place: self.drop_in_place,
668 parse: self.parse,
669 try_from: self.try_from,
670 }
671 }
672}