// Copyright 2016 FullContact, Inc
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Internal helpers for working with `MDB_val`s.

use libc::{self, c_void};
use std::slice;

use crate::error::{Error, Result};
use crate::traits::{AsLmdbBytes, FromLmdbBytes, FromReservedLmdbBytes};

pub const EMPTY_VAL: liblmdb::MDB_val = liblmdb::MDB_val {
    mv_size: 0,
    mv_data: std::ptr::null_mut::<c_void>(),
};

pub fn as_val<V: AsLmdbBytes + ?Sized>(v: &V) -> liblmdb::MDB_val {
    let bytes = v.as_lmdb_bytes();
    liblmdb::MDB_val {
        mv_size: bytes.len() as libc::size_t,
        mv_data: bytes.as_ptr() as *mut c_void,
    }
}

pub fn mdb_val_as_bytes<'a, O>(_o: &'a O, val: &liblmdb::MDB_val) -> &'a [u8] {
    debug_assert!(
        !val.mv_data.is_null(),
        "MDB_val ptr is NULL, size = {}",
        val.mv_size
    );

    unsafe { slice::from_raw_parts(val.mv_data as *const u8, val.mv_size) }
}

pub fn from_val<'a, O, V: FromLmdbBytes + ?Sized>(
    owner: &'a O,
    val: &liblmdb::MDB_val,
) -> Result<&'a V> {
    let bytes = mdb_val_as_bytes(owner, val);
    V::from_lmdb_bytes(bytes).map_err(Error::ValRejected)
}

pub unsafe fn from_reserved<'a, O, V: FromReservedLmdbBytes + ?Sized>(
    _owner: &'a mut O,
    val: &mut liblmdb::MDB_val,
) -> &'a mut V {
    let bytes = slice::from_raw_parts_mut(val.mv_data.cast::<u8>(), val.mv_size);
    V::from_reserved_lmdb_bytes(bytes)
}
