summaryrefslogtreecommitdiffstats
path: root/vendor/yoke/src/trait_hack.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/yoke/src/trait_hack.rs')
-rw-r--r--vendor/yoke/src/trait_hack.rs318
1 files changed, 318 insertions, 0 deletions
diff --git a/vendor/yoke/src/trait_hack.rs b/vendor/yoke/src/trait_hack.rs
new file mode 100644
index 000000000..7687903f7
--- /dev/null
+++ b/vendor/yoke/src/trait_hack.rs
@@ -0,0 +1,318 @@
+// This file is part of ICU4X. For terms of use, please see the file
+// called LICENSE at the top level of the ICU4X source tree
+// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ).
+
+//! Workarounds for adding trait bounds to `yoke` objects.
+//!
+//! # Trait bounds in Yoke
+//!
+//! [Compiler bug #89196](https://github.com/rust-lang/rust/issues/89196) makes it tricky to add
+//! trait bounds involving `yoke` types.
+//!
+//! For example, you may want to write:
+//!
+//! `where for<'a> <Y as Yokeable<'a>>::Output: MyTrait`
+//!
+//! The above trait bound will compile, but at call sites, you get errors such as:
+//!
+//! > the trait `for<'de> MyTrait` is not implemented for `<Y as Yokeable<'de>>::Output`
+//!
+//! There are two known workarounds:
+//!
+//! 1. If the trait is well-defined on references, like `Debug`, bind the trait to a reference:
+//! `where for<'a> &'a <Y as Yokeable<'a>>::Output: MyTrait`
+//! 2. If the trait involves `Self`, like `Clone`, use [`YokeTraitHack`]:
+//! `where for<'a> YokeTraitHack<<Y as Yokeable<'a>>::Output>: MyTrait`
+//!
+//! # Examples
+//!
+//! Code that does not compile ([playground](https://play.rust-lang.org/?version=beta&mode=debug&edition=2018&gist=ebbda5b15a398d648bdff9e439b27dc0)):
+//!
+//! ```compile_fail
+//! use yoke::*;
+//!
+//! trait MiniDataMarker {
+//! type Yokeable: for<'a> Yokeable<'a>;
+//! }
+//!
+//! struct MiniDataPayload<M>
+//! where
+//! M: MiniDataMarker
+//! {
+//! pub yoke: Yoke<M::Yokeable, ()>,
+//! }
+//!
+//! impl<M> Clone for MiniDataPayload<M>
+//! where
+//! M: MiniDataMarker,
+//! for<'a> <M::Yokeable as Yokeable<'a>>::Output: Clone,
+//! {
+//! fn clone(&self) -> Self {
+//! unimplemented!()
+//! }
+//! }
+//!
+//! trait MiniDataProvider<M>
+//! where
+//! M: MiniDataMarker
+//! {
+//! fn mini_load_data(&self) -> MiniDataPayload<M>;
+//! }
+//!
+//! struct MiniStructProvider<M>
+//! where
+//! M: MiniDataMarker,
+//! {
+//! pub payload: MiniDataPayload<M>,
+//! }
+//!
+//! impl<M> MiniDataProvider<M> for MiniStructProvider<M>
+//! where
+//! M: MiniDataMarker,
+//! for<'a> <M::Yokeable as Yokeable<'a>>::Output: Clone,
+//! {
+//! fn mini_load_data(&self) -> MiniDataPayload<M> {
+//! self.payload.clone()
+//! }
+//! }
+//!
+//! #[derive(Clone)]
+//! struct SimpleStruct(pub u32);
+//!
+//! unsafe impl<'a> Yokeable<'a> for SimpleStruct {
+//! // (not shown; see `Yokeable` for examples)
+//! # type Output = SimpleStruct;
+//! # fn transform(&'a self) -> &'a Self::Output {
+//! # self
+//! # }
+//! # fn transform_owned(self) -> Self::Output {
+//! # self
+//! # }
+//! # unsafe fn make(from: Self::Output) -> Self {
+//! # std::mem::transmute(from)
+//! # }
+//! # fn transform_mut<F>(&'a mut self, f: F)
+//! # where
+//! # F: 'static + for<'b> FnOnce(&'b mut Self::Output),
+//! # {
+//! # unsafe {
+//! # f(std::mem::transmute::<&'a mut Self, &'a mut Self::Output>(
+//! # self,
+//! # ))
+//! # }
+//! # }
+//! }
+//!
+//! impl MiniDataMarker for SimpleStruct {
+//! type Yokeable = SimpleStruct;
+//! }
+//!
+//! let provider = MiniStructProvider {
+//! payload: MiniDataPayload {
+//! yoke: Yoke::new_always_owned(SimpleStruct(42))
+//! }
+//! };
+//!
+//! // Broken:
+//! // "method cannot be called on `MiniStructProvider<_>` due to unsatisfied trait bounds"
+//! let payload: MiniDataPayload<SimpleStruct> = provider.mini_load_data();
+//!
+//! // Working:
+//! let payload = MiniDataProvider::<SimpleStruct>::mini_load_data(&provider);
+//!
+//! assert_eq!(payload.yoke.get().0, 42);
+//! ```
+//!
+//! Example for binding the trait to a reference:
+//!
+//! ```
+//! use yoke::Yoke;
+//! use yoke::Yokeable;
+//!
+//! // Example trait and struct for illustration purposes:
+//! trait MyTrait {
+//! fn demo(&self) -> u32;
+//! }
+//! struct MyStruct(u32);
+//! impl MyTrait for MyStruct {
+//! fn demo(&self) -> u32 {
+//! self.0
+//! }
+//! }
+//! unsafe impl<'a> Yokeable<'a> for MyStruct {
+//! // (not shown; see `Yokeable` for examples)
+//! # type Output = MyStruct;
+//! # fn transform(&'a self) -> &'a Self::Output {
+//! # self
+//! # }
+//! # fn transform_owned(self) -> Self::Output {
+//! # self
+//! # }
+//! # unsafe fn make(from: Self::Output) -> Self {
+//! # std::mem::transmute(from)
+//! # }
+//! # fn transform_mut<F>(&'a mut self, f: F)
+//! # where
+//! # F: 'static + for<'b> FnOnce(&'b mut Self::Output),
+//! # {
+//! # unsafe {
+//! # f(std::mem::transmute::<&'a mut Self, &'a mut Self::Output>(
+//! # self,
+//! # ))
+//! # }
+//! # }
+//! }
+//!
+//! // The trait needs to be defined on references:
+//! impl<'a, T> MyTrait for &'a T
+//! where
+//! T: MyTrait,
+//! {
+//! fn demo(&self) -> u32 {
+//! self.demo()
+//! }
+//! }
+//!
+//! impl<Y, C> MyTrait for Yoke<Y, C>
+//! where
+//! Y: for<'a> Yokeable<'a>,
+//! for<'a> &'a <Y as Yokeable<'a>>::Output: MyTrait,
+//! {
+//! fn demo(&self) -> u32 {
+//! self.get().demo()
+//! }
+//! }
+//!
+//! fn example() {
+//! let y = Yoke::<MyStruct, ()>::new_always_owned(MyStruct(42));
+//! let _: &dyn MyTrait = &y;
+//! }
+//! ```
+//!
+//! Example for using [`YokeTraitHack`]:
+//!
+//! ```
+//! use std::rc::Rc;
+//! use yoke::trait_hack::YokeTraitHack;
+//! use yoke::Yoke;
+//! use yoke::Yokeable;
+//!
+//! // Example trait and struct for illustration purposes:
+//! trait MyTrait {
+//! fn demo(data: u32) -> Self;
+//! }
+//! struct MyStruct(u32);
+//! impl MyTrait for MyStruct {
+//! fn demo(data: u32) -> Self {
+//! Self(data)
+//! }
+//! }
+//! unsafe impl<'a> Yokeable<'a> for MyStruct {
+//! // (not shown; see `Yokeable` for examples)
+//! # type Output = MyStruct;
+//! # fn transform(&'a self) -> &'a Self::Output {
+//! # self
+//! # }
+//! # fn transform_owned(self) -> Self::Output {
+//! # self
+//! # }
+//! # unsafe fn make(from: Self::Output) -> Self {
+//! # std::mem::transmute(from)
+//! # }
+//! # fn transform_mut<F>(&'a mut self, f: F)
+//! # where
+//! # F: 'static + for<'b> FnOnce(&'b mut Self::Output),
+//! # {
+//! # unsafe {
+//! # f(std::mem::transmute::<&'a mut Self, &'a mut Self::Output>(
+//! # self,
+//! # ))
+//! # }
+//! # }
+//! }
+//!
+//! // The trait needs to be defined on YokeTraitHack:
+//! impl<'a, T> MyTrait for YokeTraitHack<T>
+//! where
+//! T: MyTrait,
+//! {
+//! fn demo(data: u32) -> Self {
+//! YokeTraitHack(T::demo(data))
+//! }
+//! }
+//!
+//! impl<Y> MyTrait for Yoke<Y, Rc<u32>>
+//! where
+//! Y: for<'a> Yokeable<'a>,
+//! for<'a> YokeTraitHack<<Y as Yokeable<'a>>::Output>: MyTrait,
+//! {
+//! fn demo(data: u32) -> Self {
+//! let rc_u32: Rc<u32> = Rc::new(data);
+//! Yoke::attach_to_cart(rc_u32, |u| {
+//! YokeTraitHack::<<Y as Yokeable>::Output>::demo(*u).0
+//! })
+//! }
+//! }
+//!
+//! fn example() {
+//! let _ = Yoke::<MyStruct, Rc<u32>>::demo(42);
+//! }
+//! ```
+
+use core::mem;
+
+/// A wrapper around a type `T`, forwarding trait calls down to the inner type.
+///
+/// `YokeTraitHack` supports [`Clone`], [`PartialEq`], [`Eq`], and [`serde::Deserialize`] out of
+/// the box. Other traits can be implemented by the caller.
+///
+/// For more information, see the module-level documentation.
+///
+/// # Example
+///
+/// Using `YokeTraitHack` as a type bound in a function comparing two `Yoke`s:
+///
+/// ```
+/// use yoke::trait_hack::YokeTraitHack;
+/// use yoke::*;
+///
+/// fn compare_yokes<Y, C1, C2>(y1: Yoke<Y, C1>, y2: Yoke<Y, C2>) -> bool
+/// where
+/// Y: for<'a> Yokeable<'a>,
+/// for<'a> YokeTraitHack<<Y as Yokeable<'a>>::Output>: PartialEq,
+/// {
+/// YokeTraitHack(y1.get()).into_ref() == YokeTraitHack(y2.get()).into_ref()
+/// }
+/// ```
+#[repr(transparent)]
+#[derive(Clone, PartialEq, Eq)]
+#[allow(clippy::exhaustive_structs)] // newtype
+pub struct YokeTraitHack<T>(pub T);
+
+impl<'a, T> YokeTraitHack<&'a T> {
+ /// Converts from `YokeTraitHack<&T>` to `&YokeTraitHack<T>`.
+ ///
+ /// This is safe because `YokeTraitHack` is `repr(transparent)`.
+ ///
+ /// This method is required to implement `Clone` on `Yoke`.
+ pub fn into_ref(self) -> &'a YokeTraitHack<T> {
+ // YokeTraitHack is repr(transparent) so it's always safe
+ // to transmute YTH<&T> to &YTH<T>
+ unsafe { mem::transmute::<YokeTraitHack<&T>, &YokeTraitHack<T>>(self) }
+ }
+}
+
+// This is implemented manually to avoid the serde derive dependency.
+#[cfg(feature = "serde")]
+impl<'de, T> serde::de::Deserialize<'de> for YokeTraitHack<T>
+where
+ T: serde::de::Deserialize<'de>,
+{
+ #[inline]
+ fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+ where
+ D: serde::de::Deserializer<'de>,
+ {
+ T::deserialize(deserializer).map(YokeTraitHack)
+ }
+}