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 ).
45// In this case consistency between impls is more important
6// than using pointer casts
7#![allow(clippy::transmute_ptr_to_ptr)]
89use crate::Yokeable;
10use core::{
11 mem::{self, ManuallyDrop},
12 ptr,
13};
1415macro_rules! copy_yoke_impl {
16 () => {
17#[inline]
18fn transform(&self) -> &Self::Output {
19self
20}
21#[inline]
22fn transform_owned(self) -> Self::Output {
23self
24}
25#[inline]
26unsafe fn make(this: Self::Output) -> Self {
27 this
28 }
29#[inline]
30fn transform_mut<F>(&'a mut self, f: F)
31where
32F: 'static + for<'b> FnOnce(&'b mut Self::Output),
33 {
34 f(self)
35 }
36 };
37}
38macro_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.
42unsafe impl<'a> Yokeable<'a> for $ty {
43type Output = Self;
44copy_yoke_impl!();
45 }
46 };
47}
4849impl_copy_type!(());
50impl_copy_type!(u8);
51impl_copy_type!(u16);
52impl_copy_type!(u32);
53impl_copy_type!(u64);
54impl_copy_type!(u128);
55impl_copy_type!(usize);
56impl_copy_type!(i8);
57impl_copy_type!(i16);
58impl_copy_type!(i32);
59impl_copy_type!(i64);
60impl_copy_type!(i128);
61impl_copy_type!(isize);
62impl_copy_type!(char);
63impl_copy_type!(bool);
6465// 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.
69macro_rules! unsafe_complex_yoke_impl {
70 () => {
71fn transform(&'a self) -> &'a Self::Output {
72// Safety: equivalent to casting the lifetime. Macro caller ensures covariance.
73unsafe { mem::transmute(self) }
74 }
7576fn transform_owned(self) -> Self::Output {
77debug_assert!(mem::size_of::<Self::Output>() == mem::size_of::<Self>());
78// Safety: equivalent to casting the lifetime. Macro caller ensures covariance.
79unsafe {
80let ptr: *const Self::Output = (&self as *const Self).cast();
81let _ = ManuallyDrop::new(self);
82 ptr::read(ptr)
83 }
84 }
8586unsafe fn make(from: Self::Output) -> Self {
87debug_assert!(mem::size_of::<Self::Output>() == mem::size_of::<Self>());
88let ptr: *const Self = (&from as *const Self::Output).cast();
89let _ = 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.
92unsafe { ptr::read(ptr) }
93 }
9495fn transform_mut<F>(&'a mut self, f: F)
96where
97F: '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.
102unsafe { f(mem::transmute::<&'a mut Self, &'a mut Self::Output>(self)) }
103 }
104 };
105}
106107// Safety: since T implements Yokeable<'a>, Option<T<'b>> must be covariant on 'b or the Yokeable
108// implementation on T would be unsound.
109unsafe impl<'a, T: 'static + for<'b> Yokeable<'b>> Yokeable<'a> for Option<T> {
110type Output = Option<<T as Yokeable<'a>>::Output>;
111unsafe_complex_yoke_impl!();
112}
113114// 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.
116unsafe impl<'a, T1: 'static + for<'b> Yokeable<'b>, T2: 'static + for<'b> Yokeable<'b>> Yokeable<'a>
117for (T1, T2)
118{
119type Output = (<T1 as Yokeable<'a>>::Output, <T2 as Yokeable<'a>>::Output);
120unsafe_complex_yoke_impl!();
121}
122123// Safety: since T implements Yokeable<'a>, [T<'b>; N] must be covariant on 'b or the Yokeable
124// implementation on T would be unsound.
125unsafe impl<'a, T: 'static + for<'b> Yokeable<'b>, const N: usize> Yokeable<'a> for [T; N] {
126type Output = [<T as Yokeable<'a>>::Output; N];
127unsafe_complex_yoke_impl!();
128}