@@ -610,6 +610,84 @@ impl dyn Any + Send + Sync {
610610/// While `TypeId` implements `Hash`, `PartialOrd`, and `Ord`, it is worth
611611/// noting that the hashes and ordering will vary between Rust releases. Beware
612612/// of relying on them inside of your code!
613+ ///
614+ /// **Note on Variance**:
615+ /// Suppose `SubType` is a subtype of `SuperType`,
616+ /// that is, `SubType` can be used wherever `SuperType` can be used,
617+ /// and can be freely as-casted to it,
618+ /// and `CoVar`is a generic data type that has a covariant type parameter.
619+ /// Then by covariance, `CoVar<SubType>` is a subtype of `CoVar<SuperType>`,
620+ /// that is, `CoVar<SubType>` can be used wherever `CoVar<SuperType>` can be used,
621+ /// and can be freely as-casted to it.
622+ /// Then if `CoVar<SuperType>` relies on `TypeId::of::<SuperType>` to uphold any invariants,
623+ /// those invariants may be broken like so:
624+ /// ```
625+ /// type SubType = fn(&());
626+ /// type SuperType = fn(&'static ());
627+ /// type CoVar<T> = *const T; // imagine something more complicated
628+ ///
629+ /// let sub = CoVar::<SubType>::new();
630+ /// // not created by CoVar::<SuperType>::new
631+ /// let fake_super = sub as CoVar<SuperType>;
632+ /// ```
633+ ///
634+ /// A full example
635+ ///
636+ /// ```
637+ /// use std::any::TypeId;
638+ /// use std::collections::HashSet;
639+ /// use std::marker::PhantomData;
640+ /// use std::sync::{LazyLock, Mutex};
641+ ///
642+ /// use unique::Unique;
643+ ///
644+ /// static ID_SET: LazyLock<Mutex<HashSet<TypeId>>> = LazyLock::new(|| Mutex::new(HashSet::new()));
645+ ///
646+ /// mod unique {
647+ /// use super::*;
648+ ///
649+ /// // Due to its private data member, outside this module,
650+ /// // this struct can only be created using `new`.
651+ /// #[derive(Debug, PartialEq)]
652+ /// pub struct Unique<TypeAsId: 'static>(PhantomData<TypeAsId>);
653+ ///
654+ /// impl<TypeAsId: 'static> Unique<TypeAsId> {
655+ /// pub fn new() -> Option<Self> {
656+ /// let mut set = ID_SET.lock().unwrap();
657+ /// set.insert(TypeId::of::<TypeAsId>())
658+ /// .then(|| Self(PhantomData))
659+ /// }
660+ /// }
661+ ///
662+ /// impl<TypeAsId: 'static> Drop for Unique<TypeAsId> {
663+ /// fn drop(&mut self) {
664+ /// let mut set = ID_SET.lock().unwrap();
665+ /// (!set.remove(&TypeId::of::<TypeAsId>())).then(|| panic!("duplicity detected"));
666+ /// }
667+ /// }
668+ /// }
669+ ///
670+ /// // A FnRef can be used wherever a FnStaticRef can be used,
671+ /// // so FnRef is a subtype of FnStaticRef.
672+ /// // Both are 'static, and thus have a TypeId.
673+ /// type FnRef = fn(&());
674+ /// type FnStaticRef = fn(&'static ());
675+ ///
676+ /// fn main() {
677+ /// type TheOneRing = FnStaticRef;
678+ ///
679+ /// let the_one_ring = Unique::<TheOneRing>::new().unwrap();
680+ /// assert_eq!(Unique::<TheOneRing>::new(), None);
681+ ///
682+ /// type OtherRing = FnRef;
683+ ///
684+ /// let other_ring = Unique::<OtherRing>::new().unwrap();
685+ /// let fake_one_ring = other_ring as Unique<TheOneRing>;
686+ /// assert_eq!(fake_one_ring, the_one_ring);
687+ ///
688+ /// std::mem::forget(fake_one_ring);
689+ /// }
690+ /// ```
613691#[ derive( Clone , Copy , Eq , PartialOrd , Ord ) ]
614692#[ stable( feature = "rust1" , since = "1.0.0" ) ]
615693pub struct TypeId {
@@ -627,8 +705,7 @@ impl PartialEq for TypeId {
627705}
628706
629707impl TypeId {
630- /// Returns the `TypeId` of the type this generic function has been
631- /// instantiated with.
708+ /// Given a type (as a generic type argument), returns the `TypeId` of that type.
632709 ///
633710 /// # Examples
634711 ///
0 commit comments