use core::fmt;
#[cfg(feature = "alloc")]
use core::ptr;
#[cfg(feature = "alloc")]
use alloc::vec::Vec;
use core::marker::PhantomData;
#[cfg(feature = "std")]
use std::error::Error as StdError;
#[cfg(feature = "alloc")]
use core::mem::{align_of, size_of};
#[cfg(feature = "alloc")]
use self::super::trivial::TriviallyTransmutable;
#[derive(Clone, PartialEq, Eq, Hash)]
pub enum Error<'a, S, T> {
Guard(GuardError),
Unaligned(UnalignedError<'a, S, T>),
#[cfg(feature = "alloc")]
IncompatibleVecTarget(IncompatibleVecTargetError<S, T>),
InvalidValue,
}
impl<'a, S, T> Error<'a, S, T> {
#[cfg(feature = "alloc")]
pub fn copy(self) -> Result<Vec<T>, Error<'a, S, T>>
where T: TriviallyTransmutable
{
match self {
Error::Unaligned(e) => Ok(e.copy()),
Error::IncompatibleVecTarget(e) => Ok(e.copy()),
e => Err(e),
}
}
#[cfg(feature = "alloc")]
pub unsafe fn copy_unchecked(self) -> Result<Vec<T>, Error<'a, S, T>> {
match self {
Error::Unaligned(e) => Ok(e.copy_unchecked()),
Error::IncompatibleVecTarget(e) => Ok(e.copy_unchecked()),
e => Err(e),
}
}
pub fn without_src<'z>(self) -> Error<'z, S, T> {
match self {
Error::Unaligned(UnalignedError { source: _, offset, phantom }) => {
Error::Unaligned(UnalignedError {
source: &[],
offset: offset,
phantom: phantom,
})
}
Error::Guard(e) => Error::Guard(e),
Error::InvalidValue => Error::InvalidValue,
#[cfg(feature = "alloc")]
Error::IncompatibleVecTarget(e) => Error::IncompatibleVecTarget(e),
}
}
}
impl<'a, S, T> fmt::Debug for Error<'a, S, T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Error::Guard(e) => write!(f, "Guard({:?})", e),
Error::Unaligned(e) => write!(f, "Unaligned({:?})", e),
Error::InvalidValue => f.write_str("InvalidValue"),
#[cfg(feature = "alloc")]
Error::IncompatibleVecTarget(_) => f.write_str("IncompatibleVecTarget"),
}
}
}
#[cfg(feature = "std")]
#[allow(deprecated)]
impl<'a, S, T> StdError for Error<'a, S, T> {
fn description(&self) -> &str {
match self {
Error::Guard(e) => e.description(),
Error::Unaligned(e) => e.description(),
Error::InvalidValue => "invalid target value",
Error::IncompatibleVecTarget(e) => e.description(),
}
}
}
impl<'a, S, T> fmt::Display for Error<'a, S, T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Error::Guard(e) => e.fmt(f),
Error::Unaligned(e) => e.fmt(f),
Error::InvalidValue => f.write_str("Invalid target value"),
#[cfg(feature = "alloc")]
Error::IncompatibleVecTarget(e) => e.fmt(f),
}
}
}
impl<'a, S, T> From<GuardError> for Error<'a, S, T> {
fn from(o: GuardError) -> Self {
Error::Guard(o)
}
}
impl<'a, S, T> From<UnalignedError<'a, S, T>> for Error<'a, S, T> {
fn from(o: UnalignedError<'a, S, T>) -> Self {
Error::Unaligned(o)
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct GuardError {
pub required: usize,
pub actual: usize,
pub reason: ErrorReason,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum ErrorReason {
NotEnoughBytes,
TooManyBytes,
InexactByteCount,
}
#[cfg(feature = "std")]
impl StdError for GuardError {
fn description(&self) -> &str {
self.reason.description()
}
}
impl fmt::Display for GuardError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} (required: {}, actual: {})", self.reason.description(), self.required, self.actual)
}
}
impl ErrorReason {
pub fn description(self) -> &'static str {
match self {
ErrorReason::NotEnoughBytes => "Not enough bytes to fill type",
ErrorReason::TooManyBytes => "Too many bytes for type",
ErrorReason::InexactByteCount => "Not exactly the amount of bytes for type",
}
}
}
#[cfg(feature = "alloc")]
unsafe fn copy_to_vec_unchecked<S, T>(data: &[S]) -> Vec<T> {
let len = data.len() * size_of::<S>() / size_of::<T>();
let mut out = Vec::with_capacity(len);
ptr::copy_nonoverlapping(data.as_ptr() as *const u8, out.as_mut_ptr() as *mut u8, len * size_of::<T>());
out.set_len(len);
out
}
#[derive(Clone, Eq, Hash, PartialEq)]
pub struct UnalignedError<'a, S, T> {
pub offset: usize,
pub source: &'a [S],
phantom: PhantomData<T>,
}
impl<'a, S, T> UnalignedError<'a, S, T> {
pub fn new(offset: usize, source: &'a [S]) -> Self {
UnalignedError {
offset: offset,
source: source,
phantom: PhantomData,
}
}
#[cfg(feature = "alloc")]
pub unsafe fn copy_unchecked(&self) -> Vec<T> {
copy_to_vec_unchecked::<S, T>(self.source)
}
#[cfg(feature = "alloc")]
pub fn copy(&self) -> Vec<T>
where T: TriviallyTransmutable
{
unsafe {
self.copy_unchecked()
}
}
}
impl<'a, S, T> fmt::Debug for UnalignedError<'a, S, T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
struct Source {
len: usize,
}
impl fmt::Debug for Source {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("&[S]")
.field("len", &self.len)
.finish()
}
}
f.debug_struct("UnalignedError")
.field("offset", &self.offset)
.field("source", &Source { len: self.source.len() })
.finish()
}
}
#[cfg(feature = "std")]
impl<'a, S, T> StdError for UnalignedError<'a, S, T> {
fn description(&self) -> &str {
"data is unaligned"
}
}
impl<'a, S, T> fmt::Display for UnalignedError<'a, S, T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "data is unaligned (off by {} bytes)", self.offset)
}
}
#[cfg(feature = "alloc")]
#[derive(Clone, Eq, Hash, PartialEq)]
pub struct IncompatibleVecTargetError<S, T> {
pub vec: Vec<S>,
target: PhantomData<T>,
}
#[cfg(feature = "alloc")]
impl<S, T> IncompatibleVecTargetError<S, T> {
pub fn new(vec: Vec<S>) -> Self {
IncompatibleVecTargetError {
vec: vec,
target: PhantomData,
}
}
pub unsafe fn copy_unchecked(&self) -> Vec<T> {
copy_to_vec_unchecked::<S, T>(&self.vec)
}
pub fn copy(&self) -> Vec<T>
where T: TriviallyTransmutable
{
unsafe {
self.copy_unchecked()
}
}
}
#[cfg(feature = "alloc")]
impl<'a, S, T> From<IncompatibleVecTargetError<S, T>> for Error<'a, S, T> {
fn from(e: IncompatibleVecTargetError<S, T>) -> Self {
Error::IncompatibleVecTarget(e)
}
}
#[cfg(feature = "alloc")]
impl<S, T> fmt::Debug for IncompatibleVecTargetError<S, T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("IncompatibleVecTargetError")
.field("size_of<S>", &size_of::<S>())
.field("align_of<S>", &align_of::<S>())
.field("size_of<T>", &size_of::<T>())
.field("align_of<T>", &align_of::<T>())
.finish()
}
}
#[cfg(feature = "std")]
impl<S, T> StdError for IncompatibleVecTargetError<S, T> {
fn description(&self) -> &str {
"incompatible target type"
}
}
#[cfg(feature = "alloc")]
impl<S, T> fmt::Display for IncompatibleVecTargetError<S, T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f,
"incompatible target type (size: {}, align: {}) for transmutation from source (size: {}, align: {})",
size_of::<T>(),
align_of::<T>(),
size_of::<S>(),
align_of::<S>())
}
}