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 | // In this case consistency between impls is more important |
6 | // than using pointer casts |
7 | #![allow (clippy::transmute_ptr_to_ptr)] |
8 | |
9 | use crate::Yokeable; |
10 | use core::{ |
11 | mem::{self, ManuallyDrop}, |
12 | ptr, |
13 | }; |
14 | |
15 | macro_rules! copy_yoke_impl { |
16 | () => { |
17 | #[inline] |
18 | fn transform(&self) -> &Self::Output { |
19 | self |
20 | } |
21 | #[inline] |
22 | fn transform_owned(self) -> Self::Output { |
23 | self |
24 | } |
25 | #[inline] |
26 | unsafe fn make(this: Self::Output) -> Self { |
27 | this |
28 | } |
29 | #[inline] |
30 | fn transform_mut<F>(&'a mut self, f: F) |
31 | where |
32 | F: 'static + for<'b> FnOnce(&'b mut Self::Output), |
33 | { |
34 | f(self) |
35 | } |
36 | }; |
37 | } |
38 | macro_rules! impl_copy_type { |
39 | ($ty:ty) => { |
40 | // Safety: all the types that this macro is used to generate impls of Yokeable for do not |
41 | // borrow any memory. |
42 | unsafe impl<'a> Yokeable<'a> for $ty { |
43 | type Output = Self; |
44 | copy_yoke_impl!(); |
45 | } |
46 | }; |
47 | } |
48 | |
49 | impl_copy_type!(()); |
50 | impl_copy_type!(u8); |
51 | impl_copy_type!(u16); |
52 | impl_copy_type!(u32); |
53 | impl_copy_type!(u64); |
54 | impl_copy_type!(u128); |
55 | impl_copy_type!(usize); |
56 | impl_copy_type!(i8); |
57 | impl_copy_type!(i16); |
58 | impl_copy_type!(i32); |
59 | impl_copy_type!(i64); |
60 | impl_copy_type!(i128); |
61 | impl_copy_type!(isize); |
62 | impl_copy_type!(char); |
63 | impl_copy_type!(bool); |
64 | |
65 | // This is for when we're implementing Yoke on a complex type such that it's not |
66 | // obvious to the compiler that the lifetime is covariant |
67 | // |
68 | // Safety: the caller of this macro must ensure that `Self` is indeed covariant in 'a. |
69 | macro_rules! unsafe_complex_yoke_impl { |
70 | () => { |
71 | fn transform(&'a self) -> &'a Self::Output { |
72 | // Safety: equivalent to casting the lifetime. Macro caller ensures covariance. |
73 | unsafe { mem::transmute(self) } |
74 | } |
75 | |
76 | fn transform_owned(self) -> Self::Output { |
77 | debug_assert!(mem::size_of::<Self::Output>() == mem::size_of::<Self>()); |
78 | // Safety: equivalent to casting the lifetime. Macro caller ensures covariance. |
79 | unsafe { |
80 | let ptr: *const Self::Output = (&self as *const Self).cast(); |
81 | let _ = ManuallyDrop::new(self); |
82 | ptr::read(ptr) |
83 | } |
84 | } |
85 | |
86 | unsafe fn make(from: Self::Output) -> Self { |
87 | debug_assert!(mem::size_of::<Self::Output>() == mem::size_of::<Self>()); |
88 | let ptr: *const Self = (&from as *const Self::Output).cast(); |
89 | let _ = ManuallyDrop::new(from); |
90 | // Safety: `ptr` is certainly valid, aligned and points to a properly initialized value, as |
91 | // it comes from a value that was moved into a ManuallyDrop. |
92 | unsafe { ptr::read(ptr) } |
93 | } |
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 | // Cast away the lifetime of Self |
100 | // Safety: this is equivalent to f(transmute(self)), and the documentation of the trait |
101 | // method explains why doing so is sound. |
102 | unsafe { f(mem::transmute::<&'a mut Self, &'a mut Self::Output>(self)) } |
103 | } |
104 | }; |
105 | } |
106 | |
107 | // Safety: since T implements Yokeable<'a>, Option<T<'b>> must be covariant on 'b or the Yokeable |
108 | // implementation on T would be unsound. |
109 | unsafe impl<'a, T: 'static + for<'b> dynYokeable<'b>> Yokeable<'a> for Option<T> { |
110 | type Output = Option<<T as Yokeable<'a>>::Output>; |
111 | unsafe_complex_yoke_impl!(); |
112 | } |
113 | |
114 | // Safety: since T1, T2 implement Yokeable<'a>, (T1<'b>, T2<'b>) must be covariant on 'b or the Yokeable |
115 | // implementation on T would be unsound. |
116 | unsafe impl<'a, T1: 'static + for<'b> dynYokeable<'b>, T2: 'static + for<'b> dynYokeable<'b>> Yokeable<'a> |
117 | for (T1, T2) |
118 | { |
119 | type Output = (<T1 as Yokeable<'a>>::Output, <T2 as Yokeable<'a>>::Output); |
120 | unsafe_complex_yoke_impl!(); |
121 | } |
122 | |
123 | // Safety: since T implements Yokeable<'a>, [T<'b>; N] must be covariant on 'b or the Yokeable |
124 | // implementation on T would be unsound. |
125 | unsafe impl<'a, T: 'static + for<'b> dynYokeable<'b>, const N: usize> Yokeable<'a> for [T; N] { |
126 | type Output = [<T as Yokeable<'a>>::Output; N]; |
127 | unsafe_complex_yoke_impl!(); |
128 | } |
129 | |