lmdb_zero/
traits.rs

1// Copyright 2016 FullContact, Inc
2// Copyright 2017 Jason Lingle
3//
4// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
5// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
6// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
7// option. This file may not be copied, modified, or distributed
8// except according to those terms.
9
10//! Module containing public traits.
11//!
12//! This exists as a separate module solely so that it can be wildcard imported
13//! where necessary.
14
15use std::char;
16use std::cmp::Ord;
17use std::ffi::CStr;
18use std::mem;
19use std::num::Wrapping;
20use std::rc::Rc;
21use std::slice;
22use std::str;
23use std::sync::Arc;
24
25use supercow::Supercow;
26
27use ::Ignore;
28use cursor::{Cursor, StaleCursor};
29use dbi::Database;
30use tx::{ConstTransaction, ReadTransaction, WriteTransaction};
31
32pub use error::{self, LmdbResultExt};
33
34/// Extension trait for `Rc` and `Arc` that allows up-casting a reference to
35/// `ReadTransaction` or `WriteTransaction` to `ConstTransaction`.
36pub trait TxExt {
37    #[allow(missing_docs)]
38    type Const;
39    /// Returns `self` as a handle to a `ConstTransaction` rather than the
40    /// subtype that was passed in.
41    ///
42    /// This is still a shared handle to the same transaction.
43    fn to_const(self) -> Self::Const;
44}
45
46impl<'a> TxExt for Rc<ReadTransaction<'a>> {
47    type Const = Rc<ConstTransaction<'a>>;
48    // This is safe, despite appearances. `ReadTransaction` (and below, also
49    // `WriteTransaction`) are newtypes, which are guaranteed to have exactly
50    // the same memory representation as the thing they wrap. Further, they
51    // have no `impl Drop` of their own, so the resulting drop code is exactly
52    // equal for both `Rc<ConstTransaction>` and `Rc<ReadTransaction>`.
53    fn to_const(self) -> Self::Const { unsafe { mem::transmute(self) } }
54}
55impl<'a> TxExt for Rc<WriteTransaction<'a>> {
56    type Const = Rc<ConstTransaction<'a>>;
57    fn to_const(self) -> Self::Const { unsafe { mem::transmute(self) } }
58}
59impl<'a> TxExt for Arc<ReadTransaction<'a>> {
60    type Const = Arc<ConstTransaction<'a>>;
61    fn to_const(self) -> Self::Const { unsafe { mem::transmute(self) } }
62}
63impl<'a> TxExt for Arc<WriteTransaction<'a>> {
64    type Const = Arc<ConstTransaction<'a>>;
65    fn to_const(self) -> Self::Const { unsafe { mem::transmute(self) } }
66}
67
68/// Types of transaction references which can be used to construct `Cursor`s.
69///
70/// In most cases this is simply used as an extension trait (see the examples
71/// on `Cursor`). However, it can also be used to abstract over things that can
72/// be used to create `Cursor`s if so desired.
73///
74/// Implementations are provided for references to the three general
75/// transaction types, as well as `Rc` and `Arc` directly wrapping either
76/// concrete transaction type with a `'static` lifetime.
77pub trait CreateCursor<'txn> {
78    /// Create a cursor using `self` as the reference to the containing
79    /// transaction and `db` as the database the cursor will read from and
80    /// write into.
81    fn cursor<'db, DB>(&self, db: DB)
82                       -> error::Result<Cursor<'txn,'db>>
83    where DB : Into<Supercow<'db, Database<'db>>>;
84}
85
86impl<'txn, 'env: 'txn> CreateCursor<'txn> for &'txn ConstTransaction<'env> {
87    #[inline]
88    fn cursor<'db, DB>(&self, db: DB)
89                       -> error::Result<Cursor<'txn,'db>>
90    where DB : Into<Supercow<'db, Database<'db>>> {
91        ConstTransaction::cursor(*self, db)
92    }
93}
94
95impl<'txn, 'env: 'txn> CreateCursor<'txn> for &'txn ReadTransaction<'env> {
96    #[inline]
97    fn cursor<'db, DB>(&self, db: DB)
98                       -> error::Result<Cursor<'txn,'db>>
99    where DB : Into<Supercow<'db, Database<'db>>> {
100        ConstTransaction::cursor(*self, db)
101    }
102}
103
104impl<'txn, 'env: 'txn> CreateCursor<'txn> for &'txn WriteTransaction<'env> {
105    #[inline]
106    fn cursor<'db, DB>(&self, db: DB)
107                       -> error::Result<Cursor<'txn,'db>>
108    where DB : Into<Supercow<'db, Database<'db>>> {
109        ConstTransaction::cursor(*self, db)
110    }
111}
112
113impl<'txn> CreateCursor<'txn> for Rc<ReadTransaction<'static>> {
114    #[inline]
115    fn cursor<'db, DB>(&self, db: DB)
116                       -> error::Result<Cursor<'txn,'db>>
117    where DB : Into<Supercow<'db, Database<'db>>> {
118        Cursor::construct(Supercow::shared(self.clone().to_const()),
119                          db.into())
120    }
121}
122
123impl<'txn> CreateCursor<'txn> for Arc<ReadTransaction<'static>> {
124    #[inline]
125    fn cursor<'db, DB>(&self, db: DB)
126                       -> error::Result<Cursor<'txn,'db>>
127    where DB : Into<Supercow<'db, Database<'db>>> {
128        Cursor::construct(Supercow::shared(self.clone().to_const()),
129                          db.into())
130    }
131}
132
133impl<'txn> CreateCursor<'txn> for Rc<WriteTransaction<'static>> {
134    #[inline]
135    fn cursor<'db, DB>(&self, db: DB)
136                       -> error::Result<Cursor<'txn,'db>>
137    where DB : Into<Supercow<'db, Database<'db>>> {
138        Cursor::construct(Supercow::shared(self.clone().to_const()),
139                          db.into())
140    }
141}
142
143impl<'txn> CreateCursor<'txn> for Arc<WriteTransaction<'static>> {
144    #[inline]
145    fn cursor<'db, DB>(&self, db: DB)
146                       -> error::Result<Cursor<'txn,'db>>
147    where DB : Into<Supercow<'db, Database<'db>>> {
148        Cursor::construct(Supercow::shared(self.clone().to_const()),
149                          db.into())
150    }
151}
152
153/// Types of transaction references which can be used to renew `StaleCursor`s
154/// into functional `Cursor`s.
155///
156/// In most cases this is simply used as an extension trait (see the examples
157/// on `Cursor`). However, it can also be used to abstract over things that can
158/// be used to create `Cursor`s if so desired.
159///
160/// Implementations are provided for normal references to `ReadTransaction` as
161/// well as `Rc` and `Arc`. The latter two require the transaction's inner
162/// lifetime to be `'static`.
163pub trait AssocCursor<'txn> {
164    /// Associates a saved read-only with this transaction.
165    ///
166    /// The cursor will be rebound to this transaction, but will continue using
167    /// the same database that it was previously.
168    fn assoc_cursor<'db>(&self, cursor: StaleCursor<'db>)
169                         -> error::Result<Cursor<'txn,'db>>;
170}
171
172impl<'txn,'env: 'txn> AssocCursor<'txn> for &'txn ReadTransaction<'env> {
173    fn assoc_cursor<'db>(&self, cursor: StaleCursor<'db>)
174                         -> error::Result<Cursor<'txn,'db>> {
175        ReadTransaction::assoc_cursor(*self, cursor)
176    }
177}
178
179impl<'txn> AssocCursor<'txn> for Rc<ReadTransaction<'static>> {
180    fn assoc_cursor<'db>(&self, cursor: StaleCursor<'db>)
181                         -> error::Result<Cursor<'txn,'db>> {
182        Cursor::from_stale(cursor, Supercow::shared(self.clone().to_const()))
183    }
184}
185
186impl<'txn> AssocCursor<'txn> for Arc<ReadTransaction<'static>> {
187    fn assoc_cursor<'db>(&self, cursor: StaleCursor<'db>)
188                         -> error::Result<Cursor<'txn,'db>> {
189        Cursor::from_stale(cursor, Supercow::shared(self.clone().to_const()))
190    }
191}
192
193/// Translates a value into a byte slice to be stored in LMDB.
194///
195/// This is similar to `AsRef<[u8]>`, but is separate since there are
196/// things one may wish to store in LMDB but not have implicitly coerce to
197/// `&[u8]` in other contexts.
198///
199/// Blanket impls are provided for `LmdbRaw` and for slices of `LmdbRaw`
200/// values. Ideally there'd be one for anything `AsRef<[u8]>`, but in Rust
201/// 1.10 that's not possible due to coherence rules barring having
202/// blanket implementations for both `LmdbRaw` and `AsRef<[u8]>`, so
203/// currently it is provided only for `&str` and `&Vec<u8>`.
204///
205/// _This is not a general-purpose serialisation mechanism._ There is no
206/// way to use this trait to store values in a format other than how they
207/// are natively represented in memory. Doing this requires serialisation
208/// into a byte array before passing it onto lmdb-zero.
209pub trait AsLmdbBytes {
210    /// Casts the given reference to a byte slice appropriate for storage
211    /// in LMDB.
212    fn as_lmdb_bytes(&self) -> &[u8];
213}
214
215/// Inverts `AsLmdbBytes`, producing a reference to a structure inside a
216/// byte array.
217///
218/// Blanket implementations are provided for `LmdbRaw` and slices of
219/// `LmdbRaw` things.
220///
221/// _This is not a general-purpose deserialisation mechanism._ There is no
222/// way to use this trait to read values in any format other than how they
223/// are natively represented in memory. The only control is that outright
224/// invalid values can be rejected so as to avoid undefined behaviour from,
225/// eg, constructing `&str`s with malformed content. Reading values not in
226/// native format requires extracting the byte slice and using a separate
227/// deserialisation mechanism.
228pub trait FromLmdbBytes {
229    /// Given a byte slice, return an instance of `Self` described, or
230    /// `Err` with an error message if the given byte slice is not an
231    /// appropriate value.
232    fn from_lmdb_bytes(&[u8]) -> Result<&Self, String>;
233}
234
235/// Like `FromLmdbBytes`, but can be used with `put_reserve()` calls.
236///
237/// A blanket implementation is provided for anything which is `LmdbRaw`.
238pub trait FromReservedLmdbBytes {
239    /// Given a mutable byte slice containing arbitrary data, return an
240    /// instance of `Self`.
241    ///
242    /// This is not allowed to fail, since there is no control over the
243    /// original content of the slice.
244    ///
245    /// ## Unsafety
246    ///
247    /// This function is allowed to blindly assume that the byte slice is
248    /// an appropriate size.
249    unsafe fn from_reserved_lmdb_bytes(&mut [u8]) -> &mut Self;
250}
251
252/// Marker trait indicating a value is to be stored in LMDB by simply
253/// copying it in.
254///
255/// This trait implies that one wants integers and such in native byte order
256/// and doesn't care about inter-ABI portability of the values. There are a lot
257/// of safety implications as well.
258///
259/// Implementing this trait provides blanket implementations of
260/// `AsLmdbBytes`, `FromLmdbBytes`, and `FromReservedLmdbBytes`.
261///
262/// See also [`LmdbRawIfUnaligned`](trait.LmdbRawIfUnaligned.html) for types
263/// that become `LmdbRaw` when wrapped with
264/// [`Unaligned`](../struct.Unaligned.html). In particular, all integer and
265/// floating-point types are `LmdbRawIfUnaligned`, except for `u8` and `i8`
266/// which are also `LmdbRaw`.
267///
268/// ## Alignment
269///
270/// The `FromLmdbBytes` conversion fails if the alignment of the input data
271/// does not satisfy the alignment of the type. This means that behaviour will
272/// be unpredictable if the required alignment of the struct is greater than 1,
273/// as conversions will pass or fail depending on where LMDB decides to place
274/// the value.
275///
276/// If you run into this issue, there are several ways to work around it.
277///
278/// ### Use `Unaligned`
279///
280/// Instead of directly reading and writing the bare type, wrap it in
281/// `lmdb_zero::Unaligned`. This adds no overhead in and of itself and removes
282/// the alignment restriction, but heavily restricts what can be done with a
283/// reference without copying it.
284///
285/// This is almost always the best option if your type fits in a register or
286/// two.
287///
288/// ### Make your structure `#[repr(C, packed)]`
289///
290/// If this is a problem, you can make your structure `#[repr(packed)]` to give
291/// it an alignment of 1 (but see also below about padding).
292///
293/// Note that it is possible to produce unsafe code using this approach even
294/// without the use of `unsafe`. See [this rust
295/// bug](https://github.com/rust-lang/rust/issues/27060).
296///
297/// ### Do it yourself
298///
299/// If you have unusual requirements, your best bet is to implement
300/// `FromLmdbBytes` and friends manually as needed.
301///
302/// ## Unsafety
303///
304/// If the tagged type contains pointers of any kind, they will be stored in
305/// and retrieved from the database, which has serious ramifications,
306/// especially when the `FromReservedLmdbBytes` implementation is used. If the
307/// type contains Rust references, this will almost certainly lead to undefined
308/// behaviour.
309///
310/// Behaviour is undefined if there exist bit patterns of the same size of the
311/// type which are not valid instances of that type unless the client code can
312/// somehow guarantee that such bit patterns do not occur. If this is a
313/// problem, implement `AsLmdbBytes` and `FromLmdbBytes` manually and check for
314/// validity. Of particular note, `bool` and essentially all `enum` types are
315/// not sensible for use with `LmdbRaw` (directly or within composites) because
316/// they are only valid for particular bit patterns.
317///
318/// ## Warnings about inner padding
319///
320/// Use of this trait on a struct that is not `#[repr(packed)]` makes it
321/// possible to observe the normally unobservable padding bytes inserted into
322/// the structure to satisfy type alignment.
323///
324/// When simply using these structures as values in a non-`DUPSORT` database,
325/// this simply means some arbitrary extra bytes get written with the values.
326/// This is not going to be a problem unless you plan on sharing the databases
327/// with untrusted third parties (which could leak sensitive information) or do
328/// unusual things with type punning.
329///
330/// However, in any context where values need to be compared (ie, keys, and
331/// values in `DUPSORT` databases), these padding bytes now count towards the
332/// comparison by default. Since the padding contains unpredictable values, you
333/// can easily end up with multiple "identical" keys that differ in their
334/// padding bytes, fail to find values you know are in the database because of
335/// differences in padding values, etc.
336///
337/// One way to deal with both problems is to use `#[repr(packed)]` (in addition
338/// to `#[repr(C)]` which keeps the field order defined across Rust versions),
339/// which simply eliminates the padding bytes altogether. Note that due to a
340/// bug in the Rust compiler, [packed structures can lead to undefined
341/// behaviour in "safe Rust"](https://github.com/rust-lang/rust/issues/27060).
342/// Until that issue is fixed, you should be careful about using
343/// `#[repr(packed)]` for this purpose unless all fields in the struct have the
344/// same size or you understand the ABI(s) you care about well enough to know
345/// whether misalignment will cause issues.
346///
347/// You can alternatively opt to live with the padding bytes, but additionally
348/// implement `LmdbOrdKey` on the type, and then use
349/// `DatabaseOptions::sort_keys_as` or `DatabaseOptions::sort_values_as`
350/// appropriately to use the generated comparison function. As a result, the
351/// padding bytes will be ignored for comparison purposes, but will nontheless
352/// be written into the database and thus remain visible to puns and could leak
353/// information.
354///
355/// ## Example
356///
357/// ```
358/// use lmdb_zero::traits::*;
359///
360/// #[repr(C)]
361/// #[derive(Clone,Copy,Debug)]
362/// struct MyStruct {
363///   foo: i16,
364///   // See warning about alignment/padding above!
365///   // On AMD64, for example, we get 6 padding bytes here.
366///   bar: u64,
367/// }
368/// unsafe impl LmdbRaw for MyStruct { }
369/// ```
370pub unsafe trait LmdbRaw : Copy + Sized {
371    /// Returns the name of this type to report in error messages.
372    ///
373    /// If not implemented, defaults to `"?"`.
374    fn reported_type() -> String {
375        "?".to_owned()
376    }
377}
378
379/// Marker trait for types where `Unaligned<T>` is `LmdbRaw`.
380///
381/// This has all the implications as `LmdbRaw`, except that blanket
382/// implementations around the bare type are not available. This forces the
383/// client code to wrap the type in `Unaligned` to explicitly handle possible
384/// misalignment.
385///
386/// All integer and floating-point types have this trait.
387///
388/// Note that `LmdbRawIfUnaligned` is not blanket-implemented for fixed-size
389/// arrays, because currently doing so would preclude a blanket implementation
390/// of `LmdbRaw` for fixed-size arrays. Since the latter is generally more
391/// useful and is more consistent since variable-length slices can only
392/// usefully interact with `LmdbRaw`, that approach was chosen.
393///
394/// All `LmdbRaw` types are `LmdbRawIfUnaligned`.
395pub unsafe trait LmdbRawIfUnaligned : Copy + Sized {
396    /// Returns the name of this type to report in error messages.
397    ///
398    /// If not implemented, defaults to `"?"`.
399    fn reported_type() -> String {
400        "?".to_owned()
401    }
402}
403
404unsafe impl<T : LmdbRaw> LmdbRawIfUnaligned for T {
405    fn reported_type() -> String {
406        <T as LmdbRaw>::reported_type()
407    }
408}
409
410/// Trait describing a value which can be used as an LMDB key by having LMDB
411/// call into the value's `Ord` implementation.
412///
413/// ## Unsafety
414///
415/// Behaviour is undefined if the `FromLmdbBytes` or `Ord` implementations
416/// panic.
417pub unsafe trait LmdbOrdKey : FromLmdbBytes + Ord {
418    /// Returns whether the default LMDB byte-by-byte comparison is correct for
419    /// valid values of this type.
420    ///
421    /// Generally, one should not specifically use
422    /// `DatabaseOptions::sort_values_as` and so forth for types where this is
423    /// the case. This function exists to support generic code wishing to avoid
424    /// the conversion overhead when the types happen to already be
425    /// byte-comparable.
426    ///
427    /// Note that if this returns true, that does _not_ mean that byte
428    /// comparison is exactly equivalent to `Ord`-based comparison. For
429    /// example, invalid `str` instances sort before valid ones and are equal
430    /// to each other, but byte comparison will intermingle them. Because of
431    /// this, `DatabaseOptions::sort_values_as` and similar do not make
432    /// decisions based on this value; it is the client code's responsibility
433    /// to use this if so desired.
434    ///
435    /// ## Example
436    /// ```
437    /// # use lmdb_zero::traits::LmdbOrdKey;
438    /// assert!(<u8 as LmdbOrdKey>::ordered_by_bytes());
439    /// assert!(!<i8 as LmdbOrdKey>::ordered_by_bytes());
440    /// assert!(<str as LmdbOrdKey>::ordered_by_bytes());
441    /// assert!(<[u8] as LmdbOrdKey>::ordered_by_bytes());
442    /// assert!(!<[i8] as LmdbOrdKey>::ordered_by_bytes());
443    /// ```
444    fn ordered_by_bytes() -> bool { false }
445
446    /// Returns whether LMDB will correctly handle this value with the
447    /// `INTEGERKEY` or `INTEGERDUP` flags.
448    ///
449    /// There's generally no reason to use `sort_keys_as` and so forth with
450    /// values where this is true instead of using the appropriate flags. This
451    /// function exists to support generic code which wants to make such
452    /// decisions automatically.
453    fn ordered_as_integer() -> bool { false }
454}
455
456/// Marker trait for types where `Unaligned<T>` is `LmdbOrdKey`.
457///
458/// All `LmdbOrdKey + LmdbRaw` are `LmdbOrdKeyIfUnaligned`.
459///
460/// ## Unsafety
461///
462/// Behaviour is undefined if the `FromLmdbBytes` or `Ord` implementations
463/// panic.
464pub unsafe trait LmdbOrdKeyIfUnaligned : LmdbRawIfUnaligned + Ord {
465    /// Like `LmdbOrdKey::ordered_by_bytes()`
466    fn ordered_by_bytes() -> bool { false }
467    /// Like `LmdbOrdKey::ordered_as_integer()`
468    fn ordered_as_integer() -> bool { false }
469}
470
471unsafe impl<T : LmdbRaw + LmdbOrdKey> LmdbOrdKeyIfUnaligned for T {
472    fn ordered_by_bytes() -> bool {
473        <T as LmdbOrdKey>::ordered_by_bytes()
474    }
475
476    fn ordered_as_integer() -> bool {
477        <T as LmdbOrdKey>::ordered_as_integer()
478    }
479}
480
481macro_rules! raw {
482    ($typ:ident) => {
483        unsafe impl LmdbRawIfUnaligned for $typ {
484            fn reported_type() -> String {
485                stringify!($typ).to_owned()
486            }
487        }
488        impl AsLmdbBytes for $typ {
489            fn as_lmdb_bytes(&self) -> &[u8] {
490                unsafe {
491                    slice::from_raw_parts(
492                        self as *const $typ as *const u8,
493                        mem::size_of::<$typ>())
494                }
495            }
496        }
497        impl AsLmdbBytes for [$typ] {
498            fn as_lmdb_bytes(&self) -> &[u8] {
499                unsafe {
500                    slice::from_raw_parts(
501                        self.as_ptr() as *const u8,
502                        self.len() * mem::size_of::<$typ>())
503                }
504            }
505        }
506    };
507
508    ($typ:ident, Ord) => {
509        raw!($typ);
510        unsafe impl LmdbOrdKeyIfUnaligned for $typ { }
511    };
512
513    ($typ:ident, Int) => {
514        raw!($typ);
515        unsafe impl LmdbOrdKeyIfUnaligned for $typ {
516            fn ordered_as_integer() -> bool { true }
517        }
518    };
519}
520
521unsafe impl LmdbRaw for u8 {
522    fn reported_type() -> String {
523        "u8".to_owned()
524    }
525}
526unsafe impl LmdbOrdKey for u8 {
527    fn ordered_by_bytes() -> bool { true }
528}
529unsafe impl LmdbRaw for i8 {
530    fn reported_type() -> String {
531        "i8".to_owned()
532    }
533}
534unsafe impl LmdbOrdKey for i8 { }
535raw!(u16, Ord);
536raw!(i16, Ord);
537raw!(u32, Int);
538raw!(i32, Ord);
539raw!(u64, Ord);
540raw!(i64, Ord);
541raw!(f32);
542raw!(f64);
543
544macro_rules! raw_array {
545    ($n:expr) => {
546        unsafe impl<V : LmdbRaw> LmdbRaw for [V;$n] {
547            fn reported_type() -> String {
548                format!("[{};{}]", V::reported_type(), $n)
549            }
550        }
551        unsafe impl<V : LmdbOrdKey + LmdbRaw> LmdbOrdKey for [V;$n] {
552            fn ordered_by_bytes() -> bool { V::ordered_by_bytes() }
553        }
554    }
555}
556raw_array!(0);
557raw_array!(1);
558raw_array!(2);
559raw_array!(3);
560raw_array!(4);
561raw_array!(5);
562raw_array!(6);
563raw_array!(7);
564raw_array!(8);
565raw_array!(9);
566raw_array!(10);
567raw_array!(11);
568raw_array!(12);
569raw_array!(13);
570raw_array!(14);
571raw_array!(15);
572raw_array!(16);
573raw_array!(17);
574raw_array!(18);
575raw_array!(19);
576raw_array!(20);
577raw_array!(21);
578raw_array!(22);
579raw_array!(23);
580raw_array!(24);
581raw_array!(25);
582raw_array!(26);
583raw_array!(27);
584raw_array!(28);
585raw_array!(29);
586raw_array!(30);
587raw_array!(31);
588raw_array!(32);
589
590unsafe impl<V: LmdbRawIfUnaligned> LmdbRawIfUnaligned for Wrapping<V> {
591    fn reported_type() -> String {
592        format!("Wrapping<{}>", V::reported_type())
593    }
594}
595unsafe impl<V: LmdbOrdKeyIfUnaligned> LmdbOrdKeyIfUnaligned for Wrapping<V> {
596    fn ordered_by_bytes() -> bool { V::ordered_by_bytes() }
597}
598
599unsafe impl LmdbRaw for () { }
600
601impl<V : LmdbRaw> AsLmdbBytes for V {
602    fn as_lmdb_bytes(&self) -> &[u8] {
603        unsafe {
604            slice::from_raw_parts(
605                self as *const V as *const u8, mem::size_of::<V>())
606        }
607    }
608}
609
610impl<V: LmdbRaw> FromLmdbBytes for V {
611    fn from_lmdb_bytes(bytes: &[u8]) -> Result<&Self, String> {
612        let size = mem::size_of::<V>();
613        let align = mem::align_of::<V>();
614
615        if bytes.len() != size {
616            return Err(
617                format!("Type {} is size {}, but byte array has size {}",
618                        V::reported_type(), size, bytes.len()));
619        }
620
621        let misalign = (bytes.as_ptr() as usize) % align;
622        if 0 != misalign {
623            return Err(
624                format!("Type {} requires alignment {}, but byte array \
625                         at {:08x} is misaligned by {} bytes \
626                         (see https://docs.rs/lmdb-zero/{}/\
627                         lmdb_zero/traits/trait.LmdbRaw.html#alignment)",
628                        V::reported_type(), align,
629                        (bytes.as_ptr() as usize), misalign,
630                        env!("CARGO_PKG_VERSION")));
631        }
632
633        Ok(unsafe {
634            mem::transmute(bytes.as_ptr())
635        })
636    }
637}
638
639impl<V : LmdbRaw> FromReservedLmdbBytes for V {
640    unsafe fn from_reserved_lmdb_bytes(bytes: &mut [u8]) -> &mut Self {
641        mem::transmute(bytes.as_ptr())
642    }
643}
644
645impl<V : LmdbRaw> AsLmdbBytes for [V] {
646    fn as_lmdb_bytes(&self) -> &[u8] {
647        unsafe {
648            slice::from_raw_parts(
649                self.as_ptr() as *const u8,
650                self.len() * mem::size_of::<V>())
651        }
652    }
653}
654
655impl<V : LmdbRaw> FromLmdbBytes for [V] {
656    fn from_lmdb_bytes(bytes: &[u8]) -> Result<&Self, String> {
657        let size = mem::size_of::<V>();
658        let align = mem::align_of::<V>();
659
660        let size_mod = bytes.len() % size;
661        if 0 != size_mod {
662            return Err(
663                format!("Type [{}] must have a size which is a multiple \
664                         of {}, but byte array has size {} ({} trailing bytes)",
665                        V::reported_type(), size, bytes.len(), size_mod));
666        }
667
668        let misalign = (bytes.as_ptr() as usize) % align;
669        if 0 != misalign {
670            return Err(
671                format!("Type [{}] requires alignment {}, but byte array \
672                         at {:08x} is misaligned by {} bytes \
673                         (see https://docs.rs/lmdb-zero/{}/\
674                         lmdb_zero/traits/trait.LmdbRaw.html#alignment)",
675                        V::reported_type(), align,
676                        (bytes.as_ptr() as usize), misalign,
677                        env!("CARGO_PKG_VERSION")));
678        }
679
680        unsafe {
681            Ok(slice::from_raw_parts(
682                bytes.as_ptr() as *const V,
683                bytes.len() / size))
684        }
685    }
686}
687
688impl<V : LmdbRaw> FromReservedLmdbBytes for [V] {
689    unsafe fn from_reserved_lmdb_bytes(bytes: &mut [u8]) -> &mut Self {
690        slice::from_raw_parts_mut(
691            bytes.as_ptr() as *mut V,
692            bytes.len() / mem::size_of::<V>())
693    }
694}
695
696unsafe impl<V : LmdbOrdKey + LmdbRaw> LmdbOrdKey for [V] {
697    fn ordered_by_bytes() -> bool { V::ordered_by_bytes() }
698}
699
700impl AsLmdbBytes for CStr {
701    /// Returns the raw content of the `CStr`, including the trailing NUL.
702    fn as_lmdb_bytes(&self) -> &[u8] {
703        self.to_bytes_with_nul()
704    }
705}
706
707impl FromLmdbBytes for CStr {
708    /// Directly converts the byte slice into a `CStr`, including a
709    /// required trailing NUL.
710    fn from_lmdb_bytes(bytes: &[u8]) -> Result<&Self, String> {
711        CStr::from_bytes_with_nul(bytes).map_err(
712            |_| "NUL byte in CString value".to_owned())
713    }
714}
715
716unsafe impl LmdbOrdKey for CStr {
717    fn ordered_by_bytes() -> bool { true }
718}
719
720impl AsLmdbBytes for str {
721    fn as_lmdb_bytes(&self) -> &[u8] {
722        self.as_bytes()
723    }
724}
725
726impl FromLmdbBytes for str {
727    fn from_lmdb_bytes(bytes: &[u8]) -> Result<&str, String> {
728        str::from_utf8(bytes).map_err(
729            |_| "String is not valid UTF-8".to_owned())
730    }
731}
732
733unsafe impl LmdbOrdKey for str {
734    fn ordered_by_bytes() -> bool { true }
735}
736
737impl<V : LmdbRaw> AsLmdbBytes for Vec<V> {
738    fn as_lmdb_bytes(&self) -> &[u8] {
739        &self[..].as_lmdb_bytes()
740    }
741}
742
743static IGNORE: Ignore = Ignore;
744
745impl FromLmdbBytes for Ignore {
746    fn from_lmdb_bytes(_: &[u8]) -> Result<&Ignore, String> {
747        Ok(&IGNORE)
748    }
749}
750
751impl AsLmdbBytes for char {
752    fn as_lmdb_bytes(&self) -> &[u8] {
753        unsafe {
754            slice::from_raw_parts(
755                self as *const char as *const u8,
756                mem::size_of::<char>())
757        }
758    }
759}
760
761impl AsLmdbBytes for [char] {
762    fn as_lmdb_bytes(&self) -> &[u8] {
763        unsafe {
764            slice::from_raw_parts(
765                self.as_ptr() as *const u8,
766                self.len() * mem::size_of::<char>())
767        }
768    }
769}