Coverage Report

Created: 2025-05-08 06:13

/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
}