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}