use std::ops::Deref;
use std::sync::Arc;
use memmap2::Mmap;
#[derive(Debug)]
pub struct ValueRef {
repr: Repr,
}
#[derive(Debug)]
enum Repr {
Mmap {
mmap: Arc<Mmap>,
range: std::ops::Range<usize>,
},
#[allow(dead_code)]
Owned(Vec<u8>),
}
impl ValueRef {
pub(crate) fn from_mmap(mmap: Arc<Mmap>, range: std::ops::Range<usize>) -> Self {
debug_assert!(range.end <= mmap.len(), "ValueRef range past mmap end");
Self {
repr: Repr::Mmap { mmap, range },
}
}
#[allow(dead_code)]
pub(crate) fn from_owned(bytes: Vec<u8>) -> Self {
Self {
repr: Repr::Owned(bytes),
}
}
#[must_use]
pub fn len(&self) -> usize {
match &self.repr {
Repr::Mmap { range, .. } => range.end - range.start,
Repr::Owned(v) => v.len(),
}
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
#[must_use]
pub fn as_slice(&self) -> &[u8] {
match &self.repr {
Repr::Mmap { mmap, range } => &mmap[range.clone()],
Repr::Owned(v) => v.as_slice(),
}
}
#[must_use]
pub fn into_vec(self) -> Vec<u8> {
match self.repr {
Repr::Owned(v) => v,
Repr::Mmap { mmap, range } => mmap[range].to_vec(),
}
}
}
impl Deref for ValueRef {
type Target = [u8];
fn deref(&self) -> &[u8] {
self.as_slice()
}
}
impl AsRef<[u8]> for ValueRef {
fn as_ref(&self) -> &[u8] {
self.as_slice()
}
}
impl PartialEq for ValueRef {
fn eq(&self, other: &Self) -> bool {
self.as_slice() == other.as_slice()
}
}
impl Eq for ValueRef {}
impl PartialEq<[u8]> for ValueRef {
fn eq(&self, other: &[u8]) -> bool {
self.as_slice() == other
}
}
impl PartialEq<&[u8]> for ValueRef {
fn eq(&self, other: &&[u8]) -> bool {
self.as_slice() == *other
}
}
impl PartialEq<Vec<u8>> for ValueRef {
fn eq(&self, other: &Vec<u8>) -> bool {
self.as_slice() == other.as_slice()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn owned_round_trips_bytes_unchanged() {
let v = ValueRef::from_owned(vec![1, 2, 3]);
assert_eq!(v.len(), 3);
assert!(!v.is_empty());
assert_eq!(v.as_slice(), &[1, 2, 3]);
assert_eq!(&*v, &[1, 2, 3][..]);
assert_eq!(v.into_vec(), vec![1, 2, 3]);
}
#[test]
fn empty_owned_reports_empty() {
let v = ValueRef::from_owned(Vec::new());
assert_eq!(v.len(), 0);
assert!(v.is_empty());
}
#[test]
fn equality_against_byte_slice() {
let v = ValueRef::from_owned(b"hello".to_vec());
let bytes: &[u8] = b"hello";
assert!(v == *bytes);
assert!(v == bytes);
assert!(v == b"hello".to_vec());
}
}