use crate::Error;
use crate::wire::{Frame, Message, Packing, Writer};
use std::fmt::{self, Debug};
use std::marker::PhantomData;
pub trait List {
type Item;
fn len(&self) -> usize;
fn is_empty(&self) -> bool {
self.len() == 0
}
fn get(&self, index: usize) -> Option<Self::Item>;
fn iter(&self) -> ListIter<'_, Self>
where
Self: Sized,
{
ListIter {
list: self,
index: 0,
}
}
}
impl<L: List + ?Sized> List for &L {
type Item = L::Item;
fn len(&self) -> usize {
L::len(self)
}
fn get(&self, index: usize) -> Option<L::Item> {
L::get(self, index)
}
}
pub struct ListIter<'a, L> {
list: &'a L,
index: usize,
}
impl<L: List> Iterator for ListIter<'_, L> {
type Item = L::Item;
fn next(&mut self) -> Option<Self::Item> {
let item = self.list.get(self.index)?;
self.index += 1;
Some(item)
}
fn size_hint(&self) -> (usize, Option<usize>) {
let remaining = self.list.len() - self.index;
(remaining, Some(remaining))
}
}
impl<L: List> ExactSizeIterator for ListIter<'_, L> {}
#[derive(Clone, Copy, Debug)]
pub struct Copied<L>(pub L);
impl<'a, T: Copy + 'a, L: List<Item = &'a T>> List for Copied<L> {
type Item = T;
fn len(&self) -> usize {
self.0.len()
}
fn get(&self, index: usize) -> Option<T> {
self.0.get(index).copied()
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct OwnedList<T> {
items: Vec<T>,
}
impl<T> OwnedList<T> {
pub fn new() -> Self {
Self { items: Vec::new() }
}
pub fn push(&mut self, item: T) {
self.items.push(item);
}
pub fn len(&self) -> usize {
self.items.len()
}
pub fn is_empty(&self) -> bool {
self.items.is_empty()
}
pub fn as_slice(&self) -> &[T] {
&self.items
}
}
impl<T> Default for OwnedList<T> {
fn default() -> Self {
Self::new()
}
}
impl<T> From<Vec<T>> for OwnedList<T> {
fn from(items: Vec<T>) -> Self {
Self { items }
}
}
impl<T> FromIterator<T> for OwnedList<T> {
fn from_iter<I: IntoIterator<Item = T>>(items: I) -> Self {
Self {
items: items.into_iter().collect(),
}
}
}
impl<'a, T> List for &'a OwnedList<T> {
type Item = &'a T;
fn len(&self) -> usize {
self.items.len()
}
fn get(&self, index: usize) -> Option<&'a T> {
self.items.get(index)
}
}
pub trait Element {
type Source<'src>: ?Sized + 'src;
type Item<'buf>;
const PACKING: Option<Packing> = None;
#[doc(hidden)]
fn encode_element<'src>(source: &'src Self::Source<'src>, writer: &mut Writer<'_>);
#[doc(hidden)]
fn decode_element<'buf>(_list: Message<'buf>, _index: u32) -> Result<Self::Item<'buf>, Error> {
Err(Error::InvalidFrame)
}
#[doc(hidden)]
fn decode_packed<'buf>(_bytes: &'buf [u8]) -> Result<Self::Item<'buf>, Error> {
Err(Error::InvalidFrame)
}
}
macro_rules! number_elements {
($($ty:ty: $write:ident,)*) => {
$(
impl Element for $ty {
type Source<'src> = $ty;
type Item<'buf> = $ty;
const PACKING: Option<Packing> = Some(Packing {
width: size_of::<$ty>() as u8,
total: true,
});
fn encode_element(source: &$ty, writer: &mut Writer<'_>) {
writer.$write(*source);
}
#[inline]
fn decode_packed(bytes: &[u8]) -> Result<$ty, Error> {
let value = bytes
.get(..size_of::<$ty>())
.ok_or(Error::UnexpectedEof)?;
Ok(<$ty>::from_le_bytes(
value.try_into().expect("the slice is exactly sized"),
))
}
}
)*
};
}
number_elements! {
u8: write_u8,
u16: write_u16,
u32: write_u32,
u64: write_u64,
u128: write_u128,
i8: write_i8,
i16: write_i16,
i32: write_i32,
i64: write_i64,
i128: write_i128,
f32: write_f32,
f64: write_f64,
}
impl Element for bool {
type Source<'src> = bool;
type Item<'buf> = bool;
const PACKING: Option<Packing> = Some(Packing {
width: 1,
total: false,
});
fn encode_element(source: &bool, writer: &mut Writer<'_>) {
writer.write_bool(*source);
}
#[inline]
fn decode_packed(bytes: &[u8]) -> Result<bool, Error> {
match bytes.first().ok_or(Error::UnexpectedEof)? {
0 => Ok(false),
1 => Ok(true),
_ => Err(Error::InvalidBool),
}
}
}
impl Element for char {
type Source<'src> = char;
type Item<'buf> = char;
const PACKING: Option<Packing> = Some(Packing {
width: size_of::<char>() as u8,
total: false,
});
fn encode_element(source: &char, writer: &mut Writer<'_>) {
writer.write_char(*source);
}
#[inline]
fn decode_packed(bytes: &[u8]) -> Result<char, Error> {
char::from_u32(u32::decode_packed(bytes)?).ok_or(Error::InvalidChar)
}
}
impl Element for str {
type Source<'src> = str;
type Item<'buf> = &'buf str;
fn encode_element(source: &str, writer: &mut Writer<'_>) {
writer.write_str(source);
}
fn decode_element<'buf>(list: Message<'buf>, index: u32) -> Result<&'buf str, Error> {
list.read_str(index)
}
}
impl Element for [u8] {
type Source<'src> = [u8];
type Item<'buf> = &'buf [u8];
fn encode_element(source: &[u8], writer: &mut Writer<'_>) {
writer.write_bytes(source);
}
fn decode_element<'buf>(list: Message<'buf>, index: u32) -> Result<&'buf [u8], Error> {
list.read_bytes(index)
}
}
pub struct ListView<'buf, E: ?Sized> {
frame: Frame<'buf>,
element: PhantomData<fn() -> *const E>,
}
impl<E: ?Sized> Clone for ListView<'_, E> {
fn clone(&self) -> Self {
*self
}
}
impl<E: ?Sized> Copy for ListView<'_, E> {}
impl<'buf, E: ?Sized> ListView<'buf, E> {
pub(crate) fn new(frame: Frame<'buf>) -> Self {
Self {
frame,
element: PhantomData,
}
}
fn as_message(&self, depth: u32, validate: bool) -> Message<'buf> {
Message::nested(self.frame, depth, validate)
}
fn position(index: usize) -> Option<u32> {
u32::try_from(index).ok()
}
}
impl<'buf, E: Element + ?Sized> List for ListView<'buf, E> {
type Item = E::Item<'buf>;
fn len(&self) -> usize {
self.frame.count()
}
fn get(&self, index: usize) -> Option<E::Item<'buf>> {
if index >= self.len() {
return None;
}
Some(
self.element(index)
.expect("elements are validated when the message is decoded"),
)
}
}
impl<'buf, E: Element + ?Sized> ListView<'buf, E> {
#[inline]
fn element(&self, index: usize) -> Result<E::Item<'buf>, Error> {
match E::PACKING {
Some(packing) => {
let at = index * usize::from(packing.width);
let bytes = self
.frame
.elements()
.get(at..)
.ok_or(Error::UnexpectedEof)?;
E::decode_packed(bytes)
}
None => {
let index = Self::position(index).ok_or(Error::UnexpectedEof)?;
E::decode_element(self.as_message(0, false), index)
}
}
}
pub(crate) fn validate(&self, depth: u32) -> Result<(), Error> {
if E::PACKING.is_some() {
for index in 0..self.len() {
self.element(index)?;
}
return Ok(());
}
let list = self.as_message(depth, true);
for index in 0..self.len() {
let index = Self::position(index).ok_or(Error::UnexpectedEof)?;
E::decode_element(list, index)?;
}
Ok(())
}
}
impl<'buf, E: Element + ?Sized> Debug for ListView<'buf, E>
where
E::Item<'buf>: Debug,
{
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.debug_list().entries(self.iter()).finish()
}
}