abi_stable/docs/
prefix_types.rs

1/*!
2
3Prefix-types are types that derive StableAbi along with the
4`#[sabi(kind(Prefix(....)))]` helper attribute.
5This is mostly intended for **vtables** and **modules**.
6
7Prefix-types cannot directly be passed through ffi,
8instead they must be converted to the type declared with `prefix_ref= Foo_Ref`,
9and then pass that instead.
10
11To convert `Foo` to `Foo_Ref` you can use any of (non-exhaustive list):
12
13- `PrefixTypeTrait::leak_into_prefix`:<br>
14    Which does the conversion directly,but leaks the value.
15
16- `prefix_type::WithMetadata::new`:<br>
17    Use this if you need a compiletime constant.<br>
18    First create a `StaticRef<WithMetadata<Self>>` constant using
19    the [`staticref`] macro,
20    then construct a `Foo_Ref` constant with `Foo_Ref(THE_STATICREF_CONSTANT.as_prefix())`.<br>
21    There are two examples of this,
22    [for modules](#module_construction),and [for vtables](#vtable_construction)
23
24
25All the fields in the `DerivingType` can be accessed in `DerivingType_Ref` using
26accessor methods named the same as the fields.
27
28# Version compatibility
29
30### Adding fields
31
32To ensure that libraries stay abi compatible,
33the first minor version of the library must use the `#[sabi(last_prefix_field)]` attribute on some
34field, and every minor version after that must add fields at the end (never moving that attribute).
35Changing the field that `#[sabi(last_prefix_field)]` is applied to is a breaking change.
36
37Getter methods for fields after the one to which `#[sabi(last_prefix_field)]` was applied to
38will return `Option<FieldType>` by default,because those fields might not exist
39(the struct might come from a previous version of the library).
40To override how to deal with nonexistent fields,
41use the `#[sabi(missing_field())]` attribute,
42applied to either the struct or the field.
43
44### Alignment
45
46To ensure that users can define empty vtables/modules that can be extended in
47semver compatible versions,
48this library forces the struct converted to ffi-safe form to have an alignment at
49least that of usize.
50
51You must ensure that newer versions don't change the alignment of the struct,
52because that makes it ABI incompatible.
53
54# Grammar Reference
55
56For the grammar reference,you can look at the documentation for
57[`#[derive(StableAbi)]`](../../derive.StableAbi.html).
58
59# Examples
60
61###  Example 1
62
63Declaring a Prefix-type.
64
65```
66
67use abi_stable::{
68    std_types::{RDuration, RStr},
69    StableAbi,
70};
71
72#[repr(C)]
73#[derive(StableAbi)]
74#[sabi(kind(Prefix(prefix_ref = Module_Ref)))]
75#[sabi(missing_field(panic))]
76pub struct Module {
77    pub lib_name: RStr<'static>,
78
79    #[sabi(last_prefix_field)]
80    pub elapsed: extern "C" fn() -> RDuration,
81
82    pub description: RStr<'static>,
83}
84
85# fn main(){}
86
87
88```
89
90In this example:
91
92- `#[sabi(kind(Prefix(prefix_ref= Module_Ref)))]` declares this type as being a prefix-type
93    with an ffi-safe pointer called `Module_Ref` to which `Module` can be converted into.
94
95- `#[sabi(missing_field(panic))]`
96    makes the field accessors panic when attempting to
97    access nonexistent fields instead of the default of returning an `Option<FieldType>`.
98
99- `#[sabi(last_prefix_field)]`means that it is the last field in the struct
100    that was defined in the first compatible version of the library
101    (0.1.0, 0.2.0, 0.3.0, 1.0.0, 2.0.0 ,etc),
102    requiring new fields to always be added below preexisting ones.
103
104<span id="module_construction"></span>
105### Constructing a module
106
107This example demonstrates how you can construct a module.
108
109For constructing a vtable, you can look at [the next example](#vtable_construction)
110
111```
112
113use abi_stable::{
114    extern_fn_panic_handling,
115    prefix_type::{PrefixTypeTrait, WithMetadata},
116    staticref,
117    std_types::{RDuration, RStr},
118    StableAbi,
119};
120
121fn main() {
122    assert_eq!(MODULE_REF.lib_name().as_str(), "foo");
123
124    assert_eq!(MODULE_REF.elapsed()(1000), RDuration::from_secs(1));
125
126    assert_eq!(MODULE_REF.description().as_str(), "this is a module field");
127}
128
129#[repr(C)]
130#[derive(StableAbi)]
131#[sabi(kind(Prefix(prefix_ref = Module_Ref)))]
132#[sabi(missing_field(panic))]
133pub struct Module<T> {
134    pub lib_name: RStr<'static>,
135
136    #[sabi(last_prefix_field)]
137    pub elapsed: extern "C" fn(T) -> RDuration,
138
139    pub description: RStr<'static>,
140}
141
142impl Module<u64> {
143    // This macro declares a `StaticRef<WithMetadata<Module<u64>>>` constant.
144    staticref!(const MODULE_VAL: WithMetadata<Module<u64>> = WithMetadata::new(
145        Module{
146            lib_name: RStr::from_str("foo"),
147            elapsed,
148            description: RStr::from_str("this is a module field"),
149        },
150    ));
151}
152
153const MODULE_REF: Module_Ref<u64> = Module_Ref(Module::MODULE_VAL.as_prefix());
154
155extern "C" fn elapsed(milliseconds: u64) -> RDuration {
156    extern_fn_panic_handling! {
157        RDuration::from_millis(milliseconds)
158    }
159}
160
161```
162
163<span id="vtable_construction"></span>
164### Constructing a vtable
165
166This example demonstrates how you can construct a vtable.
167
168```rust
169use abi_stable::{
170    extern_fn_panic_handling,
171    marker_type::ErasedObject,
172    prefix_type::{PrefixTypeTrait, WithMetadata},
173    staticref, StableAbi,
174};
175
176fn main() {
177    unsafe {
178        let vtable = MakeVTable::<u64>::MAKE;
179        assert_eq!(
180            vtable.get_number()(&3u64 as *const u64 as *const ErasedObject),
181            12,
182        );
183    }
184    unsafe {
185        let vtable = MakeVTable::<u8>::MAKE;
186        assert_eq!(
187            vtable.get_number()(&128u8 as *const u8 as *const ErasedObject),
188            512,
189        );
190    }
191}
192
193#[repr(C)]
194#[derive(StableAbi)]
195#[sabi(kind(Prefix(prefix_ref = VTable_Ref)))]
196#[sabi(missing_field(panic))]
197pub struct VTable {
198    #[sabi(last_prefix_field)]
199    pub get_number: unsafe extern "C" fn(*const ErasedObject) -> u64,
200}
201
202// A dummy struct, used purely for its associated constants.
203struct MakeVTable<T>(T);
204
205impl<T> MakeVTable<T>
206where
207    T: Copy + Into<u64>,
208{
209    unsafe extern "C" fn get_number(this: *const ErasedObject) -> u64 {
210        extern_fn_panic_handling! {
211            (*this.cast::<T>()).into() * 4
212        }
213    }
214
215    // This macro declares a `StaticRef<WithMetadata<VTable>>` constant.
216    staticref! {pub const VAL: WithMetadata<VTable> = WithMetadata::new(
217        VTable{get_number: Self::get_number},
218    )}
219
220    pub const MAKE: VTable_Ref = VTable_Ref(Self::VAL.as_prefix());
221}
222
223```
224
225
226<span id="example2"></span>
227###  Example 2:Declaring a type with a VTable
228
229Here is the implementation of a Box-like type,which uses a vtable that is a prefix type.
230
231```
232
233use std::{
234    marker::PhantomData,
235    mem::ManuallyDrop,
236    ops::{Deref, DerefMut},
237};
238
239use abi_stable::{
240    extern_fn_panic_handling,
241    pointer_trait::{CallReferentDrop, TransmuteElement},
242    prefix_type::{PrefixTypeTrait, WithMetadata},
243    staticref, StableAbi,
244};
245
246/// An ffi-safe `Box<T>`
247#[repr(C)]
248#[derive(StableAbi)]
249pub struct BoxLike<T> {
250    data: *mut T,
251
252    vtable: BoxVtable_Ref<T>,
253
254    _marker: PhantomData<T>,
255}
256
257impl<T> BoxLike<T> {
258    pub fn new(value: T) -> Self {
259        let box_ = Box::new(value);
260
261        Self {
262            data: Box::into_raw(box_),
263            vtable: BoxVtable::VTABLE,
264            _marker: PhantomData,
265        }
266    }
267
268    fn vtable(&self) -> BoxVtable_Ref<T> {
269        self.vtable
270    }
271
272    /// Extracts the value this owns.
273    pub fn into_inner(self) -> T {
274        let this = ManuallyDrop::new(self);
275        let vtable = this.vtable();
276        unsafe {
277            // Must copy this before calling `vtable.destructor()`
278            // because otherwise it would be reading from a dangling pointer.
279            let ret = this.data.read();
280            vtable.destructor()(this.data, CallReferentDrop::No);
281            ret
282        }
283    }
284}
285
286impl<T> Deref for BoxLike<T> {
287    type Target = T;
288
289    fn deref(&self) -> &T {
290        unsafe { &(*self.data) }
291    }
292}
293
294impl<T> DerefMut for BoxLike<T> {
295    fn deref_mut(&mut self) -> &mut T {
296        unsafe { &mut (*self.data) }
297    }
298}
299
300impl<T> Drop for BoxLike<T> {
301    fn drop(&mut self) {
302        let vtable = self.vtable();
303
304        unsafe { vtable.destructor()(self.data, CallReferentDrop::Yes) }
305    }
306}
307
308// `#[sabi(kind(Prefix))]` Declares this type as being a prefix-type,
309// generating both of these types:
310//
311//     - BoxVTable_Prefix`: A struct with the fields up to (and including) the field with the
312//     `#[sabi(last_prefix_field)]` attribute.
313//
314//     - BoxVTable_Ref`: An ffi-safe pointer to a `BoxVtable`, with methods to get
315//     `BoxVtable`'s fields.
316//
317#[repr(C)]
318#[derive(StableAbi)]
319#[sabi(kind(Prefix))]
320pub(crate) struct BoxVtable<T> {
321    /// The `#[sabi(last_prefix_field)]` attribute here means that this is
322    /// the last field in this struct that was defined in the
323    /// first compatible version of the library
324    /// (0.1.0, 0.2.0, 0.3.0, 1.0.0, 2.0.0 ,etc),
325    /// requiring new fields to always be added after it.
326    ///
327    /// The `#[sabi(last_prefix_field)]` attribute would stay on this field until the library
328    /// bumps its "major" version,
329    /// at which point it would be moved to the last field at the time.
330    ///
331    #[sabi(last_prefix_field)]
332    destructor: unsafe extern "C" fn(*mut T, CallReferentDrop),
333}
334
335// This is how ffi-safe pointers to generic prefix types are constructed
336// at compile-time.
337impl<T> BoxVtable<T> {
338    // This macro declares a `StaticRef<WithMetadata<BoxVtable<T>>>` constant.
339    //
340    // StaticRef represents a reference to data that lives forever,
341    // but is not necessarily `'static` according to the type system,
342    // eg: `BoxVtable<T>`.
343    staticref!(const VTABLE_VAL: WithMetadata<Self> = WithMetadata::new(
344        Self{
345            destructor:destroy_box::<T>,
346        },
347    ));
348
349    const VTABLE: BoxVtable_Ref<T> =
350        { BoxVtable_Ref(Self::VTABLE_VAL.as_prefix()) };
351}
352
353unsafe extern "C" fn destroy_box<T>(v: *mut T, call_drop: CallReferentDrop) {
354    extern_fn_panic_handling! {
355        let mut box_ = Box::from_raw(v as *mut ManuallyDrop<T>);
356        if call_drop == CallReferentDrop::Yes {
357            ManuallyDrop::drop(&mut *box_);
358        }
359        drop(box_);
360    }
361}
362
363# fn main(){}
364
365```
366
367
368###  Example 3:module
369
370This declares,initializes,and uses a module.
371
372```
373use abi_stable::{
374    prefix_type::{PrefixTypeTrait, WithMetadata},
375    sabi_extern_fn,
376    std_types::RDuration,
377    StableAbi,
378};
379
380// `#[sabi(kind(Prefix))]` Declares this type as being a prefix-type,
381// generating both of these types:
382//
383//     - PersonMod_Prefix`: A struct with the fields up to (and including) the field with the
384//     `#[sabi(last_prefix_field)]` attribute.
385//
386//     - PersonMod_Ref`:
387//      An ffi-safe pointer to a `PersonMod`,with methods to get`PersonMod`'s fields.
388//
389#[repr(C)]
390#[derive(StableAbi)]
391#[sabi(kind(Prefix))]
392pub struct PersonMod {
393    /// The `#[sabi(last_prefix_field)]` attribute here means that this is
394    /// the last field in this struct that was defined in the
395    /// first compatible version of the library
396    /// (0.1.0, 0.2.0, 0.3.0, 1.0.0, 2.0.0 ,etc),
397    /// requiring new fields to always be added below preexisting ones.
398    ///
399    /// The `#[sabi(last_prefix_field)]` attribute would stay on this field until the library
400    /// bumps its "major" version,
401    /// at which point it would be moved to the last field at the time.
402    ///
403    #[sabi(last_prefix_field)]
404    pub customer_for: extern "C" fn(Id) -> RDuration,
405
406    // The default behavior for the getter is to return an Option<FieldType>,
407    // if the field exists it returns Some(_),
408    // otherwise it returns None.
409    pub bike_count: extern "C" fn(Id) -> u32,
410
411    // The getter for this field panics if the field doesn't exist.
412    #[sabi(missing_field(panic))]
413    pub visits: extern "C" fn(Id) -> u32,
414
415    // The getter for this field returns `default_score()` if the field doesn't exist.
416    #[sabi(missing_field(with = default_score))]
417    pub score: extern "C" fn(Id) -> u32,
418
419    // The getter for this field returns `Default::default()` if the field doesn't exist.
420    #[sabi(missing_field(default))]
421    pub visit_length: Option<extern "C" fn(Id) -> RDuration>,
422}
423
424fn default_score() -> extern "C" fn(Id) -> u32 {
425    extern "C" fn default(_: Id) -> u32 {
426        1000
427    }
428
429    default
430}
431
432type Id = u32;
433
434#   static VARS:&[(RDuration,u32)]=&[
435#       (RDuration::new(1_000,0),10),
436#       (RDuration::new(1_000_000,0),1),
437#   ];
438
439#   #[sabi_extern_fn]
440#   fn customer_for(id:Id)->RDuration{
441#       VARS[id as usize].0
442#   }
443
444#   #[sabi_extern_fn]
445#   fn bike_count(id:Id)->u32{
446#       VARS[id as usize].1
447#   }
448
449#   #[sabi_extern_fn]
450#   fn visits(id:Id)->u32{
451#       VARS[id as usize].1
452#   }
453
454#   #[sabi_extern_fn]
455#   fn score(id:Id)->u32{
456#       VARS[id as usize].1
457#   }
458
459/*
460    ...
461    Elided function definitions
462    ...
463*/
464
465# fn main(){
466
467const _MODULE_WM_: &WithMetadata<PersonMod> = &WithMetadata::new(
468    PersonMod {
469        customer_for,
470        bike_count,
471        visits,
472        score,
473        visit_length: None,
474    },
475);
476
477const MODULE: PersonMod_Ref = PersonMod_Ref(_MODULE_WM_.static_as_prefix());
478
479// Getting the value for every field of `MODULE`.
480
481let customer_for: extern "C" fn(Id) -> RDuration = MODULE.customer_for();
482
483let bike_count: Option<extern "C" fn(Id) -> u32> = MODULE.bike_count();
484
485let visits: extern "C" fn(Id) -> u32 = MODULE.visits();
486
487let score: extern "C" fn(Id) -> u32 = MODULE.score();
488
489let visit_length: Option<extern "C" fn(Id) -> RDuration> = MODULE.visit_length();
490
491# }
492
493
494```
495
496
497
498
499
500
501
502
503
504[`staticref`]: ../../macro.staticref.html
505
506
507
508*/