1// This file is part of ICU4X. For terms of use, please see the file
2// called LICENSE at the top level of the ICU4X source tree
3// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ).
4
5//! Workarounds for adding trait bounds to `yoke` objects.
6//!
7//! # Trait bounds in Yoke
8//!
9//! [Compiler bug #89196](https://github.com/rust-lang/rust/issues/89196) makes it tricky to add
10//! trait bounds involving `yoke` types.
11//!
12//! For example, you may want to write:
13//!
14//! `where for<'a> <Y as Yokeable<'a>>::Output: MyTrait`
15//!
16//! The above trait bound will compile, but at call sites, you get errors such as:
17//!
18//! > the trait `for<'de> MyTrait` is not implemented for `<Y as Yokeable<'de>>::Output`
19//!
20//! There are two known workarounds:
21//!
22//! 1. If the trait is well-defined on references, like `Debug`, bind the trait to a reference:
23//! `where for<'a> &'a <Y as Yokeable<'a>>::Output: MyTrait`
24//! 2. If the trait involves `Self`, like `Clone`, use [`YokeTraitHack`]:
25//! `where for<'a> YokeTraitHack<<Y as Yokeable<'a>>::Output>: MyTrait`
26//!
27//! # Examples
28//!
29//! Code that does not compile ([playground](https://play.rust-lang.org/?version=beta&mode=debug&edition=2018&gist=ebbda5b15a398d648bdff9e439b27dc0)):
30//!
31//! ```compile_fail
32//! use yoke::*;
33//!
34//! trait MiniDataMarker {
35//! type Yokeable: for<'a> Yokeable<'a>;
36//! }
37//!
38//! struct MiniDataPayload<M>
39//! where
40//! M: MiniDataMarker
41//! {
42//! pub yoke: Yoke<M::Yokeable, ()>,
43//! }
44//!
45//! impl<M> Clone for MiniDataPayload<M>
46//! where
47//! M: MiniDataMarker,
48//! for<'a> <M::Yokeable as Yokeable<'a>>::Output: Clone,
49//! {
50//! fn clone(&self) -> Self {
51//! unimplemented!()
52//! }
53//! }
54//!
55//! trait MiniDataProvider<M>
56//! where
57//! M: MiniDataMarker
58//! {
59//! fn mini_load_data(&self) -> MiniDataPayload<M>;
60//! }
61//!
62//! struct MiniStructProvider<M>
63//! where
64//! M: MiniDataMarker,
65//! {
66//! pub payload: MiniDataPayload<M>,
67//! }
68//!
69//! impl<M> MiniDataProvider<M> for MiniStructProvider<M>
70//! where
71//! M: MiniDataMarker,
72//! for<'a> <M::Yokeable as Yokeable<'a>>::Output: Clone,
73//! {
74//! fn mini_load_data(&self) -> MiniDataPayload<M> {
75//! self.payload.clone()
76//! }
77//! }
78//!
79//! #[derive(Clone)]
80//! struct SimpleStruct(pub u32);
81//!
82//! unsafe impl<'a> Yokeable<'a> for SimpleStruct {
83//! // (not shown; see `Yokeable` for examples)
84//! # type Output = SimpleStruct;
85//! # fn transform(&'a self) -> &'a Self::Output {
86//! # self
87//! # }
88//! # fn transform_owned(self) -> Self::Output {
89//! # self
90//! # }
91//! # unsafe fn make(from: Self::Output) -> Self {
92//! # std::mem::transmute(from)
93//! # }
94//! # fn transform_mut<F>(&'a mut self, f: F)
95//! # where
96//! # F: 'static + for<'b> FnOnce(&'b mut Self::Output),
97//! # {
98//! # unsafe {
99//! # f(std::mem::transmute::<&'a mut Self, &'a mut Self::Output>(
100//! # self,
101//! # ))
102//! # }
103//! # }
104//! }
105//!
106//! impl MiniDataMarker for SimpleStruct {
107//! type Yokeable = SimpleStruct;
108//! }
109//!
110//! let provider = MiniStructProvider {
111//! payload: MiniDataPayload {
112//! yoke: Yoke::new_always_owned(SimpleStruct(42))
113//! }
114//! };
115//!
116//! // Broken:
117//! // "method cannot be called on `MiniStructProvider<_>` due to unsatisfied trait bounds"
118//! let payload: MiniDataPayload<SimpleStruct> = provider.mini_load_data();
119//!
120//! // Working:
121//! let payload = MiniDataProvider::<SimpleStruct>::mini_load_data(&provider);
122//!
123//! assert_eq!(payload.yoke.get().0, 42);
124//! ```
125//!
126//! Example for binding the trait to a reference:
127//!
128//! ```
129//! use yoke::Yoke;
130//! use yoke::Yokeable;
131//!
132//! // Example trait and struct for illustration purposes:
133//! trait MyTrait {
134//! fn demo(&self) -> u32;
135//! }
136//! struct MyStruct(u32);
137//! impl MyTrait for MyStruct {
138//! fn demo(&self) -> u32 {
139//! self.0
140//! }
141//! }
142//! unsafe impl<'a> Yokeable<'a> for MyStruct {
143//! // (not shown; see `Yokeable` for examples)
144//! # type Output = MyStruct;
145//! # fn transform(&'a self) -> &'a Self::Output {
146//! # self
147//! # }
148//! # fn transform_owned(self) -> Self::Output {
149//! # self
150//! # }
151//! # unsafe fn make(from: Self::Output) -> Self {
152//! # std::mem::transmute(from)
153//! # }
154//! # fn transform_mut<F>(&'a mut self, f: F)
155//! # where
156//! # F: 'static + for<'b> FnOnce(&'b mut Self::Output),
157//! # {
158//! # unsafe {
159//! # f(std::mem::transmute::<&'a mut Self, &'a mut Self::Output>(
160//! # self,
161//! # ))
162//! # }
163//! # }
164//! }
165//!
166//! // The trait needs to be defined on references:
167//! impl<'a, T> MyTrait for &'a T
168//! where
169//! T: MyTrait,
170//! {
171//! fn demo(&self) -> u32 {
172//! self.demo()
173//! }
174//! }
175//!
176//! impl<Y, C> MyTrait for Yoke<Y, C>
177//! where
178//! Y: for<'a> Yokeable<'a>,
179//! for<'a> &'a <Y as Yokeable<'a>>::Output: MyTrait,
180//! {
181//! fn demo(&self) -> u32 {
182//! self.get().demo()
183//! }
184//! }
185//!
186//! fn example() {
187//! let y = Yoke::<MyStruct, ()>::new_always_owned(MyStruct(42));
188//! let _: &dyn MyTrait = &y;
189//! }
190//! ```
191//!
192//! Example for using [`YokeTraitHack`]:
193//!
194//! ```
195//! use std::rc::Rc;
196//! use yoke::trait_hack::YokeTraitHack;
197//! use yoke::Yoke;
198//! use yoke::Yokeable;
199//!
200//! // Example trait and struct for illustration purposes:
201//! trait MyTrait {
202//! fn demo(data: u32) -> Self;
203//! }
204//! struct MyStruct(u32);
205//! impl MyTrait for MyStruct {
206//! fn demo(data: u32) -> Self {
207//! Self(data)
208//! }
209//! }
210//! unsafe impl<'a> Yokeable<'a> for MyStruct {
211//! // (not shown; see `Yokeable` for examples)
212//! # type Output = MyStruct;
213//! # fn transform(&'a self) -> &'a Self::Output {
214//! # self
215//! # }
216//! # fn transform_owned(self) -> Self::Output {
217//! # self
218//! # }
219//! # unsafe fn make(from: Self::Output) -> Self {
220//! # std::mem::transmute(from)
221//! # }
222//! # fn transform_mut<F>(&'a mut self, f: F)
223//! # where
224//! # F: 'static + for<'b> FnOnce(&'b mut Self::Output),
225//! # {
226//! # unsafe {
227//! # f(std::mem::transmute::<&'a mut Self, &'a mut Self::Output>(
228//! # self,
229//! # ))
230//! # }
231//! # }
232//! }
233//!
234//! // The trait needs to be defined on YokeTraitHack:
235//! impl<'a, T> MyTrait for YokeTraitHack<T>
236//! where
237//! T: MyTrait,
238//! {
239//! fn demo(data: u32) -> Self {
240//! YokeTraitHack(T::demo(data))
241//! }
242//! }
243//!
244//! impl<Y> MyTrait for Yoke<Y, Rc<u32>>
245//! where
246//! Y: for<'a> Yokeable<'a>,
247//! for<'a> YokeTraitHack<<Y as Yokeable<'a>>::Output>: MyTrait,
248//! {
249//! fn demo(data: u32) -> Self {
250//! let rc_u32: Rc<u32> = Rc::new(data);
251//! Yoke::attach_to_cart(rc_u32, |u| {
252//! YokeTraitHack::<<Y as Yokeable>::Output>::demo(*u).0
253//! })
254//! }
255//! }
256//!
257//! fn example() {
258//! let _ = Yoke::<MyStruct, Rc<u32>>::demo(42);
259//! }
260//! ```
261
262use core::mem;
263
264/// A wrapper around a type `T`, forwarding trait calls down to the inner type.
265///
266/// `YokeTraitHack` supports [`Clone`], [`PartialEq`], [`Eq`], and [`serde::Deserialize`] out of
267/// the box. Other traits can be implemented by the caller.
268///
269/// For more information, see the module-level documentation.
270///
271/// # Example
272///
273/// Using `YokeTraitHack` as a type bound in a function comparing two `Yoke`s:
274///
275/// ```
276/// use yoke::trait_hack::YokeTraitHack;
277/// use yoke::*;
278///
279/// fn compare_yokes<Y, C1, C2>(y1: Yoke<Y, C1>, y2: Yoke<Y, C2>) -> bool
280/// where
281/// Y: for<'a> Yokeable<'a>,
282/// for<'a> YokeTraitHack<<Y as Yokeable<'a>>::Output>: PartialEq,
283/// {
284/// YokeTraitHack(y1.get()).into_ref() == YokeTraitHack(y2.get()).into_ref()
285/// }
286/// ```
287#[repr(transparent)]
288#[derive(Clone, PartialEq, Eq, Debug)]
289#[allow(clippy::exhaustive_structs)] // newtype
290pub struct YokeTraitHack<T>(pub T);
291
292impl<'a, T> YokeTraitHack<&'a T> {
293 /// Converts from `YokeTraitHack<&T>` to `&YokeTraitHack<T>`.
294 ///
295 /// This is safe because `YokeTraitHack` is `repr(transparent)`.
296 ///
297 /// This method is required to implement `Clone` on `Yoke`.
298 pub fn into_ref(self) -> &'a YokeTraitHack<T> {
299 // YokeTraitHack is repr(transparent) so it's always safe
300 // to transmute YTH<&T> to &YTH<T>
301 unsafe { mem::transmute::<YokeTraitHack<&T>, &YokeTraitHack<T>>(self) }
302 }
303}
304
305// This is implemented manually to avoid the serde derive dependency.
306#[cfg(feature = "serde")]
307impl<'de, T> serde::de::Deserialize<'de> for YokeTraitHack<T>
308where
309 T: serde::de::Deserialize<'de>,
310{
311 #[inline]
312 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
313 where
314 D: serde::de::Deserializer<'de>,
315 {
316 T::deserialize(deserializer).map(YokeTraitHack)
317 }
318}
319