Skip to main content

yoke/
macro_impls.rs

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