[−][src]Crate stowaway
Stowaway is a library for efficiently storing values in a pointer. The
main use case for stowaway is as a helpful way to interoperate with
libraries that require opaque data to be passed via pointer, such as C
libraries expecting a void*, std::RawWaker, and boost::context.
The central feature of this library is value packing in a Stowaway
struct. If T is not larger than a pointer (that is, if
sizeof(T) <= sizeof(*T)), then the value is packed directly into the
bytes of an opaque pointer value (specifically, a *mut ()). This
value can then be passed as the context pointer for C-like interfaces,
and then converted back into a Stowaway on the other end.
Lifecycle
The basic lifecycle of a Stowaway value is as follows:
- Create a
StowawaywithStowaway::new. This will pack the value into the space of a pointer, or box it if it's too big. - Convert that value into a pointer with
Stowaway::into_raw. - Store that value somewhere, such as in a
RawWaker, or as avoid*in a C API. Recover the value somewhere else. - Convert the pointer back into a
StowawaywithStowaway::from_raw. This takes back ownership of the value, so make sure to only do it once, and discard the pointer afterwards. - Covert the
Stowawayback into aT, or use it as a container withDeref/AsRef/DerefMut/AsMut.
Simple example:
use stowaway::Stowaway; fn demo_lifecycle<T: Clone + std::fmt::Debug + Eq>(value: T) { let cloned = value.clone(); let stowed: Stowaway<T> = Stowaway::new(value); let storage = Stowaway::into_raw(stowed); // At this point, the storage pointer would be passed into a C API, // and recovered somewhere else let new_stowed: Stowaway<T> = unsafe { Stowaway::from_raw(storage) }; let unstowed: T = Stowaway::into_inner(new_stowed); assert_eq!(unstowed, cloned); } // A small value, like a u16, is stored directly in the pointer. No // allocations are performed in this example. demo_lifecycle(137u16); // A large value, like `Vec` (which internally is a data pointer and a // pair of usize) cannot fit in a pointer, and will therefore be boxed // when stored in `Stowaway` demo_lifecycle(vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
C-like API Example
In this example, we create a fake "C like" API. We will store in this API a series of function pointers and context data pointers, which will then be called all at once.
use stowaway::Stowaway; // Fake stdout static mut stdout: String = String::new(); #[derive(Default)] struct EventList { events: Vec<(fn(*mut ()), *mut())> } impl EventList { // our fake C API: add a function pointer and a *mut () to a list // of callbacks to run. fn add_event(&mut self, fptr: fn(*mut ()), ctx: *mut()) { self.events.push((fptr, ctx)); } // For each function pointer added with add_event, call the function // with the context pointer. fn run_all_events(self) { self.events.into_iter().for_each(|(fptr, ctx)| { fptr(ctx); }) } } let mut event_list = EventList::default(); // Add some events to the list // Event 1: print a simple number. u16 should easily fit in a pointer, // so this won't allocate anything fn print_u16(value: *mut()) { unsafe { let value: Stowaway<u16> = unsafe { Stowaway::from_raw(value) }; writeln!(&mut stdout, "A number: {}", *value).unwrap(); } } event_list.add_event(print_u16, Stowaway::into_raw(Stowaway::new(10u16))); event_list.add_event(print_u16, Stowaway::into_raw(Stowaway::new(20u16))); // Event 2: Print a large array (`[u64; 8]`). This won't definitely won't fit // in a pointer, so stowaway will automatically allocate it for us fn print_big_array(value: *mut()) { unsafe { let value: Stowaway<[u64; 8]> = unsafe { Stowaway::from_raw(value) }; writeln!(&mut stdout, "8 large numbers: {:?}", *value).unwrap(); } } let data: [u64; 8] = [1, 1, 2, 3, 5, 8, 13, 21]; event_list.add_event(print_big_array, Stowaway::into_raw(Stowaway::new(data))); let data: [u64; 8] = [34, 55, 89, 144, 233, 377, 610, 987]; event_list.add_event(print_big_array, Stowaway::into_raw(Stowaway::new(data))); // Execute all the events event_list.run_all_events(); unsafe { assert_eq!(stdout, "A number: 10\n\ A number: 20\n\ 8 large numbers: [1, 1, 2, 3, 5, 8, 13, 21]\n\ 8 large numbers: [34, 55, 89, 144, 233, 377, 610, 987]\n" ); }
Structs
| Stowaway | A maybe-allocated container. This struct stores a single |
Functions
| mut_ref_from_stowed⚠ | Get a mutable reference to a value that was previously stowed, either with
|
| ref_from_stowed⚠ | Get a reference to a value that was previously stowed, either with |
| stow | Stow a value into a |
| unstow⚠ | Restore a value that was previously stowed, either with |