use crate::{FieldType, FieldValueError};
use std::iter::FusedIterator;
use std::ops::Range;
pub trait FieldMap<F> {
type Group: RepeatingGroup<Entry = Self>;
fn get_raw(&self, field: F) -> Option<&[u8]>;
fn group(
&self,
field: F,
) -> Result<Self::Group, FieldValueError<<usize as FieldType>::Error>>;
fn group_opt(
&self,
field: F,
) -> Result<Option<Self::Group>, <usize as FieldType>::Error> {
match self.group(field) {
Ok(group) => Ok(Some(group)),
Err(FieldValueError::Missing) => Ok(None),
Err(FieldValueError::Invalid(e)) => Err(e),
}
}
fn decode_field_internal<'a, V>(
&'a self,
field: F,
deserialize_fn: fn(&'a [u8]) -> Result<V, V::Error>,
) -> Result<Option<V>, V::Error>
where
V: FieldType<'a>,
{
self.get_raw(field).map(deserialize_fn).transpose()
}
fn get<'a, V>(&'a self, field: F) -> Result<V, FieldValueError<V::Error>>
where
V: FieldType<'a>,
{
self.decode_field_internal(field, V::deserialize)
.map_err(FieldValueError::Invalid)
.and_then(|opt| opt.ok_or(FieldValueError::Missing))
}
fn get_lossy<'a, V>(
&'a self,
field: F,
) -> Result<V, FieldValueError<V::Error>>
where
V: FieldType<'a>,
{
self.decode_field_internal(field, V::deserialize_lossy)
.map_err(FieldValueError::Invalid)
.and_then(|opt| opt.ok_or(FieldValueError::Missing))
}
fn get_opt<'a, V>(&'a self, field: F) -> Result<Option<V>, V::Error>
where
V: FieldType<'a>,
{
self.decode_field_internal(field, V::deserialize)
}
fn get_lossy_opt<'a, V>(&'a self, field: F) -> Result<Option<V>, V::Error>
where
V: FieldType<'a>,
{
self.decode_field_internal(field, V::deserialize_lossy)
}
}
pub trait RepeatingGroup: Sized {
type Entry;
fn len(&self) -> usize;
fn get(&self, i: usize) -> Option<Self::Entry>;
fn entries(&self) -> GroupEntries<Self> {
GroupEntries { group: self, range: 0..self.len() }
}
}
#[derive(Debug, Clone)]
pub struct GroupEntries<'a, G> {
group: &'a G,
range: Range<usize>,
}
impl<'a, G> Iterator for GroupEntries<'a, G>
where
G: RepeatingGroup,
{
type Item = G::Entry;
fn next(&mut self) -> Option<Self::Item> {
let i = self.range.next()?;
self.group.get(i)
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.range.size_hint()
}
}
impl<'a, G> FusedIterator for GroupEntries<'a, G> where G: RepeatingGroup {}
impl<'a, G> ExactSizeIterator for GroupEntries<'a, G> where G: RepeatingGroup {}
impl<'a, G> DoubleEndedIterator for GroupEntries<'a, G>
where
G: RepeatingGroup,
{
fn next_back(&mut self) -> Option<Self::Item> {
let i = self.range.next_back()?;
self.group.get(i)
}
}