rust-rocksdb 0.52.0

Rust wrapper for Facebook's RocksDB embeddable database
Documentation
// Copyright 2020 Tyler Neely
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use crate::{DB, ffi};
use core::ops::Deref;
use libc::size_t;
use std::marker::PhantomData;
use std::slice;

/// Wrapper around RocksDB PinnableSlice struct.
///
/// With a pinnable slice, we can directly leverage in-memory data within
/// RocksDB to avoid unnecessary memory copies. The struct here wraps the
/// returned raw pointer and ensures proper finalization work.
pub struct DBPinnableSlice<'a> {
    ptr: *mut ffi::rocksdb_pinnableslice_t,
    // `(data, len)` are resolved once at construction rather than on every
    // deref. `rocksdb_pinnableslice_value` is an out-of-line C function that
    // only reads `rep.data()` / `rep.size()`, so calling it from `deref` meant
    // every `len()`, index, and `as_ref()` paid a cross-crate Rust call plus a
    // C call. The underlying `PinnableSlice` is not mutated after RocksDB hands
    // it back, so the pointer and length are stable for our lifetime.
    data: *const u8,
    len: usize,
    db: PhantomData<&'a DB>,
}

unsafe impl Send for DBPinnableSlice<'_> {}
unsafe impl Sync for DBPinnableSlice<'_> {}

impl AsRef<[u8]> for DBPinnableSlice<'_> {
    #[inline]
    fn as_ref(&self) -> &[u8] {
        // Implement this via Deref so as not to repeat ourselves
        self
    }
}

impl Deref for DBPinnableSlice<'_> {
    type Target = [u8];

    #[inline]
    fn deref(&self) -> &[u8] {
        if self.len == 0 {
            // An empty-but-present value can carry a null data pointer, and
            // `slice::from_raw_parts(null, 0)` is undefined behaviour.
            return &[];
        }
        // SAFETY: `data`/`len` were read from the pinned slice at construction
        // and describe memory kept alive by the pin until `Drop`.
        unsafe { slice::from_raw_parts(self.data, self.len) }
    }
}

impl Drop for DBPinnableSlice<'_> {
    fn drop(&mut self) {
        unsafe {
            ffi::rocksdb_pinnableslice_destroy(self.ptr);
        }
    }
}

impl DBPinnableSlice<'_> {
    /// Used to wrap a PinnableSlice from rocksdb to avoid unnecessary memcpy
    ///
    /// # Unsafe
    /// Requires that the pointer must be generated by rocksdb_get_pinned
    pub(crate) unsafe fn from_c(ptr: *mut ffi::rocksdb_pinnableslice_t) -> Self {
        let mut len: size_t = 0;
        // SAFETY: caller guarantees `ptr` is a live pinnable slice.
        let data = unsafe { ffi::rocksdb_pinnableslice_value(ptr, &raw mut len) }.cast::<u8>();
        Self {
            ptr,
            data,
            len,
            db: PhantomData,
        }
    }
}