use std::borrow::Cow;
use std::ops::Range;
use std::sync::Arc;
use pigeonhole_engine::{CellData, FamilyId, TableInfo, ValueRef};
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Value<'a> {
Bytes(&'a [u8]),
I64(i64),
F64(f64),
Varint(i64),
}
#[inline]
fn payload(data: &CellData) -> &[u8] {
data.stored().get(1..).unwrap_or_default()
}
fn typed(data: &CellData) -> Value<'_> {
match data.value() {
ValueRef::Bytes(b) => Value::Bytes(b),
ValueRef::I64(v) => Value::I64(v),
ValueRef::F64(v) => Value::F64(v),
ValueRef::Varint(v) => Value::Varint(v),
ValueRef::Blob(_) => Value::Bytes(&[]),
}
}
fn as_i64(data: &CellData) -> Option<i64> {
match data.value() {
ValueRef::I64(v) | ValueRef::Varint(v) => Some(v),
_ => None,
}
}
#[derive(Debug, Clone)]
pub struct CellRef<'a> {
data: Cow<'a, CellData>,
}
impl<'a> CellRef<'a> {
#[inline]
pub(crate) fn owned(data: CellData) -> Self {
Self {
data: Cow::Owned(data),
}
}
pub(crate) fn borrowed(data: &'a CellData) -> Self {
Self {
data: Cow::Borrowed(data),
}
}
#[inline]
pub fn value(&self) -> &[u8] {
payload(&self.data)
}
pub fn typed(&self) -> Value<'_> {
typed(&self.data)
}
pub fn as_i64(&self) -> Option<i64> {
as_i64(&self.data)
}
pub fn timestamp(&self) -> u64 {
self.data.timestamp()
}
pub fn to_owned(&self) -> Cell {
Cell {
data: CellData::clone(&self.data),
}
}
}
#[derive(Debug, Clone)]
pub struct Cell {
data: CellData,
}
impl Cell {
#[inline]
pub fn value(&self) -> &[u8] {
payload(&self.data)
}
pub fn typed(&self) -> Value<'_> {
typed(&self.data)
}
pub fn as_i64(&self) -> Option<i64> {
as_i64(&self.data)
}
pub fn timestamp(&self) -> u64 {
self.data.timestamp()
}
}
#[derive(Debug, Clone)]
pub struct CellEntry<'a> {
pub family: &'a str,
pub qualifier: &'a [u8],
pub cell: CellRef<'a>,
}
#[derive(Debug, Clone)]
pub(crate) struct RowCell {
family: usize,
qualifier: Range<usize>,
cell: Cell,
}
#[derive(Debug, Clone, Default)]
pub(crate) struct RowBuf {
pub(crate) info: Option<Arc<TableInfo>>,
pub(crate) key: Vec<u8>,
pub(crate) qualifiers: Vec<u8>,
cells: Vec<RowCell>,
last_family: Option<(FamilyId, usize)>,
}
impl pigeonhole_engine::RowSink for RowBuf {
fn qualifiers(&mut self) -> &mut Vec<u8> {
&mut self.qualifiers
}
fn push(&mut self, family: FamilyId, qualifier: Range<usize>, data: CellData) {
RowBuf::push(self, family, qualifier, data);
}
#[inline]
fn push_inline(&mut self, family: FamilyId, qualifier: Range<usize>, ts: u64, stored: &[u8]) {
let family = self.family_index(family);
self.cells.push(RowCell {
family,
qualifier,
cell: Cell {
data: CellData::EMPTY,
},
});
if let Some(c) = self.cells.last_mut() {
c.cell.data.set_inline(ts, stored);
}
}
}
impl RowBuf {
pub(crate) fn new(info: Arc<TableInfo>, cells: usize) -> Self {
Self {
info: Some(info),
cells: Vec::with_capacity(cells),
..Self::default()
}
}
pub(crate) fn empty_like(&self) -> Self {
Self {
info: self.info.clone(),
key: Vec::with_capacity(self.key.len()),
qualifiers: Vec::with_capacity(self.qualifiers.len()),
cells: Vec::with_capacity(self.cells.len()),
last_family: self.last_family,
}
}
pub(crate) fn clear(&mut self) {
self.key.clear();
self.qualifiers.clear();
self.cells.clear();
}
pub(crate) fn len(&self) -> usize {
self.cells.len()
}
pub(crate) fn push(&mut self, family: FamilyId, qualifier: Range<usize>, data: CellData) {
let family = self.family_index(family);
self.cells.push(RowCell {
family,
qualifier,
cell: Cell { data },
});
}
fn family_index(&mut self, id: FamilyId) -> usize {
if let Some((last, i)) = self.last_family
&& last == id
{
return i;
}
let i = self
.info
.as_deref()
.and_then(|info| info.families.iter().position(|f| f.id == id))
.unwrap_or(usize::MAX);
self.last_family = Some((id, i));
i
}
fn family_name(&self, i: usize) -> &str {
self.info
.as_deref()
.and_then(|info| info.families.get(i))
.map_or("", |f| f.name.as_str())
}
fn qualifier(&self, cell: &RowCell) -> &[u8] {
&self.qualifiers[cell.qualifier.clone()]
}
fn entry(&self, i: usize) -> Option<(&str, &[u8], &Cell)> {
let c = self.cells.get(i)?;
Some((self.family_name(c.family), self.qualifier(c), &c.cell))
}
fn get(&self, family: &str, qualifier: &[u8]) -> Option<&Cell> {
let i = self
.info
.as_deref()?
.families
.iter()
.position(|f| f.name == family)?;
self.cells
.iter()
.find(|c| c.family == i && self.qualifier(c) == qualifier)
.map(|c| &c.cell)
}
}
#[derive(Debug, Clone)]
enum RowSrc<'a> {
Owned(Arc<RowBuf>),
Borrowed(&'a RowBuf),
}
#[derive(Debug, Clone)]
pub struct RowRef<'a> {
src: RowSrc<'a>,
}
impl<'a> RowRef<'a> {
pub(crate) fn owned(buf: RowBuf) -> Self {
Self {
src: RowSrc::Owned(Arc::new(buf)),
}
}
pub(crate) fn borrowed(buf: &'a RowBuf) -> Self {
Self {
src: RowSrc::Borrowed(buf),
}
}
fn buf(&self) -> &RowBuf {
match &self.src {
RowSrc::Owned(b) => b,
RowSrc::Borrowed(b) => b,
}
}
pub fn key(&self) -> &[u8] {
&self.buf().key
}
pub fn len(&self) -> usize {
self.buf().len()
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn entry(&self, i: usize) -> Option<CellEntry<'_>> {
let (family, qualifier, cell) = self.buf().entry(i)?;
Some(CellEntry {
family,
qualifier,
cell: CellRef::borrowed(&cell.data),
})
}
pub fn iter(&self) -> impl Iterator<Item = CellEntry<'_>> + '_ {
(0..self.len()).filter_map(move |i| self.entry(i))
}
pub fn get(&self, family: &str, qualifier: &[u8]) -> Option<CellRef<'_>> {
self.buf()
.get(family, qualifier)
.map(|c| CellRef::borrowed(&c.data))
}
pub fn to_owned(&self) -> Row {
let buf = match &self.src {
RowSrc::Owned(b) => Arc::clone(b),
RowSrc::Borrowed(b) => Arc::new(RowBuf::clone(b)),
};
Row { buf }
}
}
#[derive(Debug, Clone)]
pub struct Row {
buf: Arc<RowBuf>,
}
impl Row {
pub(crate) fn new(buf: RowBuf) -> Self {
Self { buf: Arc::new(buf) }
}
pub fn key(&self) -> &[u8] {
&self.buf.key
}
pub fn len(&self) -> usize {
self.buf.len()
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn entry(&self, i: usize) -> Option<(&str, &[u8], &Cell)> {
self.buf.entry(i)
}
pub fn get(&self, family: &str, qualifier: &[u8]) -> Option<&Cell> {
self.buf.get(family, qualifier)
}
pub fn view(&self) -> RowRef<'_> {
RowRef::borrowed(&self.buf)
}
}