try_specialize/unreliable/
weak_specialization.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
use crate::unreliable::impls_lifetime_free_weak;
use crate::{type_eq_ignore_lifetimes, Specialization};

/// A extension trait for [`Specialization`] type for specializing one
/// completely unconstrained type to another completely unconstrained type.
///
/// # Reliability
///
/// While it is unlikely, there is still a possibility that functions of this
/// module future will returning false negatives in the future Rust versions.
///
/// The correctness of the returned result of the function depends on
/// the following:
/// - Documented behavior that if `T` implements `Eq`, two `Rc`s that
///   point to the same allocation are always equal:
///   <https://doc.rust-lang.org/1.81.0/std/rc/struct.Rc.html#method.eq>.
/// - Undocumented behavior that the implementation of `Rc::partial_eq` for `T:
///   Eq` will not `PartialEq::eq` if both `Rc`s point to the same allocation.
/// - Assumption that the undocumented short-circuit behavior described above
///   will be retained for optimization purposes.
///
/// There is no formal guarantee that the undocumented behavior
/// described above will be retained. If the implementation is changed
/// in a future Rust version, the function may return a false negative,
/// that is, return `false`, even though `T` implements the trait.
/// However, the implementation guarantees that a false positive result
/// is impossible, i.e., the function will never return true if `T` does
/// not implement the trait in any future Rust version.
///
/// Details:
/// - <https://internals.rust-lang.org/t/rc-uses-visibly-behavior-changing-specialization-is-that-okay/16173/6>,
/// - <https://users.rust-lang.org/t/hack-to-specialize-w-write-for-vec-u8/100366>,
/// - <https://doc.rust-lang.org/1.81.0/std/rc/struct.Rc.html#method.eq>,
/// - <https://github.com/rust-lang/rust/issues/42655>.
pub trait WeakSpecialization: Sized {
    /// Checks the types `T1` and `T2` for equality and returns the
    /// specialization provider if types implement `LifetimeFree` and the types
    /// are equal.
    ///
    /// Note that `LifetimeFree` is not automatically derived and implemented
    /// only for a set of types without lifetimes. This function uses
    /// `impls_lifetime_free` to check wherever the unconstrained type
    /// implements `LifetimeFree` trait or not.
    #[must_use]
    fn try_new_if_lifetime_free_weak() -> Option<Self>;
}

#[cfg(feature = "alloc")]
impl<T1, T2> WeakSpecialization for Specialization<T1, T2>
where
    T1: ?Sized,
    T2: ?Sized,
{
    #[inline]
    fn try_new_if_lifetime_free_weak() -> Option<Self> {
        (impls_lifetime_free_weak::<T1>() && type_eq_ignore_lifetimes::<T1, T2>())
            // SAFETY: `T1` can be specialized to `T2` if the types are equal with
            // erased lifetime and any of it implements `NoLifetime` trait.
            .then_some(unsafe { Self::new_unchecked() })
    }
}