/rust/registry/src/index.crates.io-6f17d22bba15001f/yoke-0.7.5/src/trait_hack.rs
Line | Count | Source (jump to first uncovered line) |
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`. |
299 | 0 | pub fn into_ref(self) -> &'a YokeTraitHack<T> { |
300 | 0 | // Safety: YokeTraitHack is repr(transparent) so it's always safe |
301 | 0 | // to transmute YTH<&T> to &YTH<T> |
302 | 0 | unsafe { mem::transmute::<YokeTraitHack<&T>, &YokeTraitHack<T>>(self) } |
303 | 0 | } |
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] |
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 | | } |