abi_stable/proc_macro_reexports/sabi_trait_attribute.rs
1/**
2
3This attribute generates an ffi-safe trait object on the trait it's applied to.
4
5All items outside the list of generated items comes from [`abi_stable::sabi_trait`].
6
7
8# Supertraits.
9
10By default these are the supertraits that `#[sabi_trait]` traits can have:
11
12- lifetimes: It can be a lifetime declared by the trait, or `'static`.
13
14- `Debug`
15
16- `Display`
17
18- `std::error::Error`: Written as `Error`: The `Error` methods aren't delegated to,
19it uses the default implementation,
20
21- `Clone`
22
23- `Send`
24
25- `Sync`
26
27- `Unpin`
28
29To be able to have more supertraits you must use the `#[sabi(use_dyntrait)]` helper attribute,
30which changes the underlying implementation from [`RObject`] to [`DynTrait`],
31allowing these supertraits:
32
33- `Iterator`: requires the Item type to be specified.
34
35- `DoubleEndedIterator`: requires the Item type to be specified.
36
37- `std::fmt::Write`: Written as `FmtWrite`
38
39- `std::io::Write`: Written as `IoWrite`
40
41- `std::io::Seek`: Written as `IoSeek`
42
43- `std::io::Read`: Written as `IoRead`
44
45- `std::io::BufRead`: Written as `IoBufRead`
46
47- `Eq`
48
49- `PartialEq`
50
51- `Ord`
52
53- `PartialOrd`
54
55- `Hash`
56
57
58
59### Supertrait Extensibility
60
61The properties described below are checked when `abi_stable` loads a dynamic library.
62
63Traits can add non-marker supertraits in minor versions without breaking ABI compatibility,
64with the (non-ABI related) caveats described in the extensibility section.
65
66Traits cannot add marker supertraits in minor versions ABI compatibly,
67because that would cause problems with thread/memory safety if allowed.
68If it were allowed,`!Send` trait objects could be passed from a binary to
69a dynamic library(where the trait object type is `Send`),
70and that would be Undefined Behavior in many situations.
71
72# Extensibility
73
74`#[sabi_trait]` trait objects are (ABI-wise) safe to extend in minor versions,
75so long as methods are always added at the end, preferably as default methods.
76
77A library will not load (through safe means) if methods are added anywhere but the end.
78
79Accidentally calling newer methods on trait objects from older versions of a
80library will cause a panic at runtime, unless it has a default implementation
81(within the trait definition that `#[sabi_trait]` can see).
82
83Panics can only happen if one loads multiple versions of a library,
84where the trait is extended in each version(without using default methods),
85and passes trait objects among those libraries.
86
87# Generated items.
88
89This is a nonexhaustive list of the items generated by the attribute,
90where `Trait` is the name of the annotated trait.
91
92### `Trait_trait`
93
94This is the module inside of which all the items are generated.
95
96These are the items reexported from the module:
97
98- [`Trait`](#trait): The trait itself.
99
100- [`Trait_TO`](#trait_to): The trait object for the trait.
101
102- [`Trait_CTO`](#trait_cto):
103A type alias for the trait object which is constructible in constants.
104
105
106### `Trait_TO`
107
108The ffi-safe trait object.
109
110[Its inherent methods are documented here.
111](./docs/sabi_trait_inherent/index.html#methods)
112
113`Trait_TO` has inherent method equivalents of the trait methods,
114only requiring the wrapped pointer to implement the trait in the individual methods
115(instead of putting those bounds in the impl block itself).
116
117<br>
118
119This only implements `Trait` if all the methods are callable,
120when the wrapped pointer type implements traits for these methods:
121
122- `&self` method: requires `AsPtr<PtrTarget = ()>`.
123- `&mut self` method: requires `AsMutPtr<PtrTarget = ()>`.
124- `self` method: requires `OwnedPointer<PtrTarget = ()>`.
125
126<br>
127
128Trait_TO has these generic parameters(in order):
129
130- `'trait_lifetime_n`: The lifetime parameters of the trait, if any.
131
132- `'lt`:
133This is the lifetime of the type that the trait object was constructed with.
134If the trait requires `'static`(in the list of supertraits),
135then it doesn't have this lifetime parameter.
136
137- `Pointer`:
138 An pointer whose referent has been erased,
139 most commonly [`RBox<()>`]/[`RArc<()>`]/[`RRef<'_, ()>`]/[`RMut<'_, ()>`].
140
141- `trait_type_param_n`: The type parameters of the trait.
142
143- `trait_const_param_n`: The const parameters of the trait.
144
145- `trait_assoc_type_n`: The associated types of the trait.
146
147
148A trait defined like this: `trait Foo<'a, T, U>{ type Hello; type World; }`,
149has this trait object: `Foo_TO<'a, 'lt, Pointer, T, U, Hello, World>`.
150
151<br>
152
153One can access the underlying implementation of the trait object through the `obj` field,
154allowing one to call these methods(a nonexhaustive list):
155
156- `downcast_into`
157
158- `downcast_as`
159
160- `downcast_as_mut`
161
162To reconstruct `Trait_TO` from its underlying implementation,
163you can use the `Trait_TO::from_sabi` associated function.
164
165### Trait_CTO
166
167A type alias for the type of the trait objct that is constructible in constants,
168with the `from_const` constructor function.
169
170Constructed with `Trait_CTO::from_const(&value)`.
171
172Trait_CTO has these generic parameters(in order):
173
174- `'trait_lifetime_n`: The lifetime parameters of the trait, if any.
175
176- `'lt`: this is the lifetime of the type that the trait object was construct with.
177If the trait requires `'static`(in the list of supertraits),
178then it doesn't have this lifetime parameter.
179
180- `'_ref`: this is the lifetime of the reference that this was constructed with.
181
182- `trait_type_param_n`: The type parameters of the trait.
183
184- `trait_const_param_n`: The const parameters of the trait.
185
186- `trait_assoc_type_n`: The associated types of the trait.
187
188
189Example: `Trait_CTO<'lt, 'r, u8, u64, 10, AssocFoo>`
190
191### Trait
192
193The trait is defined similarly to how it is before being transformed by the
194`#[sabi_trait]` attribute.
195
196These are the differences:
197
198- If there is a by-value method, a `Self: Sized` constraint will be added automatically.
199
200- Lifetime supertraits are stripped, because they disallow the trait object to be
201constructed with a reference of a smaller lifetime.
202
203# VTable attributes
204
205To pass attributes to the generated vtable you can use the `#[sabi( )]` attributes
206that are valid for `#[derive(StableAbi)]`.
207
208[Here is the documentation for the derive macro.
209](./derive.StableAbi.html)
210
211# Trait attributes.
212
213These are attributes for the generated trait, applied on the trait(not on methods).
214
215### `#[sabi(no_trait_impl)]`
216
217Disables the implementation of the trait for the trait object,
218you can still call the inherent versions of those methods on the trait object.
219
220This is useful to reduce compile-time overhead,
221and to allow users to declare a blanket(generic) implementation of the trait.
222
223### `#[sabi(no_default_fallback)]`
224
225Stops using default implementation of methods (from the trait declaration)
226as the fallback implementation of the method when it's not in the vtable,
227because the trait object comes from a previous version of the library.
228
229By using this attribute, defaulted methods will behave the same as
230non-defaulted methods when they don't exist in the vtable.
231
232### `#[sabi(debug_print_trait)]`
233
234Prints the output generated by the attribute macro,
235
236Note that this does not expand the output of the
237`#[derive(StableAbi)]` attribute on the vtable.
238
239### `#[sabi(use_dyntrait)]`
240
241Changes how the trait object is implemented to use `DynTrait` instead of `RObject`,
242this allows using more traits, with the (potential) cost of having more overhead.
243
244# Associated types
245
246The only valid way to refer to associated types in the trait declaration is with
247`Self::AssocType` syntax.
248
249Associated types in the trait object are transformed into type parameters
250that come after those of the trait.
251
252# Object safety
253
254Trait objects generated using this attribute have similar restrictions to built-in trait objects:
255
256- `Self` can only be used to access associated types
257 (using the `Self::AssocType` syntax).
258
259- `self` is a valid method receiver,
260 this requires that the pointer that the generated trait object wraps
261 implements `abi_stable::pointer_trait::OwnedPointer`.
262
263# Questions and Answers
264
265**Question: ** Why does Calling from_ptr/from_value give me a expected a `'static` value error?
266
267Answer: There are 3 possible reasons
268
269- 1: Because the trait has a `'static` supertrait bound.
270
271- 2: Because the trait has one of the comparison traits
272(`Eq`/`PartialEq`/`Ord`/`PartialOrd`)
273as supertraits.
274This requires the type to be `'static` because comparing trait objects requires
275constructing a `std::any::TypeId`, which itself requires `'static` to be constructed.
276
277- 3: Because you passed `TD_CanDowncast` to the constructor function,
278which requires constructing a `std::any::TypeId`
279(to unerase the trait object back into the value),
280which itself requires `'static` to be constructed.
281
282# Examples
283
284### Dictionary trait
285
286```rust
287use abi_stable::{
288 sabi_trait,
289 sabi_trait::prelude::*,
290 std_types::{RArc, RBox, RNone, ROption, RStr, RString},
291 StableAbi,
292};
293
294use std::{collections::HashMap, fmt::Debug};
295
296#[sabi_trait]
297pub trait Dictionary: Debug + Clone {
298 type Value;
299
300 fn get(&self, key: RStr<'_>) -> Option<&Self::Value>;
301
302 /// The `#[sabi(last_prefix_field)]` attribute here means that this is the last method
303 /// that was defined in the first compatible version of the library
304 /// (0.1.0, 0.2.0, 0.3.0, 1.0.0, 2.0.0 , etc),
305 /// requiring new methods to always be added below preexisting ones.
306 ///
307 /// The `#[sabi(last_prefix_field)]` attribute would stay on this method until the library
308 /// bumps its "major" version,
309 /// at which point it would be moved to the last method at the time.
310 ///
311 #[sabi(last_prefix_field)]
312 fn insert(&mut self, key: RString, value: Self::Value) -> ROption<Self::Value>;
313
314 /// It's semver compatible to add defaulted methods below previously-defined ones in
315 /// minor version updates.
316 fn contains(&self, key: RStr<'_>) -> bool {
317 self.get(key).is_some()
318 }
319}
320
321# fn main() {
322
323{
324 impl<V> Dictionary for HashMap<RString, V>
325 where
326 V: Debug + Clone,
327 {
328 type Value = V;
329 fn get(&self, key: RStr<'_>) -> Option<&V> {
330 self.get(key.as_str())
331 }
332 fn insert(&mut self, key: RString, value: V) -> ROption<V> {
333 self.insert(key, value).into()
334 }
335 }
336
337 let mut map = HashMap::<RString, u32>::new();
338 map.insert("hello".into(), 100);
339 map.insert("world".into(), 10);
340
341 {
342 // This type annotation is for the reader
343 //
344 // You can unerase trait objects constructed with `TD_CanDowncast`
345 // (as opposed to `TD_Opaque`, which can't be unerased).
346 let mut object: Dictionary_TO<'_, RBox<()>, u32> =
347 Dictionary_TO::from_value(map.clone(), TD_CanDowncast);
348
349 assert_eq!(Dictionary::get(&object, "hello".into()), Some(&100));
350 assert_eq!(object.get("hello".into()), Some(&100)); // Inherent method call
351
352 assert_eq!(Dictionary::get(&object, "world".into()), Some(&10));
353 assert_eq!(object.get("world".into()), Some(&10)); // Inherent method call
354
355 object.insert("what".into(), 99); // Inherent method call
356
357 // You can only unerase a trait object if it was constructed with `TD_CanDowncast`
358 // and it's being unerased into a type that implements `std::any::Any`.
359 let map: RBox<HashMap<RString, u32>> = object.obj.downcast_into().unwrap();
360
361 assert_eq!(map.get("hello".into()), Some(&100));
362 assert_eq!(map.get("world".into()), Some(&10));
363 assert_eq!(map.get("what".into()), Some(&99));
364 }
365 {
366 let arc = RArc::new(map.clone());
367 // This type annotation is for the reader
368 //
369 // You can unerase trait objects constructed with `TD_CanDowncast`
370 // (as opposed to `TD_Opaque`, which can't be unerased).
371 let object: Dictionary_TO<'_, RArc<()>, u32> =
372 Dictionary_TO::from_ptr(arc, TD_CanDowncast);
373
374 assert_eq!(object.get("world".into()), Some(&10));
375
376 // Can't call these methods on `Dictionary_TO<RArc<()>,..>`
377 // because `RArc<_>` doesn't implement AsMutPtr.
378 //
379 // assert_eq!(Dictionary::get(&object,"hello"), Some(&100));
380 //
381 // object.insert("what".into(), 99);
382 // Dictionary::insert(&mut object,"what".into(), 99);
383
384 let map: RArc<HashMap<RString, u32>> = object.obj.downcast_into().unwrap();
385 assert_eq!(map.get("hello".into()), Some(&100));
386 assert_eq!(map.get("world".into()), Some(&10));
387 }
388}
389
390{
391 impl Dictionary for () {
392 type Value = RString;
393 fn get(&self, _: RStr<'_>) -> Option<&RString> {
394 None
395 }
396 fn insert(&mut self, _: RString, _: RString) -> ROption<RString> {
397 RNone
398 }
399 }
400
401 // This type annotation is for the reader
402 let object: Dictionary_TO<'_, RBox<()>, RString> =
403 Dictionary_TO::from_value((), TD_Opaque);
404
405 assert_eq!(object.get("hello".into()), None);
406 assert_eq!(object.get("world".into()), None);
407
408 // Cannot unerase trait objects created with `TD_Opaque`.
409 assert_eq!(object.obj.downcast_into::<()>().ok(), None);
410}
411
412# }
413
414
415```
416
417
418### Constructing a trait object in a constant
419
420This shows how one can construct a `#[sabi_trait]` generated trait object in a constant/static.
421
422```rust
423
424use abi_stable::{sabi_trait, sabi_trait::TD_Opaque};
425
426#[sabi_trait]
427pub trait StaticSet: Sync + Send + Debug + Clone {
428 type Element;
429
430 /// Whether the set contains the key.
431 fn contains(&self, key: &Self::Element) -> bool;
432}
433
434impl<'a, T> StaticSet for &'a [T]
435where
436 T: std::fmt::Debug + Sync + Send + std::cmp::PartialEq,
437{
438 type Element = T;
439
440 fn contains(&self, key: &Self::Element) -> bool {
441 (**self).contains(key)
442 }
443}
444
445const CARDS: &'static [char] =
446 &['A', '2', '3', '4', '5', '6', '7', '8', '9', 'J', 'Q', 'K'];
447
448static IS_CARD: StaticSet_CTO<'static, 'static, char> =
449 StaticSet_CTO::from_const(&CARDS, TD_Opaque);
450
451# fn main(){
452
453assert!(IS_CARD.contains(&'A'));
454assert!(IS_CARD.contains(&'4'));
455assert!(IS_CARD.contains(&'7'));
456assert!(IS_CARD.contains(&'9'));
457assert!(IS_CARD.contains(&'J'));
458
459assert!(!IS_CARD.contains(&'0'));
460assert!(!IS_CARD.contains(&'1'));
461assert!(!IS_CARD.contains(&'B'));
462
463# }
464
465```
466
467### Cloning an `RArc`-using trait object.
468
469Because of a quirk of how `#[sabi_trait]` trait objects work,
470trait objects that use [`RArc`] can only be `.clone()`d if they
471have a `Clone` supertrait.
472To work around this, you can use the
473[`RObject::shallow_clone`] /[`DynTrait::shallow_clone`] methods.
474
475```rust
476use abi_stable::{
477 sabi_trait,
478 sabi_trait::TD_Opaque,
479 std_types::RArc,
480};
481
482# fn main() {
483let object = Foo_TO::from_ptr(RArc::new(SomeDay{day: 10}), TD_Opaque);
484
485// calling `RObject::shallow_clone` to clone the `RArc`-based trait object,
486// now both have a `RArc` handle to the same data.
487let clone = Foo_TO::from_sabi(object.obj.shallow_clone());
488
489assert_eq!(format!("{:?}", object), format!("{:?}", clone));
490# }
491
492
493#[sabi_trait]
494pub trait Foo: Sync + Send + Debug {}
495
496#[derive(Debug)]
497struct SomeDay {
498 day: u32,
499}
500
501impl Foo for SomeDay {}
502```
503
504
505
506[`abi_stable::sabi_trait`]: ./sabi_trait/index.html
507[`RObject`]: crate::sabi_trait::RObject
508[`RObject::shallow_clone`]: crate::sabi_trait::RObject::shallow_clone
509[`DynTrait::shallow_clone`]: crate::DynTrait::shallow_clone
510[`DynTrait`]: crate::DynTrait
511[`RBox<()>`]: ./std_types/struct.RBox.html
512[`RArc<()>`]: ./std_types/struct.RArc.html
513[`RArc`]: ./std_types/struct.RArc.html
514[`RRef<'_, ()>`]: ./sabi_types/struct.RRef.html
515[`RMut<'_, ()>`]: ./sabi_types/struct.RMut.html
516
517*/
518#[doc(inline)]
519pub use abi_stable_derive::sabi_trait;