Skip to content

Commit

Permalink
Add reader::read_bytes_const (#429)
Browse files Browse the repository at this point in the history
* Add reader::read_bytes_const

* Reduce codegen for known sizes at compile time
  - DekuReader<_, Endian> for all types
  - DekuReader<_, (Endian, Endian)> for u8

* Change Strings in DekuError to Cow<'static, str>

* Change all strings in DekuError to Cow<'static, str> so that
  more can be defined as "not alloc'ed strings" and be removed with
  panic=abort, build-std and friends.

* Remove unused DekuError::Unexpected

* Add comment to lib.rs about parser binary size

* Add returning io:ErrorKind from reader and writer

* Remove DekuError::Write and replace with DekuError::Io. Instead of ignoring
  error other then UnexpectedEof, return them to bubble up.

* clippy

* clippy

* update trybuild output

* clippy

---------

Co-authored-by: Emmanuel Thompson <[email protected]>
  • Loading branch information
wcampbell0x2a and sharksforarms authored May 3, 2024
1 parent 1079ada commit e92700a
Show file tree
Hide file tree
Showing 15 changed files with 160 additions and 89 deletions.
24 changes: 12 additions & 12 deletions deku-derive/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
/*!
Procedural macros that implement `DekuRead` and `DekuWrite` traits
*/

#![warn(missing_docs)]

use std::borrow::Cow;
extern crate alloc;

use alloc::borrow::Cow;
use std::convert::TryFrom;
use std::fmt::Display;

use darling::{ast, FromDeriveInput, FromField, FromMeta, FromVariant, ToTokens};
use proc_macro2::TokenStream;
Expand All @@ -25,9 +27,9 @@ enum Id {
Int(syn::LitInt),
}

impl ToString for Id {
fn to_string(&self) -> String {
self.to_token_stream().to_string()
impl Display for Id {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(&self.to_token_stream().to_string())
}
}

Expand Down Expand Up @@ -73,9 +75,9 @@ impl Num {
}
}

impl ToString for Num {
fn to_string(&self) -> String {
self.0.to_token_stream().to_string()
impl Display for Num {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(&self.0.to_token_stream().to_string())
}
}

Expand Down Expand Up @@ -267,14 +269,12 @@ impl DekuData {

/// Emit a reader. On error, a compiler error is emitted
fn emit_reader(&self) -> TokenStream {
self.emit_reader_checked()
.map_or_else(|e| e.to_compile_error(), |tks| tks)
self.emit_reader_checked().unwrap_or_else(|e| e.to_compile_error())
}

/// Emit a writer. On error, a compiler error is emitted
fn emit_writer(&self) -> TokenStream {
self.emit_writer_checked()
.map_or_else(|e| e.to_compile_error(), |tks| tks)
self.emit_writer_checked().unwrap_or_else(|e| e.to_compile_error())
}

/// Same as `emit_reader`, but won't auto convert error to compile error
Expand Down
20 changes: 14 additions & 6 deletions deku-derive/src/macros/deku_read.rs
Original file line number Diff line number Diff line change
Expand Up @@ -275,12 +275,14 @@ fn emit_enum(input: &DekuData) -> Result<TokenStream, syn::Error> {
if !has_default_match && default_reader.is_none() {
variant_matches.push(quote! {
_ => {
extern crate alloc;
use alloc::borrow::Cow;
return Err(::#crate_::DekuError::Parse(
format!(
Cow::from(format!(
"Could not match enum variant id = {:?} on enum `{}`",
__deku_variant_id,
#ident_as_string
)
))
));
}
});
Expand Down Expand Up @@ -440,7 +442,9 @@ fn emit_magic_read(input: &DekuData) -> TokenStream {
for __deku_byte in __deku_magic {
let __deku_read_byte = u8::from_reader_with_ctx(__deku_reader, ())?;
if *__deku_byte != __deku_read_byte {
return Err(::#crate_::DekuError::Parse(format!("Missing magic value {:?}", #magic)));
extern crate alloc;
use alloc::borrow::Cow;
return Err(::#crate_::DekuError::Parse(Cow::from(format!("Missing magic value {:?}", #magic))));
}
}
}
Expand Down Expand Up @@ -514,11 +518,13 @@ fn emit_padding(bit_size: &TokenStream) -> TokenStream {
{
use core::convert::TryFrom;
// TODO: I hope this consts in most cases?
extern crate alloc;
use alloc::borrow::Cow;
let __deku_pad = usize::try_from(#bit_size).map_err(|e|
::#crate_::DekuError::InvalidParam(format!(
::#crate_::DekuError::InvalidParam(Cow::from(format!(
"Invalid padding param \"({})\": cannot convert to usize",
stringify!(#bit_size)
))
)))
)?;


Expand Down Expand Up @@ -820,7 +826,9 @@ pub fn emit_try_from(
let mut cursor = ::#crate_::no_std_io::Cursor::new(input);
let (amt_read, res) = <Self as ::#crate_::DekuContainerRead>::from_reader((&mut cursor, 0))?;
if (amt_read / 8) != total_len {
return Err(::#crate_::DekuError::Parse(format!("Too much data")));
extern crate alloc;
use alloc::borrow::Cow;
return Err(::#crate_::DekuError::Parse(Cow::from("Too much data")));
}
Ok(res)
}
Expand Down
6 changes: 4 additions & 2 deletions deku-derive/src/macros/deku_write.rs
Original file line number Diff line number Diff line change
Expand Up @@ -414,11 +414,13 @@ fn emit_padding(bit_size: &TokenStream) -> TokenStream {
quote! {
{
use core::convert::TryFrom;
extern crate alloc;
use alloc::borrow::Cow;
let __deku_pad = usize::try_from(#bit_size).map_err(|e|
::#crate_::DekuError::InvalidParam(format!(
::#crate_::DekuError::InvalidParam(Cow::from(format!(
"Invalid padding param \"({})\": cannot convert to usize",
stringify!(#bit_size)
))
)))
)?;
__deku_writer.write_bits(::#crate_::bitvec::bitvec![u8, ::#crate_::bitvec::Msb0; 0; __deku_pad].as_bitslice())?;
}
Expand Down
6 changes: 4 additions & 2 deletions deku-derive/src/macros/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -372,12 +372,14 @@ fn assertion_failed(
#[cfg(not(feature = "no-assert-string"))]
{
quote! {
return Err(::#crate_::DekuError::Assertion(format!(
extern crate alloc;
use alloc::borrow::Cow;
return Err(::#crate_::DekuError::Assertion(Cow::from(format!(
"{}.{} field failed assertion: {}",
#ident,
#field_ident_str,
#stringify,
)));
))));
}
}
}
26 changes: 12 additions & 14 deletions src/error.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
//! Error module

