use std::io;
use std::fmt;
use crate::header::DType;
use crate::type_str::{TypeStr};
#[allow(unused)] use crate::type_matchup_docs;
pub trait Deserialize: Sized {
type TypeReader: TypeRead<Value=Self>;
fn reader(dtype: &DType) -> Result<Self::TypeReader, DTypeError>;
}
pub trait Serialize {
type TypeWriter: TypeWrite<Value=Self>;
fn writer(dtype: &DType) -> Result<Self::TypeWriter, DTypeError>;
}
pub trait AutoSerialize: Serialize {
fn default_dtype() -> DType;
}
pub trait TypeRead {
type Value;
fn read_one<R: io::Read>(&self, bytes: R) -> io::Result<Self::Value>
where Self: Sized;
}
pub trait TypeWrite {
type Value: ?Sized;
fn write_one<W: io::Write>(&self, writer: W, value: &Self::Value) -> io::Result<()>
where Self: Sized;
}
pub trait TypeReadDyn: TypeRead {
#[doc(hidden)]
fn read_one_dyn(&self, writer: &mut dyn io::Read) -> io::Result<Self::Value>;
}
impl<T: TypeRead> TypeReadDyn for T {
#[inline(always)]
fn read_one_dyn(&self, reader: &mut dyn io::Read) -> io::Result<Self::Value> {
self.read_one(reader)
}
}
impl<T> TypeRead for Box<dyn TypeReadDyn<Value=T>> {
type Value = T;
#[inline(always)]
fn read_one<R: io::Read>(&self, mut reader: R) -> io::Result<T> where Self: Sized {
(**self).read_one_dyn(&mut reader)
}
}
pub trait TypeWriteDyn: TypeWrite {
#[doc(hidden)]
fn write_one_dyn(&self, writer: &mut dyn io::Write, value: &Self::Value) -> io::Result<()>;
}
impl<T: TypeWrite> TypeWriteDyn for T {
#[inline(always)]
fn write_one_dyn(&self, writer: &mut dyn io::Write, value: &Self::Value) -> io::Result<()> {
self.write_one(writer, value)
}
}
impl<T: ?Sized> TypeWrite for Box<dyn TypeWriteDyn<Value=T>> {
type Value = T;
#[inline(always)]
fn write_one<W: io::Write>(&self, mut writer: W, value: &T) -> io::Result<()>
where Self: Sized,
{
(**self).write_one_dyn(&mut writer, value)
}
}
#[derive(Debug, Clone)]
pub struct DTypeError(pub(crate) ErrorKind);
#[derive(Debug, Clone)]
pub(crate) enum ErrorKind {
Custom(String),
ExpectedScalar {
dtype: String,
rust_type: &'static str,
},
ExpectedArray {
got: &'static str, },
WrongArrayLen {
expected: u64,
actual: u64,
},
ExpectedRecord {
dtype: String,
},
WrongFields {
expected: Vec<String>,
actual: Vec<String>,
},
BadScalar {
type_str: TypeStr,
rust_type: &'static str,
verb: &'static str,
},
UsizeOverflow(u64),
RequiresPickle,
}
impl std::error::Error for DTypeError {}
impl DTypeError {
pub fn custom<S: core::fmt::Display>(msg: S) -> Self {
DTypeError(ErrorKind::Custom(msg.to_string()))
}
pub(crate) fn bad_scalar<T: ?Sized>(verb: &'static str, type_str: &TypeStr) -> Self {
let type_str = type_str.clone();
let rust_type = std::any::type_name::<T>();
DTypeError(ErrorKind::BadScalar { type_str, rust_type, verb })
}
pub(crate) fn bad_usize(x: u64) -> Self {
DTypeError(ErrorKind::UsizeOverflow(x))
}
#[doc(hidden)]
pub fn expected_record(dtype: &DType) -> Self {
DTypeError(ErrorKind::ExpectedRecord { dtype: dtype.descr() })
}
#[doc(hidden)]
pub fn wrong_fields<S1: AsRef<str>, S2: AsRef<str>>(
expected: impl IntoIterator<Item=S1>,
actual: impl IntoIterator<Item=S2>,
) -> Self {
DTypeError(ErrorKind::WrongFields {
expected: expected.into_iter().map(|s| s.as_ref().to_string()).collect(),
actual: actual.into_iter().map(|s| s.as_ref().to_string()).collect(),
})
}
}
impl fmt::Display for DTypeError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match &self.0 {
ErrorKind::Custom(msg) => {
write!(f, "{}", msg)
},
ErrorKind::ExpectedScalar { dtype, rust_type } => {
write!(f, "type {} requires a scalar (string) dtype, not {}", rust_type, dtype)
},
ErrorKind::ExpectedRecord { dtype } => {
write!(f, "expected a record type; got {}", dtype)
},
ErrorKind::ExpectedArray { got } => {
write!(f, "rust array types require an array dtype (got {})", got)
},
ErrorKind::WrongArrayLen { actual, expected } => {
write!(f, "wrong array size (expected {}, got {})", expected, actual)
},
ErrorKind::WrongFields { actual, expected } => {
write!(f, "field names do not match (expected {:?}, got {:?})", expected, actual)
},
ErrorKind::BadScalar { type_str, rust_type, verb } => {
write!(f, "cannot {} type {} with type-string '{}'", verb, rust_type, type_str)
},
ErrorKind::UsizeOverflow(value) => {
write!(f, "cannot cast {} as usize", value)
},
ErrorKind::RequiresPickle => {
write!(f, "this dtype uses a pickled array, which npyz's read/write APIs do not currently support")
}
}
}
}
#[macro_use]
pub(in crate::serialize) mod helper {
use super::*;
use std::ops::Deref;
pub struct TypeWriteViaDeref<T>
where
T: Deref,
<T as Deref>::Target: Serialize,
{
pub(crate) inner: <<T as Deref>::Target as Serialize>::TypeWriter,
}
impl<T, U: ?Sized> TypeWrite for TypeWriteViaDeref<T>
where
T: Deref<Target=U>,
U: Serialize,
{
type Value = T;
#[inline(always)]
fn write_one<W: io::Write>(&self, writer: W, value: &T) -> io::Result<()> {
self.inner.write_one(writer, value)
}
}
macro_rules! impl_serialize_by_deref {
(
$(#[$($attr:tt)+])*
[$($generics:tt)*] $T:ty => $Target:ty $(where $($bounds:tt)+)*
) => {
$(#[$($attr)+])*
impl<$($generics)*> Serialize for $T
$(where $($bounds)+)*
{
type TypeWriter = crate::serialize::helper::TypeWriteViaDeref<$T>;
#[inline(always)]
fn writer(dtype: &DType) -> core::result::Result<Self::TypeWriter, DTypeError> {
Ok(crate::serialize::helper::TypeWriteViaDeref { inner: <$Target>::writer(dtype)? })
}
}
};
}
macro_rules! impl_auto_serialize {
([$($generics:tt)*] $T:ty as $Delegate:ty $(where $($bounds:tt)+)*) => {
impl<$($generics)*> crate::serialize::AutoSerialize for $T
$(where $($bounds)+)*
{
#[inline(always)]
fn default_dtype() -> crate::DType {
<$Delegate>::default_dtype()
}
}
};
}
}
impl_serialize_by_deref!{['a, T: ?Sized] &'a T => T where T: Serialize}
impl_serialize_by_deref!{['a, T: ?Sized] &'a mut T => T where T: Serialize}
impl_serialize_by_deref!{[T: ?Sized] Box<T> => T where T: Serialize}
impl_serialize_by_deref!{[T: ?Sized] std::rc::Rc<T> => T where T: Serialize}
impl_serialize_by_deref!{[T: ?Sized] std::sync::Arc<T> => T where T: Serialize}
impl_serialize_by_deref!{['a, T: ?Sized] std::borrow::Cow<'a, T> => T where T: Serialize + std::borrow::ToOwned}
impl_auto_serialize!{[T: ?Sized] &T as T where T: AutoSerialize}
impl_auto_serialize!{[T: ?Sized] &mut T as T where T: AutoSerialize}
impl_auto_serialize!{[T: ?Sized] Box<T> as T where T: AutoSerialize}
impl_auto_serialize!{[T: ?Sized] std::rc::Rc<T> as T where T: AutoSerialize}
impl_auto_serialize!{[T: ?Sized] std::sync::Arc<T> as T where T: AutoSerialize}
impl_auto_serialize!{[T: ?Sized] std::borrow::Cow<'_, T> as T where T: AutoSerialize + std::borrow::ToOwned}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn dynamic_readers_and_writers() {
let writer: Box<dyn TypeWriteDyn<Value=i32>> = Box::new(i32::writer(&i32::default_dtype()).unwrap());
let reader: Box<dyn TypeReadDyn<Value=i32>> = Box::new(i32::reader(&i32::default_dtype()).unwrap());
let mut buf = vec![];
writer.write_one(&mut buf, &4000).unwrap();
assert_eq!(reader.read_one(&buf[..]).unwrap(), 4000);
}
}