1use std::{
4 cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd},
5 fmt::{self, Debug, Display},
6 hash::{Hash, Hasher},
7 marker::PhantomData,
8 mem::ManuallyDrop,
9 ops::Deref,
10};
11
12use crate::{
13 abi_stability::StableAbi,
14 erased_types::{c_functions, trait_objects::HasherObject, InterfaceType, MakeRequiredTraits},
15 inline_storage::ScratchSpace,
16 marker_type::ErasedObject,
17 nonexhaustive_enum::{
18 assert_correct_storage, vtable::NonExhaustiveVtable_Ref, AssertCsArgs, DeserializeEnum,
19 EnumInfo, GetEnumInfo, GetVTable, NonExhaustiveMarker, SerializeEnum, ValidDiscriminant,
20 },
21 pointer_trait::{CanTransmuteElement, TransmuteElement},
22 sabi_types::{RMut, RRef},
23 std_types::RBoxError,
24 traits::IntoReprRust,
25 type_level::{impl_enum::Implemented, trait_marker},
26};
27
28use serde::{de, ser, Deserialize, Deserializer, Serialize, Serializer};
29
30#[cfg(all(test, not(feature = "only_new_tests")))]
32mod tests;
33
34#[repr(C)]
187#[derive(StableAbi)]
188#[sabi(
189 not_stableabi(E,S,I),
191 bound(NonExhaustiveVtable_Ref<E,S,I>:StableAbi),
192 bound(E: NonExhaustiveMarker<S>),
193 bound(I: InterfaceType),
194 extra_checks = <I as MakeRequiredTraits>::MAKE,
195 phantom_type_param = <E as NonExhaustiveMarker<S>>::Marker,
196)]
197pub struct NonExhaustive<E, S, I> {
198 #[sabi(unsafe_opaque_field)]
200 fill: ScratchSpace<E, S>,
201 vtable: NonExhaustiveVtable_Ref<E, S, I>,
202 _marker: PhantomData<()>,
203}
204
205pub type NonExhaustiveFor<E> =
208 NonExhaustive<E, <E as GetEnumInfo>::DefaultStorage, <E as GetEnumInfo>::DefaultInterface>;
209
210pub type NonExhaustiveWI<E, I> = NonExhaustive<E, <E as GetEnumInfo>::DefaultStorage, I>;
213
214pub type NonExhaustiveWS<E, S> = NonExhaustive<E, S, <E as GetEnumInfo>::DefaultInterface>;
217
218impl<E, S, I> NonExhaustive<E, S, I> {
219 #[inline]
225 pub const fn new(value: E) -> Self
226 where
227 E: GetVTable<S, I> + GetEnumInfo<DefaultStorage = S, DefaultInterface = I>,
228 {
229 NonExhaustive::with_storage_and_interface(value)
230 }
231
232 #[inline]
239 pub const fn with_interface(value: E) -> Self
240 where
241 E: GetVTable<S, I> + GetEnumInfo<DefaultStorage = S>,
242 {
243 NonExhaustive::with_storage_and_interface(value)
244 }
245
246 #[inline]
253 pub const fn with_storage(value: E) -> Self
254 where
255 E: GetVTable<S, I> + GetEnumInfo<DefaultInterface = I>,
256 {
257 NonExhaustive::with_storage_and_interface(value)
258 }
259
260 #[inline]
266 pub const fn with_storage_and_interface(value: E) -> Self
267 where
268 E: GetVTable<S, I>,
269 {
270 unsafe { NonExhaustive::with_vtable(value, E::VTABLE) }
271 }
272
273 #[track_caller]
274 pub(super) const unsafe fn with_vtable(
275 value: E,
276 vtable: NonExhaustiveVtable_Ref<E, S, I>,
277 ) -> Self {
278 Self {
281 fill: ScratchSpace::<E, S>::new(value),
282 vtable,
283 _marker: PhantomData,
284 }
285 }
286}
287
288impl<E, S, I> NonExhaustive<E, S, I>
289where
290 E: GetEnumInfo,
291{
292 pub fn as_enum(&self) -> Result<&E, UnwrapEnumError<&Self>> {
318 let discriminant = self.get_discriminant();
319 if E::is_valid_discriminant(discriminant) {
320 unsafe { Ok(&*(&self.fill as *const ScratchSpace<E, S> as *const E)) }
321 } else {
322 Err(UnwrapEnumError::new(self))
323 }
324 }
325
326 pub fn as_enum_mut(&mut self) -> Result<&mut E, UnwrapEnumError<&mut Self>>
351 where
352 E: GetVTable<S, I>,
353 {
354 let discriminant = self.get_discriminant();
355 if E::is_valid_discriminant(discriminant) {
356 self.vtable = E::VTABLE;
361 unsafe { Ok(&mut *(&mut self.fill as *mut ScratchSpace<E, S> as *mut E)) }
362 } else {
363 Err(UnwrapEnumError::new(self))
364 }
365 }
366
367 pub fn into_enum(self) -> Result<E, UnwrapEnumError<Self>> {
391 let discriminant = self.get_discriminant();
392 if E::is_valid_discriminant(discriminant) {
393 let this = ManuallyDrop::new(self);
394 unsafe { Ok((&this.fill as *const ScratchSpace<E, S> as *const E).read()) }
395 } else {
396 Err(UnwrapEnumError::new(self))
397 }
398 }
399
400 #[inline]
405 pub fn is_valid_discriminant(&self) -> bool {
406 E::is_valid_discriminant(self.get_discriminant())
407 }
408
409 #[inline]
411 pub const fn get_discriminant(&self) -> E::Discriminant {
412 unsafe { *(&self.fill as *const ScratchSpace<E, S> as *const E::Discriminant) }
413 }
414}
415
416impl<E, S, I> NonExhaustive<E, S, I> {
417 pub const unsafe fn transmute_enum<F>(self) -> NonExhaustive<F, S, I> {
430 assert_correct_storage::<F, S>(AssertCsArgs::UNKNOWN);
431 unsafe { const_transmute!(NonExhaustive<E, S, I>, NonExhaustive<F, S, I>, self) }
432 }
433
434 pub const unsafe fn transmute_enum_ref<F>(&self) -> &NonExhaustive<F, S, I> {
445 assert_correct_storage::<F, S>(AssertCsArgs::UNKNOWN);
446 unsafe { &*(self as *const Self as *const _) }
447 }
448
449 pub unsafe fn transmute_enum_mut<F>(&mut self) -> &mut NonExhaustive<F, S, I> {
460 assert_correct_storage::<F, S>(AssertCsArgs::UNKNOWN);
461 unsafe { &mut *(self as *mut Self as *mut _) }
462 }
463
464 pub unsafe fn transmute_enum_ptr<P, F>(this: P) -> P::TransmutedPtr
478 where
479 P: Deref<Target = Self>,
480 P: CanTransmuteElement<NonExhaustive<F, S, I>>,
481 {
482 assert_correct_storage::<F, S>(AssertCsArgs::UNKNOWN);
483 unsafe { this.transmute_element::<NonExhaustive<F, S, I>>() }
484 }
485
486 pub(crate) const fn vtable(&self) -> NonExhaustiveVtable_Ref<E, S, I> {
488 self.vtable
489 }
490
491 const fn sabi_erased_ref(&self) -> RRef<'_, ErasedObject> {
492 unsafe { RRef::from_raw(&self.fill as *const ScratchSpace<E, S> as *const ErasedObject) }
493 }
494
495 const fn as_erased_ref(&self) -> RRef<'_, ErasedObject> {
496 unsafe { RRef::from_raw(self as *const Self as *const ErasedObject) }
497 }
498
499 fn sabi_erased_mut(&mut self) -> RMut<'_, ErasedObject> {
500 unsafe { RMut::from_raw(&mut self.fill as *mut ScratchSpace<E, S> as *mut ErasedObject) }
501 }
502}
503
504impl<E, S, I> Clone for NonExhaustive<E, S, I>
505where
506 I: InterfaceType<Clone = Implemented<trait_marker::Clone>>,
507{
508 fn clone(&self) -> Self {
509 unsafe { self.vtable().clone_()(self.sabi_erased_ref(), self.vtable) }
510 }
511}
512
513impl<E, S, I> Display for NonExhaustive<E, S, I>
514where
515 I: InterfaceType<Display = Implemented<trait_marker::Display>>,
516{
517 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
518 unsafe {
519 c_functions::adapt_std_fmt::<ErasedObject>(
520 self.sabi_erased_ref(),
521 self.vtable().display(),
522 f,
523 )
524 }
525 }
526}
527
528impl<E, S, I> Debug for NonExhaustive<E, S, I>
529where
530 I: InterfaceType<Debug = Implemented<trait_marker::Debug>>,
531{
532 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
533 unsafe {
534 c_functions::adapt_std_fmt::<ErasedObject>(
535 self.sabi_erased_ref(),
536 self.vtable().debug(),
537 f,
538 )
539 }
540 }
541}
542
543impl<E, S, I> Eq for NonExhaustive<E, S, I>
544where
545 Self: PartialEq,
546 I: InterfaceType<Eq = Implemented<trait_marker::Eq>>,
547{
548}
549
550impl<E, S, I1, I2> PartialEq<NonExhaustive<E, S, I2>> for NonExhaustive<E, S, I1>
551where
552 I1: InterfaceType<PartialEq = Implemented<trait_marker::PartialEq>>,
553{
554 fn eq(&self, other: &NonExhaustive<E, S, I2>) -> bool {
555 unsafe { self.vtable().partial_eq()(self.sabi_erased_ref(), other.as_erased_ref()) }
556 }
557}
558
559impl<E, S, I> Ord for NonExhaustive<E, S, I>
560where
561 I: InterfaceType<Ord = Implemented<trait_marker::Ord>>,
562 Self: PartialOrd + Eq,
563{
564 fn cmp(&self, other: &Self) -> Ordering {
565 unsafe { self.vtable().cmp()(self.sabi_erased_ref(), other.as_erased_ref()).into() }
566 }
567}
568
569impl<E, S, I1, I2> PartialOrd<NonExhaustive<E, S, I2>> for NonExhaustive<E, S, I1>
570where
571 I1: InterfaceType<PartialOrd = Implemented<trait_marker::PartialOrd>>,
572 Self: PartialEq<NonExhaustive<E, S, I2>>,
573{
574 fn partial_cmp(&self, other: &NonExhaustive<E, S, I2>) -> Option<Ordering> {
575 unsafe {
576 self.vtable().partial_cmp()(self.sabi_erased_ref(), other.as_erased_ref())
577 .map(IntoReprRust::into_rust)
578 .into()
579 }
580 }
581}
582
583impl<E, S, I> PartialOrd<E> for NonExhaustive<E, S, I>
586where
587 E: GetEnumInfo + PartialOrd,
588 I: InterfaceType<PartialOrd = Implemented<trait_marker::PartialOrd>>,
589 Self: PartialEq<E>,
590{
591 fn partial_cmp(&self, other: &E) -> Option<Ordering> {
592 match self.as_enum() {
593 Ok(this) => this.partial_cmp(other),
594 Err(_) => Some(Ordering::Greater),
595 }
596 }
597}
598
599impl<E, S, I> PartialEq<E> for NonExhaustive<E, S, I>
600where
601 E: GetEnumInfo + PartialEq,
602 I: InterfaceType<PartialEq = Implemented<trait_marker::PartialEq>>,
603{
604 fn eq(&self, other: &E) -> bool {
605 match self.as_enum() {
606 Ok(this) => this == other,
607 Err(_) => false,
608 }
609 }
610}
611
612impl<E, S, I> NonExhaustive<E, S, I>
615where
616 E: GetEnumInfo,
617{
618 pub fn serialize_into_proxy(&self) -> Result<I::Proxy, RBoxError>
620 where
621 I: InterfaceType<Serialize = Implemented<trait_marker::Serialize>>,
622 I: SerializeEnum<E>,
623 {
624 unsafe { self.vtable().serialize()(self.as_erased_ref()).into_result() }
625 }
626
627 pub fn deserialize_from_proxy<'borr>(proxy: I::Proxy) -> Result<Self, RBoxError>
629 where
630 I: InterfaceType<Deserialize = Implemented<trait_marker::Deserialize>>,
631 I: DeserializeEnum<'borr, Self>,
632 I::Proxy: 'borr,
633 {
634 I::deserialize_enum(proxy)
635 }
636}
637
638impl<E, S, I> Serialize for NonExhaustive<E, S, I>
640where
641 I: InterfaceType<Serialize = Implemented<trait_marker::Serialize>>,
642 I: SerializeEnum<E>,
643 I::Proxy: Serialize,
644{
645 fn serialize<Z>(&self, serializer: Z) -> Result<Z::Ok, Z::Error>
646 where
647 Z: Serializer,
648 {
649 unsafe {
650 self.vtable().serialize()(self.as_erased_ref())
651 .into_result()
652 .map_err(ser::Error::custom)?
653 .serialize(serializer)
654 }
655 }
656}
657
658impl<'de, E, S, I> Deserialize<'de> for NonExhaustive<E, S, I>
661where
662 E: 'de + GetVTable<S, I>,
663 S: 'de,
664 I: 'de + InterfaceType<Deserialize = Implemented<trait_marker::Deserialize>>,
665 I: DeserializeEnum<'de, Self>,
666 <I as DeserializeEnum<'de, Self>>::Proxy: Deserialize<'de>,
667{
668 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
669 where
670 D: Deserializer<'de>,
671 {
672 let s =
673 <<I as DeserializeEnum<'de, Self>>::Proxy as Deserialize>::deserialize(deserializer)?;
674
675 I::deserialize_enum(s).map_err(de::Error::custom)
676 }
677}
678
679impl<E, S, I> Hash for NonExhaustive<E, S, I>
682where
683 I: InterfaceType<Hash = Implemented<trait_marker::Hash>>,
684{
685 fn hash<H>(&self, state: &mut H)
686 where
687 H: Hasher,
688 {
689 unsafe { self.vtable().hash()(self.sabi_erased_ref(), HasherObject::new(state)) }
690 }
691}
692
693impl<E, S, I> std::error::Error for NonExhaustive<E, S, I> where
694 I: InterfaceType<
695 Debug = Implemented<trait_marker::Debug>,
696 Display = Implemented<trait_marker::Display>,
697 Error = Implemented<trait_marker::Error>,
698 >
699{
700}
701
702impl<E, S, I> Drop for NonExhaustive<E, S, I> {
705 fn drop(&mut self) {
706 let drop = self.vtable()._sabi_drop();
707
708 unsafe {
709 drop(self.sabi_erased_mut());
710 }
711 }
712}
713
714pub trait NonExhaustiveSharedOps {
718 type Discriminant: ValidDiscriminant;
720
721 fn get_discriminant_(&self) -> Self::Discriminant;
723
724 fn enum_info_(&self) -> &'static EnumInfo;
726}
727
728struct DiscrAndEnumInfo<E> {
730 discr: E,
731 enum_info: &'static EnumInfo,
732}
733
734impl<E> NonExhaustiveSharedOps for DiscrAndEnumInfo<E>
735where
736 E: ValidDiscriminant,
737{
738 type Discriminant = E;
739 fn get_discriminant_(&self) -> E {
740 self.discr
741 }
742 fn enum_info_(&self) -> &'static EnumInfo {
743 self.enum_info
744 }
745}
746
747macro_rules! impl_neso {
748 (
749 impl[$E:ident,$S:ident,$I:ident]
750 ) => {
751 type Discriminant = $E::Discriminant;
752
753 fn get_discriminant_(&self) -> $E::Discriminant {
754 self.get_discriminant()
755 }
756
757 fn enum_info_(&self) -> &'static EnumInfo {
758 self.vtable().enum_info()
759 }
760 };
761}
762
763impl<E, S, I> NonExhaustiveSharedOps for NonExhaustive<E, S, I>
764where
765 E: GetEnumInfo,
766{
767 impl_neso! { impl[E,S,I] }
768}
769
770impl<'a, E, S, I> NonExhaustiveSharedOps for &'a NonExhaustive<E, S, I>
771where
772 E: GetEnumInfo,
773{
774 impl_neso! { impl[E,S,I] }
775}
776
777impl<'a, E, S, I> NonExhaustiveSharedOps for &'a mut NonExhaustive<E, S, I>
778where
779 E: GetEnumInfo,
780{
781 impl_neso! { impl[E,S,I] }
782}
783
784#[must_use]
790#[repr(transparent)]
791#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, StableAbi)]
792#[non_exhaustive]
793pub struct UnwrapEnumError<N> {
794 pub non_exhaustive: N,
796}
797
798#[allow(clippy::missing_const_for_fn)]
799impl<N> UnwrapEnumError<N> {
800 #[must_use]
802 pub fn into_inner(self) -> N {
803 self.non_exhaustive
804 }
805
806 pub fn into_boxed(self) -> RBoxError
808 where
809 N: NonExhaustiveSharedOps,
810 {
811 let x = DiscrAndEnumInfo {
812 discr: self.non_exhaustive.get_discriminant_(),
813 enum_info: self.non_exhaustive.enum_info_(),
814 };
815 let x = UnwrapEnumError::new(x);
816 RBoxError::new(x)
817 }
818}
819
820impl<N> UnwrapEnumError<N> {
821 #[inline]
822 const fn new(non_exhaustive: N) -> Self {
823 Self { non_exhaustive }
824 }
825}
826
827impl<N> Display for UnwrapEnumError<N>
828where
829 N: NonExhaustiveSharedOps,
830{
831 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
832 write!(
833 f,
834 "Could not unwrap NonExhaustive into '{}'.\n\
835 Because its discriminant was {:?} .",
836 self.non_exhaustive.enum_info_().type_name(),
837 self.non_exhaustive.get_discriminant_(),
838 )
839 }
840}
841
842impl<N> Debug for UnwrapEnumError<N>
843where
844 N: NonExhaustiveSharedOps,
845{
846 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
847 f.debug_struct("UnwrapEnumError")
848 .field("non_exhaustive", &"<opaque>")
849 .field("discriminant", &self.non_exhaustive.get_discriminant_())
850 .field("enum_info", &self.non_exhaustive.enum_info_())
851 .finish()
852 }
853}
854
855impl<N> From<UnwrapEnumError<N>> for RBoxError
856where
857 N: NonExhaustiveSharedOps,
858{
859 fn from(uee: UnwrapEnumError<N>) -> RBoxError {
860 uee.into_boxed()
861 }
862}
863
864impl<N> std::error::Error for UnwrapEnumError<N> where N: NonExhaustiveSharedOps {}