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