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}