Skip to content

Commit 48894e5

Browse files
committed
include note on variance and example
Fixes #89150
1 parent 61cc3e5 commit 48894e5

File tree

1 file changed

+78
-2
lines changed

1 file changed

+78
-2
lines changed

library/core/src/any.rs

+78-2
Original file line numberDiff line numberDiff line change
@@ -610,6 +610,83 @@ 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+
///
628+
/// let sub = CoVar<SubType>::new();
629+
/// // not created by CoVar<SuperType>::new
630+
/// let fake_super = sub as CoVar<SuperType>;
631+
/// ```
632+
///
633+
/// A full example
634+
///
635+
/// ```
636+
/// use std::any::TypeId;
637+
/// use std::collections::HashSet;
638+
/// use std::marker::PhantomData;
639+
/// use std::sync::{LazyLock, Mutex};
640+
///
641+
/// use unique::Unique;
642+
///
643+
/// static ID_SET: LazyLock<Mutex<HashSet<TypeId>>> = LazyLock::new(|| Mutex::new(HashSet::new()));
644+
///
645+
/// mod unique {
646+
/// use super::*;
647+
///
648+
/// // Due to its private data member, outside this module,
649+
/// // this struct can only be created using `new`.
650+
/// #[derive(Debug, PartialEq)]
651+
/// pub struct Unique<TypeAsId: 'static>(PhantomData<TypeAsId>);
652+
///
653+
/// impl<TypeAsId: 'static> Unique<TypeAsId> {
654+
/// pub fn new() -> Option<Self> {
655+
/// let mut set = ID_SET.lock().unwrap();
656+
/// set.insert(TypeId::of::<TypeAsId>())
657+
/// .then(|| Self(PhantomData))
658+
/// }
659+
/// }
660+
///
661+
/// impl<TypeAsId: 'static> Drop for Unique<TypeAsId> {
662+
/// fn drop(&mut self) {
663+
/// let mut set = ID_SET.lock().unwrap();
664+
/// (!set.remove(&TypeId::of::<TypeAsId>())).then(|| panic!("duplicity detected"));
665+
/// }
666+
/// }
667+
/// }
668+
///
669+
/// // A FnRef can be used wherever a FnStaticRef can be used,
670+
/// // so FnRef is a subtype of FnStaticRef.
671+
/// // Both are 'static, and thus have a TypeId.
672+
/// type FnRef = fn(&());
673+
/// type FnStaticRef = fn(&'static ());
674+
///
675+
/// fn main() {
676+
/// type TheOneRing = FnStaticRef;
677+
///
678+
/// let the_one_ring = Unique::<TheOneRing>::new().unwrap();
679+
/// assert_eq!(Unique::<TheOneRing>::new(), None);
680+
///
681+
/// type OtherRing = FnRef;
682+
///
683+
/// let other_ring = Unique::<OtherRing>::new().unwrap();
684+
/// let fake_one_ring = other_ring as Unique<TheOneRing>;
685+
/// assert_eq!(fake_one_ring, the_one_ring);
686+
///
687+
/// std::mem::forget(fake_one_ring);
688+
/// }
689+
/// ```
613690
#[derive(Clone, Copy, Eq, PartialOrd, Ord)]
614691
#[stable(feature = "rust1", since = "1.0.0")]
615692
pub struct TypeId {
@@ -627,8 +704,7 @@ impl PartialEq for TypeId {
627704
}
628705

629706
impl TypeId {
630-
/// Returns the `TypeId` of the type this generic function has been
631-
/// instantiated with.
707+
/// Given a type (as a generic type argument), returns the `TypeId` of that type.
632708
///
633709
/// # Examples
634710
///

0 commit comments

Comments
 (0)