use std::collections::HashMap;
use std::convert::TryFrom;
use std::ops::{Deref, Index};
use std::rc::Rc;
use crate::error::{Error, Result};
use crate::statement::{Bindable, State, Statement};
use crate::value::Value;
pub struct Cursor<'l, 'm> {
column_count: usize,
statement: &'m mut Statement<'l>,
}
pub struct CursorWithOwnership<'l> {
column_count: usize,
statement: Statement<'l>,
}
#[derive(Debug)]
pub struct Row {
column_mapping: Rc<HashMap<String, usize>>,
values: Vec<Value>,
}
pub trait RowIndex: std::fmt::Debug {
fn index(self, row: &Row) -> usize;
}
macro_rules! implement(
($type:ident<$($lifetime:lifetime),+>) => {
impl<$($lifetime),+> $type<$($lifetime),+> {
pub fn bind<T: Bindable>(self, value: T) -> Result<Self> {
#[allow(unused_mut)]
let mut cursor = self.reset()?;
cursor.statement.bind(value)?;
Ok(cursor)
}
#[allow(unused_mut)]
pub fn bind_iter<T, U>(self, value: T) -> Result<Self>
where
T: IntoIterator<Item = U>,
U: Bindable,
{
let mut cursor = self.reset()?;
cursor.statement.bind_iter(value)?;
Ok(cursor)
}
#[allow(unused_mut)]
pub fn reset(mut self) -> Result<Self> {
self.statement.reset()?;
Ok(self)
}
pub fn try_next(&mut self) -> Result<Option<Vec<Value>>> {
if self.statement.next()? == State::Done {
return Ok(None);
}
let mut values = Vec::with_capacity(self.column_count);
for index in 0..self.column_count {
values.push(self.statement.read(index)?);
}
Ok(Some(values))
}
}
impl<$($lifetime),+> Deref for $type<$($lifetime),+> {
type Target = Statement<'l>;
#[inline]
fn deref(&self) -> &Self::Target {
&self.statement
}
}
impl<$($lifetime),+> Iterator for $type<$($lifetime),+> {
type Item = Result<Row>;
fn next(&mut self) -> Option<Self::Item> {
let column_mapping = self.statement.column_mapping();
self.try_next()
.map(|values| {
values.map(|values| Row {
column_mapping,
values,
})
})
.transpose()
}
}
}
);
implement!(Cursor<'l, 'm>);
implement!(CursorWithOwnership<'l>);
impl<'l> From<CursorWithOwnership<'l>> for Statement<'l> {
#[inline]
fn from(cursor: CursorWithOwnership<'l>) -> Self {
cursor.statement
}
}
impl Row {
#[inline]
pub fn read<'l, T, U>(&'l self, column: U) -> T
where
T: TryFrom<&'l Value, Error = Error>,
U: RowIndex,
{
self.try_read(column).unwrap()
}
#[inline]
pub fn take<U>(&mut self, column: U) -> Value
where
U: RowIndex,
{
let index = column.index(self);
std::mem::take(&mut self.values[index])
}
#[inline]
pub fn try_read<'l, T, U>(&'l self, column: U) -> Result<T>
where
T: TryFrom<&'l Value, Error = Error>,
U: RowIndex,
{
T::try_from(&self.values[column.index(self)])
}
}
impl From<Row> for Vec<Value> {
#[inline]
fn from(row: Row) -> Self {
row.values
}
}
impl<T> Index<T> for Row
where
T: RowIndex,
{
type Output = Value;
fn index(&self, index: T) -> &Value {
&self.values[index.index(self)]
}
}
impl RowIndex for &str {
#[inline]
fn index(self, row: &Row) -> usize {
debug_assert!(
row.column_mapping.contains_key(self),
"the index is out of range",
);
row.column_mapping[self]
}
}
impl RowIndex for usize {
#[inline]
fn index(self, row: &Row) -> usize {
debug_assert!(self < row.values.len(), "the index is out of range");
self
}
}
pub fn new<'l, 'm>(statement: &'m mut Statement<'l>) -> Cursor<'l, 'm> {
Cursor {
column_count: statement.column_count(),
statement,
}
}
pub fn new_with_ownership(statement: Statement<'_>) -> CursorWithOwnership<'_> {
CursorWithOwnership {
column_count: statement.column_count(),
statement,
}
}