#![cfg(feature = "alloc")]
use alloc::borrow::Cow;

use no_std_io::io::ErrorKind;

use alloc::format;
use alloc::string::String;

/// Number of bits needed to retry parsing
#[derive(Debug, Clone, PartialEq, Eq)]
Expand Down Expand Up @@ -38,30 +40,28 @@ pub enum DekuError {
/// Parsing error when reading
Incomplete(NeedSize),
/// Parsing error when reading
Parse(String),
Parse(Cow<'static, str>),
/// Invalid parameter
InvalidParam(String),
/// Unexpected error
Unexpected(String),
InvalidParam(Cow<'static, str>),
/// Assertion error from `assert` or `assert_eq` attributes
Assertion(String),
Assertion(Cow<'static, str>),
/// Assertion error from `assert` or `assert_eq` attributes, without string
AssertionNoStr,
/// Could not resolve `id` for variant
IdVariantNotFound,
/// IO error while writing
Write,
/// IO error while reading or writing
Io(ErrorKind),
}

impl From<core::num::TryFromIntError> for DekuError {
fn from(e: core::num::TryFromIntError) -> DekuError {
DekuError::Parse(format!("error parsing int: {e}"))
DekuError::Parse(Cow::from(format!("error parsing int: {e}")))
}
}

impl From<core::array::TryFromSliceError> for DekuError {
fn from(e: core::array::TryFromSliceError) -> DekuError {
DekuError::Parse(format!("error parsing from slice: {e}"))
DekuError::Parse(Cow::from(format!("error parsing from slice: {e}")))
}
}

Expand All @@ -82,11 +82,10 @@ impl core::fmt::Display for DekuError {
),
DekuError::Parse(ref err) => write!(f, "Parse error: {err}"),
DekuError::InvalidParam(ref err) => write!(f, "Invalid param error: {err}"),
DekuError::Unexpected(ref err) => write!(f, "Unexpected error: {err}"),
DekuError::Assertion(ref err) => write!(f, "Assertion error: {err}"),
DekuError::AssertionNoStr => write!(f, "Assertion error"),
DekuError::IdVariantNotFound => write!(f, "Could not resolve `id` for variant"),
DekuError::Write => write!(f, "write error"),
DekuError::Io(ref e) => write!(f, "io errorr: {e:?}"),
}
}
}
Expand All @@ -106,11 +105,10 @@ impl From<DekuError> for std::io::Error {
DekuError::Incomplete(_) => io::Error::new(io::ErrorKind::UnexpectedEof, error),
DekuError::Parse(_) => io::Error::new(io::ErrorKind::InvalidData, error),
DekuError::InvalidParam(_) => io::Error::new(io::ErrorKind::InvalidInput, error),
DekuError::Unexpected(_) => io::Error::new(io::ErrorKind::Other, error),
DekuError::Assertion(_) => io::Error::new(io::ErrorKind::InvalidData, error),
DekuError::AssertionNoStr => io::Error::from(io::ErrorKind::InvalidData),
DekuError::IdVariantNotFound => io::Error::new(io::ErrorKind::NotFound, error),
DekuError::Write => io::Error::new(io::ErrorKind::BrokenPipe, error),
DekuError::Io(e) => io::Error::new(e, error),
}
}
}
6 changes: 5 additions & 1 deletion src/impls/bool.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use no_std_io::io::{Read, Write};

