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:

  1. Unlike slab (but like slotmap), we implement versioning, detecting ABA problems, which allows us to detect use after free.
  2. Unlike slotmap, we don’t have the T: Copy restriction.
  3. 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.
  4. Our implementation of doesn’t use any unsafe (at the time of this writing).

However, it comes with the following drawbacks:

  1. slotmap holds its version information in a u32, and so it takes 231 colliding insertions and deletions before it could potentially fail to detect an ABA issue, wheras we use a u16, and are limited to 215.
  2. 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).
  3. Our implementation is slower, and uses slightly more memory than slotmap (which is in part due to the lack of unsafe 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.