use crate::{
constants::type_,
decode::{Column, Decode},
package_parser::{DecodeError, DecodeResult, PackageParser},
};
pub struct Row<'a> {
columns: &'a [Column],
package: &'a [u8],
}
impl<'a> Row<'a> {
pub(crate) fn new(columns: &'a [Column], package: &'a [u8]) -> Self {
Self { columns, package }
}
pub fn parse(&self) -> RowParser<'a> {
let mut parser = PackageParser::new(self.package);
parser.get_u8().unwrap();
let nulls = parser.get_bytes((self.columns.len() + 7 + 2) / 8).unwrap();
RowParser {
columns: self.columns,
nulls,
parser,
idx: 0,
}
}
pub fn read<T: FromRow<'a>>(&self) -> DecodeResult<T> {
T::from_row(self)
}
}
pub struct RowParser<'a> {
idx: usize,
columns: &'a [Column],
nulls: &'a [u8],
parser: PackageParser<'a>,
}
impl<'a> RowParser<'a> {
pub fn get_next_column_info(&self) -> Option<&Column> {
self.columns.get(self.idx)
}
#[allow(clippy::should_implement_trait)]
#[inline]
pub fn next<T: Decode<'a>>(&mut self) -> DecodeResult<T> {
let idx = self.idx;
let c = self.columns.get(idx).ok_or(DecodeError::EndOfColumns)?;
let null = self.nulls[(idx + 2) / 8] & (1 << ((idx + 2) % 8)) != 0;
let v = T::decode(&mut self.parser, c, null)?;
self.idx += 1;
Ok(v)
}
#[inline]
pub fn skip(&mut self) -> DecodeResult<()> {
let idx = self.idx;
let c = self.columns.get(idx).ok_or(DecodeError::EndOfColumns)?;
let null = self.nulls[(idx + 2) / 8] & (1 << ((idx + 2) % 8)) != 0;
if !null {
match c.r#type {
type_::DECIMAL
| type_::NEW_DECIMAL
| type_::STRING
| type_::JSON
| type_::VAR_CHAR
| type_::ENUM
| type_::SET
| type_::TINY_BLOB
| type_::MEDIUM_BLOB
| type_::LONG_BLOB
| type_::BLOB
| type_::VAR_STRING
| type_::BIT
| type_::GEOMETRY => {
self.parser.skip_lenenc_str()?;
}
type_::TINY => self.parser.skip_bytes(1),
type_::SHORT | type_::YEAR => self.parser.skip_bytes(2),
type_::LONG | type_::FLOAT => self.parser.skip_bytes(4),
type_::LONG_LONG | type_::DOUBLE => self.parser.skip_bytes(8),
type_::TIMESTAMP | type_::DATE | type_::DATETIME | type_::TIME => {
let len = self.parser.get_u8()?;
self.parser.skip_bytes(len.into());
}
type_::INT24 => self.parser.skip_bytes(3),
_ => return Err(DecodeError::InvalidValue),
}
}
self.idx += 1;
Ok(())
}
}
pub trait FromRow<'r>: Sized {
fn from_row(row: &Row<'r>) -> DecodeResult<Self>;
}
macro_rules! impl_from_row_for_tuple {
($( $T:ident ,)+) => {
impl<'r, $($T,)+> FromRow<'r> for ($($T,)+)
where
$($T: crate::decode::Decode<'r>,)+
{
#[inline]
fn from_row(row: &Row<'r> ) -> DecodeResult<Self> {
let mut parser= row.parse();
Ok(
($(parser.next::<$T>()?,)+)
)
}
}
};
}
impl<'r> FromRow<'r> for () {
fn from_row(_: &Row<'r>) -> DecodeResult<Self> {
Ok(())
}
}
impl_from_row_for_tuple!(T1,);
impl_from_row_for_tuple!(T1, T2,);
impl_from_row_for_tuple!(T1, T2, T3,);
impl_from_row_for_tuple!(T1, T2, T3, T4,);
impl_from_row_for_tuple!(T1, T2, T3, T4, T5,);
impl_from_row_for_tuple!(T1, T2, T3, T4, T5, T6,);
impl_from_row_for_tuple!(T1, T2, T3, T4, T5, T6, T7,);
impl_from_row_for_tuple!(T1, T2, T3, T4, T5, T6, T7, T8,);
impl_from_row_for_tuple!(T1, T2, T3, T4, T5, T6, T7, T8, T9,);
impl_from_row_for_tuple!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10,);
impl_from_row_for_tuple!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,);
impl_from_row_for_tuple!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,);
impl_from_row_for_tuple!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,);
impl_from_row_for_tuple!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,);
impl_from_row_for_tuple!(
T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
);
impl_from_row_for_tuple!(
T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16,
);
impl_from_row_for_tuple!(
T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17,
);
impl_from_row_for_tuple!(
T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18,
);
impl_from_row_for_tuple!(
T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19,
);
impl_from_row_for_tuple!(
T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20,
);
impl_from_row_for_tuple!(
T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21,
);
impl_from_row_for_tuple!(
T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21,
T22,
);
impl_from_row_for_tuple!(
T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21,
T22, T23,
);
impl_from_row_for_tuple!(
T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21,
T22, T23, T24,
);
impl_from_row_for_tuple!(
T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21,
T22, T23, T24, T25,
);