abi_stable/
prefix_type.rs

1//! Types,traits,and functions used by prefix-types.
2
3use std::marker::PhantomData;
4
5use crate::{
6    inline_storage::alignment::AlignToUsize, marker_type::NotCopyNotClone,
7    pointer_trait::ImmutableRef, sabi_types::StaticRef, utils::Transmuter,
8};
9
10#[allow(unused_imports)]
11use core_extensions::SelfOps;
12
13use repr_offset::offset_calc::next_field_offset;
14
15mod accessible_fields;
16mod layout;
17mod prefix_ref;
18mod pt_metadata;
19
20#[cfg(test)]
21mod tests;
22
23pub use self::{
24    accessible_fields::{FieldAccessibility, FieldConditionality, IsAccessible, IsConditional},
25    layout::PTStructLayout,
26    prefix_ref::PrefixRef,
27};
28
29#[doc(hidden)]
30pub use self::pt_metadata::__PrefixTypeMetadata;
31
32/// For types deriving `StableAbi` with
33/// [`#[sabi(kind(Prefix(..)))]`](derive@crate::StableAbi#sabi_kind_prefix_attr).
34///
35/// # Safety
36///
37/// This trait must be implemented by the `StableAbi` derive macro.
38pub unsafe trait PrefixTypeTrait: Sized {
39    /// Describes the layout of the struct,exclusively for use in error messages.
40    const PT_LAYOUT: &'static PTStructLayout;
41
42    /// A bit array,where each nth bit represents whether the nth field is accessible.
43    const PT_FIELD_ACCESSIBILITY: FieldAccessibility;
44
45    /// Converts `Self` to `Self::PrefixRef`,leaking it in the process.
46    ///
47    /// # Warning
48    ///
49    /// You must be careful when calling this function,
50    /// since this leak is ignored by [miri](https://github.com/rust-lang/miri) .
51    ///
52    fn leak_into_prefix(self) -> Self::PrefixRef {
53        let x = WithMetadata::new(self);
54        let x = StaticRef::leak_value(x);
55        let x = PrefixRef::from_staticref(x);
56        <Self::PrefixRef as PrefixRefTrait>::from_prefix_ref(x)
57    }
58
59    /// A struct that contains all the fields up to the field annotated with
60    /// `#[sabi(last_prefix_field)]` inclusive.
61    ///
62    /// Those structs are usually named with a `_Prefix` suffix.
63    type PrefixFields;
64
65    /// A pointer to `Self::PrefixFields`,
66    /// generally wraps a `PrefixRef<Self::PrefixFields>`.
67    ///
68    /// Those pointer types are usually named with a `_Ref` suffix.
69    type PrefixRef: PrefixRefTrait<
70        PtrTarget = WithMetadata_<Self::PrefixFields, Self::PrefixFields>,
71        PrefixFields = Self::PrefixFields,
72    >;
73}
74
75////////////////////////////////////////////////////////////////////////////////
76
77/// Marker trait for pointers to prefix field structs.
78///
79/// Generally prefix field structs are named with a `_Prefix` suffix,
80/// and have all the fields of some other struct up to the
81/// one with a `#[sabi(last_prefix_field)]` attribute.
82///
83/// # Safety
84///
85/// `Self` must either be `PrefixRef<Self::PrefixFields>`,
86/// or a `#[repr(transparent)]` wrapper around one.
87pub unsafe trait PrefixRefTrait:
88    Sized + ImmutableRef<PtrTarget = WithMetadata_<Self::PrefixFields, Self::PrefixFields>>
89{
90    /// A struct that contains all the fields of some other struct
91    /// up to the field annotated with
92    /// `#[sabi(last_prefix_field)]` inclusive.
93    ///
94    /// Those structs are usually named with a `_Prefix` suffix.
95    // The `GetWithMetadata<ForSelf = Self::Target>` bound
96    // is a hacky way to encode this type equality bound:
97    // `Self::Target == WithMetadata_<Self::PrefixFields, Self::PrefixFields>`
98    // (except that the compiler doesn't unify both types)
99    type PrefixFields;
100
101    /// Converts a `PrefixRef` to `Self`
102    #[inline]
103    fn from_prefix_ref(this: PrefixRef<Self::PrefixFields>) -> Self {
104        unsafe { Transmuter { from: this }.to }
105    }
106
107    /// Converts `Self` to a `PrefixRef`
108    #[inline]
109    fn to_prefix_ref(self) -> PrefixRef<Self::PrefixFields> {
110        unsafe { Transmuter { from: self }.to }
111    }
112}
113
114////////////////////////////////////////////////////////////////////////////////
115
116/// Alias for [`WithMetadata_`]
117/// that defaults to passing `<T as PrefixTypeTrait>::PrefixFields`
118/// as the second type parameter.
119///
120/// [`WithMetadata_`] can't have that defaulted type parameter,
121/// because `T: `[`PrefixTypeTrait`] is an overly restrictive bound in some cases.
122///
123///
124/// [`WithMetadata_`]: ./struct.WithMetadata_.html
125pub type WithMetadata<T, P = <T as PrefixTypeTrait>::PrefixFields> = WithMetadata_<T, P>;
126
127/// Wraps a type along with its prefix-type-related metadata,
128/// so that it can be converted to its prefix.
129///
130/// # Example
131///
132/// This example demonstrates how you can construct a `WithMetadata` and
133/// convert it to a prefix type pointer (`Module_Ref` in this case).
134///
135/// You can look at the [`PrefixRef` docs](./struct.PrefixRef.html#example) for
136/// a more detailed example.
137///
138/// ```rust
139/// use abi_stable::{
140///     for_examples::{Module, Module_Ref},
141///     prefix_type::{PrefixRef, PrefixTypeTrait, WithMetadata},
142///     std_types::{RSome, RStr},
143///     staticref,
144/// };
145///
146/// const WITH_META: &WithMetadata<Module> = &WithMetadata::new(
147///     Module {
148///         first: RSome(66),
149///         second: RStr::from_str("lore"),
150///         third: 333,
151///     },
152/// );
153///
154/// const MOD: Module_Ref = Module_Ref(WITH_META.static_as_prefix());
155///
156/// assert_eq!(MOD.first(), RSome(66));
157/// assert_eq!(MOD.second().as_str(), "lore");
158///
159/// ```
160///
161#[repr(C)]
162pub struct WithMetadata_<T, P> {
163    // __VALUE_OFFSET must be updated if fields are added before `value`
164    field_accessibility: FieldAccessibility,
165    type_layout: &'static PTStructLayout,
166
167    /// The wrapped value.
168    pub value: AlignToUsize<T>,
169    unbounds: NotCopyNotClone,
170    _prefix: PhantomData<P>,
171}
172
173#[doc(hidden)]
174impl<T, P> WithMetadata_<T, P> {
175    // The offset of the `value` field
176    pub const __VALUE_OFFSET: usize = {
177        let tl_offset = next_field_offset::<Self, FieldAccessibility, &'static PTStructLayout>(0);
178
179        next_field_offset::<Self, &'static PTStructLayout, AlignToUsize<T>>(tl_offset)
180    };
181}
182
183impl<T, P> WithMetadata_<T, P> {
184    /// Constructs this with `WithMetadata::new(value)`
185    #[inline]
186    pub const fn new(value: T) -> Self
187    where
188        T: PrefixTypeTrait<PrefixFields = P>,
189    {
190        Self {
191            field_accessibility: T::PT_FIELD_ACCESSIBILITY,
192            type_layout: T::PT_LAYOUT,
193            value: AlignToUsize(value),
194            unbounds: NotCopyNotClone,
195            _prefix: PhantomData,
196        }
197    }
198
199    /// A bit array that describes the accessibility of each field in `T`.
200    #[inline]
201    pub const fn field_accessibility(&self) -> FieldAccessibility {
202        self.field_accessibility
203    }
204
205    /// The basic layout of the prefix type, for error messages.
206    #[inline]
207    pub const fn type_layout(&self) -> &'static PTStructLayout {
208        self.type_layout
209    }
210
211    /// Constructs a `PrefixRef` from `this`.
212    ///
213    /// # Safety
214    ///
215    /// You must enture that this `WithMetadata` lives for the entire program's lifetime.
216    #[inline]
217    pub const unsafe fn raw_as_prefix(this: *const Self) -> PrefixRef<P> {
218        unsafe { PrefixRef::from_raw(this) }
219    }
220
221    /// Constructs a `PrefixRef` from `self`.
222    ///
223    /// # Safety
224    ///
225    /// You must ensure that `self` lives for the entire program's lifetime.
226    ///
227    /// # Alternative
228    ///
229    /// For a safe equivalent of this, you can use [`StaticRef::as_prefix`].
230    ///
231    /// [`StaticRef::as_prefix`]: ../sabi_types/struct.StaticRef.html#method.as_prefix
232    #[inline]
233    pub const unsafe fn as_prefix(&self) -> PrefixRef<P> {
234        unsafe { PrefixRef::from_raw(self) }
235    }
236
237    /// Constructs a `PrefixRef` from `self`.
238    ///
239    /// # Example
240    ///
241    /// ```rust
242    /// use abi_stable::{
243    ///     for_examples::{Module, Module_Ref},
244    ///     prefix_type::{PrefixRef, PrefixTypeTrait, WithMetadata},
245    ///     std_types::{RSome, RStr},
246    /// };
247    ///
248    /// const WITH_META: &WithMetadata<Module> = &WithMetadata::new(
249    ///     Module {
250    ///         first: RSome(13),
251    ///         second: RStr::from_str("foo"),
252    ///         third: 100,
253    ///     },
254    /// );
255    ///
256    /// const MOD: Module_Ref = Module_Ref(WITH_META.static_as_prefix());
257    ///
258    /// assert_eq!(MOD.first(), RSome(13));
259    /// assert_eq!(MOD.second().as_str(), "foo");
260    ///
261    /// ```
262    #[inline]
263    pub const fn static_as_prefix(&'static self) -> PrefixRef<P> {
264        PrefixRef::from_ref(self)
265    }
266}
267
268impl<T, P> StaticRef<WithMetadata_<T, P>> {
269    /// Constructs a `PrefixRef<P>` from self.
270    ///
271    /// This is most useful when you have a generic type that isn't `'static`
272    /// for type system reasons, but lives for the entire program.
273    ///
274    /// # Example
275    ///
276    /// ```rust
277    /// use abi_stable::{
278    ///     for_examples::{PhantModule, PhantModule_Ref},
279    ///     prefix_type::{PrefixRef, PrefixTypeTrait, WithMetadata},
280    ///     std_types::{RNone, RStr},
281    ///     staticref,
282    /// };
283    ///
284    /// struct Foo<T>(T);
285    ///
286    /// impl<T: Copy> Foo<T> {
287    ///     // The `staticref` invocation here declares a
288    ///     // `StaticRef<WithMetadata<PhantModule<T>>>` constant.
289    ///     staticref!(const WITH_META: WithMetadata<PhantModule<T>> = WithMetadata::new(
290    ///         PhantModule {
291    ///             first: RNone,
292    ///             second: RStr::from_str("hello"),
293    ///             third: 100,
294    ///             phantom: std::marker::PhantomData,
295    ///         },
296    ///     ));
297    /// }
298    ///
299    /// const MOD: PhantModule_Ref<()> = PhantModule_Ref(Foo::WITH_META.as_prefix());
300    ///
301    /// assert_eq!(MOD.first(), RNone);
302    /// assert_eq!(MOD.second().as_str(), "hello");
303    ///
304    /// ```
305    pub const fn as_prefix(self) -> PrefixRef<P> {
306        PrefixRef::from_staticref(self)
307    }
308}
309
310////////////////////////////////////////////////////////////////////////////////
311
312/// Used to panic with an error message informing the user that a field
313/// is expected to be on the `T` type when it's not.
314#[cold]
315#[inline(never)]
316pub fn panic_on_missing_field_ty<T>(field_index: usize, actual_layout: &'static PTStructLayout) -> !
317where
318    T: PrefixTypeTrait,
319{
320    #[inline(never)]
321    fn inner(
322        field_index: usize,
323        expected_layout: &'static PTStructLayout,
324        actual_layout: &'static PTStructLayout,
325    ) -> ! {
326        let field = expected_layout
327            .get_field_name(field_index)
328            .unwrap_or("<unavailable>");
329        panic_on_missing_field_val(field_index, field, expected_layout, actual_layout)
330    }
331
332    inner(field_index, T::PT_LAYOUT, actual_layout)
333}
334
335/// Used to panic with an error message informing the user that a field
336/// is expected to be on the `T` type when it's not.
337#[cold]
338#[inline(never)]
339pub fn panic_on_missing_fieldname<T>(field_index: u8, actual_layout: &'static PTStructLayout) -> !
340where
341    T: PrefixTypeTrait,
342{
343    #[inline(never)]
344    fn inner(
345        field_index: usize,
346        expected_layout: &'static PTStructLayout,
347        actual_layout: &'static PTStructLayout,
348    ) -> ! {
349        let fieldname = expected_layout
350            .get_field_name(field_index)
351            .unwrap_or("<unavaiable>");
352        panic_on_missing_field_val(field_index, fieldname, expected_layout, actual_layout)
353    }
354
355    inner(field_index as usize, T::PT_LAYOUT, actual_layout)
356}
357
358/// Used to panic with an error message informing the user that a field
359/// is expected to be on `expected` when it's not.
360#[inline(never)]
361fn panic_on_missing_field_val(
362    field_index: usize,
363    field_name: &'static str,
364    expected: &'static PTStructLayout,
365    actual: &'static PTStructLayout,
366) -> ! {
367    panic!(
368        "\n
369Attempting to access nonexistent field:
370    index:{index} 
371    named:{field_named}
372
373Inside of:{struct_name}{struct_generics}
374
375Package:'{package}' 
376
377Expected:
378    Version:{expected_package_version} (or compatible version number)
379    Field count:{expected_field_count}
380
381Found:
382    Version:{actual_package_version}
383    Field count:{actual_field_count}
384
385\n",
386        index = field_index,
387        field_named = field_name,
388        struct_name = expected.mono_layout.name(),
389        struct_generics = expected.generics.as_str(),
390        package = expected.mono_layout.item_info().package(),
391        expected_package_version = expected.mono_layout.item_info().version(),
392        expected_field_count = expected.get_field_names().count(),
393        actual_package_version = actual.mono_layout.item_info().version(),
394        actual_field_count = actual.get_field_names().count(),
395    );
396}