@@ -20,22 +20,34 @@ pub struct Type {
2020/// This function is not called directly instead a pointer to a monomorphized
2121/// instance of it is returned by [`TypeId::variant_getter`].
2222///
23+ /// # Errors
24+ /// It's an ICE to call this with anything not an enum. This is guarded for
25+ /// by [`TypeId::variant_getter`].
26+ ///
2327/// # Safety
2428///
2529/// See [`TypeId::variant_getter`] on how to safely use this function.
2630#[ lang = "variant_getter" ]
27- unsafe fn variant_getter < T : ' static > ( val : * const ( ) ) -> VariantId {
28- // SAFETY up to the caller to uphold, documented in `TypeId::variant_getter`.
31+ unsafe fn variant_getter < T > ( val : * const ( ) ) -> VariantId
32+ where
33+ <T as DiscriminantKind >:: Discriminant : ' static ,
34+ {
35+ // SAFETY: up to the caller to uphold, documented in `TypeId::variant_getter`.
2936 let v: & T = unsafe { & * val. cast :: < T > ( ) } ;
3037 let discriminant = core:: mem:: discriminant ( v) ;
3138 let lookup_table: & ' static [ <T as DiscriminantKind >:: Discriminant ] =
3239 const { intrinsics:: reflection:: type_id_variant_lookup_table :: < T > ( ) } ;
3340
41+ if lookup_table. is_empty ( ) {
42+ // for types other then enums the table will be empty
43+ return VariantId { base : const { of :: < T > ( ) } , variant : 0 } ;
44+ }
45+
3446 let variant = lookup_table
3547 . iter ( )
3648 . position ( |d| Discriminant ( * d) == discriminant)
3749 . expect ( "table contains all possible discriminants" ) ;
38- VariantId { base : const { TypeId :: of :: < T > ( ) } , variant }
50+ VariantId { base : const { of :: < T > ( ) } , variant }
3951}
4052
4153/// Info of a trait implementation, you can retrieve the vtable with [Self::get_vtable]
@@ -708,6 +720,9 @@ impl TypeId {
708720 /// When called on a `TypeId` representing some enum `T` this returns a function pointer
709721 /// which can be used to get the `VariantId` of an instance of `T` at runtime.
710722 ///
723+ /// When given a `TypeId` for something which does not represent an enum the returned
724+ /// function can still be called. It will then return the same as `TypeId::variant(0)`.
725+ ///
711726 /// # Safety
712727 ///
713728 /// While calling this function is completely safe the returned function pointer
@@ -719,39 +734,49 @@ impl TypeId {
719734 /// # Examples
720735 ///
721736 /// ```
722- /// #![feature(type_info)]
723- /// # use std::any::TypeId;
737+ /// # #![feature(const_trait_impl)]
738+ /// # #![feature(const_heap)]
739+ /// # #![feature(type_info)]
740+ /// use std::any::TypeId;
724741 /// enum Kitty {
725742 /// Sleepy,
726743 /// Playful,
727744 /// Cuddly,
728745 /// }
729- ///
746+
730747 /// let names = const {
731748 /// let type_id = TypeId::of::<Kitty>();
732749 /// let mut names = Vec::new();
733- ///
750+
734751 /// while names.len() < type_id.variants() {
735- /// let variant = type_id.variant(names.len());
736- /// names.push(variant .name());
752+ /// let variant_id = type_id.variant(names.len());
753+ /// names.push((variant_id, variant_id .name() ));
737754 /// }
738- /// names
755+ /// names.const_make_global()
739756 /// };
740757 /// let variant_getter = const { TypeId::of::<Kitty>().variant_getter() };
741- ///
758+
742759 /// let kitty = Kitty::Playful;
743- /// // Normally when using this API you no longer have the Type but only
744- /// // a type erased pointer.
745- /// let type_erased_kitty = (*&kitty) as *const ();
746- ///
747- /// let variant_idx = variant_getter(type_erased_kitty);
748- /// println!("kitty is: {}", names[variant_idx].to_lower());
760+ /// // Normally when using the getter you are manually offsetting pointers and you have no type.
761+ /// // We'll pretend here for brevity.
762+ /// let kitty_ptr = &kitty as *const Kitty;
763+ /// let kitty_ptr = kitty_ptr.cast::<()>();
764+
765+ /// let variant_id = variant_getter(kitty_ptr);
766+ /// let kitty_is_feeling = names
767+ /// .iter()
768+ /// .find(|(id, _)| *id == variant_id)
769+ /// .map(|(_, variant_name)| *variant_name)
770+ /// .expect("We have a list of steps for each VariantId")
771+ /// .to_lowercase();
772+
773+ /// assert_eq!(kitty_is_feeling, "playful");
749774 /// ```
750775 ///
751776 #[ unstable( feature = "type_info" , issue = "146922" ) ]
752777 #[ rustc_const_unstable( feature = "type_info" , issue = "146922" ) ]
753778 #[ rustc_comptime]
754- pub fn variant_getter ( self ) -> fn ( * const ( ) ) -> VariantId {
779+ pub fn variant_getter ( self ) -> unsafe fn ( * const ( ) ) -> VariantId {
755780 intrinsics:: reflection:: type_id_variant_getter ( self )
756781 }
757782}
0 commit comments