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*/