Module ffi_support::handle_map [−][src]
Expand description
This module provides a Handle
type, which you can think of something
like a dynamically checked, type erased reference/pointer type. Depending on
the usage pattern a handle can behave as either a borrowed reference, or an
owned pointer.
They can be losslessly converted to and
from a 64 bit integer, for ease of passing over the FFI
(and they implement IntoFfi
using these primitives for this purpose).
The benefit is primarially that they can detect common misuse patterns that would otherwise be silent bugs, such as use-after-free, double-free, passing a wrongly-typed pointer to a function, etc.
Handles are provided when inserting an item into either a HandleMap
or a
ConcurrentHandleMap
.
Comparison to types from other crates
HandleMap
is similar to types offered by other crates, such as
slotmap
, or slab
. However, it has a number of key differences which make
it better for our purposes as compared to the types in those crates:
- Unlike
slab
(but likeslotmap
), we implement versioning, detecting ABA problems, which allows us to detect use after free. - Unlike
slotmap
, we don’t have theT: Copy
restriction. - Unlike either, we can detect when you use a Key in a map that did not
allocate the key. This is true even when the map is from a
.so
file compiled separately. - Our implementation of doesn’t use any
unsafe
(at the time of this writing).
However, it comes with the following drawbacks:
slotmap
holds its version information in au32
, and so it takes 231 colliding insertions and deletions before it could potentially fail to detect an ABA issue, wheras we use au16
, and are limited to 215.- Similarly, we can only hold 216 items at once, unlike
slotmap
’s 232. (Considering these items are typically things like database handles, this is probably plenty). - Our implementation is slower, and uses slightly more memory than
slotmap
(which is in part due to the lack ofunsafe
mentioned above)
The first two issues seem exceptionally unlikely, even for extremely
long-lived HandleMap
, and we’re still memory safe even if they occur (we
just might fail to notice a bug). The third issue also seems unimportant for
our use case.
Structs
ConcurrentHandleMap
is a relatively thin wrapper around
RwLock<HandleMap<Mutex<T>>>
. Due to the nested locking, it’s not possible
to implement the same API as HandleMap
, however it does implement an API
that offers equivalent functionality, as well as several functions that
greatly simplify FFI usage (see example below).
A Handle we allow to be returned over the FFI by implementing IntoFfi
.
This type is intentionally not #[repr(C)]
, and getting the data out of the
FFI is done using Handle::from_u64
, or it’s implemetation of From<u64>
.
HandleMap
is a collection type which can hold any type of value, and
offers a stable handle which can be used to retrieve it on insertion. These
handles offer methods for converting to and
from 64 bit integers, meaning they’re very easy to pass
over the FFI (they also implement IntoFfi
for the same purpose).
Enums
An error representing the ways a Handle
may be invalid.
Constants
The maximum capacity of a HandleMap
. Attempting to instantiate one with
a larger capacity will cause a panic.