#[cfg(feature = "alloc")]
use alloc::borrow::Cow;
#[cfg(feature = "alloc")]
use alloc::format;

Expand All @@ -21,7 +23,9 @@ where
let ret = match val {
0x01 => Ok(true),
0x00 => Ok(false),
_ => Err(DekuError::Parse(format!("cannot parse bool value: {val}",))),
_ => Err(DekuError::Parse(Cow::from(format!(
"cannot parse bool value: {val}",
)))),
}?;

Ok(ret)
Expand Down
6 changes: 4 additions & 2 deletions src/impls/cstring.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use alloc::borrow::Cow;
use no_std_io::io::{Read, Write};
use std::ffi::CString;

Expand Down Expand Up @@ -27,8 +28,9 @@ where
let bytes =
Vec::from_reader_with_ctx(reader, (Limit::from(|b: &u8| *b == 0x00), inner_ctx))?;

let value = CString::from_vec_with_nul(bytes)
.map_err(|e| DekuError::Parse(format!("Failed to convert Vec to CString: {e}")))?;
let value = CString::from_vec_with_nul(bytes).map_err(|e| {
DekuError::Parse(Cow::from(format!("Failed to convert Vec to CString: {e}")))
})?;

Ok(value)
}
Expand Down
4 changes: 3 additions & 1 deletion src/impls/nonzero.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
#[cfg(feature = "alloc")]
use alloc::borrow::Cow;
#[cfg(feature = "alloc")]
use alloc::format;
use core::num::*;
use no_std_io::io::{Read, Write};
Expand All @@ -19,7 +21,7 @@ macro_rules! ImplDekuTraitsCtx {
let value = <$typ>::new(value);

match value {
None => Err(DekuError::Parse(format!("NonZero assertion"))),
None => Err(DekuError::Parse(Cow::from(format!("NonZero assertion")))),
Some(v) => Ok(v),
}
}
Expand Down
Loading

0 comments on commit e92700a

Please sign in to comment.