Macro abi_stable::staticref
source · macro_rules! staticref { ( $( $(#[$attr:meta])* $vis:vis const $name:ident : $ty:ty = $expr:expr );* $(;)? ) => { ... }; }
Expand description
Allows declaring a StaticRef
inherent associated const
ant
from possibly non-'static
references.
This only works in inherent implementations.
This does not work in:
- trait definitions
- trait implementations.
- modules: to define a non-associated constant.
§Example
§Basic
use abi_stable::staticref;
struct NONE_REF<T>(T);
impl<T> NONE_REF<T> {
// Declares a `StaticRef<Option<T>>` that points to a `None`, for any `T`.
staticref!(const V: Option<T> = None);
}
let none_string: &'static Option<String> = NONE_REF::<String>::V.get();
assert_eq!(none_string, &None::<String>);
§More realistic
This example demonstrates how you can construct a pointer to a vtable, constructed at compile-time.
use abi_stable::{
StableAbi,
extern_fn_panic_handling,
staticref,
pointer_trait::CallReferentDrop,
prefix_type::{PrefixTypeTrait, WithMetadata},
};
use std::{
mem::ManuallyDrop,
ops::Deref,
};
fn main(){
let boxed = BoxLike::new(100);
assert_eq!(*boxed, 100);
assert_eq!(boxed.into_inner(), 100);
}
/// An ffi-safe `Box<T>`
#[repr(C)]
#[derive(StableAbi)]
pub struct BoxLike<T> {
data: *mut T,
vtable: VTable_Ref<T>,
_marker: std::marker::PhantomData<T>,
}
impl<T> BoxLike<T>{
pub fn new(value: T) -> Self {
let box_ = Box::new(value);
Self{
data: Box::into_raw(box_),
vtable: VTable::VTABLE,
_marker: std::marker::PhantomData,
}
}
/// Extracts the value this owns.
pub fn into_inner(self) -> T{
let this = ManuallyDrop::new(self);
unsafe{
// Must copy this before calling `self.vtable.destructor()`
// because otherwise it would be reading from a dangling pointer.
let ret = this.data.read();
this.vtable.destructor()(this.data,CallReferentDrop::No);
ret
}
}
}
impl<T> Drop for BoxLike<T>{
fn drop(&mut self){
unsafe{
self.vtable.destructor()(self.data, CallReferentDrop::Yes)
}
}
}
// `#[sabi(kind(Prefix))]` Declares this type as being a prefix-type,
// generating both of these types:
//
// - VTable_Prefix`: A struct with the fields up to (and including) the field with the
// `#[sabi(last_prefix_field)]` attribute.
//
// - VTable_Ref`: An ffi-safe pointer to `VTable`,with methods to get `VTable`'s fields.
//
#[repr(C)]
#[derive(StableAbi)]
#[sabi(kind(Prefix))]
struct VTable<T>{
#[sabi(last_prefix_field)]
destructor: unsafe extern "C" fn(*mut T, CallReferentDrop),
}
impl<T> VTable<T>{
staticref!(const VTABLE_VAL: WithMetadata<Self> = WithMetadata::new(
Self{
destructor: destroy_box::<T>,
},
));
const VTABLE: VTable_Ref<T> = {
VTable_Ref( Self::VTABLE_VAL.as_prefix() )
};
}
unsafe extern "C" fn destroy_box<T>(v: *mut T, call_drop: CallReferentDrop) {
extern_fn_panic_handling! {
let mut box_ = Box::from_raw(v as *mut ManuallyDrop<T>);
if call_drop == CallReferentDrop::Yes {
ManuallyDrop::drop(&mut *box_);
}
drop(box_);
}
}
impl<T> Deref for BoxLike<T> {
type Target=T;
fn deref(&self)->&T{
unsafe{
&(*self.data)
}
}
}