abi_stable/erased_types/
trait_objects.rs

1//! Ffi-safe trait objects for individual traits.
2
3use std::{
4    fmt::{self, Debug, Display},
5    marker::PhantomData,
6};
7
8#[allow(unused_imports)]
9use core_extensions::SelfOps;
10
11use super::{c_functions::*, *};
12
13use crate::{
14    marker_type::ErasedObject,
15    pointer_trait::{AsPtr, TransmuteElement},
16    sabi_types::{RMut, RRef},
17    std_types::RBox,
18};
19
20/////////////////////////////////////////////////////////////
21
22/// An ffi-safe equivalent of `&mut dyn std::hash::Hasher`.
23#[repr(C)]
24#[derive(StableAbi)]
25pub struct HasherObject<'a> {
26    this: RMut<'a, ErasedObject>,
27    write_fns: &'static WriteFns,
28    finish: unsafe extern "C" fn(RRef<'_, ErasedObject>) -> u64,
29}
30
31impl<'a> HasherObject<'a> {
32    /// Constructs a `HasherObject`.
33    pub fn new<T: 'a>(this: &'a mut T) -> HasherObject<'a>
34    where
35        T: Hasher,
36    {
37        HasherObject {
38            this: unsafe {
39                // The lifetime is tied to the input.
40                this.transmute_element::<ErasedObject>()
41            },
42            write_fns: MakeWriteFns::<T>::V,
43            finish: finish_Hasher::<T>,
44        }
45    }
46
47    /// Reborrows this `HasherObject` with a smaller lifetime.
48    pub fn as_mut<'b: 'a>(&'b mut self) -> HasherObject<'b> {
49        Self {
50            this: self.this.reborrow(),
51            write_fns: self.write_fns,
52            finish: self.finish,
53        }
54    }
55}
56
57macro_rules! impl_write {
58    ( $(($ty:ty, $fn:ident)),* ) => {
59        $(
60            fn $fn(&mut self, val: $ty) {
61                unsafe { (self.write_fns.$fn)(self.this.reborrow(), val) }
62            }
63        )*
64    }
65}
66
67impl<'a> Hasher for HasherObject<'a> {
68    fn finish(&self) -> u64 {
69        unsafe { (self.finish)(self.this.as_rref()) }
70    }
71    fn write(&mut self, bytes: &[u8]) {
72        unsafe { (self.write_fns.write)(self.this.reborrow(), bytes.into()) }
73    }
74
75    impl_write!(
76        (i16, write_i16),
77        (i32, write_i32),
78        (i64, write_i64),
79        (i8, write_i8),
80        (isize, write_isize),
81        (u16, write_u16),
82        (u32, write_u32),
83        (u64, write_u64),
84        (u8, write_u8),
85        (usize, write_usize)
86    );
87}
88
89/// The write variations for the hasher. Even if `write` is the only required
90/// function in the trait, the rest must also be explicitly implemented in the
91/// hasher object so that the original behaviour is maintained (since the
92/// default impls may have been overridden).
93///
94/// They are declared and constructed separately from the object for
95/// cleanliness.
96#[repr(C)]
97#[derive(StableAbi)]
98struct WriteFns {
99    write: unsafe extern "C" fn(RMut<'_, ErasedObject>, RSlice<'_, u8>),
100    // No c-compatible layout for i128 yet
101    // write_i128: unsafe extern "C" fn(RMut<'_, ErasedObject>, i128),
102    write_i16: unsafe extern "C" fn(RMut<'_, ErasedObject>, i16),
103    write_i32: unsafe extern "C" fn(RMut<'_, ErasedObject>, i32),
104    write_i64: unsafe extern "C" fn(RMut<'_, ErasedObject>, i64),
105    write_i8: unsafe extern "C" fn(RMut<'_, ErasedObject>, i8),
106    write_isize: unsafe extern "C" fn(RMut<'_, ErasedObject>, isize),
107    // No c-compatible layout for u128 yet
108    // write_u128: unsafe extern "C" fn(RMut<'_, ErasedObject>, u128),
109    write_u16: unsafe extern "C" fn(RMut<'_, ErasedObject>, u16),
110    write_u32: unsafe extern "C" fn(RMut<'_, ErasedObject>, u32),
111    write_u64: unsafe extern "C" fn(RMut<'_, ErasedObject>, u64),
112    write_u8: unsafe extern "C" fn(RMut<'_, ErasedObject>, u8),
113    write_usize: unsafe extern "C" fn(RMut<'_, ErasedObject>, usize),
114}
115
116struct MakeWriteFns<T>(PhantomData<T>);
117
118impl<T: Hasher> MakeWriteFns<T> {
119    const V: &'static WriteFns = &WriteFns {
120        write: write_Hasher::<T>,
121        write_i16: write_i16_Hasher::<T>,
122        write_i32: write_i32_Hasher::<T>,
123        write_i64: write_i64_Hasher::<T>,
124        write_i8: write_i8_Hasher::<T>,
125        write_isize: write_isize_Hasher::<T>,
126        write_u16: write_u16_Hasher::<T>,
127        write_u32: write_u32_Hasher::<T>,
128        write_u64: write_u64_Hasher::<T>,
129        write_u8: write_u8_Hasher::<T>,
130        write_usize: write_usize_Hasher::<T>,
131    };
132}
133
134//////////////
135
136/// An ffi-safe equivalent of `Box<dyn Debug + Display>`
137/// (if `dyn Debug + Display` was possible).
138#[repr(C)]
139#[derive(StableAbi)]
140pub struct DebugDisplayObject {
141    this: RBox<ErasedObject>,
142    display: unsafe extern "C" fn(
143        RRef<'_, ErasedObject>,
144        FormattingMode,
145        &mut RString,
146    ) -> RResult<(), ()>,
147    debug: unsafe extern "C" fn(
148        RRef<'_, ErasedObject>,
149        FormattingMode,
150        &mut RString,
151    ) -> RResult<(), ()>,
152}
153
154impl DebugDisplayObject {
155    /// Constructs this `DebugDisplayObject`.
156    pub fn new<T>(value: T) -> DebugDisplayObject
157    where
158        T: Display + Debug + 'static,
159    {
160        DebugDisplayObject {
161            this: unsafe {
162                // The lifetime here is 'static,so it's fine to erase the type.
163                RBox::new(value).transmute_element::<ErasedObject>()
164            },
165            display: display_impl::<T>,
166            debug: debug_impl::<T>,
167        }
168    }
169
170    /// Constructs a `DebugDisplayObject`.which doesn't output anything.
171    pub fn no_output() -> DebugDisplayObject {
172        Self::new(NoFmt)
173    }
174}
175
176impl Display for DebugDisplayObject {
177    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
178        unsafe { adapt_std_fmt::<ErasedObject>(self.this.as_rref(), self.display, f) }
179    }
180}
181
182impl Debug for DebugDisplayObject {
183    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
184        unsafe { adapt_std_fmt::<ErasedObject>(self.this.as_rref(), self.debug, f) }
185    }
186}
187
188struct NoFmt;
189
190impl Display for NoFmt {
191    fn fmt(&self, _: &mut fmt::Formatter<'_>) -> fmt::Result {
192        Ok(())
193    }
194}
195
196impl Debug for NoFmt {
197    fn fmt(&self, _: &mut fmt::Formatter<'_>) -> fmt::Result {
198        Ok(())
199    }
200}
201
202//////////////