Trait lmdb_zero::traits::LmdbRaw [] [src]

pub unsafe trait LmdbRaw: Copy + Sized {
    fn reported_type() -> String { ... }
}

Marker trait indicating a value is to be stored in LMDB by simply copying it in.

This trait implies that one wants integers and such in native byte order and doesn't care about inter-ABI portability of the values. There are a lot of safety implications as well.

Implementing this trait provides blanket implementations of AsLmdbBytes, FromLmdbBytes, and FromReservedLmdbBytes.

See also LmdbRawIfUnaligned for types that become LmdbRaw when wrapped with Unaligned. In particular, all integer and floating-point types are LmdbRawIfUnaligned, except for u8 and i8 which are also LmdbRaw.

Alignment

The FromLmdbBytes conversion fails if the alignment of the input data does not satisfy the alignment of the type. This means that behaviour will be unpredictable if the required alignment of the struct is greater than 1, as conversions will pass or fail depending on where LMDB decides to place the value.

If you run into this issue, there are several ways to work around it.

Use Unaligned

Instead of directly reading and writing the bare type, wrap it in lmdb_zero::Unaligned. This adds no overhead in and of itself and removes the alignment restriction, but heavily restricts what can be done with a reference without copying it.

This is almost always the best option if your type fits in a register or two.

Make your structure #[repr(C, packed)]

If this is a problem, you can make your structure #[repr(packed)] to give it an alignment of 1 (but see also below about padding).

Note that it is possible to produce unsafe code using this approach even without the use of unsafe. See this rust bug.

Do it yourself

If you have unusual requirements, your best bet is to implement FromLmdbBytes and friends manually as needed.

Unsafety

If the tagged type contains pointers of any kind, they will be stored in and retrieved from the database, which has serious ramifications, especially when the FromReservedLmdbBytes implementation is used. If the type contains Rust references, this will almost certainly lead to undefined behaviour.

Behaviour is undefined if there exist bit patterns of the same size of the type which are not valid instances of that type unless the client code can somehow guarantee that such bit patterns do not occur. If this is a problem, implement AsLmdbBytes and FromLmdbBytes manually and check for validity. Of particular note, bool and essentially all enum types are not sensible for use with LmdbRaw (directly or within composites) because they are only valid for particular bit patterns.

Warnings about inner padding

Use of this trait on a struct that is not #[repr(packed)] makes it possible to observe the normally unobservable padding bytes inserted into the structure to satisfy type alignment.

When simply using these structures as values in a non-DUPSORT database, this simply means some arbitrary extra bytes get written with the values. This is not going to be a problem unless you plan on sharing the databases with untrusted third parties (which could leak sensitive information) or do unusual things with type punning.

However, in any context where values need to be compared (ie, keys, and values in DUPSORT databases), these padding bytes now count towards the comparison by default. Since the padding contains unpredictable values, you can easily end up with multiple "identical" keys that differ in their padding bytes, fail to find values you know are in the database because of differences in padding values, etc.

One way to deal with both problems is to use #[repr(packed)] (in addition to #[repr(C)] which keeps the field order defined across Rust versions), which simply eliminates the padding bytes altogether. Note that due to a bug in the Rust compiler, packed structures can lead to undefined behaviour in "safe Rust". Until that issue is fixed, you should be careful about using #[repr(packed)] for this purpose unless all fields in the struct have the same size or you understand the ABI(s) you care about well enough to know whether misalignment will cause issues.

You can alternatively opt to live with the padding bytes, but additionally implement LmdbOrdKey on the type, and then use DatabaseOptions::sort_keys_as or DatabaseOptions::sort_values_as appropriately to use the generated comparison function. As a result, the padding bytes will be ignored for comparison purposes, but will nontheless be written into the database and thus remain visible to puns and could leak information.

Example

use lmdb_zero::traits::*;

#[repr(C)]
#[derive(Clone,Copy,Debug)]
struct MyStruct {
  foo: i16,
  // See warning about alignment/padding above!
  // On AMD64, for example, we get 6 padding bytes here.
  bar: u64,
}
unsafe impl LmdbRaw for MyStruct { }

Provided Methods

Returns the name of this type to report in error messages.

If not implemented, defaults to "?".

Implementations on Foreign Types

impl LmdbRaw for u8
[src]

impl LmdbRaw for i8
[src]

impl<V: LmdbRaw> LmdbRaw for [V; 0]
[src]

impl<V: LmdbRaw> LmdbRaw for [V; 1]
[src]

impl<V: LmdbRaw> LmdbRaw for [V; 2]
[src]

impl<V: LmdbRaw> LmdbRaw for [V; 3]
[src]

impl<V: LmdbRaw> LmdbRaw for [V; 4]
[src]

impl<V: LmdbRaw> LmdbRaw for [V; 5]
[src]

impl<V: LmdbRaw> LmdbRaw for [V; 6]
[src]

impl<V: LmdbRaw> LmdbRaw for [V; 7]
[src]

impl<V: LmdbRaw> LmdbRaw for [V; 8]
[src]

impl<V: LmdbRaw> LmdbRaw for [V; 9]
[src]

impl<V: LmdbRaw> LmdbRaw for [V; 10]
[src]

impl<V: LmdbRaw> LmdbRaw for [V; 11]
[src]

impl<V: LmdbRaw> LmdbRaw for [V; 12]
[src]

impl<V: LmdbRaw> LmdbRaw for [V; 13]
[src]

impl<V: LmdbRaw> LmdbRaw for [V; 14]
[src]

impl<V: LmdbRaw> LmdbRaw for [V; 15]
[src]

impl<V: LmdbRaw> LmdbRaw for [V; 16]
[src]

impl<V: LmdbRaw> LmdbRaw for [V; 17]
[src]

impl<V: LmdbRaw> LmdbRaw for [V; 18]
[src]

impl<V: LmdbRaw> LmdbRaw for [V; 19]
[src]

impl<V: LmdbRaw> LmdbRaw for [V; 20]
[src]

impl<V: LmdbRaw> LmdbRaw for [V; 21]
[src]

impl<V: LmdbRaw> LmdbRaw for [V; 22]
[src]

impl<V: LmdbRaw> LmdbRaw for [V; 23]
[src]

impl<V: LmdbRaw> LmdbRaw for [V; 24]
[src]

impl<V: LmdbRaw> LmdbRaw for [V; 25]
[src]

impl<V: LmdbRaw> LmdbRaw for [V; 26]
[src]

impl<V: LmdbRaw> LmdbRaw for [V; 27]
[src]

impl<V: LmdbRaw> LmdbRaw for [V; 28]
[src]

impl<V: LmdbRaw> LmdbRaw for [V; 29]
[src]

impl<V: LmdbRaw> LmdbRaw for [V; 30]
[src]

impl<V: LmdbRaw> LmdbRaw for [V; 31]
[src]

impl<V: LmdbRaw> LmdbRaw for [V; 32]
[src]

impl LmdbRaw for ()
[src]

Implementors