| 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 | 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 ] |
| 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 | |