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