use crate::{
codec::Decode,
database::{Database, Records},
misc::{Lease, into_rslt},
};
use alloc::boxed::Box;
use core::{fmt::Debug, iter};
#[derive(Debug)]
pub struct FromRecordsParams<R> {
pub consumed_records: usize,
pub curr_field_idx: usize,
pub curr_record: R,
pub curr_record_idx: usize,
pub is_in_one_relationship: bool,
}
impl<'exec, R> FromRecordsParams<R> {
fn init<D>(records: &D::Records<'exec>) -> Option<Self>
where
D: Database<Record<'exec> = R>,
{
Some(Self {
consumed_records: 0,
curr_field_idx: 0,
curr_record: records.get(0)?,
curr_record_idx: 0,
is_in_one_relationship: false,
})
}
pub const fn inc_consumed_records(&mut self, value: usize) {
self.consumed_records = self.consumed_records.wrapping_add(value);
}
pub const fn inc_field_idx(&mut self) {
self.curr_field_idx = self.curr_field_idx.wrapping_add(1);
}
pub const fn inc_record_idx(&mut self) {
self.curr_record_idx = self.curr_record_idx.wrapping_add(1);
}
}
pub trait FromRecords<'exec, D>: Sized
where
D: Database,
{
const FIELDS: u16;
const ID_IDX: Option<usize>;
type IdTy: Copy + Debug + Decode<'exec, D> + PartialEq;
fn from_records(
curr_params: &mut FromRecordsParams<D::Record<'exec>>,
records: &D::Records<'exec>,
) -> Result<Self, D::Error>;
#[inline]
fn many<R>(records: R) -> impl Iterator<Item = Result<Self, D::Error>>
where
R: Lease<D::Records<'exec>>,
{
let mut state = FromRecordsParams::init::<D>(records.lease()).map(|el| (el, records));
iter::from_fn(move || {
let (params, local_records) = state.as_mut()?;
let local_records_ref = local_records.lease();
let record = local_records_ref.get(params.consumed_records)?;
params.curr_field_idx = 0;
params.curr_record = record;
params.curr_record_idx = params.consumed_records;
let prev_consumed_records = params.consumed_records;
let rslt = Self::from_records(params, local_records_ref);
if prev_consumed_records == params.consumed_records {
return if rslt.is_err() { Some(rslt) } else { None };
}
Some(rslt)
})
}
#[inline]
fn single(records: &D::Records<'exec>) -> Result<Self, D::Error> {
Self::from_records(&mut into_rslt(FromRecordsParams::init::<D>(records))?, records)
}
}
impl<'exec, D> FromRecords<'exec, D> for ()
where
D: Database,
i32: Decode<'exec, D>,
{
const FIELDS: u16 = 0;
const ID_IDX: Option<usize> = None;
type IdTy = i32;
#[inline]
fn from_records(
_: &mut FromRecordsParams<D::Record<'exec>>,
_: &D::Records<'exec>,
) -> Result<Self, D::Error> {
Ok(())
}
}
impl<'exec, D, T> FromRecords<'exec, D> for Box<T>
where
D: Database,
T: FromRecords<'exec, D>,
{
const FIELDS: u16 = T::FIELDS;
const ID_IDX: Option<usize> = T::ID_IDX;
type IdTy = T::IdTy;
#[inline]
fn from_records(
curr_params: &mut FromRecordsParams<D::Record<'exec>>,
records: &D::Records<'exec>,
) -> Result<Self, D::Error> {
Ok(Box::new(T::from_records(curr_params, records)?))
}
}
impl<'exec, D, T> FromRecords<'exec, D> for Option<T>
where
D: Database,
T: FromRecords<'exec, D>,
{
const FIELDS: u16 = T::FIELDS;
const ID_IDX: Option<usize> = T::ID_IDX;
type IdTy = T::IdTy;
#[inline]
fn from_records(
curr_params: &mut FromRecordsParams<D::Record<'exec>>,
records: &D::Records<'exec>,
) -> Result<Self, D::Error> {
if records.len() == 0 { Ok(None) } else { Ok(Some(T::from_records(curr_params, records)?)) }
}
}