use std::collections::BTreeMap;
use crate::error::Error;
use crate::types::{Date, Duration, Timestamp};
use super::reader::{ArrayView, MapView};
use super::writer::{ArrayWriter, MapWriter, ValueWriter};
#[doc(hidden)]
pub trait RowValue {
type View<'a>;
const FIXED_SIZE: Option<usize>;
fn write(&self, writer: ValueWriter<'_, '_>) -> Result<(), Error>;
fn read<'a>(bytes: &'a [u8]) -> Result<Self::View<'a>, Error>;
fn is_null(&self) -> bool {
false
}
fn read_null<'a>() -> Result<Self::View<'a>, Error> {
Err(Error::invalid_data(
"null row value cannot be read as a non-optional type",
))
}
}
pub trait Row: RowValue {}
macro_rules! impl_fixed_row_value {
($ty:ty, $size:expr) => {
impl RowValue for $ty {
type View<'a> = Self;
const FIXED_SIZE: Option<usize> = Some($size);
#[inline(always)]
fn write(&self, writer: ValueWriter<'_, '_>) -> Result<(), Error> {
writer.write_bytes(&self.to_le_bytes())
}
#[inline(always)]
fn read(bytes: &[u8]) -> Result<Self, Error> {
Ok(Self::from_le_bytes(read_fixed(bytes)?))
}
}
};
}
impl RowValue for bool {
type View<'a> = Self;
const FIXED_SIZE: Option<usize> = Some(1);
#[inline(always)]
fn write(&self, writer: ValueWriter<'_, '_>) -> Result<(), Error> {
writer.write_bytes(&[u8::from(*self)])
}
#[inline(always)]
fn read(bytes: &[u8]) -> Result<Self, Error> {
match read_fixed::<1>(bytes)?[0] {
0 => Ok(false),
1 => Ok(true),
_ => Err(Error::invalid_data("row boolean must be encoded as 0 or 1")),
}
}
}
impl RowValue for i8 {
type View<'a> = Self;
const FIXED_SIZE: Option<usize> = Some(1);
#[inline(always)]
fn write(&self, writer: ValueWriter<'_, '_>) -> Result<(), Error> {
writer.write_bytes(&self.to_le_bytes())
}
#[inline(always)]
fn read(bytes: &[u8]) -> Result<Self, Error> {
Ok(Self::from_le_bytes(read_fixed(bytes)?))
}
}
impl_fixed_row_value!(i16, 2);
impl_fixed_row_value!(i32, 4);
impl_fixed_row_value!(i64, 8);
impl_fixed_row_value!(f32, 4);
impl_fixed_row_value!(f64, 8);
impl RowValue for String {
type View<'a> = &'a str;
const FIXED_SIZE: Option<usize> = None;
#[inline(always)]
fn write(&self, writer: ValueWriter<'_, '_>) -> Result<(), Error> {
writer.write_bytes(self.as_bytes())
}
#[inline]
fn read(bytes: &[u8]) -> Result<&str, Error> {
std::str::from_utf8(bytes).map_err(|_| Error::invalid_data("invalid UTF-8 in row string"))
}
}
impl RowValue for &str {
type View<'a> = &'a str;
const FIXED_SIZE: Option<usize> = None;
#[inline(always)]
fn write(&self, writer: ValueWriter<'_, '_>) -> Result<(), Error> {
writer.write_bytes(self.as_bytes())
}
#[inline]
fn read(bytes: &[u8]) -> Result<&str, Error> {
std::str::from_utf8(bytes).map_err(|_| Error::invalid_data("invalid UTF-8 in row string"))
}
}
impl RowValue for Vec<u8> {
type View<'a> = &'a [u8];
const FIXED_SIZE: Option<usize> = None;
#[inline(always)]
fn write(&self, writer: ValueWriter<'_, '_>) -> Result<(), Error> {
writer.write_bytes(self)
}
#[inline(always)]
fn read(bytes: &[u8]) -> Result<&[u8], Error> {
Ok(bytes)
}
}
impl RowValue for &[u8] {
type View<'a> = &'a [u8];
const FIXED_SIZE: Option<usize> = None;
#[inline(always)]
fn write(&self, writer: ValueWriter<'_, '_>) -> Result<(), Error> {
writer.write_bytes(self)
}
#[inline(always)]
fn read(bytes: &[u8]) -> Result<&[u8], Error> {
Ok(bytes)
}
}
impl<T: RowValue> RowValue for Option<T> {
type View<'a> = Option<T::View<'a>>;
const FIXED_SIZE: Option<usize> = T::FIXED_SIZE;
#[inline(always)]
fn write(&self, writer: ValueWriter<'_, '_>) -> Result<(), Error> {
match self {
Some(value) => value.write(writer),
None => Err(Error::invalid_data(
"a null row value must be written by its container",
)),
}
}
#[inline(always)]
fn read<'a>(bytes: &'a [u8]) -> Result<Self::View<'a>, Error> {
T::read(bytes).map(Some)
}
#[inline(always)]
fn is_null(&self) -> bool {
self.is_none()
}
#[inline(always)]
fn read_null<'a>() -> Result<Self::View<'a>, Error> {
Ok(None)
}
}
impl RowValue for Date {
type View<'a> = Self;
const FIXED_SIZE: Option<usize> = Some(4);
fn write(&self, writer: ValueWriter<'_, '_>) -> Result<(), Error> {
let days = i32::try_from(self.epoch_days()).map_err(|_| {
Error::invalid_data(format!(
"row date day count {} exceeds date32 range",
self.epoch_days()
))
})?;
writer.write_bytes(&days.to_le_bytes())
}
fn read(bytes: &[u8]) -> Result<Self, Error> {
let days = i32::from_le_bytes(read_fixed(bytes)?);
Ok(Date::from_epoch_days(i64::from(days)))
}
}
impl RowValue for Timestamp {
type View<'a> = Self;
const FIXED_SIZE: Option<usize> = Some(8);
fn write(&self, writer: ValueWriter<'_, '_>) -> Result<(), Error> {
writer.write_bytes(&self.to_epoch_micros()?.to_le_bytes())
}
fn read(bytes: &[u8]) -> Result<Self, Error> {
Ok(Timestamp::from_epoch_micros(i64::from_le_bytes(
read_fixed(bytes)?,
)))
}
}
impl RowValue for Duration {
type View<'a> = Self;
const FIXED_SIZE: Option<usize> = Some(8);
fn write(&self, writer: ValueWriter<'_, '_>) -> Result<(), Error> {
writer.write_bytes(&self.to_micros()?.to_le_bytes())
}
fn read(bytes: &[u8]) -> Result<Self, Error> {
Ok(Duration::from_micros(i64::from_le_bytes(read_fixed(
bytes,
)?)))
}
}
impl<T: RowValue, const N: usize> RowValue for [T; N] {
type View<'a> = ArrayView<'a, T>;
const FIXED_SIZE: Option<usize> = None;
fn write(&self, writer: ValueWriter<'_, '_>) -> Result<(), Error> {
let mut array_writer = ArrayWriter::<T>::new(N, writer.into_variable()?)?;
for (index, value) in self.iter().enumerate() {
array_writer.write(index, value)?;
}
Ok(())
}
fn read(bytes: &[u8]) -> Result<Self::View<'_>, Error> {
let view = ArrayView::new(bytes)?;
if view.len() != N {
return Err(Error::invalid_data(format!(
"row fixed array expected {N} elements, found {}",
view.len()
)));
}
Ok(view)
}
}
impl<T: RowValue, const N: usize> Row for [T; N] {}
impl<T: RowValue> RowValue for Vec<T> {
type View<'a> = ArrayView<'a, T>;
const FIXED_SIZE: Option<usize> = None;
fn write(&self, writer: ValueWriter<'_, '_>) -> Result<(), Error> {
let mut array_writer = ArrayWriter::<T>::new(self.len(), writer.into_variable()?)?;
for (index, value) in self.iter().enumerate() {
array_writer.write(index, value)?;
}
Ok(())
}
fn read(bytes: &[u8]) -> Result<Self::View<'_>, Error> {
ArrayView::new(bytes)
}
}
impl<T: RowValue> Row for Vec<T> {}
impl<K, V> RowValue for BTreeMap<K, V>
where
K: RowValue + Ord,
V: RowValue,
{
type View<'a> = MapView<'a, K, V>;
const FIXED_SIZE: Option<usize> = None;
fn write(&self, writer: ValueWriter<'_, '_>) -> Result<(), Error> {
let mut map_writer = MapWriter::new(writer.into_variable()?);
map_writer.write(self)
}
fn read(bytes: &[u8]) -> Result<Self::View<'_>, Error> {
MapView::new(bytes)
}
}
impl<K, V> Row for BTreeMap<K, V>
where
K: RowValue + Ord,
V: RowValue,
{
}
fn read_fixed<const N: usize>(bytes: &[u8]) -> Result<[u8; N], Error> {
if bytes.len() != N {
return Err(Error::invalid_data(format!(
"row fixed-width value expected {N} bytes, found {}",
bytes.len()
)));
}
let mut value = [0u8; N];
value.copy_from_slice(bytes);
Ok(value)
}