try_specialize/unreliable/
weak_specialization.rs

1use crate::unreliable::impls_lifetime_free_weak;
2use crate::{type_eq_ignore_lifetimes, Specialization};
3
4/// A extension trait for [`Specialization`] type for specializing one
5/// completely unconstrained type to another completely unconstrained type.
6///
7/// # Reliability
8///
9/// While it is unlikely, there is still a possibility that the methods of this
10/// trait may return false negatives in future Rust versions.
11///
12/// The correctness of the results returned by the methods depends on the
13/// following:
14/// - Documented behavior that if `T` implements `Eq`, two `Rc`s that point to
15///   the same allocation are always equal:
16///   <https://doc.rust-lang.org/1.82.0/std/rc/struct.Rc.html#method.eq>.
17/// - Undocumented behavior that the `Rc::partial_eq` implementation for `T: Eq`
18///   will not use `PartialEq::eq` if both `Rc`s point to the same memory
19///   location.
20/// - The assumption that the undocumented short-circuit behavior described
21///   above will be retained for optimization purposes.
22///
23/// There is no formal guarantee that the undocumented behavior described above
24/// will be retained. If the implementation changes in a future Rust version,
25/// the function may return a false negative, that is, it may return `false`,
26/// even though `T` implements the trait. However, the implementation guarantees
27/// that a false positive result is impossible, i.e., the function will never
28/// return true if `T` does not implement the trait in any future Rust version.
29///
30/// Details:
31/// - <https://internals.rust-lang.org/t/rc-uses-visibly-behavior-changing-specialization-is-that-okay/16173/6>,
32/// - <https://users.rust-lang.org/t/hack-to-specialize-w-write-for-vec-u8/100366>,
33/// - <https://doc.rust-lang.org/1.82.0/std/rc/struct.Rc.html#method.eq>,
34/// - <https://github.com/rust-lang/rust/issues/42655>.
35pub trait WeakSpecialization: Sized {
36    /// Checks the types `T1` and `T2` for equality and returns the
37    /// specialization provider if types implement `LifetimeFree` and the types
38    /// are equal.
39    ///
40    /// The [`LifetimeFree`] trait is **not** automatically derived for all
41    /// lifetime-free types. The library only implements it for standard library
42    /// types that do not have any lifetime parameters. This function uses
43    /// `impls_lifetime_free` to check wherever the unconstrained type
44    /// implements `LifetimeFree` trait or not.
45    ///
46    /// [`LifetimeFree`]: crate::LifetimeFree
47    #[must_use]
48    fn try_new_if_lifetime_free_weak() -> Option<Self>;
49}
50
51#[cfg(feature = "alloc")]
52impl<T1, T2> WeakSpecialization for Specialization<T1, T2>
53where
54    T1: ?Sized,
55    T2: ?Sized,
56{
57    #[inline]
58    fn try_new_if_lifetime_free_weak() -> Option<Self> {
59        (impls_lifetime_free_weak::<T1>() && type_eq_ignore_lifetimes::<T1, T2>())
60            // SAFETY: `T1` can be specialized to `T2` if the types are equal with
61            // erased lifetime and any of it implements `NoLifetime` trait.
62            .then_some(unsafe { Self::new_unchecked() })
63    }
64}