From ecf547f1bca98545378e55c7e55aa0ef3cf4e66a Mon Sep 17 00:00:00 2001 From: Jun Luo <4catcode@gmail.com> Date: Thu, 12 Sep 2024 12:24:44 +0800 Subject: [PATCH 1/9] Rust: add support for no_std env --- lib/xdrgen/generators/rust.rb | 24 +- lib/xdrgen/generators/rust/src/types.rs | 155 ++++++++---- .../block_comments.x/MyXDR.rs | 167 +++++++----- .../generator_spec_rust/const.x/MyXDR.rs | 163 ++++++++---- .../generator_spec_rust/enum.x/MyXDR.rs | 179 ++++++++----- .../generator_spec_rust/nesting.x/MyXDR.rs | 179 ++++++++----- .../generator_spec_rust/optional.x/MyXDR.rs | 167 +++++++----- .../generator_spec_rust/struct.x/MyXDR.rs | 167 +++++++----- .../generator_spec_rust/test.x/MyXDR.rs | 239 +++++++++++------- .../generator_spec_rust/union.x/MyXDR.rs | 179 ++++++++----- .../block_comments.x/MyXDR.rs | 167 +++++++----- .../const.x/MyXDR.rs | 163 ++++++++---- .../enum.x/MyXDR.rs | 179 ++++++++----- .../nesting.x/MyXDR.rs | 179 ++++++++----- .../optional.x/MyXDR.rs | 167 +++++++----- .../struct.x/MyXDR.rs | 167 +++++++----- .../test.x/MyXDR.rs | 239 +++++++++++------- .../union.x/MyXDR.rs | 179 ++++++++----- .../block_comments.x/MyXDR.rs | 167 +++++++----- .../const.x/MyXDR.rs | 163 ++++++++---- .../enum.x/MyXDR.rs | 179 ++++++++----- .../nesting.x/MyXDR.rs | 179 ++++++++----- .../optional.x/MyXDR.rs | 167 +++++++----- .../struct.x/MyXDR.rs | 167 +++++++----- .../test.x/MyXDR.rs | 239 +++++++++++------- .../union.x/MyXDR.rs | 179 ++++++++----- 26 files changed, 2887 insertions(+), 1612 deletions(-) diff --git a/lib/xdrgen/generators/rust.rb b/lib/xdrgen/generators/rust.rb index 8a4d36a37..ac6a8a718 100644 --- a/lib/xdrgen/generators/rust.rb +++ b/lib/xdrgen/generators/rust.rb @@ -175,7 +175,7 @@ def render_enum_of_all_types(out, types) pub const VARIANTS: [TypeVariant; #{types.count}] = [ #{types.map { |t| "TypeVariant::#{t}," }.join("\n")} ]; pub const VARIANTS_STR: [&'static str; #{types.count}] = [ #{types.map { |t| "\"#{t}\"," }.join("\n")} ]; - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] #[allow(clippy::too_many_lines)] pub fn read_xdr(v: TypeVariant, r: &mut Limited) -> Result { match v { @@ -190,7 +190,7 @@ def render_enum_of_all_types(out, types) Ok(t) } - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] pub fn read_xdr_to_end(v: TypeVariant, r: &mut Limited) -> Result { let s = Self::read_xdr(v, r)?; // Check that any further reads, such as this read of one byte, read no @@ -234,7 +234,7 @@ def render_enum_of_all_types(out, types) } } - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] pub fn from_xdr>(v: TypeVariant, bytes: B, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(v, &mut cursor)?; @@ -318,7 +318,7 @@ def render_enum_of_all_types(out, types) } impl WriteXdr for Type { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] #[allow(clippy::too_many_lines)] fn write_xdr(&self, w: &mut Limited) -> Result<()> { match self { @@ -407,7 +407,7 @@ def render_struct(out, struct) out.puts "" out.puts <<-EOS.strip_heredoc impl ReadXdr for #{name struct} { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { Ok(Self{ @@ -420,7 +420,7 @@ def render_struct(out, struct) } impl WriteXdr for #{name struct} { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { #{struct.members.map do |m| @@ -517,7 +517,7 @@ def render_enum(out, enum) } impl ReadXdr for #{name enum} { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let e = i32::read_xdr(r)?; @@ -528,7 +528,7 @@ def render_enum(out, enum) } impl WriteXdr for #{name enum} { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i: i32 = (*self).into(); @@ -656,7 +656,7 @@ def render_union(out, union) impl Union<#{discriminant_type}> for #{name union} {} impl ReadXdr for #{name union} { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let dv: #{discriminant_type} = <#{discriminant_type} as ReadXdr>::read_xdr(r)?; @@ -678,7 +678,7 @@ def render_union(out, union) } impl WriteXdr for #{name union} { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { self.discriminant().write_xdr(w)?; @@ -816,7 +816,7 @@ def render_typedef(out, typedef) } impl ReadXdr for #{name typedef} { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = #{reference_to_call(typedef, typedef.type)}::read_xdr(r)?; @@ -827,7 +827,7 @@ def render_typedef(out, typedef) } impl WriteXdr for #{name typedef} { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w|{ self.0.write_xdr(w) }) } diff --git a/lib/xdrgen/generators/rust/src/types.rs b/lib/xdrgen/generators/rust/src/types.rs index 13a36c004..4f70c060d 100644 --- a/lib/xdrgen/generators/rust/src/types.rs +++ b/lib/xdrgen/generators/rust/src/types.rs @@ -25,6 +25,7 @@ use alloc::{ borrow::ToOwned, boxed::Box, string::{FromUtf8Error, String}, + vec, vec::Vec, }; #[cfg(feature = "std")] @@ -33,14 +34,17 @@ use std::string::FromUtf8Error; #[cfg(feature = "arbitrary")] use arbitrary::Arbitrary; -// TODO: Add support for read/write xdr fns when std not available. - #[cfg(feature = "std")] use std::{ error, io, io::{BufRead, BufReader, Cursor, Read, Write}, }; +#[cfg(all(not(feature = "std"), feature = "alloc"))] +use embedded_io::{Error as _, ErrorType, Read, Write}; +#[cfg(all(not(feature = "std"), feature = "alloc"))] +use embedded_io_cursor::Cursor; + /// Error contains all errors returned by functions in this crate. It can be /// compared via `PartialEq`, however any contained IO errors will only be /// compared on their `ErrorKind`. @@ -56,6 +60,8 @@ pub enum Error { InvalidHex, #[cfg(feature = "std")] Io(io::Error), + #[cfg(all(not(feature = "std"), feature = "alloc"))] + Io(embedded_io::ErrorKind), DepthLimitExceeded, #[cfg(feature = "serde_json")] Json(serde_json::Error), @@ -72,13 +78,34 @@ impl PartialEq for Error { // case for comparing errors outputted by the XDR library is for // error case testing, and a lack of the ability to compare has a // detrimental affect on failure testing, so this is a tradeoff. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] (Self::Io(l), Self::Io(r)) => l.kind() == r.kind(), _ => core::mem::discriminant(self) == core::mem::discriminant(other), } } } + +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl embedded_io::Error for Error { + fn kind(&self) -> embedded_io::ErrorKind { + match self { + Self::Io(e) => *e, + _ => embedded_io::ErrorKind::Other, + } + } +} + +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl From> for Error { + fn from(value: embedded_io::ReadExactError) -> Self { + match value { + embedded_io::ReadExactError::UnexpectedEof => Error::Io(embedded_io::ErrorKind::Other), + embedded_io::ReadExactError::Other(e) => e + } + } +} + #[cfg(feature = "std")] impl error::Error for Error { #[must_use] @@ -105,6 +132,8 @@ impl fmt::Display for Error { Error::InvalidHex => write!(f, "hex invalid"), #[cfg(feature = "std")] Error::Io(e) => write!(f, "{e}"), + #[cfg(all(not(feature = "std"), feature = "alloc"))] + Error::Io(_) => write!(f, "io error"), Error::DepthLimitExceeded => write!(f, "depth limit exceeded"), #[cfg(feature = "serde_json")] Error::Json(e) => write!(f, "{e}"), @@ -157,6 +186,9 @@ impl From for () { #[allow(dead_code)] type Result = core::result::Result; +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl ErrorType for Limited { type Error = Error; } + /// Name defines types that assign a static name to their value, such as the /// name given to an identifier in an XDR enum, or the name given to the case in /// a union. @@ -190,7 +222,7 @@ where /// `Limits` contains the limits that a limited reader or writer will be /// constrained to. -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] #[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct Limits { /// Defines the maximum depth for recursive calls in `Read/WriteXdr` to @@ -207,7 +239,7 @@ pub struct Limits { pub len: usize, } -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] impl Limits { #[must_use] pub fn none() -> Self { @@ -238,13 +270,13 @@ impl Limits { /// /// Intended for use with readers and writers and limiting their reads and /// writes. -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] pub struct Limited { pub inner: L, pub(crate) limits: Limits, } -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] impl Limited { /// Constructs a new `Limited`. /// @@ -297,6 +329,15 @@ impl Read for Limited { } } + +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl Read for Limited { + /// Forwards the read operation to the wrapped object. + fn read(&mut self, buf: &mut [u8]) -> core::result::Result { + self.inner.read(buf).map_err(|e| Error::Io(e.kind())) + } +} + #[cfg(feature = "std")] impl BufRead for Limited { /// Forwards the read operation to the wrapped object. @@ -323,6 +364,18 @@ impl Write for Limited { } } +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl Write for Limited { + /// Forwards the write operation to the wrapped object. + fn write(&mut self, buf: &[u8]) -> core::result::Result { + self.inner.write(buf).map_err(|e| Error::Io(e.kind())) + } + + fn flush(&mut self) -> core::result::Result<(), Self::Error> { + self.inner.flush().map_err(|e| Error::Io(e.kind())) + } +} + #[cfg(feature = "std")] pub struct ReadXdrIter { reader: Limited>, @@ -396,7 +449,7 @@ where /// /// Use [`ReadXdR: Read_xdr_to_end`] when the intent is for all bytes in the /// read implementation to be consumed by the read. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result; /// Construct the type from the XDR bytes base64 encoded. @@ -431,7 +484,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr_to_end(r: &mut Limited) -> Result { let s = Self::read_xdr(r)?; // Check that any further reads, such as this read of one byte, read no @@ -471,7 +524,7 @@ where /// /// Use [`ReadXdR: Read_xdr_into_to_end`] when the intent is for all bytes /// in the read implementation to be consumed by the read. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr_into(&mut self, r: &mut Limited) -> Result<()> { *self = Self::read_xdr(r)?; Ok(()) @@ -495,7 +548,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr_into_to_end(&mut self, r: &mut Limited) -> Result<()> { Self::read_xdr_into(self, r)?; // Check that any further reads, such as this read of one byte, read no @@ -544,7 +597,7 @@ where /// /// An error is returned if the bytes are not completely consumed by the /// deserialization. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn from_xdr(bytes: impl AsRef<[u8]>, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(&mut cursor)?; @@ -568,10 +621,10 @@ where } pub trait WriteXdr { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()>; - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn to_xdr(&self, limits: Limits) -> Result> { let mut cursor = Limited::new(Cursor::new(vec![]), limits); self.write_xdr(&mut cursor)?; @@ -593,13 +646,13 @@ pub trait WriteXdr { /// `Pad_len` returns the number of bytes to pad an XDR value of the given /// length to make the final serialized size a multiple of 4. -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] fn pad_len(len: usize) -> usize { (4 - (len % 4)) % 4 } impl ReadXdr for i32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -611,7 +664,7 @@ impl ReadXdr for i32 { } impl WriteXdr for i32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -622,7 +675,7 @@ impl WriteXdr for i32 { } impl ReadXdr for u32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -634,7 +687,7 @@ impl ReadXdr for u32 { } impl WriteXdr for u32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -645,7 +698,7 @@ impl WriteXdr for u32 { } impl ReadXdr for i64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -657,7 +710,7 @@ impl ReadXdr for i64 { } impl WriteXdr for i64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -668,7 +721,7 @@ impl WriteXdr for i64 { } impl ReadXdr for u64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -680,7 +733,7 @@ impl ReadXdr for u64 { } impl WriteXdr for u64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -691,35 +744,35 @@ impl WriteXdr for u64 { } impl ReadXdr for f32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for f64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for bool { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -730,7 +783,7 @@ impl ReadXdr for bool { } impl WriteXdr for bool { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i = u32::from(*self); // true = 1, false = 0 @@ -740,7 +793,7 @@ impl WriteXdr for bool { } impl ReadXdr for Option { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -757,7 +810,7 @@ impl ReadXdr for Option { } impl WriteXdr for Option { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { if let Some(t) = self { @@ -772,35 +825,35 @@ impl WriteXdr for Option { } impl ReadXdr for Box { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| Ok(Box::new(T::read_xdr(r)?))) } } impl WriteXdr for Box { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| T::write_xdr(self, w)) } } impl ReadXdr for () { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(_r: &mut Limited) -> Result { Ok(()) } } impl WriteXdr for () { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { Ok(()) } } impl ReadXdr for [u8; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { r.consume_len(N)?; @@ -819,7 +872,7 @@ impl ReadXdr for [u8; N] { } impl WriteXdr for [u8; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { w.consume_len(N)?; @@ -833,7 +886,7 @@ impl WriteXdr for [u8; N] { } impl ReadXdr for [T; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let mut vec = Vec::with_capacity(N); @@ -848,7 +901,7 @@ impl ReadXdr for [T; N] { } impl WriteXdr for [T; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { for t in self { @@ -1207,7 +1260,7 @@ impl<'a, const MAX: u32> TryFrom<&'a VecM> for &'a str { } impl ReadXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1234,7 +1287,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1254,7 +1307,7 @@ impl WriteXdr for VecM { } impl ReadXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len = u32::read_xdr(r)?; @@ -1274,7 +1327,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1647,7 +1700,7 @@ impl<'a, const MAX: u32> TryFrom<&'a BytesM> for &'a str { } impl ReadXdr for BytesM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1674,7 +1727,7 @@ impl ReadXdr for BytesM { } impl WriteXdr for BytesM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2050,7 +2103,7 @@ impl<'a, const MAX: u32> TryFrom<&'a StringM> for &'a str { } impl ReadXdr for StringM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -2077,7 +2130,7 @@ impl ReadXdr for StringM { } impl WriteXdr for StringM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2123,7 +2176,7 @@ impl ReadXdr for Frame where T: ReadXdr, { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { // Read the frame header value that contains 1 flag-bit and a 33-bit length. // - The 1 flag bit is 0 when there are more frames for the same record. @@ -2143,10 +2196,8 @@ where } } -#[cfg(all(test, feature = "std"))] +#[cfg(all(test, feature = "alloc"))] mod tests { - use std::io::Cursor; - use super::*; #[test] @@ -2255,7 +2306,7 @@ mod tests { } } -#[cfg(all(test, feature = "std"))] +#[cfg(all(test, feature = "alloc"))] mod test { use super::*; diff --git a/spec/output/generator_spec_rust/block_comments.x/MyXDR.rs b/spec/output/generator_spec_rust/block_comments.x/MyXDR.rs index 6bb6392dc..0f509ea49 100644 --- a/spec/output/generator_spec_rust/block_comments.x/MyXDR.rs +++ b/spec/output/generator_spec_rust/block_comments.x/MyXDR.rs @@ -35,6 +35,7 @@ use alloc::{ borrow::ToOwned, boxed::Box, string::{FromUtf8Error, String}, + vec, vec::Vec, }; #[cfg(feature = "std")] @@ -43,14 +44,17 @@ use std::string::FromUtf8Error; #[cfg(feature = "arbitrary")] use arbitrary::Arbitrary; -// TODO: Add support for read/write xdr fns when std not available. - #[cfg(feature = "std")] use std::{ error, io, io::{BufRead, BufReader, Cursor, Read, Write}, }; +#[cfg(all(not(feature = "std"), feature = "alloc"))] +use embedded_io::{Error as _, ErrorType, Read, Write}; +#[cfg(all(not(feature = "std"), feature = "alloc"))] +use embedded_io_cursor::Cursor; + /// Error contains all errors returned by functions in this crate. It can be /// compared via `PartialEq`, however any contained IO errors will only be /// compared on their `ErrorKind`. @@ -66,6 +70,8 @@ pub enum Error { InvalidHex, #[cfg(feature = "std")] Io(io::Error), + #[cfg(all(not(feature = "std"), feature = "alloc"))] + Io(embedded_io::ErrorKind), DepthLimitExceeded, #[cfg(feature = "serde_json")] Json(serde_json::Error), @@ -82,13 +88,34 @@ impl PartialEq for Error { // case for comparing errors outputted by the XDR library is for // error case testing, and a lack of the ability to compare has a // detrimental affect on failure testing, so this is a tradeoff. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] (Self::Io(l), Self::Io(r)) => l.kind() == r.kind(), _ => core::mem::discriminant(self) == core::mem::discriminant(other), } } } + +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl embedded_io::Error for Error { + fn kind(&self) -> embedded_io::ErrorKind { + match self { + Self::Io(e) => *e, + _ => embedded_io::ErrorKind::Other, + } + } +} + +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl From> for Error { + fn from(value: embedded_io::ReadExactError) -> Self { + match value { + embedded_io::ReadExactError::UnexpectedEof => Error::Io(embedded_io::ErrorKind::Other), + embedded_io::ReadExactError::Other(e) => e + } + } +} + #[cfg(feature = "std")] impl error::Error for Error { #[must_use] @@ -115,6 +142,8 @@ impl fmt::Display for Error { Error::InvalidHex => write!(f, "hex invalid"), #[cfg(feature = "std")] Error::Io(e) => write!(f, "{e}"), + #[cfg(all(not(feature = "std"), feature = "alloc"))] + Error::Io(_) => write!(f, "io error"), Error::DepthLimitExceeded => write!(f, "depth limit exceeded"), #[cfg(feature = "serde_json")] Error::Json(e) => write!(f, "{e}"), @@ -167,6 +196,9 @@ impl From for () { #[allow(dead_code)] type Result = core::result::Result; +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl ErrorType for Limited { type Error = Error; } + /// Name defines types that assign a static name to their value, such as the /// name given to an identifier in an XDR enum, or the name given to the case in /// a union. @@ -200,7 +232,7 @@ where /// `Limits` contains the limits that a limited reader or writer will be /// constrained to. -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] #[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct Limits { /// Defines the maximum depth for recursive calls in `Read/WriteXdr` to @@ -217,7 +249,7 @@ pub struct Limits { pub len: usize, } -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] impl Limits { #[must_use] pub fn none() -> Self { @@ -248,13 +280,13 @@ impl Limits { /// /// Intended for use with readers and writers and limiting their reads and /// writes. -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] pub struct Limited { pub inner: L, pub(crate) limits: Limits, } -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] impl Limited { /// Constructs a new `Limited`. /// @@ -307,6 +339,15 @@ impl Read for Limited { } } + +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl Read for Limited { + /// Forwards the read operation to the wrapped object. + fn read(&mut self, buf: &mut [u8]) -> core::result::Result { + self.inner.read(buf).map_err(|e| Error::Io(e.kind())) + } +} + #[cfg(feature = "std")] impl BufRead for Limited { /// Forwards the read operation to the wrapped object. @@ -333,6 +374,18 @@ impl Write for Limited { } } +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl Write for Limited { + /// Forwards the write operation to the wrapped object. + fn write(&mut self, buf: &[u8]) -> core::result::Result { + self.inner.write(buf).map_err(|e| Error::Io(e.kind())) + } + + fn flush(&mut self) -> core::result::Result<(), Self::Error> { + self.inner.flush().map_err(|e| Error::Io(e.kind())) + } +} + #[cfg(feature = "std")] pub struct ReadXdrIter { reader: Limited>, @@ -406,7 +459,7 @@ where /// /// Use [`ReadXdR: Read_xdr_to_end`] when the intent is for all bytes in the /// read implementation to be consumed by the read. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result; /// Construct the type from the XDR bytes base64 encoded. @@ -441,7 +494,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr_to_end(r: &mut Limited) -> Result { let s = Self::read_xdr(r)?; // Check that any further reads, such as this read of one byte, read no @@ -481,7 +534,7 @@ where /// /// Use [`ReadXdR: Read_xdr_into_to_end`] when the intent is for all bytes /// in the read implementation to be consumed by the read. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr_into(&mut self, r: &mut Limited) -> Result<()> { *self = Self::read_xdr(r)?; Ok(()) @@ -505,7 +558,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr_into_to_end(&mut self, r: &mut Limited) -> Result<()> { Self::read_xdr_into(self, r)?; // Check that any further reads, such as this read of one byte, read no @@ -554,7 +607,7 @@ where /// /// An error is returned if the bytes are not completely consumed by the /// deserialization. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn from_xdr(bytes: impl AsRef<[u8]>, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(&mut cursor)?; @@ -578,10 +631,10 @@ where } pub trait WriteXdr { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()>; - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn to_xdr(&self, limits: Limits) -> Result> { let mut cursor = Limited::new(Cursor::new(vec![]), limits); self.write_xdr(&mut cursor)?; @@ -603,13 +656,13 @@ pub trait WriteXdr { /// `Pad_len` returns the number of bytes to pad an XDR value of the given /// length to make the final serialized size a multiple of 4. -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] fn pad_len(len: usize) -> usize { (4 - (len % 4)) % 4 } impl ReadXdr for i32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -621,7 +674,7 @@ impl ReadXdr for i32 { } impl WriteXdr for i32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -632,7 +685,7 @@ impl WriteXdr for i32 { } impl ReadXdr for u32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -644,7 +697,7 @@ impl ReadXdr for u32 { } impl WriteXdr for u32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -655,7 +708,7 @@ impl WriteXdr for u32 { } impl ReadXdr for i64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -667,7 +720,7 @@ impl ReadXdr for i64 { } impl WriteXdr for i64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -678,7 +731,7 @@ impl WriteXdr for i64 { } impl ReadXdr for u64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -690,7 +743,7 @@ impl ReadXdr for u64 { } impl WriteXdr for u64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -701,35 +754,35 @@ impl WriteXdr for u64 { } impl ReadXdr for f32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for f64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for bool { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -740,7 +793,7 @@ impl ReadXdr for bool { } impl WriteXdr for bool { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i = u32::from(*self); // true = 1, false = 0 @@ -750,7 +803,7 @@ impl WriteXdr for bool { } impl ReadXdr for Option { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -767,7 +820,7 @@ impl ReadXdr for Option { } impl WriteXdr for Option { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { if let Some(t) = self { @@ -782,35 +835,35 @@ impl WriteXdr for Option { } impl ReadXdr for Box { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| Ok(Box::new(T::read_xdr(r)?))) } } impl WriteXdr for Box { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| T::write_xdr(self, w)) } } impl ReadXdr for () { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(_r: &mut Limited) -> Result { Ok(()) } } impl WriteXdr for () { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { Ok(()) } } impl ReadXdr for [u8; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { r.consume_len(N)?; @@ -829,7 +882,7 @@ impl ReadXdr for [u8; N] { } impl WriteXdr for [u8; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { w.consume_len(N)?; @@ -843,7 +896,7 @@ impl WriteXdr for [u8; N] { } impl ReadXdr for [T; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let mut vec = Vec::with_capacity(N); @@ -858,7 +911,7 @@ impl ReadXdr for [T; N] { } impl WriteXdr for [T; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { for t in self { @@ -1217,7 +1270,7 @@ impl<'a, const MAX: u32> TryFrom<&'a VecM> for &'a str { } impl ReadXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1244,7 +1297,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1264,7 +1317,7 @@ impl WriteXdr for VecM { } impl ReadXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len = u32::read_xdr(r)?; @@ -1284,7 +1337,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1657,7 +1710,7 @@ impl<'a, const MAX: u32> TryFrom<&'a BytesM> for &'a str { } impl ReadXdr for BytesM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1684,7 +1737,7 @@ impl ReadXdr for BytesM { } impl WriteXdr for BytesM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2060,7 +2113,7 @@ impl<'a, const MAX: u32> TryFrom<&'a StringM> for &'a str { } impl ReadXdr for StringM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -2087,7 +2140,7 @@ impl ReadXdr for StringM { } impl WriteXdr for StringM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2133,7 +2186,7 @@ impl ReadXdr for Frame where T: ReadXdr, { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { // Read the frame header value that contains 1 flag-bit and a 33-bit length. // - The 1 flag bit is 0 when there are more frames for the same record. @@ -2153,10 +2206,8 @@ where } } -#[cfg(all(test, feature = "std"))] +#[cfg(all(test, feature = "alloc"))] mod tests { - use std::io::Cursor; - use super::*; #[test] @@ -2265,7 +2316,7 @@ mod tests { } } -#[cfg(all(test, feature = "std"))] +#[cfg(all(test, feature = "alloc"))] mod test { use super::*; @@ -2856,7 +2907,7 @@ impl From for i32 { } impl ReadXdr for AccountFlags { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let e = i32::read_xdr(r)?; @@ -2867,7 +2918,7 @@ impl ReadXdr for AccountFlags { } impl WriteXdr for AccountFlags { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i: i32 = (*self).into(); @@ -2955,7 +3006,7 @@ impl Type { pub const VARIANTS: [TypeVariant; 1] = [ TypeVariant::AccountFlags, ]; pub const VARIANTS_STR: [&'static str; 1] = [ "AccountFlags", ]; - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] #[allow(clippy::too_many_lines)] pub fn read_xdr(v: TypeVariant, r: &mut Limited) -> Result { match v { @@ -2970,7 +3021,7 @@ impl Type { Ok(t) } - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] pub fn read_xdr_to_end(v: TypeVariant, r: &mut Limited) -> Result { let s = Self::read_xdr(v, r)?; // Check that any further reads, such as this read of one byte, read no @@ -3014,7 +3065,7 @@ impl Type { } } - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] pub fn from_xdr>(v: TypeVariant, bytes: B, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(v, &mut cursor)?; @@ -3098,7 +3149,7 @@ impl Variants for Type { } impl WriteXdr for Type { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] #[allow(clippy::too_many_lines)] fn write_xdr(&self, w: &mut Limited) -> Result<()> { match self { diff --git a/spec/output/generator_spec_rust/const.x/MyXDR.rs b/spec/output/generator_spec_rust/const.x/MyXDR.rs index 966b54a40..d4d8e38ab 100644 --- a/spec/output/generator_spec_rust/const.x/MyXDR.rs +++ b/spec/output/generator_spec_rust/const.x/MyXDR.rs @@ -35,6 +35,7 @@ use alloc::{ borrow::ToOwned, boxed::Box, string::{FromUtf8Error, String}, + vec, vec::Vec, }; #[cfg(feature = "std")] @@ -43,14 +44,17 @@ use std::string::FromUtf8Error; #[cfg(feature = "arbitrary")] use arbitrary::Arbitrary; -// TODO: Add support for read/write xdr fns when std not available. - #[cfg(feature = "std")] use std::{ error, io, io::{BufRead, BufReader, Cursor, Read, Write}, }; +#[cfg(all(not(feature = "std"), feature = "alloc"))] +use embedded_io::{Error as _, ErrorType, Read, Write}; +#[cfg(all(not(feature = "std"), feature = "alloc"))] +use embedded_io_cursor::Cursor; + /// Error contains all errors returned by functions in this crate. It can be /// compared via `PartialEq`, however any contained IO errors will only be /// compared on their `ErrorKind`. @@ -66,6 +70,8 @@ pub enum Error { InvalidHex, #[cfg(feature = "std")] Io(io::Error), + #[cfg(all(not(feature = "std"), feature = "alloc"))] + Io(embedded_io::ErrorKind), DepthLimitExceeded, #[cfg(feature = "serde_json")] Json(serde_json::Error), @@ -82,13 +88,34 @@ impl PartialEq for Error { // case for comparing errors outputted by the XDR library is for // error case testing, and a lack of the ability to compare has a // detrimental affect on failure testing, so this is a tradeoff. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] (Self::Io(l), Self::Io(r)) => l.kind() == r.kind(), _ => core::mem::discriminant(self) == core::mem::discriminant(other), } } } + +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl embedded_io::Error for Error { + fn kind(&self) -> embedded_io::ErrorKind { + match self { + Self::Io(e) => *e, + _ => embedded_io::ErrorKind::Other, + } + } +} + +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl From> for Error { + fn from(value: embedded_io::ReadExactError) -> Self { + match value { + embedded_io::ReadExactError::UnexpectedEof => Error::Io(embedded_io::ErrorKind::Other), + embedded_io::ReadExactError::Other(e) => e + } + } +} + #[cfg(feature = "std")] impl error::Error for Error { #[must_use] @@ -115,6 +142,8 @@ impl fmt::Display for Error { Error::InvalidHex => write!(f, "hex invalid"), #[cfg(feature = "std")] Error::Io(e) => write!(f, "{e}"), + #[cfg(all(not(feature = "std"), feature = "alloc"))] + Error::Io(_) => write!(f, "io error"), Error::DepthLimitExceeded => write!(f, "depth limit exceeded"), #[cfg(feature = "serde_json")] Error::Json(e) => write!(f, "{e}"), @@ -167,6 +196,9 @@ impl From for () { #[allow(dead_code)] type Result = core::result::Result; +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl ErrorType for Limited { type Error = Error; } + /// Name defines types that assign a static name to their value, such as the /// name given to an identifier in an XDR enum, or the name given to the case in /// a union. @@ -200,7 +232,7 @@ where /// `Limits` contains the limits that a limited reader or writer will be /// constrained to. -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] #[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct Limits { /// Defines the maximum depth for recursive calls in `Read/WriteXdr` to @@ -217,7 +249,7 @@ pub struct Limits { pub len: usize, } -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] impl Limits { #[must_use] pub fn none() -> Self { @@ -248,13 +280,13 @@ impl Limits { /// /// Intended for use with readers and writers and limiting their reads and /// writes. -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] pub struct Limited { pub inner: L, pub(crate) limits: Limits, } -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] impl Limited { /// Constructs a new `Limited`. /// @@ -307,6 +339,15 @@ impl Read for Limited { } } + +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl Read for Limited { + /// Forwards the read operation to the wrapped object. + fn read(&mut self, buf: &mut [u8]) -> core::result::Result { + self.inner.read(buf).map_err(|e| Error::Io(e.kind())) + } +} + #[cfg(feature = "std")] impl BufRead for Limited { /// Forwards the read operation to the wrapped object. @@ -333,6 +374,18 @@ impl Write for Limited { } } +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl Write for Limited { + /// Forwards the write operation to the wrapped object. + fn write(&mut self, buf: &[u8]) -> core::result::Result { + self.inner.write(buf).map_err(|e| Error::Io(e.kind())) + } + + fn flush(&mut self) -> core::result::Result<(), Self::Error> { + self.inner.flush().map_err(|e| Error::Io(e.kind())) + } +} + #[cfg(feature = "std")] pub struct ReadXdrIter { reader: Limited>, @@ -406,7 +459,7 @@ where /// /// Use [`ReadXdR: Read_xdr_to_end`] when the intent is for all bytes in the /// read implementation to be consumed by the read. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result; /// Construct the type from the XDR bytes base64 encoded. @@ -441,7 +494,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr_to_end(r: &mut Limited) -> Result { let s = Self::read_xdr(r)?; // Check that any further reads, such as this read of one byte, read no @@ -481,7 +534,7 @@ where /// /// Use [`ReadXdR: Read_xdr_into_to_end`] when the intent is for all bytes /// in the read implementation to be consumed by the read. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr_into(&mut self, r: &mut Limited) -> Result<()> { *self = Self::read_xdr(r)?; Ok(()) @@ -505,7 +558,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr_into_to_end(&mut self, r: &mut Limited) -> Result<()> { Self::read_xdr_into(self, r)?; // Check that any further reads, such as this read of one byte, read no @@ -554,7 +607,7 @@ where /// /// An error is returned if the bytes are not completely consumed by the /// deserialization. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn from_xdr(bytes: impl AsRef<[u8]>, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(&mut cursor)?; @@ -578,10 +631,10 @@ where } pub trait WriteXdr { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()>; - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn to_xdr(&self, limits: Limits) -> Result> { let mut cursor = Limited::new(Cursor::new(vec![]), limits); self.write_xdr(&mut cursor)?; @@ -603,13 +656,13 @@ pub trait WriteXdr { /// `Pad_len` returns the number of bytes to pad an XDR value of the given /// length to make the final serialized size a multiple of 4. -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] fn pad_len(len: usize) -> usize { (4 - (len % 4)) % 4 } impl ReadXdr for i32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -621,7 +674,7 @@ impl ReadXdr for i32 { } impl WriteXdr for i32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -632,7 +685,7 @@ impl WriteXdr for i32 { } impl ReadXdr for u32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -644,7 +697,7 @@ impl ReadXdr for u32 { } impl WriteXdr for u32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -655,7 +708,7 @@ impl WriteXdr for u32 { } impl ReadXdr for i64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -667,7 +720,7 @@ impl ReadXdr for i64 { } impl WriteXdr for i64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -678,7 +731,7 @@ impl WriteXdr for i64 { } impl ReadXdr for u64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -690,7 +743,7 @@ impl ReadXdr for u64 { } impl WriteXdr for u64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -701,35 +754,35 @@ impl WriteXdr for u64 { } impl ReadXdr for f32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for f64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for bool { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -740,7 +793,7 @@ impl ReadXdr for bool { } impl WriteXdr for bool { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i = u32::from(*self); // true = 1, false = 0 @@ -750,7 +803,7 @@ impl WriteXdr for bool { } impl ReadXdr for Option { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -767,7 +820,7 @@ impl ReadXdr for Option { } impl WriteXdr for Option { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { if let Some(t) = self { @@ -782,35 +835,35 @@ impl WriteXdr for Option { } impl ReadXdr for Box { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| Ok(Box::new(T::read_xdr(r)?))) } } impl WriteXdr for Box { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| T::write_xdr(self, w)) } } impl ReadXdr for () { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(_r: &mut Limited) -> Result { Ok(()) } } impl WriteXdr for () { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { Ok(()) } } impl ReadXdr for [u8; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { r.consume_len(N)?; @@ -829,7 +882,7 @@ impl ReadXdr for [u8; N] { } impl WriteXdr for [u8; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { w.consume_len(N)?; @@ -843,7 +896,7 @@ impl WriteXdr for [u8; N] { } impl ReadXdr for [T; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let mut vec = Vec::with_capacity(N); @@ -858,7 +911,7 @@ impl ReadXdr for [T; N] { } impl WriteXdr for [T; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { for t in self { @@ -1217,7 +1270,7 @@ impl<'a, const MAX: u32> TryFrom<&'a VecM> for &'a str { } impl ReadXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1244,7 +1297,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1264,7 +1317,7 @@ impl WriteXdr for VecM { } impl ReadXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len = u32::read_xdr(r)?; @@ -1284,7 +1337,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1657,7 +1710,7 @@ impl<'a, const MAX: u32> TryFrom<&'a BytesM> for &'a str { } impl ReadXdr for BytesM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1684,7 +1737,7 @@ impl ReadXdr for BytesM { } impl WriteXdr for BytesM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2060,7 +2113,7 @@ impl<'a, const MAX: u32> TryFrom<&'a StringM> for &'a str { } impl ReadXdr for StringM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -2087,7 +2140,7 @@ impl ReadXdr for StringM { } impl WriteXdr for StringM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2133,7 +2186,7 @@ impl ReadXdr for Frame where T: ReadXdr, { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { // Read the frame header value that contains 1 flag-bit and a 33-bit length. // - The 1 flag bit is 0 when there are more frames for the same record. @@ -2153,10 +2206,8 @@ where } } -#[cfg(all(test, feature = "std"))] +#[cfg(all(test, feature = "alloc"))] mod tests { - use std::io::Cursor; - use super::*; #[test] @@ -2265,7 +2316,7 @@ mod tests { } } -#[cfg(all(test, feature = "std"))] +#[cfg(all(test, feature = "alloc"))] mod test { use super::*; @@ -2890,7 +2941,7 @@ TypeVariant::TestArray2, ]; pub const VARIANTS_STR: [&'static str; 2] = [ "TestArray", "TestArray2", ]; - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] #[allow(clippy::too_many_lines)] pub fn read_xdr(v: TypeVariant, r: &mut Limited) -> Result { match v { @@ -2906,7 +2957,7 @@ TypeVariant::TestArray2 => r.with_limited_depth(|r| Ok(Self::TestArray2(Box::new Ok(t) } - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] pub fn read_xdr_to_end(v: TypeVariant, r: &mut Limited) -> Result { let s = Self::read_xdr(v, r)?; // Check that any further reads, such as this read of one byte, read no @@ -2953,7 +3004,7 @@ TypeVariant::TestArray2 => Box::new(ReadXdrIter::<_, TestArray2>::new(dec, r.lim } } - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] pub fn from_xdr>(v: TypeVariant, bytes: B, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(v, &mut cursor)?; @@ -3042,7 +3093,7 @@ Self::TestArray2(_) => TypeVariant::TestArray2, } impl WriteXdr for Type { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] #[allow(clippy::too_many_lines)] fn write_xdr(&self, w: &mut Limited) -> Result<()> { match self { diff --git a/spec/output/generator_spec_rust/enum.x/MyXDR.rs b/spec/output/generator_spec_rust/enum.x/MyXDR.rs index 9968bbd13..cfc1b5e62 100644 --- a/spec/output/generator_spec_rust/enum.x/MyXDR.rs +++ b/spec/output/generator_spec_rust/enum.x/MyXDR.rs @@ -35,6 +35,7 @@ use alloc::{ borrow::ToOwned, boxed::Box, string::{FromUtf8Error, String}, + vec, vec::Vec, }; #[cfg(feature = "std")] @@ -43,14 +44,17 @@ use std::string::FromUtf8Error; #[cfg(feature = "arbitrary")] use arbitrary::Arbitrary; -// TODO: Add support for read/write xdr fns when std not available. - #[cfg(feature = "std")] use std::{ error, io, io::{BufRead, BufReader, Cursor, Read, Write}, }; +#[cfg(all(not(feature = "std"), feature = "alloc"))] +use embedded_io::{Error as _, ErrorType, Read, Write}; +#[cfg(all(not(feature = "std"), feature = "alloc"))] +use embedded_io_cursor::Cursor; + /// Error contains all errors returned by functions in this crate. It can be /// compared via `PartialEq`, however any contained IO errors will only be /// compared on their `ErrorKind`. @@ -66,6 +70,8 @@ pub enum Error { InvalidHex, #[cfg(feature = "std")] Io(io::Error), + #[cfg(all(not(feature = "std"), feature = "alloc"))] + Io(embedded_io::ErrorKind), DepthLimitExceeded, #[cfg(feature = "serde_json")] Json(serde_json::Error), @@ -82,13 +88,34 @@ impl PartialEq for Error { // case for comparing errors outputted by the XDR library is for // error case testing, and a lack of the ability to compare has a // detrimental affect on failure testing, so this is a tradeoff. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] (Self::Io(l), Self::Io(r)) => l.kind() == r.kind(), _ => core::mem::discriminant(self) == core::mem::discriminant(other), } } } + +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl embedded_io::Error for Error { + fn kind(&self) -> embedded_io::ErrorKind { + match self { + Self::Io(e) => *e, + _ => embedded_io::ErrorKind::Other, + } + } +} + +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl From> for Error { + fn from(value: embedded_io::ReadExactError) -> Self { + match value { + embedded_io::ReadExactError::UnexpectedEof => Error::Io(embedded_io::ErrorKind::Other), + embedded_io::ReadExactError::Other(e) => e + } + } +} + #[cfg(feature = "std")] impl error::Error for Error { #[must_use] @@ -115,6 +142,8 @@ impl fmt::Display for Error { Error::InvalidHex => write!(f, "hex invalid"), #[cfg(feature = "std")] Error::Io(e) => write!(f, "{e}"), + #[cfg(all(not(feature = "std"), feature = "alloc"))] + Error::Io(_) => write!(f, "io error"), Error::DepthLimitExceeded => write!(f, "depth limit exceeded"), #[cfg(feature = "serde_json")] Error::Json(e) => write!(f, "{e}"), @@ -167,6 +196,9 @@ impl From for () { #[allow(dead_code)] type Result = core::result::Result; +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl ErrorType for Limited { type Error = Error; } + /// Name defines types that assign a static name to their value, such as the /// name given to an identifier in an XDR enum, or the name given to the case in /// a union. @@ -200,7 +232,7 @@ where /// `Limits` contains the limits that a limited reader or writer will be /// constrained to. -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] #[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct Limits { /// Defines the maximum depth for recursive calls in `Read/WriteXdr` to @@ -217,7 +249,7 @@ pub struct Limits { pub len: usize, } -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] impl Limits { #[must_use] pub fn none() -> Self { @@ -248,13 +280,13 @@ impl Limits { /// /// Intended for use with readers and writers and limiting their reads and /// writes. -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] pub struct Limited { pub inner: L, pub(crate) limits: Limits, } -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] impl Limited { /// Constructs a new `Limited`. /// @@ -307,6 +339,15 @@ impl Read for Limited { } } + +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl Read for Limited { + /// Forwards the read operation to the wrapped object. + fn read(&mut self, buf: &mut [u8]) -> core::result::Result { + self.inner.read(buf).map_err(|e| Error::Io(e.kind())) + } +} + #[cfg(feature = "std")] impl BufRead for Limited { /// Forwards the read operation to the wrapped object. @@ -333,6 +374,18 @@ impl Write for Limited { } } +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl Write for Limited { + /// Forwards the write operation to the wrapped object. + fn write(&mut self, buf: &[u8]) -> core::result::Result { + self.inner.write(buf).map_err(|e| Error::Io(e.kind())) + } + + fn flush(&mut self) -> core::result::Result<(), Self::Error> { + self.inner.flush().map_err(|e| Error::Io(e.kind())) + } +} + #[cfg(feature = "std")] pub struct ReadXdrIter { reader: Limited>, @@ -406,7 +459,7 @@ where /// /// Use [`ReadXdR: Read_xdr_to_end`] when the intent is for all bytes in the /// read implementation to be consumed by the read. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result; /// Construct the type from the XDR bytes base64 encoded. @@ -441,7 +494,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr_to_end(r: &mut Limited) -> Result { let s = Self::read_xdr(r)?; // Check that any further reads, such as this read of one byte, read no @@ -481,7 +534,7 @@ where /// /// Use [`ReadXdR: Read_xdr_into_to_end`] when the intent is for all bytes /// in the read implementation to be consumed by the read. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr_into(&mut self, r: &mut Limited) -> Result<()> { *self = Self::read_xdr(r)?; Ok(()) @@ -505,7 +558,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr_into_to_end(&mut self, r: &mut Limited) -> Result<()> { Self::read_xdr_into(self, r)?; // Check that any further reads, such as this read of one byte, read no @@ -554,7 +607,7 @@ where /// /// An error is returned if the bytes are not completely consumed by the /// deserialization. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn from_xdr(bytes: impl AsRef<[u8]>, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(&mut cursor)?; @@ -578,10 +631,10 @@ where } pub trait WriteXdr { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()>; - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn to_xdr(&self, limits: Limits) -> Result> { let mut cursor = Limited::new(Cursor::new(vec![]), limits); self.write_xdr(&mut cursor)?; @@ -603,13 +656,13 @@ pub trait WriteXdr { /// `Pad_len` returns the number of bytes to pad an XDR value of the given /// length to make the final serialized size a multiple of 4. -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] fn pad_len(len: usize) -> usize { (4 - (len % 4)) % 4 } impl ReadXdr for i32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -621,7 +674,7 @@ impl ReadXdr for i32 { } impl WriteXdr for i32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -632,7 +685,7 @@ impl WriteXdr for i32 { } impl ReadXdr for u32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -644,7 +697,7 @@ impl ReadXdr for u32 { } impl WriteXdr for u32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -655,7 +708,7 @@ impl WriteXdr for u32 { } impl ReadXdr for i64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -667,7 +720,7 @@ impl ReadXdr for i64 { } impl WriteXdr for i64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -678,7 +731,7 @@ impl WriteXdr for i64 { } impl ReadXdr for u64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -690,7 +743,7 @@ impl ReadXdr for u64 { } impl WriteXdr for u64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -701,35 +754,35 @@ impl WriteXdr for u64 { } impl ReadXdr for f32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for f64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for bool { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -740,7 +793,7 @@ impl ReadXdr for bool { } impl WriteXdr for bool { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i = u32::from(*self); // true = 1, false = 0 @@ -750,7 +803,7 @@ impl WriteXdr for bool { } impl ReadXdr for Option { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -767,7 +820,7 @@ impl ReadXdr for Option { } impl WriteXdr for Option { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { if let Some(t) = self { @@ -782,35 +835,35 @@ impl WriteXdr for Option { } impl ReadXdr for Box { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| Ok(Box::new(T::read_xdr(r)?))) } } impl WriteXdr for Box { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| T::write_xdr(self, w)) } } impl ReadXdr for () { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(_r: &mut Limited) -> Result { Ok(()) } } impl WriteXdr for () { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { Ok(()) } } impl ReadXdr for [u8; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { r.consume_len(N)?; @@ -829,7 +882,7 @@ impl ReadXdr for [u8; N] { } impl WriteXdr for [u8; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { w.consume_len(N)?; @@ -843,7 +896,7 @@ impl WriteXdr for [u8; N] { } impl ReadXdr for [T; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let mut vec = Vec::with_capacity(N); @@ -858,7 +911,7 @@ impl ReadXdr for [T; N] { } impl WriteXdr for [T; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { for t in self { @@ -1217,7 +1270,7 @@ impl<'a, const MAX: u32> TryFrom<&'a VecM> for &'a str { } impl ReadXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1244,7 +1297,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1264,7 +1317,7 @@ impl WriteXdr for VecM { } impl ReadXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len = u32::read_xdr(r)?; @@ -1284,7 +1337,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1657,7 +1710,7 @@ impl<'a, const MAX: u32> TryFrom<&'a BytesM> for &'a str { } impl ReadXdr for BytesM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1684,7 +1737,7 @@ impl ReadXdr for BytesM { } impl WriteXdr for BytesM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2060,7 +2113,7 @@ impl<'a, const MAX: u32> TryFrom<&'a StringM> for &'a str { } impl ReadXdr for StringM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -2087,7 +2140,7 @@ impl ReadXdr for StringM { } impl WriteXdr for StringM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2133,7 +2186,7 @@ impl ReadXdr for Frame where T: ReadXdr, { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { // Read the frame header value that contains 1 flag-bit and a 33-bit length. // - The 1 flag bit is 0 when there are more frames for the same record. @@ -2153,10 +2206,8 @@ where } } -#[cfg(all(test, feature = "std"))] +#[cfg(all(test, feature = "alloc"))] mod tests { - use std::io::Cursor; - use super::*; #[test] @@ -2265,7 +2316,7 @@ mod tests { } } -#[cfg(all(test, feature = "std"))] +#[cfg(all(test, feature = "alloc"))] mod test { use super::*; @@ -2940,7 +2991,7 @@ Self::FbaMessage => "FbaMessage", } impl ReadXdr for MessageType { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let e = i32::read_xdr(r)?; @@ -2951,7 +3002,7 @@ Self::FbaMessage => "FbaMessage", } impl WriteXdr for MessageType { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i: i32 = (*self).into(); @@ -3049,7 +3100,7 @@ Self::Blue => "Blue", } impl ReadXdr for Color { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let e = i32::read_xdr(r)?; @@ -3060,7 +3111,7 @@ Self::Blue => "Blue", } impl WriteXdr for Color { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i: i32 = (*self).into(); @@ -3158,7 +3209,7 @@ Self::Blue2 => "Blue2", } impl ReadXdr for Color2 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let e = i32::read_xdr(r)?; @@ -3169,7 +3220,7 @@ Self::Blue2 => "Blue2", } impl WriteXdr for Color2 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i: i32 = (*self).into(); @@ -3267,7 +3318,7 @@ Self::R3 => "R3", } impl ReadXdr for Color3 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let e = i32::read_xdr(r)?; @@ -3278,7 +3329,7 @@ Self::R3 => "R3", } impl WriteXdr for Color3 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i: i32 = (*self).into(); @@ -3393,7 +3444,7 @@ TypeVariant::Color3, ]; "Color2", "Color3", ]; - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] #[allow(clippy::too_many_lines)] pub fn read_xdr(v: TypeVariant, r: &mut Limited) -> Result { match v { @@ -3411,7 +3462,7 @@ TypeVariant::Color3 => r.with_limited_depth(|r| Ok(Self::Color3(Box::new(Color3: Ok(t) } - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] pub fn read_xdr_to_end(v: TypeVariant, r: &mut Limited) -> Result { let s = Self::read_xdr(v, r)?; // Check that any further reads, such as this read of one byte, read no @@ -3464,7 +3515,7 @@ TypeVariant::Color3 => Box::new(ReadXdrIter::<_, Color3>::new(dec, r.limits.clon } } - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] pub fn from_xdr>(v: TypeVariant, bytes: B, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(v, &mut cursor)?; @@ -3563,7 +3614,7 @@ Self::Color3(_) => TypeVariant::Color3, } impl WriteXdr for Type { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] #[allow(clippy::too_many_lines)] fn write_xdr(&self, w: &mut Limited) -> Result<()> { match self { diff --git a/spec/output/generator_spec_rust/nesting.x/MyXDR.rs b/spec/output/generator_spec_rust/nesting.x/MyXDR.rs index 4cdff6d8b..038bb9c08 100644 --- a/spec/output/generator_spec_rust/nesting.x/MyXDR.rs +++ b/spec/output/generator_spec_rust/nesting.x/MyXDR.rs @@ -35,6 +35,7 @@ use alloc::{ borrow::ToOwned, boxed::Box, string::{FromUtf8Error, String}, + vec, vec::Vec, }; #[cfg(feature = "std")] @@ -43,14 +44,17 @@ use std::string::FromUtf8Error; #[cfg(feature = "arbitrary")] use arbitrary::Arbitrary; -// TODO: Add support for read/write xdr fns when std not available. - #[cfg(feature = "std")] use std::{ error, io, io::{BufRead, BufReader, Cursor, Read, Write}, }; +#[cfg(all(not(feature = "std"), feature = "alloc"))] +use embedded_io::{Error as _, ErrorType, Read, Write}; +#[cfg(all(not(feature = "std"), feature = "alloc"))] +use embedded_io_cursor::Cursor; + /// Error contains all errors returned by functions in this crate. It can be /// compared via `PartialEq`, however any contained IO errors will only be /// compared on their `ErrorKind`. @@ -66,6 +70,8 @@ pub enum Error { InvalidHex, #[cfg(feature = "std")] Io(io::Error), + #[cfg(all(not(feature = "std"), feature = "alloc"))] + Io(embedded_io::ErrorKind), DepthLimitExceeded, #[cfg(feature = "serde_json")] Json(serde_json::Error), @@ -82,13 +88,34 @@ impl PartialEq for Error { // case for comparing errors outputted by the XDR library is for // error case testing, and a lack of the ability to compare has a // detrimental affect on failure testing, so this is a tradeoff. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] (Self::Io(l), Self::Io(r)) => l.kind() == r.kind(), _ => core::mem::discriminant(self) == core::mem::discriminant(other), } } } + +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl embedded_io::Error for Error { + fn kind(&self) -> embedded_io::ErrorKind { + match self { + Self::Io(e) => *e, + _ => embedded_io::ErrorKind::Other, + } + } +} + +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl From> for Error { + fn from(value: embedded_io::ReadExactError) -> Self { + match value { + embedded_io::ReadExactError::UnexpectedEof => Error::Io(embedded_io::ErrorKind::Other), + embedded_io::ReadExactError::Other(e) => e + } + } +} + #[cfg(feature = "std")] impl error::Error for Error { #[must_use] @@ -115,6 +142,8 @@ impl fmt::Display for Error { Error::InvalidHex => write!(f, "hex invalid"), #[cfg(feature = "std")] Error::Io(e) => write!(f, "{e}"), + #[cfg(all(not(feature = "std"), feature = "alloc"))] + Error::Io(_) => write!(f, "io error"), Error::DepthLimitExceeded => write!(f, "depth limit exceeded"), #[cfg(feature = "serde_json")] Error::Json(e) => write!(f, "{e}"), @@ -167,6 +196,9 @@ impl From for () { #[allow(dead_code)] type Result = core::result::Result; +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl ErrorType for Limited { type Error = Error; } + /// Name defines types that assign a static name to their value, such as the /// name given to an identifier in an XDR enum, or the name given to the case in /// a union. @@ -200,7 +232,7 @@ where /// `Limits` contains the limits that a limited reader or writer will be /// constrained to. -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] #[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct Limits { /// Defines the maximum depth for recursive calls in `Read/WriteXdr` to @@ -217,7 +249,7 @@ pub struct Limits { pub len: usize, } -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] impl Limits { #[must_use] pub fn none() -> Self { @@ -248,13 +280,13 @@ impl Limits { /// /// Intended for use with readers and writers and limiting their reads and /// writes. -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] pub struct Limited { pub inner: L, pub(crate) limits: Limits, } -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] impl Limited { /// Constructs a new `Limited`. /// @@ -307,6 +339,15 @@ impl Read for Limited { } } + +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl Read for Limited { + /// Forwards the read operation to the wrapped object. + fn read(&mut self, buf: &mut [u8]) -> core::result::Result { + self.inner.read(buf).map_err(|e| Error::Io(e.kind())) + } +} + #[cfg(feature = "std")] impl BufRead for Limited { /// Forwards the read operation to the wrapped object. @@ -333,6 +374,18 @@ impl Write for Limited { } } +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl Write for Limited { + /// Forwards the write operation to the wrapped object. + fn write(&mut self, buf: &[u8]) -> core::result::Result { + self.inner.write(buf).map_err(|e| Error::Io(e.kind())) + } + + fn flush(&mut self) -> core::result::Result<(), Self::Error> { + self.inner.flush().map_err(|e| Error::Io(e.kind())) + } +} + #[cfg(feature = "std")] pub struct ReadXdrIter { reader: Limited>, @@ -406,7 +459,7 @@ where /// /// Use [`ReadXdR: Read_xdr_to_end`] when the intent is for all bytes in the /// read implementation to be consumed by the read. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result; /// Construct the type from the XDR bytes base64 encoded. @@ -441,7 +494,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr_to_end(r: &mut Limited) -> Result { let s = Self::read_xdr(r)?; // Check that any further reads, such as this read of one byte, read no @@ -481,7 +534,7 @@ where /// /// Use [`ReadXdR: Read_xdr_into_to_end`] when the intent is for all bytes /// in the read implementation to be consumed by the read. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr_into(&mut self, r: &mut Limited) -> Result<()> { *self = Self::read_xdr(r)?; Ok(()) @@ -505,7 +558,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr_into_to_end(&mut self, r: &mut Limited) -> Result<()> { Self::read_xdr_into(self, r)?; // Check that any further reads, such as this read of one byte, read no @@ -554,7 +607,7 @@ where /// /// An error is returned if the bytes are not completely consumed by the /// deserialization. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn from_xdr(bytes: impl AsRef<[u8]>, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(&mut cursor)?; @@ -578,10 +631,10 @@ where } pub trait WriteXdr { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()>; - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn to_xdr(&self, limits: Limits) -> Result> { let mut cursor = Limited::new(Cursor::new(vec![]), limits); self.write_xdr(&mut cursor)?; @@ -603,13 +656,13 @@ pub trait WriteXdr { /// `Pad_len` returns the number of bytes to pad an XDR value of the given /// length to make the final serialized size a multiple of 4. -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] fn pad_len(len: usize) -> usize { (4 - (len % 4)) % 4 } impl ReadXdr for i32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -621,7 +674,7 @@ impl ReadXdr for i32 { } impl WriteXdr for i32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -632,7 +685,7 @@ impl WriteXdr for i32 { } impl ReadXdr for u32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -644,7 +697,7 @@ impl ReadXdr for u32 { } impl WriteXdr for u32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -655,7 +708,7 @@ impl WriteXdr for u32 { } impl ReadXdr for i64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -667,7 +720,7 @@ impl ReadXdr for i64 { } impl WriteXdr for i64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -678,7 +731,7 @@ impl WriteXdr for i64 { } impl ReadXdr for u64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -690,7 +743,7 @@ impl ReadXdr for u64 { } impl WriteXdr for u64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -701,35 +754,35 @@ impl WriteXdr for u64 { } impl ReadXdr for f32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for f64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for bool { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -740,7 +793,7 @@ impl ReadXdr for bool { } impl WriteXdr for bool { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i = u32::from(*self); // true = 1, false = 0 @@ -750,7 +803,7 @@ impl WriteXdr for bool { } impl ReadXdr for Option { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -767,7 +820,7 @@ impl ReadXdr for Option { } impl WriteXdr for Option { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { if let Some(t) = self { @@ -782,35 +835,35 @@ impl WriteXdr for Option { } impl ReadXdr for Box { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| Ok(Box::new(T::read_xdr(r)?))) } } impl WriteXdr for Box { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| T::write_xdr(self, w)) } } impl ReadXdr for () { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(_r: &mut Limited) -> Result { Ok(()) } } impl WriteXdr for () { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { Ok(()) } } impl ReadXdr for [u8; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { r.consume_len(N)?; @@ -829,7 +882,7 @@ impl ReadXdr for [u8; N] { } impl WriteXdr for [u8; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { w.consume_len(N)?; @@ -843,7 +896,7 @@ impl WriteXdr for [u8; N] { } impl ReadXdr for [T; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let mut vec = Vec::with_capacity(N); @@ -858,7 +911,7 @@ impl ReadXdr for [T; N] { } impl WriteXdr for [T; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { for t in self { @@ -1217,7 +1270,7 @@ impl<'a, const MAX: u32> TryFrom<&'a VecM> for &'a str { } impl ReadXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1244,7 +1297,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1264,7 +1317,7 @@ impl WriteXdr for VecM { } impl ReadXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len = u32::read_xdr(r)?; @@ -1284,7 +1337,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1657,7 +1710,7 @@ impl<'a, const MAX: u32> TryFrom<&'a BytesM> for &'a str { } impl ReadXdr for BytesM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1684,7 +1737,7 @@ impl ReadXdr for BytesM { } impl WriteXdr for BytesM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2060,7 +2113,7 @@ impl<'a, const MAX: u32> TryFrom<&'a StringM> for &'a str { } impl ReadXdr for StringM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -2087,7 +2140,7 @@ impl ReadXdr for StringM { } impl WriteXdr for StringM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2133,7 +2186,7 @@ impl ReadXdr for Frame where T: ReadXdr, { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { // Read the frame header value that contains 1 flag-bit and a 33-bit length. // - The 1 flag bit is 0 when there are more frames for the same record. @@ -2153,10 +2206,8 @@ where } } -#[cfg(all(test, feature = "std"))] +#[cfg(all(test, feature = "alloc"))] mod tests { - use std::io::Cursor; - use super::*; #[test] @@ -2265,7 +2316,7 @@ mod tests { } } -#[cfg(all(test, feature = "std"))] +#[cfg(all(test, feature = "alloc"))] mod test { use super::*; @@ -2867,7 +2918,7 @@ Self::Offer => "Offer", } impl ReadXdr for UnionKey { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let e = i32::read_xdr(r)?; @@ -2878,7 +2929,7 @@ Self::Offer => "Offer", } impl WriteXdr for UnionKey { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i: i32 = (*self).into(); @@ -2912,7 +2963,7 @@ pub struct MyUnionOne { } impl ReadXdr for MyUnionOne { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { Ok(Self{ @@ -2923,7 +2974,7 @@ impl ReadXdr for MyUnionOne { } impl WriteXdr for MyUnionOne { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { self.some_int.write_xdr(w)?; @@ -2951,7 +3002,7 @@ pub struct MyUnionTwo { } impl ReadXdr for MyUnionTwo { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { Ok(Self{ @@ -2963,7 +3014,7 @@ foo: i32::read_xdr(r)?, } impl WriteXdr for MyUnionTwo { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { self.some_int.write_xdr(w)?; @@ -3066,7 +3117,7 @@ Self::Offer => UnionKey::Offer, impl Union for MyUnion {} impl ReadXdr for MyUnion { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let dv: UnionKey = ::read_xdr(r)?; @@ -3084,7 +3135,7 @@ UnionKey::Offer => Self::Offer, } impl WriteXdr for MyUnion { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { self.discriminant().write_xdr(w)?; @@ -3214,7 +3265,7 @@ TypeVariant::MyUnionTwo, ]; "MyUnionOne", "MyUnionTwo", ]; - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] #[allow(clippy::too_many_lines)] pub fn read_xdr(v: TypeVariant, r: &mut Limited) -> Result { match v { @@ -3233,7 +3284,7 @@ TypeVariant::MyUnionTwo => r.with_limited_depth(|r| Ok(Self::MyUnionTwo(Box::new Ok(t) } - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] pub fn read_xdr_to_end(v: TypeVariant, r: &mut Limited) -> Result { let s = Self::read_xdr(v, r)?; // Check that any further reads, such as this read of one byte, read no @@ -3289,7 +3340,7 @@ TypeVariant::MyUnionTwo => Box::new(ReadXdrIter::<_, MyUnionTwo>::new(dec, r.lim } } - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] pub fn from_xdr>(v: TypeVariant, bytes: B, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(v, &mut cursor)?; @@ -3393,7 +3444,7 @@ Self::MyUnionTwo(_) => TypeVariant::MyUnionTwo, } impl WriteXdr for Type { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] #[allow(clippy::too_many_lines)] fn write_xdr(&self, w: &mut Limited) -> Result<()> { match self { diff --git a/spec/output/generator_spec_rust/optional.x/MyXDR.rs b/spec/output/generator_spec_rust/optional.x/MyXDR.rs index b9454b181..bd6ef6b10 100644 --- a/spec/output/generator_spec_rust/optional.x/MyXDR.rs +++ b/spec/output/generator_spec_rust/optional.x/MyXDR.rs @@ -35,6 +35,7 @@ use alloc::{ borrow::ToOwned, boxed::Box, string::{FromUtf8Error, String}, + vec, vec::Vec, }; #[cfg(feature = "std")] @@ -43,14 +44,17 @@ use std::string::FromUtf8Error; #[cfg(feature = "arbitrary")] use arbitrary::Arbitrary; -// TODO: Add support for read/write xdr fns when std not available. - #[cfg(feature = "std")] use std::{ error, io, io::{BufRead, BufReader, Cursor, Read, Write}, }; +#[cfg(all(not(feature = "std"), feature = "alloc"))] +use embedded_io::{Error as _, ErrorType, Read, Write}; +#[cfg(all(not(feature = "std"), feature = "alloc"))] +use embedded_io_cursor::Cursor; + /// Error contains all errors returned by functions in this crate. It can be /// compared via `PartialEq`, however any contained IO errors will only be /// compared on their `ErrorKind`. @@ -66,6 +70,8 @@ pub enum Error { InvalidHex, #[cfg(feature = "std")] Io(io::Error), + #[cfg(all(not(feature = "std"), feature = "alloc"))] + Io(embedded_io::ErrorKind), DepthLimitExceeded, #[cfg(feature = "serde_json")] Json(serde_json::Error), @@ -82,13 +88,34 @@ impl PartialEq for Error { // case for comparing errors outputted by the XDR library is for // error case testing, and a lack of the ability to compare has a // detrimental affect on failure testing, so this is a tradeoff. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] (Self::Io(l), Self::Io(r)) => l.kind() == r.kind(), _ => core::mem::discriminant(self) == core::mem::discriminant(other), } } } + +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl embedded_io::Error for Error { + fn kind(&self) -> embedded_io::ErrorKind { + match self { + Self::Io(e) => *e, + _ => embedded_io::ErrorKind::Other, + } + } +} + +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl From> for Error { + fn from(value: embedded_io::ReadExactError) -> Self { + match value { + embedded_io::ReadExactError::UnexpectedEof => Error::Io(embedded_io::ErrorKind::Other), + embedded_io::ReadExactError::Other(e) => e + } + } +} + #[cfg(feature = "std")] impl error::Error for Error { #[must_use] @@ -115,6 +142,8 @@ impl fmt::Display for Error { Error::InvalidHex => write!(f, "hex invalid"), #[cfg(feature = "std")] Error::Io(e) => write!(f, "{e}"), + #[cfg(all(not(feature = "std"), feature = "alloc"))] + Error::Io(_) => write!(f, "io error"), Error::DepthLimitExceeded => write!(f, "depth limit exceeded"), #[cfg(feature = "serde_json")] Error::Json(e) => write!(f, "{e}"), @@ -167,6 +196,9 @@ impl From for () { #[allow(dead_code)] type Result = core::result::Result; +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl ErrorType for Limited { type Error = Error; } + /// Name defines types that assign a static name to their value, such as the /// name given to an identifier in an XDR enum, or the name given to the case in /// a union. @@ -200,7 +232,7 @@ where /// `Limits` contains the limits that a limited reader or writer will be /// constrained to. -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] #[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct Limits { /// Defines the maximum depth for recursive calls in `Read/WriteXdr` to @@ -217,7 +249,7 @@ pub struct Limits { pub len: usize, } -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] impl Limits { #[must_use] pub fn none() -> Self { @@ -248,13 +280,13 @@ impl Limits { /// /// Intended for use with readers and writers and limiting their reads and /// writes. -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] pub struct Limited { pub inner: L, pub(crate) limits: Limits, } -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] impl Limited { /// Constructs a new `Limited`. /// @@ -307,6 +339,15 @@ impl Read for Limited { } } + +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl Read for Limited { + /// Forwards the read operation to the wrapped object. + fn read(&mut self, buf: &mut [u8]) -> core::result::Result { + self.inner.read(buf).map_err(|e| Error::Io(e.kind())) + } +} + #[cfg(feature = "std")] impl BufRead for Limited { /// Forwards the read operation to the wrapped object. @@ -333,6 +374,18 @@ impl Write for Limited { } } +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl Write for Limited { + /// Forwards the write operation to the wrapped object. + fn write(&mut self, buf: &[u8]) -> core::result::Result { + self.inner.write(buf).map_err(|e| Error::Io(e.kind())) + } + + fn flush(&mut self) -> core::result::Result<(), Self::Error> { + self.inner.flush().map_err(|e| Error::Io(e.kind())) + } +} + #[cfg(feature = "std")] pub struct ReadXdrIter { reader: Limited>, @@ -406,7 +459,7 @@ where /// /// Use [`ReadXdR: Read_xdr_to_end`] when the intent is for all bytes in the /// read implementation to be consumed by the read. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result; /// Construct the type from the XDR bytes base64 encoded. @@ -441,7 +494,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr_to_end(r: &mut Limited) -> Result { let s = Self::read_xdr(r)?; // Check that any further reads, such as this read of one byte, read no @@ -481,7 +534,7 @@ where /// /// Use [`ReadXdR: Read_xdr_into_to_end`] when the intent is for all bytes /// in the read implementation to be consumed by the read. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr_into(&mut self, r: &mut Limited) -> Result<()> { *self = Self::read_xdr(r)?; Ok(()) @@ -505,7 +558,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr_into_to_end(&mut self, r: &mut Limited) -> Result<()> { Self::read_xdr_into(self, r)?; // Check that any further reads, such as this read of one byte, read no @@ -554,7 +607,7 @@ where /// /// An error is returned if the bytes are not completely consumed by the /// deserialization. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn from_xdr(bytes: impl AsRef<[u8]>, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(&mut cursor)?; @@ -578,10 +631,10 @@ where } pub trait WriteXdr { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()>; - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn to_xdr(&self, limits: Limits) -> Result> { let mut cursor = Limited::new(Cursor::new(vec![]), limits); self.write_xdr(&mut cursor)?; @@ -603,13 +656,13 @@ pub trait WriteXdr { /// `Pad_len` returns the number of bytes to pad an XDR value of the given /// length to make the final serialized size a multiple of 4. -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] fn pad_len(len: usize) -> usize { (4 - (len % 4)) % 4 } impl ReadXdr for i32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -621,7 +674,7 @@ impl ReadXdr for i32 { } impl WriteXdr for i32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -632,7 +685,7 @@ impl WriteXdr for i32 { } impl ReadXdr for u32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -644,7 +697,7 @@ impl ReadXdr for u32 { } impl WriteXdr for u32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -655,7 +708,7 @@ impl WriteXdr for u32 { } impl ReadXdr for i64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -667,7 +720,7 @@ impl ReadXdr for i64 { } impl WriteXdr for i64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -678,7 +731,7 @@ impl WriteXdr for i64 { } impl ReadXdr for u64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -690,7 +743,7 @@ impl ReadXdr for u64 { } impl WriteXdr for u64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -701,35 +754,35 @@ impl WriteXdr for u64 { } impl ReadXdr for f32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for f64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for bool { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -740,7 +793,7 @@ impl ReadXdr for bool { } impl WriteXdr for bool { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i = u32::from(*self); // true = 1, false = 0 @@ -750,7 +803,7 @@ impl WriteXdr for bool { } impl ReadXdr for Option { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -767,7 +820,7 @@ impl ReadXdr for Option { } impl WriteXdr for Option { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { if let Some(t) = self { @@ -782,35 +835,35 @@ impl WriteXdr for Option { } impl ReadXdr for Box { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| Ok(Box::new(T::read_xdr(r)?))) } } impl WriteXdr for Box { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| T::write_xdr(self, w)) } } impl ReadXdr for () { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(_r: &mut Limited) -> Result { Ok(()) } } impl WriteXdr for () { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { Ok(()) } } impl ReadXdr for [u8; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { r.consume_len(N)?; @@ -829,7 +882,7 @@ impl ReadXdr for [u8; N] { } impl WriteXdr for [u8; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { w.consume_len(N)?; @@ -843,7 +896,7 @@ impl WriteXdr for [u8; N] { } impl ReadXdr for [T; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let mut vec = Vec::with_capacity(N); @@ -858,7 +911,7 @@ impl ReadXdr for [T; N] { } impl WriteXdr for [T; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { for t in self { @@ -1217,7 +1270,7 @@ impl<'a, const MAX: u32> TryFrom<&'a VecM> for &'a str { } impl ReadXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1244,7 +1297,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1264,7 +1317,7 @@ impl WriteXdr for VecM { } impl ReadXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len = u32::read_xdr(r)?; @@ -1284,7 +1337,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1657,7 +1710,7 @@ impl<'a, const MAX: u32> TryFrom<&'a BytesM> for &'a str { } impl ReadXdr for BytesM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1684,7 +1737,7 @@ impl ReadXdr for BytesM { } impl WriteXdr for BytesM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2060,7 +2113,7 @@ impl<'a, const MAX: u32> TryFrom<&'a StringM> for &'a str { } impl ReadXdr for StringM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -2087,7 +2140,7 @@ impl ReadXdr for StringM { } impl WriteXdr for StringM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2133,7 +2186,7 @@ impl ReadXdr for Frame where T: ReadXdr, { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { // Read the frame header value that contains 1 flag-bit and a 33-bit length. // - The 1 flag bit is 0 when there are more frames for the same record. @@ -2153,10 +2206,8 @@ where } } -#[cfg(all(test, feature = "std"))] +#[cfg(all(test, feature = "alloc"))] mod tests { - use std::io::Cursor; - use super::*; #[test] @@ -2265,7 +2316,7 @@ mod tests { } } -#[cfg(all(test, feature = "std"))] +#[cfg(all(test, feature = "alloc"))] mod test { use super::*; @@ -2808,7 +2859,7 @@ pub struct HasOptions { } impl ReadXdr for HasOptions { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { Ok(Self{ @@ -2821,7 +2872,7 @@ third_option: Option::::read_xdr(r)?, } impl WriteXdr for HasOptions { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { self.first_option.write_xdr(w)?; @@ -2920,7 +2971,7 @@ TypeVariant::HasOptions, ]; pub const VARIANTS_STR: [&'static str; 2] = [ "Arr", "HasOptions", ]; - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] #[allow(clippy::too_many_lines)] pub fn read_xdr(v: TypeVariant, r: &mut Limited) -> Result { match v { @@ -2936,7 +2987,7 @@ TypeVariant::HasOptions => r.with_limited_depth(|r| Ok(Self::HasOptions(Box::new Ok(t) } - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] pub fn read_xdr_to_end(v: TypeVariant, r: &mut Limited) -> Result { let s = Self::read_xdr(v, r)?; // Check that any further reads, such as this read of one byte, read no @@ -2983,7 +3034,7 @@ TypeVariant::HasOptions => Box::new(ReadXdrIter::<_, HasOptions>::new(dec, r.lim } } - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] pub fn from_xdr>(v: TypeVariant, bytes: B, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(v, &mut cursor)?; @@ -3072,7 +3123,7 @@ Self::HasOptions(_) => TypeVariant::HasOptions, } impl WriteXdr for Type { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] #[allow(clippy::too_many_lines)] fn write_xdr(&self, w: &mut Limited) -> Result<()> { match self { diff --git a/spec/output/generator_spec_rust/struct.x/MyXDR.rs b/spec/output/generator_spec_rust/struct.x/MyXDR.rs index 696a6f49a..0f788ddfb 100644 --- a/spec/output/generator_spec_rust/struct.x/MyXDR.rs +++ b/spec/output/generator_spec_rust/struct.x/MyXDR.rs @@ -35,6 +35,7 @@ use alloc::{ borrow::ToOwned, boxed::Box, string::{FromUtf8Error, String}, + vec, vec::Vec, }; #[cfg(feature = "std")] @@ -43,14 +44,17 @@ use std::string::FromUtf8Error; #[cfg(feature = "arbitrary")] use arbitrary::Arbitrary; -// TODO: Add support for read/write xdr fns when std not available. - #[cfg(feature = "std")] use std::{ error, io, io::{BufRead, BufReader, Cursor, Read, Write}, }; +#[cfg(all(not(feature = "std"), feature = "alloc"))] +use embedded_io::{Error as _, ErrorType, Read, Write}; +#[cfg(all(not(feature = "std"), feature = "alloc"))] +use embedded_io_cursor::Cursor; + /// Error contains all errors returned by functions in this crate. It can be /// compared via `PartialEq`, however any contained IO errors will only be /// compared on their `ErrorKind`. @@ -66,6 +70,8 @@ pub enum Error { InvalidHex, #[cfg(feature = "std")] Io(io::Error), + #[cfg(all(not(feature = "std"), feature = "alloc"))] + Io(embedded_io::ErrorKind), DepthLimitExceeded, #[cfg(feature = "serde_json")] Json(serde_json::Error), @@ -82,13 +88,34 @@ impl PartialEq for Error { // case for comparing errors outputted by the XDR library is for // error case testing, and a lack of the ability to compare has a // detrimental affect on failure testing, so this is a tradeoff. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] (Self::Io(l), Self::Io(r)) => l.kind() == r.kind(), _ => core::mem::discriminant(self) == core::mem::discriminant(other), } } } + +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl embedded_io::Error for Error { + fn kind(&self) -> embedded_io::ErrorKind { + match self { + Self::Io(e) => *e, + _ => embedded_io::ErrorKind::Other, + } + } +} + +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl From> for Error { + fn from(value: embedded_io::ReadExactError) -> Self { + match value { + embedded_io::ReadExactError::UnexpectedEof => Error::Io(embedded_io::ErrorKind::Other), + embedded_io::ReadExactError::Other(e) => e + } + } +} + #[cfg(feature = "std")] impl error::Error for Error { #[must_use] @@ -115,6 +142,8 @@ impl fmt::Display for Error { Error::InvalidHex => write!(f, "hex invalid"), #[cfg(feature = "std")] Error::Io(e) => write!(f, "{e}"), + #[cfg(all(not(feature = "std"), feature = "alloc"))] + Error::Io(_) => write!(f, "io error"), Error::DepthLimitExceeded => write!(f, "depth limit exceeded"), #[cfg(feature = "serde_json")] Error::Json(e) => write!(f, "{e}"), @@ -167,6 +196,9 @@ impl From for () { #[allow(dead_code)] type Result = core::result::Result; +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl ErrorType for Limited { type Error = Error; } + /// Name defines types that assign a static name to their value, such as the /// name given to an identifier in an XDR enum, or the name given to the case in /// a union. @@ -200,7 +232,7 @@ where /// `Limits` contains the limits that a limited reader or writer will be /// constrained to. -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] #[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct Limits { /// Defines the maximum depth for recursive calls in `Read/WriteXdr` to @@ -217,7 +249,7 @@ pub struct Limits { pub len: usize, } -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] impl Limits { #[must_use] pub fn none() -> Self { @@ -248,13 +280,13 @@ impl Limits { /// /// Intended for use with readers and writers and limiting their reads and /// writes. -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] pub struct Limited { pub inner: L, pub(crate) limits: Limits, } -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] impl Limited { /// Constructs a new `Limited`. /// @@ -307,6 +339,15 @@ impl Read for Limited { } } + +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl Read for Limited { + /// Forwards the read operation to the wrapped object. + fn read(&mut self, buf: &mut [u8]) -> core::result::Result { + self.inner.read(buf).map_err(|e| Error::Io(e.kind())) + } +} + #[cfg(feature = "std")] impl BufRead for Limited { /// Forwards the read operation to the wrapped object. @@ -333,6 +374,18 @@ impl Write for Limited { } } +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl Write for Limited { + /// Forwards the write operation to the wrapped object. + fn write(&mut self, buf: &[u8]) -> core::result::Result { + self.inner.write(buf).map_err(|e| Error::Io(e.kind())) + } + + fn flush(&mut self) -> core::result::Result<(), Self::Error> { + self.inner.flush().map_err(|e| Error::Io(e.kind())) + } +} + #[cfg(feature = "std")] pub struct ReadXdrIter { reader: Limited>, @@ -406,7 +459,7 @@ where /// /// Use [`ReadXdR: Read_xdr_to_end`] when the intent is for all bytes in the /// read implementation to be consumed by the read. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result; /// Construct the type from the XDR bytes base64 encoded. @@ -441,7 +494,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr_to_end(r: &mut Limited) -> Result { let s = Self::read_xdr(r)?; // Check that any further reads, such as this read of one byte, read no @@ -481,7 +534,7 @@ where /// /// Use [`ReadXdR: Read_xdr_into_to_end`] when the intent is for all bytes /// in the read implementation to be consumed by the read. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr_into(&mut self, r: &mut Limited) -> Result<()> { *self = Self::read_xdr(r)?; Ok(()) @@ -505,7 +558,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr_into_to_end(&mut self, r: &mut Limited) -> Result<()> { Self::read_xdr_into(self, r)?; // Check that any further reads, such as this read of one byte, read no @@ -554,7 +607,7 @@ where /// /// An error is returned if the bytes are not completely consumed by the /// deserialization. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn from_xdr(bytes: impl AsRef<[u8]>, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(&mut cursor)?; @@ -578,10 +631,10 @@ where } pub trait WriteXdr { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()>; - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn to_xdr(&self, limits: Limits) -> Result> { let mut cursor = Limited::new(Cursor::new(vec![]), limits); self.write_xdr(&mut cursor)?; @@ -603,13 +656,13 @@ pub trait WriteXdr { /// `Pad_len` returns the number of bytes to pad an XDR value of the given /// length to make the final serialized size a multiple of 4. -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] fn pad_len(len: usize) -> usize { (4 - (len % 4)) % 4 } impl ReadXdr for i32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -621,7 +674,7 @@ impl ReadXdr for i32 { } impl WriteXdr for i32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -632,7 +685,7 @@ impl WriteXdr for i32 { } impl ReadXdr for u32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -644,7 +697,7 @@ impl ReadXdr for u32 { } impl WriteXdr for u32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -655,7 +708,7 @@ impl WriteXdr for u32 { } impl ReadXdr for i64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -667,7 +720,7 @@ impl ReadXdr for i64 { } impl WriteXdr for i64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -678,7 +731,7 @@ impl WriteXdr for i64 { } impl ReadXdr for u64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -690,7 +743,7 @@ impl ReadXdr for u64 { } impl WriteXdr for u64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -701,35 +754,35 @@ impl WriteXdr for u64 { } impl ReadXdr for f32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for f64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for bool { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -740,7 +793,7 @@ impl ReadXdr for bool { } impl WriteXdr for bool { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i = u32::from(*self); // true = 1, false = 0 @@ -750,7 +803,7 @@ impl WriteXdr for bool { } impl ReadXdr for Option { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -767,7 +820,7 @@ impl ReadXdr for Option { } impl WriteXdr for Option { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { if let Some(t) = self { @@ -782,35 +835,35 @@ impl WriteXdr for Option { } impl ReadXdr for Box { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| Ok(Box::new(T::read_xdr(r)?))) } } impl WriteXdr for Box { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| T::write_xdr(self, w)) } } impl ReadXdr for () { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(_r: &mut Limited) -> Result { Ok(()) } } impl WriteXdr for () { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { Ok(()) } } impl ReadXdr for [u8; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { r.consume_len(N)?; @@ -829,7 +882,7 @@ impl ReadXdr for [u8; N] { } impl WriteXdr for [u8; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { w.consume_len(N)?; @@ -843,7 +896,7 @@ impl WriteXdr for [u8; N] { } impl ReadXdr for [T; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let mut vec = Vec::with_capacity(N); @@ -858,7 +911,7 @@ impl ReadXdr for [T; N] { } impl WriteXdr for [T; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { for t in self { @@ -1217,7 +1270,7 @@ impl<'a, const MAX: u32> TryFrom<&'a VecM> for &'a str { } impl ReadXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1244,7 +1297,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1264,7 +1317,7 @@ impl WriteXdr for VecM { } impl ReadXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len = u32::read_xdr(r)?; @@ -1284,7 +1337,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1657,7 +1710,7 @@ impl<'a, const MAX: u32> TryFrom<&'a BytesM> for &'a str { } impl ReadXdr for BytesM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1684,7 +1737,7 @@ impl ReadXdr for BytesM { } impl WriteXdr for BytesM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2060,7 +2113,7 @@ impl<'a, const MAX: u32> TryFrom<&'a StringM> for &'a str { } impl ReadXdr for StringM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -2087,7 +2140,7 @@ impl ReadXdr for StringM { } impl WriteXdr for StringM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2133,7 +2186,7 @@ impl ReadXdr for Frame where T: ReadXdr, { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { // Read the frame header value that contains 1 flag-bit and a 33-bit length. // - The 1 flag bit is 0 when there are more frames for the same record. @@ -2153,10 +2206,8 @@ where } } -#[cfg(all(test, feature = "std"))] +#[cfg(all(test, feature = "alloc"))] mod tests { - use std::io::Cursor; - use super::*; #[test] @@ -2265,7 +2316,7 @@ mod tests { } } -#[cfg(all(test, feature = "std"))] +#[cfg(all(test, feature = "alloc"))] mod test { use super::*; @@ -2812,7 +2863,7 @@ pub struct MyStruct { } impl ReadXdr for MyStruct { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { Ok(Self{ @@ -2827,7 +2878,7 @@ max_string: StringM::<100>::read_xdr(r)?, } impl WriteXdr for MyStruct { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { self.some_int.write_xdr(w)?; @@ -2928,7 +2979,7 @@ TypeVariant::MyStruct, ]; pub const VARIANTS_STR: [&'static str; 2] = [ "Int64", "MyStruct", ]; - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] #[allow(clippy::too_many_lines)] pub fn read_xdr(v: TypeVariant, r: &mut Limited) -> Result { match v { @@ -2944,7 +2995,7 @@ TypeVariant::MyStruct => r.with_limited_depth(|r| Ok(Self::MyStruct(Box::new(MyS Ok(t) } - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] pub fn read_xdr_to_end(v: TypeVariant, r: &mut Limited) -> Result { let s = Self::read_xdr(v, r)?; // Check that any further reads, such as this read of one byte, read no @@ -2991,7 +3042,7 @@ TypeVariant::MyStruct => Box::new(ReadXdrIter::<_, MyStruct>::new(dec, r.limits. } } - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] pub fn from_xdr>(v: TypeVariant, bytes: B, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(v, &mut cursor)?; @@ -3080,7 +3131,7 @@ Self::MyStruct(_) => TypeVariant::MyStruct, } impl WriteXdr for Type { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] #[allow(clippy::too_many_lines)] fn write_xdr(&self, w: &mut Limited) -> Result<()> { match self { diff --git a/spec/output/generator_spec_rust/test.x/MyXDR.rs b/spec/output/generator_spec_rust/test.x/MyXDR.rs index 5d234038f..2a35f2a19 100644 --- a/spec/output/generator_spec_rust/test.x/MyXDR.rs +++ b/spec/output/generator_spec_rust/test.x/MyXDR.rs @@ -35,6 +35,7 @@ use alloc::{ borrow::ToOwned, boxed::Box, string::{FromUtf8Error, String}, + vec, vec::Vec, }; #[cfg(feature = "std")] @@ -43,14 +44,17 @@ use std::string::FromUtf8Error; #[cfg(feature = "arbitrary")] use arbitrary::Arbitrary; -// TODO: Add support for read/write xdr fns when std not available. - #[cfg(feature = "std")] use std::{ error, io, io::{BufRead, BufReader, Cursor, Read, Write}, }; +#[cfg(all(not(feature = "std"), feature = "alloc"))] +use embedded_io::{Error as _, ErrorType, Read, Write}; +#[cfg(all(not(feature = "std"), feature = "alloc"))] +use embedded_io_cursor::Cursor; + /// Error contains all errors returned by functions in this crate. It can be /// compared via `PartialEq`, however any contained IO errors will only be /// compared on their `ErrorKind`. @@ -66,6 +70,8 @@ pub enum Error { InvalidHex, #[cfg(feature = "std")] Io(io::Error), + #[cfg(all(not(feature = "std"), feature = "alloc"))] + Io(embedded_io::ErrorKind), DepthLimitExceeded, #[cfg(feature = "serde_json")] Json(serde_json::Error), @@ -82,13 +88,34 @@ impl PartialEq for Error { // case for comparing errors outputted by the XDR library is for // error case testing, and a lack of the ability to compare has a // detrimental affect on failure testing, so this is a tradeoff. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] (Self::Io(l), Self::Io(r)) => l.kind() == r.kind(), _ => core::mem::discriminant(self) == core::mem::discriminant(other), } } } + +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl embedded_io::Error for Error { + fn kind(&self) -> embedded_io::ErrorKind { + match self { + Self::Io(e) => *e, + _ => embedded_io::ErrorKind::Other, + } + } +} + +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl From> for Error { + fn from(value: embedded_io::ReadExactError) -> Self { + match value { + embedded_io::ReadExactError::UnexpectedEof => Error::Io(embedded_io::ErrorKind::Other), + embedded_io::ReadExactError::Other(e) => e + } + } +} + #[cfg(feature = "std")] impl error::Error for Error { #[must_use] @@ -115,6 +142,8 @@ impl fmt::Display for Error { Error::InvalidHex => write!(f, "hex invalid"), #[cfg(feature = "std")] Error::Io(e) => write!(f, "{e}"), + #[cfg(all(not(feature = "std"), feature = "alloc"))] + Error::Io(_) => write!(f, "io error"), Error::DepthLimitExceeded => write!(f, "depth limit exceeded"), #[cfg(feature = "serde_json")] Error::Json(e) => write!(f, "{e}"), @@ -167,6 +196,9 @@ impl From for () { #[allow(dead_code)] type Result = core::result::Result; +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl ErrorType for Limited { type Error = Error; } + /// Name defines types that assign a static name to their value, such as the /// name given to an identifier in an XDR enum, or the name given to the case in /// a union. @@ -200,7 +232,7 @@ where /// `Limits` contains the limits that a limited reader or writer will be /// constrained to. -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] #[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct Limits { /// Defines the maximum depth for recursive calls in `Read/WriteXdr` to @@ -217,7 +249,7 @@ pub struct Limits { pub len: usize, } -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] impl Limits { #[must_use] pub fn none() -> Self { @@ -248,13 +280,13 @@ impl Limits { /// /// Intended for use with readers and writers and limiting their reads and /// writes. -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] pub struct Limited { pub inner: L, pub(crate) limits: Limits, } -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] impl Limited { /// Constructs a new `Limited`. /// @@ -307,6 +339,15 @@ impl Read for Limited { } } + +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl Read for Limited { + /// Forwards the read operation to the wrapped object. + fn read(&mut self, buf: &mut [u8]) -> core::result::Result { + self.inner.read(buf).map_err(|e| Error::Io(e.kind())) + } +} + #[cfg(feature = "std")] impl BufRead for Limited { /// Forwards the read operation to the wrapped object. @@ -333,6 +374,18 @@ impl Write for Limited { } } +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl Write for Limited { + /// Forwards the write operation to the wrapped object. + fn write(&mut self, buf: &[u8]) -> core::result::Result { + self.inner.write(buf).map_err(|e| Error::Io(e.kind())) + } + + fn flush(&mut self) -> core::result::Result<(), Self::Error> { + self.inner.flush().map_err(|e| Error::Io(e.kind())) + } +} + #[cfg(feature = "std")] pub struct ReadXdrIter { reader: Limited>, @@ -406,7 +459,7 @@ where /// /// Use [`ReadXdR: Read_xdr_to_end`] when the intent is for all bytes in the /// read implementation to be consumed by the read. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result; /// Construct the type from the XDR bytes base64 encoded. @@ -441,7 +494,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr_to_end(r: &mut Limited) -> Result { let s = Self::read_xdr(r)?; // Check that any further reads, such as this read of one byte, read no @@ -481,7 +534,7 @@ where /// /// Use [`ReadXdR: Read_xdr_into_to_end`] when the intent is for all bytes /// in the read implementation to be consumed by the read. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr_into(&mut self, r: &mut Limited) -> Result<()> { *self = Self::read_xdr(r)?; Ok(()) @@ -505,7 +558,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr_into_to_end(&mut self, r: &mut Limited) -> Result<()> { Self::read_xdr_into(self, r)?; // Check that any further reads, such as this read of one byte, read no @@ -554,7 +607,7 @@ where /// /// An error is returned if the bytes are not completely consumed by the /// deserialization. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn from_xdr(bytes: impl AsRef<[u8]>, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(&mut cursor)?; @@ -578,10 +631,10 @@ where } pub trait WriteXdr { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()>; - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn to_xdr(&self, limits: Limits) -> Result> { let mut cursor = Limited::new(Cursor::new(vec![]), limits); self.write_xdr(&mut cursor)?; @@ -603,13 +656,13 @@ pub trait WriteXdr { /// `Pad_len` returns the number of bytes to pad an XDR value of the given /// length to make the final serialized size a multiple of 4. -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] fn pad_len(len: usize) -> usize { (4 - (len % 4)) % 4 } impl ReadXdr for i32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -621,7 +674,7 @@ impl ReadXdr for i32 { } impl WriteXdr for i32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -632,7 +685,7 @@ impl WriteXdr for i32 { } impl ReadXdr for u32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -644,7 +697,7 @@ impl ReadXdr for u32 { } impl WriteXdr for u32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -655,7 +708,7 @@ impl WriteXdr for u32 { } impl ReadXdr for i64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -667,7 +720,7 @@ impl ReadXdr for i64 { } impl WriteXdr for i64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -678,7 +731,7 @@ impl WriteXdr for i64 { } impl ReadXdr for u64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -690,7 +743,7 @@ impl ReadXdr for u64 { } impl WriteXdr for u64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -701,35 +754,35 @@ impl WriteXdr for u64 { } impl ReadXdr for f32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for f64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for bool { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -740,7 +793,7 @@ impl ReadXdr for bool { } impl WriteXdr for bool { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i = u32::from(*self); // true = 1, false = 0 @@ -750,7 +803,7 @@ impl WriteXdr for bool { } impl ReadXdr for Option { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -767,7 +820,7 @@ impl ReadXdr for Option { } impl WriteXdr for Option { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { if let Some(t) = self { @@ -782,35 +835,35 @@ impl WriteXdr for Option { } impl ReadXdr for Box { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| Ok(Box::new(T::read_xdr(r)?))) } } impl WriteXdr for Box { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| T::write_xdr(self, w)) } } impl ReadXdr for () { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(_r: &mut Limited) -> Result { Ok(()) } } impl WriteXdr for () { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { Ok(()) } } impl ReadXdr for [u8; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { r.consume_len(N)?; @@ -829,7 +882,7 @@ impl ReadXdr for [u8; N] { } impl WriteXdr for [u8; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { w.consume_len(N)?; @@ -843,7 +896,7 @@ impl WriteXdr for [u8; N] { } impl ReadXdr for [T; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let mut vec = Vec::with_capacity(N); @@ -858,7 +911,7 @@ impl ReadXdr for [T; N] { } impl WriteXdr for [T; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { for t in self { @@ -1217,7 +1270,7 @@ impl<'a, const MAX: u32> TryFrom<&'a VecM> for &'a str { } impl ReadXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1244,7 +1297,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1264,7 +1317,7 @@ impl WriteXdr for VecM { } impl ReadXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len = u32::read_xdr(r)?; @@ -1284,7 +1337,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1657,7 +1710,7 @@ impl<'a, const MAX: u32> TryFrom<&'a BytesM> for &'a str { } impl ReadXdr for BytesM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1684,7 +1737,7 @@ impl ReadXdr for BytesM { } impl WriteXdr for BytesM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2060,7 +2113,7 @@ impl<'a, const MAX: u32> TryFrom<&'a StringM> for &'a str { } impl ReadXdr for StringM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -2087,7 +2140,7 @@ impl ReadXdr for StringM { } impl WriteXdr for StringM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2133,7 +2186,7 @@ impl ReadXdr for Frame where T: ReadXdr, { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { // Read the frame header value that contains 1 flag-bit and a 33-bit length. // - The 1 flag bit is 0 when there are more frames for the same record. @@ -2153,10 +2206,8 @@ where } } -#[cfg(all(test, feature = "std"))] +#[cfg(all(test, feature = "alloc"))] mod tests { - use std::io::Cursor; - use super::*; #[test] @@ -2265,7 +2316,7 @@ mod tests { } } -#[cfg(all(test, feature = "std"))] +#[cfg(all(test, feature = "alloc"))] mod test { use super::*; @@ -2872,7 +2923,7 @@ impl AsRef<[u8; 64]> for Uint512 { } impl ReadXdr for Uint512 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = <[u8; 64]>::read_xdr(r)?; @@ -2883,7 +2934,7 @@ impl ReadXdr for Uint512 { } impl WriteXdr for Uint512 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w|{ self.0.write_xdr(w) }) } @@ -2962,7 +3013,7 @@ impl AsRef> for Uint513 { } impl ReadXdr for Uint513 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = BytesM::<64>::read_xdr(r)?; @@ -2973,7 +3024,7 @@ impl ReadXdr for Uint513 { } impl WriteXdr for Uint513 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w|{ self.0.write_xdr(w) }) } @@ -3064,7 +3115,7 @@ impl AsRef for Uint514 { } impl ReadXdr for Uint514 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = BytesM::read_xdr(r)?; @@ -3075,7 +3126,7 @@ impl ReadXdr for Uint514 { } impl WriteXdr for Uint514 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w|{ self.0.write_xdr(w) }) } @@ -3166,7 +3217,7 @@ impl AsRef> for Str { } impl ReadXdr for Str { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = StringM::<64>::read_xdr(r)?; @@ -3177,7 +3228,7 @@ impl ReadXdr for Str { } impl WriteXdr for Str { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w|{ self.0.write_xdr(w) }) } @@ -3268,7 +3319,7 @@ impl AsRef for Str2 { } impl ReadXdr for Str2 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = StringM::read_xdr(r)?; @@ -3279,7 +3330,7 @@ impl ReadXdr for Str2 { } impl WriteXdr for Str2 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w|{ self.0.write_xdr(w) }) } @@ -3428,7 +3479,7 @@ impl AsRef<[u8; 32]> for Hash { } impl ReadXdr for Hash { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = <[u8; 32]>::read_xdr(r)?; @@ -3439,7 +3490,7 @@ impl ReadXdr for Hash { } impl WriteXdr for Hash { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w|{ self.0.write_xdr(w) }) } @@ -3517,7 +3568,7 @@ impl AsRef<[Hash; 12]> for Hashes1 { } impl ReadXdr for Hashes1 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = <[Hash; 12]>::read_xdr(r)?; @@ -3528,7 +3579,7 @@ impl ReadXdr for Hashes1 { } impl WriteXdr for Hashes1 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w|{ self.0.write_xdr(w) }) } @@ -3607,7 +3658,7 @@ impl AsRef> for Hashes2 { } impl ReadXdr for Hashes2 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = VecM::::read_xdr(r)?; @@ -3618,7 +3669,7 @@ impl ReadXdr for Hashes2 { } impl WriteXdr for Hashes2 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w|{ self.0.write_xdr(w) }) } @@ -3709,7 +3760,7 @@ impl AsRef> for Hashes3 { } impl ReadXdr for Hashes3 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = VecM::::read_xdr(r)?; @@ -3720,7 +3771,7 @@ impl ReadXdr for Hashes3 { } impl WriteXdr for Hashes3 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w|{ self.0.write_xdr(w) }) } @@ -3810,7 +3861,7 @@ impl AsRef> for OptHash1 { } impl ReadXdr for OptHash1 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = Option::::read_xdr(r)?; @@ -3821,7 +3872,7 @@ impl ReadXdr for OptHash1 { } impl WriteXdr for OptHash1 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w|{ self.0.write_xdr(w) }) } @@ -3862,7 +3913,7 @@ impl AsRef> for OptHash2 { } impl ReadXdr for OptHash2 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = Option::::read_xdr(r)?; @@ -3873,7 +3924,7 @@ impl ReadXdr for OptHash2 { } impl WriteXdr for OptHash2 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w|{ self.0.write_xdr(w) }) } @@ -3941,7 +3992,7 @@ pub struct MyStruct { } impl ReadXdr for MyStruct { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { Ok(Self{ @@ -3958,7 +4009,7 @@ field7: bool::read_xdr(r)?, } impl WriteXdr for MyStruct { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { self.field1.write_xdr(w)?; @@ -3991,7 +4042,7 @@ pub struct LotsOfMyStructs { } impl ReadXdr for LotsOfMyStructs { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { Ok(Self{ @@ -4002,7 +4053,7 @@ impl ReadXdr for LotsOfMyStructs { } impl WriteXdr for LotsOfMyStructs { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { self.members.write_xdr(w)?; @@ -4029,7 +4080,7 @@ pub struct HasStuff { } impl ReadXdr for HasStuff { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { Ok(Self{ @@ -4040,7 +4091,7 @@ impl ReadXdr for HasStuff { } impl WriteXdr for HasStuff { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { self.data.write_xdr(w)?; @@ -4138,7 +4189,7 @@ Self::Green => "Green", } impl ReadXdr for Color { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let e = i32::read_xdr(r)?; @@ -4149,7 +4200,7 @@ Self::Green => "Green", } impl WriteXdr for Color { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i: i32 = (*self).into(); @@ -4257,7 +4308,7 @@ Self::B2 => "B2", } impl ReadXdr for NesterNestedEnum { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let e = i32::read_xdr(r)?; @@ -4268,7 +4319,7 @@ Self::B2 => "B2", } impl WriteXdr for NesterNestedEnum { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i: i32 = (*self).into(); @@ -4294,7 +4345,7 @@ pub struct NesterNestedStruct { } impl ReadXdr for NesterNestedStruct { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { Ok(Self{ @@ -4305,7 +4356,7 @@ impl ReadXdr for NesterNestedStruct { } impl WriteXdr for NesterNestedStruct { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { self.blah.write_xdr(w)?; @@ -4387,7 +4438,7 @@ impl Variants for NesterNestedUnion { impl Union for NesterNestedUnion {} impl ReadXdr for NesterNestedUnion { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let dv: Color = ::read_xdr(r)?; @@ -4403,7 +4454,7 @@ impl ReadXdr for NesterNestedUnion { } impl WriteXdr for NesterNestedUnion { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { self.discriminant().write_xdr(w)?; @@ -4452,7 +4503,7 @@ pub struct Nester { } impl ReadXdr for Nester { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { Ok(Self{ @@ -4465,7 +4516,7 @@ nested_union: NesterNestedUnion::read_xdr(r)?, } impl WriteXdr for Nester { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { self.nested_enum.write_xdr(w)?; @@ -4753,7 +4804,7 @@ TypeVariant::NesterNestedUnion, ]; "NesterNestedStruct", "NesterNestedUnion", ]; - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] #[allow(clippy::too_many_lines)] pub fn read_xdr(v: TypeVariant, r: &mut Limited) -> Result { match v { @@ -4790,7 +4841,7 @@ TypeVariant::NesterNestedUnion => r.with_limited_depth(|r| Ok(Self::NesterNested Ok(t) } - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] pub fn read_xdr_to_end(v: TypeVariant, r: &mut Limited) -> Result { let s = Self::read_xdr(v, r)?; // Check that any further reads, such as this read of one byte, read no @@ -4900,7 +4951,7 @@ TypeVariant::NesterNestedUnion => Box::new(ReadXdrIter::<_, NesterNestedUnion>:: } } - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] pub fn from_xdr>(v: TypeVariant, bytes: B, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(v, &mut cursor)?; @@ -5094,7 +5145,7 @@ Self::NesterNestedUnion(_) => TypeVariant::NesterNestedUnion, } impl WriteXdr for Type { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] #[allow(clippy::too_many_lines)] fn write_xdr(&self, w: &mut Limited) -> Result<()> { match self { diff --git a/spec/output/generator_spec_rust/union.x/MyXDR.rs b/spec/output/generator_spec_rust/union.x/MyXDR.rs index ad02b2966..a277e7408 100644 --- a/spec/output/generator_spec_rust/union.x/MyXDR.rs +++ b/spec/output/generator_spec_rust/union.x/MyXDR.rs @@ -35,6 +35,7 @@ use alloc::{ borrow::ToOwned, boxed::Box, string::{FromUtf8Error, String}, + vec, vec::Vec, }; #[cfg(feature = "std")] @@ -43,14 +44,17 @@ use std::string::FromUtf8Error; #[cfg(feature = "arbitrary")] use arbitrary::Arbitrary; -// TODO: Add support for read/write xdr fns when std not available. - #[cfg(feature = "std")] use std::{ error, io, io::{BufRead, BufReader, Cursor, Read, Write}, }; +#[cfg(all(not(feature = "std"), feature = "alloc"))] +use embedded_io::{Error as _, ErrorType, Read, Write}; +#[cfg(all(not(feature = "std"), feature = "alloc"))] +use embedded_io_cursor::Cursor; + /// Error contains all errors returned by functions in this crate. It can be /// compared via `PartialEq`, however any contained IO errors will only be /// compared on their `ErrorKind`. @@ -66,6 +70,8 @@ pub enum Error { InvalidHex, #[cfg(feature = "std")] Io(io::Error), + #[cfg(all(not(feature = "std"), feature = "alloc"))] + Io(embedded_io::ErrorKind), DepthLimitExceeded, #[cfg(feature = "serde_json")] Json(serde_json::Error), @@ -82,13 +88,34 @@ impl PartialEq for Error { // case for comparing errors outputted by the XDR library is for // error case testing, and a lack of the ability to compare has a // detrimental affect on failure testing, so this is a tradeoff. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] (Self::Io(l), Self::Io(r)) => l.kind() == r.kind(), _ => core::mem::discriminant(self) == core::mem::discriminant(other), } } } + +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl embedded_io::Error for Error { + fn kind(&self) -> embedded_io::ErrorKind { + match self { + Self::Io(e) => *e, + _ => embedded_io::ErrorKind::Other, + } + } +} + +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl From> for Error { + fn from(value: embedded_io::ReadExactError) -> Self { + match value { + embedded_io::ReadExactError::UnexpectedEof => Error::Io(embedded_io::ErrorKind::Other), + embedded_io::ReadExactError::Other(e) => e + } + } +} + #[cfg(feature = "std")] impl error::Error for Error { #[must_use] @@ -115,6 +142,8 @@ impl fmt::Display for Error { Error::InvalidHex => write!(f, "hex invalid"), #[cfg(feature = "std")] Error::Io(e) => write!(f, "{e}"), + #[cfg(all(not(feature = "std"), feature = "alloc"))] + Error::Io(_) => write!(f, "io error"), Error::DepthLimitExceeded => write!(f, "depth limit exceeded"), #[cfg(feature = "serde_json")] Error::Json(e) => write!(f, "{e}"), @@ -167,6 +196,9 @@ impl From for () { #[allow(dead_code)] type Result = core::result::Result; +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl ErrorType for Limited { type Error = Error; } + /// Name defines types that assign a static name to their value, such as the /// name given to an identifier in an XDR enum, or the name given to the case in /// a union. @@ -200,7 +232,7 @@ where /// `Limits` contains the limits that a limited reader or writer will be /// constrained to. -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] #[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct Limits { /// Defines the maximum depth for recursive calls in `Read/WriteXdr` to @@ -217,7 +249,7 @@ pub struct Limits { pub len: usize, } -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] impl Limits { #[must_use] pub fn none() -> Self { @@ -248,13 +280,13 @@ impl Limits { /// /// Intended for use with readers and writers and limiting their reads and /// writes. -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] pub struct Limited { pub inner: L, pub(crate) limits: Limits, } -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] impl Limited { /// Constructs a new `Limited`. /// @@ -307,6 +339,15 @@ impl Read for Limited { } } + +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl Read for Limited { + /// Forwards the read operation to the wrapped object. + fn read(&mut self, buf: &mut [u8]) -> core::result::Result { + self.inner.read(buf).map_err(|e| Error::Io(e.kind())) + } +} + #[cfg(feature = "std")] impl BufRead for Limited { /// Forwards the read operation to the wrapped object. @@ -333,6 +374,18 @@ impl Write for Limited { } } +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl Write for Limited { + /// Forwards the write operation to the wrapped object. + fn write(&mut self, buf: &[u8]) -> core::result::Result { + self.inner.write(buf).map_err(|e| Error::Io(e.kind())) + } + + fn flush(&mut self) -> core::result::Result<(), Self::Error> { + self.inner.flush().map_err(|e| Error::Io(e.kind())) + } +} + #[cfg(feature = "std")] pub struct ReadXdrIter { reader: Limited>, @@ -406,7 +459,7 @@ where /// /// Use [`ReadXdR: Read_xdr_to_end`] when the intent is for all bytes in the /// read implementation to be consumed by the read. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result; /// Construct the type from the XDR bytes base64 encoded. @@ -441,7 +494,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr_to_end(r: &mut Limited) -> Result { let s = Self::read_xdr(r)?; // Check that any further reads, such as this read of one byte, read no @@ -481,7 +534,7 @@ where /// /// Use [`ReadXdR: Read_xdr_into_to_end`] when the intent is for all bytes /// in the read implementation to be consumed by the read. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr_into(&mut self, r: &mut Limited) -> Result<()> { *self = Self::read_xdr(r)?; Ok(()) @@ -505,7 +558,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr_into_to_end(&mut self, r: &mut Limited) -> Result<()> { Self::read_xdr_into(self, r)?; // Check that any further reads, such as this read of one byte, read no @@ -554,7 +607,7 @@ where /// /// An error is returned if the bytes are not completely consumed by the /// deserialization. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn from_xdr(bytes: impl AsRef<[u8]>, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(&mut cursor)?; @@ -578,10 +631,10 @@ where } pub trait WriteXdr { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()>; - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn to_xdr(&self, limits: Limits) -> Result> { let mut cursor = Limited::new(Cursor::new(vec![]), limits); self.write_xdr(&mut cursor)?; @@ -603,13 +656,13 @@ pub trait WriteXdr { /// `Pad_len` returns the number of bytes to pad an XDR value of the given /// length to make the final serialized size a multiple of 4. -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] fn pad_len(len: usize) -> usize { (4 - (len % 4)) % 4 } impl ReadXdr for i32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -621,7 +674,7 @@ impl ReadXdr for i32 { } impl WriteXdr for i32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -632,7 +685,7 @@ impl WriteXdr for i32 { } impl ReadXdr for u32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -644,7 +697,7 @@ impl ReadXdr for u32 { } impl WriteXdr for u32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -655,7 +708,7 @@ impl WriteXdr for u32 { } impl ReadXdr for i64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -667,7 +720,7 @@ impl ReadXdr for i64 { } impl WriteXdr for i64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -678,7 +731,7 @@ impl WriteXdr for i64 { } impl ReadXdr for u64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -690,7 +743,7 @@ impl ReadXdr for u64 { } impl WriteXdr for u64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -701,35 +754,35 @@ impl WriteXdr for u64 { } impl ReadXdr for f32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for f64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for bool { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -740,7 +793,7 @@ impl ReadXdr for bool { } impl WriteXdr for bool { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i = u32::from(*self); // true = 1, false = 0 @@ -750,7 +803,7 @@ impl WriteXdr for bool { } impl ReadXdr for Option { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -767,7 +820,7 @@ impl ReadXdr for Option { } impl WriteXdr for Option { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { if let Some(t) = self { @@ -782,35 +835,35 @@ impl WriteXdr for Option { } impl ReadXdr for Box { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| Ok(Box::new(T::read_xdr(r)?))) } } impl WriteXdr for Box { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| T::write_xdr(self, w)) } } impl ReadXdr for () { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(_r: &mut Limited) -> Result { Ok(()) } } impl WriteXdr for () { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { Ok(()) } } impl ReadXdr for [u8; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { r.consume_len(N)?; @@ -829,7 +882,7 @@ impl ReadXdr for [u8; N] { } impl WriteXdr for [u8; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { w.consume_len(N)?; @@ -843,7 +896,7 @@ impl WriteXdr for [u8; N] { } impl ReadXdr for [T; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let mut vec = Vec::with_capacity(N); @@ -858,7 +911,7 @@ impl ReadXdr for [T; N] { } impl WriteXdr for [T; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { for t in self { @@ -1217,7 +1270,7 @@ impl<'a, const MAX: u32> TryFrom<&'a VecM> for &'a str { } impl ReadXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1244,7 +1297,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1264,7 +1317,7 @@ impl WriteXdr for VecM { } impl ReadXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len = u32::read_xdr(r)?; @@ -1284,7 +1337,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1657,7 +1710,7 @@ impl<'a, const MAX: u32> TryFrom<&'a BytesM> for &'a str { } impl ReadXdr for BytesM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1684,7 +1737,7 @@ impl ReadXdr for BytesM { } impl WriteXdr for BytesM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2060,7 +2113,7 @@ impl<'a, const MAX: u32> TryFrom<&'a StringM> for &'a str { } impl ReadXdr for StringM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -2087,7 +2140,7 @@ impl ReadXdr for StringM { } impl WriteXdr for StringM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2133,7 +2186,7 @@ impl ReadXdr for Frame where T: ReadXdr, { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { // Read the frame header value that contains 1 flag-bit and a 33-bit length. // - The 1 flag bit is 0 when there are more frames for the same record. @@ -2153,10 +2206,8 @@ where } } -#[cfg(all(test, feature = "std"))] +#[cfg(all(test, feature = "alloc"))] mod tests { - use std::io::Cursor; - use super::*; #[test] @@ -2265,7 +2316,7 @@ mod tests { } } -#[cfg(all(test, feature = "std"))] +#[cfg(all(test, feature = "alloc"))] mod test { use super::*; @@ -2877,7 +2928,7 @@ Self::Multi => "Multi", } impl ReadXdr for UnionKey { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let e = i32::read_xdr(r)?; @@ -2888,7 +2939,7 @@ Self::Multi => "Multi", } impl WriteXdr for UnionKey { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i: i32 = (*self).into(); @@ -2978,7 +3029,7 @@ Self::Multi(_) => UnionKey::Multi, impl Union for MyUnion {} impl ReadXdr for MyUnion { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let dv: UnionKey = ::read_xdr(r)?; @@ -2995,7 +3046,7 @@ UnionKey::Multi => Self::Multi(VecM::::read_xdr(r)?), } impl WriteXdr for MyUnion { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { self.discriminant().write_xdr(w)?; @@ -3089,7 +3140,7 @@ Self::V1(_) => 1, impl Union for IntUnion {} impl ReadXdr for IntUnion { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let dv: i32 = ::read_xdr(r)?; @@ -3106,7 +3157,7 @@ Self::V1(_) => 1, } impl WriteXdr for IntUnion { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { self.discriminant().write_xdr(w)?; @@ -3155,7 +3206,7 @@ impl AsRef for IntUnion2 { } impl ReadXdr for IntUnion2 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = IntUnion::read_xdr(r)?; @@ -3166,7 +3217,7 @@ impl ReadXdr for IntUnion2 { } impl WriteXdr for IntUnion2 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w|{ self.0.write_xdr(w) }) } @@ -3296,7 +3347,7 @@ TypeVariant::IntUnion2, ]; "IntUnion", "IntUnion2", ]; - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] #[allow(clippy::too_many_lines)] pub fn read_xdr(v: TypeVariant, r: &mut Limited) -> Result { match v { @@ -3316,7 +3367,7 @@ TypeVariant::IntUnion2 => r.with_limited_depth(|r| Ok(Self::IntUnion2(Box::new(I Ok(t) } - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] pub fn read_xdr_to_end(v: TypeVariant, r: &mut Limited) -> Result { let s = Self::read_xdr(v, r)?; // Check that any further reads, such as this read of one byte, read no @@ -3375,7 +3426,7 @@ TypeVariant::IntUnion2 => Box::new(ReadXdrIter::<_, IntUnion2>::new(dec, r.limit } } - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] pub fn from_xdr>(v: TypeVariant, bytes: B, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(v, &mut cursor)?; @@ -3484,7 +3535,7 @@ Self::IntUnion2(_) => TypeVariant::IntUnion2, } impl WriteXdr for Type { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] #[allow(clippy::too_many_lines)] fn write_xdr(&self, w: &mut Limited) -> Result<()> { match self { diff --git a/spec/output/generator_spec_rust_custom_jsonschema_impls/block_comments.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_jsonschema_impls/block_comments.x/MyXDR.rs index 6bb6392dc..0f509ea49 100644 --- a/spec/output/generator_spec_rust_custom_jsonschema_impls/block_comments.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_jsonschema_impls/block_comments.x/MyXDR.rs @@ -35,6 +35,7 @@ use alloc::{ borrow::ToOwned, boxed::Box, string::{FromUtf8Error, String}, + vec, vec::Vec, }; #[cfg(feature = "std")] @@ -43,14 +44,17 @@ use std::string::FromUtf8Error; #[cfg(feature = "arbitrary")] use arbitrary::Arbitrary; -// TODO: Add support for read/write xdr fns when std not available. - #[cfg(feature = "std")] use std::{ error, io, io::{BufRead, BufReader, Cursor, Read, Write}, }; +#[cfg(all(not(feature = "std"), feature = "alloc"))] +use embedded_io::{Error as _, ErrorType, Read, Write}; +#[cfg(all(not(feature = "std"), feature = "alloc"))] +use embedded_io_cursor::Cursor; + /// Error contains all errors returned by functions in this crate. It can be /// compared via `PartialEq`, however any contained IO errors will only be /// compared on their `ErrorKind`. @@ -66,6 +70,8 @@ pub enum Error { InvalidHex, #[cfg(feature = "std")] Io(io::Error), + #[cfg(all(not(feature = "std"), feature = "alloc"))] + Io(embedded_io::ErrorKind), DepthLimitExceeded, #[cfg(feature = "serde_json")] Json(serde_json::Error), @@ -82,13 +88,34 @@ impl PartialEq for Error { // case for comparing errors outputted by the XDR library is for // error case testing, and a lack of the ability to compare has a // detrimental affect on failure testing, so this is a tradeoff. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] (Self::Io(l), Self::Io(r)) => l.kind() == r.kind(), _ => core::mem::discriminant(self) == core::mem::discriminant(other), } } } + +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl embedded_io::Error for Error { + fn kind(&self) -> embedded_io::ErrorKind { + match self { + Self::Io(e) => *e, + _ => embedded_io::ErrorKind::Other, + } + } +} + +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl From> for Error { + fn from(value: embedded_io::ReadExactError) -> Self { + match value { + embedded_io::ReadExactError::UnexpectedEof => Error::Io(embedded_io::ErrorKind::Other), + embedded_io::ReadExactError::Other(e) => e + } + } +} + #[cfg(feature = "std")] impl error::Error for Error { #[must_use] @@ -115,6 +142,8 @@ impl fmt::Display for Error { Error::InvalidHex => write!(f, "hex invalid"), #[cfg(feature = "std")] Error::Io(e) => write!(f, "{e}"), + #[cfg(all(not(feature = "std"), feature = "alloc"))] + Error::Io(_) => write!(f, "io error"), Error::DepthLimitExceeded => write!(f, "depth limit exceeded"), #[cfg(feature = "serde_json")] Error::Json(e) => write!(f, "{e}"), @@ -167,6 +196,9 @@ impl From for () { #[allow(dead_code)] type Result = core::result::Result; +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl ErrorType for Limited { type Error = Error; } + /// Name defines types that assign a static name to their value, such as the /// name given to an identifier in an XDR enum, or the name given to the case in /// a union. @@ -200,7 +232,7 @@ where /// `Limits` contains the limits that a limited reader or writer will be /// constrained to. -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] #[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct Limits { /// Defines the maximum depth for recursive calls in `Read/WriteXdr` to @@ -217,7 +249,7 @@ pub struct Limits { pub len: usize, } -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] impl Limits { #[must_use] pub fn none() -> Self { @@ -248,13 +280,13 @@ impl Limits { /// /// Intended for use with readers and writers and limiting their reads and /// writes. -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] pub struct Limited { pub inner: L, pub(crate) limits: Limits, } -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] impl Limited { /// Constructs a new `Limited`. /// @@ -307,6 +339,15 @@ impl Read for Limited { } } + +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl Read for Limited { + /// Forwards the read operation to the wrapped object. + fn read(&mut self, buf: &mut [u8]) -> core::result::Result { + self.inner.read(buf).map_err(|e| Error::Io(e.kind())) + } +} + #[cfg(feature = "std")] impl BufRead for Limited { /// Forwards the read operation to the wrapped object. @@ -333,6 +374,18 @@ impl Write for Limited { } } +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl Write for Limited { + /// Forwards the write operation to the wrapped object. + fn write(&mut self, buf: &[u8]) -> core::result::Result { + self.inner.write(buf).map_err(|e| Error::Io(e.kind())) + } + + fn flush(&mut self) -> core::result::Result<(), Self::Error> { + self.inner.flush().map_err(|e| Error::Io(e.kind())) + } +} + #[cfg(feature = "std")] pub struct ReadXdrIter { reader: Limited>, @@ -406,7 +459,7 @@ where /// /// Use [`ReadXdR: Read_xdr_to_end`] when the intent is for all bytes in the /// read implementation to be consumed by the read. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result; /// Construct the type from the XDR bytes base64 encoded. @@ -441,7 +494,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr_to_end(r: &mut Limited) -> Result { let s = Self::read_xdr(r)?; // Check that any further reads, such as this read of one byte, read no @@ -481,7 +534,7 @@ where /// /// Use [`ReadXdR: Read_xdr_into_to_end`] when the intent is for all bytes /// in the read implementation to be consumed by the read. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr_into(&mut self, r: &mut Limited) -> Result<()> { *self = Self::read_xdr(r)?; Ok(()) @@ -505,7 +558,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr_into_to_end(&mut self, r: &mut Limited) -> Result<()> { Self::read_xdr_into(self, r)?; // Check that any further reads, such as this read of one byte, read no @@ -554,7 +607,7 @@ where /// /// An error is returned if the bytes are not completely consumed by the /// deserialization. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn from_xdr(bytes: impl AsRef<[u8]>, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(&mut cursor)?; @@ -578,10 +631,10 @@ where } pub trait WriteXdr { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()>; - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn to_xdr(&self, limits: Limits) -> Result> { let mut cursor = Limited::new(Cursor::new(vec![]), limits); self.write_xdr(&mut cursor)?; @@ -603,13 +656,13 @@ pub trait WriteXdr { /// `Pad_len` returns the number of bytes to pad an XDR value of the given /// length to make the final serialized size a multiple of 4. -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] fn pad_len(len: usize) -> usize { (4 - (len % 4)) % 4 } impl ReadXdr for i32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -621,7 +674,7 @@ impl ReadXdr for i32 { } impl WriteXdr for i32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -632,7 +685,7 @@ impl WriteXdr for i32 { } impl ReadXdr for u32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -644,7 +697,7 @@ impl ReadXdr for u32 { } impl WriteXdr for u32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -655,7 +708,7 @@ impl WriteXdr for u32 { } impl ReadXdr for i64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -667,7 +720,7 @@ impl ReadXdr for i64 { } impl WriteXdr for i64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -678,7 +731,7 @@ impl WriteXdr for i64 { } impl ReadXdr for u64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -690,7 +743,7 @@ impl ReadXdr for u64 { } impl WriteXdr for u64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -701,35 +754,35 @@ impl WriteXdr for u64 { } impl ReadXdr for f32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for f64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for bool { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -740,7 +793,7 @@ impl ReadXdr for bool { } impl WriteXdr for bool { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i = u32::from(*self); // true = 1, false = 0 @@ -750,7 +803,7 @@ impl WriteXdr for bool { } impl ReadXdr for Option { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -767,7 +820,7 @@ impl ReadXdr for Option { } impl WriteXdr for Option { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { if let Some(t) = self { @@ -782,35 +835,35 @@ impl WriteXdr for Option { } impl ReadXdr for Box { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| Ok(Box::new(T::read_xdr(r)?))) } } impl WriteXdr for Box { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| T::write_xdr(self, w)) } } impl ReadXdr for () { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(_r: &mut Limited) -> Result { Ok(()) } } impl WriteXdr for () { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { Ok(()) } } impl ReadXdr for [u8; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { r.consume_len(N)?; @@ -829,7 +882,7 @@ impl ReadXdr for [u8; N] { } impl WriteXdr for [u8; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { w.consume_len(N)?; @@ -843,7 +896,7 @@ impl WriteXdr for [u8; N] { } impl ReadXdr for [T; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let mut vec = Vec::with_capacity(N); @@ -858,7 +911,7 @@ impl ReadXdr for [T; N] { } impl WriteXdr for [T; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { for t in self { @@ -1217,7 +1270,7 @@ impl<'a, const MAX: u32> TryFrom<&'a VecM> for &'a str { } impl ReadXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1244,7 +1297,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1264,7 +1317,7 @@ impl WriteXdr for VecM { } impl ReadXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len = u32::read_xdr(r)?; @@ -1284,7 +1337,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1657,7 +1710,7 @@ impl<'a, const MAX: u32> TryFrom<&'a BytesM> for &'a str { } impl ReadXdr for BytesM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1684,7 +1737,7 @@ impl ReadXdr for BytesM { } impl WriteXdr for BytesM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2060,7 +2113,7 @@ impl<'a, const MAX: u32> TryFrom<&'a StringM> for &'a str { } impl ReadXdr for StringM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -2087,7 +2140,7 @@ impl ReadXdr for StringM { } impl WriteXdr for StringM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2133,7 +2186,7 @@ impl ReadXdr for Frame where T: ReadXdr, { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { // Read the frame header value that contains 1 flag-bit and a 33-bit length. // - The 1 flag bit is 0 when there are more frames for the same record. @@ -2153,10 +2206,8 @@ where } } -#[cfg(all(test, feature = "std"))] +#[cfg(all(test, feature = "alloc"))] mod tests { - use std::io::Cursor; - use super::*; #[test] @@ -2265,7 +2316,7 @@ mod tests { } } -#[cfg(all(test, feature = "std"))] +#[cfg(all(test, feature = "alloc"))] mod test { use super::*; @@ -2856,7 +2907,7 @@ impl From for i32 { } impl ReadXdr for AccountFlags { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let e = i32::read_xdr(r)?; @@ -2867,7 +2918,7 @@ impl ReadXdr for AccountFlags { } impl WriteXdr for AccountFlags { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i: i32 = (*self).into(); @@ -2955,7 +3006,7 @@ impl Type { pub const VARIANTS: [TypeVariant; 1] = [ TypeVariant::AccountFlags, ]; pub const VARIANTS_STR: [&'static str; 1] = [ "AccountFlags", ]; - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] #[allow(clippy::too_many_lines)] pub fn read_xdr(v: TypeVariant, r: &mut Limited) -> Result { match v { @@ -2970,7 +3021,7 @@ impl Type { Ok(t) } - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] pub fn read_xdr_to_end(v: TypeVariant, r: &mut Limited) -> Result { let s = Self::read_xdr(v, r)?; // Check that any further reads, such as this read of one byte, read no @@ -3014,7 +3065,7 @@ impl Type { } } - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] pub fn from_xdr>(v: TypeVariant, bytes: B, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(v, &mut cursor)?; @@ -3098,7 +3149,7 @@ impl Variants for Type { } impl WriteXdr for Type { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] #[allow(clippy::too_many_lines)] fn write_xdr(&self, w: &mut Limited) -> Result<()> { match self { diff --git a/spec/output/generator_spec_rust_custom_jsonschema_impls/const.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_jsonschema_impls/const.x/MyXDR.rs index 966b54a40..d4d8e38ab 100644 --- a/spec/output/generator_spec_rust_custom_jsonschema_impls/const.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_jsonschema_impls/const.x/MyXDR.rs @@ -35,6 +35,7 @@ use alloc::{ borrow::ToOwned, boxed::Box, string::{FromUtf8Error, String}, + vec, vec::Vec, }; #[cfg(feature = "std")] @@ -43,14 +44,17 @@ use std::string::FromUtf8Error; #[cfg(feature = "arbitrary")] use arbitrary::Arbitrary; -// TODO: Add support for read/write xdr fns when std not available. - #[cfg(feature = "std")] use std::{ error, io, io::{BufRead, BufReader, Cursor, Read, Write}, }; +#[cfg(all(not(feature = "std"), feature = "alloc"))] +use embedded_io::{Error as _, ErrorType, Read, Write}; +#[cfg(all(not(feature = "std"), feature = "alloc"))] +use embedded_io_cursor::Cursor; + /// Error contains all errors returned by functions in this crate. It can be /// compared via `PartialEq`, however any contained IO errors will only be /// compared on their `ErrorKind`. @@ -66,6 +70,8 @@ pub enum Error { InvalidHex, #[cfg(feature = "std")] Io(io::Error), + #[cfg(all(not(feature = "std"), feature = "alloc"))] + Io(embedded_io::ErrorKind), DepthLimitExceeded, #[cfg(feature = "serde_json")] Json(serde_json::Error), @@ -82,13 +88,34 @@ impl PartialEq for Error { // case for comparing errors outputted by the XDR library is for // error case testing, and a lack of the ability to compare has a // detrimental affect on failure testing, so this is a tradeoff. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] (Self::Io(l), Self::Io(r)) => l.kind() == r.kind(), _ => core::mem::discriminant(self) == core::mem::discriminant(other), } } } + +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl embedded_io::Error for Error { + fn kind(&self) -> embedded_io::ErrorKind { + match self { + Self::Io(e) => *e, + _ => embedded_io::ErrorKind::Other, + } + } +} + +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl From> for Error { + fn from(value: embedded_io::ReadExactError) -> Self { + match value { + embedded_io::ReadExactError::UnexpectedEof => Error::Io(embedded_io::ErrorKind::Other), + embedded_io::ReadExactError::Other(e) => e + } + } +} + #[cfg(feature = "std")] impl error::Error for Error { #[must_use] @@ -115,6 +142,8 @@ impl fmt::Display for Error { Error::InvalidHex => write!(f, "hex invalid"), #[cfg(feature = "std")] Error::Io(e) => write!(f, "{e}"), + #[cfg(all(not(feature = "std"), feature = "alloc"))] + Error::Io(_) => write!(f, "io error"), Error::DepthLimitExceeded => write!(f, "depth limit exceeded"), #[cfg(feature = "serde_json")] Error::Json(e) => write!(f, "{e}"), @@ -167,6 +196,9 @@ impl From for () { #[allow(dead_code)] type Result = core::result::Result; +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl ErrorType for Limited { type Error = Error; } + /// Name defines types that assign a static name to their value, such as the /// name given to an identifier in an XDR enum, or the name given to the case in /// a union. @@ -200,7 +232,7 @@ where /// `Limits` contains the limits that a limited reader or writer will be /// constrained to. -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] #[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct Limits { /// Defines the maximum depth for recursive calls in `Read/WriteXdr` to @@ -217,7 +249,7 @@ pub struct Limits { pub len: usize, } -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] impl Limits { #[must_use] pub fn none() -> Self { @@ -248,13 +280,13 @@ impl Limits { /// /// Intended for use with readers and writers and limiting their reads and /// writes. -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] pub struct Limited { pub inner: L, pub(crate) limits: Limits, } -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] impl Limited { /// Constructs a new `Limited`. /// @@ -307,6 +339,15 @@ impl Read for Limited { } } + +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl Read for Limited { + /// Forwards the read operation to the wrapped object. + fn read(&mut self, buf: &mut [u8]) -> core::result::Result { + self.inner.read(buf).map_err(|e| Error::Io(e.kind())) + } +} + #[cfg(feature = "std")] impl BufRead for Limited { /// Forwards the read operation to the wrapped object. @@ -333,6 +374,18 @@ impl Write for Limited { } } +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl Write for Limited { + /// Forwards the write operation to the wrapped object. + fn write(&mut self, buf: &[u8]) -> core::result::Result { + self.inner.write(buf).map_err(|e| Error::Io(e.kind())) + } + + fn flush(&mut self) -> core::result::Result<(), Self::Error> { + self.inner.flush().map_err(|e| Error::Io(e.kind())) + } +} + #[cfg(feature = "std")] pub struct ReadXdrIter { reader: Limited>, @@ -406,7 +459,7 @@ where /// /// Use [`ReadXdR: Read_xdr_to_end`] when the intent is for all bytes in the /// read implementation to be consumed by the read. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result; /// Construct the type from the XDR bytes base64 encoded. @@ -441,7 +494,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr_to_end(r: &mut Limited) -> Result { let s = Self::read_xdr(r)?; // Check that any further reads, such as this read of one byte, read no @@ -481,7 +534,7 @@ where /// /// Use [`ReadXdR: Read_xdr_into_to_end`] when the intent is for all bytes /// in the read implementation to be consumed by the read. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr_into(&mut self, r: &mut Limited) -> Result<()> { *self = Self::read_xdr(r)?; Ok(()) @@ -505,7 +558,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr_into_to_end(&mut self, r: &mut Limited) -> Result<()> { Self::read_xdr_into(self, r)?; // Check that any further reads, such as this read of one byte, read no @@ -554,7 +607,7 @@ where /// /// An error is returned if the bytes are not completely consumed by the /// deserialization. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn from_xdr(bytes: impl AsRef<[u8]>, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(&mut cursor)?; @@ -578,10 +631,10 @@ where } pub trait WriteXdr { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()>; - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn to_xdr(&self, limits: Limits) -> Result> { let mut cursor = Limited::new(Cursor::new(vec![]), limits); self.write_xdr(&mut cursor)?; @@ -603,13 +656,13 @@ pub trait WriteXdr { /// `Pad_len` returns the number of bytes to pad an XDR value of the given /// length to make the final serialized size a multiple of 4. -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] fn pad_len(len: usize) -> usize { (4 - (len % 4)) % 4 } impl ReadXdr for i32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -621,7 +674,7 @@ impl ReadXdr for i32 { } impl WriteXdr for i32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -632,7 +685,7 @@ impl WriteXdr for i32 { } impl ReadXdr for u32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -644,7 +697,7 @@ impl ReadXdr for u32 { } impl WriteXdr for u32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -655,7 +708,7 @@ impl WriteXdr for u32 { } impl ReadXdr for i64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -667,7 +720,7 @@ impl ReadXdr for i64 { } impl WriteXdr for i64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -678,7 +731,7 @@ impl WriteXdr for i64 { } impl ReadXdr for u64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -690,7 +743,7 @@ impl ReadXdr for u64 { } impl WriteXdr for u64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -701,35 +754,35 @@ impl WriteXdr for u64 { } impl ReadXdr for f32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for f64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for bool { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -740,7 +793,7 @@ impl ReadXdr for bool { } impl WriteXdr for bool { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i = u32::from(*self); // true = 1, false = 0 @@ -750,7 +803,7 @@ impl WriteXdr for bool { } impl ReadXdr for Option { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -767,7 +820,7 @@ impl ReadXdr for Option { } impl WriteXdr for Option { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { if let Some(t) = self { @@ -782,35 +835,35 @@ impl WriteXdr for Option { } impl ReadXdr for Box { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| Ok(Box::new(T::read_xdr(r)?))) } } impl WriteXdr for Box { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| T::write_xdr(self, w)) } } impl ReadXdr for () { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(_r: &mut Limited) -> Result { Ok(()) } } impl WriteXdr for () { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { Ok(()) } } impl ReadXdr for [u8; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { r.consume_len(N)?; @@ -829,7 +882,7 @@ impl ReadXdr for [u8; N] { } impl WriteXdr for [u8; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { w.consume_len(N)?; @@ -843,7 +896,7 @@ impl WriteXdr for [u8; N] { } impl ReadXdr for [T; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let mut vec = Vec::with_capacity(N); @@ -858,7 +911,7 @@ impl ReadXdr for [T; N] { } impl WriteXdr for [T; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { for t in self { @@ -1217,7 +1270,7 @@ impl<'a, const MAX: u32> TryFrom<&'a VecM> for &'a str { } impl ReadXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1244,7 +1297,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1264,7 +1317,7 @@ impl WriteXdr for VecM { } impl ReadXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len = u32::read_xdr(r)?; @@ -1284,7 +1337,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1657,7 +1710,7 @@ impl<'a, const MAX: u32> TryFrom<&'a BytesM> for &'a str { } impl ReadXdr for BytesM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1684,7 +1737,7 @@ impl ReadXdr for BytesM { } impl WriteXdr for BytesM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2060,7 +2113,7 @@ impl<'a, const MAX: u32> TryFrom<&'a StringM> for &'a str { } impl ReadXdr for StringM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -2087,7 +2140,7 @@ impl ReadXdr for StringM { } impl WriteXdr for StringM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2133,7 +2186,7 @@ impl ReadXdr for Frame where T: ReadXdr, { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { // Read the frame header value that contains 1 flag-bit and a 33-bit length. // - The 1 flag bit is 0 when there are more frames for the same record. @@ -2153,10 +2206,8 @@ where } } -#[cfg(all(test, feature = "std"))] +#[cfg(all(test, feature = "alloc"))] mod tests { - use std::io::Cursor; - use super::*; #[test] @@ -2265,7 +2316,7 @@ mod tests { } } -#[cfg(all(test, feature = "std"))] +#[cfg(all(test, feature = "alloc"))] mod test { use super::*; @@ -2890,7 +2941,7 @@ TypeVariant::TestArray2, ]; pub const VARIANTS_STR: [&'static str; 2] = [ "TestArray", "TestArray2", ]; - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] #[allow(clippy::too_many_lines)] pub fn read_xdr(v: TypeVariant, r: &mut Limited) -> Result { match v { @@ -2906,7 +2957,7 @@ TypeVariant::TestArray2 => r.with_limited_depth(|r| Ok(Self::TestArray2(Box::new Ok(t) } - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] pub fn read_xdr_to_end(v: TypeVariant, r: &mut Limited) -> Result { let s = Self::read_xdr(v, r)?; // Check that any further reads, such as this read of one byte, read no @@ -2953,7 +3004,7 @@ TypeVariant::TestArray2 => Box::new(ReadXdrIter::<_, TestArray2>::new(dec, r.lim } } - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] pub fn from_xdr>(v: TypeVariant, bytes: B, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(v, &mut cursor)?; @@ -3042,7 +3093,7 @@ Self::TestArray2(_) => TypeVariant::TestArray2, } impl WriteXdr for Type { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] #[allow(clippy::too_many_lines)] fn write_xdr(&self, w: &mut Limited) -> Result<()> { match self { diff --git a/spec/output/generator_spec_rust_custom_jsonschema_impls/enum.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_jsonschema_impls/enum.x/MyXDR.rs index 62d418406..7db523c78 100644 --- a/spec/output/generator_spec_rust_custom_jsonschema_impls/enum.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_jsonschema_impls/enum.x/MyXDR.rs @@ -35,6 +35,7 @@ use alloc::{ borrow::ToOwned, boxed::Box, string::{FromUtf8Error, String}, + vec, vec::Vec, }; #[cfg(feature = "std")] @@ -43,14 +44,17 @@ use std::string::FromUtf8Error; #[cfg(feature = "arbitrary")] use arbitrary::Arbitrary; -// TODO: Add support for read/write xdr fns when std not available. - #[cfg(feature = "std")] use std::{ error, io, io::{BufRead, BufReader, Cursor, Read, Write}, }; +#[cfg(all(not(feature = "std"), feature = "alloc"))] +use embedded_io::{Error as _, ErrorType, Read, Write}; +#[cfg(all(not(feature = "std"), feature = "alloc"))] +use embedded_io_cursor::Cursor; + /// Error contains all errors returned by functions in this crate. It can be /// compared via `PartialEq`, however any contained IO errors will only be /// compared on their `ErrorKind`. @@ -66,6 +70,8 @@ pub enum Error { InvalidHex, #[cfg(feature = "std")] Io(io::Error), + #[cfg(all(not(feature = "std"), feature = "alloc"))] + Io(embedded_io::ErrorKind), DepthLimitExceeded, #[cfg(feature = "serde_json")] Json(serde_json::Error), @@ -82,13 +88,34 @@ impl PartialEq for Error { // case for comparing errors outputted by the XDR library is for // error case testing, and a lack of the ability to compare has a // detrimental affect on failure testing, so this is a tradeoff. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] (Self::Io(l), Self::Io(r)) => l.kind() == r.kind(), _ => core::mem::discriminant(self) == core::mem::discriminant(other), } } } + +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl embedded_io::Error for Error { + fn kind(&self) -> embedded_io::ErrorKind { + match self { + Self::Io(e) => *e, + _ => embedded_io::ErrorKind::Other, + } + } +} + +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl From> for Error { + fn from(value: embedded_io::ReadExactError) -> Self { + match value { + embedded_io::ReadExactError::UnexpectedEof => Error::Io(embedded_io::ErrorKind::Other), + embedded_io::ReadExactError::Other(e) => e + } + } +} + #[cfg(feature = "std")] impl error::Error for Error { #[must_use] @@ -115,6 +142,8 @@ impl fmt::Display for Error { Error::InvalidHex => write!(f, "hex invalid"), #[cfg(feature = "std")] Error::Io(e) => write!(f, "{e}"), + #[cfg(all(not(feature = "std"), feature = "alloc"))] + Error::Io(_) => write!(f, "io error"), Error::DepthLimitExceeded => write!(f, "depth limit exceeded"), #[cfg(feature = "serde_json")] Error::Json(e) => write!(f, "{e}"), @@ -167,6 +196,9 @@ impl From for () { #[allow(dead_code)] type Result = core::result::Result; +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl ErrorType for Limited { type Error = Error; } + /// Name defines types that assign a static name to their value, such as the /// name given to an identifier in an XDR enum, or the name given to the case in /// a union. @@ -200,7 +232,7 @@ where /// `Limits` contains the limits that a limited reader or writer will be /// constrained to. -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] #[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct Limits { /// Defines the maximum depth for recursive calls in `Read/WriteXdr` to @@ -217,7 +249,7 @@ pub struct Limits { pub len: usize, } -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] impl Limits { #[must_use] pub fn none() -> Self { @@ -248,13 +280,13 @@ impl Limits { /// /// Intended for use with readers and writers and limiting their reads and /// writes. -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] pub struct Limited { pub inner: L, pub(crate) limits: Limits, } -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] impl Limited { /// Constructs a new `Limited`. /// @@ -307,6 +339,15 @@ impl Read for Limited { } } + +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl Read for Limited { + /// Forwards the read operation to the wrapped object. + fn read(&mut self, buf: &mut [u8]) -> core::result::Result { + self.inner.read(buf).map_err(|e| Error::Io(e.kind())) + } +} + #[cfg(feature = "std")] impl BufRead for Limited { /// Forwards the read operation to the wrapped object. @@ -333,6 +374,18 @@ impl Write for Limited { } } +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl Write for Limited { + /// Forwards the write operation to the wrapped object. + fn write(&mut self, buf: &[u8]) -> core::result::Result { + self.inner.write(buf).map_err(|e| Error::Io(e.kind())) + } + + fn flush(&mut self) -> core::result::Result<(), Self::Error> { + self.inner.flush().map_err(|e| Error::Io(e.kind())) + } +} + #[cfg(feature = "std")] pub struct ReadXdrIter { reader: Limited>, @@ -406,7 +459,7 @@ where /// /// Use [`ReadXdR: Read_xdr_to_end`] when the intent is for all bytes in the /// read implementation to be consumed by the read. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result; /// Construct the type from the XDR bytes base64 encoded. @@ -441,7 +494,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr_to_end(r: &mut Limited) -> Result { let s = Self::read_xdr(r)?; // Check that any further reads, such as this read of one byte, read no @@ -481,7 +534,7 @@ where /// /// Use [`ReadXdR: Read_xdr_into_to_end`] when the intent is for all bytes /// in the read implementation to be consumed by the read. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr_into(&mut self, r: &mut Limited) -> Result<()> { *self = Self::read_xdr(r)?; Ok(()) @@ -505,7 +558,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr_into_to_end(&mut self, r: &mut Limited) -> Result<()> { Self::read_xdr_into(self, r)?; // Check that any further reads, such as this read of one byte, read no @@ -554,7 +607,7 @@ where /// /// An error is returned if the bytes are not completely consumed by the /// deserialization. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn from_xdr(bytes: impl AsRef<[u8]>, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(&mut cursor)?; @@ -578,10 +631,10 @@ where } pub trait WriteXdr { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()>; - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn to_xdr(&self, limits: Limits) -> Result> { let mut cursor = Limited::new(Cursor::new(vec![]), limits); self.write_xdr(&mut cursor)?; @@ -603,13 +656,13 @@ pub trait WriteXdr { /// `Pad_len` returns the number of bytes to pad an XDR value of the given /// length to make the final serialized size a multiple of 4. -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] fn pad_len(len: usize) -> usize { (4 - (len % 4)) % 4 } impl ReadXdr for i32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -621,7 +674,7 @@ impl ReadXdr for i32 { } impl WriteXdr for i32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -632,7 +685,7 @@ impl WriteXdr for i32 { } impl ReadXdr for u32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -644,7 +697,7 @@ impl ReadXdr for u32 { } impl WriteXdr for u32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -655,7 +708,7 @@ impl WriteXdr for u32 { } impl ReadXdr for i64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -667,7 +720,7 @@ impl ReadXdr for i64 { } impl WriteXdr for i64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -678,7 +731,7 @@ impl WriteXdr for i64 { } impl ReadXdr for u64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -690,7 +743,7 @@ impl ReadXdr for u64 { } impl WriteXdr for u64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -701,35 +754,35 @@ impl WriteXdr for u64 { } impl ReadXdr for f32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for f64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for bool { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -740,7 +793,7 @@ impl ReadXdr for bool { } impl WriteXdr for bool { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i = u32::from(*self); // true = 1, false = 0 @@ -750,7 +803,7 @@ impl WriteXdr for bool { } impl ReadXdr for Option { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -767,7 +820,7 @@ impl ReadXdr for Option { } impl WriteXdr for Option { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { if let Some(t) = self { @@ -782,35 +835,35 @@ impl WriteXdr for Option { } impl ReadXdr for Box { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| Ok(Box::new(T::read_xdr(r)?))) } } impl WriteXdr for Box { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| T::write_xdr(self, w)) } } impl ReadXdr for () { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(_r: &mut Limited) -> Result { Ok(()) } } impl WriteXdr for () { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { Ok(()) } } impl ReadXdr for [u8; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { r.consume_len(N)?; @@ -829,7 +882,7 @@ impl ReadXdr for [u8; N] { } impl WriteXdr for [u8; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { w.consume_len(N)?; @@ -843,7 +896,7 @@ impl WriteXdr for [u8; N] { } impl ReadXdr for [T; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let mut vec = Vec::with_capacity(N); @@ -858,7 +911,7 @@ impl ReadXdr for [T; N] { } impl WriteXdr for [T; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { for t in self { @@ -1217,7 +1270,7 @@ impl<'a, const MAX: u32> TryFrom<&'a VecM> for &'a str { } impl ReadXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1244,7 +1297,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1264,7 +1317,7 @@ impl WriteXdr for VecM { } impl ReadXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len = u32::read_xdr(r)?; @@ -1284,7 +1337,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1657,7 +1710,7 @@ impl<'a, const MAX: u32> TryFrom<&'a BytesM> for &'a str { } impl ReadXdr for BytesM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1684,7 +1737,7 @@ impl ReadXdr for BytesM { } impl WriteXdr for BytesM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2060,7 +2113,7 @@ impl<'a, const MAX: u32> TryFrom<&'a StringM> for &'a str { } impl ReadXdr for StringM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -2087,7 +2140,7 @@ impl ReadXdr for StringM { } impl WriteXdr for StringM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2133,7 +2186,7 @@ impl ReadXdr for Frame where T: ReadXdr, { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { // Read the frame header value that contains 1 flag-bit and a 33-bit length. // - The 1 flag bit is 0 when there are more frames for the same record. @@ -2153,10 +2206,8 @@ where } } -#[cfg(all(test, feature = "std"))] +#[cfg(all(test, feature = "alloc"))] mod tests { - use std::io::Cursor; - use super::*; #[test] @@ -2265,7 +2316,7 @@ mod tests { } } -#[cfg(all(test, feature = "std"))] +#[cfg(all(test, feature = "alloc"))] mod test { use super::*; @@ -2940,7 +2991,7 @@ Self::FbaMessage => "FbaMessage", } impl ReadXdr for MessageType { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let e = i32::read_xdr(r)?; @@ -2951,7 +3002,7 @@ Self::FbaMessage => "FbaMessage", } impl WriteXdr for MessageType { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i: i32 = (*self).into(); @@ -3049,7 +3100,7 @@ Self::Blue => "Blue", } impl ReadXdr for Color { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let e = i32::read_xdr(r)?; @@ -3060,7 +3111,7 @@ Self::Blue => "Blue", } impl WriteXdr for Color { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i: i32 = (*self).into(); @@ -3157,7 +3208,7 @@ Self::Blue2 => "Blue2", } impl ReadXdr for Color2 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let e = i32::read_xdr(r)?; @@ -3168,7 +3219,7 @@ Self::Blue2 => "Blue2", } impl WriteXdr for Color2 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i: i32 = (*self).into(); @@ -3266,7 +3317,7 @@ Self::R3 => "R3", } impl ReadXdr for Color3 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let e = i32::read_xdr(r)?; @@ -3277,7 +3328,7 @@ Self::R3 => "R3", } impl WriteXdr for Color3 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i: i32 = (*self).into(); @@ -3392,7 +3443,7 @@ TypeVariant::Color3, ]; "Color2", "Color3", ]; - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] #[allow(clippy::too_many_lines)] pub fn read_xdr(v: TypeVariant, r: &mut Limited) -> Result { match v { @@ -3410,7 +3461,7 @@ TypeVariant::Color3 => r.with_limited_depth(|r| Ok(Self::Color3(Box::new(Color3: Ok(t) } - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] pub fn read_xdr_to_end(v: TypeVariant, r: &mut Limited) -> Result { let s = Self::read_xdr(v, r)?; // Check that any further reads, such as this read of one byte, read no @@ -3463,7 +3514,7 @@ TypeVariant::Color3 => Box::new(ReadXdrIter::<_, Color3>::new(dec, r.limits.clon } } - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] pub fn from_xdr>(v: TypeVariant, bytes: B, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(v, &mut cursor)?; @@ -3562,7 +3613,7 @@ Self::Color3(_) => TypeVariant::Color3, } impl WriteXdr for Type { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] #[allow(clippy::too_many_lines)] fn write_xdr(&self, w: &mut Limited) -> Result<()> { match self { diff --git a/spec/output/generator_spec_rust_custom_jsonschema_impls/nesting.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_jsonschema_impls/nesting.x/MyXDR.rs index 81767aed3..af26cbeca 100644 --- a/spec/output/generator_spec_rust_custom_jsonschema_impls/nesting.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_jsonschema_impls/nesting.x/MyXDR.rs @@ -35,6 +35,7 @@ use alloc::{ borrow::ToOwned, boxed::Box, string::{FromUtf8Error, String}, + vec, vec::Vec, }; #[cfg(feature = "std")] @@ -43,14 +44,17 @@ use std::string::FromUtf8Error; #[cfg(feature = "arbitrary")] use arbitrary::Arbitrary; -// TODO: Add support for read/write xdr fns when std not available. - #[cfg(feature = "std")] use std::{ error, io, io::{BufRead, BufReader, Cursor, Read, Write}, }; +#[cfg(all(not(feature = "std"), feature = "alloc"))] +use embedded_io::{Error as _, ErrorType, Read, Write}; +#[cfg(all(not(feature = "std"), feature = "alloc"))] +use embedded_io_cursor::Cursor; + /// Error contains all errors returned by functions in this crate. It can be /// compared via `PartialEq`, however any contained IO errors will only be /// compared on their `ErrorKind`. @@ -66,6 +70,8 @@ pub enum Error { InvalidHex, #[cfg(feature = "std")] Io(io::Error), + #[cfg(all(not(feature = "std"), feature = "alloc"))] + Io(embedded_io::ErrorKind), DepthLimitExceeded, #[cfg(feature = "serde_json")] Json(serde_json::Error), @@ -82,13 +88,34 @@ impl PartialEq for Error { // case for comparing errors outputted by the XDR library is for // error case testing, and a lack of the ability to compare has a // detrimental affect on failure testing, so this is a tradeoff. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] (Self::Io(l), Self::Io(r)) => l.kind() == r.kind(), _ => core::mem::discriminant(self) == core::mem::discriminant(other), } } } + +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl embedded_io::Error for Error { + fn kind(&self) -> embedded_io::ErrorKind { + match self { + Self::Io(e) => *e, + _ => embedded_io::ErrorKind::Other, + } + } +} + +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl From> for Error { + fn from(value: embedded_io::ReadExactError) -> Self { + match value { + embedded_io::ReadExactError::UnexpectedEof => Error::Io(embedded_io::ErrorKind::Other), + embedded_io::ReadExactError::Other(e) => e + } + } +} + #[cfg(feature = "std")] impl error::Error for Error { #[must_use] @@ -115,6 +142,8 @@ impl fmt::Display for Error { Error::InvalidHex => write!(f, "hex invalid"), #[cfg(feature = "std")] Error::Io(e) => write!(f, "{e}"), + #[cfg(all(not(feature = "std"), feature = "alloc"))] + Error::Io(_) => write!(f, "io error"), Error::DepthLimitExceeded => write!(f, "depth limit exceeded"), #[cfg(feature = "serde_json")] Error::Json(e) => write!(f, "{e}"), @@ -167,6 +196,9 @@ impl From for () { #[allow(dead_code)] type Result = core::result::Result; +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl ErrorType for Limited { type Error = Error; } + /// Name defines types that assign a static name to their value, such as the /// name given to an identifier in an XDR enum, or the name given to the case in /// a union. @@ -200,7 +232,7 @@ where /// `Limits` contains the limits that a limited reader or writer will be /// constrained to. -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] #[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct Limits { /// Defines the maximum depth for recursive calls in `Read/WriteXdr` to @@ -217,7 +249,7 @@ pub struct Limits { pub len: usize, } -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] impl Limits { #[must_use] pub fn none() -> Self { @@ -248,13 +280,13 @@ impl Limits { /// /// Intended for use with readers and writers and limiting their reads and /// writes. -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] pub struct Limited { pub inner: L, pub(crate) limits: Limits, } -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] impl Limited { /// Constructs a new `Limited`. /// @@ -307,6 +339,15 @@ impl Read for Limited { } } + +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl Read for Limited { + /// Forwards the read operation to the wrapped object. + fn read(&mut self, buf: &mut [u8]) -> core::result::Result { + self.inner.read(buf).map_err(|e| Error::Io(e.kind())) + } +} + #[cfg(feature = "std")] impl BufRead for Limited { /// Forwards the read operation to the wrapped object. @@ -333,6 +374,18 @@ impl Write for Limited { } } +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl Write for Limited { + /// Forwards the write operation to the wrapped object. + fn write(&mut self, buf: &[u8]) -> core::result::Result { + self.inner.write(buf).map_err(|e| Error::Io(e.kind())) + } + + fn flush(&mut self) -> core::result::Result<(), Self::Error> { + self.inner.flush().map_err(|e| Error::Io(e.kind())) + } +} + #[cfg(feature = "std")] pub struct ReadXdrIter { reader: Limited>, @@ -406,7 +459,7 @@ where /// /// Use [`ReadXdR: Read_xdr_to_end`] when the intent is for all bytes in the /// read implementation to be consumed by the read. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result; /// Construct the type from the XDR bytes base64 encoded. @@ -441,7 +494,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr_to_end(r: &mut Limited) -> Result { let s = Self::read_xdr(r)?; // Check that any further reads, such as this read of one byte, read no @@ -481,7 +534,7 @@ where /// /// Use [`ReadXdR: Read_xdr_into_to_end`] when the intent is for all bytes /// in the read implementation to be consumed by the read. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr_into(&mut self, r: &mut Limited) -> Result<()> { *self = Self::read_xdr(r)?; Ok(()) @@ -505,7 +558,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr_into_to_end(&mut self, r: &mut Limited) -> Result<()> { Self::read_xdr_into(self, r)?; // Check that any further reads, such as this read of one byte, read no @@ -554,7 +607,7 @@ where /// /// An error is returned if the bytes are not completely consumed by the /// deserialization. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn from_xdr(bytes: impl AsRef<[u8]>, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(&mut cursor)?; @@ -578,10 +631,10 @@ where } pub trait WriteXdr { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()>; - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn to_xdr(&self, limits: Limits) -> Result> { let mut cursor = Limited::new(Cursor::new(vec![]), limits); self.write_xdr(&mut cursor)?; @@ -603,13 +656,13 @@ pub trait WriteXdr { /// `Pad_len` returns the number of bytes to pad an XDR value of the given /// length to make the final serialized size a multiple of 4. -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] fn pad_len(len: usize) -> usize { (4 - (len % 4)) % 4 } impl ReadXdr for i32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -621,7 +674,7 @@ impl ReadXdr for i32 { } impl WriteXdr for i32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -632,7 +685,7 @@ impl WriteXdr for i32 { } impl ReadXdr for u32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -644,7 +697,7 @@ impl ReadXdr for u32 { } impl WriteXdr for u32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -655,7 +708,7 @@ impl WriteXdr for u32 { } impl ReadXdr for i64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -667,7 +720,7 @@ impl ReadXdr for i64 { } impl WriteXdr for i64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -678,7 +731,7 @@ impl WriteXdr for i64 { } impl ReadXdr for u64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -690,7 +743,7 @@ impl ReadXdr for u64 { } impl WriteXdr for u64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -701,35 +754,35 @@ impl WriteXdr for u64 { } impl ReadXdr for f32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for f64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for bool { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -740,7 +793,7 @@ impl ReadXdr for bool { } impl WriteXdr for bool { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i = u32::from(*self); // true = 1, false = 0 @@ -750,7 +803,7 @@ impl WriteXdr for bool { } impl ReadXdr for Option { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -767,7 +820,7 @@ impl ReadXdr for Option { } impl WriteXdr for Option { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { if let Some(t) = self { @@ -782,35 +835,35 @@ impl WriteXdr for Option { } impl ReadXdr for Box { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| Ok(Box::new(T::read_xdr(r)?))) } } impl WriteXdr for Box { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| T::write_xdr(self, w)) } } impl ReadXdr for () { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(_r: &mut Limited) -> Result { Ok(()) } } impl WriteXdr for () { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { Ok(()) } } impl ReadXdr for [u8; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { r.consume_len(N)?; @@ -829,7 +882,7 @@ impl ReadXdr for [u8; N] { } impl WriteXdr for [u8; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { w.consume_len(N)?; @@ -843,7 +896,7 @@ impl WriteXdr for [u8; N] { } impl ReadXdr for [T; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let mut vec = Vec::with_capacity(N); @@ -858,7 +911,7 @@ impl ReadXdr for [T; N] { } impl WriteXdr for [T; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { for t in self { @@ -1217,7 +1270,7 @@ impl<'a, const MAX: u32> TryFrom<&'a VecM> for &'a str { } impl ReadXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1244,7 +1297,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1264,7 +1317,7 @@ impl WriteXdr for VecM { } impl ReadXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len = u32::read_xdr(r)?; @@ -1284,7 +1337,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1657,7 +1710,7 @@ impl<'a, const MAX: u32> TryFrom<&'a BytesM> for &'a str { } impl ReadXdr for BytesM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1684,7 +1737,7 @@ impl ReadXdr for BytesM { } impl WriteXdr for BytesM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2060,7 +2113,7 @@ impl<'a, const MAX: u32> TryFrom<&'a StringM> for &'a str { } impl ReadXdr for StringM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -2087,7 +2140,7 @@ impl ReadXdr for StringM { } impl WriteXdr for StringM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2133,7 +2186,7 @@ impl ReadXdr for Frame where T: ReadXdr, { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { // Read the frame header value that contains 1 flag-bit and a 33-bit length. // - The 1 flag bit is 0 when there are more frames for the same record. @@ -2153,10 +2206,8 @@ where } } -#[cfg(all(test, feature = "std"))] +#[cfg(all(test, feature = "alloc"))] mod tests { - use std::io::Cursor; - use super::*; #[test] @@ -2265,7 +2316,7 @@ mod tests { } } -#[cfg(all(test, feature = "std"))] +#[cfg(all(test, feature = "alloc"))] mod test { use super::*; @@ -2866,7 +2917,7 @@ Self::Offer => "Offer", } impl ReadXdr for UnionKey { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let e = i32::read_xdr(r)?; @@ -2877,7 +2928,7 @@ Self::Offer => "Offer", } impl WriteXdr for UnionKey { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i: i32 = (*self).into(); @@ -2911,7 +2962,7 @@ pub struct MyUnionOne { } impl ReadXdr for MyUnionOne { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { Ok(Self{ @@ -2922,7 +2973,7 @@ impl ReadXdr for MyUnionOne { } impl WriteXdr for MyUnionOne { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { self.some_int.write_xdr(w)?; @@ -2950,7 +3001,7 @@ pub struct MyUnionTwo { } impl ReadXdr for MyUnionTwo { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { Ok(Self{ @@ -2962,7 +3013,7 @@ foo: i32::read_xdr(r)?, } impl WriteXdr for MyUnionTwo { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { self.some_int.write_xdr(w)?; @@ -3064,7 +3115,7 @@ Self::Offer => UnionKey::Offer, impl Union for MyUnion {} impl ReadXdr for MyUnion { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let dv: UnionKey = ::read_xdr(r)?; @@ -3082,7 +3133,7 @@ UnionKey::Offer => Self::Offer, } impl WriteXdr for MyUnion { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { self.discriminant().write_xdr(w)?; @@ -3212,7 +3263,7 @@ TypeVariant::MyUnionTwo, ]; "MyUnionOne", "MyUnionTwo", ]; - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] #[allow(clippy::too_many_lines)] pub fn read_xdr(v: TypeVariant, r: &mut Limited) -> Result { match v { @@ -3231,7 +3282,7 @@ TypeVariant::MyUnionTwo => r.with_limited_depth(|r| Ok(Self::MyUnionTwo(Box::new Ok(t) } - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] pub fn read_xdr_to_end(v: TypeVariant, r: &mut Limited) -> Result { let s = Self::read_xdr(v, r)?; // Check that any further reads, such as this read of one byte, read no @@ -3287,7 +3338,7 @@ TypeVariant::MyUnionTwo => Box::new(ReadXdrIter::<_, MyUnionTwo>::new(dec, r.lim } } - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] pub fn from_xdr>(v: TypeVariant, bytes: B, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(v, &mut cursor)?; @@ -3391,7 +3442,7 @@ Self::MyUnionTwo(_) => TypeVariant::MyUnionTwo, } impl WriteXdr for Type { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] #[allow(clippy::too_many_lines)] fn write_xdr(&self, w: &mut Limited) -> Result<()> { match self { diff --git a/spec/output/generator_spec_rust_custom_jsonschema_impls/optional.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_jsonschema_impls/optional.x/MyXDR.rs index 0848b0a4a..2a13253f0 100644 --- a/spec/output/generator_spec_rust_custom_jsonschema_impls/optional.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_jsonschema_impls/optional.x/MyXDR.rs @@ -35,6 +35,7 @@ use alloc::{ borrow::ToOwned, boxed::Box, string::{FromUtf8Error, String}, + vec, vec::Vec, }; #[cfg(feature = "std")] @@ -43,14 +44,17 @@ use std::string::FromUtf8Error; #[cfg(feature = "arbitrary")] use arbitrary::Arbitrary; -// TODO: Add support for read/write xdr fns when std not available. - #[cfg(feature = "std")] use std::{ error, io, io::{BufRead, BufReader, Cursor, Read, Write}, }; +#[cfg(all(not(feature = "std"), feature = "alloc"))] +use embedded_io::{Error as _, ErrorType, Read, Write}; +#[cfg(all(not(feature = "std"), feature = "alloc"))] +use embedded_io_cursor::Cursor; + /// Error contains all errors returned by functions in this crate. It can be /// compared via `PartialEq`, however any contained IO errors will only be /// compared on their `ErrorKind`. @@ -66,6 +70,8 @@ pub enum Error { InvalidHex, #[cfg(feature = "std")] Io(io::Error), + #[cfg(all(not(feature = "std"), feature = "alloc"))] + Io(embedded_io::ErrorKind), DepthLimitExceeded, #[cfg(feature = "serde_json")] Json(serde_json::Error), @@ -82,13 +88,34 @@ impl PartialEq for Error { // case for comparing errors outputted by the XDR library is for // error case testing, and a lack of the ability to compare has a // detrimental affect on failure testing, so this is a tradeoff. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] (Self::Io(l), Self::Io(r)) => l.kind() == r.kind(), _ => core::mem::discriminant(self) == core::mem::discriminant(other), } } } + +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl embedded_io::Error for Error { + fn kind(&self) -> embedded_io::ErrorKind { + match self { + Self::Io(e) => *e, + _ => embedded_io::ErrorKind::Other, + } + } +} + +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl From> for Error { + fn from(value: embedded_io::ReadExactError) -> Self { + match value { + embedded_io::ReadExactError::UnexpectedEof => Error::Io(embedded_io::ErrorKind::Other), + embedded_io::ReadExactError::Other(e) => e + } + } +} + #[cfg(feature = "std")] impl error::Error for Error { #[must_use] @@ -115,6 +142,8 @@ impl fmt::Display for Error { Error::InvalidHex => write!(f, "hex invalid"), #[cfg(feature = "std")] Error::Io(e) => write!(f, "{e}"), + #[cfg(all(not(feature = "std"), feature = "alloc"))] + Error::Io(_) => write!(f, "io error"), Error::DepthLimitExceeded => write!(f, "depth limit exceeded"), #[cfg(feature = "serde_json")] Error::Json(e) => write!(f, "{e}"), @@ -167,6 +196,9 @@ impl From for () { #[allow(dead_code)] type Result = core::result::Result; +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl ErrorType for Limited { type Error = Error; } + /// Name defines types that assign a static name to their value, such as the /// name given to an identifier in an XDR enum, or the name given to the case in /// a union. @@ -200,7 +232,7 @@ where /// `Limits` contains the limits that a limited reader or writer will be /// constrained to. -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] #[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct Limits { /// Defines the maximum depth for recursive calls in `Read/WriteXdr` to @@ -217,7 +249,7 @@ pub struct Limits { pub len: usize, } -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] impl Limits { #[must_use] pub fn none() -> Self { @@ -248,13 +280,13 @@ impl Limits { /// /// Intended for use with readers and writers and limiting their reads and /// writes. -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] pub struct Limited { pub inner: L, pub(crate) limits: Limits, } -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] impl Limited { /// Constructs a new `Limited`. /// @@ -307,6 +339,15 @@ impl Read for Limited { } } + +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl Read for Limited { + /// Forwards the read operation to the wrapped object. + fn read(&mut self, buf: &mut [u8]) -> core::result::Result { + self.inner.read(buf).map_err(|e| Error::Io(e.kind())) + } +} + #[cfg(feature = "std")] impl BufRead for Limited { /// Forwards the read operation to the wrapped object. @@ -333,6 +374,18 @@ impl Write for Limited { } } +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl Write for Limited { + /// Forwards the write operation to the wrapped object. + fn write(&mut self, buf: &[u8]) -> core::result::Result { + self.inner.write(buf).map_err(|e| Error::Io(e.kind())) + } + + fn flush(&mut self) -> core::result::Result<(), Self::Error> { + self.inner.flush().map_err(|e| Error::Io(e.kind())) + } +} + #[cfg(feature = "std")] pub struct ReadXdrIter { reader: Limited>, @@ -406,7 +459,7 @@ where /// /// Use [`ReadXdR: Read_xdr_to_end`] when the intent is for all bytes in the /// read implementation to be consumed by the read. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result; /// Construct the type from the XDR bytes base64 encoded. @@ -441,7 +494,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr_to_end(r: &mut Limited) -> Result { let s = Self::read_xdr(r)?; // Check that any further reads, such as this read of one byte, read no @@ -481,7 +534,7 @@ where /// /// Use [`ReadXdR: Read_xdr_into_to_end`] when the intent is for all bytes /// in the read implementation to be consumed by the read. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr_into(&mut self, r: &mut Limited) -> Result<()> { *self = Self::read_xdr(r)?; Ok(()) @@ -505,7 +558,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr_into_to_end(&mut self, r: &mut Limited) -> Result<()> { Self::read_xdr_into(self, r)?; // Check that any further reads, such as this read of one byte, read no @@ -554,7 +607,7 @@ where /// /// An error is returned if the bytes are not completely consumed by the /// deserialization. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn from_xdr(bytes: impl AsRef<[u8]>, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(&mut cursor)?; @@ -578,10 +631,10 @@ where } pub trait WriteXdr { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()>; - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn to_xdr(&self, limits: Limits) -> Result> { let mut cursor = Limited::new(Cursor::new(vec![]), limits); self.write_xdr(&mut cursor)?; @@ -603,13 +656,13 @@ pub trait WriteXdr { /// `Pad_len` returns the number of bytes to pad an XDR value of the given /// length to make the final serialized size a multiple of 4. -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] fn pad_len(len: usize) -> usize { (4 - (len % 4)) % 4 } impl ReadXdr for i32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -621,7 +674,7 @@ impl ReadXdr for i32 { } impl WriteXdr for i32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -632,7 +685,7 @@ impl WriteXdr for i32 { } impl ReadXdr for u32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -644,7 +697,7 @@ impl ReadXdr for u32 { } impl WriteXdr for u32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -655,7 +708,7 @@ impl WriteXdr for u32 { } impl ReadXdr for i64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -667,7 +720,7 @@ impl ReadXdr for i64 { } impl WriteXdr for i64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -678,7 +731,7 @@ impl WriteXdr for i64 { } impl ReadXdr for u64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -690,7 +743,7 @@ impl ReadXdr for u64 { } impl WriteXdr for u64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -701,35 +754,35 @@ impl WriteXdr for u64 { } impl ReadXdr for f32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for f64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for bool { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -740,7 +793,7 @@ impl ReadXdr for bool { } impl WriteXdr for bool { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i = u32::from(*self); // true = 1, false = 0 @@ -750,7 +803,7 @@ impl WriteXdr for bool { } impl ReadXdr for Option { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -767,7 +820,7 @@ impl ReadXdr for Option { } impl WriteXdr for Option { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { if let Some(t) = self { @@ -782,35 +835,35 @@ impl WriteXdr for Option { } impl ReadXdr for Box { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| Ok(Box::new(T::read_xdr(r)?))) } } impl WriteXdr for Box { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| T::write_xdr(self, w)) } } impl ReadXdr for () { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(_r: &mut Limited) -> Result { Ok(()) } } impl WriteXdr for () { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { Ok(()) } } impl ReadXdr for [u8; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { r.consume_len(N)?; @@ -829,7 +882,7 @@ impl ReadXdr for [u8; N] { } impl WriteXdr for [u8; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { w.consume_len(N)?; @@ -843,7 +896,7 @@ impl WriteXdr for [u8; N] { } impl ReadXdr for [T; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let mut vec = Vec::with_capacity(N); @@ -858,7 +911,7 @@ impl ReadXdr for [T; N] { } impl WriteXdr for [T; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { for t in self { @@ -1217,7 +1270,7 @@ impl<'a, const MAX: u32> TryFrom<&'a VecM> for &'a str { } impl ReadXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1244,7 +1297,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1264,7 +1317,7 @@ impl WriteXdr for VecM { } impl ReadXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len = u32::read_xdr(r)?; @@ -1284,7 +1337,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1657,7 +1710,7 @@ impl<'a, const MAX: u32> TryFrom<&'a BytesM> for &'a str { } impl ReadXdr for BytesM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1684,7 +1737,7 @@ impl ReadXdr for BytesM { } impl WriteXdr for BytesM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2060,7 +2113,7 @@ impl<'a, const MAX: u32> TryFrom<&'a StringM> for &'a str { } impl ReadXdr for StringM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -2087,7 +2140,7 @@ impl ReadXdr for StringM { } impl WriteXdr for StringM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2133,7 +2186,7 @@ impl ReadXdr for Frame where T: ReadXdr, { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { // Read the frame header value that contains 1 flag-bit and a 33-bit length. // - The 1 flag bit is 0 when there are more frames for the same record. @@ -2153,10 +2206,8 @@ where } } -#[cfg(all(test, feature = "std"))] +#[cfg(all(test, feature = "alloc"))] mod tests { - use std::io::Cursor; - use super::*; #[test] @@ -2265,7 +2316,7 @@ mod tests { } } -#[cfg(all(test, feature = "std"))] +#[cfg(all(test, feature = "alloc"))] mod test { use super::*; @@ -2807,7 +2858,7 @@ pub struct HasOptions { } impl ReadXdr for HasOptions { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { Ok(Self{ @@ -2820,7 +2871,7 @@ third_option: Option::::read_xdr(r)?, } impl WriteXdr for HasOptions { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { self.first_option.write_xdr(w)?; @@ -2919,7 +2970,7 @@ TypeVariant::HasOptions, ]; pub const VARIANTS_STR: [&'static str; 2] = [ "Arr", "HasOptions", ]; - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] #[allow(clippy::too_many_lines)] pub fn read_xdr(v: TypeVariant, r: &mut Limited) -> Result { match v { @@ -2935,7 +2986,7 @@ TypeVariant::HasOptions => r.with_limited_depth(|r| Ok(Self::HasOptions(Box::new Ok(t) } - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] pub fn read_xdr_to_end(v: TypeVariant, r: &mut Limited) -> Result { let s = Self::read_xdr(v, r)?; // Check that any further reads, such as this read of one byte, read no @@ -2982,7 +3033,7 @@ TypeVariant::HasOptions => Box::new(ReadXdrIter::<_, HasOptions>::new(dec, r.lim } } - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] pub fn from_xdr>(v: TypeVariant, bytes: B, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(v, &mut cursor)?; @@ -3071,7 +3122,7 @@ Self::HasOptions(_) => TypeVariant::HasOptions, } impl WriteXdr for Type { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] #[allow(clippy::too_many_lines)] fn write_xdr(&self, w: &mut Limited) -> Result<()> { match self { diff --git a/spec/output/generator_spec_rust_custom_jsonschema_impls/struct.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_jsonschema_impls/struct.x/MyXDR.rs index e43738634..327c024bf 100644 --- a/spec/output/generator_spec_rust_custom_jsonschema_impls/struct.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_jsonschema_impls/struct.x/MyXDR.rs @@ -35,6 +35,7 @@ use alloc::{ borrow::ToOwned, boxed::Box, string::{FromUtf8Error, String}, + vec, vec::Vec, }; #[cfg(feature = "std")] @@ -43,14 +44,17 @@ use std::string::FromUtf8Error; #[cfg(feature = "arbitrary")] use arbitrary::Arbitrary; -// TODO: Add support for read/write xdr fns when std not available. - #[cfg(feature = "std")] use std::{ error, io, io::{BufRead, BufReader, Cursor, Read, Write}, }; +#[cfg(all(not(feature = "std"), feature = "alloc"))] +use embedded_io::{Error as _, ErrorType, Read, Write}; +#[cfg(all(not(feature = "std"), feature = "alloc"))] +use embedded_io_cursor::Cursor; + /// Error contains all errors returned by functions in this crate. It can be /// compared via `PartialEq`, however any contained IO errors will only be /// compared on their `ErrorKind`. @@ -66,6 +70,8 @@ pub enum Error { InvalidHex, #[cfg(feature = "std")] Io(io::Error), + #[cfg(all(not(feature = "std"), feature = "alloc"))] + Io(embedded_io::ErrorKind), DepthLimitExceeded, #[cfg(feature = "serde_json")] Json(serde_json::Error), @@ -82,13 +88,34 @@ impl PartialEq for Error { // case for comparing errors outputted by the XDR library is for // error case testing, and a lack of the ability to compare has a // detrimental affect on failure testing, so this is a tradeoff. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] (Self::Io(l), Self::Io(r)) => l.kind() == r.kind(), _ => core::mem::discriminant(self) == core::mem::discriminant(other), } } } + +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl embedded_io::Error for Error { + fn kind(&self) -> embedded_io::ErrorKind { + match self { + Self::Io(e) => *e, + _ => embedded_io::ErrorKind::Other, + } + } +} + +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl From> for Error { + fn from(value: embedded_io::ReadExactError) -> Self { + match value { + embedded_io::ReadExactError::UnexpectedEof => Error::Io(embedded_io::ErrorKind::Other), + embedded_io::ReadExactError::Other(e) => e + } + } +} + #[cfg(feature = "std")] impl error::Error for Error { #[must_use] @@ -115,6 +142,8 @@ impl fmt::Display for Error { Error::InvalidHex => write!(f, "hex invalid"), #[cfg(feature = "std")] Error::Io(e) => write!(f, "{e}"), + #[cfg(all(not(feature = "std"), feature = "alloc"))] + Error::Io(_) => write!(f, "io error"), Error::DepthLimitExceeded => write!(f, "depth limit exceeded"), #[cfg(feature = "serde_json")] Error::Json(e) => write!(f, "{e}"), @@ -167,6 +196,9 @@ impl From for () { #[allow(dead_code)] type Result = core::result::Result; +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl ErrorType for Limited { type Error = Error; } + /// Name defines types that assign a static name to their value, such as the /// name given to an identifier in an XDR enum, or the name given to the case in /// a union. @@ -200,7 +232,7 @@ where /// `Limits` contains the limits that a limited reader or writer will be /// constrained to. -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] #[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct Limits { /// Defines the maximum depth for recursive calls in `Read/WriteXdr` to @@ -217,7 +249,7 @@ pub struct Limits { pub len: usize, } -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] impl Limits { #[must_use] pub fn none() -> Self { @@ -248,13 +280,13 @@ impl Limits { /// /// Intended for use with readers and writers and limiting their reads and /// writes. -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] pub struct Limited { pub inner: L, pub(crate) limits: Limits, } -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] impl Limited { /// Constructs a new `Limited`. /// @@ -307,6 +339,15 @@ impl Read for Limited { } } + +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl Read for Limited { + /// Forwards the read operation to the wrapped object. + fn read(&mut self, buf: &mut [u8]) -> core::result::Result { + self.inner.read(buf).map_err(|e| Error::Io(e.kind())) + } +} + #[cfg(feature = "std")] impl BufRead for Limited { /// Forwards the read operation to the wrapped object. @@ -333,6 +374,18 @@ impl Write for Limited { } } +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl Write for Limited { + /// Forwards the write operation to the wrapped object. + fn write(&mut self, buf: &[u8]) -> core::result::Result { + self.inner.write(buf).map_err(|e| Error::Io(e.kind())) + } + + fn flush(&mut self) -> core::result::Result<(), Self::Error> { + self.inner.flush().map_err(|e| Error::Io(e.kind())) + } +} + #[cfg(feature = "std")] pub struct ReadXdrIter { reader: Limited>, @@ -406,7 +459,7 @@ where /// /// Use [`ReadXdR: Read_xdr_to_end`] when the intent is for all bytes in the /// read implementation to be consumed by the read. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result; /// Construct the type from the XDR bytes base64 encoded. @@ -441,7 +494,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr_to_end(r: &mut Limited) -> Result { let s = Self::read_xdr(r)?; // Check that any further reads, such as this read of one byte, read no @@ -481,7 +534,7 @@ where /// /// Use [`ReadXdR: Read_xdr_into_to_end`] when the intent is for all bytes /// in the read implementation to be consumed by the read. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr_into(&mut self, r: &mut Limited) -> Result<()> { *self = Self::read_xdr(r)?; Ok(()) @@ -505,7 +558,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr_into_to_end(&mut self, r: &mut Limited) -> Result<()> { Self::read_xdr_into(self, r)?; // Check that any further reads, such as this read of one byte, read no @@ -554,7 +607,7 @@ where /// /// An error is returned if the bytes are not completely consumed by the /// deserialization. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn from_xdr(bytes: impl AsRef<[u8]>, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(&mut cursor)?; @@ -578,10 +631,10 @@ where } pub trait WriteXdr { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()>; - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn to_xdr(&self, limits: Limits) -> Result> { let mut cursor = Limited::new(Cursor::new(vec![]), limits); self.write_xdr(&mut cursor)?; @@ -603,13 +656,13 @@ pub trait WriteXdr { /// `Pad_len` returns the number of bytes to pad an XDR value of the given /// length to make the final serialized size a multiple of 4. -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] fn pad_len(len: usize) -> usize { (4 - (len % 4)) % 4 } impl ReadXdr for i32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -621,7 +674,7 @@ impl ReadXdr for i32 { } impl WriteXdr for i32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -632,7 +685,7 @@ impl WriteXdr for i32 { } impl ReadXdr for u32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -644,7 +697,7 @@ impl ReadXdr for u32 { } impl WriteXdr for u32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -655,7 +708,7 @@ impl WriteXdr for u32 { } impl ReadXdr for i64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -667,7 +720,7 @@ impl ReadXdr for i64 { } impl WriteXdr for i64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -678,7 +731,7 @@ impl WriteXdr for i64 { } impl ReadXdr for u64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -690,7 +743,7 @@ impl ReadXdr for u64 { } impl WriteXdr for u64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -701,35 +754,35 @@ impl WriteXdr for u64 { } impl ReadXdr for f32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for f64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for bool { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -740,7 +793,7 @@ impl ReadXdr for bool { } impl WriteXdr for bool { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i = u32::from(*self); // true = 1, false = 0 @@ -750,7 +803,7 @@ impl WriteXdr for bool { } impl ReadXdr for Option { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -767,7 +820,7 @@ impl ReadXdr for Option { } impl WriteXdr for Option { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { if let Some(t) = self { @@ -782,35 +835,35 @@ impl WriteXdr for Option { } impl ReadXdr for Box { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| Ok(Box::new(T::read_xdr(r)?))) } } impl WriteXdr for Box { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| T::write_xdr(self, w)) } } impl ReadXdr for () { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(_r: &mut Limited) -> Result { Ok(()) } } impl WriteXdr for () { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { Ok(()) } } impl ReadXdr for [u8; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { r.consume_len(N)?; @@ -829,7 +882,7 @@ impl ReadXdr for [u8; N] { } impl WriteXdr for [u8; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { w.consume_len(N)?; @@ -843,7 +896,7 @@ impl WriteXdr for [u8; N] { } impl ReadXdr for [T; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let mut vec = Vec::with_capacity(N); @@ -858,7 +911,7 @@ impl ReadXdr for [T; N] { } impl WriteXdr for [T; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { for t in self { @@ -1217,7 +1270,7 @@ impl<'a, const MAX: u32> TryFrom<&'a VecM> for &'a str { } impl ReadXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1244,7 +1297,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1264,7 +1317,7 @@ impl WriteXdr for VecM { } impl ReadXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len = u32::read_xdr(r)?; @@ -1284,7 +1337,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1657,7 +1710,7 @@ impl<'a, const MAX: u32> TryFrom<&'a BytesM> for &'a str { } impl ReadXdr for BytesM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1684,7 +1737,7 @@ impl ReadXdr for BytesM { } impl WriteXdr for BytesM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2060,7 +2113,7 @@ impl<'a, const MAX: u32> TryFrom<&'a StringM> for &'a str { } impl ReadXdr for StringM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -2087,7 +2140,7 @@ impl ReadXdr for StringM { } impl WriteXdr for StringM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2133,7 +2186,7 @@ impl ReadXdr for Frame where T: ReadXdr, { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { // Read the frame header value that contains 1 flag-bit and a 33-bit length. // - The 1 flag bit is 0 when there are more frames for the same record. @@ -2153,10 +2206,8 @@ where } } -#[cfg(all(test, feature = "std"))] +#[cfg(all(test, feature = "alloc"))] mod tests { - use std::io::Cursor; - use super::*; #[test] @@ -2265,7 +2316,7 @@ mod tests { } } -#[cfg(all(test, feature = "std"))] +#[cfg(all(test, feature = "alloc"))] mod test { use super::*; @@ -2811,7 +2862,7 @@ pub struct MyStruct { } impl ReadXdr for MyStruct { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { Ok(Self{ @@ -2826,7 +2877,7 @@ max_string: StringM::<100>::read_xdr(r)?, } impl WriteXdr for MyStruct { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { self.some_int.write_xdr(w)?; @@ -2927,7 +2978,7 @@ TypeVariant::MyStruct, ]; pub const VARIANTS_STR: [&'static str; 2] = [ "Int64", "MyStruct", ]; - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] #[allow(clippy::too_many_lines)] pub fn read_xdr(v: TypeVariant, r: &mut Limited) -> Result { match v { @@ -2943,7 +2994,7 @@ TypeVariant::MyStruct => r.with_limited_depth(|r| Ok(Self::MyStruct(Box::new(MyS Ok(t) } - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] pub fn read_xdr_to_end(v: TypeVariant, r: &mut Limited) -> Result { let s = Self::read_xdr(v, r)?; // Check that any further reads, such as this read of one byte, read no @@ -2990,7 +3041,7 @@ TypeVariant::MyStruct => Box::new(ReadXdrIter::<_, MyStruct>::new(dec, r.limits. } } - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] pub fn from_xdr>(v: TypeVariant, bytes: B, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(v, &mut cursor)?; @@ -3079,7 +3130,7 @@ Self::MyStruct(_) => TypeVariant::MyStruct, } impl WriteXdr for Type { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] #[allow(clippy::too_many_lines)] fn write_xdr(&self, w: &mut Limited) -> Result<()> { match self { diff --git a/spec/output/generator_spec_rust_custom_jsonschema_impls/test.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_jsonschema_impls/test.x/MyXDR.rs index c16a6f4f9..5164b451e 100644 --- a/spec/output/generator_spec_rust_custom_jsonschema_impls/test.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_jsonschema_impls/test.x/MyXDR.rs @@ -35,6 +35,7 @@ use alloc::{ borrow::ToOwned, boxed::Box, string::{FromUtf8Error, String}, + vec, vec::Vec, }; #[cfg(feature = "std")] @@ -43,14 +44,17 @@ use std::string::FromUtf8Error; #[cfg(feature = "arbitrary")] use arbitrary::Arbitrary; -// TODO: Add support for read/write xdr fns when std not available. - #[cfg(feature = "std")] use std::{ error, io, io::{BufRead, BufReader, Cursor, Read, Write}, }; +#[cfg(all(not(feature = "std"), feature = "alloc"))] +use embedded_io::{Error as _, ErrorType, Read, Write}; +#[cfg(all(not(feature = "std"), feature = "alloc"))] +use embedded_io_cursor::Cursor; + /// Error contains all errors returned by functions in this crate. It can be /// compared via `PartialEq`, however any contained IO errors will only be /// compared on their `ErrorKind`. @@ -66,6 +70,8 @@ pub enum Error { InvalidHex, #[cfg(feature = "std")] Io(io::Error), + #[cfg(all(not(feature = "std"), feature = "alloc"))] + Io(embedded_io::ErrorKind), DepthLimitExceeded, #[cfg(feature = "serde_json")] Json(serde_json::Error), @@ -82,13 +88,34 @@ impl PartialEq for Error { // case for comparing errors outputted by the XDR library is for // error case testing, and a lack of the ability to compare has a // detrimental affect on failure testing, so this is a tradeoff. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] (Self::Io(l), Self::Io(r)) => l.kind() == r.kind(), _ => core::mem::discriminant(self) == core::mem::discriminant(other), } } } + +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl embedded_io::Error for Error { + fn kind(&self) -> embedded_io::ErrorKind { + match self { + Self::Io(e) => *e, + _ => embedded_io::ErrorKind::Other, + } + } +} + +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl From> for Error { + fn from(value: embedded_io::ReadExactError) -> Self { + match value { + embedded_io::ReadExactError::UnexpectedEof => Error::Io(embedded_io::ErrorKind::Other), + embedded_io::ReadExactError::Other(e) => e + } + } +} + #[cfg(feature = "std")] impl error::Error for Error { #[must_use] @@ -115,6 +142,8 @@ impl fmt::Display for Error { Error::InvalidHex => write!(f, "hex invalid"), #[cfg(feature = "std")] Error::Io(e) => write!(f, "{e}"), + #[cfg(all(not(feature = "std"), feature = "alloc"))] + Error::Io(_) => write!(f, "io error"), Error::DepthLimitExceeded => write!(f, "depth limit exceeded"), #[cfg(feature = "serde_json")] Error::Json(e) => write!(f, "{e}"), @@ -167,6 +196,9 @@ impl From for () { #[allow(dead_code)] type Result = core::result::Result; +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl ErrorType for Limited { type Error = Error; } + /// Name defines types that assign a static name to their value, such as the /// name given to an identifier in an XDR enum, or the name given to the case in /// a union. @@ -200,7 +232,7 @@ where /// `Limits` contains the limits that a limited reader or writer will be /// constrained to. -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] #[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct Limits { /// Defines the maximum depth for recursive calls in `Read/WriteXdr` to @@ -217,7 +249,7 @@ pub struct Limits { pub len: usize, } -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] impl Limits { #[must_use] pub fn none() -> Self { @@ -248,13 +280,13 @@ impl Limits { /// /// Intended for use with readers and writers and limiting their reads and /// writes. -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] pub struct Limited { pub inner: L, pub(crate) limits: Limits, } -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] impl Limited { /// Constructs a new `Limited`. /// @@ -307,6 +339,15 @@ impl Read for Limited { } } + +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl Read for Limited { + /// Forwards the read operation to the wrapped object. + fn read(&mut self, buf: &mut [u8]) -> core::result::Result { + self.inner.read(buf).map_err(|e| Error::Io(e.kind())) + } +} + #[cfg(feature = "std")] impl BufRead for Limited { /// Forwards the read operation to the wrapped object. @@ -333,6 +374,18 @@ impl Write for Limited { } } +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl Write for Limited { + /// Forwards the write operation to the wrapped object. + fn write(&mut self, buf: &[u8]) -> core::result::Result { + self.inner.write(buf).map_err(|e| Error::Io(e.kind())) + } + + fn flush(&mut self) -> core::result::Result<(), Self::Error> { + self.inner.flush().map_err(|e| Error::Io(e.kind())) + } +} + #[cfg(feature = "std")] pub struct ReadXdrIter { reader: Limited>, @@ -406,7 +459,7 @@ where /// /// Use [`ReadXdR: Read_xdr_to_end`] when the intent is for all bytes in the /// read implementation to be consumed by the read. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result; /// Construct the type from the XDR bytes base64 encoded. @@ -441,7 +494,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr_to_end(r: &mut Limited) -> Result { let s = Self::read_xdr(r)?; // Check that any further reads, such as this read of one byte, read no @@ -481,7 +534,7 @@ where /// /// Use [`ReadXdR: Read_xdr_into_to_end`] when the intent is for all bytes /// in the read implementation to be consumed by the read. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr_into(&mut self, r: &mut Limited) -> Result<()> { *self = Self::read_xdr(r)?; Ok(()) @@ -505,7 +558,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr_into_to_end(&mut self, r: &mut Limited) -> Result<()> { Self::read_xdr_into(self, r)?; // Check that any further reads, such as this read of one byte, read no @@ -554,7 +607,7 @@ where /// /// An error is returned if the bytes are not completely consumed by the /// deserialization. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn from_xdr(bytes: impl AsRef<[u8]>, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(&mut cursor)?; @@ -578,10 +631,10 @@ where } pub trait WriteXdr { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()>; - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn to_xdr(&self, limits: Limits) -> Result> { let mut cursor = Limited::new(Cursor::new(vec![]), limits); self.write_xdr(&mut cursor)?; @@ -603,13 +656,13 @@ pub trait WriteXdr { /// `Pad_len` returns the number of bytes to pad an XDR value of the given /// length to make the final serialized size a multiple of 4. -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] fn pad_len(len: usize) -> usize { (4 - (len % 4)) % 4 } impl ReadXdr for i32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -621,7 +674,7 @@ impl ReadXdr for i32 { } impl WriteXdr for i32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -632,7 +685,7 @@ impl WriteXdr for i32 { } impl ReadXdr for u32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -644,7 +697,7 @@ impl ReadXdr for u32 { } impl WriteXdr for u32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -655,7 +708,7 @@ impl WriteXdr for u32 { } impl ReadXdr for i64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -667,7 +720,7 @@ impl ReadXdr for i64 { } impl WriteXdr for i64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -678,7 +731,7 @@ impl WriteXdr for i64 { } impl ReadXdr for u64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -690,7 +743,7 @@ impl ReadXdr for u64 { } impl WriteXdr for u64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -701,35 +754,35 @@ impl WriteXdr for u64 { } impl ReadXdr for f32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for f64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for bool { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -740,7 +793,7 @@ impl ReadXdr for bool { } impl WriteXdr for bool { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i = u32::from(*self); // true = 1, false = 0 @@ -750,7 +803,7 @@ impl WriteXdr for bool { } impl ReadXdr for Option { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -767,7 +820,7 @@ impl ReadXdr for Option { } impl WriteXdr for Option { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { if let Some(t) = self { @@ -782,35 +835,35 @@ impl WriteXdr for Option { } impl ReadXdr for Box { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| Ok(Box::new(T::read_xdr(r)?))) } } impl WriteXdr for Box { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| T::write_xdr(self, w)) } } impl ReadXdr for () { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(_r: &mut Limited) -> Result { Ok(()) } } impl WriteXdr for () { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { Ok(()) } } impl ReadXdr for [u8; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { r.consume_len(N)?; @@ -829,7 +882,7 @@ impl ReadXdr for [u8; N] { } impl WriteXdr for [u8; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { w.consume_len(N)?; @@ -843,7 +896,7 @@ impl WriteXdr for [u8; N] { } impl ReadXdr for [T; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let mut vec = Vec::with_capacity(N); @@ -858,7 +911,7 @@ impl ReadXdr for [T; N] { } impl WriteXdr for [T; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { for t in self { @@ -1217,7 +1270,7 @@ impl<'a, const MAX: u32> TryFrom<&'a VecM> for &'a str { } impl ReadXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1244,7 +1297,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1264,7 +1317,7 @@ impl WriteXdr for VecM { } impl ReadXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len = u32::read_xdr(r)?; @@ -1284,7 +1337,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1657,7 +1710,7 @@ impl<'a, const MAX: u32> TryFrom<&'a BytesM> for &'a str { } impl ReadXdr for BytesM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1684,7 +1737,7 @@ impl ReadXdr for BytesM { } impl WriteXdr for BytesM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2060,7 +2113,7 @@ impl<'a, const MAX: u32> TryFrom<&'a StringM> for &'a str { } impl ReadXdr for StringM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -2087,7 +2140,7 @@ impl ReadXdr for StringM { } impl WriteXdr for StringM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2133,7 +2186,7 @@ impl ReadXdr for Frame where T: ReadXdr, { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { // Read the frame header value that contains 1 flag-bit and a 33-bit length. // - The 1 flag bit is 0 when there are more frames for the same record. @@ -2153,10 +2206,8 @@ where } } -#[cfg(all(test, feature = "std"))] +#[cfg(all(test, feature = "alloc"))] mod tests { - use std::io::Cursor; - use super::*; #[test] @@ -2265,7 +2316,7 @@ mod tests { } } -#[cfg(all(test, feature = "std"))] +#[cfg(all(test, feature = "alloc"))] mod test { use super::*; @@ -2872,7 +2923,7 @@ impl AsRef<[u8; 64]> for Uint512 { } impl ReadXdr for Uint512 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = <[u8; 64]>::read_xdr(r)?; @@ -2883,7 +2934,7 @@ impl ReadXdr for Uint512 { } impl WriteXdr for Uint512 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w|{ self.0.write_xdr(w) }) } @@ -2962,7 +3013,7 @@ impl AsRef> for Uint513 { } impl ReadXdr for Uint513 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = BytesM::<64>::read_xdr(r)?; @@ -2973,7 +3024,7 @@ impl ReadXdr for Uint513 { } impl WriteXdr for Uint513 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w|{ self.0.write_xdr(w) }) } @@ -3064,7 +3115,7 @@ impl AsRef for Uint514 { } impl ReadXdr for Uint514 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = BytesM::read_xdr(r)?; @@ -3075,7 +3126,7 @@ impl ReadXdr for Uint514 { } impl WriteXdr for Uint514 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w|{ self.0.write_xdr(w) }) } @@ -3166,7 +3217,7 @@ impl AsRef> for Str { } impl ReadXdr for Str { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = StringM::<64>::read_xdr(r)?; @@ -3177,7 +3228,7 @@ impl ReadXdr for Str { } impl WriteXdr for Str { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w|{ self.0.write_xdr(w) }) } @@ -3268,7 +3319,7 @@ impl AsRef for Str2 { } impl ReadXdr for Str2 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = StringM::read_xdr(r)?; @@ -3279,7 +3330,7 @@ impl ReadXdr for Str2 { } impl WriteXdr for Str2 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w|{ self.0.write_xdr(w) }) } @@ -3428,7 +3479,7 @@ impl AsRef<[u8; 32]> for Hash { } impl ReadXdr for Hash { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = <[u8; 32]>::read_xdr(r)?; @@ -3439,7 +3490,7 @@ impl ReadXdr for Hash { } impl WriteXdr for Hash { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w|{ self.0.write_xdr(w) }) } @@ -3517,7 +3568,7 @@ impl AsRef<[Hash; 12]> for Hashes1 { } impl ReadXdr for Hashes1 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = <[Hash; 12]>::read_xdr(r)?; @@ -3528,7 +3579,7 @@ impl ReadXdr for Hashes1 { } impl WriteXdr for Hashes1 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w|{ self.0.write_xdr(w) }) } @@ -3607,7 +3658,7 @@ impl AsRef> for Hashes2 { } impl ReadXdr for Hashes2 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = VecM::::read_xdr(r)?; @@ -3618,7 +3669,7 @@ impl ReadXdr for Hashes2 { } impl WriteXdr for Hashes2 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w|{ self.0.write_xdr(w) }) } @@ -3709,7 +3760,7 @@ impl AsRef> for Hashes3 { } impl ReadXdr for Hashes3 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = VecM::::read_xdr(r)?; @@ -3720,7 +3771,7 @@ impl ReadXdr for Hashes3 { } impl WriteXdr for Hashes3 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w|{ self.0.write_xdr(w) }) } @@ -3810,7 +3861,7 @@ impl AsRef> for OptHash1 { } impl ReadXdr for OptHash1 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = Option::::read_xdr(r)?; @@ -3821,7 +3872,7 @@ impl ReadXdr for OptHash1 { } impl WriteXdr for OptHash1 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w|{ self.0.write_xdr(w) }) } @@ -3862,7 +3913,7 @@ impl AsRef> for OptHash2 { } impl ReadXdr for OptHash2 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = Option::::read_xdr(r)?; @@ -3873,7 +3924,7 @@ impl ReadXdr for OptHash2 { } impl WriteXdr for OptHash2 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w|{ self.0.write_xdr(w) }) } @@ -3940,7 +3991,7 @@ pub struct MyStruct { } impl ReadXdr for MyStruct { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { Ok(Self{ @@ -3957,7 +4008,7 @@ field7: bool::read_xdr(r)?, } impl WriteXdr for MyStruct { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { self.field1.write_xdr(w)?; @@ -3989,7 +4040,7 @@ pub struct LotsOfMyStructs { } impl ReadXdr for LotsOfMyStructs { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { Ok(Self{ @@ -4000,7 +4051,7 @@ impl ReadXdr for LotsOfMyStructs { } impl WriteXdr for LotsOfMyStructs { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { self.members.write_xdr(w)?; @@ -4027,7 +4078,7 @@ pub struct HasStuff { } impl ReadXdr for HasStuff { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { Ok(Self{ @@ -4038,7 +4089,7 @@ impl ReadXdr for HasStuff { } impl WriteXdr for HasStuff { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { self.data.write_xdr(w)?; @@ -4136,7 +4187,7 @@ Self::Green => "Green", } impl ReadXdr for Color { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let e = i32::read_xdr(r)?; @@ -4147,7 +4198,7 @@ Self::Green => "Green", } impl WriteXdr for Color { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i: i32 = (*self).into(); @@ -4255,7 +4306,7 @@ Self::B2 => "B2", } impl ReadXdr for NesterNestedEnum { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let e = i32::read_xdr(r)?; @@ -4266,7 +4317,7 @@ Self::B2 => "B2", } impl WriteXdr for NesterNestedEnum { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i: i32 = (*self).into(); @@ -4292,7 +4343,7 @@ pub struct NesterNestedStruct { } impl ReadXdr for NesterNestedStruct { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { Ok(Self{ @@ -4303,7 +4354,7 @@ impl ReadXdr for NesterNestedStruct { } impl WriteXdr for NesterNestedStruct { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { self.blah.write_xdr(w)?; @@ -4385,7 +4436,7 @@ impl Variants for NesterNestedUnion { impl Union for NesterNestedUnion {} impl ReadXdr for NesterNestedUnion { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let dv: Color = ::read_xdr(r)?; @@ -4401,7 +4452,7 @@ impl ReadXdr for NesterNestedUnion { } impl WriteXdr for NesterNestedUnion { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { self.discriminant().write_xdr(w)?; @@ -4450,7 +4501,7 @@ pub struct Nester { } impl ReadXdr for Nester { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { Ok(Self{ @@ -4463,7 +4514,7 @@ nested_union: NesterNestedUnion::read_xdr(r)?, } impl WriteXdr for Nester { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { self.nested_enum.write_xdr(w)?; @@ -4751,7 +4802,7 @@ TypeVariant::NesterNestedUnion, ]; "NesterNestedStruct", "NesterNestedUnion", ]; - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] #[allow(clippy::too_many_lines)] pub fn read_xdr(v: TypeVariant, r: &mut Limited) -> Result { match v { @@ -4788,7 +4839,7 @@ TypeVariant::NesterNestedUnion => r.with_limited_depth(|r| Ok(Self::NesterNested Ok(t) } - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] pub fn read_xdr_to_end(v: TypeVariant, r: &mut Limited) -> Result { let s = Self::read_xdr(v, r)?; // Check that any further reads, such as this read of one byte, read no @@ -4898,7 +4949,7 @@ TypeVariant::NesterNestedUnion => Box::new(ReadXdrIter::<_, NesterNestedUnion>:: } } - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] pub fn from_xdr>(v: TypeVariant, bytes: B, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(v, &mut cursor)?; @@ -5092,7 +5143,7 @@ Self::NesterNestedUnion(_) => TypeVariant::NesterNestedUnion, } impl WriteXdr for Type { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] #[allow(clippy::too_many_lines)] fn write_xdr(&self, w: &mut Limited) -> Result<()> { match self { diff --git a/spec/output/generator_spec_rust_custom_jsonschema_impls/union.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_jsonschema_impls/union.x/MyXDR.rs index d0b2a427a..04fa7cfcc 100644 --- a/spec/output/generator_spec_rust_custom_jsonschema_impls/union.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_jsonschema_impls/union.x/MyXDR.rs @@ -35,6 +35,7 @@ use alloc::{ borrow::ToOwned, boxed::Box, string::{FromUtf8Error, String}, + vec, vec::Vec, }; #[cfg(feature = "std")] @@ -43,14 +44,17 @@ use std::string::FromUtf8Error; #[cfg(feature = "arbitrary")] use arbitrary::Arbitrary; -// TODO: Add support for read/write xdr fns when std not available. - #[cfg(feature = "std")] use std::{ error, io, io::{BufRead, BufReader, Cursor, Read, Write}, }; +#[cfg(all(not(feature = "std"), feature = "alloc"))] +use embedded_io::{Error as _, ErrorType, Read, Write}; +#[cfg(all(not(feature = "std"), feature = "alloc"))] +use embedded_io_cursor::Cursor; + /// Error contains all errors returned by functions in this crate. It can be /// compared via `PartialEq`, however any contained IO errors will only be /// compared on their `ErrorKind`. @@ -66,6 +70,8 @@ pub enum Error { InvalidHex, #[cfg(feature = "std")] Io(io::Error), + #[cfg(all(not(feature = "std"), feature = "alloc"))] + Io(embedded_io::ErrorKind), DepthLimitExceeded, #[cfg(feature = "serde_json")] Json(serde_json::Error), @@ -82,13 +88,34 @@ impl PartialEq for Error { // case for comparing errors outputted by the XDR library is for // error case testing, and a lack of the ability to compare has a // detrimental affect on failure testing, so this is a tradeoff. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] (Self::Io(l), Self::Io(r)) => l.kind() == r.kind(), _ => core::mem::discriminant(self) == core::mem::discriminant(other), } } } + +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl embedded_io::Error for Error { + fn kind(&self) -> embedded_io::ErrorKind { + match self { + Self::Io(e) => *e, + _ => embedded_io::ErrorKind::Other, + } + } +} + +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl From> for Error { + fn from(value: embedded_io::ReadExactError) -> Self { + match value { + embedded_io::ReadExactError::UnexpectedEof => Error::Io(embedded_io::ErrorKind::Other), + embedded_io::ReadExactError::Other(e) => e + } + } +} + #[cfg(feature = "std")] impl error::Error for Error { #[must_use] @@ -115,6 +142,8 @@ impl fmt::Display for Error { Error::InvalidHex => write!(f, "hex invalid"), #[cfg(feature = "std")] Error::Io(e) => write!(f, "{e}"), + #[cfg(all(not(feature = "std"), feature = "alloc"))] + Error::Io(_) => write!(f, "io error"), Error::DepthLimitExceeded => write!(f, "depth limit exceeded"), #[cfg(feature = "serde_json")] Error::Json(e) => write!(f, "{e}"), @@ -167,6 +196,9 @@ impl From for () { #[allow(dead_code)] type Result = core::result::Result; +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl ErrorType for Limited { type Error = Error; } + /// Name defines types that assign a static name to their value, such as the /// name given to an identifier in an XDR enum, or the name given to the case in /// a union. @@ -200,7 +232,7 @@ where /// `Limits` contains the limits that a limited reader or writer will be /// constrained to. -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] #[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct Limits { /// Defines the maximum depth for recursive calls in `Read/WriteXdr` to @@ -217,7 +249,7 @@ pub struct Limits { pub len: usize, } -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] impl Limits { #[must_use] pub fn none() -> Self { @@ -248,13 +280,13 @@ impl Limits { /// /// Intended for use with readers and writers and limiting their reads and /// writes. -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] pub struct Limited { pub inner: L, pub(crate) limits: Limits, } -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] impl Limited { /// Constructs a new `Limited`. /// @@ -307,6 +339,15 @@ impl Read for Limited { } } + +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl Read for Limited { + /// Forwards the read operation to the wrapped object. + fn read(&mut self, buf: &mut [u8]) -> core::result::Result { + self.inner.read(buf).map_err(|e| Error::Io(e.kind())) + } +} + #[cfg(feature = "std")] impl BufRead for Limited { /// Forwards the read operation to the wrapped object. @@ -333,6 +374,18 @@ impl Write for Limited { } } +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl Write for Limited { + /// Forwards the write operation to the wrapped object. + fn write(&mut self, buf: &[u8]) -> core::result::Result { + self.inner.write(buf).map_err(|e| Error::Io(e.kind())) + } + + fn flush(&mut self) -> core::result::Result<(), Self::Error> { + self.inner.flush().map_err(|e| Error::Io(e.kind())) + } +} + #[cfg(feature = "std")] pub struct ReadXdrIter { reader: Limited>, @@ -406,7 +459,7 @@ where /// /// Use [`ReadXdR: Read_xdr_to_end`] when the intent is for all bytes in the /// read implementation to be consumed by the read. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result; /// Construct the type from the XDR bytes base64 encoded. @@ -441,7 +494,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr_to_end(r: &mut Limited) -> Result { let s = Self::read_xdr(r)?; // Check that any further reads, such as this read of one byte, read no @@ -481,7 +534,7 @@ where /// /// Use [`ReadXdR: Read_xdr_into_to_end`] when the intent is for all bytes /// in the read implementation to be consumed by the read. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr_into(&mut self, r: &mut Limited) -> Result<()> { *self = Self::read_xdr(r)?; Ok(()) @@ -505,7 +558,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr_into_to_end(&mut self, r: &mut Limited) -> Result<()> { Self::read_xdr_into(self, r)?; // Check that any further reads, such as this read of one byte, read no @@ -554,7 +607,7 @@ where /// /// An error is returned if the bytes are not completely consumed by the /// deserialization. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn from_xdr(bytes: impl AsRef<[u8]>, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(&mut cursor)?; @@ -578,10 +631,10 @@ where } pub trait WriteXdr { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()>; - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn to_xdr(&self, limits: Limits) -> Result> { let mut cursor = Limited::new(Cursor::new(vec![]), limits); self.write_xdr(&mut cursor)?; @@ -603,13 +656,13 @@ pub trait WriteXdr { /// `Pad_len` returns the number of bytes to pad an XDR value of the given /// length to make the final serialized size a multiple of 4. -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] fn pad_len(len: usize) -> usize { (4 - (len % 4)) % 4 } impl ReadXdr for i32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -621,7 +674,7 @@ impl ReadXdr for i32 { } impl WriteXdr for i32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -632,7 +685,7 @@ impl WriteXdr for i32 { } impl ReadXdr for u32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -644,7 +697,7 @@ impl ReadXdr for u32 { } impl WriteXdr for u32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -655,7 +708,7 @@ impl WriteXdr for u32 { } impl ReadXdr for i64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -667,7 +720,7 @@ impl ReadXdr for i64 { } impl WriteXdr for i64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -678,7 +731,7 @@ impl WriteXdr for i64 { } impl ReadXdr for u64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -690,7 +743,7 @@ impl ReadXdr for u64 { } impl WriteXdr for u64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -701,35 +754,35 @@ impl WriteXdr for u64 { } impl ReadXdr for f32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for f64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for bool { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -740,7 +793,7 @@ impl ReadXdr for bool { } impl WriteXdr for bool { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i = u32::from(*self); // true = 1, false = 0 @@ -750,7 +803,7 @@ impl WriteXdr for bool { } impl ReadXdr for Option { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -767,7 +820,7 @@ impl ReadXdr for Option { } impl WriteXdr for Option { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { if let Some(t) = self { @@ -782,35 +835,35 @@ impl WriteXdr for Option { } impl ReadXdr for Box { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| Ok(Box::new(T::read_xdr(r)?))) } } impl WriteXdr for Box { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| T::write_xdr(self, w)) } } impl ReadXdr for () { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(_r: &mut Limited) -> Result { Ok(()) } } impl WriteXdr for () { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { Ok(()) } } impl ReadXdr for [u8; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { r.consume_len(N)?; @@ -829,7 +882,7 @@ impl ReadXdr for [u8; N] { } impl WriteXdr for [u8; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { w.consume_len(N)?; @@ -843,7 +896,7 @@ impl WriteXdr for [u8; N] { } impl ReadXdr for [T; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let mut vec = Vec::with_capacity(N); @@ -858,7 +911,7 @@ impl ReadXdr for [T; N] { } impl WriteXdr for [T; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { for t in self { @@ -1217,7 +1270,7 @@ impl<'a, const MAX: u32> TryFrom<&'a VecM> for &'a str { } impl ReadXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1244,7 +1297,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1264,7 +1317,7 @@ impl WriteXdr for VecM { } impl ReadXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len = u32::read_xdr(r)?; @@ -1284,7 +1337,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1657,7 +1710,7 @@ impl<'a, const MAX: u32> TryFrom<&'a BytesM> for &'a str { } impl ReadXdr for BytesM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1684,7 +1737,7 @@ impl ReadXdr for BytesM { } impl WriteXdr for BytesM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2060,7 +2113,7 @@ impl<'a, const MAX: u32> TryFrom<&'a StringM> for &'a str { } impl ReadXdr for StringM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -2087,7 +2140,7 @@ impl ReadXdr for StringM { } impl WriteXdr for StringM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2133,7 +2186,7 @@ impl ReadXdr for Frame where T: ReadXdr, { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { // Read the frame header value that contains 1 flag-bit and a 33-bit length. // - The 1 flag bit is 0 when there are more frames for the same record. @@ -2153,10 +2206,8 @@ where } } -#[cfg(all(test, feature = "std"))] +#[cfg(all(test, feature = "alloc"))] mod tests { - use std::io::Cursor; - use super::*; #[test] @@ -2265,7 +2316,7 @@ mod tests { } } -#[cfg(all(test, feature = "std"))] +#[cfg(all(test, feature = "alloc"))] mod test { use super::*; @@ -2876,7 +2927,7 @@ Self::Multi => "Multi", } impl ReadXdr for UnionKey { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let e = i32::read_xdr(r)?; @@ -2887,7 +2938,7 @@ Self::Multi => "Multi", } impl WriteXdr for UnionKey { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i: i32 = (*self).into(); @@ -2976,7 +3027,7 @@ Self::Multi(_) => UnionKey::Multi, impl Union for MyUnion {} impl ReadXdr for MyUnion { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let dv: UnionKey = ::read_xdr(r)?; @@ -2993,7 +3044,7 @@ UnionKey::Multi => Self::Multi(VecM::::read_xdr(r)?), } impl WriteXdr for MyUnion { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { self.discriminant().write_xdr(w)?; @@ -3087,7 +3138,7 @@ Self::V1(_) => 1, impl Union for IntUnion {} impl ReadXdr for IntUnion { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let dv: i32 = ::read_xdr(r)?; @@ -3104,7 +3155,7 @@ Self::V1(_) => 1, } impl WriteXdr for IntUnion { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { self.discriminant().write_xdr(w)?; @@ -3153,7 +3204,7 @@ impl AsRef for IntUnion2 { } impl ReadXdr for IntUnion2 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = IntUnion::read_xdr(r)?; @@ -3164,7 +3215,7 @@ impl ReadXdr for IntUnion2 { } impl WriteXdr for IntUnion2 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w|{ self.0.write_xdr(w) }) } @@ -3294,7 +3345,7 @@ TypeVariant::IntUnion2, ]; "IntUnion", "IntUnion2", ]; - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] #[allow(clippy::too_many_lines)] pub fn read_xdr(v: TypeVariant, r: &mut Limited) -> Result { match v { @@ -3314,7 +3365,7 @@ TypeVariant::IntUnion2 => r.with_limited_depth(|r| Ok(Self::IntUnion2(Box::new(I Ok(t) } - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] pub fn read_xdr_to_end(v: TypeVariant, r: &mut Limited) -> Result { let s = Self::read_xdr(v, r)?; // Check that any further reads, such as this read of one byte, read no @@ -3373,7 +3424,7 @@ TypeVariant::IntUnion2 => Box::new(ReadXdrIter::<_, IntUnion2>::new(dec, r.limit } } - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] pub fn from_xdr>(v: TypeVariant, bytes: B, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(v, &mut cursor)?; @@ -3482,7 +3533,7 @@ Self::IntUnion2(_) => TypeVariant::IntUnion2, } impl WriteXdr for Type { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] #[allow(clippy::too_many_lines)] fn write_xdr(&self, w: &mut Limited) -> Result<()> { match self { diff --git a/spec/output/generator_spec_rust_custom_str_impls/block_comments.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_str_impls/block_comments.x/MyXDR.rs index 6bb6392dc..0f509ea49 100644 --- a/spec/output/generator_spec_rust_custom_str_impls/block_comments.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_str_impls/block_comments.x/MyXDR.rs @@ -35,6 +35,7 @@ use alloc::{ borrow::ToOwned, boxed::Box, string::{FromUtf8Error, String}, + vec, vec::Vec, }; #[cfg(feature = "std")] @@ -43,14 +44,17 @@ use std::string::FromUtf8Error; #[cfg(feature = "arbitrary")] use arbitrary::Arbitrary; -// TODO: Add support for read/write xdr fns when std not available. - #[cfg(feature = "std")] use std::{ error, io, io::{BufRead, BufReader, Cursor, Read, Write}, }; +#[cfg(all(not(feature = "std"), feature = "alloc"))] +use embedded_io::{Error as _, ErrorType, Read, Write}; +#[cfg(all(not(feature = "std"), feature = "alloc"))] +use embedded_io_cursor::Cursor; + /// Error contains all errors returned by functions in this crate. It can be /// compared via `PartialEq`, however any contained IO errors will only be /// compared on their `ErrorKind`. @@ -66,6 +70,8 @@ pub enum Error { InvalidHex, #[cfg(feature = "std")] Io(io::Error), + #[cfg(all(not(feature = "std"), feature = "alloc"))] + Io(embedded_io::ErrorKind), DepthLimitExceeded, #[cfg(feature = "serde_json")] Json(serde_json::Error), @@ -82,13 +88,34 @@ impl PartialEq for Error { // case for comparing errors outputted by the XDR library is for // error case testing, and a lack of the ability to compare has a // detrimental affect on failure testing, so this is a tradeoff. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] (Self::Io(l), Self::Io(r)) => l.kind() == r.kind(), _ => core::mem::discriminant(self) == core::mem::discriminant(other), } } } + +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl embedded_io::Error for Error { + fn kind(&self) -> embedded_io::ErrorKind { + match self { + Self::Io(e) => *e, + _ => embedded_io::ErrorKind::Other, + } + } +} + +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl From> for Error { + fn from(value: embedded_io::ReadExactError) -> Self { + match value { + embedded_io::ReadExactError::UnexpectedEof => Error::Io(embedded_io::ErrorKind::Other), + embedded_io::ReadExactError::Other(e) => e + } + } +} + #[cfg(feature = "std")] impl error::Error for Error { #[must_use] @@ -115,6 +142,8 @@ impl fmt::Display for Error { Error::InvalidHex => write!(f, "hex invalid"), #[cfg(feature = "std")] Error::Io(e) => write!(f, "{e}"), + #[cfg(all(not(feature = "std"), feature = "alloc"))] + Error::Io(_) => write!(f, "io error"), Error::DepthLimitExceeded => write!(f, "depth limit exceeded"), #[cfg(feature = "serde_json")] Error::Json(e) => write!(f, "{e}"), @@ -167,6 +196,9 @@ impl From for () { #[allow(dead_code)] type Result = core::result::Result; +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl ErrorType for Limited { type Error = Error; } + /// Name defines types that assign a static name to their value, such as the /// name given to an identifier in an XDR enum, or the name given to the case in /// a union. @@ -200,7 +232,7 @@ where /// `Limits` contains the limits that a limited reader or writer will be /// constrained to. -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] #[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct Limits { /// Defines the maximum depth for recursive calls in `Read/WriteXdr` to @@ -217,7 +249,7 @@ pub struct Limits { pub len: usize, } -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] impl Limits { #[must_use] pub fn none() -> Self { @@ -248,13 +280,13 @@ impl Limits { /// /// Intended for use with readers and writers and limiting their reads and /// writes. -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] pub struct Limited { pub inner: L, pub(crate) limits: Limits, } -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] impl Limited { /// Constructs a new `Limited`. /// @@ -307,6 +339,15 @@ impl Read for Limited { } } + +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl Read for Limited { + /// Forwards the read operation to the wrapped object. + fn read(&mut self, buf: &mut [u8]) -> core::result::Result { + self.inner.read(buf).map_err(|e| Error::Io(e.kind())) + } +} + #[cfg(feature = "std")] impl BufRead for Limited { /// Forwards the read operation to the wrapped object. @@ -333,6 +374,18 @@ impl Write for Limited { } } +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl Write for Limited { + /// Forwards the write operation to the wrapped object. + fn write(&mut self, buf: &[u8]) -> core::result::Result { + self.inner.write(buf).map_err(|e| Error::Io(e.kind())) + } + + fn flush(&mut self) -> core::result::Result<(), Self::Error> { + self.inner.flush().map_err(|e| Error::Io(e.kind())) + } +} + #[cfg(feature = "std")] pub struct ReadXdrIter { reader: Limited>, @@ -406,7 +459,7 @@ where /// /// Use [`ReadXdR: Read_xdr_to_end`] when the intent is for all bytes in the /// read implementation to be consumed by the read. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result; /// Construct the type from the XDR bytes base64 encoded. @@ -441,7 +494,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr_to_end(r: &mut Limited) -> Result { let s = Self::read_xdr(r)?; // Check that any further reads, such as this read of one byte, read no @@ -481,7 +534,7 @@ where /// /// Use [`ReadXdR: Read_xdr_into_to_end`] when the intent is for all bytes /// in the read implementation to be consumed by the read. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr_into(&mut self, r: &mut Limited) -> Result<()> { *self = Self::read_xdr(r)?; Ok(()) @@ -505,7 +558,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr_into_to_end(&mut self, r: &mut Limited) -> Result<()> { Self::read_xdr_into(self, r)?; // Check that any further reads, such as this read of one byte, read no @@ -554,7 +607,7 @@ where /// /// An error is returned if the bytes are not completely consumed by the /// deserialization. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn from_xdr(bytes: impl AsRef<[u8]>, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(&mut cursor)?; @@ -578,10 +631,10 @@ where } pub trait WriteXdr { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()>; - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn to_xdr(&self, limits: Limits) -> Result> { let mut cursor = Limited::new(Cursor::new(vec![]), limits); self.write_xdr(&mut cursor)?; @@ -603,13 +656,13 @@ pub trait WriteXdr { /// `Pad_len` returns the number of bytes to pad an XDR value of the given /// length to make the final serialized size a multiple of 4. -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] fn pad_len(len: usize) -> usize { (4 - (len % 4)) % 4 } impl ReadXdr for i32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -621,7 +674,7 @@ impl ReadXdr for i32 { } impl WriteXdr for i32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -632,7 +685,7 @@ impl WriteXdr for i32 { } impl ReadXdr for u32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -644,7 +697,7 @@ impl ReadXdr for u32 { } impl WriteXdr for u32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -655,7 +708,7 @@ impl WriteXdr for u32 { } impl ReadXdr for i64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -667,7 +720,7 @@ impl ReadXdr for i64 { } impl WriteXdr for i64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -678,7 +731,7 @@ impl WriteXdr for i64 { } impl ReadXdr for u64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -690,7 +743,7 @@ impl ReadXdr for u64 { } impl WriteXdr for u64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -701,35 +754,35 @@ impl WriteXdr for u64 { } impl ReadXdr for f32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for f64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for bool { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -740,7 +793,7 @@ impl ReadXdr for bool { } impl WriteXdr for bool { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i = u32::from(*self); // true = 1, false = 0 @@ -750,7 +803,7 @@ impl WriteXdr for bool { } impl ReadXdr for Option { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -767,7 +820,7 @@ impl ReadXdr for Option { } impl WriteXdr for Option { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { if let Some(t) = self { @@ -782,35 +835,35 @@ impl WriteXdr for Option { } impl ReadXdr for Box { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| Ok(Box::new(T::read_xdr(r)?))) } } impl WriteXdr for Box { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| T::write_xdr(self, w)) } } impl ReadXdr for () { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(_r: &mut Limited) -> Result { Ok(()) } } impl WriteXdr for () { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { Ok(()) } } impl ReadXdr for [u8; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { r.consume_len(N)?; @@ -829,7 +882,7 @@ impl ReadXdr for [u8; N] { } impl WriteXdr for [u8; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { w.consume_len(N)?; @@ -843,7 +896,7 @@ impl WriteXdr for [u8; N] { } impl ReadXdr for [T; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let mut vec = Vec::with_capacity(N); @@ -858,7 +911,7 @@ impl ReadXdr for [T; N] { } impl WriteXdr for [T; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { for t in self { @@ -1217,7 +1270,7 @@ impl<'a, const MAX: u32> TryFrom<&'a VecM> for &'a str { } impl ReadXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1244,7 +1297,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1264,7 +1317,7 @@ impl WriteXdr for VecM { } impl ReadXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len = u32::read_xdr(r)?; @@ -1284,7 +1337,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1657,7 +1710,7 @@ impl<'a, const MAX: u32> TryFrom<&'a BytesM> for &'a str { } impl ReadXdr for BytesM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1684,7 +1737,7 @@ impl ReadXdr for BytesM { } impl WriteXdr for BytesM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2060,7 +2113,7 @@ impl<'a, const MAX: u32> TryFrom<&'a StringM> for &'a str { } impl ReadXdr for StringM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -2087,7 +2140,7 @@ impl ReadXdr for StringM { } impl WriteXdr for StringM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2133,7 +2186,7 @@ impl ReadXdr for Frame where T: ReadXdr, { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { // Read the frame header value that contains 1 flag-bit and a 33-bit length. // - The 1 flag bit is 0 when there are more frames for the same record. @@ -2153,10 +2206,8 @@ where } } -#[cfg(all(test, feature = "std"))] +#[cfg(all(test, feature = "alloc"))] mod tests { - use std::io::Cursor; - use super::*; #[test] @@ -2265,7 +2316,7 @@ mod tests { } } -#[cfg(all(test, feature = "std"))] +#[cfg(all(test, feature = "alloc"))] mod test { use super::*; @@ -2856,7 +2907,7 @@ impl From for i32 { } impl ReadXdr for AccountFlags { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let e = i32::read_xdr(r)?; @@ -2867,7 +2918,7 @@ impl ReadXdr for AccountFlags { } impl WriteXdr for AccountFlags { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i: i32 = (*self).into(); @@ -2955,7 +3006,7 @@ impl Type { pub const VARIANTS: [TypeVariant; 1] = [ TypeVariant::AccountFlags, ]; pub const VARIANTS_STR: [&'static str; 1] = [ "AccountFlags", ]; - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] #[allow(clippy::too_many_lines)] pub fn read_xdr(v: TypeVariant, r: &mut Limited) -> Result { match v { @@ -2970,7 +3021,7 @@ impl Type { Ok(t) } - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] pub fn read_xdr_to_end(v: TypeVariant, r: &mut Limited) -> Result { let s = Self::read_xdr(v, r)?; // Check that any further reads, such as this read of one byte, read no @@ -3014,7 +3065,7 @@ impl Type { } } - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] pub fn from_xdr>(v: TypeVariant, bytes: B, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(v, &mut cursor)?; @@ -3098,7 +3149,7 @@ impl Variants for Type { } impl WriteXdr for Type { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] #[allow(clippy::too_many_lines)] fn write_xdr(&self, w: &mut Limited) -> Result<()> { match self { diff --git a/spec/output/generator_spec_rust_custom_str_impls/const.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_str_impls/const.x/MyXDR.rs index 966b54a40..d4d8e38ab 100644 --- a/spec/output/generator_spec_rust_custom_str_impls/const.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_str_impls/const.x/MyXDR.rs @@ -35,6 +35,7 @@ use alloc::{ borrow::ToOwned, boxed::Box, string::{FromUtf8Error, String}, + vec, vec::Vec, }; #[cfg(feature = "std")] @@ -43,14 +44,17 @@ use std::string::FromUtf8Error; #[cfg(feature = "arbitrary")] use arbitrary::Arbitrary; -// TODO: Add support for read/write xdr fns when std not available. - #[cfg(feature = "std")] use std::{ error, io, io::{BufRead, BufReader, Cursor, Read, Write}, }; +#[cfg(all(not(feature = "std"), feature = "alloc"))] +use embedded_io::{Error as _, ErrorType, Read, Write}; +#[cfg(all(not(feature = "std"), feature = "alloc"))] +use embedded_io_cursor::Cursor; + /// Error contains all errors returned by functions in this crate. It can be /// compared via `PartialEq`, however any contained IO errors will only be /// compared on their `ErrorKind`. @@ -66,6 +70,8 @@ pub enum Error { InvalidHex, #[cfg(feature = "std")] Io(io::Error), + #[cfg(all(not(feature = "std"), feature = "alloc"))] + Io(embedded_io::ErrorKind), DepthLimitExceeded, #[cfg(feature = "serde_json")] Json(serde_json::Error), @@ -82,13 +88,34 @@ impl PartialEq for Error { // case for comparing errors outputted by the XDR library is for // error case testing, and a lack of the ability to compare has a // detrimental affect on failure testing, so this is a tradeoff. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] (Self::Io(l), Self::Io(r)) => l.kind() == r.kind(), _ => core::mem::discriminant(self) == core::mem::discriminant(other), } } } + +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl embedded_io::Error for Error { + fn kind(&self) -> embedded_io::ErrorKind { + match self { + Self::Io(e) => *e, + _ => embedded_io::ErrorKind::Other, + } + } +} + +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl From> for Error { + fn from(value: embedded_io::ReadExactError) -> Self { + match value { + embedded_io::ReadExactError::UnexpectedEof => Error::Io(embedded_io::ErrorKind::Other), + embedded_io::ReadExactError::Other(e) => e + } + } +} + #[cfg(feature = "std")] impl error::Error for Error { #[must_use] @@ -115,6 +142,8 @@ impl fmt::Display for Error { Error::InvalidHex => write!(f, "hex invalid"), #[cfg(feature = "std")] Error::Io(e) => write!(f, "{e}"), + #[cfg(all(not(feature = "std"), feature = "alloc"))] + Error::Io(_) => write!(f, "io error"), Error::DepthLimitExceeded => write!(f, "depth limit exceeded"), #[cfg(feature = "serde_json")] Error::Json(e) => write!(f, "{e}"), @@ -167,6 +196,9 @@ impl From for () { #[allow(dead_code)] type Result = core::result::Result; +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl ErrorType for Limited { type Error = Error; } + /// Name defines types that assign a static name to their value, such as the /// name given to an identifier in an XDR enum, or the name given to the case in /// a union. @@ -200,7 +232,7 @@ where /// `Limits` contains the limits that a limited reader or writer will be /// constrained to. -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] #[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct Limits { /// Defines the maximum depth for recursive calls in `Read/WriteXdr` to @@ -217,7 +249,7 @@ pub struct Limits { pub len: usize, } -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] impl Limits { #[must_use] pub fn none() -> Self { @@ -248,13 +280,13 @@ impl Limits { /// /// Intended for use with readers and writers and limiting their reads and /// writes. -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] pub struct Limited { pub inner: L, pub(crate) limits: Limits, } -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] impl Limited { /// Constructs a new `Limited`. /// @@ -307,6 +339,15 @@ impl Read for Limited { } } + +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl Read for Limited { + /// Forwards the read operation to the wrapped object. + fn read(&mut self, buf: &mut [u8]) -> core::result::Result { + self.inner.read(buf).map_err(|e| Error::Io(e.kind())) + } +} + #[cfg(feature = "std")] impl BufRead for Limited { /// Forwards the read operation to the wrapped object. @@ -333,6 +374,18 @@ impl Write for Limited { } } +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl Write for Limited { + /// Forwards the write operation to the wrapped object. + fn write(&mut self, buf: &[u8]) -> core::result::Result { + self.inner.write(buf).map_err(|e| Error::Io(e.kind())) + } + + fn flush(&mut self) -> core::result::Result<(), Self::Error> { + self.inner.flush().map_err(|e| Error::Io(e.kind())) + } +} + #[cfg(feature = "std")] pub struct ReadXdrIter { reader: Limited>, @@ -406,7 +459,7 @@ where /// /// Use [`ReadXdR: Read_xdr_to_end`] when the intent is for all bytes in the /// read implementation to be consumed by the read. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result; /// Construct the type from the XDR bytes base64 encoded. @@ -441,7 +494,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr_to_end(r: &mut Limited) -> Result { let s = Self::read_xdr(r)?; // Check that any further reads, such as this read of one byte, read no @@ -481,7 +534,7 @@ where /// /// Use [`ReadXdR: Read_xdr_into_to_end`] when the intent is for all bytes /// in the read implementation to be consumed by the read. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr_into(&mut self, r: &mut Limited) -> Result<()> { *self = Self::read_xdr(r)?; Ok(()) @@ -505,7 +558,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr_into_to_end(&mut self, r: &mut Limited) -> Result<()> { Self::read_xdr_into(self, r)?; // Check that any further reads, such as this read of one byte, read no @@ -554,7 +607,7 @@ where /// /// An error is returned if the bytes are not completely consumed by the /// deserialization. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn from_xdr(bytes: impl AsRef<[u8]>, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(&mut cursor)?; @@ -578,10 +631,10 @@ where } pub trait WriteXdr { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()>; - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn to_xdr(&self, limits: Limits) -> Result> { let mut cursor = Limited::new(Cursor::new(vec![]), limits); self.write_xdr(&mut cursor)?; @@ -603,13 +656,13 @@ pub trait WriteXdr { /// `Pad_len` returns the number of bytes to pad an XDR value of the given /// length to make the final serialized size a multiple of 4. -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] fn pad_len(len: usize) -> usize { (4 - (len % 4)) % 4 } impl ReadXdr for i32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -621,7 +674,7 @@ impl ReadXdr for i32 { } impl WriteXdr for i32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -632,7 +685,7 @@ impl WriteXdr for i32 { } impl ReadXdr for u32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -644,7 +697,7 @@ impl ReadXdr for u32 { } impl WriteXdr for u32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -655,7 +708,7 @@ impl WriteXdr for u32 { } impl ReadXdr for i64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -667,7 +720,7 @@ impl ReadXdr for i64 { } impl WriteXdr for i64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -678,7 +731,7 @@ impl WriteXdr for i64 { } impl ReadXdr for u64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -690,7 +743,7 @@ impl ReadXdr for u64 { } impl WriteXdr for u64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -701,35 +754,35 @@ impl WriteXdr for u64 { } impl ReadXdr for f32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for f64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for bool { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -740,7 +793,7 @@ impl ReadXdr for bool { } impl WriteXdr for bool { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i = u32::from(*self); // true = 1, false = 0 @@ -750,7 +803,7 @@ impl WriteXdr for bool { } impl ReadXdr for Option { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -767,7 +820,7 @@ impl ReadXdr for Option { } impl WriteXdr for Option { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { if let Some(t) = self { @@ -782,35 +835,35 @@ impl WriteXdr for Option { } impl ReadXdr for Box { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| Ok(Box::new(T::read_xdr(r)?))) } } impl WriteXdr for Box { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| T::write_xdr(self, w)) } } impl ReadXdr for () { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(_r: &mut Limited) -> Result { Ok(()) } } impl WriteXdr for () { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { Ok(()) } } impl ReadXdr for [u8; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { r.consume_len(N)?; @@ -829,7 +882,7 @@ impl ReadXdr for [u8; N] { } impl WriteXdr for [u8; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { w.consume_len(N)?; @@ -843,7 +896,7 @@ impl WriteXdr for [u8; N] { } impl ReadXdr for [T; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let mut vec = Vec::with_capacity(N); @@ -858,7 +911,7 @@ impl ReadXdr for [T; N] { } impl WriteXdr for [T; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { for t in self { @@ -1217,7 +1270,7 @@ impl<'a, const MAX: u32> TryFrom<&'a VecM> for &'a str { } impl ReadXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1244,7 +1297,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1264,7 +1317,7 @@ impl WriteXdr for VecM { } impl ReadXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len = u32::read_xdr(r)?; @@ -1284,7 +1337,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1657,7 +1710,7 @@ impl<'a, const MAX: u32> TryFrom<&'a BytesM> for &'a str { } impl ReadXdr for BytesM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1684,7 +1737,7 @@ impl ReadXdr for BytesM { } impl WriteXdr for BytesM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2060,7 +2113,7 @@ impl<'a, const MAX: u32> TryFrom<&'a StringM> for &'a str { } impl ReadXdr for StringM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -2087,7 +2140,7 @@ impl ReadXdr for StringM { } impl WriteXdr for StringM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2133,7 +2186,7 @@ impl ReadXdr for Frame where T: ReadXdr, { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { // Read the frame header value that contains 1 flag-bit and a 33-bit length. // - The 1 flag bit is 0 when there are more frames for the same record. @@ -2153,10 +2206,8 @@ where } } -#[cfg(all(test, feature = "std"))] +#[cfg(all(test, feature = "alloc"))] mod tests { - use std::io::Cursor; - use super::*; #[test] @@ -2265,7 +2316,7 @@ mod tests { } } -#[cfg(all(test, feature = "std"))] +#[cfg(all(test, feature = "alloc"))] mod test { use super::*; @@ -2890,7 +2941,7 @@ TypeVariant::TestArray2, ]; pub const VARIANTS_STR: [&'static str; 2] = [ "TestArray", "TestArray2", ]; - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] #[allow(clippy::too_many_lines)] pub fn read_xdr(v: TypeVariant, r: &mut Limited) -> Result { match v { @@ -2906,7 +2957,7 @@ TypeVariant::TestArray2 => r.with_limited_depth(|r| Ok(Self::TestArray2(Box::new Ok(t) } - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] pub fn read_xdr_to_end(v: TypeVariant, r: &mut Limited) -> Result { let s = Self::read_xdr(v, r)?; // Check that any further reads, such as this read of one byte, read no @@ -2953,7 +3004,7 @@ TypeVariant::TestArray2 => Box::new(ReadXdrIter::<_, TestArray2>::new(dec, r.lim } } - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] pub fn from_xdr>(v: TypeVariant, bytes: B, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(v, &mut cursor)?; @@ -3042,7 +3093,7 @@ Self::TestArray2(_) => TypeVariant::TestArray2, } impl WriteXdr for Type { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] #[allow(clippy::too_many_lines)] fn write_xdr(&self, w: &mut Limited) -> Result<()> { match self { diff --git a/spec/output/generator_spec_rust_custom_str_impls/enum.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_str_impls/enum.x/MyXDR.rs index 3a63ac95d..e890eb80d 100644 --- a/spec/output/generator_spec_rust_custom_str_impls/enum.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_str_impls/enum.x/MyXDR.rs @@ -35,6 +35,7 @@ use alloc::{ borrow::ToOwned, boxed::Box, string::{FromUtf8Error, String}, + vec, vec::Vec, }; #[cfg(feature = "std")] @@ -43,14 +44,17 @@ use std::string::FromUtf8Error; #[cfg(feature = "arbitrary")] use arbitrary::Arbitrary; -// TODO: Add support for read/write xdr fns when std not available. - #[cfg(feature = "std")] use std::{ error, io, io::{BufRead, BufReader, Cursor, Read, Write}, }; +#[cfg(all(not(feature = "std"), feature = "alloc"))] +use embedded_io::{Error as _, ErrorType, Read, Write}; +#[cfg(all(not(feature = "std"), feature = "alloc"))] +use embedded_io_cursor::Cursor; + /// Error contains all errors returned by functions in this crate. It can be /// compared via `PartialEq`, however any contained IO errors will only be /// compared on their `ErrorKind`. @@ -66,6 +70,8 @@ pub enum Error { InvalidHex, #[cfg(feature = "std")] Io(io::Error), + #[cfg(all(not(feature = "std"), feature = "alloc"))] + Io(embedded_io::ErrorKind), DepthLimitExceeded, #[cfg(feature = "serde_json")] Json(serde_json::Error), @@ -82,13 +88,34 @@ impl PartialEq for Error { // case for comparing errors outputted by the XDR library is for // error case testing, and a lack of the ability to compare has a // detrimental affect on failure testing, so this is a tradeoff. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] (Self::Io(l), Self::Io(r)) => l.kind() == r.kind(), _ => core::mem::discriminant(self) == core::mem::discriminant(other), } } } + +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl embedded_io::Error for Error { + fn kind(&self) -> embedded_io::ErrorKind { + match self { + Self::Io(e) => *e, + _ => embedded_io::ErrorKind::Other, + } + } +} + +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl From> for Error { + fn from(value: embedded_io::ReadExactError) -> Self { + match value { + embedded_io::ReadExactError::UnexpectedEof => Error::Io(embedded_io::ErrorKind::Other), + embedded_io::ReadExactError::Other(e) => e + } + } +} + #[cfg(feature = "std")] impl error::Error for Error { #[must_use] @@ -115,6 +142,8 @@ impl fmt::Display for Error { Error::InvalidHex => write!(f, "hex invalid"), #[cfg(feature = "std")] Error::Io(e) => write!(f, "{e}"), + #[cfg(all(not(feature = "std"), feature = "alloc"))] + Error::Io(_) => write!(f, "io error"), Error::DepthLimitExceeded => write!(f, "depth limit exceeded"), #[cfg(feature = "serde_json")] Error::Json(e) => write!(f, "{e}"), @@ -167,6 +196,9 @@ impl From for () { #[allow(dead_code)] type Result = core::result::Result; +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl ErrorType for Limited { type Error = Error; } + /// Name defines types that assign a static name to their value, such as the /// name given to an identifier in an XDR enum, or the name given to the case in /// a union. @@ -200,7 +232,7 @@ where /// `Limits` contains the limits that a limited reader or writer will be /// constrained to. -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] #[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct Limits { /// Defines the maximum depth for recursive calls in `Read/WriteXdr` to @@ -217,7 +249,7 @@ pub struct Limits { pub len: usize, } -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] impl Limits { #[must_use] pub fn none() -> Self { @@ -248,13 +280,13 @@ impl Limits { /// /// Intended for use with readers and writers and limiting their reads and /// writes. -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] pub struct Limited { pub inner: L, pub(crate) limits: Limits, } -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] impl Limited { /// Constructs a new `Limited`. /// @@ -307,6 +339,15 @@ impl Read for Limited { } } + +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl Read for Limited { + /// Forwards the read operation to the wrapped object. + fn read(&mut self, buf: &mut [u8]) -> core::result::Result { + self.inner.read(buf).map_err(|e| Error::Io(e.kind())) + } +} + #[cfg(feature = "std")] impl BufRead for Limited { /// Forwards the read operation to the wrapped object. @@ -333,6 +374,18 @@ impl Write for Limited { } } +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl Write for Limited { + /// Forwards the write operation to the wrapped object. + fn write(&mut self, buf: &[u8]) -> core::result::Result { + self.inner.write(buf).map_err(|e| Error::Io(e.kind())) + } + + fn flush(&mut self) -> core::result::Result<(), Self::Error> { + self.inner.flush().map_err(|e| Error::Io(e.kind())) + } +} + #[cfg(feature = "std")] pub struct ReadXdrIter { reader: Limited>, @@ -406,7 +459,7 @@ where /// /// Use [`ReadXdR: Read_xdr_to_end`] when the intent is for all bytes in the /// read implementation to be consumed by the read. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result; /// Construct the type from the XDR bytes base64 encoded. @@ -441,7 +494,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr_to_end(r: &mut Limited) -> Result { let s = Self::read_xdr(r)?; // Check that any further reads, such as this read of one byte, read no @@ -481,7 +534,7 @@ where /// /// Use [`ReadXdR: Read_xdr_into_to_end`] when the intent is for all bytes /// in the read implementation to be consumed by the read. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr_into(&mut self, r: &mut Limited) -> Result<()> { *self = Self::read_xdr(r)?; Ok(()) @@ -505,7 +558,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr_into_to_end(&mut self, r: &mut Limited) -> Result<()> { Self::read_xdr_into(self, r)?; // Check that any further reads, such as this read of one byte, read no @@ -554,7 +607,7 @@ where /// /// An error is returned if the bytes are not completely consumed by the /// deserialization. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn from_xdr(bytes: impl AsRef<[u8]>, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(&mut cursor)?; @@ -578,10 +631,10 @@ where } pub trait WriteXdr { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()>; - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn to_xdr(&self, limits: Limits) -> Result> { let mut cursor = Limited::new(Cursor::new(vec![]), limits); self.write_xdr(&mut cursor)?; @@ -603,13 +656,13 @@ pub trait WriteXdr { /// `Pad_len` returns the number of bytes to pad an XDR value of the given /// length to make the final serialized size a multiple of 4. -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] fn pad_len(len: usize) -> usize { (4 - (len % 4)) % 4 } impl ReadXdr for i32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -621,7 +674,7 @@ impl ReadXdr for i32 { } impl WriteXdr for i32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -632,7 +685,7 @@ impl WriteXdr for i32 { } impl ReadXdr for u32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -644,7 +697,7 @@ impl ReadXdr for u32 { } impl WriteXdr for u32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -655,7 +708,7 @@ impl WriteXdr for u32 { } impl ReadXdr for i64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -667,7 +720,7 @@ impl ReadXdr for i64 { } impl WriteXdr for i64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -678,7 +731,7 @@ impl WriteXdr for i64 { } impl ReadXdr for u64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -690,7 +743,7 @@ impl ReadXdr for u64 { } impl WriteXdr for u64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -701,35 +754,35 @@ impl WriteXdr for u64 { } impl ReadXdr for f32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for f64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for bool { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -740,7 +793,7 @@ impl ReadXdr for bool { } impl WriteXdr for bool { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i = u32::from(*self); // true = 1, false = 0 @@ -750,7 +803,7 @@ impl WriteXdr for bool { } impl ReadXdr for Option { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -767,7 +820,7 @@ impl ReadXdr for Option { } impl WriteXdr for Option { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { if let Some(t) = self { @@ -782,35 +835,35 @@ impl WriteXdr for Option { } impl ReadXdr for Box { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| Ok(Box::new(T::read_xdr(r)?))) } } impl WriteXdr for Box { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| T::write_xdr(self, w)) } } impl ReadXdr for () { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(_r: &mut Limited) -> Result { Ok(()) } } impl WriteXdr for () { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { Ok(()) } } impl ReadXdr for [u8; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { r.consume_len(N)?; @@ -829,7 +882,7 @@ impl ReadXdr for [u8; N] { } impl WriteXdr for [u8; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { w.consume_len(N)?; @@ -843,7 +896,7 @@ impl WriteXdr for [u8; N] { } impl ReadXdr for [T; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let mut vec = Vec::with_capacity(N); @@ -858,7 +911,7 @@ impl ReadXdr for [T; N] { } impl WriteXdr for [T; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { for t in self { @@ -1217,7 +1270,7 @@ impl<'a, const MAX: u32> TryFrom<&'a VecM> for &'a str { } impl ReadXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1244,7 +1297,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1264,7 +1317,7 @@ impl WriteXdr for VecM { } impl ReadXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len = u32::read_xdr(r)?; @@ -1284,7 +1337,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1657,7 +1710,7 @@ impl<'a, const MAX: u32> TryFrom<&'a BytesM> for &'a str { } impl ReadXdr for BytesM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1684,7 +1737,7 @@ impl ReadXdr for BytesM { } impl WriteXdr for BytesM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2060,7 +2113,7 @@ impl<'a, const MAX: u32> TryFrom<&'a StringM> for &'a str { } impl ReadXdr for StringM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -2087,7 +2140,7 @@ impl ReadXdr for StringM { } impl WriteXdr for StringM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2133,7 +2186,7 @@ impl ReadXdr for Frame where T: ReadXdr, { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { // Read the frame header value that contains 1 flag-bit and a 33-bit length. // - The 1 flag bit is 0 when there are more frames for the same record. @@ -2153,10 +2206,8 @@ where } } -#[cfg(all(test, feature = "std"))] +#[cfg(all(test, feature = "alloc"))] mod tests { - use std::io::Cursor; - use super::*; #[test] @@ -2265,7 +2316,7 @@ mod tests { } } -#[cfg(all(test, feature = "std"))] +#[cfg(all(test, feature = "alloc"))] mod test { use super::*; @@ -2940,7 +2991,7 @@ Self::FbaMessage => "FbaMessage", } impl ReadXdr for MessageType { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let e = i32::read_xdr(r)?; @@ -2951,7 +3002,7 @@ Self::FbaMessage => "FbaMessage", } impl WriteXdr for MessageType { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i: i32 = (*self).into(); @@ -3049,7 +3100,7 @@ Self::Blue => "Blue", } impl ReadXdr for Color { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let e = i32::read_xdr(r)?; @@ -3060,7 +3111,7 @@ Self::Blue => "Blue", } impl WriteXdr for Color { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i: i32 = (*self).into(); @@ -3158,7 +3209,7 @@ Self::Blue2 => "Blue2", } impl ReadXdr for Color2 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let e = i32::read_xdr(r)?; @@ -3169,7 +3220,7 @@ Self::Blue2 => "Blue2", } impl WriteXdr for Color2 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i: i32 = (*self).into(); @@ -3267,7 +3318,7 @@ Self::R3 => "R3", } impl ReadXdr for Color3 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let e = i32::read_xdr(r)?; @@ -3278,7 +3329,7 @@ Self::R3 => "R3", } impl WriteXdr for Color3 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i: i32 = (*self).into(); @@ -3393,7 +3444,7 @@ TypeVariant::Color3, ]; "Color2", "Color3", ]; - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] #[allow(clippy::too_many_lines)] pub fn read_xdr(v: TypeVariant, r: &mut Limited) -> Result { match v { @@ -3411,7 +3462,7 @@ TypeVariant::Color3 => r.with_limited_depth(|r| Ok(Self::Color3(Box::new(Color3: Ok(t) } - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] pub fn read_xdr_to_end(v: TypeVariant, r: &mut Limited) -> Result { let s = Self::read_xdr(v, r)?; // Check that any further reads, such as this read of one byte, read no @@ -3464,7 +3515,7 @@ TypeVariant::Color3 => Box::new(ReadXdrIter::<_, Color3>::new(dec, r.limits.clon } } - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] pub fn from_xdr>(v: TypeVariant, bytes: B, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(v, &mut cursor)?; @@ -3563,7 +3614,7 @@ Self::Color3(_) => TypeVariant::Color3, } impl WriteXdr for Type { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] #[allow(clippy::too_many_lines)] fn write_xdr(&self, w: &mut Limited) -> Result<()> { match self { diff --git a/spec/output/generator_spec_rust_custom_str_impls/nesting.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_str_impls/nesting.x/MyXDR.rs index fd6a7b54f..58cb1b478 100644 --- a/spec/output/generator_spec_rust_custom_str_impls/nesting.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_str_impls/nesting.x/MyXDR.rs @@ -35,6 +35,7 @@ use alloc::{ borrow::ToOwned, boxed::Box, string::{FromUtf8Error, String}, + vec, vec::Vec, }; #[cfg(feature = "std")] @@ -43,14 +44,17 @@ use std::string::FromUtf8Error; #[cfg(feature = "arbitrary")] use arbitrary::Arbitrary; -// TODO: Add support for read/write xdr fns when std not available. - #[cfg(feature = "std")] use std::{ error, io, io::{BufRead, BufReader, Cursor, Read, Write}, }; +#[cfg(all(not(feature = "std"), feature = "alloc"))] +use embedded_io::{Error as _, ErrorType, Read, Write}; +#[cfg(all(not(feature = "std"), feature = "alloc"))] +use embedded_io_cursor::Cursor; + /// Error contains all errors returned by functions in this crate. It can be /// compared via `PartialEq`, however any contained IO errors will only be /// compared on their `ErrorKind`. @@ -66,6 +70,8 @@ pub enum Error { InvalidHex, #[cfg(feature = "std")] Io(io::Error), + #[cfg(all(not(feature = "std"), feature = "alloc"))] + Io(embedded_io::ErrorKind), DepthLimitExceeded, #[cfg(feature = "serde_json")] Json(serde_json::Error), @@ -82,13 +88,34 @@ impl PartialEq for Error { // case for comparing errors outputted by the XDR library is for // error case testing, and a lack of the ability to compare has a // detrimental affect on failure testing, so this is a tradeoff. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] (Self::Io(l), Self::Io(r)) => l.kind() == r.kind(), _ => core::mem::discriminant(self) == core::mem::discriminant(other), } } } + +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl embedded_io::Error for Error { + fn kind(&self) -> embedded_io::ErrorKind { + match self { + Self::Io(e) => *e, + _ => embedded_io::ErrorKind::Other, + } + } +} + +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl From> for Error { + fn from(value: embedded_io::ReadExactError) -> Self { + match value { + embedded_io::ReadExactError::UnexpectedEof => Error::Io(embedded_io::ErrorKind::Other), + embedded_io::ReadExactError::Other(e) => e + } + } +} + #[cfg(feature = "std")] impl error::Error for Error { #[must_use] @@ -115,6 +142,8 @@ impl fmt::Display for Error { Error::InvalidHex => write!(f, "hex invalid"), #[cfg(feature = "std")] Error::Io(e) => write!(f, "{e}"), + #[cfg(all(not(feature = "std"), feature = "alloc"))] + Error::Io(_) => write!(f, "io error"), Error::DepthLimitExceeded => write!(f, "depth limit exceeded"), #[cfg(feature = "serde_json")] Error::Json(e) => write!(f, "{e}"), @@ -167,6 +196,9 @@ impl From for () { #[allow(dead_code)] type Result = core::result::Result; +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl ErrorType for Limited { type Error = Error; } + /// Name defines types that assign a static name to their value, such as the /// name given to an identifier in an XDR enum, or the name given to the case in /// a union. @@ -200,7 +232,7 @@ where /// `Limits` contains the limits that a limited reader or writer will be /// constrained to. -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] #[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct Limits { /// Defines the maximum depth for recursive calls in `Read/WriteXdr` to @@ -217,7 +249,7 @@ pub struct Limits { pub len: usize, } -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] impl Limits { #[must_use] pub fn none() -> Self { @@ -248,13 +280,13 @@ impl Limits { /// /// Intended for use with readers and writers and limiting their reads and /// writes. -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] pub struct Limited { pub inner: L, pub(crate) limits: Limits, } -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] impl Limited { /// Constructs a new `Limited`. /// @@ -307,6 +339,15 @@ impl Read for Limited { } } + +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl Read for Limited { + /// Forwards the read operation to the wrapped object. + fn read(&mut self, buf: &mut [u8]) -> core::result::Result { + self.inner.read(buf).map_err(|e| Error::Io(e.kind())) + } +} + #[cfg(feature = "std")] impl BufRead for Limited { /// Forwards the read operation to the wrapped object. @@ -333,6 +374,18 @@ impl Write for Limited { } } +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl Write for Limited { + /// Forwards the write operation to the wrapped object. + fn write(&mut self, buf: &[u8]) -> core::result::Result { + self.inner.write(buf).map_err(|e| Error::Io(e.kind())) + } + + fn flush(&mut self) -> core::result::Result<(), Self::Error> { + self.inner.flush().map_err(|e| Error::Io(e.kind())) + } +} + #[cfg(feature = "std")] pub struct ReadXdrIter { reader: Limited>, @@ -406,7 +459,7 @@ where /// /// Use [`ReadXdR: Read_xdr_to_end`] when the intent is for all bytes in the /// read implementation to be consumed by the read. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result; /// Construct the type from the XDR bytes base64 encoded. @@ -441,7 +494,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr_to_end(r: &mut Limited) -> Result { let s = Self::read_xdr(r)?; // Check that any further reads, such as this read of one byte, read no @@ -481,7 +534,7 @@ where /// /// Use [`ReadXdR: Read_xdr_into_to_end`] when the intent is for all bytes /// in the read implementation to be consumed by the read. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr_into(&mut self, r: &mut Limited) -> Result<()> { *self = Self::read_xdr(r)?; Ok(()) @@ -505,7 +558,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr_into_to_end(&mut self, r: &mut Limited) -> Result<()> { Self::read_xdr_into(self, r)?; // Check that any further reads, such as this read of one byte, read no @@ -554,7 +607,7 @@ where /// /// An error is returned if the bytes are not completely consumed by the /// deserialization. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn from_xdr(bytes: impl AsRef<[u8]>, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(&mut cursor)?; @@ -578,10 +631,10 @@ where } pub trait WriteXdr { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()>; - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn to_xdr(&self, limits: Limits) -> Result> { let mut cursor = Limited::new(Cursor::new(vec![]), limits); self.write_xdr(&mut cursor)?; @@ -603,13 +656,13 @@ pub trait WriteXdr { /// `Pad_len` returns the number of bytes to pad an XDR value of the given /// length to make the final serialized size a multiple of 4. -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] fn pad_len(len: usize) -> usize { (4 - (len % 4)) % 4 } impl ReadXdr for i32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -621,7 +674,7 @@ impl ReadXdr for i32 { } impl WriteXdr for i32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -632,7 +685,7 @@ impl WriteXdr for i32 { } impl ReadXdr for u32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -644,7 +697,7 @@ impl ReadXdr for u32 { } impl WriteXdr for u32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -655,7 +708,7 @@ impl WriteXdr for u32 { } impl ReadXdr for i64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -667,7 +720,7 @@ impl ReadXdr for i64 { } impl WriteXdr for i64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -678,7 +731,7 @@ impl WriteXdr for i64 { } impl ReadXdr for u64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -690,7 +743,7 @@ impl ReadXdr for u64 { } impl WriteXdr for u64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -701,35 +754,35 @@ impl WriteXdr for u64 { } impl ReadXdr for f32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for f64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for bool { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -740,7 +793,7 @@ impl ReadXdr for bool { } impl WriteXdr for bool { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i = u32::from(*self); // true = 1, false = 0 @@ -750,7 +803,7 @@ impl WriteXdr for bool { } impl ReadXdr for Option { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -767,7 +820,7 @@ impl ReadXdr for Option { } impl WriteXdr for Option { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { if let Some(t) = self { @@ -782,35 +835,35 @@ impl WriteXdr for Option { } impl ReadXdr for Box { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| Ok(Box::new(T::read_xdr(r)?))) } } impl WriteXdr for Box { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| T::write_xdr(self, w)) } } impl ReadXdr for () { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(_r: &mut Limited) -> Result { Ok(()) } } impl WriteXdr for () { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { Ok(()) } } impl ReadXdr for [u8; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { r.consume_len(N)?; @@ -829,7 +882,7 @@ impl ReadXdr for [u8; N] { } impl WriteXdr for [u8; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { w.consume_len(N)?; @@ -843,7 +896,7 @@ impl WriteXdr for [u8; N] { } impl ReadXdr for [T; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let mut vec = Vec::with_capacity(N); @@ -858,7 +911,7 @@ impl ReadXdr for [T; N] { } impl WriteXdr for [T; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { for t in self { @@ -1217,7 +1270,7 @@ impl<'a, const MAX: u32> TryFrom<&'a VecM> for &'a str { } impl ReadXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1244,7 +1297,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1264,7 +1317,7 @@ impl WriteXdr for VecM { } impl ReadXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len = u32::read_xdr(r)?; @@ -1284,7 +1337,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1657,7 +1710,7 @@ impl<'a, const MAX: u32> TryFrom<&'a BytesM> for &'a str { } impl ReadXdr for BytesM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1684,7 +1737,7 @@ impl ReadXdr for BytesM { } impl WriteXdr for BytesM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2060,7 +2113,7 @@ impl<'a, const MAX: u32> TryFrom<&'a StringM> for &'a str { } impl ReadXdr for StringM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -2087,7 +2140,7 @@ impl ReadXdr for StringM { } impl WriteXdr for StringM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2133,7 +2186,7 @@ impl ReadXdr for Frame where T: ReadXdr, { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { // Read the frame header value that contains 1 flag-bit and a 33-bit length. // - The 1 flag bit is 0 when there are more frames for the same record. @@ -2153,10 +2206,8 @@ where } } -#[cfg(all(test, feature = "std"))] +#[cfg(all(test, feature = "alloc"))] mod tests { - use std::io::Cursor; - use super::*; #[test] @@ -2265,7 +2316,7 @@ mod tests { } } -#[cfg(all(test, feature = "std"))] +#[cfg(all(test, feature = "alloc"))] mod test { use super::*; @@ -2867,7 +2918,7 @@ Self::Offer => "Offer", } impl ReadXdr for UnionKey { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let e = i32::read_xdr(r)?; @@ -2878,7 +2929,7 @@ Self::Offer => "Offer", } impl WriteXdr for UnionKey { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i: i32 = (*self).into(); @@ -2912,7 +2963,7 @@ pub struct MyUnionOne { } impl ReadXdr for MyUnionOne { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { Ok(Self{ @@ -2923,7 +2974,7 @@ impl ReadXdr for MyUnionOne { } impl WriteXdr for MyUnionOne { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { self.some_int.write_xdr(w)?; @@ -2951,7 +3002,7 @@ pub struct MyUnionTwo { } impl ReadXdr for MyUnionTwo { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { Ok(Self{ @@ -2963,7 +3014,7 @@ foo: i32::read_xdr(r)?, } impl WriteXdr for MyUnionTwo { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { self.some_int.write_xdr(w)?; @@ -3066,7 +3117,7 @@ Self::Offer => UnionKey::Offer, impl Union for MyUnion {} impl ReadXdr for MyUnion { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let dv: UnionKey = ::read_xdr(r)?; @@ -3084,7 +3135,7 @@ UnionKey::Offer => Self::Offer, } impl WriteXdr for MyUnion { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { self.discriminant().write_xdr(w)?; @@ -3214,7 +3265,7 @@ TypeVariant::MyUnionTwo, ]; "MyUnionOne", "MyUnionTwo", ]; - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] #[allow(clippy::too_many_lines)] pub fn read_xdr(v: TypeVariant, r: &mut Limited) -> Result { match v { @@ -3233,7 +3284,7 @@ TypeVariant::MyUnionTwo => r.with_limited_depth(|r| Ok(Self::MyUnionTwo(Box::new Ok(t) } - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] pub fn read_xdr_to_end(v: TypeVariant, r: &mut Limited) -> Result { let s = Self::read_xdr(v, r)?; // Check that any further reads, such as this read of one byte, read no @@ -3289,7 +3340,7 @@ TypeVariant::MyUnionTwo => Box::new(ReadXdrIter::<_, MyUnionTwo>::new(dec, r.lim } } - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] pub fn from_xdr>(v: TypeVariant, bytes: B, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(v, &mut cursor)?; @@ -3393,7 +3444,7 @@ Self::MyUnionTwo(_) => TypeVariant::MyUnionTwo, } impl WriteXdr for Type { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] #[allow(clippy::too_many_lines)] fn write_xdr(&self, w: &mut Limited) -> Result<()> { match self { diff --git a/spec/output/generator_spec_rust_custom_str_impls/optional.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_str_impls/optional.x/MyXDR.rs index d4fed65d3..9ac7c5c6d 100644 --- a/spec/output/generator_spec_rust_custom_str_impls/optional.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_str_impls/optional.x/MyXDR.rs @@ -35,6 +35,7 @@ use alloc::{ borrow::ToOwned, boxed::Box, string::{FromUtf8Error, String}, + vec, vec::Vec, }; #[cfg(feature = "std")] @@ -43,14 +44,17 @@ use std::string::FromUtf8Error; #[cfg(feature = "arbitrary")] use arbitrary::Arbitrary; -// TODO: Add support for read/write xdr fns when std not available. - #[cfg(feature = "std")] use std::{ error, io, io::{BufRead, BufReader, Cursor, Read, Write}, }; +#[cfg(all(not(feature = "std"), feature = "alloc"))] +use embedded_io::{Error as _, ErrorType, Read, Write}; +#[cfg(all(not(feature = "std"), feature = "alloc"))] +use embedded_io_cursor::Cursor; + /// Error contains all errors returned by functions in this crate. It can be /// compared via `PartialEq`, however any contained IO errors will only be /// compared on their `ErrorKind`. @@ -66,6 +70,8 @@ pub enum Error { InvalidHex, #[cfg(feature = "std")] Io(io::Error), + #[cfg(all(not(feature = "std"), feature = "alloc"))] + Io(embedded_io::ErrorKind), DepthLimitExceeded, #[cfg(feature = "serde_json")] Json(serde_json::Error), @@ -82,13 +88,34 @@ impl PartialEq for Error { // case for comparing errors outputted by the XDR library is for // error case testing, and a lack of the ability to compare has a // detrimental affect on failure testing, so this is a tradeoff. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] (Self::Io(l), Self::Io(r)) => l.kind() == r.kind(), _ => core::mem::discriminant(self) == core::mem::discriminant(other), } } } + +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl embedded_io::Error for Error { + fn kind(&self) -> embedded_io::ErrorKind { + match self { + Self::Io(e) => *e, + _ => embedded_io::ErrorKind::Other, + } + } +} + +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl From> for Error { + fn from(value: embedded_io::ReadExactError) -> Self { + match value { + embedded_io::ReadExactError::UnexpectedEof => Error::Io(embedded_io::ErrorKind::Other), + embedded_io::ReadExactError::Other(e) => e + } + } +} + #[cfg(feature = "std")] impl error::Error for Error { #[must_use] @@ -115,6 +142,8 @@ impl fmt::Display for Error { Error::InvalidHex => write!(f, "hex invalid"), #[cfg(feature = "std")] Error::Io(e) => write!(f, "{e}"), + #[cfg(all(not(feature = "std"), feature = "alloc"))] + Error::Io(_) => write!(f, "io error"), Error::DepthLimitExceeded => write!(f, "depth limit exceeded"), #[cfg(feature = "serde_json")] Error::Json(e) => write!(f, "{e}"), @@ -167,6 +196,9 @@ impl From for () { #[allow(dead_code)] type Result = core::result::Result; +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl ErrorType for Limited { type Error = Error; } + /// Name defines types that assign a static name to their value, such as the /// name given to an identifier in an XDR enum, or the name given to the case in /// a union. @@ -200,7 +232,7 @@ where /// `Limits` contains the limits that a limited reader or writer will be /// constrained to. -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] #[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct Limits { /// Defines the maximum depth for recursive calls in `Read/WriteXdr` to @@ -217,7 +249,7 @@ pub struct Limits { pub len: usize, } -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] impl Limits { #[must_use] pub fn none() -> Self { @@ -248,13 +280,13 @@ impl Limits { /// /// Intended for use with readers and writers and limiting their reads and /// writes. -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] pub struct Limited { pub inner: L, pub(crate) limits: Limits, } -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] impl Limited { /// Constructs a new `Limited`. /// @@ -307,6 +339,15 @@ impl Read for Limited { } } + +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl Read for Limited { + /// Forwards the read operation to the wrapped object. + fn read(&mut self, buf: &mut [u8]) -> core::result::Result { + self.inner.read(buf).map_err(|e| Error::Io(e.kind())) + } +} + #[cfg(feature = "std")] impl BufRead for Limited { /// Forwards the read operation to the wrapped object. @@ -333,6 +374,18 @@ impl Write for Limited { } } +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl Write for Limited { + /// Forwards the write operation to the wrapped object. + fn write(&mut self, buf: &[u8]) -> core::result::Result { + self.inner.write(buf).map_err(|e| Error::Io(e.kind())) + } + + fn flush(&mut self) -> core::result::Result<(), Self::Error> { + self.inner.flush().map_err(|e| Error::Io(e.kind())) + } +} + #[cfg(feature = "std")] pub struct ReadXdrIter { reader: Limited>, @@ -406,7 +459,7 @@ where /// /// Use [`ReadXdR: Read_xdr_to_end`] when the intent is for all bytes in the /// read implementation to be consumed by the read. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result; /// Construct the type from the XDR bytes base64 encoded. @@ -441,7 +494,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr_to_end(r: &mut Limited) -> Result { let s = Self::read_xdr(r)?; // Check that any further reads, such as this read of one byte, read no @@ -481,7 +534,7 @@ where /// /// Use [`ReadXdR: Read_xdr_into_to_end`] when the intent is for all bytes /// in the read implementation to be consumed by the read. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr_into(&mut self, r: &mut Limited) -> Result<()> { *self = Self::read_xdr(r)?; Ok(()) @@ -505,7 +558,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr_into_to_end(&mut self, r: &mut Limited) -> Result<()> { Self::read_xdr_into(self, r)?; // Check that any further reads, such as this read of one byte, read no @@ -554,7 +607,7 @@ where /// /// An error is returned if the bytes are not completely consumed by the /// deserialization. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn from_xdr(bytes: impl AsRef<[u8]>, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(&mut cursor)?; @@ -578,10 +631,10 @@ where } pub trait WriteXdr { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()>; - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn to_xdr(&self, limits: Limits) -> Result> { let mut cursor = Limited::new(Cursor::new(vec![]), limits); self.write_xdr(&mut cursor)?; @@ -603,13 +656,13 @@ pub trait WriteXdr { /// `Pad_len` returns the number of bytes to pad an XDR value of the given /// length to make the final serialized size a multiple of 4. -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] fn pad_len(len: usize) -> usize { (4 - (len % 4)) % 4 } impl ReadXdr for i32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -621,7 +674,7 @@ impl ReadXdr for i32 { } impl WriteXdr for i32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -632,7 +685,7 @@ impl WriteXdr for i32 { } impl ReadXdr for u32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -644,7 +697,7 @@ impl ReadXdr for u32 { } impl WriteXdr for u32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -655,7 +708,7 @@ impl WriteXdr for u32 { } impl ReadXdr for i64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -667,7 +720,7 @@ impl ReadXdr for i64 { } impl WriteXdr for i64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -678,7 +731,7 @@ impl WriteXdr for i64 { } impl ReadXdr for u64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -690,7 +743,7 @@ impl ReadXdr for u64 { } impl WriteXdr for u64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -701,35 +754,35 @@ impl WriteXdr for u64 { } impl ReadXdr for f32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for f64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for bool { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -740,7 +793,7 @@ impl ReadXdr for bool { } impl WriteXdr for bool { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i = u32::from(*self); // true = 1, false = 0 @@ -750,7 +803,7 @@ impl WriteXdr for bool { } impl ReadXdr for Option { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -767,7 +820,7 @@ impl ReadXdr for Option { } impl WriteXdr for Option { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { if let Some(t) = self { @@ -782,35 +835,35 @@ impl WriteXdr for Option { } impl ReadXdr for Box { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| Ok(Box::new(T::read_xdr(r)?))) } } impl WriteXdr for Box { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| T::write_xdr(self, w)) } } impl ReadXdr for () { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(_r: &mut Limited) -> Result { Ok(()) } } impl WriteXdr for () { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { Ok(()) } } impl ReadXdr for [u8; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { r.consume_len(N)?; @@ -829,7 +882,7 @@ impl ReadXdr for [u8; N] { } impl WriteXdr for [u8; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { w.consume_len(N)?; @@ -843,7 +896,7 @@ impl WriteXdr for [u8; N] { } impl ReadXdr for [T; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let mut vec = Vec::with_capacity(N); @@ -858,7 +911,7 @@ impl ReadXdr for [T; N] { } impl WriteXdr for [T; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { for t in self { @@ -1217,7 +1270,7 @@ impl<'a, const MAX: u32> TryFrom<&'a VecM> for &'a str { } impl ReadXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1244,7 +1297,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1264,7 +1317,7 @@ impl WriteXdr for VecM { } impl ReadXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len = u32::read_xdr(r)?; @@ -1284,7 +1337,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1657,7 +1710,7 @@ impl<'a, const MAX: u32> TryFrom<&'a BytesM> for &'a str { } impl ReadXdr for BytesM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1684,7 +1737,7 @@ impl ReadXdr for BytesM { } impl WriteXdr for BytesM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2060,7 +2113,7 @@ impl<'a, const MAX: u32> TryFrom<&'a StringM> for &'a str { } impl ReadXdr for StringM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -2087,7 +2140,7 @@ impl ReadXdr for StringM { } impl WriteXdr for StringM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2133,7 +2186,7 @@ impl ReadXdr for Frame where T: ReadXdr, { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { // Read the frame header value that contains 1 flag-bit and a 33-bit length. // - The 1 flag bit is 0 when there are more frames for the same record. @@ -2153,10 +2206,8 @@ where } } -#[cfg(all(test, feature = "std"))] +#[cfg(all(test, feature = "alloc"))] mod tests { - use std::io::Cursor; - use super::*; #[test] @@ -2265,7 +2316,7 @@ mod tests { } } -#[cfg(all(test, feature = "std"))] +#[cfg(all(test, feature = "alloc"))] mod test { use super::*; @@ -2808,7 +2859,7 @@ pub struct HasOptions { } impl ReadXdr for HasOptions { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { Ok(Self{ @@ -2821,7 +2872,7 @@ third_option: Option::::read_xdr(r)?, } impl WriteXdr for HasOptions { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { self.first_option.write_xdr(w)?; @@ -2920,7 +2971,7 @@ TypeVariant::HasOptions, ]; pub const VARIANTS_STR: [&'static str; 2] = [ "Arr", "HasOptions", ]; - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] #[allow(clippy::too_many_lines)] pub fn read_xdr(v: TypeVariant, r: &mut Limited) -> Result { match v { @@ -2936,7 +2987,7 @@ TypeVariant::HasOptions => r.with_limited_depth(|r| Ok(Self::HasOptions(Box::new Ok(t) } - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] pub fn read_xdr_to_end(v: TypeVariant, r: &mut Limited) -> Result { let s = Self::read_xdr(v, r)?; // Check that any further reads, such as this read of one byte, read no @@ -2983,7 +3034,7 @@ TypeVariant::HasOptions => Box::new(ReadXdrIter::<_, HasOptions>::new(dec, r.lim } } - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] pub fn from_xdr>(v: TypeVariant, bytes: B, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(v, &mut cursor)?; @@ -3072,7 +3123,7 @@ Self::HasOptions(_) => TypeVariant::HasOptions, } impl WriteXdr for Type { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] #[allow(clippy::too_many_lines)] fn write_xdr(&self, w: &mut Limited) -> Result<()> { match self { diff --git a/spec/output/generator_spec_rust_custom_str_impls/struct.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_str_impls/struct.x/MyXDR.rs index 882f72e13..932215fdf 100644 --- a/spec/output/generator_spec_rust_custom_str_impls/struct.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_str_impls/struct.x/MyXDR.rs @@ -35,6 +35,7 @@ use alloc::{ borrow::ToOwned, boxed::Box, string::{FromUtf8Error, String}, + vec, vec::Vec, }; #[cfg(feature = "std")] @@ -43,14 +44,17 @@ use std::string::FromUtf8Error; #[cfg(feature = "arbitrary")] use arbitrary::Arbitrary; -// TODO: Add support for read/write xdr fns when std not available. - #[cfg(feature = "std")] use std::{ error, io, io::{BufRead, BufReader, Cursor, Read, Write}, }; +#[cfg(all(not(feature = "std"), feature = "alloc"))] +use embedded_io::{Error as _, ErrorType, Read, Write}; +#[cfg(all(not(feature = "std"), feature = "alloc"))] +use embedded_io_cursor::Cursor; + /// Error contains all errors returned by functions in this crate. It can be /// compared via `PartialEq`, however any contained IO errors will only be /// compared on their `ErrorKind`. @@ -66,6 +70,8 @@ pub enum Error { InvalidHex, #[cfg(feature = "std")] Io(io::Error), + #[cfg(all(not(feature = "std"), feature = "alloc"))] + Io(embedded_io::ErrorKind), DepthLimitExceeded, #[cfg(feature = "serde_json")] Json(serde_json::Error), @@ -82,13 +88,34 @@ impl PartialEq for Error { // case for comparing errors outputted by the XDR library is for // error case testing, and a lack of the ability to compare has a // detrimental affect on failure testing, so this is a tradeoff. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] (Self::Io(l), Self::Io(r)) => l.kind() == r.kind(), _ => core::mem::discriminant(self) == core::mem::discriminant(other), } } } + +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl embedded_io::Error for Error { + fn kind(&self) -> embedded_io::ErrorKind { + match self { + Self::Io(e) => *e, + _ => embedded_io::ErrorKind::Other, + } + } +} + +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl From> for Error { + fn from(value: embedded_io::ReadExactError) -> Self { + match value { + embedded_io::ReadExactError::UnexpectedEof => Error::Io(embedded_io::ErrorKind::Other), + embedded_io::ReadExactError::Other(e) => e + } + } +} + #[cfg(feature = "std")] impl error::Error for Error { #[must_use] @@ -115,6 +142,8 @@ impl fmt::Display for Error { Error::InvalidHex => write!(f, "hex invalid"), #[cfg(feature = "std")] Error::Io(e) => write!(f, "{e}"), + #[cfg(all(not(feature = "std"), feature = "alloc"))] + Error::Io(_) => write!(f, "io error"), Error::DepthLimitExceeded => write!(f, "depth limit exceeded"), #[cfg(feature = "serde_json")] Error::Json(e) => write!(f, "{e}"), @@ -167,6 +196,9 @@ impl From for () { #[allow(dead_code)] type Result = core::result::Result; +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl ErrorType for Limited { type Error = Error; } + /// Name defines types that assign a static name to their value, such as the /// name given to an identifier in an XDR enum, or the name given to the case in /// a union. @@ -200,7 +232,7 @@ where /// `Limits` contains the limits that a limited reader or writer will be /// constrained to. -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] #[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct Limits { /// Defines the maximum depth for recursive calls in `Read/WriteXdr` to @@ -217,7 +249,7 @@ pub struct Limits { pub len: usize, } -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] impl Limits { #[must_use] pub fn none() -> Self { @@ -248,13 +280,13 @@ impl Limits { /// /// Intended for use with readers and writers and limiting their reads and /// writes. -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] pub struct Limited { pub inner: L, pub(crate) limits: Limits, } -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] impl Limited { /// Constructs a new `Limited`. /// @@ -307,6 +339,15 @@ impl Read for Limited { } } + +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl Read for Limited { + /// Forwards the read operation to the wrapped object. + fn read(&mut self, buf: &mut [u8]) -> core::result::Result { + self.inner.read(buf).map_err(|e| Error::Io(e.kind())) + } +} + #[cfg(feature = "std")] impl BufRead for Limited { /// Forwards the read operation to the wrapped object. @@ -333,6 +374,18 @@ impl Write for Limited { } } +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl Write for Limited { + /// Forwards the write operation to the wrapped object. + fn write(&mut self, buf: &[u8]) -> core::result::Result { + self.inner.write(buf).map_err(|e| Error::Io(e.kind())) + } + + fn flush(&mut self) -> core::result::Result<(), Self::Error> { + self.inner.flush().map_err(|e| Error::Io(e.kind())) + } +} + #[cfg(feature = "std")] pub struct ReadXdrIter { reader: Limited>, @@ -406,7 +459,7 @@ where /// /// Use [`ReadXdR: Read_xdr_to_end`] when the intent is for all bytes in the /// read implementation to be consumed by the read. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result; /// Construct the type from the XDR bytes base64 encoded. @@ -441,7 +494,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr_to_end(r: &mut Limited) -> Result { let s = Self::read_xdr(r)?; // Check that any further reads, such as this read of one byte, read no @@ -481,7 +534,7 @@ where /// /// Use [`ReadXdR: Read_xdr_into_to_end`] when the intent is for all bytes /// in the read implementation to be consumed by the read. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr_into(&mut self, r: &mut Limited) -> Result<()> { *self = Self::read_xdr(r)?; Ok(()) @@ -505,7 +558,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr_into_to_end(&mut self, r: &mut Limited) -> Result<()> { Self::read_xdr_into(self, r)?; // Check that any further reads, such as this read of one byte, read no @@ -554,7 +607,7 @@ where /// /// An error is returned if the bytes are not completely consumed by the /// deserialization. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn from_xdr(bytes: impl AsRef<[u8]>, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(&mut cursor)?; @@ -578,10 +631,10 @@ where } pub trait WriteXdr { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()>; - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn to_xdr(&self, limits: Limits) -> Result> { let mut cursor = Limited::new(Cursor::new(vec![]), limits); self.write_xdr(&mut cursor)?; @@ -603,13 +656,13 @@ pub trait WriteXdr { /// `Pad_len` returns the number of bytes to pad an XDR value of the given /// length to make the final serialized size a multiple of 4. -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] fn pad_len(len: usize) -> usize { (4 - (len % 4)) % 4 } impl ReadXdr for i32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -621,7 +674,7 @@ impl ReadXdr for i32 { } impl WriteXdr for i32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -632,7 +685,7 @@ impl WriteXdr for i32 { } impl ReadXdr for u32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -644,7 +697,7 @@ impl ReadXdr for u32 { } impl WriteXdr for u32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -655,7 +708,7 @@ impl WriteXdr for u32 { } impl ReadXdr for i64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -667,7 +720,7 @@ impl ReadXdr for i64 { } impl WriteXdr for i64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -678,7 +731,7 @@ impl WriteXdr for i64 { } impl ReadXdr for u64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -690,7 +743,7 @@ impl ReadXdr for u64 { } impl WriteXdr for u64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -701,35 +754,35 @@ impl WriteXdr for u64 { } impl ReadXdr for f32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for f64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for bool { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -740,7 +793,7 @@ impl ReadXdr for bool { } impl WriteXdr for bool { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i = u32::from(*self); // true = 1, false = 0 @@ -750,7 +803,7 @@ impl WriteXdr for bool { } impl ReadXdr for Option { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -767,7 +820,7 @@ impl ReadXdr for Option { } impl WriteXdr for Option { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { if let Some(t) = self { @@ -782,35 +835,35 @@ impl WriteXdr for Option { } impl ReadXdr for Box { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| Ok(Box::new(T::read_xdr(r)?))) } } impl WriteXdr for Box { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| T::write_xdr(self, w)) } } impl ReadXdr for () { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(_r: &mut Limited) -> Result { Ok(()) } } impl WriteXdr for () { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { Ok(()) } } impl ReadXdr for [u8; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { r.consume_len(N)?; @@ -829,7 +882,7 @@ impl ReadXdr for [u8; N] { } impl WriteXdr for [u8; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { w.consume_len(N)?; @@ -843,7 +896,7 @@ impl WriteXdr for [u8; N] { } impl ReadXdr for [T; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let mut vec = Vec::with_capacity(N); @@ -858,7 +911,7 @@ impl ReadXdr for [T; N] { } impl WriteXdr for [T; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { for t in self { @@ -1217,7 +1270,7 @@ impl<'a, const MAX: u32> TryFrom<&'a VecM> for &'a str { } impl ReadXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1244,7 +1297,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1264,7 +1317,7 @@ impl WriteXdr for VecM { } impl ReadXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len = u32::read_xdr(r)?; @@ -1284,7 +1337,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1657,7 +1710,7 @@ impl<'a, const MAX: u32> TryFrom<&'a BytesM> for &'a str { } impl ReadXdr for BytesM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1684,7 +1737,7 @@ impl ReadXdr for BytesM { } impl WriteXdr for BytesM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2060,7 +2113,7 @@ impl<'a, const MAX: u32> TryFrom<&'a StringM> for &'a str { } impl ReadXdr for StringM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -2087,7 +2140,7 @@ impl ReadXdr for StringM { } impl WriteXdr for StringM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2133,7 +2186,7 @@ impl ReadXdr for Frame where T: ReadXdr, { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { // Read the frame header value that contains 1 flag-bit and a 33-bit length. // - The 1 flag bit is 0 when there are more frames for the same record. @@ -2153,10 +2206,8 @@ where } } -#[cfg(all(test, feature = "std"))] +#[cfg(all(test, feature = "alloc"))] mod tests { - use std::io::Cursor; - use super::*; #[test] @@ -2265,7 +2316,7 @@ mod tests { } } -#[cfg(all(test, feature = "std"))] +#[cfg(all(test, feature = "alloc"))] mod test { use super::*; @@ -2812,7 +2863,7 @@ pub struct MyStruct { } impl ReadXdr for MyStruct { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { Ok(Self{ @@ -2827,7 +2878,7 @@ max_string: StringM::<100>::read_xdr(r)?, } impl WriteXdr for MyStruct { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { self.some_int.write_xdr(w)?; @@ -2928,7 +2979,7 @@ TypeVariant::MyStruct, ]; pub const VARIANTS_STR: [&'static str; 2] = [ "Int64", "MyStruct", ]; - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] #[allow(clippy::too_many_lines)] pub fn read_xdr(v: TypeVariant, r: &mut Limited) -> Result { match v { @@ -2944,7 +2995,7 @@ TypeVariant::MyStruct => r.with_limited_depth(|r| Ok(Self::MyStruct(Box::new(MyS Ok(t) } - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] pub fn read_xdr_to_end(v: TypeVariant, r: &mut Limited) -> Result { let s = Self::read_xdr(v, r)?; // Check that any further reads, such as this read of one byte, read no @@ -2991,7 +3042,7 @@ TypeVariant::MyStruct => Box::new(ReadXdrIter::<_, MyStruct>::new(dec, r.limits. } } - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] pub fn from_xdr>(v: TypeVariant, bytes: B, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(v, &mut cursor)?; @@ -3080,7 +3131,7 @@ Self::MyStruct(_) => TypeVariant::MyStruct, } impl WriteXdr for Type { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] #[allow(clippy::too_many_lines)] fn write_xdr(&self, w: &mut Limited) -> Result<()> { match self { diff --git a/spec/output/generator_spec_rust_custom_str_impls/test.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_str_impls/test.x/MyXDR.rs index 52d6e3d11..69abdac69 100644 --- a/spec/output/generator_spec_rust_custom_str_impls/test.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_str_impls/test.x/MyXDR.rs @@ -35,6 +35,7 @@ use alloc::{ borrow::ToOwned, boxed::Box, string::{FromUtf8Error, String}, + vec, vec::Vec, }; #[cfg(feature = "std")] @@ -43,14 +44,17 @@ use std::string::FromUtf8Error; #[cfg(feature = "arbitrary")] use arbitrary::Arbitrary; -// TODO: Add support for read/write xdr fns when std not available. - #[cfg(feature = "std")] use std::{ error, io, io::{BufRead, BufReader, Cursor, Read, Write}, }; +#[cfg(all(not(feature = "std"), feature = "alloc"))] +use embedded_io::{Error as _, ErrorType, Read, Write}; +#[cfg(all(not(feature = "std"), feature = "alloc"))] +use embedded_io_cursor::Cursor; + /// Error contains all errors returned by functions in this crate. It can be /// compared via `PartialEq`, however any contained IO errors will only be /// compared on their `ErrorKind`. @@ -66,6 +70,8 @@ pub enum Error { InvalidHex, #[cfg(feature = "std")] Io(io::Error), + #[cfg(all(not(feature = "std"), feature = "alloc"))] + Io(embedded_io::ErrorKind), DepthLimitExceeded, #[cfg(feature = "serde_json")] Json(serde_json::Error), @@ -82,13 +88,34 @@ impl PartialEq for Error { // case for comparing errors outputted by the XDR library is for // error case testing, and a lack of the ability to compare has a // detrimental affect on failure testing, so this is a tradeoff. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] (Self::Io(l), Self::Io(r)) => l.kind() == r.kind(), _ => core::mem::discriminant(self) == core::mem::discriminant(other), } } } + +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl embedded_io::Error for Error { + fn kind(&self) -> embedded_io::ErrorKind { + match self { + Self::Io(e) => *e, + _ => embedded_io::ErrorKind::Other, + } + } +} + +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl From> for Error { + fn from(value: embedded_io::ReadExactError) -> Self { + match value { + embedded_io::ReadExactError::UnexpectedEof => Error::Io(embedded_io::ErrorKind::Other), + embedded_io::ReadExactError::Other(e) => e + } + } +} + #[cfg(feature = "std")] impl error::Error for Error { #[must_use] @@ -115,6 +142,8 @@ impl fmt::Display for Error { Error::InvalidHex => write!(f, "hex invalid"), #[cfg(feature = "std")] Error::Io(e) => write!(f, "{e}"), + #[cfg(all(not(feature = "std"), feature = "alloc"))] + Error::Io(_) => write!(f, "io error"), Error::DepthLimitExceeded => write!(f, "depth limit exceeded"), #[cfg(feature = "serde_json")] Error::Json(e) => write!(f, "{e}"), @@ -167,6 +196,9 @@ impl From for () { #[allow(dead_code)] type Result = core::result::Result; +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl ErrorType for Limited { type Error = Error; } + /// Name defines types that assign a static name to their value, such as the /// name given to an identifier in an XDR enum, or the name given to the case in /// a union. @@ -200,7 +232,7 @@ where /// `Limits` contains the limits that a limited reader or writer will be /// constrained to. -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] #[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct Limits { /// Defines the maximum depth for recursive calls in `Read/WriteXdr` to @@ -217,7 +249,7 @@ pub struct Limits { pub len: usize, } -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] impl Limits { #[must_use] pub fn none() -> Self { @@ -248,13 +280,13 @@ impl Limits { /// /// Intended for use with readers and writers and limiting their reads and /// writes. -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] pub struct Limited { pub inner: L, pub(crate) limits: Limits, } -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] impl Limited { /// Constructs a new `Limited`. /// @@ -307,6 +339,15 @@ impl Read for Limited { } } + +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl Read for Limited { + /// Forwards the read operation to the wrapped object. + fn read(&mut self, buf: &mut [u8]) -> core::result::Result { + self.inner.read(buf).map_err(|e| Error::Io(e.kind())) + } +} + #[cfg(feature = "std")] impl BufRead for Limited { /// Forwards the read operation to the wrapped object. @@ -333,6 +374,18 @@ impl Write for Limited { } } +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl Write for Limited { + /// Forwards the write operation to the wrapped object. + fn write(&mut self, buf: &[u8]) -> core::result::Result { + self.inner.write(buf).map_err(|e| Error::Io(e.kind())) + } + + fn flush(&mut self) -> core::result::Result<(), Self::Error> { + self.inner.flush().map_err(|e| Error::Io(e.kind())) + } +} + #[cfg(feature = "std")] pub struct ReadXdrIter { reader: Limited>, @@ -406,7 +459,7 @@ where /// /// Use [`ReadXdR: Read_xdr_to_end`] when the intent is for all bytes in the /// read implementation to be consumed by the read. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result; /// Construct the type from the XDR bytes base64 encoded. @@ -441,7 +494,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr_to_end(r: &mut Limited) -> Result { let s = Self::read_xdr(r)?; // Check that any further reads, such as this read of one byte, read no @@ -481,7 +534,7 @@ where /// /// Use [`ReadXdR: Read_xdr_into_to_end`] when the intent is for all bytes /// in the read implementation to be consumed by the read. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr_into(&mut self, r: &mut Limited) -> Result<()> { *self = Self::read_xdr(r)?; Ok(()) @@ -505,7 +558,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr_into_to_end(&mut self, r: &mut Limited) -> Result<()> { Self::read_xdr_into(self, r)?; // Check that any further reads, such as this read of one byte, read no @@ -554,7 +607,7 @@ where /// /// An error is returned if the bytes are not completely consumed by the /// deserialization. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn from_xdr(bytes: impl AsRef<[u8]>, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(&mut cursor)?; @@ -578,10 +631,10 @@ where } pub trait WriteXdr { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()>; - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn to_xdr(&self, limits: Limits) -> Result> { let mut cursor = Limited::new(Cursor::new(vec![]), limits); self.write_xdr(&mut cursor)?; @@ -603,13 +656,13 @@ pub trait WriteXdr { /// `Pad_len` returns the number of bytes to pad an XDR value of the given /// length to make the final serialized size a multiple of 4. -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] fn pad_len(len: usize) -> usize { (4 - (len % 4)) % 4 } impl ReadXdr for i32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -621,7 +674,7 @@ impl ReadXdr for i32 { } impl WriteXdr for i32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -632,7 +685,7 @@ impl WriteXdr for i32 { } impl ReadXdr for u32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -644,7 +697,7 @@ impl ReadXdr for u32 { } impl WriteXdr for u32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -655,7 +708,7 @@ impl WriteXdr for u32 { } impl ReadXdr for i64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -667,7 +720,7 @@ impl ReadXdr for i64 { } impl WriteXdr for i64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -678,7 +731,7 @@ impl WriteXdr for i64 { } impl ReadXdr for u64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -690,7 +743,7 @@ impl ReadXdr for u64 { } impl WriteXdr for u64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -701,35 +754,35 @@ impl WriteXdr for u64 { } impl ReadXdr for f32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for f64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for bool { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -740,7 +793,7 @@ impl ReadXdr for bool { } impl WriteXdr for bool { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i = u32::from(*self); // true = 1, false = 0 @@ -750,7 +803,7 @@ impl WriteXdr for bool { } impl ReadXdr for Option { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -767,7 +820,7 @@ impl ReadXdr for Option { } impl WriteXdr for Option { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { if let Some(t) = self { @@ -782,35 +835,35 @@ impl WriteXdr for Option { } impl ReadXdr for Box { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| Ok(Box::new(T::read_xdr(r)?))) } } impl WriteXdr for Box { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| T::write_xdr(self, w)) } } impl ReadXdr for () { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(_r: &mut Limited) -> Result { Ok(()) } } impl WriteXdr for () { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { Ok(()) } } impl ReadXdr for [u8; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { r.consume_len(N)?; @@ -829,7 +882,7 @@ impl ReadXdr for [u8; N] { } impl WriteXdr for [u8; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { w.consume_len(N)?; @@ -843,7 +896,7 @@ impl WriteXdr for [u8; N] { } impl ReadXdr for [T; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let mut vec = Vec::with_capacity(N); @@ -858,7 +911,7 @@ impl ReadXdr for [T; N] { } impl WriteXdr for [T; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { for t in self { @@ -1217,7 +1270,7 @@ impl<'a, const MAX: u32> TryFrom<&'a VecM> for &'a str { } impl ReadXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1244,7 +1297,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1264,7 +1317,7 @@ impl WriteXdr for VecM { } impl ReadXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len = u32::read_xdr(r)?; @@ -1284,7 +1337,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1657,7 +1710,7 @@ impl<'a, const MAX: u32> TryFrom<&'a BytesM> for &'a str { } impl ReadXdr for BytesM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1684,7 +1737,7 @@ impl ReadXdr for BytesM { } impl WriteXdr for BytesM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2060,7 +2113,7 @@ impl<'a, const MAX: u32> TryFrom<&'a StringM> for &'a str { } impl ReadXdr for StringM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -2087,7 +2140,7 @@ impl ReadXdr for StringM { } impl WriteXdr for StringM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2133,7 +2186,7 @@ impl ReadXdr for Frame where T: ReadXdr, { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { // Read the frame header value that contains 1 flag-bit and a 33-bit length. // - The 1 flag bit is 0 when there are more frames for the same record. @@ -2153,10 +2206,8 @@ where } } -#[cfg(all(test, feature = "std"))] +#[cfg(all(test, feature = "alloc"))] mod tests { - use std::io::Cursor; - use super::*; #[test] @@ -2265,7 +2316,7 @@ mod tests { } } -#[cfg(all(test, feature = "std"))] +#[cfg(all(test, feature = "alloc"))] mod test { use super::*; @@ -2872,7 +2923,7 @@ impl AsRef<[u8; 64]> for Uint512 { } impl ReadXdr for Uint512 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = <[u8; 64]>::read_xdr(r)?; @@ -2883,7 +2934,7 @@ impl ReadXdr for Uint512 { } impl WriteXdr for Uint512 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w|{ self.0.write_xdr(w) }) } @@ -2962,7 +3013,7 @@ impl AsRef> for Uint513 { } impl ReadXdr for Uint513 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = BytesM::<64>::read_xdr(r)?; @@ -2973,7 +3024,7 @@ impl ReadXdr for Uint513 { } impl WriteXdr for Uint513 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w|{ self.0.write_xdr(w) }) } @@ -3064,7 +3115,7 @@ impl AsRef for Uint514 { } impl ReadXdr for Uint514 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = BytesM::read_xdr(r)?; @@ -3075,7 +3126,7 @@ impl ReadXdr for Uint514 { } impl WriteXdr for Uint514 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w|{ self.0.write_xdr(w) }) } @@ -3166,7 +3217,7 @@ impl AsRef> for Str { } impl ReadXdr for Str { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = StringM::<64>::read_xdr(r)?; @@ -3177,7 +3228,7 @@ impl ReadXdr for Str { } impl WriteXdr for Str { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w|{ self.0.write_xdr(w) }) } @@ -3268,7 +3319,7 @@ impl AsRef for Str2 { } impl ReadXdr for Str2 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = StringM::read_xdr(r)?; @@ -3279,7 +3330,7 @@ impl ReadXdr for Str2 { } impl WriteXdr for Str2 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w|{ self.0.write_xdr(w) }) } @@ -3428,7 +3479,7 @@ impl AsRef<[u8; 32]> for Hash { } impl ReadXdr for Hash { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = <[u8; 32]>::read_xdr(r)?; @@ -3439,7 +3490,7 @@ impl ReadXdr for Hash { } impl WriteXdr for Hash { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w|{ self.0.write_xdr(w) }) } @@ -3517,7 +3568,7 @@ impl AsRef<[Hash; 12]> for Hashes1 { } impl ReadXdr for Hashes1 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = <[Hash; 12]>::read_xdr(r)?; @@ -3528,7 +3579,7 @@ impl ReadXdr for Hashes1 { } impl WriteXdr for Hashes1 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w|{ self.0.write_xdr(w) }) } @@ -3607,7 +3658,7 @@ impl AsRef> for Hashes2 { } impl ReadXdr for Hashes2 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = VecM::::read_xdr(r)?; @@ -3618,7 +3669,7 @@ impl ReadXdr for Hashes2 { } impl WriteXdr for Hashes2 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w|{ self.0.write_xdr(w) }) } @@ -3709,7 +3760,7 @@ impl AsRef> for Hashes3 { } impl ReadXdr for Hashes3 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = VecM::::read_xdr(r)?; @@ -3720,7 +3771,7 @@ impl ReadXdr for Hashes3 { } impl WriteXdr for Hashes3 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w|{ self.0.write_xdr(w) }) } @@ -3810,7 +3861,7 @@ impl AsRef> for OptHash1 { } impl ReadXdr for OptHash1 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = Option::::read_xdr(r)?; @@ -3821,7 +3872,7 @@ impl ReadXdr for OptHash1 { } impl WriteXdr for OptHash1 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w|{ self.0.write_xdr(w) }) } @@ -3862,7 +3913,7 @@ impl AsRef> for OptHash2 { } impl ReadXdr for OptHash2 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = Option::::read_xdr(r)?; @@ -3873,7 +3924,7 @@ impl ReadXdr for OptHash2 { } impl WriteXdr for OptHash2 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w|{ self.0.write_xdr(w) }) } @@ -3941,7 +3992,7 @@ pub struct MyStruct { } impl ReadXdr for MyStruct { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { Ok(Self{ @@ -3958,7 +4009,7 @@ field7: bool::read_xdr(r)?, } impl WriteXdr for MyStruct { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { self.field1.write_xdr(w)?; @@ -3991,7 +4042,7 @@ pub struct LotsOfMyStructs { } impl ReadXdr for LotsOfMyStructs { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { Ok(Self{ @@ -4002,7 +4053,7 @@ impl ReadXdr for LotsOfMyStructs { } impl WriteXdr for LotsOfMyStructs { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { self.members.write_xdr(w)?; @@ -4029,7 +4080,7 @@ pub struct HasStuff { } impl ReadXdr for HasStuff { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { Ok(Self{ @@ -4040,7 +4091,7 @@ impl ReadXdr for HasStuff { } impl WriteXdr for HasStuff { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { self.data.write_xdr(w)?; @@ -4138,7 +4189,7 @@ Self::Green => "Green", } impl ReadXdr for Color { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let e = i32::read_xdr(r)?; @@ -4149,7 +4200,7 @@ Self::Green => "Green", } impl WriteXdr for Color { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i: i32 = (*self).into(); @@ -4257,7 +4308,7 @@ Self::B2 => "B2", } impl ReadXdr for NesterNestedEnum { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let e = i32::read_xdr(r)?; @@ -4268,7 +4319,7 @@ Self::B2 => "B2", } impl WriteXdr for NesterNestedEnum { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i: i32 = (*self).into(); @@ -4294,7 +4345,7 @@ pub struct NesterNestedStruct { } impl ReadXdr for NesterNestedStruct { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { Ok(Self{ @@ -4305,7 +4356,7 @@ impl ReadXdr for NesterNestedStruct { } impl WriteXdr for NesterNestedStruct { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { self.blah.write_xdr(w)?; @@ -4387,7 +4438,7 @@ impl Variants for NesterNestedUnion { impl Union for NesterNestedUnion {} impl ReadXdr for NesterNestedUnion { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let dv: Color = ::read_xdr(r)?; @@ -4403,7 +4454,7 @@ impl ReadXdr for NesterNestedUnion { } impl WriteXdr for NesterNestedUnion { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { self.discriminant().write_xdr(w)?; @@ -4452,7 +4503,7 @@ pub struct Nester { } impl ReadXdr for Nester { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { Ok(Self{ @@ -4465,7 +4516,7 @@ nested_union: NesterNestedUnion::read_xdr(r)?, } impl WriteXdr for Nester { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { self.nested_enum.write_xdr(w)?; @@ -4753,7 +4804,7 @@ TypeVariant::NesterNestedUnion, ]; "NesterNestedStruct", "NesterNestedUnion", ]; - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] #[allow(clippy::too_many_lines)] pub fn read_xdr(v: TypeVariant, r: &mut Limited) -> Result { match v { @@ -4790,7 +4841,7 @@ TypeVariant::NesterNestedUnion => r.with_limited_depth(|r| Ok(Self::NesterNested Ok(t) } - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] pub fn read_xdr_to_end(v: TypeVariant, r: &mut Limited) -> Result { let s = Self::read_xdr(v, r)?; // Check that any further reads, such as this read of one byte, read no @@ -4900,7 +4951,7 @@ TypeVariant::NesterNestedUnion => Box::new(ReadXdrIter::<_, NesterNestedUnion>:: } } - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] pub fn from_xdr>(v: TypeVariant, bytes: B, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(v, &mut cursor)?; @@ -5094,7 +5145,7 @@ Self::NesterNestedUnion(_) => TypeVariant::NesterNestedUnion, } impl WriteXdr for Type { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] #[allow(clippy::too_many_lines)] fn write_xdr(&self, w: &mut Limited) -> Result<()> { match self { diff --git a/spec/output/generator_spec_rust_custom_str_impls/union.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_str_impls/union.x/MyXDR.rs index 946a36cc9..3ac492b1c 100644 --- a/spec/output/generator_spec_rust_custom_str_impls/union.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_str_impls/union.x/MyXDR.rs @@ -35,6 +35,7 @@ use alloc::{ borrow::ToOwned, boxed::Box, string::{FromUtf8Error, String}, + vec, vec::Vec, }; #[cfg(feature = "std")] @@ -43,14 +44,17 @@ use std::string::FromUtf8Error; #[cfg(feature = "arbitrary")] use arbitrary::Arbitrary; -// TODO: Add support for read/write xdr fns when std not available. - #[cfg(feature = "std")] use std::{ error, io, io::{BufRead, BufReader, Cursor, Read, Write}, }; +#[cfg(all(not(feature = "std"), feature = "alloc"))] +use embedded_io::{Error as _, ErrorType, Read, Write}; +#[cfg(all(not(feature = "std"), feature = "alloc"))] +use embedded_io_cursor::Cursor; + /// Error contains all errors returned by functions in this crate. It can be /// compared via `PartialEq`, however any contained IO errors will only be /// compared on their `ErrorKind`. @@ -66,6 +70,8 @@ pub enum Error { InvalidHex, #[cfg(feature = "std")] Io(io::Error), + #[cfg(all(not(feature = "std"), feature = "alloc"))] + Io(embedded_io::ErrorKind), DepthLimitExceeded, #[cfg(feature = "serde_json")] Json(serde_json::Error), @@ -82,13 +88,34 @@ impl PartialEq for Error { // case for comparing errors outputted by the XDR library is for // error case testing, and a lack of the ability to compare has a // detrimental affect on failure testing, so this is a tradeoff. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] (Self::Io(l), Self::Io(r)) => l.kind() == r.kind(), _ => core::mem::discriminant(self) == core::mem::discriminant(other), } } } + +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl embedded_io::Error for Error { + fn kind(&self) -> embedded_io::ErrorKind { + match self { + Self::Io(e) => *e, + _ => embedded_io::ErrorKind::Other, + } + } +} + +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl From> for Error { + fn from(value: embedded_io::ReadExactError) -> Self { + match value { + embedded_io::ReadExactError::UnexpectedEof => Error::Io(embedded_io::ErrorKind::Other), + embedded_io::ReadExactError::Other(e) => e + } + } +} + #[cfg(feature = "std")] impl error::Error for Error { #[must_use] @@ -115,6 +142,8 @@ impl fmt::Display for Error { Error::InvalidHex => write!(f, "hex invalid"), #[cfg(feature = "std")] Error::Io(e) => write!(f, "{e}"), + #[cfg(all(not(feature = "std"), feature = "alloc"))] + Error::Io(_) => write!(f, "io error"), Error::DepthLimitExceeded => write!(f, "depth limit exceeded"), #[cfg(feature = "serde_json")] Error::Json(e) => write!(f, "{e}"), @@ -167,6 +196,9 @@ impl From for () { #[allow(dead_code)] type Result = core::result::Result; +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl ErrorType for Limited { type Error = Error; } + /// Name defines types that assign a static name to their value, such as the /// name given to an identifier in an XDR enum, or the name given to the case in /// a union. @@ -200,7 +232,7 @@ where /// `Limits` contains the limits that a limited reader or writer will be /// constrained to. -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] #[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct Limits { /// Defines the maximum depth for recursive calls in `Read/WriteXdr` to @@ -217,7 +249,7 @@ pub struct Limits { pub len: usize, } -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] impl Limits { #[must_use] pub fn none() -> Self { @@ -248,13 +280,13 @@ impl Limits { /// /// Intended for use with readers and writers and limiting their reads and /// writes. -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] pub struct Limited { pub inner: L, pub(crate) limits: Limits, } -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] impl Limited { /// Constructs a new `Limited`. /// @@ -307,6 +339,15 @@ impl Read for Limited { } } + +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl Read for Limited { + /// Forwards the read operation to the wrapped object. + fn read(&mut self, buf: &mut [u8]) -> core::result::Result { + self.inner.read(buf).map_err(|e| Error::Io(e.kind())) + } +} + #[cfg(feature = "std")] impl BufRead for Limited { /// Forwards the read operation to the wrapped object. @@ -333,6 +374,18 @@ impl Write for Limited { } } +#[cfg(all(not(feature = "std"), feature = "alloc"))] +impl Write for Limited { + /// Forwards the write operation to the wrapped object. + fn write(&mut self, buf: &[u8]) -> core::result::Result { + self.inner.write(buf).map_err(|e| Error::Io(e.kind())) + } + + fn flush(&mut self) -> core::result::Result<(), Self::Error> { + self.inner.flush().map_err(|e| Error::Io(e.kind())) + } +} + #[cfg(feature = "std")] pub struct ReadXdrIter { reader: Limited>, @@ -406,7 +459,7 @@ where /// /// Use [`ReadXdR: Read_xdr_to_end`] when the intent is for all bytes in the /// read implementation to be consumed by the read. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result; /// Construct the type from the XDR bytes base64 encoded. @@ -441,7 +494,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr_to_end(r: &mut Limited) -> Result { let s = Self::read_xdr(r)?; // Check that any further reads, such as this read of one byte, read no @@ -481,7 +534,7 @@ where /// /// Use [`ReadXdR: Read_xdr_into_to_end`] when the intent is for all bytes /// in the read implementation to be consumed by the read. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr_into(&mut self, r: &mut Limited) -> Result<()> { *self = Self::read_xdr(r)?; Ok(()) @@ -505,7 +558,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr_into_to_end(&mut self, r: &mut Limited) -> Result<()> { Self::read_xdr_into(self, r)?; // Check that any further reads, such as this read of one byte, read no @@ -554,7 +607,7 @@ where /// /// An error is returned if the bytes are not completely consumed by the /// deserialization. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn from_xdr(bytes: impl AsRef<[u8]>, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(&mut cursor)?; @@ -578,10 +631,10 @@ where } pub trait WriteXdr { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()>; - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn to_xdr(&self, limits: Limits) -> Result> { let mut cursor = Limited::new(Cursor::new(vec![]), limits); self.write_xdr(&mut cursor)?; @@ -603,13 +656,13 @@ pub trait WriteXdr { /// `Pad_len` returns the number of bytes to pad an XDR value of the given /// length to make the final serialized size a multiple of 4. -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] fn pad_len(len: usize) -> usize { (4 - (len % 4)) % 4 } impl ReadXdr for i32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -621,7 +674,7 @@ impl ReadXdr for i32 { } impl WriteXdr for i32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -632,7 +685,7 @@ impl WriteXdr for i32 { } impl ReadXdr for u32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -644,7 +697,7 @@ impl ReadXdr for u32 { } impl WriteXdr for u32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -655,7 +708,7 @@ impl WriteXdr for u32 { } impl ReadXdr for i64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -667,7 +720,7 @@ impl ReadXdr for i64 { } impl WriteXdr for i64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -678,7 +731,7 @@ impl WriteXdr for i64 { } impl ReadXdr for u64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -690,7 +743,7 @@ impl ReadXdr for u64 { } impl WriteXdr for u64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -701,35 +754,35 @@ impl WriteXdr for u64 { } impl ReadXdr for f32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f32 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for f64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f64 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for bool { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -740,7 +793,7 @@ impl ReadXdr for bool { } impl WriteXdr for bool { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i = u32::from(*self); // true = 1, false = 0 @@ -750,7 +803,7 @@ impl WriteXdr for bool { } impl ReadXdr for Option { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -767,7 +820,7 @@ impl ReadXdr for Option { } impl WriteXdr for Option { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { if let Some(t) = self { @@ -782,35 +835,35 @@ impl WriteXdr for Option { } impl ReadXdr for Box { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| Ok(Box::new(T::read_xdr(r)?))) } } impl WriteXdr for Box { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| T::write_xdr(self, w)) } } impl ReadXdr for () { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(_r: &mut Limited) -> Result { Ok(()) } } impl WriteXdr for () { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { Ok(()) } } impl ReadXdr for [u8; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { r.consume_len(N)?; @@ -829,7 +882,7 @@ impl ReadXdr for [u8; N] { } impl WriteXdr for [u8; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { w.consume_len(N)?; @@ -843,7 +896,7 @@ impl WriteXdr for [u8; N] { } impl ReadXdr for [T; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let mut vec = Vec::with_capacity(N); @@ -858,7 +911,7 @@ impl ReadXdr for [T; N] { } impl WriteXdr for [T; N] { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { for t in self { @@ -1217,7 +1270,7 @@ impl<'a, const MAX: u32> TryFrom<&'a VecM> for &'a str { } impl ReadXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1244,7 +1297,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1264,7 +1317,7 @@ impl WriteXdr for VecM { } impl ReadXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len = u32::read_xdr(r)?; @@ -1284,7 +1337,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1657,7 +1710,7 @@ impl<'a, const MAX: u32> TryFrom<&'a BytesM> for &'a str { } impl ReadXdr for BytesM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1684,7 +1737,7 @@ impl ReadXdr for BytesM { } impl WriteXdr for BytesM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2060,7 +2113,7 @@ impl<'a, const MAX: u32> TryFrom<&'a StringM> for &'a str { } impl ReadXdr for StringM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -2087,7 +2140,7 @@ impl ReadXdr for StringM { } impl WriteXdr for StringM { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2133,7 +2186,7 @@ impl ReadXdr for Frame where T: ReadXdr, { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { // Read the frame header value that contains 1 flag-bit and a 33-bit length. // - The 1 flag bit is 0 when there are more frames for the same record. @@ -2153,10 +2206,8 @@ where } } -#[cfg(all(test, feature = "std"))] +#[cfg(all(test, feature = "alloc"))] mod tests { - use std::io::Cursor; - use super::*; #[test] @@ -2265,7 +2316,7 @@ mod tests { } } -#[cfg(all(test, feature = "std"))] +#[cfg(all(test, feature = "alloc"))] mod test { use super::*; @@ -2877,7 +2928,7 @@ Self::Multi => "Multi", } impl ReadXdr for UnionKey { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let e = i32::read_xdr(r)?; @@ -2888,7 +2939,7 @@ Self::Multi => "Multi", } impl WriteXdr for UnionKey { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i: i32 = (*self).into(); @@ -2978,7 +3029,7 @@ Self::Multi(_) => UnionKey::Multi, impl Union for MyUnion {} impl ReadXdr for MyUnion { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let dv: UnionKey = ::read_xdr(r)?; @@ -2995,7 +3046,7 @@ UnionKey::Multi => Self::Multi(VecM::::read_xdr(r)?), } impl WriteXdr for MyUnion { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { self.discriminant().write_xdr(w)?; @@ -3089,7 +3140,7 @@ Self::V1(_) => 1, impl Union for IntUnion {} impl ReadXdr for IntUnion { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let dv: i32 = ::read_xdr(r)?; @@ -3106,7 +3157,7 @@ Self::V1(_) => 1, } impl WriteXdr for IntUnion { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { self.discriminant().write_xdr(w)?; @@ -3155,7 +3206,7 @@ impl AsRef for IntUnion2 { } impl ReadXdr for IntUnion2 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = IntUnion::read_xdr(r)?; @@ -3166,7 +3217,7 @@ impl ReadXdr for IntUnion2 { } impl WriteXdr for IntUnion2 { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w|{ self.0.write_xdr(w) }) } @@ -3296,7 +3347,7 @@ TypeVariant::IntUnion2, ]; "IntUnion", "IntUnion2", ]; - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] #[allow(clippy::too_many_lines)] pub fn read_xdr(v: TypeVariant, r: &mut Limited) -> Result { match v { @@ -3316,7 +3367,7 @@ TypeVariant::IntUnion2 => r.with_limited_depth(|r| Ok(Self::IntUnion2(Box::new(I Ok(t) } - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] pub fn read_xdr_to_end(v: TypeVariant, r: &mut Limited) -> Result { let s = Self::read_xdr(v, r)?; // Check that any further reads, such as this read of one byte, read no @@ -3375,7 +3426,7 @@ TypeVariant::IntUnion2 => Box::new(ReadXdrIter::<_, IntUnion2>::new(dec, r.limit } } - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] pub fn from_xdr>(v: TypeVariant, bytes: B, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(v, &mut cursor)?; @@ -3484,7 +3535,7 @@ Self::IntUnion2(_) => TypeVariant::IntUnion2, } impl WriteXdr for Type { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] #[allow(clippy::too_many_lines)] fn write_xdr(&self, w: &mut Limited) -> Result<()> { match self { From 3bac661688af0615a7192271b79ced8cd30e9dd4 Mon Sep 17 00:00:00 2001 From: Jun Luo <4catcode@gmail.com> Date: Thu, 12 Sep 2024 14:47:55 +0800 Subject: [PATCH 2/9] Rust: add support for no_std env --- lib/xdrgen/generators/rust/src/types.rs | 20 +++++++++---------- .../block_comments.x/MyXDR.rs | 20 +++++++++---------- .../generator_spec_rust/const.x/MyXDR.rs | 20 +++++++++---------- .../generator_spec_rust/enum.x/MyXDR.rs | 20 +++++++++---------- .../generator_spec_rust/nesting.x/MyXDR.rs | 20 +++++++++---------- .../generator_spec_rust/optional.x/MyXDR.rs | 20 +++++++++---------- .../generator_spec_rust/struct.x/MyXDR.rs | 20 +++++++++---------- .../generator_spec_rust/test.x/MyXDR.rs | 20 +++++++++---------- .../generator_spec_rust/union.x/MyXDR.rs | 20 +++++++++---------- .../block_comments.x/MyXDR.rs | 20 +++++++++---------- .../const.x/MyXDR.rs | 20 +++++++++---------- .../enum.x/MyXDR.rs | 20 +++++++++---------- .../nesting.x/MyXDR.rs | 20 +++++++++---------- .../optional.x/MyXDR.rs | 20 +++++++++---------- .../struct.x/MyXDR.rs | 20 +++++++++---------- .../test.x/MyXDR.rs | 20 +++++++++---------- .../union.x/MyXDR.rs | 20 +++++++++---------- .../block_comments.x/MyXDR.rs | 20 +++++++++---------- .../const.x/MyXDR.rs | 20 +++++++++---------- .../enum.x/MyXDR.rs | 20 +++++++++---------- .../nesting.x/MyXDR.rs | 20 +++++++++---------- .../optional.x/MyXDR.rs | 20 +++++++++---------- .../struct.x/MyXDR.rs | 20 +++++++++---------- .../test.x/MyXDR.rs | 20 +++++++++---------- .../union.x/MyXDR.rs | 20 +++++++++---------- 25 files changed, 225 insertions(+), 275 deletions(-) diff --git a/lib/xdrgen/generators/rust/src/types.rs b/lib/xdrgen/generators/rust/src/types.rs index 4f70c060d..1614fba29 100644 --- a/lib/xdrgen/generators/rust/src/types.rs +++ b/lib/xdrgen/generators/rust/src/types.rs @@ -41,9 +41,7 @@ use std::{ }; #[cfg(all(not(feature = "std"), feature = "alloc"))] -use embedded_io::{Error as _, ErrorType, Read, Write}; -#[cfg(all(not(feature = "std"), feature = "alloc"))] -use embedded_io_cursor::Cursor; +use embedded_io_extras::{Cursor, Error as _, ErrorType, Read, Write}; /// Error contains all errors returned by functions in this crate. It can be /// compared via `PartialEq`, however any contained IO errors will only be @@ -61,7 +59,7 @@ pub enum Error { #[cfg(feature = "std")] Io(io::Error), #[cfg(all(not(feature = "std"), feature = "alloc"))] - Io(embedded_io::ErrorKind), + Io(embedded_io_extras::ErrorKind), DepthLimitExceeded, #[cfg(feature = "serde_json")] Json(serde_json::Error), @@ -87,21 +85,21 @@ impl PartialEq for Error { #[cfg(all(not(feature = "std"), feature = "alloc"))] -impl embedded_io::Error for Error { - fn kind(&self) -> embedded_io::ErrorKind { +impl embedded_io_extras::Error for Error { + fn kind(&self) -> embedded_io_extras::ErrorKind { match self { Self::Io(e) => *e, - _ => embedded_io::ErrorKind::Other, + _ => embedded_io_extras::ErrorKind::Other, } } } #[cfg(all(not(feature = "std"), feature = "alloc"))] -impl From> for Error { - fn from(value: embedded_io::ReadExactError) -> Self { +impl From> for Error { + fn from(value: embedded_io_extras::ReadExactError) -> Self { match value { - embedded_io::ReadExactError::UnexpectedEof => Error::Io(embedded_io::ErrorKind::Other), - embedded_io::ReadExactError::Other(e) => e + embedded_io_extras::ReadExactError::UnexpectedEof => Error::Io(embedded_io_extras::ErrorKind::Other), + embedded_io_extras::ReadExactError::Other(e) => e } } } diff --git a/spec/output/generator_spec_rust/block_comments.x/MyXDR.rs b/spec/output/generator_spec_rust/block_comments.x/MyXDR.rs index 0f509ea49..9482a1915 100644 --- a/spec/output/generator_spec_rust/block_comments.x/MyXDR.rs +++ b/spec/output/generator_spec_rust/block_comments.x/MyXDR.rs @@ -51,9 +51,7 @@ use std::{ }; #[cfg(all(not(feature = "std"), feature = "alloc"))] -use embedded_io::{Error as _, ErrorType, Read, Write}; -#[cfg(all(not(feature = "std"), feature = "alloc"))] -use embedded_io_cursor::Cursor; +use embedded_io_extras::{Cursor, Error as _, ErrorType, Read, Write}; /// Error contains all errors returned by functions in this crate. It can be /// compared via `PartialEq`, however any contained IO errors will only be @@ -71,7 +69,7 @@ pub enum Error { #[cfg(feature = "std")] Io(io::Error), #[cfg(all(not(feature = "std"), feature = "alloc"))] - Io(embedded_io::ErrorKind), + Io(embedded_io_extras::ErrorKind), DepthLimitExceeded, #[cfg(feature = "serde_json")] Json(serde_json::Error), @@ -97,21 +95,21 @@ impl PartialEq for Error { #[cfg(all(not(feature = "std"), feature = "alloc"))] -impl embedded_io::Error for Error { - fn kind(&self) -> embedded_io::ErrorKind { +impl embedded_io_extras::Error for Error { + fn kind(&self) -> embedded_io_extras::ErrorKind { match self { Self::Io(e) => *e, - _ => embedded_io::ErrorKind::Other, + _ => embedded_io_extras::ErrorKind::Other, } } } #[cfg(all(not(feature = "std"), feature = "alloc"))] -impl From> for Error { - fn from(value: embedded_io::ReadExactError) -> Self { +impl From> for Error { + fn from(value: embedded_io_extras::ReadExactError) -> Self { match value { - embedded_io::ReadExactError::UnexpectedEof => Error::Io(embedded_io::ErrorKind::Other), - embedded_io::ReadExactError::Other(e) => e + embedded_io_extras::ReadExactError::UnexpectedEof => Error::Io(embedded_io_extras::ErrorKind::Other), + embedded_io_extras::ReadExactError::Other(e) => e } } } diff --git a/spec/output/generator_spec_rust/const.x/MyXDR.rs b/spec/output/generator_spec_rust/const.x/MyXDR.rs index d4d8e38ab..5463b6eba 100644 --- a/spec/output/generator_spec_rust/const.x/MyXDR.rs +++ b/spec/output/generator_spec_rust/const.x/MyXDR.rs @@ -51,9 +51,7 @@ use std::{ }; #[cfg(all(not(feature = "std"), feature = "alloc"))] -use embedded_io::{Error as _, ErrorType, Read, Write}; -#[cfg(all(not(feature = "std"), feature = "alloc"))] -use embedded_io_cursor::Cursor; +use embedded_io_extras::{Cursor, Error as _, ErrorType, Read, Write}; /// Error contains all errors returned by functions in this crate. It can be /// compared via `PartialEq`, however any contained IO errors will only be @@ -71,7 +69,7 @@ pub enum Error { #[cfg(feature = "std")] Io(io::Error), #[cfg(all(not(feature = "std"), feature = "alloc"))] - Io(embedded_io::ErrorKind), + Io(embedded_io_extras::ErrorKind), DepthLimitExceeded, #[cfg(feature = "serde_json")] Json(serde_json::Error), @@ -97,21 +95,21 @@ impl PartialEq for Error { #[cfg(all(not(feature = "std"), feature = "alloc"))] -impl embedded_io::Error for Error { - fn kind(&self) -> embedded_io::ErrorKind { +impl embedded_io_extras::Error for Error { + fn kind(&self) -> embedded_io_extras::ErrorKind { match self { Self::Io(e) => *e, - _ => embedded_io::ErrorKind::Other, + _ => embedded_io_extras::ErrorKind::Other, } } } #[cfg(all(not(feature = "std"), feature = "alloc"))] -impl From> for Error { - fn from(value: embedded_io::ReadExactError) -> Self { +impl From> for Error { + fn from(value: embedded_io_extras::ReadExactError) -> Self { match value { - embedded_io::ReadExactError::UnexpectedEof => Error::Io(embedded_io::ErrorKind::Other), - embedded_io::ReadExactError::Other(e) => e + embedded_io_extras::ReadExactError::UnexpectedEof => Error::Io(embedded_io_extras::ErrorKind::Other), + embedded_io_extras::ReadExactError::Other(e) => e } } } diff --git a/spec/output/generator_spec_rust/enum.x/MyXDR.rs b/spec/output/generator_spec_rust/enum.x/MyXDR.rs index cfc1b5e62..a0186d28b 100644 --- a/spec/output/generator_spec_rust/enum.x/MyXDR.rs +++ b/spec/output/generator_spec_rust/enum.x/MyXDR.rs @@ -51,9 +51,7 @@ use std::{ }; #[cfg(all(not(feature = "std"), feature = "alloc"))] -use embedded_io::{Error as _, ErrorType, Read, Write}; -#[cfg(all(not(feature = "std"), feature = "alloc"))] -use embedded_io_cursor::Cursor; +use embedded_io_extras::{Cursor, Error as _, ErrorType, Read, Write}; /// Error contains all errors returned by functions in this crate. It can be /// compared via `PartialEq`, however any contained IO errors will only be @@ -71,7 +69,7 @@ pub enum Error { #[cfg(feature = "std")] Io(io::Error), #[cfg(all(not(feature = "std"), feature = "alloc"))] - Io(embedded_io::ErrorKind), + Io(embedded_io_extras::ErrorKind), DepthLimitExceeded, #[cfg(feature = "serde_json")] Json(serde_json::Error), @@ -97,21 +95,21 @@ impl PartialEq for Error { #[cfg(all(not(feature = "std"), feature = "alloc"))] -impl embedded_io::Error for Error { - fn kind(&self) -> embedded_io::ErrorKind { +impl embedded_io_extras::Error for Error { + fn kind(&self) -> embedded_io_extras::ErrorKind { match self { Self::Io(e) => *e, - _ => embedded_io::ErrorKind::Other, + _ => embedded_io_extras::ErrorKind::Other, } } } #[cfg(all(not(feature = "std"), feature = "alloc"))] -impl From> for Error { - fn from(value: embedded_io::ReadExactError) -> Self { +impl From> for Error { + fn from(value: embedded_io_extras::ReadExactError) -> Self { match value { - embedded_io::ReadExactError::UnexpectedEof => Error::Io(embedded_io::ErrorKind::Other), - embedded_io::ReadExactError::Other(e) => e + embedded_io_extras::ReadExactError::UnexpectedEof => Error::Io(embedded_io_extras::ErrorKind::Other), + embedded_io_extras::ReadExactError::Other(e) => e } } } diff --git a/spec/output/generator_spec_rust/nesting.x/MyXDR.rs b/spec/output/generator_spec_rust/nesting.x/MyXDR.rs index 038bb9c08..e6f36d9c3 100644 --- a/spec/output/generator_spec_rust/nesting.x/MyXDR.rs +++ b/spec/output/generator_spec_rust/nesting.x/MyXDR.rs @@ -51,9 +51,7 @@ use std::{ }; #[cfg(all(not(feature = "std"), feature = "alloc"))] -use embedded_io::{Error as _, ErrorType, Read, Write}; -#[cfg(all(not(feature = "std"), feature = "alloc"))] -use embedded_io_cursor::Cursor; +use embedded_io_extras::{Cursor, Error as _, ErrorType, Read, Write}; /// Error contains all errors returned by functions in this crate. It can be /// compared via `PartialEq`, however any contained IO errors will only be @@ -71,7 +69,7 @@ pub enum Error { #[cfg(feature = "std")] Io(io::Error), #[cfg(all(not(feature = "std"), feature = "alloc"))] - Io(embedded_io::ErrorKind), + Io(embedded_io_extras::ErrorKind), DepthLimitExceeded, #[cfg(feature = "serde_json")] Json(serde_json::Error), @@ -97,21 +95,21 @@ impl PartialEq for Error { #[cfg(all(not(feature = "std"), feature = "alloc"))] -impl embedded_io::Error for Error { - fn kind(&self) -> embedded_io::ErrorKind { +impl embedded_io_extras::Error for Error { + fn kind(&self) -> embedded_io_extras::ErrorKind { match self { Self::Io(e) => *e, - _ => embedded_io::ErrorKind::Other, + _ => embedded_io_extras::ErrorKind::Other, } } } #[cfg(all(not(feature = "std"), feature = "alloc"))] -impl From> for Error { - fn from(value: embedded_io::ReadExactError) -> Self { +impl From> for Error { + fn from(value: embedded_io_extras::ReadExactError) -> Self { match value { - embedded_io::ReadExactError::UnexpectedEof => Error::Io(embedded_io::ErrorKind::Other), - embedded_io::ReadExactError::Other(e) => e + embedded_io_extras::ReadExactError::UnexpectedEof => Error::Io(embedded_io_extras::ErrorKind::Other), + embedded_io_extras::ReadExactError::Other(e) => e } } } diff --git a/spec/output/generator_spec_rust/optional.x/MyXDR.rs b/spec/output/generator_spec_rust/optional.x/MyXDR.rs index bd6ef6b10..6a953c99e 100644 --- a/spec/output/generator_spec_rust/optional.x/MyXDR.rs +++ b/spec/output/generator_spec_rust/optional.x/MyXDR.rs @@ -51,9 +51,7 @@ use std::{ }; #[cfg(all(not(feature = "std"), feature = "alloc"))] -use embedded_io::{Error as _, ErrorType, Read, Write}; -#[cfg(all(not(feature = "std"), feature = "alloc"))] -use embedded_io_cursor::Cursor; +use embedded_io_extras::{Cursor, Error as _, ErrorType, Read, Write}; /// Error contains all errors returned by functions in this crate. It can be /// compared via `PartialEq`, however any contained IO errors will only be @@ -71,7 +69,7 @@ pub enum Error { #[cfg(feature = "std")] Io(io::Error), #[cfg(all(not(feature = "std"), feature = "alloc"))] - Io(embedded_io::ErrorKind), + Io(embedded_io_extras::ErrorKind), DepthLimitExceeded, #[cfg(feature = "serde_json")] Json(serde_json::Error), @@ -97,21 +95,21 @@ impl PartialEq for Error { #[cfg(all(not(feature = "std"), feature = "alloc"))] -impl embedded_io::Error for Error { - fn kind(&self) -> embedded_io::ErrorKind { +impl embedded_io_extras::Error for Error { + fn kind(&self) -> embedded_io_extras::ErrorKind { match self { Self::Io(e) => *e, - _ => embedded_io::ErrorKind::Other, + _ => embedded_io_extras::ErrorKind::Other, } } } #[cfg(all(not(feature = "std"), feature = "alloc"))] -impl From> for Error { - fn from(value: embedded_io::ReadExactError) -> Self { +impl From> for Error { + fn from(value: embedded_io_extras::ReadExactError) -> Self { match value { - embedded_io::ReadExactError::UnexpectedEof => Error::Io(embedded_io::ErrorKind::Other), - embedded_io::ReadExactError::Other(e) => e + embedded_io_extras::ReadExactError::UnexpectedEof => Error::Io(embedded_io_extras::ErrorKind::Other), + embedded_io_extras::ReadExactError::Other(e) => e } } } diff --git a/spec/output/generator_spec_rust/struct.x/MyXDR.rs b/spec/output/generator_spec_rust/struct.x/MyXDR.rs index 0f788ddfb..c10313f19 100644 --- a/spec/output/generator_spec_rust/struct.x/MyXDR.rs +++ b/spec/output/generator_spec_rust/struct.x/MyXDR.rs @@ -51,9 +51,7 @@ use std::{ }; #[cfg(all(not(feature = "std"), feature = "alloc"))] -use embedded_io::{Error as _, ErrorType, Read, Write}; -#[cfg(all(not(feature = "std"), feature = "alloc"))] -use embedded_io_cursor::Cursor; +use embedded_io_extras::{Cursor, Error as _, ErrorType, Read, Write}; /// Error contains all errors returned by functions in this crate. It can be /// compared via `PartialEq`, however any contained IO errors will only be @@ -71,7 +69,7 @@ pub enum Error { #[cfg(feature = "std")] Io(io::Error), #[cfg(all(not(feature = "std"), feature = "alloc"))] - Io(embedded_io::ErrorKind), + Io(embedded_io_extras::ErrorKind), DepthLimitExceeded, #[cfg(feature = "serde_json")] Json(serde_json::Error), @@ -97,21 +95,21 @@ impl PartialEq for Error { #[cfg(all(not(feature = "std"), feature = "alloc"))] -impl embedded_io::Error for Error { - fn kind(&self) -> embedded_io::ErrorKind { +impl embedded_io_extras::Error for Error { + fn kind(&self) -> embedded_io_extras::ErrorKind { match self { Self::Io(e) => *e, - _ => embedded_io::ErrorKind::Other, + _ => embedded_io_extras::ErrorKind::Other, } } } #[cfg(all(not(feature = "std"), feature = "alloc"))] -impl From> for Error { - fn from(value: embedded_io::ReadExactError) -> Self { +impl From> for Error { + fn from(value: embedded_io_extras::ReadExactError) -> Self { match value { - embedded_io::ReadExactError::UnexpectedEof => Error::Io(embedded_io::ErrorKind::Other), - embedded_io::ReadExactError::Other(e) => e + embedded_io_extras::ReadExactError::UnexpectedEof => Error::Io(embedded_io_extras::ErrorKind::Other), + embedded_io_extras::ReadExactError::Other(e) => e } } } diff --git a/spec/output/generator_spec_rust/test.x/MyXDR.rs b/spec/output/generator_spec_rust/test.x/MyXDR.rs index 2a35f2a19..9386fcdb2 100644 --- a/spec/output/generator_spec_rust/test.x/MyXDR.rs +++ b/spec/output/generator_spec_rust/test.x/MyXDR.rs @@ -51,9 +51,7 @@ use std::{ }; #[cfg(all(not(feature = "std"), feature = "alloc"))] -use embedded_io::{Error as _, ErrorType, Read, Write}; -#[cfg(all(not(feature = "std"), feature = "alloc"))] -use embedded_io_cursor::Cursor; +use embedded_io_extras::{Cursor, Error as _, ErrorType, Read, Write}; /// Error contains all errors returned by functions in this crate. It can be /// compared via `PartialEq`, however any contained IO errors will only be @@ -71,7 +69,7 @@ pub enum Error { #[cfg(feature = "std")] Io(io::Error), #[cfg(all(not(feature = "std"), feature = "alloc"))] - Io(embedded_io::ErrorKind), + Io(embedded_io_extras::ErrorKind), DepthLimitExceeded, #[cfg(feature = "serde_json")] Json(serde_json::Error), @@ -97,21 +95,21 @@ impl PartialEq for Error { #[cfg(all(not(feature = "std"), feature = "alloc"))] -impl embedded_io::Error for Error { - fn kind(&self) -> embedded_io::ErrorKind { +impl embedded_io_extras::Error for Error { + fn kind(&self) -> embedded_io_extras::ErrorKind { match self { Self::Io(e) => *e, - _ => embedded_io::ErrorKind::Other, + _ => embedded_io_extras::ErrorKind::Other, } } } #[cfg(all(not(feature = "std"), feature = "alloc"))] -impl From> for Error { - fn from(value: embedded_io::ReadExactError) -> Self { +impl From> for Error { + fn from(value: embedded_io_extras::ReadExactError) -> Self { match value { - embedded_io::ReadExactError::UnexpectedEof => Error::Io(embedded_io::ErrorKind::Other), - embedded_io::ReadExactError::Other(e) => e + embedded_io_extras::ReadExactError::UnexpectedEof => Error::Io(embedded_io_extras::ErrorKind::Other), + embedded_io_extras::ReadExactError::Other(e) => e } } } diff --git a/spec/output/generator_spec_rust/union.x/MyXDR.rs b/spec/output/generator_spec_rust/union.x/MyXDR.rs index a277e7408..b2ba8b915 100644 --- a/spec/output/generator_spec_rust/union.x/MyXDR.rs +++ b/spec/output/generator_spec_rust/union.x/MyXDR.rs @@ -51,9 +51,7 @@ use std::{ }; #[cfg(all(not(feature = "std"), feature = "alloc"))] -use embedded_io::{Error as _, ErrorType, Read, Write}; -#[cfg(all(not(feature = "std"), feature = "alloc"))] -use embedded_io_cursor::Cursor; +use embedded_io_extras::{Cursor, Error as _, ErrorType, Read, Write}; /// Error contains all errors returned by functions in this crate. It can be /// compared via `PartialEq`, however any contained IO errors will only be @@ -71,7 +69,7 @@ pub enum Error { #[cfg(feature = "std")] Io(io::Error), #[cfg(all(not(feature = "std"), feature = "alloc"))] - Io(embedded_io::ErrorKind), + Io(embedded_io_extras::ErrorKind), DepthLimitExceeded, #[cfg(feature = "serde_json")] Json(serde_json::Error), @@ -97,21 +95,21 @@ impl PartialEq for Error { #[cfg(all(not(feature = "std"), feature = "alloc"))] -impl embedded_io::Error for Error { - fn kind(&self) -> embedded_io::ErrorKind { +impl embedded_io_extras::Error for Error { + fn kind(&self) -> embedded_io_extras::ErrorKind { match self { Self::Io(e) => *e, - _ => embedded_io::ErrorKind::Other, + _ => embedded_io_extras::ErrorKind::Other, } } } #[cfg(all(not(feature = "std"), feature = "alloc"))] -impl From> for Error { - fn from(value: embedded_io::ReadExactError) -> Self { +impl From> for Error { + fn from(value: embedded_io_extras::ReadExactError) -> Self { match value { - embedded_io::ReadExactError::UnexpectedEof => Error::Io(embedded_io::ErrorKind::Other), - embedded_io::ReadExactError::Other(e) => e + embedded_io_extras::ReadExactError::UnexpectedEof => Error::Io(embedded_io_extras::ErrorKind::Other), + embedded_io_extras::ReadExactError::Other(e) => e } } } diff --git a/spec/output/generator_spec_rust_custom_jsonschema_impls/block_comments.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_jsonschema_impls/block_comments.x/MyXDR.rs index 0f509ea49..9482a1915 100644 --- a/spec/output/generator_spec_rust_custom_jsonschema_impls/block_comments.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_jsonschema_impls/block_comments.x/MyXDR.rs @@ -51,9 +51,7 @@ use std::{ }; #[cfg(all(not(feature = "std"), feature = "alloc"))] -use embedded_io::{Error as _, ErrorType, Read, Write}; -#[cfg(all(not(feature = "std"), feature = "alloc"))] -use embedded_io_cursor::Cursor; +use embedded_io_extras::{Cursor, Error as _, ErrorType, Read, Write}; /// Error contains all errors returned by functions in this crate. It can be /// compared via `PartialEq`, however any contained IO errors will only be @@ -71,7 +69,7 @@ pub enum Error { #[cfg(feature = "std")] Io(io::Error), #[cfg(all(not(feature = "std"), feature = "alloc"))] - Io(embedded_io::ErrorKind), + Io(embedded_io_extras::ErrorKind), DepthLimitExceeded, #[cfg(feature = "serde_json")] Json(serde_json::Error), @@ -97,21 +95,21 @@ impl PartialEq for Error { #[cfg(all(not(feature = "std"), feature = "alloc"))] -impl embedded_io::Error for Error { - fn kind(&self) -> embedded_io::ErrorKind { +impl embedded_io_extras::Error for Error { + fn kind(&self) -> embedded_io_extras::ErrorKind { match self { Self::Io(e) => *e, - _ => embedded_io::ErrorKind::Other, + _ => embedded_io_extras::ErrorKind::Other, } } } #[cfg(all(not(feature = "std"), feature = "alloc"))] -impl From> for Error { - fn from(value: embedded_io::ReadExactError) -> Self { +impl From> for Error { + fn from(value: embedded_io_extras::ReadExactError) -> Self { match value { - embedded_io::ReadExactError::UnexpectedEof => Error::Io(embedded_io::ErrorKind::Other), - embedded_io::ReadExactError::Other(e) => e + embedded_io_extras::ReadExactError::UnexpectedEof => Error::Io(embedded_io_extras::ErrorKind::Other), + embedded_io_extras::ReadExactError::Other(e) => e } } } diff --git a/spec/output/generator_spec_rust_custom_jsonschema_impls/const.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_jsonschema_impls/const.x/MyXDR.rs index d4d8e38ab..5463b6eba 100644 --- a/spec/output/generator_spec_rust_custom_jsonschema_impls/const.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_jsonschema_impls/const.x/MyXDR.rs @@ -51,9 +51,7 @@ use std::{ }; #[cfg(all(not(feature = "std"), feature = "alloc"))] -use embedded_io::{Error as _, ErrorType, Read, Write}; -#[cfg(all(not(feature = "std"), feature = "alloc"))] -use embedded_io_cursor::Cursor; +use embedded_io_extras::{Cursor, Error as _, ErrorType, Read, Write}; /// Error contains all errors returned by functions in this crate. It can be /// compared via `PartialEq`, however any contained IO errors will only be @@ -71,7 +69,7 @@ pub enum Error { #[cfg(feature = "std")] Io(io::Error), #[cfg(all(not(feature = "std"), feature = "alloc"))] - Io(embedded_io::ErrorKind), + Io(embedded_io_extras::ErrorKind), DepthLimitExceeded, #[cfg(feature = "serde_json")] Json(serde_json::Error), @@ -97,21 +95,21 @@ impl PartialEq for Error { #[cfg(all(not(feature = "std"), feature = "alloc"))] -impl embedded_io::Error for Error { - fn kind(&self) -> embedded_io::ErrorKind { +impl embedded_io_extras::Error for Error { + fn kind(&self) -> embedded_io_extras::ErrorKind { match self { Self::Io(e) => *e, - _ => embedded_io::ErrorKind::Other, + _ => embedded_io_extras::ErrorKind::Other, } } } #[cfg(all(not(feature = "std"), feature = "alloc"))] -impl From> for Error { - fn from(value: embedded_io::ReadExactError) -> Self { +impl From> for Error { + fn from(value: embedded_io_extras::ReadExactError) -> Self { match value { - embedded_io::ReadExactError::UnexpectedEof => Error::Io(embedded_io::ErrorKind::Other), - embedded_io::ReadExactError::Other(e) => e + embedded_io_extras::ReadExactError::UnexpectedEof => Error::Io(embedded_io_extras::ErrorKind::Other), + embedded_io_extras::ReadExactError::Other(e) => e } } } diff --git a/spec/output/generator_spec_rust_custom_jsonschema_impls/enum.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_jsonschema_impls/enum.x/MyXDR.rs index 7db523c78..c1949d871 100644 --- a/spec/output/generator_spec_rust_custom_jsonschema_impls/enum.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_jsonschema_impls/enum.x/MyXDR.rs @@ -51,9 +51,7 @@ use std::{ }; #[cfg(all(not(feature = "std"), feature = "alloc"))] -use embedded_io::{Error as _, ErrorType, Read, Write}; -#[cfg(all(not(feature = "std"), feature = "alloc"))] -use embedded_io_cursor::Cursor; +use embedded_io_extras::{Cursor, Error as _, ErrorType, Read, Write}; /// Error contains all errors returned by functions in this crate. It can be /// compared via `PartialEq`, however any contained IO errors will only be @@ -71,7 +69,7 @@ pub enum Error { #[cfg(feature = "std")] Io(io::Error), #[cfg(all(not(feature = "std"), feature = "alloc"))] - Io(embedded_io::ErrorKind), + Io(embedded_io_extras::ErrorKind), DepthLimitExceeded, #[cfg(feature = "serde_json")] Json(serde_json::Error), @@ -97,21 +95,21 @@ impl PartialEq for Error { #[cfg(all(not(feature = "std"), feature = "alloc"))] -impl embedded_io::Error for Error { - fn kind(&self) -> embedded_io::ErrorKind { +impl embedded_io_extras::Error for Error { + fn kind(&self) -> embedded_io_extras::ErrorKind { match self { Self::Io(e) => *e, - _ => embedded_io::ErrorKind::Other, + _ => embedded_io_extras::ErrorKind::Other, } } } #[cfg(all(not(feature = "std"), feature = "alloc"))] -impl From> for Error { - fn from(value: embedded_io::ReadExactError) -> Self { +impl From> for Error { + fn from(value: embedded_io_extras::ReadExactError) -> Self { match value { - embedded_io::ReadExactError::UnexpectedEof => Error::Io(embedded_io::ErrorKind::Other), - embedded_io::ReadExactError::Other(e) => e + embedded_io_extras::ReadExactError::UnexpectedEof => Error::Io(embedded_io_extras::ErrorKind::Other), + embedded_io_extras::ReadExactError::Other(e) => e } } } diff --git a/spec/output/generator_spec_rust_custom_jsonschema_impls/nesting.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_jsonschema_impls/nesting.x/MyXDR.rs index af26cbeca..8da3e4efe 100644 --- a/spec/output/generator_spec_rust_custom_jsonschema_impls/nesting.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_jsonschema_impls/nesting.x/MyXDR.rs @@ -51,9 +51,7 @@ use std::{ }; #[cfg(all(not(feature = "std"), feature = "alloc"))] -use embedded_io::{Error as _, ErrorType, Read, Write}; -#[cfg(all(not(feature = "std"), feature = "alloc"))] -use embedded_io_cursor::Cursor; +use embedded_io_extras::{Cursor, Error as _, ErrorType, Read, Write}; /// Error contains all errors returned by functions in this crate. It can be /// compared via `PartialEq`, however any contained IO errors will only be @@ -71,7 +69,7 @@ pub enum Error { #[cfg(feature = "std")] Io(io::Error), #[cfg(all(not(feature = "std"), feature = "alloc"))] - Io(embedded_io::ErrorKind), + Io(embedded_io_extras::ErrorKind), DepthLimitExceeded, #[cfg(feature = "serde_json")] Json(serde_json::Error), @@ -97,21 +95,21 @@ impl PartialEq for Error { #[cfg(all(not(feature = "std"), feature = "alloc"))] -impl embedded_io::Error for Error { - fn kind(&self) -> embedded_io::ErrorKind { +impl embedded_io_extras::Error for Error { + fn kind(&self) -> embedded_io_extras::ErrorKind { match self { Self::Io(e) => *e, - _ => embedded_io::ErrorKind::Other, + _ => embedded_io_extras::ErrorKind::Other, } } } #[cfg(all(not(feature = "std"), feature = "alloc"))] -impl From> for Error { - fn from(value: embedded_io::ReadExactError) -> Self { +impl From> for Error { + fn from(value: embedded_io_extras::ReadExactError) -> Self { match value { - embedded_io::ReadExactError::UnexpectedEof => Error::Io(embedded_io::ErrorKind::Other), - embedded_io::ReadExactError::Other(e) => e + embedded_io_extras::ReadExactError::UnexpectedEof => Error::Io(embedded_io_extras::ErrorKind::Other), + embedded_io_extras::ReadExactError::Other(e) => e } } } diff --git a/spec/output/generator_spec_rust_custom_jsonschema_impls/optional.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_jsonschema_impls/optional.x/MyXDR.rs index 2a13253f0..2a0294a05 100644 --- a/spec/output/generator_spec_rust_custom_jsonschema_impls/optional.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_jsonschema_impls/optional.x/MyXDR.rs @@ -51,9 +51,7 @@ use std::{ }; #[cfg(all(not(feature = "std"), feature = "alloc"))] -use embedded_io::{Error as _, ErrorType, Read, Write}; -#[cfg(all(not(feature = "std"), feature = "alloc"))] -use embedded_io_cursor::Cursor; +use embedded_io_extras::{Cursor, Error as _, ErrorType, Read, Write}; /// Error contains all errors returned by functions in this crate. It can be /// compared via `PartialEq`, however any contained IO errors will only be @@ -71,7 +69,7 @@ pub enum Error { #[cfg(feature = "std")] Io(io::Error), #[cfg(all(not(feature = "std"), feature = "alloc"))] - Io(embedded_io::ErrorKind), + Io(embedded_io_extras::ErrorKind), DepthLimitExceeded, #[cfg(feature = "serde_json")] Json(serde_json::Error), @@ -97,21 +95,21 @@ impl PartialEq for Error { #[cfg(all(not(feature = "std"), feature = "alloc"))] -impl embedded_io::Error for Error { - fn kind(&self) -> embedded_io::ErrorKind { +impl embedded_io_extras::Error for Error { + fn kind(&self) -> embedded_io_extras::ErrorKind { match self { Self::Io(e) => *e, - _ => embedded_io::ErrorKind::Other, + _ => embedded_io_extras::ErrorKind::Other, } } } #[cfg(all(not(feature = "std"), feature = "alloc"))] -impl From> for Error { - fn from(value: embedded_io::ReadExactError) -> Self { +impl From> for Error { + fn from(value: embedded_io_extras::ReadExactError) -> Self { match value { - embedded_io::ReadExactError::UnexpectedEof => Error::Io(embedded_io::ErrorKind::Other), - embedded_io::ReadExactError::Other(e) => e + embedded_io_extras::ReadExactError::UnexpectedEof => Error::Io(embedded_io_extras::ErrorKind::Other), + embedded_io_extras::ReadExactError::Other(e) => e } } } diff --git a/spec/output/generator_spec_rust_custom_jsonschema_impls/struct.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_jsonschema_impls/struct.x/MyXDR.rs index 327c024bf..fa6dc9473 100644 --- a/spec/output/generator_spec_rust_custom_jsonschema_impls/struct.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_jsonschema_impls/struct.x/MyXDR.rs @@ -51,9 +51,7 @@ use std::{ }; #[cfg(all(not(feature = "std"), feature = "alloc"))] -use embedded_io::{Error as _, ErrorType, Read, Write}; -#[cfg(all(not(feature = "std"), feature = "alloc"))] -use embedded_io_cursor::Cursor; +use embedded_io_extras::{Cursor, Error as _, ErrorType, Read, Write}; /// Error contains all errors returned by functions in this crate. It can be /// compared via `PartialEq`, however any contained IO errors will only be @@ -71,7 +69,7 @@ pub enum Error { #[cfg(feature = "std")] Io(io::Error), #[cfg(all(not(feature = "std"), feature = "alloc"))] - Io(embedded_io::ErrorKind), + Io(embedded_io_extras::ErrorKind), DepthLimitExceeded, #[cfg(feature = "serde_json")] Json(serde_json::Error), @@ -97,21 +95,21 @@ impl PartialEq for Error { #[cfg(all(not(feature = "std"), feature = "alloc"))] -impl embedded_io::Error for Error { - fn kind(&self) -> embedded_io::ErrorKind { +impl embedded_io_extras::Error for Error { + fn kind(&self) -> embedded_io_extras::ErrorKind { match self { Self::Io(e) => *e, - _ => embedded_io::ErrorKind::Other, + _ => embedded_io_extras::ErrorKind::Other, } } } #[cfg(all(not(feature = "std"), feature = "alloc"))] -impl From> for Error { - fn from(value: embedded_io::ReadExactError) -> Self { +impl From> for Error { + fn from(value: embedded_io_extras::ReadExactError) -> Self { match value { - embedded_io::ReadExactError::UnexpectedEof => Error::Io(embedded_io::ErrorKind::Other), - embedded_io::ReadExactError::Other(e) => e + embedded_io_extras::ReadExactError::UnexpectedEof => Error::Io(embedded_io_extras::ErrorKind::Other), + embedded_io_extras::ReadExactError::Other(e) => e } } } diff --git a/spec/output/generator_spec_rust_custom_jsonschema_impls/test.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_jsonschema_impls/test.x/MyXDR.rs index 5164b451e..05f26846c 100644 --- a/spec/output/generator_spec_rust_custom_jsonschema_impls/test.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_jsonschema_impls/test.x/MyXDR.rs @@ -51,9 +51,7 @@ use std::{ }; #[cfg(all(not(feature = "std"), feature = "alloc"))] -use embedded_io::{Error as _, ErrorType, Read, Write}; -#[cfg(all(not(feature = "std"), feature = "alloc"))] -use embedded_io_cursor::Cursor; +use embedded_io_extras::{Cursor, Error as _, ErrorType, Read, Write}; /// Error contains all errors returned by functions in this crate. It can be /// compared via `PartialEq`, however any contained IO errors will only be @@ -71,7 +69,7 @@ pub enum Error { #[cfg(feature = "std")] Io(io::Error), #[cfg(all(not(feature = "std"), feature = "alloc"))] - Io(embedded_io::ErrorKind), + Io(embedded_io_extras::ErrorKind), DepthLimitExceeded, #[cfg(feature = "serde_json")] Json(serde_json::Error), @@ -97,21 +95,21 @@ impl PartialEq for Error { #[cfg(all(not(feature = "std"), feature = "alloc"))] -impl embedded_io::Error for Error { - fn kind(&self) -> embedded_io::ErrorKind { +impl embedded_io_extras::Error for Error { + fn kind(&self) -> embedded_io_extras::ErrorKind { match self { Self::Io(e) => *e, - _ => embedded_io::ErrorKind::Other, + _ => embedded_io_extras::ErrorKind::Other, } } } #[cfg(all(not(feature = "std"), feature = "alloc"))] -impl From> for Error { - fn from(value: embedded_io::ReadExactError) -> Self { +impl From> for Error { + fn from(value: embedded_io_extras::ReadExactError) -> Self { match value { - embedded_io::ReadExactError::UnexpectedEof => Error::Io(embedded_io::ErrorKind::Other), - embedded_io::ReadExactError::Other(e) => e + embedded_io_extras::ReadExactError::UnexpectedEof => Error::Io(embedded_io_extras::ErrorKind::Other), + embedded_io_extras::ReadExactError::Other(e) => e } } } diff --git a/spec/output/generator_spec_rust_custom_jsonschema_impls/union.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_jsonschema_impls/union.x/MyXDR.rs index 04fa7cfcc..960a61484 100644 --- a/spec/output/generator_spec_rust_custom_jsonschema_impls/union.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_jsonschema_impls/union.x/MyXDR.rs @@ -51,9 +51,7 @@ use std::{ }; #[cfg(all(not(feature = "std"), feature = "alloc"))] -use embedded_io::{Error as _, ErrorType, Read, Write}; -#[cfg(all(not(feature = "std"), feature = "alloc"))] -use embedded_io_cursor::Cursor; +use embedded_io_extras::{Cursor, Error as _, ErrorType, Read, Write}; /// Error contains all errors returned by functions in this crate. It can be /// compared via `PartialEq`, however any contained IO errors will only be @@ -71,7 +69,7 @@ pub enum Error { #[cfg(feature = "std")] Io(io::Error), #[cfg(all(not(feature = "std"), feature = "alloc"))] - Io(embedded_io::ErrorKind), + Io(embedded_io_extras::ErrorKind), DepthLimitExceeded, #[cfg(feature = "serde_json")] Json(serde_json::Error), @@ -97,21 +95,21 @@ impl PartialEq for Error { #[cfg(all(not(feature = "std"), feature = "alloc"))] -impl embedded_io::Error for Error { - fn kind(&self) -> embedded_io::ErrorKind { +impl embedded_io_extras::Error for Error { + fn kind(&self) -> embedded_io_extras::ErrorKind { match self { Self::Io(e) => *e, - _ => embedded_io::ErrorKind::Other, + _ => embedded_io_extras::ErrorKind::Other, } } } #[cfg(all(not(feature = "std"), feature = "alloc"))] -impl From> for Error { - fn from(value: embedded_io::ReadExactError) -> Self { +impl From> for Error { + fn from(value: embedded_io_extras::ReadExactError) -> Self { match value { - embedded_io::ReadExactError::UnexpectedEof => Error::Io(embedded_io::ErrorKind::Other), - embedded_io::ReadExactError::Other(e) => e + embedded_io_extras::ReadExactError::UnexpectedEof => Error::Io(embedded_io_extras::ErrorKind::Other), + embedded_io_extras::ReadExactError::Other(e) => e } } } diff --git a/spec/output/generator_spec_rust_custom_str_impls/block_comments.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_str_impls/block_comments.x/MyXDR.rs index 0f509ea49..9482a1915 100644 --- a/spec/output/generator_spec_rust_custom_str_impls/block_comments.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_str_impls/block_comments.x/MyXDR.rs @@ -51,9 +51,7 @@ use std::{ }; #[cfg(all(not(feature = "std"), feature = "alloc"))] -use embedded_io::{Error as _, ErrorType, Read, Write}; -#[cfg(all(not(feature = "std"), feature = "alloc"))] -use embedded_io_cursor::Cursor; +use embedded_io_extras::{Cursor, Error as _, ErrorType, Read, Write}; /// Error contains all errors returned by functions in this crate. It can be /// compared via `PartialEq`, however any contained IO errors will only be @@ -71,7 +69,7 @@ pub enum Error { #[cfg(feature = "std")] Io(io::Error), #[cfg(all(not(feature = "std"), feature = "alloc"))] - Io(embedded_io::ErrorKind), + Io(embedded_io_extras::ErrorKind), DepthLimitExceeded, #[cfg(feature = "serde_json")] Json(serde_json::Error), @@ -97,21 +95,21 @@ impl PartialEq for Error { #[cfg(all(not(feature = "std"), feature = "alloc"))] -impl embedded_io::Error for Error { - fn kind(&self) -> embedded_io::ErrorKind { +impl embedded_io_extras::Error for Error { + fn kind(&self) -> embedded_io_extras::ErrorKind { match self { Self::Io(e) => *e, - _ => embedded_io::ErrorKind::Other, + _ => embedded_io_extras::ErrorKind::Other, } } } #[cfg(all(not(feature = "std"), feature = "alloc"))] -impl From> for Error { - fn from(value: embedded_io::ReadExactError) -> Self { +impl From> for Error { + fn from(value: embedded_io_extras::ReadExactError) -> Self { match value { - embedded_io::ReadExactError::UnexpectedEof => Error::Io(embedded_io::ErrorKind::Other), - embedded_io::ReadExactError::Other(e) => e + embedded_io_extras::ReadExactError::UnexpectedEof => Error::Io(embedded_io_extras::ErrorKind::Other), + embedded_io_extras::ReadExactError::Other(e) => e } } } diff --git a/spec/output/generator_spec_rust_custom_str_impls/const.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_str_impls/const.x/MyXDR.rs index d4d8e38ab..5463b6eba 100644 --- a/spec/output/generator_spec_rust_custom_str_impls/const.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_str_impls/const.x/MyXDR.rs @@ -51,9 +51,7 @@ use std::{ }; #[cfg(all(not(feature = "std"), feature = "alloc"))] -use embedded_io::{Error as _, ErrorType, Read, Write}; -#[cfg(all(not(feature = "std"), feature = "alloc"))] -use embedded_io_cursor::Cursor; +use embedded_io_extras::{Cursor, Error as _, ErrorType, Read, Write}; /// Error contains all errors returned by functions in this crate. It can be /// compared via `PartialEq`, however any contained IO errors will only be @@ -71,7 +69,7 @@ pub enum Error { #[cfg(feature = "std")] Io(io::Error), #[cfg(all(not(feature = "std"), feature = "alloc"))] - Io(embedded_io::ErrorKind), + Io(embedded_io_extras::ErrorKind), DepthLimitExceeded, #[cfg(feature = "serde_json")] Json(serde_json::Error), @@ -97,21 +95,21 @@ impl PartialEq for Error { #[cfg(all(not(feature = "std"), feature = "alloc"))] -impl embedded_io::Error for Error { - fn kind(&self) -> embedded_io::ErrorKind { +impl embedded_io_extras::Error for Error { + fn kind(&self) -> embedded_io_extras::ErrorKind { match self { Self::Io(e) => *e, - _ => embedded_io::ErrorKind::Other, + _ => embedded_io_extras::ErrorKind::Other, } } } #[cfg(all(not(feature = "std"), feature = "alloc"))] -impl From> for Error { - fn from(value: embedded_io::ReadExactError) -> Self { +impl From> for Error { + fn from(value: embedded_io_extras::ReadExactError) -> Self { match value { - embedded_io::ReadExactError::UnexpectedEof => Error::Io(embedded_io::ErrorKind::Other), - embedded_io::ReadExactError::Other(e) => e + embedded_io_extras::ReadExactError::UnexpectedEof => Error::Io(embedded_io_extras::ErrorKind::Other), + embedded_io_extras::ReadExactError::Other(e) => e } } } diff --git a/spec/output/generator_spec_rust_custom_str_impls/enum.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_str_impls/enum.x/MyXDR.rs index e890eb80d..e90df36e5 100644 --- a/spec/output/generator_spec_rust_custom_str_impls/enum.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_str_impls/enum.x/MyXDR.rs @@ -51,9 +51,7 @@ use std::{ }; #[cfg(all(not(feature = "std"), feature = "alloc"))] -use embedded_io::{Error as _, ErrorType, Read, Write}; -#[cfg(all(not(feature = "std"), feature = "alloc"))] -use embedded_io_cursor::Cursor; +use embedded_io_extras::{Cursor, Error as _, ErrorType, Read, Write}; /// Error contains all errors returned by functions in this crate. It can be /// compared via `PartialEq`, however any contained IO errors will only be @@ -71,7 +69,7 @@ pub enum Error { #[cfg(feature = "std")] Io(io::Error), #[cfg(all(not(feature = "std"), feature = "alloc"))] - Io(embedded_io::ErrorKind), + Io(embedded_io_extras::ErrorKind), DepthLimitExceeded, #[cfg(feature = "serde_json")] Json(serde_json::Error), @@ -97,21 +95,21 @@ impl PartialEq for Error { #[cfg(all(not(feature = "std"), feature = "alloc"))] -impl embedded_io::Error for Error { - fn kind(&self) -> embedded_io::ErrorKind { +impl embedded_io_extras::Error for Error { + fn kind(&self) -> embedded_io_extras::ErrorKind { match self { Self::Io(e) => *e, - _ => embedded_io::ErrorKind::Other, + _ => embedded_io_extras::ErrorKind::Other, } } } #[cfg(all(not(feature = "std"), feature = "alloc"))] -impl From> for Error { - fn from(value: embedded_io::ReadExactError) -> Self { +impl From> for Error { + fn from(value: embedded_io_extras::ReadExactError) -> Self { match value { - embedded_io::ReadExactError::UnexpectedEof => Error::Io(embedded_io::ErrorKind::Other), - embedded_io::ReadExactError::Other(e) => e + embedded_io_extras::ReadExactError::UnexpectedEof => Error::Io(embedded_io_extras::ErrorKind::Other), + embedded_io_extras::ReadExactError::Other(e) => e } } } diff --git a/spec/output/generator_spec_rust_custom_str_impls/nesting.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_str_impls/nesting.x/MyXDR.rs index 58cb1b478..89de975e1 100644 --- a/spec/output/generator_spec_rust_custom_str_impls/nesting.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_str_impls/nesting.x/MyXDR.rs @@ -51,9 +51,7 @@ use std::{ }; #[cfg(all(not(feature = "std"), feature = "alloc"))] -use embedded_io::{Error as _, ErrorType, Read, Write}; -#[cfg(all(not(feature = "std"), feature = "alloc"))] -use embedded_io_cursor::Cursor; +use embedded_io_extras::{Cursor, Error as _, ErrorType, Read, Write}; /// Error contains all errors returned by functions in this crate. It can be /// compared via `PartialEq`, however any contained IO errors will only be @@ -71,7 +69,7 @@ pub enum Error { #[cfg(feature = "std")] Io(io::Error), #[cfg(all(not(feature = "std"), feature = "alloc"))] - Io(embedded_io::ErrorKind), + Io(embedded_io_extras::ErrorKind), DepthLimitExceeded, #[cfg(feature = "serde_json")] Json(serde_json::Error), @@ -97,21 +95,21 @@ impl PartialEq for Error { #[cfg(all(not(feature = "std"), feature = "alloc"))] -impl embedded_io::Error for Error { - fn kind(&self) -> embedded_io::ErrorKind { +impl embedded_io_extras::Error for Error { + fn kind(&self) -> embedded_io_extras::ErrorKind { match self { Self::Io(e) => *e, - _ => embedded_io::ErrorKind::Other, + _ => embedded_io_extras::ErrorKind::Other, } } } #[cfg(all(not(feature = "std"), feature = "alloc"))] -impl From> for Error { - fn from(value: embedded_io::ReadExactError) -> Self { +impl From> for Error { + fn from(value: embedded_io_extras::ReadExactError) -> Self { match value { - embedded_io::ReadExactError::UnexpectedEof => Error::Io(embedded_io::ErrorKind::Other), - embedded_io::ReadExactError::Other(e) => e + embedded_io_extras::ReadExactError::UnexpectedEof => Error::Io(embedded_io_extras::ErrorKind::Other), + embedded_io_extras::ReadExactError::Other(e) => e } } } diff --git a/spec/output/generator_spec_rust_custom_str_impls/optional.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_str_impls/optional.x/MyXDR.rs index 9ac7c5c6d..9ed8491dd 100644 --- a/spec/output/generator_spec_rust_custom_str_impls/optional.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_str_impls/optional.x/MyXDR.rs @@ -51,9 +51,7 @@ use std::{ }; #[cfg(all(not(feature = "std"), feature = "alloc"))] -use embedded_io::{Error as _, ErrorType, Read, Write}; -#[cfg(all(not(feature = "std"), feature = "alloc"))] -use embedded_io_cursor::Cursor; +use embedded_io_extras::{Cursor, Error as _, ErrorType, Read, Write}; /// Error contains all errors returned by functions in this crate. It can be /// compared via `PartialEq`, however any contained IO errors will only be @@ -71,7 +69,7 @@ pub enum Error { #[cfg(feature = "std")] Io(io::Error), #[cfg(all(not(feature = "std"), feature = "alloc"))] - Io(embedded_io::ErrorKind), + Io(embedded_io_extras::ErrorKind), DepthLimitExceeded, #[cfg(feature = "serde_json")] Json(serde_json::Error), @@ -97,21 +95,21 @@ impl PartialEq for Error { #[cfg(all(not(feature = "std"), feature = "alloc"))] -impl embedded_io::Error for Error { - fn kind(&self) -> embedded_io::ErrorKind { +impl embedded_io_extras::Error for Error { + fn kind(&self) -> embedded_io_extras::ErrorKind { match self { Self::Io(e) => *e, - _ => embedded_io::ErrorKind::Other, + _ => embedded_io_extras::ErrorKind::Other, } } } #[cfg(all(not(feature = "std"), feature = "alloc"))] -impl From> for Error { - fn from(value: embedded_io::ReadExactError) -> Self { +impl From> for Error { + fn from(value: embedded_io_extras::ReadExactError) -> Self { match value { - embedded_io::ReadExactError::UnexpectedEof => Error::Io(embedded_io::ErrorKind::Other), - embedded_io::ReadExactError::Other(e) => e + embedded_io_extras::ReadExactError::UnexpectedEof => Error::Io(embedded_io_extras::ErrorKind::Other), + embedded_io_extras::ReadExactError::Other(e) => e } } } diff --git a/spec/output/generator_spec_rust_custom_str_impls/struct.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_str_impls/struct.x/MyXDR.rs index 932215fdf..f703197c7 100644 --- a/spec/output/generator_spec_rust_custom_str_impls/struct.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_str_impls/struct.x/MyXDR.rs @@ -51,9 +51,7 @@ use std::{ }; #[cfg(all(not(feature = "std"), feature = "alloc"))] -use embedded_io::{Error as _, ErrorType, Read, Write}; -#[cfg(all(not(feature = "std"), feature = "alloc"))] -use embedded_io_cursor::Cursor; +use embedded_io_extras::{Cursor, Error as _, ErrorType, Read, Write}; /// Error contains all errors returned by functions in this crate. It can be /// compared via `PartialEq`, however any contained IO errors will only be @@ -71,7 +69,7 @@ pub enum Error { #[cfg(feature = "std")] Io(io::Error), #[cfg(all(not(feature = "std"), feature = "alloc"))] - Io(embedded_io::ErrorKind), + Io(embedded_io_extras::ErrorKind), DepthLimitExceeded, #[cfg(feature = "serde_json")] Json(serde_json::Error), @@ -97,21 +95,21 @@ impl PartialEq for Error { #[cfg(all(not(feature = "std"), feature = "alloc"))] -impl embedded_io::Error for Error { - fn kind(&self) -> embedded_io::ErrorKind { +impl embedded_io_extras::Error for Error { + fn kind(&self) -> embedded_io_extras::ErrorKind { match self { Self::Io(e) => *e, - _ => embedded_io::ErrorKind::Other, + _ => embedded_io_extras::ErrorKind::Other, } } } #[cfg(all(not(feature = "std"), feature = "alloc"))] -impl From> for Error { - fn from(value: embedded_io::ReadExactError) -> Self { +impl From> for Error { + fn from(value: embedded_io_extras::ReadExactError) -> Self { match value { - embedded_io::ReadExactError::UnexpectedEof => Error::Io(embedded_io::ErrorKind::Other), - embedded_io::ReadExactError::Other(e) => e + embedded_io_extras::ReadExactError::UnexpectedEof => Error::Io(embedded_io_extras::ErrorKind::Other), + embedded_io_extras::ReadExactError::Other(e) => e } } } diff --git a/spec/output/generator_spec_rust_custom_str_impls/test.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_str_impls/test.x/MyXDR.rs index 69abdac69..0eaaffb2e 100644 --- a/spec/output/generator_spec_rust_custom_str_impls/test.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_str_impls/test.x/MyXDR.rs @@ -51,9 +51,7 @@ use std::{ }; #[cfg(all(not(feature = "std"), feature = "alloc"))] -use embedded_io::{Error as _, ErrorType, Read, Write}; -#[cfg(all(not(feature = "std"), feature = "alloc"))] -use embedded_io_cursor::Cursor; +use embedded_io_extras::{Cursor, Error as _, ErrorType, Read, Write}; /// Error contains all errors returned by functions in this crate. It can be /// compared via `PartialEq`, however any contained IO errors will only be @@ -71,7 +69,7 @@ pub enum Error { #[cfg(feature = "std")] Io(io::Error), #[cfg(all(not(feature = "std"), feature = "alloc"))] - Io(embedded_io::ErrorKind), + Io(embedded_io_extras::ErrorKind), DepthLimitExceeded, #[cfg(feature = "serde_json")] Json(serde_json::Error), @@ -97,21 +95,21 @@ impl PartialEq for Error { #[cfg(all(not(feature = "std"), feature = "alloc"))] -impl embedded_io::Error for Error { - fn kind(&self) -> embedded_io::ErrorKind { +impl embedded_io_extras::Error for Error { + fn kind(&self) -> embedded_io_extras::ErrorKind { match self { Self::Io(e) => *e, - _ => embedded_io::ErrorKind::Other, + _ => embedded_io_extras::ErrorKind::Other, } } } #[cfg(all(not(feature = "std"), feature = "alloc"))] -impl From> for Error { - fn from(value: embedded_io::ReadExactError) -> Self { +impl From> for Error { + fn from(value: embedded_io_extras::ReadExactError) -> Self { match value { - embedded_io::ReadExactError::UnexpectedEof => Error::Io(embedded_io::ErrorKind::Other), - embedded_io::ReadExactError::Other(e) => e + embedded_io_extras::ReadExactError::UnexpectedEof => Error::Io(embedded_io_extras::ErrorKind::Other), + embedded_io_extras::ReadExactError::Other(e) => e } } } diff --git a/spec/output/generator_spec_rust_custom_str_impls/union.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_str_impls/union.x/MyXDR.rs index 3ac492b1c..971897b4a 100644 --- a/spec/output/generator_spec_rust_custom_str_impls/union.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_str_impls/union.x/MyXDR.rs @@ -51,9 +51,7 @@ use std::{ }; #[cfg(all(not(feature = "std"), feature = "alloc"))] -use embedded_io::{Error as _, ErrorType, Read, Write}; -#[cfg(all(not(feature = "std"), feature = "alloc"))] -use embedded_io_cursor::Cursor; +use embedded_io_extras::{Cursor, Error as _, ErrorType, Read, Write}; /// Error contains all errors returned by functions in this crate. It can be /// compared via `PartialEq`, however any contained IO errors will only be @@ -71,7 +69,7 @@ pub enum Error { #[cfg(feature = "std")] Io(io::Error), #[cfg(all(not(feature = "std"), feature = "alloc"))] - Io(embedded_io::ErrorKind), + Io(embedded_io_extras::ErrorKind), DepthLimitExceeded, #[cfg(feature = "serde_json")] Json(serde_json::Error), @@ -97,21 +95,21 @@ impl PartialEq for Error { #[cfg(all(not(feature = "std"), feature = "alloc"))] -impl embedded_io::Error for Error { - fn kind(&self) -> embedded_io::ErrorKind { +impl embedded_io_extras::Error for Error { + fn kind(&self) -> embedded_io_extras::ErrorKind { match self { Self::Io(e) => *e, - _ => embedded_io::ErrorKind::Other, + _ => embedded_io_extras::ErrorKind::Other, } } } #[cfg(all(not(feature = "std"), feature = "alloc"))] -impl From> for Error { - fn from(value: embedded_io::ReadExactError) -> Self { +impl From> for Error { + fn from(value: embedded_io_extras::ReadExactError) -> Self { match value { - embedded_io::ReadExactError::UnexpectedEof => Error::Io(embedded_io::ErrorKind::Other), - embedded_io::ReadExactError::Other(e) => e + embedded_io_extras::ReadExactError::UnexpectedEof => Error::Io(embedded_io_extras::ErrorKind::Other), + embedded_io_extras::ReadExactError::Other(e) => e } } } From c63cda9c87779e9ddd9be343b8fcac24117a8f22 Mon Sep 17 00:00:00 2001 From: Jun Luo <4catcode@gmail.com> Date: Thu, 12 Sep 2024 16:08:57 +0800 Subject: [PATCH 3/9] clippy::needless_question_mark --- lib/xdrgen/generators/rust.rb | 2 +- spec/output/generator_spec_rust/block_comments.x/MyXDR.rs | 2 +- spec/output/generator_spec_rust/const.x/MyXDR.rs | 2 +- spec/output/generator_spec_rust/enum.x/MyXDR.rs | 2 +- spec/output/generator_spec_rust/nesting.x/MyXDR.rs | 2 +- spec/output/generator_spec_rust/optional.x/MyXDR.rs | 2 +- spec/output/generator_spec_rust/struct.x/MyXDR.rs | 2 +- spec/output/generator_spec_rust/test.x/MyXDR.rs | 2 +- spec/output/generator_spec_rust/union.x/MyXDR.rs | 2 +- .../block_comments.x/MyXDR.rs | 2 +- .../const.x/MyXDR.rs | 2 +- .../generator_spec_rust_custom_jsonschema_impls/enum.x/MyXDR.rs | 2 +- .../nesting.x/MyXDR.rs | 2 +- .../optional.x/MyXDR.rs | 2 +- .../struct.x/MyXDR.rs | 2 +- .../generator_spec_rust_custom_jsonschema_impls/test.x/MyXDR.rs | 2 +- .../union.x/MyXDR.rs | 2 +- .../block_comments.x/MyXDR.rs | 2 +- .../generator_spec_rust_custom_str_impls/const.x/MyXDR.rs | 2 +- .../output/generator_spec_rust_custom_str_impls/enum.x/MyXDR.rs | 2 +- .../generator_spec_rust_custom_str_impls/nesting.x/MyXDR.rs | 2 +- .../generator_spec_rust_custom_str_impls/optional.x/MyXDR.rs | 2 +- .../generator_spec_rust_custom_str_impls/struct.x/MyXDR.rs | 2 +- .../output/generator_spec_rust_custom_str_impls/test.x/MyXDR.rs | 2 +- .../generator_spec_rust_custom_str_impls/union.x/MyXDR.rs | 2 +- 25 files changed, 25 insertions(+), 25 deletions(-) diff --git a/lib/xdrgen/generators/rust.rb b/lib/xdrgen/generators/rust.rb index ac6a8a718..83378626b 100644 --- a/lib/xdrgen/generators/rust.rb +++ b/lib/xdrgen/generators/rust.rb @@ -76,7 +76,7 @@ def render_top_matter(out) // #{@output.relative_source_paths.join("\n// ")} EOS out.break - out.puts "#![allow(clippy::missing_errors_doc, clippy::unreadable_literal)]" + out.puts "#![allow(clippy::missing_errors_doc, clippy::unreadable_literal, clippy::needless_question_mark)]" out.break source_paths_sha256_hashes = @output.relative_source_path_sha256_hashes out.puts <<-EOS.strip_heredoc diff --git a/spec/output/generator_spec_rust/block_comments.x/MyXDR.rs b/spec/output/generator_spec_rust/block_comments.x/MyXDR.rs index 9482a1915..925e06c32 100644 --- a/spec/output/generator_spec_rust/block_comments.x/MyXDR.rs +++ b/spec/output/generator_spec_rust/block_comments.x/MyXDR.rs @@ -1,7 +1,7 @@ // Module is generated from: // spec/fixtures/generator/block_comments.x -#![allow(clippy::missing_errors_doc, clippy::unreadable_literal)] +#![allow(clippy::missing_errors_doc, clippy::unreadable_literal, clippy::needless_question_mark)] /// `XDR_FILES_SHA256` is a list of pairs of source files and their SHA256 hashes. pub const XDR_FILES_SHA256: [(&str, &str); 1] = [ diff --git a/spec/output/generator_spec_rust/const.x/MyXDR.rs b/spec/output/generator_spec_rust/const.x/MyXDR.rs index 5463b6eba..735e0265e 100644 --- a/spec/output/generator_spec_rust/const.x/MyXDR.rs +++ b/spec/output/generator_spec_rust/const.x/MyXDR.rs @@ -1,7 +1,7 @@ // Module is generated from: // spec/fixtures/generator/const.x -#![allow(clippy::missing_errors_doc, clippy::unreadable_literal)] +#![allow(clippy::missing_errors_doc, clippy::unreadable_literal, clippy::needless_question_mark)] /// `XDR_FILES_SHA256` is a list of pairs of source files and their SHA256 hashes. pub const XDR_FILES_SHA256: [(&str, &str); 1] = [ diff --git a/spec/output/generator_spec_rust/enum.x/MyXDR.rs b/spec/output/generator_spec_rust/enum.x/MyXDR.rs index a0186d28b..2842c0d32 100644 --- a/spec/output/generator_spec_rust/enum.x/MyXDR.rs +++ b/spec/output/generator_spec_rust/enum.x/MyXDR.rs @@ -1,7 +1,7 @@ // Module is generated from: // spec/fixtures/generator/enum.x -#![allow(clippy::missing_errors_doc, clippy::unreadable_literal)] +#![allow(clippy::missing_errors_doc, clippy::unreadable_literal, clippy::needless_question_mark)] /// `XDR_FILES_SHA256` is a list of pairs of source files and their SHA256 hashes. pub const XDR_FILES_SHA256: [(&str, &str); 1] = [ diff --git a/spec/output/generator_spec_rust/nesting.x/MyXDR.rs b/spec/output/generator_spec_rust/nesting.x/MyXDR.rs index e6f36d9c3..c88154ab3 100644 --- a/spec/output/generator_spec_rust/nesting.x/MyXDR.rs +++ b/spec/output/generator_spec_rust/nesting.x/MyXDR.rs @@ -1,7 +1,7 @@ // Module is generated from: // spec/fixtures/generator/nesting.x -#![allow(clippy::missing_errors_doc, clippy::unreadable_literal)] +#![allow(clippy::missing_errors_doc, clippy::unreadable_literal, clippy::needless_question_mark)] /// `XDR_FILES_SHA256` is a list of pairs of source files and their SHA256 hashes. pub const XDR_FILES_SHA256: [(&str, &str); 1] = [ diff --git a/spec/output/generator_spec_rust/optional.x/MyXDR.rs b/spec/output/generator_spec_rust/optional.x/MyXDR.rs index 6a953c99e..fee6ae7da 100644 --- a/spec/output/generator_spec_rust/optional.x/MyXDR.rs +++ b/spec/output/generator_spec_rust/optional.x/MyXDR.rs @@ -1,7 +1,7 @@ // Module is generated from: // spec/fixtures/generator/optional.x -#![allow(clippy::missing_errors_doc, clippy::unreadable_literal)] +#![allow(clippy::missing_errors_doc, clippy::unreadable_literal, clippy::needless_question_mark)] /// `XDR_FILES_SHA256` is a list of pairs of source files and their SHA256 hashes. pub const XDR_FILES_SHA256: [(&str, &str); 1] = [ diff --git a/spec/output/generator_spec_rust/struct.x/MyXDR.rs b/spec/output/generator_spec_rust/struct.x/MyXDR.rs index c10313f19..96206ef71 100644 --- a/spec/output/generator_spec_rust/struct.x/MyXDR.rs +++ b/spec/output/generator_spec_rust/struct.x/MyXDR.rs @@ -1,7 +1,7 @@ // Module is generated from: // spec/fixtures/generator/struct.x -#![allow(clippy::missing_errors_doc, clippy::unreadable_literal)] +#![allow(clippy::missing_errors_doc, clippy::unreadable_literal, clippy::needless_question_mark)] /// `XDR_FILES_SHA256` is a list of pairs of source files and their SHA256 hashes. pub const XDR_FILES_SHA256: [(&str, &str); 1] = [ diff --git a/spec/output/generator_spec_rust/test.x/MyXDR.rs b/spec/output/generator_spec_rust/test.x/MyXDR.rs index 9386fcdb2..e5aac9e17 100644 --- a/spec/output/generator_spec_rust/test.x/MyXDR.rs +++ b/spec/output/generator_spec_rust/test.x/MyXDR.rs @@ -1,7 +1,7 @@ // Module is generated from: // spec/fixtures/generator/test.x -#![allow(clippy::missing_errors_doc, clippy::unreadable_literal)] +#![allow(clippy::missing_errors_doc, clippy::unreadable_literal, clippy::needless_question_mark)] /// `XDR_FILES_SHA256` is a list of pairs of source files and their SHA256 hashes. pub const XDR_FILES_SHA256: [(&str, &str); 1] = [ diff --git a/spec/output/generator_spec_rust/union.x/MyXDR.rs b/spec/output/generator_spec_rust/union.x/MyXDR.rs index b2ba8b915..c7c0f024d 100644 --- a/spec/output/generator_spec_rust/union.x/MyXDR.rs +++ b/spec/output/generator_spec_rust/union.x/MyXDR.rs @@ -1,7 +1,7 @@ // Module is generated from: // spec/fixtures/generator/union.x -#![allow(clippy::missing_errors_doc, clippy::unreadable_literal)] +#![allow(clippy::missing_errors_doc, clippy::unreadable_literal, clippy::needless_question_mark)] /// `XDR_FILES_SHA256` is a list of pairs of source files and their SHA256 hashes. pub const XDR_FILES_SHA256: [(&str, &str); 1] = [ diff --git a/spec/output/generator_spec_rust_custom_jsonschema_impls/block_comments.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_jsonschema_impls/block_comments.x/MyXDR.rs index 9482a1915..925e06c32 100644 --- a/spec/output/generator_spec_rust_custom_jsonschema_impls/block_comments.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_jsonschema_impls/block_comments.x/MyXDR.rs @@ -1,7 +1,7 @@ // Module is generated from: // spec/fixtures/generator/block_comments.x -#![allow(clippy::missing_errors_doc, clippy::unreadable_literal)] +#![allow(clippy::missing_errors_doc, clippy::unreadable_literal, clippy::needless_question_mark)] /// `XDR_FILES_SHA256` is a list of pairs of source files and their SHA256 hashes. pub const XDR_FILES_SHA256: [(&str, &str); 1] = [ diff --git a/spec/output/generator_spec_rust_custom_jsonschema_impls/const.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_jsonschema_impls/const.x/MyXDR.rs index 5463b6eba..735e0265e 100644 --- a/spec/output/generator_spec_rust_custom_jsonschema_impls/const.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_jsonschema_impls/const.x/MyXDR.rs @@ -1,7 +1,7 @@ // Module is generated from: // spec/fixtures/generator/const.x -#![allow(clippy::missing_errors_doc, clippy::unreadable_literal)] +#![allow(clippy::missing_errors_doc, clippy::unreadable_literal, clippy::needless_question_mark)] /// `XDR_FILES_SHA256` is a list of pairs of source files and their SHA256 hashes. pub const XDR_FILES_SHA256: [(&str, &str); 1] = [ diff --git a/spec/output/generator_spec_rust_custom_jsonschema_impls/enum.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_jsonschema_impls/enum.x/MyXDR.rs index c1949d871..b6085e759 100644 --- a/spec/output/generator_spec_rust_custom_jsonschema_impls/enum.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_jsonschema_impls/enum.x/MyXDR.rs @@ -1,7 +1,7 @@ // Module is generated from: // spec/fixtures/generator/enum.x -#![allow(clippy::missing_errors_doc, clippy::unreadable_literal)] +#![allow(clippy::missing_errors_doc, clippy::unreadable_literal, clippy::needless_question_mark)] /// `XDR_FILES_SHA256` is a list of pairs of source files and their SHA256 hashes. pub const XDR_FILES_SHA256: [(&str, &str); 1] = [ diff --git a/spec/output/generator_spec_rust_custom_jsonschema_impls/nesting.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_jsonschema_impls/nesting.x/MyXDR.rs index 8da3e4efe..dcb6da971 100644 --- a/spec/output/generator_spec_rust_custom_jsonschema_impls/nesting.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_jsonschema_impls/nesting.x/MyXDR.rs @@ -1,7 +1,7 @@ // Module is generated from: // spec/fixtures/generator/nesting.x -#![allow(clippy::missing_errors_doc, clippy::unreadable_literal)] +#![allow(clippy::missing_errors_doc, clippy::unreadable_literal, clippy::needless_question_mark)] /// `XDR_FILES_SHA256` is a list of pairs of source files and their SHA256 hashes. pub const XDR_FILES_SHA256: [(&str, &str); 1] = [ diff --git a/spec/output/generator_spec_rust_custom_jsonschema_impls/optional.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_jsonschema_impls/optional.x/MyXDR.rs index 2a0294a05..5ef7eb8f3 100644 --- a/spec/output/generator_spec_rust_custom_jsonschema_impls/optional.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_jsonschema_impls/optional.x/MyXDR.rs @@ -1,7 +1,7 @@ // Module is generated from: // spec/fixtures/generator/optional.x -#![allow(clippy::missing_errors_doc, clippy::unreadable_literal)] +#![allow(clippy::missing_errors_doc, clippy::unreadable_literal, clippy::needless_question_mark)] /// `XDR_FILES_SHA256` is a list of pairs of source files and their SHA256 hashes. pub const XDR_FILES_SHA256: [(&str, &str); 1] = [ diff --git a/spec/output/generator_spec_rust_custom_jsonschema_impls/struct.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_jsonschema_impls/struct.x/MyXDR.rs index fa6dc9473..c25eb15aa 100644 --- a/spec/output/generator_spec_rust_custom_jsonschema_impls/struct.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_jsonschema_impls/struct.x/MyXDR.rs @@ -1,7 +1,7 @@ // Module is generated from: // spec/fixtures/generator/struct.x -#![allow(clippy::missing_errors_doc, clippy::unreadable_literal)] +#![allow(clippy::missing_errors_doc, clippy::unreadable_literal, clippy::needless_question_mark)] /// `XDR_FILES_SHA256` is a list of pairs of source files and their SHA256 hashes. pub const XDR_FILES_SHA256: [(&str, &str); 1] = [ diff --git a/spec/output/generator_spec_rust_custom_jsonschema_impls/test.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_jsonschema_impls/test.x/MyXDR.rs index 05f26846c..f76a26c4d 100644 --- a/spec/output/generator_spec_rust_custom_jsonschema_impls/test.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_jsonschema_impls/test.x/MyXDR.rs @@ -1,7 +1,7 @@ // Module is generated from: // spec/fixtures/generator/test.x -#![allow(clippy::missing_errors_doc, clippy::unreadable_literal)] +#![allow(clippy::missing_errors_doc, clippy::unreadable_literal, clippy::needless_question_mark)] /// `XDR_FILES_SHA256` is a list of pairs of source files and their SHA256 hashes. pub const XDR_FILES_SHA256: [(&str, &str); 1] = [ diff --git a/spec/output/generator_spec_rust_custom_jsonschema_impls/union.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_jsonschema_impls/union.x/MyXDR.rs index 960a61484..bf9c226a7 100644 --- a/spec/output/generator_spec_rust_custom_jsonschema_impls/union.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_jsonschema_impls/union.x/MyXDR.rs @@ -1,7 +1,7 @@ // Module is generated from: // spec/fixtures/generator/union.x -#![allow(clippy::missing_errors_doc, clippy::unreadable_literal)] +#![allow(clippy::missing_errors_doc, clippy::unreadable_literal, clippy::needless_question_mark)] /// `XDR_FILES_SHA256` is a list of pairs of source files and their SHA256 hashes. pub const XDR_FILES_SHA256: [(&str, &str); 1] = [ diff --git a/spec/output/generator_spec_rust_custom_str_impls/block_comments.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_str_impls/block_comments.x/MyXDR.rs index 9482a1915..925e06c32 100644 --- a/spec/output/generator_spec_rust_custom_str_impls/block_comments.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_str_impls/block_comments.x/MyXDR.rs @@ -1,7 +1,7 @@ // Module is generated from: // spec/fixtures/generator/block_comments.x -#![allow(clippy::missing_errors_doc, clippy::unreadable_literal)] +#![allow(clippy::missing_errors_doc, clippy::unreadable_literal, clippy::needless_question_mark)] /// `XDR_FILES_SHA256` is a list of pairs of source files and their SHA256 hashes. pub const XDR_FILES_SHA256: [(&str, &str); 1] = [ diff --git a/spec/output/generator_spec_rust_custom_str_impls/const.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_str_impls/const.x/MyXDR.rs index 5463b6eba..735e0265e 100644 --- a/spec/output/generator_spec_rust_custom_str_impls/const.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_str_impls/const.x/MyXDR.rs @@ -1,7 +1,7 @@ // Module is generated from: // spec/fixtures/generator/const.x -#![allow(clippy::missing_errors_doc, clippy::unreadable_literal)] +#![allow(clippy::missing_errors_doc, clippy::unreadable_literal, clippy::needless_question_mark)] /// `XDR_FILES_SHA256` is a list of pairs of source files and their SHA256 hashes. pub const XDR_FILES_SHA256: [(&str, &str); 1] = [ diff --git a/spec/output/generator_spec_rust_custom_str_impls/enum.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_str_impls/enum.x/MyXDR.rs index e90df36e5..43e09ebca 100644 --- a/spec/output/generator_spec_rust_custom_str_impls/enum.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_str_impls/enum.x/MyXDR.rs @@ -1,7 +1,7 @@ // Module is generated from: // spec/fixtures/generator/enum.x -#![allow(clippy::missing_errors_doc, clippy::unreadable_literal)] +#![allow(clippy::missing_errors_doc, clippy::unreadable_literal, clippy::needless_question_mark)] /// `XDR_FILES_SHA256` is a list of pairs of source files and their SHA256 hashes. pub const XDR_FILES_SHA256: [(&str, &str); 1] = [ diff --git a/spec/output/generator_spec_rust_custom_str_impls/nesting.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_str_impls/nesting.x/MyXDR.rs index 89de975e1..5a29f359f 100644 --- a/spec/output/generator_spec_rust_custom_str_impls/nesting.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_str_impls/nesting.x/MyXDR.rs @@ -1,7 +1,7 @@ // Module is generated from: // spec/fixtures/generator/nesting.x -#![allow(clippy::missing_errors_doc, clippy::unreadable_literal)] +#![allow(clippy::missing_errors_doc, clippy::unreadable_literal, clippy::needless_question_mark)] /// `XDR_FILES_SHA256` is a list of pairs of source files and their SHA256 hashes. pub const XDR_FILES_SHA256: [(&str, &str); 1] = [ diff --git a/spec/output/generator_spec_rust_custom_str_impls/optional.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_str_impls/optional.x/MyXDR.rs index 9ed8491dd..57f860332 100644 --- a/spec/output/generator_spec_rust_custom_str_impls/optional.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_str_impls/optional.x/MyXDR.rs @@ -1,7 +1,7 @@ // Module is generated from: // spec/fixtures/generator/optional.x -#![allow(clippy::missing_errors_doc, clippy::unreadable_literal)] +#![allow(clippy::missing_errors_doc, clippy::unreadable_literal, clippy::needless_question_mark)] /// `XDR_FILES_SHA256` is a list of pairs of source files and their SHA256 hashes. pub const XDR_FILES_SHA256: [(&str, &str); 1] = [ diff --git a/spec/output/generator_spec_rust_custom_str_impls/struct.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_str_impls/struct.x/MyXDR.rs index f703197c7..09e40232a 100644 --- a/spec/output/generator_spec_rust_custom_str_impls/struct.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_str_impls/struct.x/MyXDR.rs @@ -1,7 +1,7 @@ // Module is generated from: // spec/fixtures/generator/struct.x -#![allow(clippy::missing_errors_doc, clippy::unreadable_literal)] +#![allow(clippy::missing_errors_doc, clippy::unreadable_literal, clippy::needless_question_mark)] /// `XDR_FILES_SHA256` is a list of pairs of source files and their SHA256 hashes. pub const XDR_FILES_SHA256: [(&str, &str); 1] = [ diff --git a/spec/output/generator_spec_rust_custom_str_impls/test.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_str_impls/test.x/MyXDR.rs index 0eaaffb2e..be4c6845c 100644 --- a/spec/output/generator_spec_rust_custom_str_impls/test.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_str_impls/test.x/MyXDR.rs @@ -1,7 +1,7 @@ // Module is generated from: // spec/fixtures/generator/test.x -#![allow(clippy::missing_errors_doc, clippy::unreadable_literal)] +#![allow(clippy::missing_errors_doc, clippy::unreadable_literal, clippy::needless_question_mark)] /// `XDR_FILES_SHA256` is a list of pairs of source files and their SHA256 hashes. pub const XDR_FILES_SHA256: [(&str, &str); 1] = [ diff --git a/spec/output/generator_spec_rust_custom_str_impls/union.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_str_impls/union.x/MyXDR.rs index 971897b4a..853087ece 100644 --- a/spec/output/generator_spec_rust_custom_str_impls/union.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_str_impls/union.x/MyXDR.rs @@ -1,7 +1,7 @@ // Module is generated from: // spec/fixtures/generator/union.x -#![allow(clippy::missing_errors_doc, clippy::unreadable_literal)] +#![allow(clippy::missing_errors_doc, clippy::unreadable_literal, clippy::needless_question_mark)] /// `XDR_FILES_SHA256` is a list of pairs of source files and their SHA256 hashes. pub const XDR_FILES_SHA256: [(&str, &str); 1] = [ From 35f955ce4bad775cfefd7f46e824a111e79a4da6 Mon Sep 17 00:00:00 2001 From: Jun Luo <4catcode@gmail.com> Date: Sat, 21 Sep 2024 08:40:20 +0800 Subject: [PATCH 4/9] add `#[cfg(feature = "embedded_io")]` --- lib/xdrgen/generators/rust.rb | 24 ++--- lib/xdrgen/generators/rust/src/types.rs | 114 ++++++++++++------------ 2 files changed, 68 insertions(+), 70 deletions(-) diff --git a/lib/xdrgen/generators/rust.rb b/lib/xdrgen/generators/rust.rb index 83378626b..bfab30c33 100644 --- a/lib/xdrgen/generators/rust.rb +++ b/lib/xdrgen/generators/rust.rb @@ -175,7 +175,7 @@ def render_enum_of_all_types(out, types) pub const VARIANTS: [TypeVariant; #{types.count}] = [ #{types.map { |t| "TypeVariant::#{t}," }.join("\n")} ]; pub const VARIANTS_STR: [&'static str; #{types.count}] = [ #{types.map { |t| "\"#{t}\"," }.join("\n")} ]; - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] #[allow(clippy::too_many_lines)] pub fn read_xdr(v: TypeVariant, r: &mut Limited) -> Result { match v { @@ -190,7 +190,7 @@ def render_enum_of_all_types(out, types) Ok(t) } - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] pub fn read_xdr_to_end(v: TypeVariant, r: &mut Limited) -> Result { let s = Self::read_xdr(v, r)?; // Check that any further reads, such as this read of one byte, read no @@ -234,7 +234,7 @@ def render_enum_of_all_types(out, types) } } - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] pub fn from_xdr>(v: TypeVariant, bytes: B, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(v, &mut cursor)?; @@ -318,7 +318,7 @@ def render_enum_of_all_types(out, types) } impl WriteXdr for Type { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] #[allow(clippy::too_many_lines)] fn write_xdr(&self, w: &mut Limited) -> Result<()> { match self { @@ -407,7 +407,7 @@ def render_struct(out, struct) out.puts "" out.puts <<-EOS.strip_heredoc impl ReadXdr for #{name struct} { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { Ok(Self{ @@ -420,7 +420,7 @@ def render_struct(out, struct) } impl WriteXdr for #{name struct} { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { #{struct.members.map do |m| @@ -517,7 +517,7 @@ def render_enum(out, enum) } impl ReadXdr for #{name enum} { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let e = i32::read_xdr(r)?; @@ -528,7 +528,7 @@ def render_enum(out, enum) } impl WriteXdr for #{name enum} { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i: i32 = (*self).into(); @@ -656,7 +656,7 @@ def render_union(out, union) impl Union<#{discriminant_type}> for #{name union} {} impl ReadXdr for #{name union} { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let dv: #{discriminant_type} = <#{discriminant_type} as ReadXdr>::read_xdr(r)?; @@ -678,7 +678,7 @@ def render_union(out, union) } impl WriteXdr for #{name union} { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { self.discriminant().write_xdr(w)?; @@ -816,7 +816,7 @@ def render_typedef(out, typedef) } impl ReadXdr for #{name typedef} { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = #{reference_to_call(typedef, typedef.type)}::read_xdr(r)?; @@ -827,7 +827,7 @@ def render_typedef(out, typedef) } impl WriteXdr for #{name typedef} { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w|{ self.0.write_xdr(w) }) } diff --git a/lib/xdrgen/generators/rust/src/types.rs b/lib/xdrgen/generators/rust/src/types.rs index 1614fba29..537172406 100644 --- a/lib/xdrgen/generators/rust/src/types.rs +++ b/lib/xdrgen/generators/rust/src/types.rs @@ -40,7 +40,7 @@ use std::{ io::{BufRead, BufReader, Cursor, Read, Write}, }; -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] use embedded_io_extras::{Cursor, Error as _, ErrorType, Read, Write}; /// Error contains all errors returned by functions in this crate. It can be @@ -58,7 +58,7 @@ pub enum Error { InvalidHex, #[cfg(feature = "std")] Io(io::Error), - #[cfg(all(not(feature = "std"), feature = "alloc"))] + #[cfg(feature = "embedded_io")] Io(embedded_io_extras::ErrorKind), DepthLimitExceeded, #[cfg(feature = "serde_json")] @@ -76,15 +76,14 @@ impl PartialEq for Error { // case for comparing errors outputted by the XDR library is for // error case testing, and a lack of the ability to compare has a // detrimental affect on failure testing, so this is a tradeoff. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] (Self::Io(l), Self::Io(r)) => l.kind() == r.kind(), _ => core::mem::discriminant(self) == core::mem::discriminant(other), } } } - -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl embedded_io_extras::Error for Error { fn kind(&self) -> embedded_io_extras::ErrorKind { match self { @@ -94,7 +93,7 @@ impl embedded_io_extras::Error for Error { } } -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl From> for Error { fn from(value: embedded_io_extras::ReadExactError) -> Self { match value { @@ -130,7 +129,7 @@ impl fmt::Display for Error { Error::InvalidHex => write!(f, "hex invalid"), #[cfg(feature = "std")] Error::Io(e) => write!(f, "{e}"), - #[cfg(all(not(feature = "std"), feature = "alloc"))] + #[cfg(feature = "embedded_io")] Error::Io(_) => write!(f, "io error"), Error::DepthLimitExceeded => write!(f, "depth limit exceeded"), #[cfg(feature = "serde_json")] @@ -184,7 +183,7 @@ impl From for () { #[allow(dead_code)] type Result = core::result::Result; -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl ErrorType for Limited { type Error = Error; } /// Name defines types that assign a static name to their value, such as the @@ -220,7 +219,7 @@ where /// `Limits` contains the limits that a limited reader or writer will be /// constrained to. -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] #[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct Limits { /// Defines the maximum depth for recursive calls in `Read/WriteXdr` to @@ -237,7 +236,7 @@ pub struct Limits { pub len: usize, } -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] impl Limits { #[must_use] pub fn none() -> Self { @@ -268,13 +267,13 @@ impl Limits { /// /// Intended for use with readers and writers and limiting their reads and /// writes. -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] pub struct Limited { pub inner: L, pub(crate) limits: Limits, } -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] impl Limited { /// Constructs a new `Limited`. /// @@ -327,8 +326,7 @@ impl Read for Limited { } } - -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl Read for Limited { /// Forwards the read operation to the wrapped object. fn read(&mut self, buf: &mut [u8]) -> core::result::Result { @@ -362,7 +360,7 @@ impl Write for Limited { } } -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl Write for Limited { /// Forwards the write operation to the wrapped object. fn write(&mut self, buf: &[u8]) -> core::result::Result { @@ -447,7 +445,7 @@ where /// /// Use [`ReadXdR: Read_xdr_to_end`] when the intent is for all bytes in the /// read implementation to be consumed by the read. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result; /// Construct the type from the XDR bytes base64 encoded. @@ -482,7 +480,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr_to_end(r: &mut Limited) -> Result { let s = Self::read_xdr(r)?; // Check that any further reads, such as this read of one byte, read no @@ -522,7 +520,7 @@ where /// /// Use [`ReadXdR: Read_xdr_into_to_end`] when the intent is for all bytes /// in the read implementation to be consumed by the read. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr_into(&mut self, r: &mut Limited) -> Result<()> { *self = Self::read_xdr(r)?; Ok(()) @@ -546,7 +544,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr_into_to_end(&mut self, r: &mut Limited) -> Result<()> { Self::read_xdr_into(self, r)?; // Check that any further reads, such as this read of one byte, read no @@ -595,7 +593,7 @@ where /// /// An error is returned if the bytes are not completely consumed by the /// deserialization. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn from_xdr(bytes: impl AsRef<[u8]>, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(&mut cursor)?; @@ -619,10 +617,10 @@ where } pub trait WriteXdr { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()>; - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn to_xdr(&self, limits: Limits) -> Result> { let mut cursor = Limited::new(Cursor::new(vec![]), limits); self.write_xdr(&mut cursor)?; @@ -644,13 +642,13 @@ pub trait WriteXdr { /// `Pad_len` returns the number of bytes to pad an XDR value of the given /// length to make the final serialized size a multiple of 4. -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] fn pad_len(len: usize) -> usize { (4 - (len % 4)) % 4 } impl ReadXdr for i32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -662,7 +660,7 @@ impl ReadXdr for i32 { } impl WriteXdr for i32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -673,7 +671,7 @@ impl WriteXdr for i32 { } impl ReadXdr for u32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -685,7 +683,7 @@ impl ReadXdr for u32 { } impl WriteXdr for u32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -696,7 +694,7 @@ impl WriteXdr for u32 { } impl ReadXdr for i64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -708,7 +706,7 @@ impl ReadXdr for i64 { } impl WriteXdr for i64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -719,7 +717,7 @@ impl WriteXdr for i64 { } impl ReadXdr for u64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -731,7 +729,7 @@ impl ReadXdr for u64 { } impl WriteXdr for u64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -742,35 +740,35 @@ impl WriteXdr for u64 { } impl ReadXdr for f32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for f64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for bool { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -781,7 +779,7 @@ impl ReadXdr for bool { } impl WriteXdr for bool { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i = u32::from(*self); // true = 1, false = 0 @@ -791,7 +789,7 @@ impl WriteXdr for bool { } impl ReadXdr for Option { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -808,7 +806,7 @@ impl ReadXdr for Option { } impl WriteXdr for Option { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { if let Some(t) = self { @@ -823,35 +821,35 @@ impl WriteXdr for Option { } impl ReadXdr for Box { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| Ok(Box::new(T::read_xdr(r)?))) } } impl WriteXdr for Box { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| T::write_xdr(self, w)) } } impl ReadXdr for () { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(_r: &mut Limited) -> Result { Ok(()) } } impl WriteXdr for () { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { Ok(()) } } impl ReadXdr for [u8; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { r.consume_len(N)?; @@ -870,7 +868,7 @@ impl ReadXdr for [u8; N] { } impl WriteXdr for [u8; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { w.consume_len(N)?; @@ -884,7 +882,7 @@ impl WriteXdr for [u8; N] { } impl ReadXdr for [T; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let mut vec = Vec::with_capacity(N); @@ -899,7 +897,7 @@ impl ReadXdr for [T; N] { } impl WriteXdr for [T; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { for t in self { @@ -1258,7 +1256,7 @@ impl<'a, const MAX: u32> TryFrom<&'a VecM> for &'a str { } impl ReadXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1285,7 +1283,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1305,7 +1303,7 @@ impl WriteXdr for VecM { } impl ReadXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len = u32::read_xdr(r)?; @@ -1325,7 +1323,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1698,7 +1696,7 @@ impl<'a, const MAX: u32> TryFrom<&'a BytesM> for &'a str { } impl ReadXdr for BytesM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1725,7 +1723,7 @@ impl ReadXdr for BytesM { } impl WriteXdr for BytesM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2101,7 +2099,7 @@ impl<'a, const MAX: u32> TryFrom<&'a StringM> for &'a str { } impl ReadXdr for StringM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -2128,7 +2126,7 @@ impl ReadXdr for StringM { } impl WriteXdr for StringM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2174,7 +2172,7 @@ impl ReadXdr for Frame where T: ReadXdr, { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { // Read the frame header value that contains 1 flag-bit and a 33-bit length. // - The 1 flag bit is 0 when there are more frames for the same record. @@ -2194,7 +2192,7 @@ where } } -#[cfg(all(test, feature = "alloc"))] +#[cfg(all(test, any(feature = "std", feature = "embedded_io")))] mod tests { use super::*; @@ -2304,7 +2302,7 @@ mod tests { } } -#[cfg(all(test, feature = "alloc"))] +#[cfg(all(test, any(feature = "std", feature = "embedded_io")))] mod test { use super::*; From 2cb36691503ce12ebf146858fc11d04d9b3263db Mon Sep 17 00:00:00 2001 From: Jun Luo <4catcode@gmail.com> Date: Sat, 21 Sep 2024 10:42:03 +0800 Subject: [PATCH 5/9] add io test --- lib/xdrgen/generators/rust/src/types.rs | 213 +++++++++ .../block_comments.x/MyXDR.rs | 339 ++++++++++++--- .../generator_spec_rust/const.x/MyXDR.rs | 335 +++++++++++--- .../generator_spec_rust/enum.x/MyXDR.rs | 351 ++++++++++++--- .../generator_spec_rust/nesting.x/MyXDR.rs | 351 ++++++++++++--- .../generator_spec_rust/optional.x/MyXDR.rs | 339 ++++++++++++--- .../generator_spec_rust/struct.x/MyXDR.rs | 339 ++++++++++++--- .../generator_spec_rust/test.x/MyXDR.rs | 411 +++++++++++++----- .../generator_spec_rust/union.x/MyXDR.rs | 351 ++++++++++++--- .../block_comments.x/MyXDR.rs | 339 ++++++++++++--- .../const.x/MyXDR.rs | 335 +++++++++++--- .../enum.x/MyXDR.rs | 351 ++++++++++++--- .../nesting.x/MyXDR.rs | 351 ++++++++++++--- .../optional.x/MyXDR.rs | 339 ++++++++++++--- .../struct.x/MyXDR.rs | 339 ++++++++++++--- .../test.x/MyXDR.rs | 411 +++++++++++++----- .../union.x/MyXDR.rs | 351 ++++++++++++--- .../block_comments.x/MyXDR.rs | 339 ++++++++++++--- .../const.x/MyXDR.rs | 335 +++++++++++--- .../enum.x/MyXDR.rs | 351 ++++++++++++--- .../nesting.x/MyXDR.rs | 351 ++++++++++++--- .../optional.x/MyXDR.rs | 339 ++++++++++++--- .../struct.x/MyXDR.rs | 339 ++++++++++++--- .../test.x/MyXDR.rs | 411 +++++++++++++----- .../union.x/MyXDR.rs | 351 ++++++++++++--- 25 files changed, 6969 insertions(+), 1692 deletions(-) diff --git a/lib/xdrgen/generators/rust/src/types.rs b/lib/xdrgen/generators/rust/src/types.rs index 537172406..73313bd1d 100644 --- a/lib/xdrgen/generators/rust/src/types.rs +++ b/lib/xdrgen/generators/rust/src/types.rs @@ -2814,3 +2814,216 @@ mod test { assert_eq!(v.to_option(), Some(1)); } } + +#[cfg(all(test, any(feature = "std", feature = "embedded_io")))] +mod test_io { + // We will use different IO libraries according to the feature, + // we hope the selected IO library can work as expected + + use super::*; + + #[test] + fn test_read_exact_success() { + let data = b"The quick brown fox jumps over the lazy dog."; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 19]; // Exactly the length of "The quick brown fox" + + // Attempt to read exactly 19 bytes + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"The quick brown fox"); + assert_eq!(cursor.position(), 19); + } + + #[test] + fn test_read_exact_less_than_available() { + let data = b"Hello, Rust!"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 5]; + + // Attempt to read 5 bytes from the start + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Hello"); + assert_eq!(cursor.position(), 5); + } + + #[test] + fn test_read_exact_exact_eof() { + let data = b"Data"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 4]; + + // Attempt to read exactly 4 bytes, which is the entire buffer + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Data"); + assert_eq!(cursor.position(), 4); + + // Further attempt to read should fail with EOF + let mut buffer_eof = [0u8; 1]; + let result = cursor.read_exact(&mut buffer_eof); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 4); // Position should remain at EOF + } + + #[test] + fn test_read_exact_past_eof() { + let data = b"Short"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 10]; // Requesting more bytes than available + + // Attempt to read 10 bytes from a 5-byte buffer + let result = cursor.read_exact(&mut buffer); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 5); // Position should move to EOF + } + + #[test] + fn test_read_exact_empty_buffer() { + let data = b"Non-empty"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 0]; // Zero-length buffer + + // Attempt to read zero bytes + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(cursor.position(), 0); // Position should remain unchanged + } + + #[test] + fn test_read_exact_from_empty_cursor() { + let data: &[u8] = b""; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 5]; + + // Attempt to read from an empty cursor + let result = cursor.read_exact(&mut buffer); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 0); // Position remains at 0 + } + + #[test] + fn test_read_exact_multiple_reads() { + let data = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + let mut cursor = Cursor::new(data); + + let mut buffer1 = [0u8; 10]; + let mut buffer2 = [0u8; 10]; + let mut buffer3 = [0u8; 10]; // Only 6 bytes left + + // First read: 10 bytes + assert!(cursor.read_exact(&mut buffer1).is_ok()); + assert_eq!(&buffer1, b"ABCDEFGHIJ"); + assert_eq!(cursor.position(), 10); + + // Second read: 10 bytes + assert!(cursor.read_exact(&mut buffer2).is_ok()); + assert_eq!(&buffer2, b"KLMNOPQRST"); + assert_eq!(cursor.position(), 20); + + // Third read: Attempt to read 10 bytes, but only 6 are available + let result = cursor.read_exact(&mut buffer3); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + // read_exact makes no promises about the content of the buffer on error + // assert_eq!(&buffer3[..6], b"UVWXYZ"); + assert_eq!(cursor.position(), 26); // Position should be at EOF + } + + #[test] + fn test_cursor_read_exact_after_eof() { + let data = b"End"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 3]; + + // First read: read the entire buffer + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"End"); + assert_eq!(cursor.position(), 3); + + // Second read: attempt to read again, should fail + let mut buffer_eof = [0u8; 1]; + let result = cursor.read_exact(&mut buffer_eof); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 3); // Position remains at EOF + } + + #[test] + fn test_slice_read_exact_success() { + let data = b"SliceReadTest"; + let mut slice = &data[..]; + let mut buffer = [0u8; 13]; // Exact length + + // Using Read trait directly on slice + assert!(slice.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"SliceReadTest"); + } + + #[test] + fn test_slice_read_exact_partial() { + let data = b"SlicePartial"; + let mut slice = &data[..]; + let mut buffer = [0u8; 20]; // Request more bytes than available + + // Using Read trait directly on slice + let result = slice.read_exact(&mut buffer); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + // read_exact makes no promises about the content of the buffer on error + } +} diff --git a/spec/output/generator_spec_rust/block_comments.x/MyXDR.rs b/spec/output/generator_spec_rust/block_comments.x/MyXDR.rs index 925e06c32..b219d1dd8 100644 --- a/spec/output/generator_spec_rust/block_comments.x/MyXDR.rs +++ b/spec/output/generator_spec_rust/block_comments.x/MyXDR.rs @@ -50,7 +50,7 @@ use std::{ io::{BufRead, BufReader, Cursor, Read, Write}, }; -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] use embedded_io_extras::{Cursor, Error as _, ErrorType, Read, Write}; /// Error contains all errors returned by functions in this crate. It can be @@ -68,7 +68,7 @@ pub enum Error { InvalidHex, #[cfg(feature = "std")] Io(io::Error), - #[cfg(all(not(feature = "std"), feature = "alloc"))] + #[cfg(feature = "embedded_io")] Io(embedded_io_extras::ErrorKind), DepthLimitExceeded, #[cfg(feature = "serde_json")] @@ -86,15 +86,14 @@ impl PartialEq for Error { // case for comparing errors outputted by the XDR library is for // error case testing, and a lack of the ability to compare has a // detrimental affect on failure testing, so this is a tradeoff. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] (Self::Io(l), Self::Io(r)) => l.kind() == r.kind(), _ => core::mem::discriminant(self) == core::mem::discriminant(other), } } } - -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl embedded_io_extras::Error for Error { fn kind(&self) -> embedded_io_extras::ErrorKind { match self { @@ -104,7 +103,7 @@ impl embedded_io_extras::Error for Error { } } -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl From> for Error { fn from(value: embedded_io_extras::ReadExactError) -> Self { match value { @@ -140,7 +139,7 @@ impl fmt::Display for Error { Error::InvalidHex => write!(f, "hex invalid"), #[cfg(feature = "std")] Error::Io(e) => write!(f, "{e}"), - #[cfg(all(not(feature = "std"), feature = "alloc"))] + #[cfg(feature = "embedded_io")] Error::Io(_) => write!(f, "io error"), Error::DepthLimitExceeded => write!(f, "depth limit exceeded"), #[cfg(feature = "serde_json")] @@ -194,7 +193,7 @@ impl From for () { #[allow(dead_code)] type Result = core::result::Result; -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl ErrorType for Limited { type Error = Error; } /// Name defines types that assign a static name to their value, such as the @@ -230,7 +229,7 @@ where /// `Limits` contains the limits that a limited reader or writer will be /// constrained to. -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] #[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct Limits { /// Defines the maximum depth for recursive calls in `Read/WriteXdr` to @@ -247,7 +246,7 @@ pub struct Limits { pub len: usize, } -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] impl Limits { #[must_use] pub fn none() -> Self { @@ -278,13 +277,13 @@ impl Limits { /// /// Intended for use with readers and writers and limiting their reads and /// writes. -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] pub struct Limited { pub inner: L, pub(crate) limits: Limits, } -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] impl Limited { /// Constructs a new `Limited`. /// @@ -337,8 +336,7 @@ impl Read for Limited { } } - -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl Read for Limited { /// Forwards the read operation to the wrapped object. fn read(&mut self, buf: &mut [u8]) -> core::result::Result { @@ -372,7 +370,7 @@ impl Write for Limited { } } -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl Write for Limited { /// Forwards the write operation to the wrapped object. fn write(&mut self, buf: &[u8]) -> core::result::Result { @@ -457,7 +455,7 @@ where /// /// Use [`ReadXdR: Read_xdr_to_end`] when the intent is for all bytes in the /// read implementation to be consumed by the read. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result; /// Construct the type from the XDR bytes base64 encoded. @@ -492,7 +490,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr_to_end(r: &mut Limited) -> Result { let s = Self::read_xdr(r)?; // Check that any further reads, such as this read of one byte, read no @@ -532,7 +530,7 @@ where /// /// Use [`ReadXdR: Read_xdr_into_to_end`] when the intent is for all bytes /// in the read implementation to be consumed by the read. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr_into(&mut self, r: &mut Limited) -> Result<()> { *self = Self::read_xdr(r)?; Ok(()) @@ -556,7 +554,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr_into_to_end(&mut self, r: &mut Limited) -> Result<()> { Self::read_xdr_into(self, r)?; // Check that any further reads, such as this read of one byte, read no @@ -605,7 +603,7 @@ where /// /// An error is returned if the bytes are not completely consumed by the /// deserialization. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn from_xdr(bytes: impl AsRef<[u8]>, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(&mut cursor)?; @@ -629,10 +627,10 @@ where } pub trait WriteXdr { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()>; - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn to_xdr(&self, limits: Limits) -> Result> { let mut cursor = Limited::new(Cursor::new(vec![]), limits); self.write_xdr(&mut cursor)?; @@ -654,13 +652,13 @@ pub trait WriteXdr { /// `Pad_len` returns the number of bytes to pad an XDR value of the given /// length to make the final serialized size a multiple of 4. -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] fn pad_len(len: usize) -> usize { (4 - (len % 4)) % 4 } impl ReadXdr for i32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -672,7 +670,7 @@ impl ReadXdr for i32 { } impl WriteXdr for i32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -683,7 +681,7 @@ impl WriteXdr for i32 { } impl ReadXdr for u32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -695,7 +693,7 @@ impl ReadXdr for u32 { } impl WriteXdr for u32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -706,7 +704,7 @@ impl WriteXdr for u32 { } impl ReadXdr for i64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -718,7 +716,7 @@ impl ReadXdr for i64 { } impl WriteXdr for i64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -729,7 +727,7 @@ impl WriteXdr for i64 { } impl ReadXdr for u64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -741,7 +739,7 @@ impl ReadXdr for u64 { } impl WriteXdr for u64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -752,35 +750,35 @@ impl WriteXdr for u64 { } impl ReadXdr for f32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for f64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for bool { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -791,7 +789,7 @@ impl ReadXdr for bool { } impl WriteXdr for bool { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i = u32::from(*self); // true = 1, false = 0 @@ -801,7 +799,7 @@ impl WriteXdr for bool { } impl ReadXdr for Option { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -818,7 +816,7 @@ impl ReadXdr for Option { } impl WriteXdr for Option { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { if let Some(t) = self { @@ -833,35 +831,35 @@ impl WriteXdr for Option { } impl ReadXdr for Box { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| Ok(Box::new(T::read_xdr(r)?))) } } impl WriteXdr for Box { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| T::write_xdr(self, w)) } } impl ReadXdr for () { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(_r: &mut Limited) -> Result { Ok(()) } } impl WriteXdr for () { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { Ok(()) } } impl ReadXdr for [u8; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { r.consume_len(N)?; @@ -880,7 +878,7 @@ impl ReadXdr for [u8; N] { } impl WriteXdr for [u8; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { w.consume_len(N)?; @@ -894,7 +892,7 @@ impl WriteXdr for [u8; N] { } impl ReadXdr for [T; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let mut vec = Vec::with_capacity(N); @@ -909,7 +907,7 @@ impl ReadXdr for [T; N] { } impl WriteXdr for [T; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { for t in self { @@ -1268,7 +1266,7 @@ impl<'a, const MAX: u32> TryFrom<&'a VecM> for &'a str { } impl ReadXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1295,7 +1293,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1315,7 +1313,7 @@ impl WriteXdr for VecM { } impl ReadXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len = u32::read_xdr(r)?; @@ -1335,7 +1333,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1708,7 +1706,7 @@ impl<'a, const MAX: u32> TryFrom<&'a BytesM> for &'a str { } impl ReadXdr for BytesM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1735,7 +1733,7 @@ impl ReadXdr for BytesM { } impl WriteXdr for BytesM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2111,7 +2109,7 @@ impl<'a, const MAX: u32> TryFrom<&'a StringM> for &'a str { } impl ReadXdr for StringM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -2138,7 +2136,7 @@ impl ReadXdr for StringM { } impl WriteXdr for StringM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2184,7 +2182,7 @@ impl ReadXdr for Frame where T: ReadXdr, { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { // Read the frame header value that contains 1 flag-bit and a 33-bit length. // - The 1 flag bit is 0 when there are more frames for the same record. @@ -2204,7 +2202,7 @@ where } } -#[cfg(all(test, feature = "alloc"))] +#[cfg(all(test, any(feature = "std", feature = "embedded_io")))] mod tests { use super::*; @@ -2314,7 +2312,7 @@ mod tests { } } -#[cfg(all(test, feature = "alloc"))] +#[cfg(all(test, any(feature = "std", feature = "embedded_io")))] mod test { use super::*; @@ -2827,6 +2825,219 @@ mod test { } } +#[cfg(all(test, any(feature = "std", feature = "embedded_io")))] +mod test_io { + // We will use different IO libraries according to the feature, + // we hope the selected IO library can work as expected + + use super::*; + + #[test] + fn test_read_exact_success() { + let data = b"The quick brown fox jumps over the lazy dog."; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 19]; // Exactly the length of "The quick brown fox" + + // Attempt to read exactly 19 bytes + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"The quick brown fox"); + assert_eq!(cursor.position(), 19); + } + + #[test] + fn test_read_exact_less_than_available() { + let data = b"Hello, Rust!"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 5]; + + // Attempt to read 5 bytes from the start + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Hello"); + assert_eq!(cursor.position(), 5); + } + + #[test] + fn test_read_exact_exact_eof() { + let data = b"Data"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 4]; + + // Attempt to read exactly 4 bytes, which is the entire buffer + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Data"); + assert_eq!(cursor.position(), 4); + + // Further attempt to read should fail with EOF + let mut buffer_eof = [0u8; 1]; + let result = cursor.read_exact(&mut buffer_eof); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 4); // Position should remain at EOF + } + + #[test] + fn test_read_exact_past_eof() { + let data = b"Short"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 10]; // Requesting more bytes than available + + // Attempt to read 10 bytes from a 5-byte buffer + let result = cursor.read_exact(&mut buffer); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 5); // Position should move to EOF + } + + #[test] + fn test_read_exact_empty_buffer() { + let data = b"Non-empty"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 0]; // Zero-length buffer + + // Attempt to read zero bytes + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(cursor.position(), 0); // Position should remain unchanged + } + + #[test] + fn test_read_exact_from_empty_cursor() { + let data: &[u8] = b""; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 5]; + + // Attempt to read from an empty cursor + let result = cursor.read_exact(&mut buffer); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 0); // Position remains at 0 + } + + #[test] + fn test_read_exact_multiple_reads() { + let data = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + let mut cursor = Cursor::new(data); + + let mut buffer1 = [0u8; 10]; + let mut buffer2 = [0u8; 10]; + let mut buffer3 = [0u8; 10]; // Only 6 bytes left + + // First read: 10 bytes + assert!(cursor.read_exact(&mut buffer1).is_ok()); + assert_eq!(&buffer1, b"ABCDEFGHIJ"); + assert_eq!(cursor.position(), 10); + + // Second read: 10 bytes + assert!(cursor.read_exact(&mut buffer2).is_ok()); + assert_eq!(&buffer2, b"KLMNOPQRST"); + assert_eq!(cursor.position(), 20); + + // Third read: Attempt to read 10 bytes, but only 6 are available + let result = cursor.read_exact(&mut buffer3); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + // read_exact makes no promises about the content of the buffer on error + // assert_eq!(&buffer3[..6], b"UVWXYZ"); + assert_eq!(cursor.position(), 26); // Position should be at EOF + } + + #[test] + fn test_cursor_read_exact_after_eof() { + let data = b"End"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 3]; + + // First read: read the entire buffer + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"End"); + assert_eq!(cursor.position(), 3); + + // Second read: attempt to read again, should fail + let mut buffer_eof = [0u8; 1]; + let result = cursor.read_exact(&mut buffer_eof); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 3); // Position remains at EOF + } + + #[test] + fn test_slice_read_exact_success() { + let data = b"SliceReadTest"; + let mut slice = &data[..]; + let mut buffer = [0u8; 13]; // Exact length + + // Using Read trait directly on slice + assert!(slice.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"SliceReadTest"); + } + + #[test] + fn test_slice_read_exact_partial() { + let data = b"SlicePartial"; + let mut slice = &data[..]; + let mut buffer = [0u8; 20]; // Request more bytes than available + + // Using Read trait directly on slice + let result = slice.read_exact(&mut buffer); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + // read_exact makes no promises about the content of the buffer on error + } +} + /// AccountFlags is an XDR Enum defines as: /// /// ```text @@ -2905,7 +3116,7 @@ impl From for i32 { } impl ReadXdr for AccountFlags { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let e = i32::read_xdr(r)?; @@ -2916,7 +3127,7 @@ impl ReadXdr for AccountFlags { } impl WriteXdr for AccountFlags { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i: i32 = (*self).into(); @@ -3004,7 +3215,7 @@ impl Type { pub const VARIANTS: [TypeVariant; 1] = [ TypeVariant::AccountFlags, ]; pub const VARIANTS_STR: [&'static str; 1] = [ "AccountFlags", ]; - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] #[allow(clippy::too_many_lines)] pub fn read_xdr(v: TypeVariant, r: &mut Limited) -> Result { match v { @@ -3019,7 +3230,7 @@ impl Type { Ok(t) } - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] pub fn read_xdr_to_end(v: TypeVariant, r: &mut Limited) -> Result { let s = Self::read_xdr(v, r)?; // Check that any further reads, such as this read of one byte, read no @@ -3063,7 +3274,7 @@ impl Type { } } - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] pub fn from_xdr>(v: TypeVariant, bytes: B, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(v, &mut cursor)?; @@ -3147,7 +3358,7 @@ impl Variants for Type { } impl WriteXdr for Type { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] #[allow(clippy::too_many_lines)] fn write_xdr(&self, w: &mut Limited) -> Result<()> { match self { diff --git a/spec/output/generator_spec_rust/const.x/MyXDR.rs b/spec/output/generator_spec_rust/const.x/MyXDR.rs index 735e0265e..fbe2a13d8 100644 --- a/spec/output/generator_spec_rust/const.x/MyXDR.rs +++ b/spec/output/generator_spec_rust/const.x/MyXDR.rs @@ -50,7 +50,7 @@ use std::{ io::{BufRead, BufReader, Cursor, Read, Write}, }; -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] use embedded_io_extras::{Cursor, Error as _, ErrorType, Read, Write}; /// Error contains all errors returned by functions in this crate. It can be @@ -68,7 +68,7 @@ pub enum Error { InvalidHex, #[cfg(feature = "std")] Io(io::Error), - #[cfg(all(not(feature = "std"), feature = "alloc"))] + #[cfg(feature = "embedded_io")] Io(embedded_io_extras::ErrorKind), DepthLimitExceeded, #[cfg(feature = "serde_json")] @@ -86,15 +86,14 @@ impl PartialEq for Error { // case for comparing errors outputted by the XDR library is for // error case testing, and a lack of the ability to compare has a // detrimental affect on failure testing, so this is a tradeoff. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] (Self::Io(l), Self::Io(r)) => l.kind() == r.kind(), _ => core::mem::discriminant(self) == core::mem::discriminant(other), } } } - -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl embedded_io_extras::Error for Error { fn kind(&self) -> embedded_io_extras::ErrorKind { match self { @@ -104,7 +103,7 @@ impl embedded_io_extras::Error for Error { } } -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl From> for Error { fn from(value: embedded_io_extras::ReadExactError) -> Self { match value { @@ -140,7 +139,7 @@ impl fmt::Display for Error { Error::InvalidHex => write!(f, "hex invalid"), #[cfg(feature = "std")] Error::Io(e) => write!(f, "{e}"), - #[cfg(all(not(feature = "std"), feature = "alloc"))] + #[cfg(feature = "embedded_io")] Error::Io(_) => write!(f, "io error"), Error::DepthLimitExceeded => write!(f, "depth limit exceeded"), #[cfg(feature = "serde_json")] @@ -194,7 +193,7 @@ impl From for () { #[allow(dead_code)] type Result = core::result::Result; -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl ErrorType for Limited { type Error = Error; } /// Name defines types that assign a static name to their value, such as the @@ -230,7 +229,7 @@ where /// `Limits` contains the limits that a limited reader or writer will be /// constrained to. -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] #[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct Limits { /// Defines the maximum depth for recursive calls in `Read/WriteXdr` to @@ -247,7 +246,7 @@ pub struct Limits { pub len: usize, } -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] impl Limits { #[must_use] pub fn none() -> Self { @@ -278,13 +277,13 @@ impl Limits { /// /// Intended for use with readers and writers and limiting their reads and /// writes. -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] pub struct Limited { pub inner: L, pub(crate) limits: Limits, } -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] impl Limited { /// Constructs a new `Limited`. /// @@ -337,8 +336,7 @@ impl Read for Limited { } } - -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl Read for Limited { /// Forwards the read operation to the wrapped object. fn read(&mut self, buf: &mut [u8]) -> core::result::Result { @@ -372,7 +370,7 @@ impl Write for Limited { } } -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl Write for Limited { /// Forwards the write operation to the wrapped object. fn write(&mut self, buf: &[u8]) -> core::result::Result { @@ -457,7 +455,7 @@ where /// /// Use [`ReadXdR: Read_xdr_to_end`] when the intent is for all bytes in the /// read implementation to be consumed by the read. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result; /// Construct the type from the XDR bytes base64 encoded. @@ -492,7 +490,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr_to_end(r: &mut Limited) -> Result { let s = Self::read_xdr(r)?; // Check that any further reads, such as this read of one byte, read no @@ -532,7 +530,7 @@ where /// /// Use [`ReadXdR: Read_xdr_into_to_end`] when the intent is for all bytes /// in the read implementation to be consumed by the read. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr_into(&mut self, r: &mut Limited) -> Result<()> { *self = Self::read_xdr(r)?; Ok(()) @@ -556,7 +554,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr_into_to_end(&mut self, r: &mut Limited) -> Result<()> { Self::read_xdr_into(self, r)?; // Check that any further reads, such as this read of one byte, read no @@ -605,7 +603,7 @@ where /// /// An error is returned if the bytes are not completely consumed by the /// deserialization. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn from_xdr(bytes: impl AsRef<[u8]>, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(&mut cursor)?; @@ -629,10 +627,10 @@ where } pub trait WriteXdr { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()>; - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn to_xdr(&self, limits: Limits) -> Result> { let mut cursor = Limited::new(Cursor::new(vec![]), limits); self.write_xdr(&mut cursor)?; @@ -654,13 +652,13 @@ pub trait WriteXdr { /// `Pad_len` returns the number of bytes to pad an XDR value of the given /// length to make the final serialized size a multiple of 4. -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] fn pad_len(len: usize) -> usize { (4 - (len % 4)) % 4 } impl ReadXdr for i32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -672,7 +670,7 @@ impl ReadXdr for i32 { } impl WriteXdr for i32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -683,7 +681,7 @@ impl WriteXdr for i32 { } impl ReadXdr for u32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -695,7 +693,7 @@ impl ReadXdr for u32 { } impl WriteXdr for u32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -706,7 +704,7 @@ impl WriteXdr for u32 { } impl ReadXdr for i64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -718,7 +716,7 @@ impl ReadXdr for i64 { } impl WriteXdr for i64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -729,7 +727,7 @@ impl WriteXdr for i64 { } impl ReadXdr for u64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -741,7 +739,7 @@ impl ReadXdr for u64 { } impl WriteXdr for u64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -752,35 +750,35 @@ impl WriteXdr for u64 { } impl ReadXdr for f32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for f64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for bool { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -791,7 +789,7 @@ impl ReadXdr for bool { } impl WriteXdr for bool { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i = u32::from(*self); // true = 1, false = 0 @@ -801,7 +799,7 @@ impl WriteXdr for bool { } impl ReadXdr for Option { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -818,7 +816,7 @@ impl ReadXdr for Option { } impl WriteXdr for Option { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { if let Some(t) = self { @@ -833,35 +831,35 @@ impl WriteXdr for Option { } impl ReadXdr for Box { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| Ok(Box::new(T::read_xdr(r)?))) } } impl WriteXdr for Box { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| T::write_xdr(self, w)) } } impl ReadXdr for () { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(_r: &mut Limited) -> Result { Ok(()) } } impl WriteXdr for () { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { Ok(()) } } impl ReadXdr for [u8; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { r.consume_len(N)?; @@ -880,7 +878,7 @@ impl ReadXdr for [u8; N] { } impl WriteXdr for [u8; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { w.consume_len(N)?; @@ -894,7 +892,7 @@ impl WriteXdr for [u8; N] { } impl ReadXdr for [T; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let mut vec = Vec::with_capacity(N); @@ -909,7 +907,7 @@ impl ReadXdr for [T; N] { } impl WriteXdr for [T; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { for t in self { @@ -1268,7 +1266,7 @@ impl<'a, const MAX: u32> TryFrom<&'a VecM> for &'a str { } impl ReadXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1295,7 +1293,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1315,7 +1313,7 @@ impl WriteXdr for VecM { } impl ReadXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len = u32::read_xdr(r)?; @@ -1335,7 +1333,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1708,7 +1706,7 @@ impl<'a, const MAX: u32> TryFrom<&'a BytesM> for &'a str { } impl ReadXdr for BytesM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1735,7 +1733,7 @@ impl ReadXdr for BytesM { } impl WriteXdr for BytesM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2111,7 +2109,7 @@ impl<'a, const MAX: u32> TryFrom<&'a StringM> for &'a str { } impl ReadXdr for StringM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -2138,7 +2136,7 @@ impl ReadXdr for StringM { } impl WriteXdr for StringM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2184,7 +2182,7 @@ impl ReadXdr for Frame where T: ReadXdr, { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { // Read the frame header value that contains 1 flag-bit and a 33-bit length. // - The 1 flag bit is 0 when there are more frames for the same record. @@ -2204,7 +2202,7 @@ where } } -#[cfg(all(test, feature = "alloc"))] +#[cfg(all(test, any(feature = "std", feature = "embedded_io")))] mod tests { use super::*; @@ -2314,7 +2312,7 @@ mod tests { } } -#[cfg(all(test, feature = "alloc"))] +#[cfg(all(test, any(feature = "std", feature = "embedded_io")))] mod test { use super::*; @@ -2827,6 +2825,219 @@ mod test { } } +#[cfg(all(test, any(feature = "std", feature = "embedded_io")))] +mod test_io { + // We will use different IO libraries according to the feature, + // we hope the selected IO library can work as expected + + use super::*; + + #[test] + fn test_read_exact_success() { + let data = b"The quick brown fox jumps over the lazy dog."; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 19]; // Exactly the length of "The quick brown fox" + + // Attempt to read exactly 19 bytes + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"The quick brown fox"); + assert_eq!(cursor.position(), 19); + } + + #[test] + fn test_read_exact_less_than_available() { + let data = b"Hello, Rust!"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 5]; + + // Attempt to read 5 bytes from the start + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Hello"); + assert_eq!(cursor.position(), 5); + } + + #[test] + fn test_read_exact_exact_eof() { + let data = b"Data"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 4]; + + // Attempt to read exactly 4 bytes, which is the entire buffer + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Data"); + assert_eq!(cursor.position(), 4); + + // Further attempt to read should fail with EOF + let mut buffer_eof = [0u8; 1]; + let result = cursor.read_exact(&mut buffer_eof); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 4); // Position should remain at EOF + } + + #[test] + fn test_read_exact_past_eof() { + let data = b"Short"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 10]; // Requesting more bytes than available + + // Attempt to read 10 bytes from a 5-byte buffer + let result = cursor.read_exact(&mut buffer); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 5); // Position should move to EOF + } + + #[test] + fn test_read_exact_empty_buffer() { + let data = b"Non-empty"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 0]; // Zero-length buffer + + // Attempt to read zero bytes + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(cursor.position(), 0); // Position should remain unchanged + } + + #[test] + fn test_read_exact_from_empty_cursor() { + let data: &[u8] = b""; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 5]; + + // Attempt to read from an empty cursor + let result = cursor.read_exact(&mut buffer); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 0); // Position remains at 0 + } + + #[test] + fn test_read_exact_multiple_reads() { + let data = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + let mut cursor = Cursor::new(data); + + let mut buffer1 = [0u8; 10]; + let mut buffer2 = [0u8; 10]; + let mut buffer3 = [0u8; 10]; // Only 6 bytes left + + // First read: 10 bytes + assert!(cursor.read_exact(&mut buffer1).is_ok()); + assert_eq!(&buffer1, b"ABCDEFGHIJ"); + assert_eq!(cursor.position(), 10); + + // Second read: 10 bytes + assert!(cursor.read_exact(&mut buffer2).is_ok()); + assert_eq!(&buffer2, b"KLMNOPQRST"); + assert_eq!(cursor.position(), 20); + + // Third read: Attempt to read 10 bytes, but only 6 are available + let result = cursor.read_exact(&mut buffer3); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + // read_exact makes no promises about the content of the buffer on error + // assert_eq!(&buffer3[..6], b"UVWXYZ"); + assert_eq!(cursor.position(), 26); // Position should be at EOF + } + + #[test] + fn test_cursor_read_exact_after_eof() { + let data = b"End"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 3]; + + // First read: read the entire buffer + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"End"); + assert_eq!(cursor.position(), 3); + + // Second read: attempt to read again, should fail + let mut buffer_eof = [0u8; 1]; + let result = cursor.read_exact(&mut buffer_eof); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 3); // Position remains at EOF + } + + #[test] + fn test_slice_read_exact_success() { + let data = b"SliceReadTest"; + let mut slice = &data[..]; + let mut buffer = [0u8; 13]; // Exact length + + // Using Read trait directly on slice + assert!(slice.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"SliceReadTest"); + } + + #[test] + fn test_slice_read_exact_partial() { + let data = b"SlicePartial"; + let mut slice = &data[..]; + let mut buffer = [0u8; 20]; // Request more bytes than available + + // Using Read trait directly on slice + let result = slice.read_exact(&mut buffer); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + // read_exact makes no promises about the content of the buffer on error + } +} + /// Foo is an XDR Const defines as: /// /// ```text @@ -2939,7 +3150,7 @@ TypeVariant::TestArray2, ]; pub const VARIANTS_STR: [&'static str; 2] = [ "TestArray", "TestArray2", ]; - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] #[allow(clippy::too_many_lines)] pub fn read_xdr(v: TypeVariant, r: &mut Limited) -> Result { match v { @@ -2955,7 +3166,7 @@ TypeVariant::TestArray2 => r.with_limited_depth(|r| Ok(Self::TestArray2(Box::new Ok(t) } - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] pub fn read_xdr_to_end(v: TypeVariant, r: &mut Limited) -> Result { let s = Self::read_xdr(v, r)?; // Check that any further reads, such as this read of one byte, read no @@ -3002,7 +3213,7 @@ TypeVariant::TestArray2 => Box::new(ReadXdrIter::<_, TestArray2>::new(dec, r.lim } } - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] pub fn from_xdr>(v: TypeVariant, bytes: B, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(v, &mut cursor)?; @@ -3091,7 +3302,7 @@ Self::TestArray2(_) => TypeVariant::TestArray2, } impl WriteXdr for Type { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] #[allow(clippy::too_many_lines)] fn write_xdr(&self, w: &mut Limited) -> Result<()> { match self { diff --git a/spec/output/generator_spec_rust/enum.x/MyXDR.rs b/spec/output/generator_spec_rust/enum.x/MyXDR.rs index 2842c0d32..598a798fb 100644 --- a/spec/output/generator_spec_rust/enum.x/MyXDR.rs +++ b/spec/output/generator_spec_rust/enum.x/MyXDR.rs @@ -50,7 +50,7 @@ use std::{ io::{BufRead, BufReader, Cursor, Read, Write}, }; -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] use embedded_io_extras::{Cursor, Error as _, ErrorType, Read, Write}; /// Error contains all errors returned by functions in this crate. It can be @@ -68,7 +68,7 @@ pub enum Error { InvalidHex, #[cfg(feature = "std")] Io(io::Error), - #[cfg(all(not(feature = "std"), feature = "alloc"))] + #[cfg(feature = "embedded_io")] Io(embedded_io_extras::ErrorKind), DepthLimitExceeded, #[cfg(feature = "serde_json")] @@ -86,15 +86,14 @@ impl PartialEq for Error { // case for comparing errors outputted by the XDR library is for // error case testing, and a lack of the ability to compare has a // detrimental affect on failure testing, so this is a tradeoff. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] (Self::Io(l), Self::Io(r)) => l.kind() == r.kind(), _ => core::mem::discriminant(self) == core::mem::discriminant(other), } } } - -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl embedded_io_extras::Error for Error { fn kind(&self) -> embedded_io_extras::ErrorKind { match self { @@ -104,7 +103,7 @@ impl embedded_io_extras::Error for Error { } } -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl From> for Error { fn from(value: embedded_io_extras::ReadExactError) -> Self { match value { @@ -140,7 +139,7 @@ impl fmt::Display for Error { Error::InvalidHex => write!(f, "hex invalid"), #[cfg(feature = "std")] Error::Io(e) => write!(f, "{e}"), - #[cfg(all(not(feature = "std"), feature = "alloc"))] + #[cfg(feature = "embedded_io")] Error::Io(_) => write!(f, "io error"), Error::DepthLimitExceeded => write!(f, "depth limit exceeded"), #[cfg(feature = "serde_json")] @@ -194,7 +193,7 @@ impl From for () { #[allow(dead_code)] type Result = core::result::Result; -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl ErrorType for Limited { type Error = Error; } /// Name defines types that assign a static name to their value, such as the @@ -230,7 +229,7 @@ where /// `Limits` contains the limits that a limited reader or writer will be /// constrained to. -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] #[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct Limits { /// Defines the maximum depth for recursive calls in `Read/WriteXdr` to @@ -247,7 +246,7 @@ pub struct Limits { pub len: usize, } -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] impl Limits { #[must_use] pub fn none() -> Self { @@ -278,13 +277,13 @@ impl Limits { /// /// Intended for use with readers and writers and limiting their reads and /// writes. -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] pub struct Limited { pub inner: L, pub(crate) limits: Limits, } -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] impl Limited { /// Constructs a new `Limited`. /// @@ -337,8 +336,7 @@ impl Read for Limited { } } - -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl Read for Limited { /// Forwards the read operation to the wrapped object. fn read(&mut self, buf: &mut [u8]) -> core::result::Result { @@ -372,7 +370,7 @@ impl Write for Limited { } } -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl Write for Limited { /// Forwards the write operation to the wrapped object. fn write(&mut self, buf: &[u8]) -> core::result::Result { @@ -457,7 +455,7 @@ where /// /// Use [`ReadXdR: Read_xdr_to_end`] when the intent is for all bytes in the /// read implementation to be consumed by the read. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result; /// Construct the type from the XDR bytes base64 encoded. @@ -492,7 +490,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr_to_end(r: &mut Limited) -> Result { let s = Self::read_xdr(r)?; // Check that any further reads, such as this read of one byte, read no @@ -532,7 +530,7 @@ where /// /// Use [`ReadXdR: Read_xdr_into_to_end`] when the intent is for all bytes /// in the read implementation to be consumed by the read. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr_into(&mut self, r: &mut Limited) -> Result<()> { *self = Self::read_xdr(r)?; Ok(()) @@ -556,7 +554,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr_into_to_end(&mut self, r: &mut Limited) -> Result<()> { Self::read_xdr_into(self, r)?; // Check that any further reads, such as this read of one byte, read no @@ -605,7 +603,7 @@ where /// /// An error is returned if the bytes are not completely consumed by the /// deserialization. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn from_xdr(bytes: impl AsRef<[u8]>, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(&mut cursor)?; @@ -629,10 +627,10 @@ where } pub trait WriteXdr { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()>; - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn to_xdr(&self, limits: Limits) -> Result> { let mut cursor = Limited::new(Cursor::new(vec![]), limits); self.write_xdr(&mut cursor)?; @@ -654,13 +652,13 @@ pub trait WriteXdr { /// `Pad_len` returns the number of bytes to pad an XDR value of the given /// length to make the final serialized size a multiple of 4. -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] fn pad_len(len: usize) -> usize { (4 - (len % 4)) % 4 } impl ReadXdr for i32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -672,7 +670,7 @@ impl ReadXdr for i32 { } impl WriteXdr for i32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -683,7 +681,7 @@ impl WriteXdr for i32 { } impl ReadXdr for u32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -695,7 +693,7 @@ impl ReadXdr for u32 { } impl WriteXdr for u32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -706,7 +704,7 @@ impl WriteXdr for u32 { } impl ReadXdr for i64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -718,7 +716,7 @@ impl ReadXdr for i64 { } impl WriteXdr for i64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -729,7 +727,7 @@ impl WriteXdr for i64 { } impl ReadXdr for u64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -741,7 +739,7 @@ impl ReadXdr for u64 { } impl WriteXdr for u64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -752,35 +750,35 @@ impl WriteXdr for u64 { } impl ReadXdr for f32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for f64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for bool { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -791,7 +789,7 @@ impl ReadXdr for bool { } impl WriteXdr for bool { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i = u32::from(*self); // true = 1, false = 0 @@ -801,7 +799,7 @@ impl WriteXdr for bool { } impl ReadXdr for Option { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -818,7 +816,7 @@ impl ReadXdr for Option { } impl WriteXdr for Option { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { if let Some(t) = self { @@ -833,35 +831,35 @@ impl WriteXdr for Option { } impl ReadXdr for Box { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| Ok(Box::new(T::read_xdr(r)?))) } } impl WriteXdr for Box { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| T::write_xdr(self, w)) } } impl ReadXdr for () { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(_r: &mut Limited) -> Result { Ok(()) } } impl WriteXdr for () { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { Ok(()) } } impl ReadXdr for [u8; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { r.consume_len(N)?; @@ -880,7 +878,7 @@ impl ReadXdr for [u8; N] { } impl WriteXdr for [u8; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { w.consume_len(N)?; @@ -894,7 +892,7 @@ impl WriteXdr for [u8; N] { } impl ReadXdr for [T; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let mut vec = Vec::with_capacity(N); @@ -909,7 +907,7 @@ impl ReadXdr for [T; N] { } impl WriteXdr for [T; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { for t in self { @@ -1268,7 +1266,7 @@ impl<'a, const MAX: u32> TryFrom<&'a VecM> for &'a str { } impl ReadXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1295,7 +1293,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1315,7 +1313,7 @@ impl WriteXdr for VecM { } impl ReadXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len = u32::read_xdr(r)?; @@ -1335,7 +1333,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1708,7 +1706,7 @@ impl<'a, const MAX: u32> TryFrom<&'a BytesM> for &'a str { } impl ReadXdr for BytesM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1735,7 +1733,7 @@ impl ReadXdr for BytesM { } impl WriteXdr for BytesM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2111,7 +2109,7 @@ impl<'a, const MAX: u32> TryFrom<&'a StringM> for &'a str { } impl ReadXdr for StringM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -2138,7 +2136,7 @@ impl ReadXdr for StringM { } impl WriteXdr for StringM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2184,7 +2182,7 @@ impl ReadXdr for Frame where T: ReadXdr, { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { // Read the frame header value that contains 1 flag-bit and a 33-bit length. // - The 1 flag bit is 0 when there are more frames for the same record. @@ -2204,7 +2202,7 @@ where } } -#[cfg(all(test, feature = "alloc"))] +#[cfg(all(test, any(feature = "std", feature = "embedded_io")))] mod tests { use super::*; @@ -2314,7 +2312,7 @@ mod tests { } } -#[cfg(all(test, feature = "alloc"))] +#[cfg(all(test, any(feature = "std", feature = "embedded_io")))] mod test { use super::*; @@ -2827,6 +2825,219 @@ mod test { } } +#[cfg(all(test, any(feature = "std", feature = "embedded_io")))] +mod test_io { + // We will use different IO libraries according to the feature, + // we hope the selected IO library can work as expected + + use super::*; + + #[test] + fn test_read_exact_success() { + let data = b"The quick brown fox jumps over the lazy dog."; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 19]; // Exactly the length of "The quick brown fox" + + // Attempt to read exactly 19 bytes + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"The quick brown fox"); + assert_eq!(cursor.position(), 19); + } + + #[test] + fn test_read_exact_less_than_available() { + let data = b"Hello, Rust!"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 5]; + + // Attempt to read 5 bytes from the start + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Hello"); + assert_eq!(cursor.position(), 5); + } + + #[test] + fn test_read_exact_exact_eof() { + let data = b"Data"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 4]; + + // Attempt to read exactly 4 bytes, which is the entire buffer + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Data"); + assert_eq!(cursor.position(), 4); + + // Further attempt to read should fail with EOF + let mut buffer_eof = [0u8; 1]; + let result = cursor.read_exact(&mut buffer_eof); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 4); // Position should remain at EOF + } + + #[test] + fn test_read_exact_past_eof() { + let data = b"Short"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 10]; // Requesting more bytes than available + + // Attempt to read 10 bytes from a 5-byte buffer + let result = cursor.read_exact(&mut buffer); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 5); // Position should move to EOF + } + + #[test] + fn test_read_exact_empty_buffer() { + let data = b"Non-empty"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 0]; // Zero-length buffer + + // Attempt to read zero bytes + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(cursor.position(), 0); // Position should remain unchanged + } + + #[test] + fn test_read_exact_from_empty_cursor() { + let data: &[u8] = b""; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 5]; + + // Attempt to read from an empty cursor + let result = cursor.read_exact(&mut buffer); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 0); // Position remains at 0 + } + + #[test] + fn test_read_exact_multiple_reads() { + let data = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + let mut cursor = Cursor::new(data); + + let mut buffer1 = [0u8; 10]; + let mut buffer2 = [0u8; 10]; + let mut buffer3 = [0u8; 10]; // Only 6 bytes left + + // First read: 10 bytes + assert!(cursor.read_exact(&mut buffer1).is_ok()); + assert_eq!(&buffer1, b"ABCDEFGHIJ"); + assert_eq!(cursor.position(), 10); + + // Second read: 10 bytes + assert!(cursor.read_exact(&mut buffer2).is_ok()); + assert_eq!(&buffer2, b"KLMNOPQRST"); + assert_eq!(cursor.position(), 20); + + // Third read: Attempt to read 10 bytes, but only 6 are available + let result = cursor.read_exact(&mut buffer3); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + // read_exact makes no promises about the content of the buffer on error + // assert_eq!(&buffer3[..6], b"UVWXYZ"); + assert_eq!(cursor.position(), 26); // Position should be at EOF + } + + #[test] + fn test_cursor_read_exact_after_eof() { + let data = b"End"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 3]; + + // First read: read the entire buffer + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"End"); + assert_eq!(cursor.position(), 3); + + // Second read: attempt to read again, should fail + let mut buffer_eof = [0u8; 1]; + let result = cursor.read_exact(&mut buffer_eof); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 3); // Position remains at EOF + } + + #[test] + fn test_slice_read_exact_success() { + let data = b"SliceReadTest"; + let mut slice = &data[..]; + let mut buffer = [0u8; 13]; // Exact length + + // Using Read trait directly on slice + assert!(slice.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"SliceReadTest"); + } + + #[test] + fn test_slice_read_exact_partial() { + let data = b"SlicePartial"; + let mut slice = &data[..]; + let mut buffer = [0u8; 20]; // Request more bytes than available + + // Using Read trait directly on slice + let result = slice.read_exact(&mut buffer); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + // read_exact makes no promises about the content of the buffer on error + } +} + /// MessageType is an XDR Enum defines as: /// /// ```text @@ -2989,7 +3200,7 @@ Self::FbaMessage => "FbaMessage", } impl ReadXdr for MessageType { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let e = i32::read_xdr(r)?; @@ -3000,7 +3211,7 @@ Self::FbaMessage => "FbaMessage", } impl WriteXdr for MessageType { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i: i32 = (*self).into(); @@ -3098,7 +3309,7 @@ Self::Blue => "Blue", } impl ReadXdr for Color { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let e = i32::read_xdr(r)?; @@ -3109,7 +3320,7 @@ Self::Blue => "Blue", } impl WriteXdr for Color { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i: i32 = (*self).into(); @@ -3207,7 +3418,7 @@ Self::Blue2 => "Blue2", } impl ReadXdr for Color2 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let e = i32::read_xdr(r)?; @@ -3218,7 +3429,7 @@ Self::Blue2 => "Blue2", } impl WriteXdr for Color2 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i: i32 = (*self).into(); @@ -3316,7 +3527,7 @@ Self::R3 => "R3", } impl ReadXdr for Color3 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let e = i32::read_xdr(r)?; @@ -3327,7 +3538,7 @@ Self::R3 => "R3", } impl WriteXdr for Color3 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i: i32 = (*self).into(); @@ -3442,7 +3653,7 @@ TypeVariant::Color3, ]; "Color2", "Color3", ]; - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] #[allow(clippy::too_many_lines)] pub fn read_xdr(v: TypeVariant, r: &mut Limited) -> Result { match v { @@ -3460,7 +3671,7 @@ TypeVariant::Color3 => r.with_limited_depth(|r| Ok(Self::Color3(Box::new(Color3: Ok(t) } - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] pub fn read_xdr_to_end(v: TypeVariant, r: &mut Limited) -> Result { let s = Self::read_xdr(v, r)?; // Check that any further reads, such as this read of one byte, read no @@ -3513,7 +3724,7 @@ TypeVariant::Color3 => Box::new(ReadXdrIter::<_, Color3>::new(dec, r.limits.clon } } - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] pub fn from_xdr>(v: TypeVariant, bytes: B, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(v, &mut cursor)?; @@ -3612,7 +3823,7 @@ Self::Color3(_) => TypeVariant::Color3, } impl WriteXdr for Type { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] #[allow(clippy::too_many_lines)] fn write_xdr(&self, w: &mut Limited) -> Result<()> { match self { diff --git a/spec/output/generator_spec_rust/nesting.x/MyXDR.rs b/spec/output/generator_spec_rust/nesting.x/MyXDR.rs index c88154ab3..be4ca56e5 100644 --- a/spec/output/generator_spec_rust/nesting.x/MyXDR.rs +++ b/spec/output/generator_spec_rust/nesting.x/MyXDR.rs @@ -50,7 +50,7 @@ use std::{ io::{BufRead, BufReader, Cursor, Read, Write}, }; -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] use embedded_io_extras::{Cursor, Error as _, ErrorType, Read, Write}; /// Error contains all errors returned by functions in this crate. It can be @@ -68,7 +68,7 @@ pub enum Error { InvalidHex, #[cfg(feature = "std")] Io(io::Error), - #[cfg(all(not(feature = "std"), feature = "alloc"))] + #[cfg(feature = "embedded_io")] Io(embedded_io_extras::ErrorKind), DepthLimitExceeded, #[cfg(feature = "serde_json")] @@ -86,15 +86,14 @@ impl PartialEq for Error { // case for comparing errors outputted by the XDR library is for // error case testing, and a lack of the ability to compare has a // detrimental affect on failure testing, so this is a tradeoff. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] (Self::Io(l), Self::Io(r)) => l.kind() == r.kind(), _ => core::mem::discriminant(self) == core::mem::discriminant(other), } } } - -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl embedded_io_extras::Error for Error { fn kind(&self) -> embedded_io_extras::ErrorKind { match self { @@ -104,7 +103,7 @@ impl embedded_io_extras::Error for Error { } } -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl From> for Error { fn from(value: embedded_io_extras::ReadExactError) -> Self { match value { @@ -140,7 +139,7 @@ impl fmt::Display for Error { Error::InvalidHex => write!(f, "hex invalid"), #[cfg(feature = "std")] Error::Io(e) => write!(f, "{e}"), - #[cfg(all(not(feature = "std"), feature = "alloc"))] + #[cfg(feature = "embedded_io")] Error::Io(_) => write!(f, "io error"), Error::DepthLimitExceeded => write!(f, "depth limit exceeded"), #[cfg(feature = "serde_json")] @@ -194,7 +193,7 @@ impl From for () { #[allow(dead_code)] type Result = core::result::Result; -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl ErrorType for Limited { type Error = Error; } /// Name defines types that assign a static name to their value, such as the @@ -230,7 +229,7 @@ where /// `Limits` contains the limits that a limited reader or writer will be /// constrained to. -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] #[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct Limits { /// Defines the maximum depth for recursive calls in `Read/WriteXdr` to @@ -247,7 +246,7 @@ pub struct Limits { pub len: usize, } -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] impl Limits { #[must_use] pub fn none() -> Self { @@ -278,13 +277,13 @@ impl Limits { /// /// Intended for use with readers and writers and limiting their reads and /// writes. -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] pub struct Limited { pub inner: L, pub(crate) limits: Limits, } -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] impl Limited { /// Constructs a new `Limited`. /// @@ -337,8 +336,7 @@ impl Read for Limited { } } - -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl Read for Limited { /// Forwards the read operation to the wrapped object. fn read(&mut self, buf: &mut [u8]) -> core::result::Result { @@ -372,7 +370,7 @@ impl Write for Limited { } } -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl Write for Limited { /// Forwards the write operation to the wrapped object. fn write(&mut self, buf: &[u8]) -> core::result::Result { @@ -457,7 +455,7 @@ where /// /// Use [`ReadXdR: Read_xdr_to_end`] when the intent is for all bytes in the /// read implementation to be consumed by the read. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result; /// Construct the type from the XDR bytes base64 encoded. @@ -492,7 +490,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr_to_end(r: &mut Limited) -> Result { let s = Self::read_xdr(r)?; // Check that any further reads, such as this read of one byte, read no @@ -532,7 +530,7 @@ where /// /// Use [`ReadXdR: Read_xdr_into_to_end`] when the intent is for all bytes /// in the read implementation to be consumed by the read. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr_into(&mut self, r: &mut Limited) -> Result<()> { *self = Self::read_xdr(r)?; Ok(()) @@ -556,7 +554,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr_into_to_end(&mut self, r: &mut Limited) -> Result<()> { Self::read_xdr_into(self, r)?; // Check that any further reads, such as this read of one byte, read no @@ -605,7 +603,7 @@ where /// /// An error is returned if the bytes are not completely consumed by the /// deserialization. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn from_xdr(bytes: impl AsRef<[u8]>, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(&mut cursor)?; @@ -629,10 +627,10 @@ where } pub trait WriteXdr { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()>; - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn to_xdr(&self, limits: Limits) -> Result> { let mut cursor = Limited::new(Cursor::new(vec![]), limits); self.write_xdr(&mut cursor)?; @@ -654,13 +652,13 @@ pub trait WriteXdr { /// `Pad_len` returns the number of bytes to pad an XDR value of the given /// length to make the final serialized size a multiple of 4. -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] fn pad_len(len: usize) -> usize { (4 - (len % 4)) % 4 } impl ReadXdr for i32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -672,7 +670,7 @@ impl ReadXdr for i32 { } impl WriteXdr for i32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -683,7 +681,7 @@ impl WriteXdr for i32 { } impl ReadXdr for u32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -695,7 +693,7 @@ impl ReadXdr for u32 { } impl WriteXdr for u32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -706,7 +704,7 @@ impl WriteXdr for u32 { } impl ReadXdr for i64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -718,7 +716,7 @@ impl ReadXdr for i64 { } impl WriteXdr for i64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -729,7 +727,7 @@ impl WriteXdr for i64 { } impl ReadXdr for u64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -741,7 +739,7 @@ impl ReadXdr for u64 { } impl WriteXdr for u64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -752,35 +750,35 @@ impl WriteXdr for u64 { } impl ReadXdr for f32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for f64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for bool { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -791,7 +789,7 @@ impl ReadXdr for bool { } impl WriteXdr for bool { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i = u32::from(*self); // true = 1, false = 0 @@ -801,7 +799,7 @@ impl WriteXdr for bool { } impl ReadXdr for Option { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -818,7 +816,7 @@ impl ReadXdr for Option { } impl WriteXdr for Option { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { if let Some(t) = self { @@ -833,35 +831,35 @@ impl WriteXdr for Option { } impl ReadXdr for Box { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| Ok(Box::new(T::read_xdr(r)?))) } } impl WriteXdr for Box { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| T::write_xdr(self, w)) } } impl ReadXdr for () { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(_r: &mut Limited) -> Result { Ok(()) } } impl WriteXdr for () { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { Ok(()) } } impl ReadXdr for [u8; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { r.consume_len(N)?; @@ -880,7 +878,7 @@ impl ReadXdr for [u8; N] { } impl WriteXdr for [u8; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { w.consume_len(N)?; @@ -894,7 +892,7 @@ impl WriteXdr for [u8; N] { } impl ReadXdr for [T; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let mut vec = Vec::with_capacity(N); @@ -909,7 +907,7 @@ impl ReadXdr for [T; N] { } impl WriteXdr for [T; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { for t in self { @@ -1268,7 +1266,7 @@ impl<'a, const MAX: u32> TryFrom<&'a VecM> for &'a str { } impl ReadXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1295,7 +1293,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1315,7 +1313,7 @@ impl WriteXdr for VecM { } impl ReadXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len = u32::read_xdr(r)?; @@ -1335,7 +1333,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1708,7 +1706,7 @@ impl<'a, const MAX: u32> TryFrom<&'a BytesM> for &'a str { } impl ReadXdr for BytesM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1735,7 +1733,7 @@ impl ReadXdr for BytesM { } impl WriteXdr for BytesM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2111,7 +2109,7 @@ impl<'a, const MAX: u32> TryFrom<&'a StringM> for &'a str { } impl ReadXdr for StringM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -2138,7 +2136,7 @@ impl ReadXdr for StringM { } impl WriteXdr for StringM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2184,7 +2182,7 @@ impl ReadXdr for Frame where T: ReadXdr, { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { // Read the frame header value that contains 1 flag-bit and a 33-bit length. // - The 1 flag bit is 0 when there are more frames for the same record. @@ -2204,7 +2202,7 @@ where } } -#[cfg(all(test, feature = "alloc"))] +#[cfg(all(test, any(feature = "std", feature = "embedded_io")))] mod tests { use super::*; @@ -2314,7 +2312,7 @@ mod tests { } } -#[cfg(all(test, feature = "alloc"))] +#[cfg(all(test, any(feature = "std", feature = "embedded_io")))] mod test { use super::*; @@ -2827,6 +2825,219 @@ mod test { } } +#[cfg(all(test, any(feature = "std", feature = "embedded_io")))] +mod test_io { + // We will use different IO libraries according to the feature, + // we hope the selected IO library can work as expected + + use super::*; + + #[test] + fn test_read_exact_success() { + let data = b"The quick brown fox jumps over the lazy dog."; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 19]; // Exactly the length of "The quick brown fox" + + // Attempt to read exactly 19 bytes + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"The quick brown fox"); + assert_eq!(cursor.position(), 19); + } + + #[test] + fn test_read_exact_less_than_available() { + let data = b"Hello, Rust!"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 5]; + + // Attempt to read 5 bytes from the start + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Hello"); + assert_eq!(cursor.position(), 5); + } + + #[test] + fn test_read_exact_exact_eof() { + let data = b"Data"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 4]; + + // Attempt to read exactly 4 bytes, which is the entire buffer + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Data"); + assert_eq!(cursor.position(), 4); + + // Further attempt to read should fail with EOF + let mut buffer_eof = [0u8; 1]; + let result = cursor.read_exact(&mut buffer_eof); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 4); // Position should remain at EOF + } + + #[test] + fn test_read_exact_past_eof() { + let data = b"Short"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 10]; // Requesting more bytes than available + + // Attempt to read 10 bytes from a 5-byte buffer + let result = cursor.read_exact(&mut buffer); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 5); // Position should move to EOF + } + + #[test] + fn test_read_exact_empty_buffer() { + let data = b"Non-empty"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 0]; // Zero-length buffer + + // Attempt to read zero bytes + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(cursor.position(), 0); // Position should remain unchanged + } + + #[test] + fn test_read_exact_from_empty_cursor() { + let data: &[u8] = b""; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 5]; + + // Attempt to read from an empty cursor + let result = cursor.read_exact(&mut buffer); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 0); // Position remains at 0 + } + + #[test] + fn test_read_exact_multiple_reads() { + let data = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + let mut cursor = Cursor::new(data); + + let mut buffer1 = [0u8; 10]; + let mut buffer2 = [0u8; 10]; + let mut buffer3 = [0u8; 10]; // Only 6 bytes left + + // First read: 10 bytes + assert!(cursor.read_exact(&mut buffer1).is_ok()); + assert_eq!(&buffer1, b"ABCDEFGHIJ"); + assert_eq!(cursor.position(), 10); + + // Second read: 10 bytes + assert!(cursor.read_exact(&mut buffer2).is_ok()); + assert_eq!(&buffer2, b"KLMNOPQRST"); + assert_eq!(cursor.position(), 20); + + // Third read: Attempt to read 10 bytes, but only 6 are available + let result = cursor.read_exact(&mut buffer3); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + // read_exact makes no promises about the content of the buffer on error + // assert_eq!(&buffer3[..6], b"UVWXYZ"); + assert_eq!(cursor.position(), 26); // Position should be at EOF + } + + #[test] + fn test_cursor_read_exact_after_eof() { + let data = b"End"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 3]; + + // First read: read the entire buffer + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"End"); + assert_eq!(cursor.position(), 3); + + // Second read: attempt to read again, should fail + let mut buffer_eof = [0u8; 1]; + let result = cursor.read_exact(&mut buffer_eof); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 3); // Position remains at EOF + } + + #[test] + fn test_slice_read_exact_success() { + let data = b"SliceReadTest"; + let mut slice = &data[..]; + let mut buffer = [0u8; 13]; // Exact length + + // Using Read trait directly on slice + assert!(slice.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"SliceReadTest"); + } + + #[test] + fn test_slice_read_exact_partial() { + let data = b"SlicePartial"; + let mut slice = &data[..]; + let mut buffer = [0u8; 20]; // Request more bytes than available + + // Using Read trait directly on slice + let result = slice.read_exact(&mut buffer); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + // read_exact makes no promises about the content of the buffer on error + } +} + /// UnionKey is an XDR Enum defines as: /// /// ```text @@ -2916,7 +3127,7 @@ Self::Offer => "Offer", } impl ReadXdr for UnionKey { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let e = i32::read_xdr(r)?; @@ -2927,7 +3138,7 @@ Self::Offer => "Offer", } impl WriteXdr for UnionKey { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i: i32 = (*self).into(); @@ -2961,7 +3172,7 @@ pub struct MyUnionOne { } impl ReadXdr for MyUnionOne { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { Ok(Self{ @@ -2972,7 +3183,7 @@ impl ReadXdr for MyUnionOne { } impl WriteXdr for MyUnionOne { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { self.some_int.write_xdr(w)?; @@ -3000,7 +3211,7 @@ pub struct MyUnionTwo { } impl ReadXdr for MyUnionTwo { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { Ok(Self{ @@ -3012,7 +3223,7 @@ foo: i32::read_xdr(r)?, } impl WriteXdr for MyUnionTwo { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { self.some_int.write_xdr(w)?; @@ -3115,7 +3326,7 @@ Self::Offer => UnionKey::Offer, impl Union for MyUnion {} impl ReadXdr for MyUnion { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let dv: UnionKey = ::read_xdr(r)?; @@ -3133,7 +3344,7 @@ UnionKey::Offer => Self::Offer, } impl WriteXdr for MyUnion { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { self.discriminant().write_xdr(w)?; @@ -3263,7 +3474,7 @@ TypeVariant::MyUnionTwo, ]; "MyUnionOne", "MyUnionTwo", ]; - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] #[allow(clippy::too_many_lines)] pub fn read_xdr(v: TypeVariant, r: &mut Limited) -> Result { match v { @@ -3282,7 +3493,7 @@ TypeVariant::MyUnionTwo => r.with_limited_depth(|r| Ok(Self::MyUnionTwo(Box::new Ok(t) } - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] pub fn read_xdr_to_end(v: TypeVariant, r: &mut Limited) -> Result { let s = Self::read_xdr(v, r)?; // Check that any further reads, such as this read of one byte, read no @@ -3338,7 +3549,7 @@ TypeVariant::MyUnionTwo => Box::new(ReadXdrIter::<_, MyUnionTwo>::new(dec, r.lim } } - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] pub fn from_xdr>(v: TypeVariant, bytes: B, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(v, &mut cursor)?; @@ -3442,7 +3653,7 @@ Self::MyUnionTwo(_) => TypeVariant::MyUnionTwo, } impl WriteXdr for Type { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] #[allow(clippy::too_many_lines)] fn write_xdr(&self, w: &mut Limited) -> Result<()> { match self { diff --git a/spec/output/generator_spec_rust/optional.x/MyXDR.rs b/spec/output/generator_spec_rust/optional.x/MyXDR.rs index fee6ae7da..fbc4a1bf2 100644 --- a/spec/output/generator_spec_rust/optional.x/MyXDR.rs +++ b/spec/output/generator_spec_rust/optional.x/MyXDR.rs @@ -50,7 +50,7 @@ use std::{ io::{BufRead, BufReader, Cursor, Read, Write}, }; -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] use embedded_io_extras::{Cursor, Error as _, ErrorType, Read, Write}; /// Error contains all errors returned by functions in this crate. It can be @@ -68,7 +68,7 @@ pub enum Error { InvalidHex, #[cfg(feature = "std")] Io(io::Error), - #[cfg(all(not(feature = "std"), feature = "alloc"))] + #[cfg(feature = "embedded_io")] Io(embedded_io_extras::ErrorKind), DepthLimitExceeded, #[cfg(feature = "serde_json")] @@ -86,15 +86,14 @@ impl PartialEq for Error { // case for comparing errors outputted by the XDR library is for // error case testing, and a lack of the ability to compare has a // detrimental affect on failure testing, so this is a tradeoff. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] (Self::Io(l), Self::Io(r)) => l.kind() == r.kind(), _ => core::mem::discriminant(self) == core::mem::discriminant(other), } } } - -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl embedded_io_extras::Error for Error { fn kind(&self) -> embedded_io_extras::ErrorKind { match self { @@ -104,7 +103,7 @@ impl embedded_io_extras::Error for Error { } } -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl From> for Error { fn from(value: embedded_io_extras::ReadExactError) -> Self { match value { @@ -140,7 +139,7 @@ impl fmt::Display for Error { Error::InvalidHex => write!(f, "hex invalid"), #[cfg(feature = "std")] Error::Io(e) => write!(f, "{e}"), - #[cfg(all(not(feature = "std"), feature = "alloc"))] + #[cfg(feature = "embedded_io")] Error::Io(_) => write!(f, "io error"), Error::DepthLimitExceeded => write!(f, "depth limit exceeded"), #[cfg(feature = "serde_json")] @@ -194,7 +193,7 @@ impl From for () { #[allow(dead_code)] type Result = core::result::Result; -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl ErrorType for Limited { type Error = Error; } /// Name defines types that assign a static name to their value, such as the @@ -230,7 +229,7 @@ where /// `Limits` contains the limits that a limited reader or writer will be /// constrained to. -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] #[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct Limits { /// Defines the maximum depth for recursive calls in `Read/WriteXdr` to @@ -247,7 +246,7 @@ pub struct Limits { pub len: usize, } -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] impl Limits { #[must_use] pub fn none() -> Self { @@ -278,13 +277,13 @@ impl Limits { /// /// Intended for use with readers and writers and limiting their reads and /// writes. -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] pub struct Limited { pub inner: L, pub(crate) limits: Limits, } -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] impl Limited { /// Constructs a new `Limited`. /// @@ -337,8 +336,7 @@ impl Read for Limited { } } - -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl Read for Limited { /// Forwards the read operation to the wrapped object. fn read(&mut self, buf: &mut [u8]) -> core::result::Result { @@ -372,7 +370,7 @@ impl Write for Limited { } } -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl Write for Limited { /// Forwards the write operation to the wrapped object. fn write(&mut self, buf: &[u8]) -> core::result::Result { @@ -457,7 +455,7 @@ where /// /// Use [`ReadXdR: Read_xdr_to_end`] when the intent is for all bytes in the /// read implementation to be consumed by the read. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result; /// Construct the type from the XDR bytes base64 encoded. @@ -492,7 +490,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr_to_end(r: &mut Limited) -> Result { let s = Self::read_xdr(r)?; // Check that any further reads, such as this read of one byte, read no @@ -532,7 +530,7 @@ where /// /// Use [`ReadXdR: Read_xdr_into_to_end`] when the intent is for all bytes /// in the read implementation to be consumed by the read. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr_into(&mut self, r: &mut Limited) -> Result<()> { *self = Self::read_xdr(r)?; Ok(()) @@ -556,7 +554,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr_into_to_end(&mut self, r: &mut Limited) -> Result<()> { Self::read_xdr_into(self, r)?; // Check that any further reads, such as this read of one byte, read no @@ -605,7 +603,7 @@ where /// /// An error is returned if the bytes are not completely consumed by the /// deserialization. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn from_xdr(bytes: impl AsRef<[u8]>, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(&mut cursor)?; @@ -629,10 +627,10 @@ where } pub trait WriteXdr { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()>; - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn to_xdr(&self, limits: Limits) -> Result> { let mut cursor = Limited::new(Cursor::new(vec![]), limits); self.write_xdr(&mut cursor)?; @@ -654,13 +652,13 @@ pub trait WriteXdr { /// `Pad_len` returns the number of bytes to pad an XDR value of the given /// length to make the final serialized size a multiple of 4. -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] fn pad_len(len: usize) -> usize { (4 - (len % 4)) % 4 } impl ReadXdr for i32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -672,7 +670,7 @@ impl ReadXdr for i32 { } impl WriteXdr for i32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -683,7 +681,7 @@ impl WriteXdr for i32 { } impl ReadXdr for u32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -695,7 +693,7 @@ impl ReadXdr for u32 { } impl WriteXdr for u32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -706,7 +704,7 @@ impl WriteXdr for u32 { } impl ReadXdr for i64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -718,7 +716,7 @@ impl ReadXdr for i64 { } impl WriteXdr for i64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -729,7 +727,7 @@ impl WriteXdr for i64 { } impl ReadXdr for u64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -741,7 +739,7 @@ impl ReadXdr for u64 { } impl WriteXdr for u64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -752,35 +750,35 @@ impl WriteXdr for u64 { } impl ReadXdr for f32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for f64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for bool { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -791,7 +789,7 @@ impl ReadXdr for bool { } impl WriteXdr for bool { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i = u32::from(*self); // true = 1, false = 0 @@ -801,7 +799,7 @@ impl WriteXdr for bool { } impl ReadXdr for Option { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -818,7 +816,7 @@ impl ReadXdr for Option { } impl WriteXdr for Option { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { if let Some(t) = self { @@ -833,35 +831,35 @@ impl WriteXdr for Option { } impl ReadXdr for Box { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| Ok(Box::new(T::read_xdr(r)?))) } } impl WriteXdr for Box { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| T::write_xdr(self, w)) } } impl ReadXdr for () { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(_r: &mut Limited) -> Result { Ok(()) } } impl WriteXdr for () { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { Ok(()) } } impl ReadXdr for [u8; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { r.consume_len(N)?; @@ -880,7 +878,7 @@ impl ReadXdr for [u8; N] { } impl WriteXdr for [u8; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { w.consume_len(N)?; @@ -894,7 +892,7 @@ impl WriteXdr for [u8; N] { } impl ReadXdr for [T; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let mut vec = Vec::with_capacity(N); @@ -909,7 +907,7 @@ impl ReadXdr for [T; N] { } impl WriteXdr for [T; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { for t in self { @@ -1268,7 +1266,7 @@ impl<'a, const MAX: u32> TryFrom<&'a VecM> for &'a str { } impl ReadXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1295,7 +1293,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1315,7 +1313,7 @@ impl WriteXdr for VecM { } impl ReadXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len = u32::read_xdr(r)?; @@ -1335,7 +1333,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1708,7 +1706,7 @@ impl<'a, const MAX: u32> TryFrom<&'a BytesM> for &'a str { } impl ReadXdr for BytesM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1735,7 +1733,7 @@ impl ReadXdr for BytesM { } impl WriteXdr for BytesM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2111,7 +2109,7 @@ impl<'a, const MAX: u32> TryFrom<&'a StringM> for &'a str { } impl ReadXdr for StringM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -2138,7 +2136,7 @@ impl ReadXdr for StringM { } impl WriteXdr for StringM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2184,7 +2182,7 @@ impl ReadXdr for Frame where T: ReadXdr, { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { // Read the frame header value that contains 1 flag-bit and a 33-bit length. // - The 1 flag bit is 0 when there are more frames for the same record. @@ -2204,7 +2202,7 @@ where } } -#[cfg(all(test, feature = "alloc"))] +#[cfg(all(test, any(feature = "std", feature = "embedded_io")))] mod tests { use super::*; @@ -2314,7 +2312,7 @@ mod tests { } } -#[cfg(all(test, feature = "alloc"))] +#[cfg(all(test, any(feature = "std", feature = "embedded_io")))] mod test { use super::*; @@ -2827,6 +2825,219 @@ mod test { } } +#[cfg(all(test, any(feature = "std", feature = "embedded_io")))] +mod test_io { + // We will use different IO libraries according to the feature, + // we hope the selected IO library can work as expected + + use super::*; + + #[test] + fn test_read_exact_success() { + let data = b"The quick brown fox jumps over the lazy dog."; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 19]; // Exactly the length of "The quick brown fox" + + // Attempt to read exactly 19 bytes + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"The quick brown fox"); + assert_eq!(cursor.position(), 19); + } + + #[test] + fn test_read_exact_less_than_available() { + let data = b"Hello, Rust!"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 5]; + + // Attempt to read 5 bytes from the start + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Hello"); + assert_eq!(cursor.position(), 5); + } + + #[test] + fn test_read_exact_exact_eof() { + let data = b"Data"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 4]; + + // Attempt to read exactly 4 bytes, which is the entire buffer + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Data"); + assert_eq!(cursor.position(), 4); + + // Further attempt to read should fail with EOF + let mut buffer_eof = [0u8; 1]; + let result = cursor.read_exact(&mut buffer_eof); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 4); // Position should remain at EOF + } + + #[test] + fn test_read_exact_past_eof() { + let data = b"Short"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 10]; // Requesting more bytes than available + + // Attempt to read 10 bytes from a 5-byte buffer + let result = cursor.read_exact(&mut buffer); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 5); // Position should move to EOF + } + + #[test] + fn test_read_exact_empty_buffer() { + let data = b"Non-empty"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 0]; // Zero-length buffer + + // Attempt to read zero bytes + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(cursor.position(), 0); // Position should remain unchanged + } + + #[test] + fn test_read_exact_from_empty_cursor() { + let data: &[u8] = b""; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 5]; + + // Attempt to read from an empty cursor + let result = cursor.read_exact(&mut buffer); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 0); // Position remains at 0 + } + + #[test] + fn test_read_exact_multiple_reads() { + let data = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + let mut cursor = Cursor::new(data); + + let mut buffer1 = [0u8; 10]; + let mut buffer2 = [0u8; 10]; + let mut buffer3 = [0u8; 10]; // Only 6 bytes left + + // First read: 10 bytes + assert!(cursor.read_exact(&mut buffer1).is_ok()); + assert_eq!(&buffer1, b"ABCDEFGHIJ"); + assert_eq!(cursor.position(), 10); + + // Second read: 10 bytes + assert!(cursor.read_exact(&mut buffer2).is_ok()); + assert_eq!(&buffer2, b"KLMNOPQRST"); + assert_eq!(cursor.position(), 20); + + // Third read: Attempt to read 10 bytes, but only 6 are available + let result = cursor.read_exact(&mut buffer3); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + // read_exact makes no promises about the content of the buffer on error + // assert_eq!(&buffer3[..6], b"UVWXYZ"); + assert_eq!(cursor.position(), 26); // Position should be at EOF + } + + #[test] + fn test_cursor_read_exact_after_eof() { + let data = b"End"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 3]; + + // First read: read the entire buffer + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"End"); + assert_eq!(cursor.position(), 3); + + // Second read: attempt to read again, should fail + let mut buffer_eof = [0u8; 1]; + let result = cursor.read_exact(&mut buffer_eof); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 3); // Position remains at EOF + } + + #[test] + fn test_slice_read_exact_success() { + let data = b"SliceReadTest"; + let mut slice = &data[..]; + let mut buffer = [0u8; 13]; // Exact length + + // Using Read trait directly on slice + assert!(slice.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"SliceReadTest"); + } + + #[test] + fn test_slice_read_exact_partial() { + let data = b"SlicePartial"; + let mut slice = &data[..]; + let mut buffer = [0u8; 20]; // Request more bytes than available + + // Using Read trait directly on slice + let result = slice.read_exact(&mut buffer); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + // read_exact makes no promises about the content of the buffer on error + } +} + /// Arr is an XDR Typedef defines as: /// /// ```text @@ -2857,7 +3068,7 @@ pub struct HasOptions { } impl ReadXdr for HasOptions { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { Ok(Self{ @@ -2870,7 +3081,7 @@ third_option: Option::::read_xdr(r)?, } impl WriteXdr for HasOptions { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { self.first_option.write_xdr(w)?; @@ -2969,7 +3180,7 @@ TypeVariant::HasOptions, ]; pub const VARIANTS_STR: [&'static str; 2] = [ "Arr", "HasOptions", ]; - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] #[allow(clippy::too_many_lines)] pub fn read_xdr(v: TypeVariant, r: &mut Limited) -> Result { match v { @@ -2985,7 +3196,7 @@ TypeVariant::HasOptions => r.with_limited_depth(|r| Ok(Self::HasOptions(Box::new Ok(t) } - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] pub fn read_xdr_to_end(v: TypeVariant, r: &mut Limited) -> Result { let s = Self::read_xdr(v, r)?; // Check that any further reads, such as this read of one byte, read no @@ -3032,7 +3243,7 @@ TypeVariant::HasOptions => Box::new(ReadXdrIter::<_, HasOptions>::new(dec, r.lim } } - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] pub fn from_xdr>(v: TypeVariant, bytes: B, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(v, &mut cursor)?; @@ -3121,7 +3332,7 @@ Self::HasOptions(_) => TypeVariant::HasOptions, } impl WriteXdr for Type { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] #[allow(clippy::too_many_lines)] fn write_xdr(&self, w: &mut Limited) -> Result<()> { match self { diff --git a/spec/output/generator_spec_rust/struct.x/MyXDR.rs b/spec/output/generator_spec_rust/struct.x/MyXDR.rs index 96206ef71..908fed8d5 100644 --- a/spec/output/generator_spec_rust/struct.x/MyXDR.rs +++ b/spec/output/generator_spec_rust/struct.x/MyXDR.rs @@ -50,7 +50,7 @@ use std::{ io::{BufRead, BufReader, Cursor, Read, Write}, }; -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] use embedded_io_extras::{Cursor, Error as _, ErrorType, Read, Write}; /// Error contains all errors returned by functions in this crate. It can be @@ -68,7 +68,7 @@ pub enum Error { InvalidHex, #[cfg(feature = "std")] Io(io::Error), - #[cfg(all(not(feature = "std"), feature = "alloc"))] + #[cfg(feature = "embedded_io")] Io(embedded_io_extras::ErrorKind), DepthLimitExceeded, #[cfg(feature = "serde_json")] @@ -86,15 +86,14 @@ impl PartialEq for Error { // case for comparing errors outputted by the XDR library is for // error case testing, and a lack of the ability to compare has a // detrimental affect on failure testing, so this is a tradeoff. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] (Self::Io(l), Self::Io(r)) => l.kind() == r.kind(), _ => core::mem::discriminant(self) == core::mem::discriminant(other), } } } - -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl embedded_io_extras::Error for Error { fn kind(&self) -> embedded_io_extras::ErrorKind { match self { @@ -104,7 +103,7 @@ impl embedded_io_extras::Error for Error { } } -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl From> for Error { fn from(value: embedded_io_extras::ReadExactError) -> Self { match value { @@ -140,7 +139,7 @@ impl fmt::Display for Error { Error::InvalidHex => write!(f, "hex invalid"), #[cfg(feature = "std")] Error::Io(e) => write!(f, "{e}"), - #[cfg(all(not(feature = "std"), feature = "alloc"))] + #[cfg(feature = "embedded_io")] Error::Io(_) => write!(f, "io error"), Error::DepthLimitExceeded => write!(f, "depth limit exceeded"), #[cfg(feature = "serde_json")] @@ -194,7 +193,7 @@ impl From for () { #[allow(dead_code)] type Result = core::result::Result; -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl ErrorType for Limited { type Error = Error; } /// Name defines types that assign a static name to their value, such as the @@ -230,7 +229,7 @@ where /// `Limits` contains the limits that a limited reader or writer will be /// constrained to. -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] #[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct Limits { /// Defines the maximum depth for recursive calls in `Read/WriteXdr` to @@ -247,7 +246,7 @@ pub struct Limits { pub len: usize, } -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] impl Limits { #[must_use] pub fn none() -> Self { @@ -278,13 +277,13 @@ impl Limits { /// /// Intended for use with readers and writers and limiting their reads and /// writes. -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] pub struct Limited { pub inner: L, pub(crate) limits: Limits, } -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] impl Limited { /// Constructs a new `Limited`. /// @@ -337,8 +336,7 @@ impl Read for Limited { } } - -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl Read for Limited { /// Forwards the read operation to the wrapped object. fn read(&mut self, buf: &mut [u8]) -> core::result::Result { @@ -372,7 +370,7 @@ impl Write for Limited { } } -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl Write for Limited { /// Forwards the write operation to the wrapped object. fn write(&mut self, buf: &[u8]) -> core::result::Result { @@ -457,7 +455,7 @@ where /// /// Use [`ReadXdR: Read_xdr_to_end`] when the intent is for all bytes in the /// read implementation to be consumed by the read. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result; /// Construct the type from the XDR bytes base64 encoded. @@ -492,7 +490,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr_to_end(r: &mut Limited) -> Result { let s = Self::read_xdr(r)?; // Check that any further reads, such as this read of one byte, read no @@ -532,7 +530,7 @@ where /// /// Use [`ReadXdR: Read_xdr_into_to_end`] when the intent is for all bytes /// in the read implementation to be consumed by the read. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr_into(&mut self, r: &mut Limited) -> Result<()> { *self = Self::read_xdr(r)?; Ok(()) @@ -556,7 +554,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr_into_to_end(&mut self, r: &mut Limited) -> Result<()> { Self::read_xdr_into(self, r)?; // Check that any further reads, such as this read of one byte, read no @@ -605,7 +603,7 @@ where /// /// An error is returned if the bytes are not completely consumed by the /// deserialization. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn from_xdr(bytes: impl AsRef<[u8]>, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(&mut cursor)?; @@ -629,10 +627,10 @@ where } pub trait WriteXdr { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()>; - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn to_xdr(&self, limits: Limits) -> Result> { let mut cursor = Limited::new(Cursor::new(vec![]), limits); self.write_xdr(&mut cursor)?; @@ -654,13 +652,13 @@ pub trait WriteXdr { /// `Pad_len` returns the number of bytes to pad an XDR value of the given /// length to make the final serialized size a multiple of 4. -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] fn pad_len(len: usize) -> usize { (4 - (len % 4)) % 4 } impl ReadXdr for i32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -672,7 +670,7 @@ impl ReadXdr for i32 { } impl WriteXdr for i32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -683,7 +681,7 @@ impl WriteXdr for i32 { } impl ReadXdr for u32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -695,7 +693,7 @@ impl ReadXdr for u32 { } impl WriteXdr for u32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -706,7 +704,7 @@ impl WriteXdr for u32 { } impl ReadXdr for i64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -718,7 +716,7 @@ impl ReadXdr for i64 { } impl WriteXdr for i64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -729,7 +727,7 @@ impl WriteXdr for i64 { } impl ReadXdr for u64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -741,7 +739,7 @@ impl ReadXdr for u64 { } impl WriteXdr for u64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -752,35 +750,35 @@ impl WriteXdr for u64 { } impl ReadXdr for f32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for f64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for bool { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -791,7 +789,7 @@ impl ReadXdr for bool { } impl WriteXdr for bool { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i = u32::from(*self); // true = 1, false = 0 @@ -801,7 +799,7 @@ impl WriteXdr for bool { } impl ReadXdr for Option { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -818,7 +816,7 @@ impl ReadXdr for Option { } impl WriteXdr for Option { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { if let Some(t) = self { @@ -833,35 +831,35 @@ impl WriteXdr for Option { } impl ReadXdr for Box { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| Ok(Box::new(T::read_xdr(r)?))) } } impl WriteXdr for Box { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| T::write_xdr(self, w)) } } impl ReadXdr for () { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(_r: &mut Limited) -> Result { Ok(()) } } impl WriteXdr for () { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { Ok(()) } } impl ReadXdr for [u8; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { r.consume_len(N)?; @@ -880,7 +878,7 @@ impl ReadXdr for [u8; N] { } impl WriteXdr for [u8; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { w.consume_len(N)?; @@ -894,7 +892,7 @@ impl WriteXdr for [u8; N] { } impl ReadXdr for [T; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let mut vec = Vec::with_capacity(N); @@ -909,7 +907,7 @@ impl ReadXdr for [T; N] { } impl WriteXdr for [T; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { for t in self { @@ -1268,7 +1266,7 @@ impl<'a, const MAX: u32> TryFrom<&'a VecM> for &'a str { } impl ReadXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1295,7 +1293,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1315,7 +1313,7 @@ impl WriteXdr for VecM { } impl ReadXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len = u32::read_xdr(r)?; @@ -1335,7 +1333,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1708,7 +1706,7 @@ impl<'a, const MAX: u32> TryFrom<&'a BytesM> for &'a str { } impl ReadXdr for BytesM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1735,7 +1733,7 @@ impl ReadXdr for BytesM { } impl WriteXdr for BytesM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2111,7 +2109,7 @@ impl<'a, const MAX: u32> TryFrom<&'a StringM> for &'a str { } impl ReadXdr for StringM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -2138,7 +2136,7 @@ impl ReadXdr for StringM { } impl WriteXdr for StringM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2184,7 +2182,7 @@ impl ReadXdr for Frame where T: ReadXdr, { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { // Read the frame header value that contains 1 flag-bit and a 33-bit length. // - The 1 flag bit is 0 when there are more frames for the same record. @@ -2204,7 +2202,7 @@ where } } -#[cfg(all(test, feature = "alloc"))] +#[cfg(all(test, any(feature = "std", feature = "embedded_io")))] mod tests { use super::*; @@ -2314,7 +2312,7 @@ mod tests { } } -#[cfg(all(test, feature = "alloc"))] +#[cfg(all(test, any(feature = "std", feature = "embedded_io")))] mod test { use super::*; @@ -2827,6 +2825,219 @@ mod test { } } +#[cfg(all(test, any(feature = "std", feature = "embedded_io")))] +mod test_io { + // We will use different IO libraries according to the feature, + // we hope the selected IO library can work as expected + + use super::*; + + #[test] + fn test_read_exact_success() { + let data = b"The quick brown fox jumps over the lazy dog."; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 19]; // Exactly the length of "The quick brown fox" + + // Attempt to read exactly 19 bytes + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"The quick brown fox"); + assert_eq!(cursor.position(), 19); + } + + #[test] + fn test_read_exact_less_than_available() { + let data = b"Hello, Rust!"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 5]; + + // Attempt to read 5 bytes from the start + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Hello"); + assert_eq!(cursor.position(), 5); + } + + #[test] + fn test_read_exact_exact_eof() { + let data = b"Data"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 4]; + + // Attempt to read exactly 4 bytes, which is the entire buffer + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Data"); + assert_eq!(cursor.position(), 4); + + // Further attempt to read should fail with EOF + let mut buffer_eof = [0u8; 1]; + let result = cursor.read_exact(&mut buffer_eof); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 4); // Position should remain at EOF + } + + #[test] + fn test_read_exact_past_eof() { + let data = b"Short"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 10]; // Requesting more bytes than available + + // Attempt to read 10 bytes from a 5-byte buffer + let result = cursor.read_exact(&mut buffer); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 5); // Position should move to EOF + } + + #[test] + fn test_read_exact_empty_buffer() { + let data = b"Non-empty"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 0]; // Zero-length buffer + + // Attempt to read zero bytes + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(cursor.position(), 0); // Position should remain unchanged + } + + #[test] + fn test_read_exact_from_empty_cursor() { + let data: &[u8] = b""; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 5]; + + // Attempt to read from an empty cursor + let result = cursor.read_exact(&mut buffer); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 0); // Position remains at 0 + } + + #[test] + fn test_read_exact_multiple_reads() { + let data = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + let mut cursor = Cursor::new(data); + + let mut buffer1 = [0u8; 10]; + let mut buffer2 = [0u8; 10]; + let mut buffer3 = [0u8; 10]; // Only 6 bytes left + + // First read: 10 bytes + assert!(cursor.read_exact(&mut buffer1).is_ok()); + assert_eq!(&buffer1, b"ABCDEFGHIJ"); + assert_eq!(cursor.position(), 10); + + // Second read: 10 bytes + assert!(cursor.read_exact(&mut buffer2).is_ok()); + assert_eq!(&buffer2, b"KLMNOPQRST"); + assert_eq!(cursor.position(), 20); + + // Third read: Attempt to read 10 bytes, but only 6 are available + let result = cursor.read_exact(&mut buffer3); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + // read_exact makes no promises about the content of the buffer on error + // assert_eq!(&buffer3[..6], b"UVWXYZ"); + assert_eq!(cursor.position(), 26); // Position should be at EOF + } + + #[test] + fn test_cursor_read_exact_after_eof() { + let data = b"End"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 3]; + + // First read: read the entire buffer + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"End"); + assert_eq!(cursor.position(), 3); + + // Second read: attempt to read again, should fail + let mut buffer_eof = [0u8; 1]; + let result = cursor.read_exact(&mut buffer_eof); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 3); // Position remains at EOF + } + + #[test] + fn test_slice_read_exact_success() { + let data = b"SliceReadTest"; + let mut slice = &data[..]; + let mut buffer = [0u8; 13]; // Exact length + + // Using Read trait directly on slice + assert!(slice.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"SliceReadTest"); + } + + #[test] + fn test_slice_read_exact_partial() { + let data = b"SlicePartial"; + let mut slice = &data[..]; + let mut buffer = [0u8; 20]; // Request more bytes than available + + // Using Read trait directly on slice + let result = slice.read_exact(&mut buffer); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + // read_exact makes no promises about the content of the buffer on error + } +} + /// Int64 is an XDR Typedef defines as: /// /// ```text @@ -2861,7 +3072,7 @@ pub struct MyStruct { } impl ReadXdr for MyStruct { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { Ok(Self{ @@ -2876,7 +3087,7 @@ max_string: StringM::<100>::read_xdr(r)?, } impl WriteXdr for MyStruct { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { self.some_int.write_xdr(w)?; @@ -2977,7 +3188,7 @@ TypeVariant::MyStruct, ]; pub const VARIANTS_STR: [&'static str; 2] = [ "Int64", "MyStruct", ]; - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] #[allow(clippy::too_many_lines)] pub fn read_xdr(v: TypeVariant, r: &mut Limited) -> Result { match v { @@ -2993,7 +3204,7 @@ TypeVariant::MyStruct => r.with_limited_depth(|r| Ok(Self::MyStruct(Box::new(MyS Ok(t) } - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] pub fn read_xdr_to_end(v: TypeVariant, r: &mut Limited) -> Result { let s = Self::read_xdr(v, r)?; // Check that any further reads, such as this read of one byte, read no @@ -3040,7 +3251,7 @@ TypeVariant::MyStruct => Box::new(ReadXdrIter::<_, MyStruct>::new(dec, r.limits. } } - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] pub fn from_xdr>(v: TypeVariant, bytes: B, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(v, &mut cursor)?; @@ -3129,7 +3340,7 @@ Self::MyStruct(_) => TypeVariant::MyStruct, } impl WriteXdr for Type { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] #[allow(clippy::too_many_lines)] fn write_xdr(&self, w: &mut Limited) -> Result<()> { match self { diff --git a/spec/output/generator_spec_rust/test.x/MyXDR.rs b/spec/output/generator_spec_rust/test.x/MyXDR.rs index e5aac9e17..95ab6e44b 100644 --- a/spec/output/generator_spec_rust/test.x/MyXDR.rs +++ b/spec/output/generator_spec_rust/test.x/MyXDR.rs @@ -50,7 +50,7 @@ use std::{ io::{BufRead, BufReader, Cursor, Read, Write}, }; -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] use embedded_io_extras::{Cursor, Error as _, ErrorType, Read, Write}; /// Error contains all errors returned by functions in this crate. It can be @@ -68,7 +68,7 @@ pub enum Error { InvalidHex, #[cfg(feature = "std")] Io(io::Error), - #[cfg(all(not(feature = "std"), feature = "alloc"))] + #[cfg(feature = "embedded_io")] Io(embedded_io_extras::ErrorKind), DepthLimitExceeded, #[cfg(feature = "serde_json")] @@ -86,15 +86,14 @@ impl PartialEq for Error { // case for comparing errors outputted by the XDR library is for // error case testing, and a lack of the ability to compare has a // detrimental affect on failure testing, so this is a tradeoff. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] (Self::Io(l), Self::Io(r)) => l.kind() == r.kind(), _ => core::mem::discriminant(self) == core::mem::discriminant(other), } } } - -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl embedded_io_extras::Error for Error { fn kind(&self) -> embedded_io_extras::ErrorKind { match self { @@ -104,7 +103,7 @@ impl embedded_io_extras::Error for Error { } } -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl From> for Error { fn from(value: embedded_io_extras::ReadExactError) -> Self { match value { @@ -140,7 +139,7 @@ impl fmt::Display for Error { Error::InvalidHex => write!(f, "hex invalid"), #[cfg(feature = "std")] Error::Io(e) => write!(f, "{e}"), - #[cfg(all(not(feature = "std"), feature = "alloc"))] + #[cfg(feature = "embedded_io")] Error::Io(_) => write!(f, "io error"), Error::DepthLimitExceeded => write!(f, "depth limit exceeded"), #[cfg(feature = "serde_json")] @@ -194,7 +193,7 @@ impl From for () { #[allow(dead_code)] type Result = core::result::Result; -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl ErrorType for Limited { type Error = Error; } /// Name defines types that assign a static name to their value, such as the @@ -230,7 +229,7 @@ where /// `Limits` contains the limits that a limited reader or writer will be /// constrained to. -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] #[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct Limits { /// Defines the maximum depth for recursive calls in `Read/WriteXdr` to @@ -247,7 +246,7 @@ pub struct Limits { pub len: usize, } -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] impl Limits { #[must_use] pub fn none() -> Self { @@ -278,13 +277,13 @@ impl Limits { /// /// Intended for use with readers and writers and limiting their reads and /// writes. -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] pub struct Limited { pub inner: L, pub(crate) limits: Limits, } -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] impl Limited { /// Constructs a new `Limited`. /// @@ -337,8 +336,7 @@ impl Read for Limited { } } - -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl Read for Limited { /// Forwards the read operation to the wrapped object. fn read(&mut self, buf: &mut [u8]) -> core::result::Result { @@ -372,7 +370,7 @@ impl Write for Limited { } } -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl Write for Limited { /// Forwards the write operation to the wrapped object. fn write(&mut self, buf: &[u8]) -> core::result::Result { @@ -457,7 +455,7 @@ where /// /// Use [`ReadXdR: Read_xdr_to_end`] when the intent is for all bytes in the /// read implementation to be consumed by the read. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result; /// Construct the type from the XDR bytes base64 encoded. @@ -492,7 +490,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr_to_end(r: &mut Limited) -> Result { let s = Self::read_xdr(r)?; // Check that any further reads, such as this read of one byte, read no @@ -532,7 +530,7 @@ where /// /// Use [`ReadXdR: Read_xdr_into_to_end`] when the intent is for all bytes /// in the read implementation to be consumed by the read. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr_into(&mut self, r: &mut Limited) -> Result<()> { *self = Self::read_xdr(r)?; Ok(()) @@ -556,7 +554,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr_into_to_end(&mut self, r: &mut Limited) -> Result<()> { Self::read_xdr_into(self, r)?; // Check that any further reads, such as this read of one byte, read no @@ -605,7 +603,7 @@ where /// /// An error is returned if the bytes are not completely consumed by the /// deserialization. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn from_xdr(bytes: impl AsRef<[u8]>, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(&mut cursor)?; @@ -629,10 +627,10 @@ where } pub trait WriteXdr { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()>; - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn to_xdr(&self, limits: Limits) -> Result> { let mut cursor = Limited::new(Cursor::new(vec![]), limits); self.write_xdr(&mut cursor)?; @@ -654,13 +652,13 @@ pub trait WriteXdr { /// `Pad_len` returns the number of bytes to pad an XDR value of the given /// length to make the final serialized size a multiple of 4. -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] fn pad_len(len: usize) -> usize { (4 - (len % 4)) % 4 } impl ReadXdr for i32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -672,7 +670,7 @@ impl ReadXdr for i32 { } impl WriteXdr for i32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -683,7 +681,7 @@ impl WriteXdr for i32 { } impl ReadXdr for u32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -695,7 +693,7 @@ impl ReadXdr for u32 { } impl WriteXdr for u32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -706,7 +704,7 @@ impl WriteXdr for u32 { } impl ReadXdr for i64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -718,7 +716,7 @@ impl ReadXdr for i64 { } impl WriteXdr for i64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -729,7 +727,7 @@ impl WriteXdr for i64 { } impl ReadXdr for u64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -741,7 +739,7 @@ impl ReadXdr for u64 { } impl WriteXdr for u64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -752,35 +750,35 @@ impl WriteXdr for u64 { } impl ReadXdr for f32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for f64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for bool { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -791,7 +789,7 @@ impl ReadXdr for bool { } impl WriteXdr for bool { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i = u32::from(*self); // true = 1, false = 0 @@ -801,7 +799,7 @@ impl WriteXdr for bool { } impl ReadXdr for Option { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -818,7 +816,7 @@ impl ReadXdr for Option { } impl WriteXdr for Option { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { if let Some(t) = self { @@ -833,35 +831,35 @@ impl WriteXdr for Option { } impl ReadXdr for Box { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| Ok(Box::new(T::read_xdr(r)?))) } } impl WriteXdr for Box { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| T::write_xdr(self, w)) } } impl ReadXdr for () { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(_r: &mut Limited) -> Result { Ok(()) } } impl WriteXdr for () { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { Ok(()) } } impl ReadXdr for [u8; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { r.consume_len(N)?; @@ -880,7 +878,7 @@ impl ReadXdr for [u8; N] { } impl WriteXdr for [u8; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { w.consume_len(N)?; @@ -894,7 +892,7 @@ impl WriteXdr for [u8; N] { } impl ReadXdr for [T; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let mut vec = Vec::with_capacity(N); @@ -909,7 +907,7 @@ impl ReadXdr for [T; N] { } impl WriteXdr for [T; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { for t in self { @@ -1268,7 +1266,7 @@ impl<'a, const MAX: u32> TryFrom<&'a VecM> for &'a str { } impl ReadXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1295,7 +1293,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1315,7 +1313,7 @@ impl WriteXdr for VecM { } impl ReadXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len = u32::read_xdr(r)?; @@ -1335,7 +1333,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1708,7 +1706,7 @@ impl<'a, const MAX: u32> TryFrom<&'a BytesM> for &'a str { } impl ReadXdr for BytesM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1735,7 +1733,7 @@ impl ReadXdr for BytesM { } impl WriteXdr for BytesM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2111,7 +2109,7 @@ impl<'a, const MAX: u32> TryFrom<&'a StringM> for &'a str { } impl ReadXdr for StringM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -2138,7 +2136,7 @@ impl ReadXdr for StringM { } impl WriteXdr for StringM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2184,7 +2182,7 @@ impl ReadXdr for Frame where T: ReadXdr, { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { // Read the frame header value that contains 1 flag-bit and a 33-bit length. // - The 1 flag bit is 0 when there are more frames for the same record. @@ -2204,7 +2202,7 @@ where } } -#[cfg(all(test, feature = "alloc"))] +#[cfg(all(test, any(feature = "std", feature = "embedded_io")))] mod tests { use super::*; @@ -2314,7 +2312,7 @@ mod tests { } } -#[cfg(all(test, feature = "alloc"))] +#[cfg(all(test, any(feature = "std", feature = "embedded_io")))] mod test { use super::*; @@ -2827,6 +2825,219 @@ mod test { } } +#[cfg(all(test, any(feature = "std", feature = "embedded_io")))] +mod test_io { + // We will use different IO libraries according to the feature, + // we hope the selected IO library can work as expected + + use super::*; + + #[test] + fn test_read_exact_success() { + let data = b"The quick brown fox jumps over the lazy dog."; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 19]; // Exactly the length of "The quick brown fox" + + // Attempt to read exactly 19 bytes + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"The quick brown fox"); + assert_eq!(cursor.position(), 19); + } + + #[test] + fn test_read_exact_less_than_available() { + let data = b"Hello, Rust!"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 5]; + + // Attempt to read 5 bytes from the start + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Hello"); + assert_eq!(cursor.position(), 5); + } + + #[test] + fn test_read_exact_exact_eof() { + let data = b"Data"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 4]; + + // Attempt to read exactly 4 bytes, which is the entire buffer + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Data"); + assert_eq!(cursor.position(), 4); + + // Further attempt to read should fail with EOF + let mut buffer_eof = [0u8; 1]; + let result = cursor.read_exact(&mut buffer_eof); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 4); // Position should remain at EOF + } + + #[test] + fn test_read_exact_past_eof() { + let data = b"Short"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 10]; // Requesting more bytes than available + + // Attempt to read 10 bytes from a 5-byte buffer + let result = cursor.read_exact(&mut buffer); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 5); // Position should move to EOF + } + + #[test] + fn test_read_exact_empty_buffer() { + let data = b"Non-empty"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 0]; // Zero-length buffer + + // Attempt to read zero bytes + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(cursor.position(), 0); // Position should remain unchanged + } + + #[test] + fn test_read_exact_from_empty_cursor() { + let data: &[u8] = b""; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 5]; + + // Attempt to read from an empty cursor + let result = cursor.read_exact(&mut buffer); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 0); // Position remains at 0 + } + + #[test] + fn test_read_exact_multiple_reads() { + let data = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + let mut cursor = Cursor::new(data); + + let mut buffer1 = [0u8; 10]; + let mut buffer2 = [0u8; 10]; + let mut buffer3 = [0u8; 10]; // Only 6 bytes left + + // First read: 10 bytes + assert!(cursor.read_exact(&mut buffer1).is_ok()); + assert_eq!(&buffer1, b"ABCDEFGHIJ"); + assert_eq!(cursor.position(), 10); + + // Second read: 10 bytes + assert!(cursor.read_exact(&mut buffer2).is_ok()); + assert_eq!(&buffer2, b"KLMNOPQRST"); + assert_eq!(cursor.position(), 20); + + // Third read: Attempt to read 10 bytes, but only 6 are available + let result = cursor.read_exact(&mut buffer3); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + // read_exact makes no promises about the content of the buffer on error + // assert_eq!(&buffer3[..6], b"UVWXYZ"); + assert_eq!(cursor.position(), 26); // Position should be at EOF + } + + #[test] + fn test_cursor_read_exact_after_eof() { + let data = b"End"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 3]; + + // First read: read the entire buffer + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"End"); + assert_eq!(cursor.position(), 3); + + // Second read: attempt to read again, should fail + let mut buffer_eof = [0u8; 1]; + let result = cursor.read_exact(&mut buffer_eof); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 3); // Position remains at EOF + } + + #[test] + fn test_slice_read_exact_success() { + let data = b"SliceReadTest"; + let mut slice = &data[..]; + let mut buffer = [0u8; 13]; // Exact length + + // Using Read trait directly on slice + assert!(slice.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"SliceReadTest"); + } + + #[test] + fn test_slice_read_exact_partial() { + let data = b"SlicePartial"; + let mut slice = &data[..]; + let mut buffer = [0u8; 20]; // Request more bytes than available + + // Using Read trait directly on slice + let result = slice.read_exact(&mut buffer); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + // read_exact makes no promises about the content of the buffer on error + } +} + /// Uint512 is an XDR Typedef defines as: /// /// ```text @@ -2921,7 +3132,7 @@ impl AsRef<[u8; 64]> for Uint512 { } impl ReadXdr for Uint512 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = <[u8; 64]>::read_xdr(r)?; @@ -2932,7 +3143,7 @@ impl ReadXdr for Uint512 { } impl WriteXdr for Uint512 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w|{ self.0.write_xdr(w) }) } @@ -3011,7 +3222,7 @@ impl AsRef> for Uint513 { } impl ReadXdr for Uint513 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = BytesM::<64>::read_xdr(r)?; @@ -3022,7 +3233,7 @@ impl ReadXdr for Uint513 { } impl WriteXdr for Uint513 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w|{ self.0.write_xdr(w) }) } @@ -3113,7 +3324,7 @@ impl AsRef for Uint514 { } impl ReadXdr for Uint514 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = BytesM::read_xdr(r)?; @@ -3124,7 +3335,7 @@ impl ReadXdr for Uint514 { } impl WriteXdr for Uint514 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w|{ self.0.write_xdr(w) }) } @@ -3215,7 +3426,7 @@ impl AsRef> for Str { } impl ReadXdr for Str { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = StringM::<64>::read_xdr(r)?; @@ -3226,7 +3437,7 @@ impl ReadXdr for Str { } impl WriteXdr for Str { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w|{ self.0.write_xdr(w) }) } @@ -3317,7 +3528,7 @@ impl AsRef for Str2 { } impl ReadXdr for Str2 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = StringM::read_xdr(r)?; @@ -3328,7 +3539,7 @@ impl ReadXdr for Str2 { } impl WriteXdr for Str2 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w|{ self.0.write_xdr(w) }) } @@ -3477,7 +3688,7 @@ impl AsRef<[u8; 32]> for Hash { } impl ReadXdr for Hash { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = <[u8; 32]>::read_xdr(r)?; @@ -3488,7 +3699,7 @@ impl ReadXdr for Hash { } impl WriteXdr for Hash { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w|{ self.0.write_xdr(w) }) } @@ -3566,7 +3777,7 @@ impl AsRef<[Hash; 12]> for Hashes1 { } impl ReadXdr for Hashes1 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = <[Hash; 12]>::read_xdr(r)?; @@ -3577,7 +3788,7 @@ impl ReadXdr for Hashes1 { } impl WriteXdr for Hashes1 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w|{ self.0.write_xdr(w) }) } @@ -3656,7 +3867,7 @@ impl AsRef> for Hashes2 { } impl ReadXdr for Hashes2 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = VecM::::read_xdr(r)?; @@ -3667,7 +3878,7 @@ impl ReadXdr for Hashes2 { } impl WriteXdr for Hashes2 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w|{ self.0.write_xdr(w) }) } @@ -3758,7 +3969,7 @@ impl AsRef> for Hashes3 { } impl ReadXdr for Hashes3 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = VecM::::read_xdr(r)?; @@ -3769,7 +3980,7 @@ impl ReadXdr for Hashes3 { } impl WriteXdr for Hashes3 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w|{ self.0.write_xdr(w) }) } @@ -3859,7 +4070,7 @@ impl AsRef> for OptHash1 { } impl ReadXdr for OptHash1 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = Option::::read_xdr(r)?; @@ -3870,7 +4081,7 @@ impl ReadXdr for OptHash1 { } impl WriteXdr for OptHash1 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w|{ self.0.write_xdr(w) }) } @@ -3911,7 +4122,7 @@ impl AsRef> for OptHash2 { } impl ReadXdr for OptHash2 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = Option::::read_xdr(r)?; @@ -3922,7 +4133,7 @@ impl ReadXdr for OptHash2 { } impl WriteXdr for OptHash2 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w|{ self.0.write_xdr(w) }) } @@ -3990,7 +4201,7 @@ pub struct MyStruct { } impl ReadXdr for MyStruct { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { Ok(Self{ @@ -4007,7 +4218,7 @@ field7: bool::read_xdr(r)?, } impl WriteXdr for MyStruct { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { self.field1.write_xdr(w)?; @@ -4040,7 +4251,7 @@ pub struct LotsOfMyStructs { } impl ReadXdr for LotsOfMyStructs { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { Ok(Self{ @@ -4051,7 +4262,7 @@ impl ReadXdr for LotsOfMyStructs { } impl WriteXdr for LotsOfMyStructs { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { self.members.write_xdr(w)?; @@ -4078,7 +4289,7 @@ pub struct HasStuff { } impl ReadXdr for HasStuff { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { Ok(Self{ @@ -4089,7 +4300,7 @@ impl ReadXdr for HasStuff { } impl WriteXdr for HasStuff { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { self.data.write_xdr(w)?; @@ -4187,7 +4398,7 @@ Self::Green => "Green", } impl ReadXdr for Color { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let e = i32::read_xdr(r)?; @@ -4198,7 +4409,7 @@ Self::Green => "Green", } impl WriteXdr for Color { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i: i32 = (*self).into(); @@ -4306,7 +4517,7 @@ Self::B2 => "B2", } impl ReadXdr for NesterNestedEnum { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let e = i32::read_xdr(r)?; @@ -4317,7 +4528,7 @@ Self::B2 => "B2", } impl WriteXdr for NesterNestedEnum { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i: i32 = (*self).into(); @@ -4343,7 +4554,7 @@ pub struct NesterNestedStruct { } impl ReadXdr for NesterNestedStruct { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { Ok(Self{ @@ -4354,7 +4565,7 @@ impl ReadXdr for NesterNestedStruct { } impl WriteXdr for NesterNestedStruct { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { self.blah.write_xdr(w)?; @@ -4436,7 +4647,7 @@ impl Variants for NesterNestedUnion { impl Union for NesterNestedUnion {} impl ReadXdr for NesterNestedUnion { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let dv: Color = ::read_xdr(r)?; @@ -4452,7 +4663,7 @@ impl ReadXdr for NesterNestedUnion { } impl WriteXdr for NesterNestedUnion { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { self.discriminant().write_xdr(w)?; @@ -4501,7 +4712,7 @@ pub struct Nester { } impl ReadXdr for Nester { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { Ok(Self{ @@ -4514,7 +4725,7 @@ nested_union: NesterNestedUnion::read_xdr(r)?, } impl WriteXdr for Nester { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { self.nested_enum.write_xdr(w)?; @@ -4802,7 +5013,7 @@ TypeVariant::NesterNestedUnion, ]; "NesterNestedStruct", "NesterNestedUnion", ]; - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] #[allow(clippy::too_many_lines)] pub fn read_xdr(v: TypeVariant, r: &mut Limited) -> Result { match v { @@ -4839,7 +5050,7 @@ TypeVariant::NesterNestedUnion => r.with_limited_depth(|r| Ok(Self::NesterNested Ok(t) } - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] pub fn read_xdr_to_end(v: TypeVariant, r: &mut Limited) -> Result { let s = Self::read_xdr(v, r)?; // Check that any further reads, such as this read of one byte, read no @@ -4949,7 +5160,7 @@ TypeVariant::NesterNestedUnion => Box::new(ReadXdrIter::<_, NesterNestedUnion>:: } } - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] pub fn from_xdr>(v: TypeVariant, bytes: B, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(v, &mut cursor)?; @@ -5143,7 +5354,7 @@ Self::NesterNestedUnion(_) => TypeVariant::NesterNestedUnion, } impl WriteXdr for Type { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] #[allow(clippy::too_many_lines)] fn write_xdr(&self, w: &mut Limited) -> Result<()> { match self { diff --git a/spec/output/generator_spec_rust/union.x/MyXDR.rs b/spec/output/generator_spec_rust/union.x/MyXDR.rs index c7c0f024d..ae06d165a 100644 --- a/spec/output/generator_spec_rust/union.x/MyXDR.rs +++ b/spec/output/generator_spec_rust/union.x/MyXDR.rs @@ -50,7 +50,7 @@ use std::{ io::{BufRead, BufReader, Cursor, Read, Write}, }; -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] use embedded_io_extras::{Cursor, Error as _, ErrorType, Read, Write}; /// Error contains all errors returned by functions in this crate. It can be @@ -68,7 +68,7 @@ pub enum Error { InvalidHex, #[cfg(feature = "std")] Io(io::Error), - #[cfg(all(not(feature = "std"), feature = "alloc"))] + #[cfg(feature = "embedded_io")] Io(embedded_io_extras::ErrorKind), DepthLimitExceeded, #[cfg(feature = "serde_json")] @@ -86,15 +86,14 @@ impl PartialEq for Error { // case for comparing errors outputted by the XDR library is for // error case testing, and a lack of the ability to compare has a // detrimental affect on failure testing, so this is a tradeoff. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] (Self::Io(l), Self::Io(r)) => l.kind() == r.kind(), _ => core::mem::discriminant(self) == core::mem::discriminant(other), } } } - -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl embedded_io_extras::Error for Error { fn kind(&self) -> embedded_io_extras::ErrorKind { match self { @@ -104,7 +103,7 @@ impl embedded_io_extras::Error for Error { } } -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl From> for Error { fn from(value: embedded_io_extras::ReadExactError) -> Self { match value { @@ -140,7 +139,7 @@ impl fmt::Display for Error { Error::InvalidHex => write!(f, "hex invalid"), #[cfg(feature = "std")] Error::Io(e) => write!(f, "{e}"), - #[cfg(all(not(feature = "std"), feature = "alloc"))] + #[cfg(feature = "embedded_io")] Error::Io(_) => write!(f, "io error"), Error::DepthLimitExceeded => write!(f, "depth limit exceeded"), #[cfg(feature = "serde_json")] @@ -194,7 +193,7 @@ impl From for () { #[allow(dead_code)] type Result = core::result::Result; -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl ErrorType for Limited { type Error = Error; } /// Name defines types that assign a static name to their value, such as the @@ -230,7 +229,7 @@ where /// `Limits` contains the limits that a limited reader or writer will be /// constrained to. -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] #[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct Limits { /// Defines the maximum depth for recursive calls in `Read/WriteXdr` to @@ -247,7 +246,7 @@ pub struct Limits { pub len: usize, } -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] impl Limits { #[must_use] pub fn none() -> Self { @@ -278,13 +277,13 @@ impl Limits { /// /// Intended for use with readers and writers and limiting their reads and /// writes. -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] pub struct Limited { pub inner: L, pub(crate) limits: Limits, } -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] impl Limited { /// Constructs a new `Limited`. /// @@ -337,8 +336,7 @@ impl Read for Limited { } } - -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl Read for Limited { /// Forwards the read operation to the wrapped object. fn read(&mut self, buf: &mut [u8]) -> core::result::Result { @@ -372,7 +370,7 @@ impl Write for Limited { } } -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl Write for Limited { /// Forwards the write operation to the wrapped object. fn write(&mut self, buf: &[u8]) -> core::result::Result { @@ -457,7 +455,7 @@ where /// /// Use [`ReadXdR: Read_xdr_to_end`] when the intent is for all bytes in the /// read implementation to be consumed by the read. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result; /// Construct the type from the XDR bytes base64 encoded. @@ -492,7 +490,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr_to_end(r: &mut Limited) -> Result { let s = Self::read_xdr(r)?; // Check that any further reads, such as this read of one byte, read no @@ -532,7 +530,7 @@ where /// /// Use [`ReadXdR: Read_xdr_into_to_end`] when the intent is for all bytes /// in the read implementation to be consumed by the read. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr_into(&mut self, r: &mut Limited) -> Result<()> { *self = Self::read_xdr(r)?; Ok(()) @@ -556,7 +554,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr_into_to_end(&mut self, r: &mut Limited) -> Result<()> { Self::read_xdr_into(self, r)?; // Check that any further reads, such as this read of one byte, read no @@ -605,7 +603,7 @@ where /// /// An error is returned if the bytes are not completely consumed by the /// deserialization. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn from_xdr(bytes: impl AsRef<[u8]>, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(&mut cursor)?; @@ -629,10 +627,10 @@ where } pub trait WriteXdr { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()>; - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn to_xdr(&self, limits: Limits) -> Result> { let mut cursor = Limited::new(Cursor::new(vec![]), limits); self.write_xdr(&mut cursor)?; @@ -654,13 +652,13 @@ pub trait WriteXdr { /// `Pad_len` returns the number of bytes to pad an XDR value of the given /// length to make the final serialized size a multiple of 4. -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] fn pad_len(len: usize) -> usize { (4 - (len % 4)) % 4 } impl ReadXdr for i32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -672,7 +670,7 @@ impl ReadXdr for i32 { } impl WriteXdr for i32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -683,7 +681,7 @@ impl WriteXdr for i32 { } impl ReadXdr for u32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -695,7 +693,7 @@ impl ReadXdr for u32 { } impl WriteXdr for u32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -706,7 +704,7 @@ impl WriteXdr for u32 { } impl ReadXdr for i64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -718,7 +716,7 @@ impl ReadXdr for i64 { } impl WriteXdr for i64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -729,7 +727,7 @@ impl WriteXdr for i64 { } impl ReadXdr for u64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -741,7 +739,7 @@ impl ReadXdr for u64 { } impl WriteXdr for u64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -752,35 +750,35 @@ impl WriteXdr for u64 { } impl ReadXdr for f32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for f64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for bool { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -791,7 +789,7 @@ impl ReadXdr for bool { } impl WriteXdr for bool { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i = u32::from(*self); // true = 1, false = 0 @@ -801,7 +799,7 @@ impl WriteXdr for bool { } impl ReadXdr for Option { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -818,7 +816,7 @@ impl ReadXdr for Option { } impl WriteXdr for Option { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { if let Some(t) = self { @@ -833,35 +831,35 @@ impl WriteXdr for Option { } impl ReadXdr for Box { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| Ok(Box::new(T::read_xdr(r)?))) } } impl WriteXdr for Box { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| T::write_xdr(self, w)) } } impl ReadXdr for () { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(_r: &mut Limited) -> Result { Ok(()) } } impl WriteXdr for () { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { Ok(()) } } impl ReadXdr for [u8; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { r.consume_len(N)?; @@ -880,7 +878,7 @@ impl ReadXdr for [u8; N] { } impl WriteXdr for [u8; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { w.consume_len(N)?; @@ -894,7 +892,7 @@ impl WriteXdr for [u8; N] { } impl ReadXdr for [T; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let mut vec = Vec::with_capacity(N); @@ -909,7 +907,7 @@ impl ReadXdr for [T; N] { } impl WriteXdr for [T; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { for t in self { @@ -1268,7 +1266,7 @@ impl<'a, const MAX: u32> TryFrom<&'a VecM> for &'a str { } impl ReadXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1295,7 +1293,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1315,7 +1313,7 @@ impl WriteXdr for VecM { } impl ReadXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len = u32::read_xdr(r)?; @@ -1335,7 +1333,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1708,7 +1706,7 @@ impl<'a, const MAX: u32> TryFrom<&'a BytesM> for &'a str { } impl ReadXdr for BytesM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1735,7 +1733,7 @@ impl ReadXdr for BytesM { } impl WriteXdr for BytesM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2111,7 +2109,7 @@ impl<'a, const MAX: u32> TryFrom<&'a StringM> for &'a str { } impl ReadXdr for StringM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -2138,7 +2136,7 @@ impl ReadXdr for StringM { } impl WriteXdr for StringM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2184,7 +2182,7 @@ impl ReadXdr for Frame where T: ReadXdr, { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { // Read the frame header value that contains 1 flag-bit and a 33-bit length. // - The 1 flag bit is 0 when there are more frames for the same record. @@ -2204,7 +2202,7 @@ where } } -#[cfg(all(test, feature = "alloc"))] +#[cfg(all(test, any(feature = "std", feature = "embedded_io")))] mod tests { use super::*; @@ -2314,7 +2312,7 @@ mod tests { } } -#[cfg(all(test, feature = "alloc"))] +#[cfg(all(test, any(feature = "std", feature = "embedded_io")))] mod test { use super::*; @@ -2827,6 +2825,219 @@ mod test { } } +#[cfg(all(test, any(feature = "std", feature = "embedded_io")))] +mod test_io { + // We will use different IO libraries according to the feature, + // we hope the selected IO library can work as expected + + use super::*; + + #[test] + fn test_read_exact_success() { + let data = b"The quick brown fox jumps over the lazy dog."; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 19]; // Exactly the length of "The quick brown fox" + + // Attempt to read exactly 19 bytes + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"The quick brown fox"); + assert_eq!(cursor.position(), 19); + } + + #[test] + fn test_read_exact_less_than_available() { + let data = b"Hello, Rust!"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 5]; + + // Attempt to read 5 bytes from the start + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Hello"); + assert_eq!(cursor.position(), 5); + } + + #[test] + fn test_read_exact_exact_eof() { + let data = b"Data"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 4]; + + // Attempt to read exactly 4 bytes, which is the entire buffer + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Data"); + assert_eq!(cursor.position(), 4); + + // Further attempt to read should fail with EOF + let mut buffer_eof = [0u8; 1]; + let result = cursor.read_exact(&mut buffer_eof); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 4); // Position should remain at EOF + } + + #[test] + fn test_read_exact_past_eof() { + let data = b"Short"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 10]; // Requesting more bytes than available + + // Attempt to read 10 bytes from a 5-byte buffer + let result = cursor.read_exact(&mut buffer); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 5); // Position should move to EOF + } + + #[test] + fn test_read_exact_empty_buffer() { + let data = b"Non-empty"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 0]; // Zero-length buffer + + // Attempt to read zero bytes + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(cursor.position(), 0); // Position should remain unchanged + } + + #[test] + fn test_read_exact_from_empty_cursor() { + let data: &[u8] = b""; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 5]; + + // Attempt to read from an empty cursor + let result = cursor.read_exact(&mut buffer); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 0); // Position remains at 0 + } + + #[test] + fn test_read_exact_multiple_reads() { + let data = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + let mut cursor = Cursor::new(data); + + let mut buffer1 = [0u8; 10]; + let mut buffer2 = [0u8; 10]; + let mut buffer3 = [0u8; 10]; // Only 6 bytes left + + // First read: 10 bytes + assert!(cursor.read_exact(&mut buffer1).is_ok()); + assert_eq!(&buffer1, b"ABCDEFGHIJ"); + assert_eq!(cursor.position(), 10); + + // Second read: 10 bytes + assert!(cursor.read_exact(&mut buffer2).is_ok()); + assert_eq!(&buffer2, b"KLMNOPQRST"); + assert_eq!(cursor.position(), 20); + + // Third read: Attempt to read 10 bytes, but only 6 are available + let result = cursor.read_exact(&mut buffer3); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + // read_exact makes no promises about the content of the buffer on error + // assert_eq!(&buffer3[..6], b"UVWXYZ"); + assert_eq!(cursor.position(), 26); // Position should be at EOF + } + + #[test] + fn test_cursor_read_exact_after_eof() { + let data = b"End"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 3]; + + // First read: read the entire buffer + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"End"); + assert_eq!(cursor.position(), 3); + + // Second read: attempt to read again, should fail + let mut buffer_eof = [0u8; 1]; + let result = cursor.read_exact(&mut buffer_eof); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 3); // Position remains at EOF + } + + #[test] + fn test_slice_read_exact_success() { + let data = b"SliceReadTest"; + let mut slice = &data[..]; + let mut buffer = [0u8; 13]; // Exact length + + // Using Read trait directly on slice + assert!(slice.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"SliceReadTest"); + } + + #[test] + fn test_slice_read_exact_partial() { + let data = b"SlicePartial"; + let mut slice = &data[..]; + let mut buffer = [0u8; 20]; // Request more bytes than available + + // Using Read trait directly on slice + let result = slice.read_exact(&mut buffer); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + // read_exact makes no promises about the content of the buffer on error + } +} + /// SError is an XDR Typedef defines as: /// /// ```text @@ -2926,7 +3137,7 @@ Self::Multi => "Multi", } impl ReadXdr for UnionKey { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let e = i32::read_xdr(r)?; @@ -2937,7 +3148,7 @@ Self::Multi => "Multi", } impl WriteXdr for UnionKey { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i: i32 = (*self).into(); @@ -3027,7 +3238,7 @@ Self::Multi(_) => UnionKey::Multi, impl Union for MyUnion {} impl ReadXdr for MyUnion { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let dv: UnionKey = ::read_xdr(r)?; @@ -3044,7 +3255,7 @@ UnionKey::Multi => Self::Multi(VecM::::read_xdr(r)?), } impl WriteXdr for MyUnion { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { self.discriminant().write_xdr(w)?; @@ -3138,7 +3349,7 @@ Self::V1(_) => 1, impl Union for IntUnion {} impl ReadXdr for IntUnion { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let dv: i32 = ::read_xdr(r)?; @@ -3155,7 +3366,7 @@ Self::V1(_) => 1, } impl WriteXdr for IntUnion { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { self.discriminant().write_xdr(w)?; @@ -3204,7 +3415,7 @@ impl AsRef for IntUnion2 { } impl ReadXdr for IntUnion2 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = IntUnion::read_xdr(r)?; @@ -3215,7 +3426,7 @@ impl ReadXdr for IntUnion2 { } impl WriteXdr for IntUnion2 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w|{ self.0.write_xdr(w) }) } @@ -3345,7 +3556,7 @@ TypeVariant::IntUnion2, ]; "IntUnion", "IntUnion2", ]; - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] #[allow(clippy::too_many_lines)] pub fn read_xdr(v: TypeVariant, r: &mut Limited) -> Result { match v { @@ -3365,7 +3576,7 @@ TypeVariant::IntUnion2 => r.with_limited_depth(|r| Ok(Self::IntUnion2(Box::new(I Ok(t) } - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] pub fn read_xdr_to_end(v: TypeVariant, r: &mut Limited) -> Result { let s = Self::read_xdr(v, r)?; // Check that any further reads, such as this read of one byte, read no @@ -3424,7 +3635,7 @@ TypeVariant::IntUnion2 => Box::new(ReadXdrIter::<_, IntUnion2>::new(dec, r.limit } } - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] pub fn from_xdr>(v: TypeVariant, bytes: B, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(v, &mut cursor)?; @@ -3533,7 +3744,7 @@ Self::IntUnion2(_) => TypeVariant::IntUnion2, } impl WriteXdr for Type { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] #[allow(clippy::too_many_lines)] fn write_xdr(&self, w: &mut Limited) -> Result<()> { match self { diff --git a/spec/output/generator_spec_rust_custom_jsonschema_impls/block_comments.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_jsonschema_impls/block_comments.x/MyXDR.rs index 925e06c32..b219d1dd8 100644 --- a/spec/output/generator_spec_rust_custom_jsonschema_impls/block_comments.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_jsonschema_impls/block_comments.x/MyXDR.rs @@ -50,7 +50,7 @@ use std::{ io::{BufRead, BufReader, Cursor, Read, Write}, }; -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] use embedded_io_extras::{Cursor, Error as _, ErrorType, Read, Write}; /// Error contains all errors returned by functions in this crate. It can be @@ -68,7 +68,7 @@ pub enum Error { InvalidHex, #[cfg(feature = "std")] Io(io::Error), - #[cfg(all(not(feature = "std"), feature = "alloc"))] + #[cfg(feature = "embedded_io")] Io(embedded_io_extras::ErrorKind), DepthLimitExceeded, #[cfg(feature = "serde_json")] @@ -86,15 +86,14 @@ impl PartialEq for Error { // case for comparing errors outputted by the XDR library is for // error case testing, and a lack of the ability to compare has a // detrimental affect on failure testing, so this is a tradeoff. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] (Self::Io(l), Self::Io(r)) => l.kind() == r.kind(), _ => core::mem::discriminant(self) == core::mem::discriminant(other), } } } - -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl embedded_io_extras::Error for Error { fn kind(&self) -> embedded_io_extras::ErrorKind { match self { @@ -104,7 +103,7 @@ impl embedded_io_extras::Error for Error { } } -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl From> for Error { fn from(value: embedded_io_extras::ReadExactError) -> Self { match value { @@ -140,7 +139,7 @@ impl fmt::Display for Error { Error::InvalidHex => write!(f, "hex invalid"), #[cfg(feature = "std")] Error::Io(e) => write!(f, "{e}"), - #[cfg(all(not(feature = "std"), feature = "alloc"))] + #[cfg(feature = "embedded_io")] Error::Io(_) => write!(f, "io error"), Error::DepthLimitExceeded => write!(f, "depth limit exceeded"), #[cfg(feature = "serde_json")] @@ -194,7 +193,7 @@ impl From for () { #[allow(dead_code)] type Result = core::result::Result; -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl ErrorType for Limited { type Error = Error; } /// Name defines types that assign a static name to their value, such as the @@ -230,7 +229,7 @@ where /// `Limits` contains the limits that a limited reader or writer will be /// constrained to. -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] #[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct Limits { /// Defines the maximum depth for recursive calls in `Read/WriteXdr` to @@ -247,7 +246,7 @@ pub struct Limits { pub len: usize, } -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] impl Limits { #[must_use] pub fn none() -> Self { @@ -278,13 +277,13 @@ impl Limits { /// /// Intended for use with readers and writers and limiting their reads and /// writes. -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] pub struct Limited { pub inner: L, pub(crate) limits: Limits, } -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] impl Limited { /// Constructs a new `Limited`. /// @@ -337,8 +336,7 @@ impl Read for Limited { } } - -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl Read for Limited { /// Forwards the read operation to the wrapped object. fn read(&mut self, buf: &mut [u8]) -> core::result::Result { @@ -372,7 +370,7 @@ impl Write for Limited { } } -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl Write for Limited { /// Forwards the write operation to the wrapped object. fn write(&mut self, buf: &[u8]) -> core::result::Result { @@ -457,7 +455,7 @@ where /// /// Use [`ReadXdR: Read_xdr_to_end`] when the intent is for all bytes in the /// read implementation to be consumed by the read. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result; /// Construct the type from the XDR bytes base64 encoded. @@ -492,7 +490,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr_to_end(r: &mut Limited) -> Result { let s = Self::read_xdr(r)?; // Check that any further reads, such as this read of one byte, read no @@ -532,7 +530,7 @@ where /// /// Use [`ReadXdR: Read_xdr_into_to_end`] when the intent is for all bytes /// in the read implementation to be consumed by the read. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr_into(&mut self, r: &mut Limited) -> Result<()> { *self = Self::read_xdr(r)?; Ok(()) @@ -556,7 +554,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr_into_to_end(&mut self, r: &mut Limited) -> Result<()> { Self::read_xdr_into(self, r)?; // Check that any further reads, such as this read of one byte, read no @@ -605,7 +603,7 @@ where /// /// An error is returned if the bytes are not completely consumed by the /// deserialization. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn from_xdr(bytes: impl AsRef<[u8]>, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(&mut cursor)?; @@ -629,10 +627,10 @@ where } pub trait WriteXdr { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()>; - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn to_xdr(&self, limits: Limits) -> Result> { let mut cursor = Limited::new(Cursor::new(vec![]), limits); self.write_xdr(&mut cursor)?; @@ -654,13 +652,13 @@ pub trait WriteXdr { /// `Pad_len` returns the number of bytes to pad an XDR value of the given /// length to make the final serialized size a multiple of 4. -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] fn pad_len(len: usize) -> usize { (4 - (len % 4)) % 4 } impl ReadXdr for i32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -672,7 +670,7 @@ impl ReadXdr for i32 { } impl WriteXdr for i32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -683,7 +681,7 @@ impl WriteXdr for i32 { } impl ReadXdr for u32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -695,7 +693,7 @@ impl ReadXdr for u32 { } impl WriteXdr for u32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -706,7 +704,7 @@ impl WriteXdr for u32 { } impl ReadXdr for i64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -718,7 +716,7 @@ impl ReadXdr for i64 { } impl WriteXdr for i64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -729,7 +727,7 @@ impl WriteXdr for i64 { } impl ReadXdr for u64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -741,7 +739,7 @@ impl ReadXdr for u64 { } impl WriteXdr for u64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -752,35 +750,35 @@ impl WriteXdr for u64 { } impl ReadXdr for f32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for f64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for bool { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -791,7 +789,7 @@ impl ReadXdr for bool { } impl WriteXdr for bool { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i = u32::from(*self); // true = 1, false = 0 @@ -801,7 +799,7 @@ impl WriteXdr for bool { } impl ReadXdr for Option { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -818,7 +816,7 @@ impl ReadXdr for Option { } impl WriteXdr for Option { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { if let Some(t) = self { @@ -833,35 +831,35 @@ impl WriteXdr for Option { } impl ReadXdr for Box { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| Ok(Box::new(T::read_xdr(r)?))) } } impl WriteXdr for Box { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| T::write_xdr(self, w)) } } impl ReadXdr for () { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(_r: &mut Limited) -> Result { Ok(()) } } impl WriteXdr for () { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { Ok(()) } } impl ReadXdr for [u8; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { r.consume_len(N)?; @@ -880,7 +878,7 @@ impl ReadXdr for [u8; N] { } impl WriteXdr for [u8; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { w.consume_len(N)?; @@ -894,7 +892,7 @@ impl WriteXdr for [u8; N] { } impl ReadXdr for [T; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let mut vec = Vec::with_capacity(N); @@ -909,7 +907,7 @@ impl ReadXdr for [T; N] { } impl WriteXdr for [T; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { for t in self { @@ -1268,7 +1266,7 @@ impl<'a, const MAX: u32> TryFrom<&'a VecM> for &'a str { } impl ReadXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1295,7 +1293,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1315,7 +1313,7 @@ impl WriteXdr for VecM { } impl ReadXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len = u32::read_xdr(r)?; @@ -1335,7 +1333,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1708,7 +1706,7 @@ impl<'a, const MAX: u32> TryFrom<&'a BytesM> for &'a str { } impl ReadXdr for BytesM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1735,7 +1733,7 @@ impl ReadXdr for BytesM { } impl WriteXdr for BytesM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2111,7 +2109,7 @@ impl<'a, const MAX: u32> TryFrom<&'a StringM> for &'a str { } impl ReadXdr for StringM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -2138,7 +2136,7 @@ impl ReadXdr for StringM { } impl WriteXdr for StringM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2184,7 +2182,7 @@ impl ReadXdr for Frame where T: ReadXdr, { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { // Read the frame header value that contains 1 flag-bit and a 33-bit length. // - The 1 flag bit is 0 when there are more frames for the same record. @@ -2204,7 +2202,7 @@ where } } -#[cfg(all(test, feature = "alloc"))] +#[cfg(all(test, any(feature = "std", feature = "embedded_io")))] mod tests { use super::*; @@ -2314,7 +2312,7 @@ mod tests { } } -#[cfg(all(test, feature = "alloc"))] +#[cfg(all(test, any(feature = "std", feature = "embedded_io")))] mod test { use super::*; @@ -2827,6 +2825,219 @@ mod test { } } +#[cfg(all(test, any(feature = "std", feature = "embedded_io")))] +mod test_io { + // We will use different IO libraries according to the feature, + // we hope the selected IO library can work as expected + + use super::*; + + #[test] + fn test_read_exact_success() { + let data = b"The quick brown fox jumps over the lazy dog."; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 19]; // Exactly the length of "The quick brown fox" + + // Attempt to read exactly 19 bytes + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"The quick brown fox"); + assert_eq!(cursor.position(), 19); + } + + #[test] + fn test_read_exact_less_than_available() { + let data = b"Hello, Rust!"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 5]; + + // Attempt to read 5 bytes from the start + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Hello"); + assert_eq!(cursor.position(), 5); + } + + #[test] + fn test_read_exact_exact_eof() { + let data = b"Data"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 4]; + + // Attempt to read exactly 4 bytes, which is the entire buffer + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Data"); + assert_eq!(cursor.position(), 4); + + // Further attempt to read should fail with EOF + let mut buffer_eof = [0u8; 1]; + let result = cursor.read_exact(&mut buffer_eof); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 4); // Position should remain at EOF + } + + #[test] + fn test_read_exact_past_eof() { + let data = b"Short"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 10]; // Requesting more bytes than available + + // Attempt to read 10 bytes from a 5-byte buffer + let result = cursor.read_exact(&mut buffer); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 5); // Position should move to EOF + } + + #[test] + fn test_read_exact_empty_buffer() { + let data = b"Non-empty"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 0]; // Zero-length buffer + + // Attempt to read zero bytes + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(cursor.position(), 0); // Position should remain unchanged + } + + #[test] + fn test_read_exact_from_empty_cursor() { + let data: &[u8] = b""; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 5]; + + // Attempt to read from an empty cursor + let result = cursor.read_exact(&mut buffer); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 0); // Position remains at 0 + } + + #[test] + fn test_read_exact_multiple_reads() { + let data = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + let mut cursor = Cursor::new(data); + + let mut buffer1 = [0u8; 10]; + let mut buffer2 = [0u8; 10]; + let mut buffer3 = [0u8; 10]; // Only 6 bytes left + + // First read: 10 bytes + assert!(cursor.read_exact(&mut buffer1).is_ok()); + assert_eq!(&buffer1, b"ABCDEFGHIJ"); + assert_eq!(cursor.position(), 10); + + // Second read: 10 bytes + assert!(cursor.read_exact(&mut buffer2).is_ok()); + assert_eq!(&buffer2, b"KLMNOPQRST"); + assert_eq!(cursor.position(), 20); + + // Third read: Attempt to read 10 bytes, but only 6 are available + let result = cursor.read_exact(&mut buffer3); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + // read_exact makes no promises about the content of the buffer on error + // assert_eq!(&buffer3[..6], b"UVWXYZ"); + assert_eq!(cursor.position(), 26); // Position should be at EOF + } + + #[test] + fn test_cursor_read_exact_after_eof() { + let data = b"End"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 3]; + + // First read: read the entire buffer + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"End"); + assert_eq!(cursor.position(), 3); + + // Second read: attempt to read again, should fail + let mut buffer_eof = [0u8; 1]; + let result = cursor.read_exact(&mut buffer_eof); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 3); // Position remains at EOF + } + + #[test] + fn test_slice_read_exact_success() { + let data = b"SliceReadTest"; + let mut slice = &data[..]; + let mut buffer = [0u8; 13]; // Exact length + + // Using Read trait directly on slice + assert!(slice.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"SliceReadTest"); + } + + #[test] + fn test_slice_read_exact_partial() { + let data = b"SlicePartial"; + let mut slice = &data[..]; + let mut buffer = [0u8; 20]; // Request more bytes than available + + // Using Read trait directly on slice + let result = slice.read_exact(&mut buffer); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + // read_exact makes no promises about the content of the buffer on error + } +} + /// AccountFlags is an XDR Enum defines as: /// /// ```text @@ -2905,7 +3116,7 @@ impl From for i32 { } impl ReadXdr for AccountFlags { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let e = i32::read_xdr(r)?; @@ -2916,7 +3127,7 @@ impl ReadXdr for AccountFlags { } impl WriteXdr for AccountFlags { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i: i32 = (*self).into(); @@ -3004,7 +3215,7 @@ impl Type { pub const VARIANTS: [TypeVariant; 1] = [ TypeVariant::AccountFlags, ]; pub const VARIANTS_STR: [&'static str; 1] = [ "AccountFlags", ]; - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] #[allow(clippy::too_many_lines)] pub fn read_xdr(v: TypeVariant, r: &mut Limited) -> Result { match v { @@ -3019,7 +3230,7 @@ impl Type { Ok(t) } - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] pub fn read_xdr_to_end(v: TypeVariant, r: &mut Limited) -> Result { let s = Self::read_xdr(v, r)?; // Check that any further reads, such as this read of one byte, read no @@ -3063,7 +3274,7 @@ impl Type { } } - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] pub fn from_xdr>(v: TypeVariant, bytes: B, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(v, &mut cursor)?; @@ -3147,7 +3358,7 @@ impl Variants for Type { } impl WriteXdr for Type { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] #[allow(clippy::too_many_lines)] fn write_xdr(&self, w: &mut Limited) -> Result<()> { match self { diff --git a/spec/output/generator_spec_rust_custom_jsonschema_impls/const.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_jsonschema_impls/const.x/MyXDR.rs index 735e0265e..fbe2a13d8 100644 --- a/spec/output/generator_spec_rust_custom_jsonschema_impls/const.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_jsonschema_impls/const.x/MyXDR.rs @@ -50,7 +50,7 @@ use std::{ io::{BufRead, BufReader, Cursor, Read, Write}, }; -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] use embedded_io_extras::{Cursor, Error as _, ErrorType, Read, Write}; /// Error contains all errors returned by functions in this crate. It can be @@ -68,7 +68,7 @@ pub enum Error { InvalidHex, #[cfg(feature = "std")] Io(io::Error), - #[cfg(all(not(feature = "std"), feature = "alloc"))] + #[cfg(feature = "embedded_io")] Io(embedded_io_extras::ErrorKind), DepthLimitExceeded, #[cfg(feature = "serde_json")] @@ -86,15 +86,14 @@ impl PartialEq for Error { // case for comparing errors outputted by the XDR library is for // error case testing, and a lack of the ability to compare has a // detrimental affect on failure testing, so this is a tradeoff. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] (Self::Io(l), Self::Io(r)) => l.kind() == r.kind(), _ => core::mem::discriminant(self) == core::mem::discriminant(other), } } } - -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl embedded_io_extras::Error for Error { fn kind(&self) -> embedded_io_extras::ErrorKind { match self { @@ -104,7 +103,7 @@ impl embedded_io_extras::Error for Error { } } -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl From> for Error { fn from(value: embedded_io_extras::ReadExactError) -> Self { match value { @@ -140,7 +139,7 @@ impl fmt::Display for Error { Error::InvalidHex => write!(f, "hex invalid"), #[cfg(feature = "std")] Error::Io(e) => write!(f, "{e}"), - #[cfg(all(not(feature = "std"), feature = "alloc"))] + #[cfg(feature = "embedded_io")] Error::Io(_) => write!(f, "io error"), Error::DepthLimitExceeded => write!(f, "depth limit exceeded"), #[cfg(feature = "serde_json")] @@ -194,7 +193,7 @@ impl From for () { #[allow(dead_code)] type Result = core::result::Result; -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl ErrorType for Limited { type Error = Error; } /// Name defines types that assign a static name to their value, such as the @@ -230,7 +229,7 @@ where /// `Limits` contains the limits that a limited reader or writer will be /// constrained to. -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] #[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct Limits { /// Defines the maximum depth for recursive calls in `Read/WriteXdr` to @@ -247,7 +246,7 @@ pub struct Limits { pub len: usize, } -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] impl Limits { #[must_use] pub fn none() -> Self { @@ -278,13 +277,13 @@ impl Limits { /// /// Intended for use with readers and writers and limiting their reads and /// writes. -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] pub struct Limited { pub inner: L, pub(crate) limits: Limits, } -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] impl Limited { /// Constructs a new `Limited`. /// @@ -337,8 +336,7 @@ impl Read for Limited { } } - -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl Read for Limited { /// Forwards the read operation to the wrapped object. fn read(&mut self, buf: &mut [u8]) -> core::result::Result { @@ -372,7 +370,7 @@ impl Write for Limited { } } -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl Write for Limited { /// Forwards the write operation to the wrapped object. fn write(&mut self, buf: &[u8]) -> core::result::Result { @@ -457,7 +455,7 @@ where /// /// Use [`ReadXdR: Read_xdr_to_end`] when the intent is for all bytes in the /// read implementation to be consumed by the read. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result; /// Construct the type from the XDR bytes base64 encoded. @@ -492,7 +490,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr_to_end(r: &mut Limited) -> Result { let s = Self::read_xdr(r)?; // Check that any further reads, such as this read of one byte, read no @@ -532,7 +530,7 @@ where /// /// Use [`ReadXdR: Read_xdr_into_to_end`] when the intent is for all bytes /// in the read implementation to be consumed by the read. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr_into(&mut self, r: &mut Limited) -> Result<()> { *self = Self::read_xdr(r)?; Ok(()) @@ -556,7 +554,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr_into_to_end(&mut self, r: &mut Limited) -> Result<()> { Self::read_xdr_into(self, r)?; // Check that any further reads, such as this read of one byte, read no @@ -605,7 +603,7 @@ where /// /// An error is returned if the bytes are not completely consumed by the /// deserialization. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn from_xdr(bytes: impl AsRef<[u8]>, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(&mut cursor)?; @@ -629,10 +627,10 @@ where } pub trait WriteXdr { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()>; - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn to_xdr(&self, limits: Limits) -> Result> { let mut cursor = Limited::new(Cursor::new(vec![]), limits); self.write_xdr(&mut cursor)?; @@ -654,13 +652,13 @@ pub trait WriteXdr { /// `Pad_len` returns the number of bytes to pad an XDR value of the given /// length to make the final serialized size a multiple of 4. -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] fn pad_len(len: usize) -> usize { (4 - (len % 4)) % 4 } impl ReadXdr for i32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -672,7 +670,7 @@ impl ReadXdr for i32 { } impl WriteXdr for i32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -683,7 +681,7 @@ impl WriteXdr for i32 { } impl ReadXdr for u32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -695,7 +693,7 @@ impl ReadXdr for u32 { } impl WriteXdr for u32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -706,7 +704,7 @@ impl WriteXdr for u32 { } impl ReadXdr for i64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -718,7 +716,7 @@ impl ReadXdr for i64 { } impl WriteXdr for i64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -729,7 +727,7 @@ impl WriteXdr for i64 { } impl ReadXdr for u64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -741,7 +739,7 @@ impl ReadXdr for u64 { } impl WriteXdr for u64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -752,35 +750,35 @@ impl WriteXdr for u64 { } impl ReadXdr for f32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for f64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for bool { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -791,7 +789,7 @@ impl ReadXdr for bool { } impl WriteXdr for bool { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i = u32::from(*self); // true = 1, false = 0 @@ -801,7 +799,7 @@ impl WriteXdr for bool { } impl ReadXdr for Option { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -818,7 +816,7 @@ impl ReadXdr for Option { } impl WriteXdr for Option { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { if let Some(t) = self { @@ -833,35 +831,35 @@ impl WriteXdr for Option { } impl ReadXdr for Box { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| Ok(Box::new(T::read_xdr(r)?))) } } impl WriteXdr for Box { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| T::write_xdr(self, w)) } } impl ReadXdr for () { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(_r: &mut Limited) -> Result { Ok(()) } } impl WriteXdr for () { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { Ok(()) } } impl ReadXdr for [u8; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { r.consume_len(N)?; @@ -880,7 +878,7 @@ impl ReadXdr for [u8; N] { } impl WriteXdr for [u8; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { w.consume_len(N)?; @@ -894,7 +892,7 @@ impl WriteXdr for [u8; N] { } impl ReadXdr for [T; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let mut vec = Vec::with_capacity(N); @@ -909,7 +907,7 @@ impl ReadXdr for [T; N] { } impl WriteXdr for [T; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { for t in self { @@ -1268,7 +1266,7 @@ impl<'a, const MAX: u32> TryFrom<&'a VecM> for &'a str { } impl ReadXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1295,7 +1293,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1315,7 +1313,7 @@ impl WriteXdr for VecM { } impl ReadXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len = u32::read_xdr(r)?; @@ -1335,7 +1333,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1708,7 +1706,7 @@ impl<'a, const MAX: u32> TryFrom<&'a BytesM> for &'a str { } impl ReadXdr for BytesM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1735,7 +1733,7 @@ impl ReadXdr for BytesM { } impl WriteXdr for BytesM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2111,7 +2109,7 @@ impl<'a, const MAX: u32> TryFrom<&'a StringM> for &'a str { } impl ReadXdr for StringM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -2138,7 +2136,7 @@ impl ReadXdr for StringM { } impl WriteXdr for StringM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2184,7 +2182,7 @@ impl ReadXdr for Frame where T: ReadXdr, { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { // Read the frame header value that contains 1 flag-bit and a 33-bit length. // - The 1 flag bit is 0 when there are more frames for the same record. @@ -2204,7 +2202,7 @@ where } } -#[cfg(all(test, feature = "alloc"))] +#[cfg(all(test, any(feature = "std", feature = "embedded_io")))] mod tests { use super::*; @@ -2314,7 +2312,7 @@ mod tests { } } -#[cfg(all(test, feature = "alloc"))] +#[cfg(all(test, any(feature = "std", feature = "embedded_io")))] mod test { use super::*; @@ -2827,6 +2825,219 @@ mod test { } } +#[cfg(all(test, any(feature = "std", feature = "embedded_io")))] +mod test_io { + // We will use different IO libraries according to the feature, + // we hope the selected IO library can work as expected + + use super::*; + + #[test] + fn test_read_exact_success() { + let data = b"The quick brown fox jumps over the lazy dog."; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 19]; // Exactly the length of "The quick brown fox" + + // Attempt to read exactly 19 bytes + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"The quick brown fox"); + assert_eq!(cursor.position(), 19); + } + + #[test] + fn test_read_exact_less_than_available() { + let data = b"Hello, Rust!"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 5]; + + // Attempt to read 5 bytes from the start + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Hello"); + assert_eq!(cursor.position(), 5); + } + + #[test] + fn test_read_exact_exact_eof() { + let data = b"Data"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 4]; + + // Attempt to read exactly 4 bytes, which is the entire buffer + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Data"); + assert_eq!(cursor.position(), 4); + + // Further attempt to read should fail with EOF + let mut buffer_eof = [0u8; 1]; + let result = cursor.read_exact(&mut buffer_eof); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 4); // Position should remain at EOF + } + + #[test] + fn test_read_exact_past_eof() { + let data = b"Short"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 10]; // Requesting more bytes than available + + // Attempt to read 10 bytes from a 5-byte buffer + let result = cursor.read_exact(&mut buffer); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 5); // Position should move to EOF + } + + #[test] + fn test_read_exact_empty_buffer() { + let data = b"Non-empty"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 0]; // Zero-length buffer + + // Attempt to read zero bytes + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(cursor.position(), 0); // Position should remain unchanged + } + + #[test] + fn test_read_exact_from_empty_cursor() { + let data: &[u8] = b""; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 5]; + + // Attempt to read from an empty cursor + let result = cursor.read_exact(&mut buffer); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 0); // Position remains at 0 + } + + #[test] + fn test_read_exact_multiple_reads() { + let data = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + let mut cursor = Cursor::new(data); + + let mut buffer1 = [0u8; 10]; + let mut buffer2 = [0u8; 10]; + let mut buffer3 = [0u8; 10]; // Only 6 bytes left + + // First read: 10 bytes + assert!(cursor.read_exact(&mut buffer1).is_ok()); + assert_eq!(&buffer1, b"ABCDEFGHIJ"); + assert_eq!(cursor.position(), 10); + + // Second read: 10 bytes + assert!(cursor.read_exact(&mut buffer2).is_ok()); + assert_eq!(&buffer2, b"KLMNOPQRST"); + assert_eq!(cursor.position(), 20); + + // Third read: Attempt to read 10 bytes, but only 6 are available + let result = cursor.read_exact(&mut buffer3); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + // read_exact makes no promises about the content of the buffer on error + // assert_eq!(&buffer3[..6], b"UVWXYZ"); + assert_eq!(cursor.position(), 26); // Position should be at EOF + } + + #[test] + fn test_cursor_read_exact_after_eof() { + let data = b"End"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 3]; + + // First read: read the entire buffer + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"End"); + assert_eq!(cursor.position(), 3); + + // Second read: attempt to read again, should fail + let mut buffer_eof = [0u8; 1]; + let result = cursor.read_exact(&mut buffer_eof); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 3); // Position remains at EOF + } + + #[test] + fn test_slice_read_exact_success() { + let data = b"SliceReadTest"; + let mut slice = &data[..]; + let mut buffer = [0u8; 13]; // Exact length + + // Using Read trait directly on slice + assert!(slice.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"SliceReadTest"); + } + + #[test] + fn test_slice_read_exact_partial() { + let data = b"SlicePartial"; + let mut slice = &data[..]; + let mut buffer = [0u8; 20]; // Request more bytes than available + + // Using Read trait directly on slice + let result = slice.read_exact(&mut buffer); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + // read_exact makes no promises about the content of the buffer on error + } +} + /// Foo is an XDR Const defines as: /// /// ```text @@ -2939,7 +3150,7 @@ TypeVariant::TestArray2, ]; pub const VARIANTS_STR: [&'static str; 2] = [ "TestArray", "TestArray2", ]; - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] #[allow(clippy::too_many_lines)] pub fn read_xdr(v: TypeVariant, r: &mut Limited) -> Result { match v { @@ -2955,7 +3166,7 @@ TypeVariant::TestArray2 => r.with_limited_depth(|r| Ok(Self::TestArray2(Box::new Ok(t) } - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] pub fn read_xdr_to_end(v: TypeVariant, r: &mut Limited) -> Result { let s = Self::read_xdr(v, r)?; // Check that any further reads, such as this read of one byte, read no @@ -3002,7 +3213,7 @@ TypeVariant::TestArray2 => Box::new(ReadXdrIter::<_, TestArray2>::new(dec, r.lim } } - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] pub fn from_xdr>(v: TypeVariant, bytes: B, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(v, &mut cursor)?; @@ -3091,7 +3302,7 @@ Self::TestArray2(_) => TypeVariant::TestArray2, } impl WriteXdr for Type { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] #[allow(clippy::too_many_lines)] fn write_xdr(&self, w: &mut Limited) -> Result<()> { match self { diff --git a/spec/output/generator_spec_rust_custom_jsonschema_impls/enum.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_jsonschema_impls/enum.x/MyXDR.rs index b6085e759..5585727d9 100644 --- a/spec/output/generator_spec_rust_custom_jsonschema_impls/enum.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_jsonschema_impls/enum.x/MyXDR.rs @@ -50,7 +50,7 @@ use std::{ io::{BufRead, BufReader, Cursor, Read, Write}, }; -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] use embedded_io_extras::{Cursor, Error as _, ErrorType, Read, Write}; /// Error contains all errors returned by functions in this crate. It can be @@ -68,7 +68,7 @@ pub enum Error { InvalidHex, #[cfg(feature = "std")] Io(io::Error), - #[cfg(all(not(feature = "std"), feature = "alloc"))] + #[cfg(feature = "embedded_io")] Io(embedded_io_extras::ErrorKind), DepthLimitExceeded, #[cfg(feature = "serde_json")] @@ -86,15 +86,14 @@ impl PartialEq for Error { // case for comparing errors outputted by the XDR library is for // error case testing, and a lack of the ability to compare has a // detrimental affect on failure testing, so this is a tradeoff. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] (Self::Io(l), Self::Io(r)) => l.kind() == r.kind(), _ => core::mem::discriminant(self) == core::mem::discriminant(other), } } } - -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl embedded_io_extras::Error for Error { fn kind(&self) -> embedded_io_extras::ErrorKind { match self { @@ -104,7 +103,7 @@ impl embedded_io_extras::Error for Error { } } -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl From> for Error { fn from(value: embedded_io_extras::ReadExactError) -> Self { match value { @@ -140,7 +139,7 @@ impl fmt::Display for Error { Error::InvalidHex => write!(f, "hex invalid"), #[cfg(feature = "std")] Error::Io(e) => write!(f, "{e}"), - #[cfg(all(not(feature = "std"), feature = "alloc"))] + #[cfg(feature = "embedded_io")] Error::Io(_) => write!(f, "io error"), Error::DepthLimitExceeded => write!(f, "depth limit exceeded"), #[cfg(feature = "serde_json")] @@ -194,7 +193,7 @@ impl From for () { #[allow(dead_code)] type Result = core::result::Result; -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl ErrorType for Limited { type Error = Error; } /// Name defines types that assign a static name to their value, such as the @@ -230,7 +229,7 @@ where /// `Limits` contains the limits that a limited reader or writer will be /// constrained to. -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] #[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct Limits { /// Defines the maximum depth for recursive calls in `Read/WriteXdr` to @@ -247,7 +246,7 @@ pub struct Limits { pub len: usize, } -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] impl Limits { #[must_use] pub fn none() -> Self { @@ -278,13 +277,13 @@ impl Limits { /// /// Intended for use with readers and writers and limiting their reads and /// writes. -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] pub struct Limited { pub inner: L, pub(crate) limits: Limits, } -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] impl Limited { /// Constructs a new `Limited`. /// @@ -337,8 +336,7 @@ impl Read for Limited { } } - -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl Read for Limited { /// Forwards the read operation to the wrapped object. fn read(&mut self, buf: &mut [u8]) -> core::result::Result { @@ -372,7 +370,7 @@ impl Write for Limited { } } -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl Write for Limited { /// Forwards the write operation to the wrapped object. fn write(&mut self, buf: &[u8]) -> core::result::Result { @@ -457,7 +455,7 @@ where /// /// Use [`ReadXdR: Read_xdr_to_end`] when the intent is for all bytes in the /// read implementation to be consumed by the read. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result; /// Construct the type from the XDR bytes base64 encoded. @@ -492,7 +490,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr_to_end(r: &mut Limited) -> Result { let s = Self::read_xdr(r)?; // Check that any further reads, such as this read of one byte, read no @@ -532,7 +530,7 @@ where /// /// Use [`ReadXdR: Read_xdr_into_to_end`] when the intent is for all bytes /// in the read implementation to be consumed by the read. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr_into(&mut self, r: &mut Limited) -> Result<()> { *self = Self::read_xdr(r)?; Ok(()) @@ -556,7 +554,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr_into_to_end(&mut self, r: &mut Limited) -> Result<()> { Self::read_xdr_into(self, r)?; // Check that any further reads, such as this read of one byte, read no @@ -605,7 +603,7 @@ where /// /// An error is returned if the bytes are not completely consumed by the /// deserialization. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn from_xdr(bytes: impl AsRef<[u8]>, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(&mut cursor)?; @@ -629,10 +627,10 @@ where } pub trait WriteXdr { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()>; - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn to_xdr(&self, limits: Limits) -> Result> { let mut cursor = Limited::new(Cursor::new(vec![]), limits); self.write_xdr(&mut cursor)?; @@ -654,13 +652,13 @@ pub trait WriteXdr { /// `Pad_len` returns the number of bytes to pad an XDR value of the given /// length to make the final serialized size a multiple of 4. -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] fn pad_len(len: usize) -> usize { (4 - (len % 4)) % 4 } impl ReadXdr for i32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -672,7 +670,7 @@ impl ReadXdr for i32 { } impl WriteXdr for i32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -683,7 +681,7 @@ impl WriteXdr for i32 { } impl ReadXdr for u32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -695,7 +693,7 @@ impl ReadXdr for u32 { } impl WriteXdr for u32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -706,7 +704,7 @@ impl WriteXdr for u32 { } impl ReadXdr for i64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -718,7 +716,7 @@ impl ReadXdr for i64 { } impl WriteXdr for i64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -729,7 +727,7 @@ impl WriteXdr for i64 { } impl ReadXdr for u64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -741,7 +739,7 @@ impl ReadXdr for u64 { } impl WriteXdr for u64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -752,35 +750,35 @@ impl WriteXdr for u64 { } impl ReadXdr for f32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for f64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for bool { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -791,7 +789,7 @@ impl ReadXdr for bool { } impl WriteXdr for bool { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i = u32::from(*self); // true = 1, false = 0 @@ -801,7 +799,7 @@ impl WriteXdr for bool { } impl ReadXdr for Option { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -818,7 +816,7 @@ impl ReadXdr for Option { } impl WriteXdr for Option { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { if let Some(t) = self { @@ -833,35 +831,35 @@ impl WriteXdr for Option { } impl ReadXdr for Box { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| Ok(Box::new(T::read_xdr(r)?))) } } impl WriteXdr for Box { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| T::write_xdr(self, w)) } } impl ReadXdr for () { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(_r: &mut Limited) -> Result { Ok(()) } } impl WriteXdr for () { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { Ok(()) } } impl ReadXdr for [u8; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { r.consume_len(N)?; @@ -880,7 +878,7 @@ impl ReadXdr for [u8; N] { } impl WriteXdr for [u8; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { w.consume_len(N)?; @@ -894,7 +892,7 @@ impl WriteXdr for [u8; N] { } impl ReadXdr for [T; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let mut vec = Vec::with_capacity(N); @@ -909,7 +907,7 @@ impl ReadXdr for [T; N] { } impl WriteXdr for [T; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { for t in self { @@ -1268,7 +1266,7 @@ impl<'a, const MAX: u32> TryFrom<&'a VecM> for &'a str { } impl ReadXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1295,7 +1293,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1315,7 +1313,7 @@ impl WriteXdr for VecM { } impl ReadXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len = u32::read_xdr(r)?; @@ -1335,7 +1333,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1708,7 +1706,7 @@ impl<'a, const MAX: u32> TryFrom<&'a BytesM> for &'a str { } impl ReadXdr for BytesM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1735,7 +1733,7 @@ impl ReadXdr for BytesM { } impl WriteXdr for BytesM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2111,7 +2109,7 @@ impl<'a, const MAX: u32> TryFrom<&'a StringM> for &'a str { } impl ReadXdr for StringM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -2138,7 +2136,7 @@ impl ReadXdr for StringM { } impl WriteXdr for StringM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2184,7 +2182,7 @@ impl ReadXdr for Frame where T: ReadXdr, { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { // Read the frame header value that contains 1 flag-bit and a 33-bit length. // - The 1 flag bit is 0 when there are more frames for the same record. @@ -2204,7 +2202,7 @@ where } } -#[cfg(all(test, feature = "alloc"))] +#[cfg(all(test, any(feature = "std", feature = "embedded_io")))] mod tests { use super::*; @@ -2314,7 +2312,7 @@ mod tests { } } -#[cfg(all(test, feature = "alloc"))] +#[cfg(all(test, any(feature = "std", feature = "embedded_io")))] mod test { use super::*; @@ -2827,6 +2825,219 @@ mod test { } } +#[cfg(all(test, any(feature = "std", feature = "embedded_io")))] +mod test_io { + // We will use different IO libraries according to the feature, + // we hope the selected IO library can work as expected + + use super::*; + + #[test] + fn test_read_exact_success() { + let data = b"The quick brown fox jumps over the lazy dog."; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 19]; // Exactly the length of "The quick brown fox" + + // Attempt to read exactly 19 bytes + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"The quick brown fox"); + assert_eq!(cursor.position(), 19); + } + + #[test] + fn test_read_exact_less_than_available() { + let data = b"Hello, Rust!"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 5]; + + // Attempt to read 5 bytes from the start + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Hello"); + assert_eq!(cursor.position(), 5); + } + + #[test] + fn test_read_exact_exact_eof() { + let data = b"Data"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 4]; + + // Attempt to read exactly 4 bytes, which is the entire buffer + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Data"); + assert_eq!(cursor.position(), 4); + + // Further attempt to read should fail with EOF + let mut buffer_eof = [0u8; 1]; + let result = cursor.read_exact(&mut buffer_eof); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 4); // Position should remain at EOF + } + + #[test] + fn test_read_exact_past_eof() { + let data = b"Short"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 10]; // Requesting more bytes than available + + // Attempt to read 10 bytes from a 5-byte buffer + let result = cursor.read_exact(&mut buffer); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 5); // Position should move to EOF + } + + #[test] + fn test_read_exact_empty_buffer() { + let data = b"Non-empty"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 0]; // Zero-length buffer + + // Attempt to read zero bytes + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(cursor.position(), 0); // Position should remain unchanged + } + + #[test] + fn test_read_exact_from_empty_cursor() { + let data: &[u8] = b""; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 5]; + + // Attempt to read from an empty cursor + let result = cursor.read_exact(&mut buffer); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 0); // Position remains at 0 + } + + #[test] + fn test_read_exact_multiple_reads() { + let data = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + let mut cursor = Cursor::new(data); + + let mut buffer1 = [0u8; 10]; + let mut buffer2 = [0u8; 10]; + let mut buffer3 = [0u8; 10]; // Only 6 bytes left + + // First read: 10 bytes + assert!(cursor.read_exact(&mut buffer1).is_ok()); + assert_eq!(&buffer1, b"ABCDEFGHIJ"); + assert_eq!(cursor.position(), 10); + + // Second read: 10 bytes + assert!(cursor.read_exact(&mut buffer2).is_ok()); + assert_eq!(&buffer2, b"KLMNOPQRST"); + assert_eq!(cursor.position(), 20); + + // Third read: Attempt to read 10 bytes, but only 6 are available + let result = cursor.read_exact(&mut buffer3); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + // read_exact makes no promises about the content of the buffer on error + // assert_eq!(&buffer3[..6], b"UVWXYZ"); + assert_eq!(cursor.position(), 26); // Position should be at EOF + } + + #[test] + fn test_cursor_read_exact_after_eof() { + let data = b"End"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 3]; + + // First read: read the entire buffer + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"End"); + assert_eq!(cursor.position(), 3); + + // Second read: attempt to read again, should fail + let mut buffer_eof = [0u8; 1]; + let result = cursor.read_exact(&mut buffer_eof); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 3); // Position remains at EOF + } + + #[test] + fn test_slice_read_exact_success() { + let data = b"SliceReadTest"; + let mut slice = &data[..]; + let mut buffer = [0u8; 13]; // Exact length + + // Using Read trait directly on slice + assert!(slice.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"SliceReadTest"); + } + + #[test] + fn test_slice_read_exact_partial() { + let data = b"SlicePartial"; + let mut slice = &data[..]; + let mut buffer = [0u8; 20]; // Request more bytes than available + + // Using Read trait directly on slice + let result = slice.read_exact(&mut buffer); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + // read_exact makes no promises about the content of the buffer on error + } +} + /// MessageType is an XDR Enum defines as: /// /// ```text @@ -2989,7 +3200,7 @@ Self::FbaMessage => "FbaMessage", } impl ReadXdr for MessageType { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let e = i32::read_xdr(r)?; @@ -3000,7 +3211,7 @@ Self::FbaMessage => "FbaMessage", } impl WriteXdr for MessageType { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i: i32 = (*self).into(); @@ -3098,7 +3309,7 @@ Self::Blue => "Blue", } impl ReadXdr for Color { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let e = i32::read_xdr(r)?; @@ -3109,7 +3320,7 @@ Self::Blue => "Blue", } impl WriteXdr for Color { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i: i32 = (*self).into(); @@ -3206,7 +3417,7 @@ Self::Blue2 => "Blue2", } impl ReadXdr for Color2 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let e = i32::read_xdr(r)?; @@ -3217,7 +3428,7 @@ Self::Blue2 => "Blue2", } impl WriteXdr for Color2 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i: i32 = (*self).into(); @@ -3315,7 +3526,7 @@ Self::R3 => "R3", } impl ReadXdr for Color3 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let e = i32::read_xdr(r)?; @@ -3326,7 +3537,7 @@ Self::R3 => "R3", } impl WriteXdr for Color3 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i: i32 = (*self).into(); @@ -3441,7 +3652,7 @@ TypeVariant::Color3, ]; "Color2", "Color3", ]; - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] #[allow(clippy::too_many_lines)] pub fn read_xdr(v: TypeVariant, r: &mut Limited) -> Result { match v { @@ -3459,7 +3670,7 @@ TypeVariant::Color3 => r.with_limited_depth(|r| Ok(Self::Color3(Box::new(Color3: Ok(t) } - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] pub fn read_xdr_to_end(v: TypeVariant, r: &mut Limited) -> Result { let s = Self::read_xdr(v, r)?; // Check that any further reads, such as this read of one byte, read no @@ -3512,7 +3723,7 @@ TypeVariant::Color3 => Box::new(ReadXdrIter::<_, Color3>::new(dec, r.limits.clon } } - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] pub fn from_xdr>(v: TypeVariant, bytes: B, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(v, &mut cursor)?; @@ -3611,7 +3822,7 @@ Self::Color3(_) => TypeVariant::Color3, } impl WriteXdr for Type { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] #[allow(clippy::too_many_lines)] fn write_xdr(&self, w: &mut Limited) -> Result<()> { match self { diff --git a/spec/output/generator_spec_rust_custom_jsonschema_impls/nesting.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_jsonschema_impls/nesting.x/MyXDR.rs index dcb6da971..5cf38ade8 100644 --- a/spec/output/generator_spec_rust_custom_jsonschema_impls/nesting.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_jsonschema_impls/nesting.x/MyXDR.rs @@ -50,7 +50,7 @@ use std::{ io::{BufRead, BufReader, Cursor, Read, Write}, }; -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] use embedded_io_extras::{Cursor, Error as _, ErrorType, Read, Write}; /// Error contains all errors returned by functions in this crate. It can be @@ -68,7 +68,7 @@ pub enum Error { InvalidHex, #[cfg(feature = "std")] Io(io::Error), - #[cfg(all(not(feature = "std"), feature = "alloc"))] + #[cfg(feature = "embedded_io")] Io(embedded_io_extras::ErrorKind), DepthLimitExceeded, #[cfg(feature = "serde_json")] @@ -86,15 +86,14 @@ impl PartialEq for Error { // case for comparing errors outputted by the XDR library is for // error case testing, and a lack of the ability to compare has a // detrimental affect on failure testing, so this is a tradeoff. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] (Self::Io(l), Self::Io(r)) => l.kind() == r.kind(), _ => core::mem::discriminant(self) == core::mem::discriminant(other), } } } - -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl embedded_io_extras::Error for Error { fn kind(&self) -> embedded_io_extras::ErrorKind { match self { @@ -104,7 +103,7 @@ impl embedded_io_extras::Error for Error { } } -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl From> for Error { fn from(value: embedded_io_extras::ReadExactError) -> Self { match value { @@ -140,7 +139,7 @@ impl fmt::Display for Error { Error::InvalidHex => write!(f, "hex invalid"), #[cfg(feature = "std")] Error::Io(e) => write!(f, "{e}"), - #[cfg(all(not(feature = "std"), feature = "alloc"))] + #[cfg(feature = "embedded_io")] Error::Io(_) => write!(f, "io error"), Error::DepthLimitExceeded => write!(f, "depth limit exceeded"), #[cfg(feature = "serde_json")] @@ -194,7 +193,7 @@ impl From for () { #[allow(dead_code)] type Result = core::result::Result; -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl ErrorType for Limited { type Error = Error; } /// Name defines types that assign a static name to their value, such as the @@ -230,7 +229,7 @@ where /// `Limits` contains the limits that a limited reader or writer will be /// constrained to. -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] #[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct Limits { /// Defines the maximum depth for recursive calls in `Read/WriteXdr` to @@ -247,7 +246,7 @@ pub struct Limits { pub len: usize, } -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] impl Limits { #[must_use] pub fn none() -> Self { @@ -278,13 +277,13 @@ impl Limits { /// /// Intended for use with readers and writers and limiting their reads and /// writes. -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] pub struct Limited { pub inner: L, pub(crate) limits: Limits, } -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] impl Limited { /// Constructs a new `Limited`. /// @@ -337,8 +336,7 @@ impl Read for Limited { } } - -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl Read for Limited { /// Forwards the read operation to the wrapped object. fn read(&mut self, buf: &mut [u8]) -> core::result::Result { @@ -372,7 +370,7 @@ impl Write for Limited { } } -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl Write for Limited { /// Forwards the write operation to the wrapped object. fn write(&mut self, buf: &[u8]) -> core::result::Result { @@ -457,7 +455,7 @@ where /// /// Use [`ReadXdR: Read_xdr_to_end`] when the intent is for all bytes in the /// read implementation to be consumed by the read. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result; /// Construct the type from the XDR bytes base64 encoded. @@ -492,7 +490,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr_to_end(r: &mut Limited) -> Result { let s = Self::read_xdr(r)?; // Check that any further reads, such as this read of one byte, read no @@ -532,7 +530,7 @@ where /// /// Use [`ReadXdR: Read_xdr_into_to_end`] when the intent is for all bytes /// in the read implementation to be consumed by the read. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr_into(&mut self, r: &mut Limited) -> Result<()> { *self = Self::read_xdr(r)?; Ok(()) @@ -556,7 +554,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr_into_to_end(&mut self, r: &mut Limited) -> Result<()> { Self::read_xdr_into(self, r)?; // Check that any further reads, such as this read of one byte, read no @@ -605,7 +603,7 @@ where /// /// An error is returned if the bytes are not completely consumed by the /// deserialization. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn from_xdr(bytes: impl AsRef<[u8]>, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(&mut cursor)?; @@ -629,10 +627,10 @@ where } pub trait WriteXdr { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()>; - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn to_xdr(&self, limits: Limits) -> Result> { let mut cursor = Limited::new(Cursor::new(vec![]), limits); self.write_xdr(&mut cursor)?; @@ -654,13 +652,13 @@ pub trait WriteXdr { /// `Pad_len` returns the number of bytes to pad an XDR value of the given /// length to make the final serialized size a multiple of 4. -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] fn pad_len(len: usize) -> usize { (4 - (len % 4)) % 4 } impl ReadXdr for i32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -672,7 +670,7 @@ impl ReadXdr for i32 { } impl WriteXdr for i32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -683,7 +681,7 @@ impl WriteXdr for i32 { } impl ReadXdr for u32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -695,7 +693,7 @@ impl ReadXdr for u32 { } impl WriteXdr for u32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -706,7 +704,7 @@ impl WriteXdr for u32 { } impl ReadXdr for i64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -718,7 +716,7 @@ impl ReadXdr for i64 { } impl WriteXdr for i64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -729,7 +727,7 @@ impl WriteXdr for i64 { } impl ReadXdr for u64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -741,7 +739,7 @@ impl ReadXdr for u64 { } impl WriteXdr for u64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -752,35 +750,35 @@ impl WriteXdr for u64 { } impl ReadXdr for f32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for f64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for bool { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -791,7 +789,7 @@ impl ReadXdr for bool { } impl WriteXdr for bool { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i = u32::from(*self); // true = 1, false = 0 @@ -801,7 +799,7 @@ impl WriteXdr for bool { } impl ReadXdr for Option { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -818,7 +816,7 @@ impl ReadXdr for Option { } impl WriteXdr for Option { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { if let Some(t) = self { @@ -833,35 +831,35 @@ impl WriteXdr for Option { } impl ReadXdr for Box { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| Ok(Box::new(T::read_xdr(r)?))) } } impl WriteXdr for Box { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| T::write_xdr(self, w)) } } impl ReadXdr for () { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(_r: &mut Limited) -> Result { Ok(()) } } impl WriteXdr for () { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { Ok(()) } } impl ReadXdr for [u8; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { r.consume_len(N)?; @@ -880,7 +878,7 @@ impl ReadXdr for [u8; N] { } impl WriteXdr for [u8; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { w.consume_len(N)?; @@ -894,7 +892,7 @@ impl WriteXdr for [u8; N] { } impl ReadXdr for [T; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let mut vec = Vec::with_capacity(N); @@ -909,7 +907,7 @@ impl ReadXdr for [T; N] { } impl WriteXdr for [T; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { for t in self { @@ -1268,7 +1266,7 @@ impl<'a, const MAX: u32> TryFrom<&'a VecM> for &'a str { } impl ReadXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1295,7 +1293,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1315,7 +1313,7 @@ impl WriteXdr for VecM { } impl ReadXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len = u32::read_xdr(r)?; @@ -1335,7 +1333,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1708,7 +1706,7 @@ impl<'a, const MAX: u32> TryFrom<&'a BytesM> for &'a str { } impl ReadXdr for BytesM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1735,7 +1733,7 @@ impl ReadXdr for BytesM { } impl WriteXdr for BytesM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2111,7 +2109,7 @@ impl<'a, const MAX: u32> TryFrom<&'a StringM> for &'a str { } impl ReadXdr for StringM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -2138,7 +2136,7 @@ impl ReadXdr for StringM { } impl WriteXdr for StringM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2184,7 +2182,7 @@ impl ReadXdr for Frame where T: ReadXdr, { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { // Read the frame header value that contains 1 flag-bit and a 33-bit length. // - The 1 flag bit is 0 when there are more frames for the same record. @@ -2204,7 +2202,7 @@ where } } -#[cfg(all(test, feature = "alloc"))] +#[cfg(all(test, any(feature = "std", feature = "embedded_io")))] mod tests { use super::*; @@ -2314,7 +2312,7 @@ mod tests { } } -#[cfg(all(test, feature = "alloc"))] +#[cfg(all(test, any(feature = "std", feature = "embedded_io")))] mod test { use super::*; @@ -2827,6 +2825,219 @@ mod test { } } +#[cfg(all(test, any(feature = "std", feature = "embedded_io")))] +mod test_io { + // We will use different IO libraries according to the feature, + // we hope the selected IO library can work as expected + + use super::*; + + #[test] + fn test_read_exact_success() { + let data = b"The quick brown fox jumps over the lazy dog."; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 19]; // Exactly the length of "The quick brown fox" + + // Attempt to read exactly 19 bytes + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"The quick brown fox"); + assert_eq!(cursor.position(), 19); + } + + #[test] + fn test_read_exact_less_than_available() { + let data = b"Hello, Rust!"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 5]; + + // Attempt to read 5 bytes from the start + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Hello"); + assert_eq!(cursor.position(), 5); + } + + #[test] + fn test_read_exact_exact_eof() { + let data = b"Data"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 4]; + + // Attempt to read exactly 4 bytes, which is the entire buffer + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Data"); + assert_eq!(cursor.position(), 4); + + // Further attempt to read should fail with EOF + let mut buffer_eof = [0u8; 1]; + let result = cursor.read_exact(&mut buffer_eof); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 4); // Position should remain at EOF + } + + #[test] + fn test_read_exact_past_eof() { + let data = b"Short"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 10]; // Requesting more bytes than available + + // Attempt to read 10 bytes from a 5-byte buffer + let result = cursor.read_exact(&mut buffer); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 5); // Position should move to EOF + } + + #[test] + fn test_read_exact_empty_buffer() { + let data = b"Non-empty"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 0]; // Zero-length buffer + + // Attempt to read zero bytes + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(cursor.position(), 0); // Position should remain unchanged + } + + #[test] + fn test_read_exact_from_empty_cursor() { + let data: &[u8] = b""; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 5]; + + // Attempt to read from an empty cursor + let result = cursor.read_exact(&mut buffer); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 0); // Position remains at 0 + } + + #[test] + fn test_read_exact_multiple_reads() { + let data = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + let mut cursor = Cursor::new(data); + + let mut buffer1 = [0u8; 10]; + let mut buffer2 = [0u8; 10]; + let mut buffer3 = [0u8; 10]; // Only 6 bytes left + + // First read: 10 bytes + assert!(cursor.read_exact(&mut buffer1).is_ok()); + assert_eq!(&buffer1, b"ABCDEFGHIJ"); + assert_eq!(cursor.position(), 10); + + // Second read: 10 bytes + assert!(cursor.read_exact(&mut buffer2).is_ok()); + assert_eq!(&buffer2, b"KLMNOPQRST"); + assert_eq!(cursor.position(), 20); + + // Third read: Attempt to read 10 bytes, but only 6 are available + let result = cursor.read_exact(&mut buffer3); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + // read_exact makes no promises about the content of the buffer on error + // assert_eq!(&buffer3[..6], b"UVWXYZ"); + assert_eq!(cursor.position(), 26); // Position should be at EOF + } + + #[test] + fn test_cursor_read_exact_after_eof() { + let data = b"End"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 3]; + + // First read: read the entire buffer + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"End"); + assert_eq!(cursor.position(), 3); + + // Second read: attempt to read again, should fail + let mut buffer_eof = [0u8; 1]; + let result = cursor.read_exact(&mut buffer_eof); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 3); // Position remains at EOF + } + + #[test] + fn test_slice_read_exact_success() { + let data = b"SliceReadTest"; + let mut slice = &data[..]; + let mut buffer = [0u8; 13]; // Exact length + + // Using Read trait directly on slice + assert!(slice.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"SliceReadTest"); + } + + #[test] + fn test_slice_read_exact_partial() { + let data = b"SlicePartial"; + let mut slice = &data[..]; + let mut buffer = [0u8; 20]; // Request more bytes than available + + // Using Read trait directly on slice + let result = slice.read_exact(&mut buffer); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + // read_exact makes no promises about the content of the buffer on error + } +} + /// UnionKey is an XDR Enum defines as: /// /// ```text @@ -2915,7 +3126,7 @@ Self::Offer => "Offer", } impl ReadXdr for UnionKey { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let e = i32::read_xdr(r)?; @@ -2926,7 +3137,7 @@ Self::Offer => "Offer", } impl WriteXdr for UnionKey { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i: i32 = (*self).into(); @@ -2960,7 +3171,7 @@ pub struct MyUnionOne { } impl ReadXdr for MyUnionOne { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { Ok(Self{ @@ -2971,7 +3182,7 @@ impl ReadXdr for MyUnionOne { } impl WriteXdr for MyUnionOne { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { self.some_int.write_xdr(w)?; @@ -2999,7 +3210,7 @@ pub struct MyUnionTwo { } impl ReadXdr for MyUnionTwo { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { Ok(Self{ @@ -3011,7 +3222,7 @@ foo: i32::read_xdr(r)?, } impl WriteXdr for MyUnionTwo { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { self.some_int.write_xdr(w)?; @@ -3113,7 +3324,7 @@ Self::Offer => UnionKey::Offer, impl Union for MyUnion {} impl ReadXdr for MyUnion { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let dv: UnionKey = ::read_xdr(r)?; @@ -3131,7 +3342,7 @@ UnionKey::Offer => Self::Offer, } impl WriteXdr for MyUnion { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { self.discriminant().write_xdr(w)?; @@ -3261,7 +3472,7 @@ TypeVariant::MyUnionTwo, ]; "MyUnionOne", "MyUnionTwo", ]; - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] #[allow(clippy::too_many_lines)] pub fn read_xdr(v: TypeVariant, r: &mut Limited) -> Result { match v { @@ -3280,7 +3491,7 @@ TypeVariant::MyUnionTwo => r.with_limited_depth(|r| Ok(Self::MyUnionTwo(Box::new Ok(t) } - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] pub fn read_xdr_to_end(v: TypeVariant, r: &mut Limited) -> Result { let s = Self::read_xdr(v, r)?; // Check that any further reads, such as this read of one byte, read no @@ -3336,7 +3547,7 @@ TypeVariant::MyUnionTwo => Box::new(ReadXdrIter::<_, MyUnionTwo>::new(dec, r.lim } } - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] pub fn from_xdr>(v: TypeVariant, bytes: B, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(v, &mut cursor)?; @@ -3440,7 +3651,7 @@ Self::MyUnionTwo(_) => TypeVariant::MyUnionTwo, } impl WriteXdr for Type { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] #[allow(clippy::too_many_lines)] fn write_xdr(&self, w: &mut Limited) -> Result<()> { match self { diff --git a/spec/output/generator_spec_rust_custom_jsonschema_impls/optional.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_jsonschema_impls/optional.x/MyXDR.rs index 5ef7eb8f3..19aaa676c 100644 --- a/spec/output/generator_spec_rust_custom_jsonschema_impls/optional.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_jsonschema_impls/optional.x/MyXDR.rs @@ -50,7 +50,7 @@ use std::{ io::{BufRead, BufReader, Cursor, Read, Write}, }; -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] use embedded_io_extras::{Cursor, Error as _, ErrorType, Read, Write}; /// Error contains all errors returned by functions in this crate. It can be @@ -68,7 +68,7 @@ pub enum Error { InvalidHex, #[cfg(feature = "std")] Io(io::Error), - #[cfg(all(not(feature = "std"), feature = "alloc"))] + #[cfg(feature = "embedded_io")] Io(embedded_io_extras::ErrorKind), DepthLimitExceeded, #[cfg(feature = "serde_json")] @@ -86,15 +86,14 @@ impl PartialEq for Error { // case for comparing errors outputted by the XDR library is for // error case testing, and a lack of the ability to compare has a // detrimental affect on failure testing, so this is a tradeoff. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] (Self::Io(l), Self::Io(r)) => l.kind() == r.kind(), _ => core::mem::discriminant(self) == core::mem::discriminant(other), } } } - -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl embedded_io_extras::Error for Error { fn kind(&self) -> embedded_io_extras::ErrorKind { match self { @@ -104,7 +103,7 @@ impl embedded_io_extras::Error for Error { } } -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl From> for Error { fn from(value: embedded_io_extras::ReadExactError) -> Self { match value { @@ -140,7 +139,7 @@ impl fmt::Display for Error { Error::InvalidHex => write!(f, "hex invalid"), #[cfg(feature = "std")] Error::Io(e) => write!(f, "{e}"), - #[cfg(all(not(feature = "std"), feature = "alloc"))] + #[cfg(feature = "embedded_io")] Error::Io(_) => write!(f, "io error"), Error::DepthLimitExceeded => write!(f, "depth limit exceeded"), #[cfg(feature = "serde_json")] @@ -194,7 +193,7 @@ impl From for () { #[allow(dead_code)] type Result = core::result::Result; -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl ErrorType for Limited { type Error = Error; } /// Name defines types that assign a static name to their value, such as the @@ -230,7 +229,7 @@ where /// `Limits` contains the limits that a limited reader or writer will be /// constrained to. -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] #[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct Limits { /// Defines the maximum depth for recursive calls in `Read/WriteXdr` to @@ -247,7 +246,7 @@ pub struct Limits { pub len: usize, } -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] impl Limits { #[must_use] pub fn none() -> Self { @@ -278,13 +277,13 @@ impl Limits { /// /// Intended for use with readers and writers and limiting their reads and /// writes. -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] pub struct Limited { pub inner: L, pub(crate) limits: Limits, } -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] impl Limited { /// Constructs a new `Limited`. /// @@ -337,8 +336,7 @@ impl Read for Limited { } } - -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl Read for Limited { /// Forwards the read operation to the wrapped object. fn read(&mut self, buf: &mut [u8]) -> core::result::Result { @@ -372,7 +370,7 @@ impl Write for Limited { } } -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl Write for Limited { /// Forwards the write operation to the wrapped object. fn write(&mut self, buf: &[u8]) -> core::result::Result { @@ -457,7 +455,7 @@ where /// /// Use [`ReadXdR: Read_xdr_to_end`] when the intent is for all bytes in the /// read implementation to be consumed by the read. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result; /// Construct the type from the XDR bytes base64 encoded. @@ -492,7 +490,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr_to_end(r: &mut Limited) -> Result { let s = Self::read_xdr(r)?; // Check that any further reads, such as this read of one byte, read no @@ -532,7 +530,7 @@ where /// /// Use [`ReadXdR: Read_xdr_into_to_end`] when the intent is for all bytes /// in the read implementation to be consumed by the read. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr_into(&mut self, r: &mut Limited) -> Result<()> { *self = Self::read_xdr(r)?; Ok(()) @@ -556,7 +554,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr_into_to_end(&mut self, r: &mut Limited) -> Result<()> { Self::read_xdr_into(self, r)?; // Check that any further reads, such as this read of one byte, read no @@ -605,7 +603,7 @@ where /// /// An error is returned if the bytes are not completely consumed by the /// deserialization. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn from_xdr(bytes: impl AsRef<[u8]>, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(&mut cursor)?; @@ -629,10 +627,10 @@ where } pub trait WriteXdr { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()>; - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn to_xdr(&self, limits: Limits) -> Result> { let mut cursor = Limited::new(Cursor::new(vec![]), limits); self.write_xdr(&mut cursor)?; @@ -654,13 +652,13 @@ pub trait WriteXdr { /// `Pad_len` returns the number of bytes to pad an XDR value of the given /// length to make the final serialized size a multiple of 4. -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] fn pad_len(len: usize) -> usize { (4 - (len % 4)) % 4 } impl ReadXdr for i32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -672,7 +670,7 @@ impl ReadXdr for i32 { } impl WriteXdr for i32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -683,7 +681,7 @@ impl WriteXdr for i32 { } impl ReadXdr for u32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -695,7 +693,7 @@ impl ReadXdr for u32 { } impl WriteXdr for u32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -706,7 +704,7 @@ impl WriteXdr for u32 { } impl ReadXdr for i64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -718,7 +716,7 @@ impl ReadXdr for i64 { } impl WriteXdr for i64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -729,7 +727,7 @@ impl WriteXdr for i64 { } impl ReadXdr for u64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -741,7 +739,7 @@ impl ReadXdr for u64 { } impl WriteXdr for u64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -752,35 +750,35 @@ impl WriteXdr for u64 { } impl ReadXdr for f32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for f64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for bool { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -791,7 +789,7 @@ impl ReadXdr for bool { } impl WriteXdr for bool { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i = u32::from(*self); // true = 1, false = 0 @@ -801,7 +799,7 @@ impl WriteXdr for bool { } impl ReadXdr for Option { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -818,7 +816,7 @@ impl ReadXdr for Option { } impl WriteXdr for Option { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { if let Some(t) = self { @@ -833,35 +831,35 @@ impl WriteXdr for Option { } impl ReadXdr for Box { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| Ok(Box::new(T::read_xdr(r)?))) } } impl WriteXdr for Box { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| T::write_xdr(self, w)) } } impl ReadXdr for () { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(_r: &mut Limited) -> Result { Ok(()) } } impl WriteXdr for () { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { Ok(()) } } impl ReadXdr for [u8; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { r.consume_len(N)?; @@ -880,7 +878,7 @@ impl ReadXdr for [u8; N] { } impl WriteXdr for [u8; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { w.consume_len(N)?; @@ -894,7 +892,7 @@ impl WriteXdr for [u8; N] { } impl ReadXdr for [T; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let mut vec = Vec::with_capacity(N); @@ -909,7 +907,7 @@ impl ReadXdr for [T; N] { } impl WriteXdr for [T; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { for t in self { @@ -1268,7 +1266,7 @@ impl<'a, const MAX: u32> TryFrom<&'a VecM> for &'a str { } impl ReadXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1295,7 +1293,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1315,7 +1313,7 @@ impl WriteXdr for VecM { } impl ReadXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len = u32::read_xdr(r)?; @@ -1335,7 +1333,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1708,7 +1706,7 @@ impl<'a, const MAX: u32> TryFrom<&'a BytesM> for &'a str { } impl ReadXdr for BytesM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1735,7 +1733,7 @@ impl ReadXdr for BytesM { } impl WriteXdr for BytesM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2111,7 +2109,7 @@ impl<'a, const MAX: u32> TryFrom<&'a StringM> for &'a str { } impl ReadXdr for StringM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -2138,7 +2136,7 @@ impl ReadXdr for StringM { } impl WriteXdr for StringM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2184,7 +2182,7 @@ impl ReadXdr for Frame where T: ReadXdr, { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { // Read the frame header value that contains 1 flag-bit and a 33-bit length. // - The 1 flag bit is 0 when there are more frames for the same record. @@ -2204,7 +2202,7 @@ where } } -#[cfg(all(test, feature = "alloc"))] +#[cfg(all(test, any(feature = "std", feature = "embedded_io")))] mod tests { use super::*; @@ -2314,7 +2312,7 @@ mod tests { } } -#[cfg(all(test, feature = "alloc"))] +#[cfg(all(test, any(feature = "std", feature = "embedded_io")))] mod test { use super::*; @@ -2827,6 +2825,219 @@ mod test { } } +#[cfg(all(test, any(feature = "std", feature = "embedded_io")))] +mod test_io { + // We will use different IO libraries according to the feature, + // we hope the selected IO library can work as expected + + use super::*; + + #[test] + fn test_read_exact_success() { + let data = b"The quick brown fox jumps over the lazy dog."; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 19]; // Exactly the length of "The quick brown fox" + + // Attempt to read exactly 19 bytes + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"The quick brown fox"); + assert_eq!(cursor.position(), 19); + } + + #[test] + fn test_read_exact_less_than_available() { + let data = b"Hello, Rust!"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 5]; + + // Attempt to read 5 bytes from the start + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Hello"); + assert_eq!(cursor.position(), 5); + } + + #[test] + fn test_read_exact_exact_eof() { + let data = b"Data"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 4]; + + // Attempt to read exactly 4 bytes, which is the entire buffer + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Data"); + assert_eq!(cursor.position(), 4); + + // Further attempt to read should fail with EOF + let mut buffer_eof = [0u8; 1]; + let result = cursor.read_exact(&mut buffer_eof); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 4); // Position should remain at EOF + } + + #[test] + fn test_read_exact_past_eof() { + let data = b"Short"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 10]; // Requesting more bytes than available + + // Attempt to read 10 bytes from a 5-byte buffer + let result = cursor.read_exact(&mut buffer); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 5); // Position should move to EOF + } + + #[test] + fn test_read_exact_empty_buffer() { + let data = b"Non-empty"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 0]; // Zero-length buffer + + // Attempt to read zero bytes + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(cursor.position(), 0); // Position should remain unchanged + } + + #[test] + fn test_read_exact_from_empty_cursor() { + let data: &[u8] = b""; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 5]; + + // Attempt to read from an empty cursor + let result = cursor.read_exact(&mut buffer); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 0); // Position remains at 0 + } + + #[test] + fn test_read_exact_multiple_reads() { + let data = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + let mut cursor = Cursor::new(data); + + let mut buffer1 = [0u8; 10]; + let mut buffer2 = [0u8; 10]; + let mut buffer3 = [0u8; 10]; // Only 6 bytes left + + // First read: 10 bytes + assert!(cursor.read_exact(&mut buffer1).is_ok()); + assert_eq!(&buffer1, b"ABCDEFGHIJ"); + assert_eq!(cursor.position(), 10); + + // Second read: 10 bytes + assert!(cursor.read_exact(&mut buffer2).is_ok()); + assert_eq!(&buffer2, b"KLMNOPQRST"); + assert_eq!(cursor.position(), 20); + + // Third read: Attempt to read 10 bytes, but only 6 are available + let result = cursor.read_exact(&mut buffer3); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + // read_exact makes no promises about the content of the buffer on error + // assert_eq!(&buffer3[..6], b"UVWXYZ"); + assert_eq!(cursor.position(), 26); // Position should be at EOF + } + + #[test] + fn test_cursor_read_exact_after_eof() { + let data = b"End"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 3]; + + // First read: read the entire buffer + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"End"); + assert_eq!(cursor.position(), 3); + + // Second read: attempt to read again, should fail + let mut buffer_eof = [0u8; 1]; + let result = cursor.read_exact(&mut buffer_eof); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 3); // Position remains at EOF + } + + #[test] + fn test_slice_read_exact_success() { + let data = b"SliceReadTest"; + let mut slice = &data[..]; + let mut buffer = [0u8; 13]; // Exact length + + // Using Read trait directly on slice + assert!(slice.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"SliceReadTest"); + } + + #[test] + fn test_slice_read_exact_partial() { + let data = b"SlicePartial"; + let mut slice = &data[..]; + let mut buffer = [0u8; 20]; // Request more bytes than available + + // Using Read trait directly on slice + let result = slice.read_exact(&mut buffer); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + // read_exact makes no promises about the content of the buffer on error + } +} + /// Arr is an XDR Typedef defines as: /// /// ```text @@ -2856,7 +3067,7 @@ pub struct HasOptions { } impl ReadXdr for HasOptions { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { Ok(Self{ @@ -2869,7 +3080,7 @@ third_option: Option::::read_xdr(r)?, } impl WriteXdr for HasOptions { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { self.first_option.write_xdr(w)?; @@ -2968,7 +3179,7 @@ TypeVariant::HasOptions, ]; pub const VARIANTS_STR: [&'static str; 2] = [ "Arr", "HasOptions", ]; - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] #[allow(clippy::too_many_lines)] pub fn read_xdr(v: TypeVariant, r: &mut Limited) -> Result { match v { @@ -2984,7 +3195,7 @@ TypeVariant::HasOptions => r.with_limited_depth(|r| Ok(Self::HasOptions(Box::new Ok(t) } - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] pub fn read_xdr_to_end(v: TypeVariant, r: &mut Limited) -> Result { let s = Self::read_xdr(v, r)?; // Check that any further reads, such as this read of one byte, read no @@ -3031,7 +3242,7 @@ TypeVariant::HasOptions => Box::new(ReadXdrIter::<_, HasOptions>::new(dec, r.lim } } - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] pub fn from_xdr>(v: TypeVariant, bytes: B, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(v, &mut cursor)?; @@ -3120,7 +3331,7 @@ Self::HasOptions(_) => TypeVariant::HasOptions, } impl WriteXdr for Type { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] #[allow(clippy::too_many_lines)] fn write_xdr(&self, w: &mut Limited) -> Result<()> { match self { diff --git a/spec/output/generator_spec_rust_custom_jsonschema_impls/struct.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_jsonschema_impls/struct.x/MyXDR.rs index c25eb15aa..86a157170 100644 --- a/spec/output/generator_spec_rust_custom_jsonschema_impls/struct.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_jsonschema_impls/struct.x/MyXDR.rs @@ -50,7 +50,7 @@ use std::{ io::{BufRead, BufReader, Cursor, Read, Write}, }; -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] use embedded_io_extras::{Cursor, Error as _, ErrorType, Read, Write}; /// Error contains all errors returned by functions in this crate. It can be @@ -68,7 +68,7 @@ pub enum Error { InvalidHex, #[cfg(feature = "std")] Io(io::Error), - #[cfg(all(not(feature = "std"), feature = "alloc"))] + #[cfg(feature = "embedded_io")] Io(embedded_io_extras::ErrorKind), DepthLimitExceeded, #[cfg(feature = "serde_json")] @@ -86,15 +86,14 @@ impl PartialEq for Error { // case for comparing errors outputted by the XDR library is for // error case testing, and a lack of the ability to compare has a // detrimental affect on failure testing, so this is a tradeoff. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] (Self::Io(l), Self::Io(r)) => l.kind() == r.kind(), _ => core::mem::discriminant(self) == core::mem::discriminant(other), } } } - -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl embedded_io_extras::Error for Error { fn kind(&self) -> embedded_io_extras::ErrorKind { match self { @@ -104,7 +103,7 @@ impl embedded_io_extras::Error for Error { } } -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl From> for Error { fn from(value: embedded_io_extras::ReadExactError) -> Self { match value { @@ -140,7 +139,7 @@ impl fmt::Display for Error { Error::InvalidHex => write!(f, "hex invalid"), #[cfg(feature = "std")] Error::Io(e) => write!(f, "{e}"), - #[cfg(all(not(feature = "std"), feature = "alloc"))] + #[cfg(feature = "embedded_io")] Error::Io(_) => write!(f, "io error"), Error::DepthLimitExceeded => write!(f, "depth limit exceeded"), #[cfg(feature = "serde_json")] @@ -194,7 +193,7 @@ impl From for () { #[allow(dead_code)] type Result = core::result::Result; -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl ErrorType for Limited { type Error = Error; } /// Name defines types that assign a static name to their value, such as the @@ -230,7 +229,7 @@ where /// `Limits` contains the limits that a limited reader or writer will be /// constrained to. -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] #[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct Limits { /// Defines the maximum depth for recursive calls in `Read/WriteXdr` to @@ -247,7 +246,7 @@ pub struct Limits { pub len: usize, } -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] impl Limits { #[must_use] pub fn none() -> Self { @@ -278,13 +277,13 @@ impl Limits { /// /// Intended for use with readers and writers and limiting their reads and /// writes. -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] pub struct Limited { pub inner: L, pub(crate) limits: Limits, } -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] impl Limited { /// Constructs a new `Limited`. /// @@ -337,8 +336,7 @@ impl Read for Limited { } } - -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl Read for Limited { /// Forwards the read operation to the wrapped object. fn read(&mut self, buf: &mut [u8]) -> core::result::Result { @@ -372,7 +370,7 @@ impl Write for Limited { } } -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl Write for Limited { /// Forwards the write operation to the wrapped object. fn write(&mut self, buf: &[u8]) -> core::result::Result { @@ -457,7 +455,7 @@ where /// /// Use [`ReadXdR: Read_xdr_to_end`] when the intent is for all bytes in the /// read implementation to be consumed by the read. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result; /// Construct the type from the XDR bytes base64 encoded. @@ -492,7 +490,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr_to_end(r: &mut Limited) -> Result { let s = Self::read_xdr(r)?; // Check that any further reads, such as this read of one byte, read no @@ -532,7 +530,7 @@ where /// /// Use [`ReadXdR: Read_xdr_into_to_end`] when the intent is for all bytes /// in the read implementation to be consumed by the read. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr_into(&mut self, r: &mut Limited) -> Result<()> { *self = Self::read_xdr(r)?; Ok(()) @@ -556,7 +554,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr_into_to_end(&mut self, r: &mut Limited) -> Result<()> { Self::read_xdr_into(self, r)?; // Check that any further reads, such as this read of one byte, read no @@ -605,7 +603,7 @@ where /// /// An error is returned if the bytes are not completely consumed by the /// deserialization. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn from_xdr(bytes: impl AsRef<[u8]>, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(&mut cursor)?; @@ -629,10 +627,10 @@ where } pub trait WriteXdr { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()>; - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn to_xdr(&self, limits: Limits) -> Result> { let mut cursor = Limited::new(Cursor::new(vec![]), limits); self.write_xdr(&mut cursor)?; @@ -654,13 +652,13 @@ pub trait WriteXdr { /// `Pad_len` returns the number of bytes to pad an XDR value of the given /// length to make the final serialized size a multiple of 4. -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] fn pad_len(len: usize) -> usize { (4 - (len % 4)) % 4 } impl ReadXdr for i32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -672,7 +670,7 @@ impl ReadXdr for i32 { } impl WriteXdr for i32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -683,7 +681,7 @@ impl WriteXdr for i32 { } impl ReadXdr for u32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -695,7 +693,7 @@ impl ReadXdr for u32 { } impl WriteXdr for u32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -706,7 +704,7 @@ impl WriteXdr for u32 { } impl ReadXdr for i64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -718,7 +716,7 @@ impl ReadXdr for i64 { } impl WriteXdr for i64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -729,7 +727,7 @@ impl WriteXdr for i64 { } impl ReadXdr for u64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -741,7 +739,7 @@ impl ReadXdr for u64 { } impl WriteXdr for u64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -752,35 +750,35 @@ impl WriteXdr for u64 { } impl ReadXdr for f32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for f64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for bool { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -791,7 +789,7 @@ impl ReadXdr for bool { } impl WriteXdr for bool { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i = u32::from(*self); // true = 1, false = 0 @@ -801,7 +799,7 @@ impl WriteXdr for bool { } impl ReadXdr for Option { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -818,7 +816,7 @@ impl ReadXdr for Option { } impl WriteXdr for Option { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { if let Some(t) = self { @@ -833,35 +831,35 @@ impl WriteXdr for Option { } impl ReadXdr for Box { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| Ok(Box::new(T::read_xdr(r)?))) } } impl WriteXdr for Box { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| T::write_xdr(self, w)) } } impl ReadXdr for () { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(_r: &mut Limited) -> Result { Ok(()) } } impl WriteXdr for () { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { Ok(()) } } impl ReadXdr for [u8; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { r.consume_len(N)?; @@ -880,7 +878,7 @@ impl ReadXdr for [u8; N] { } impl WriteXdr for [u8; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { w.consume_len(N)?; @@ -894,7 +892,7 @@ impl WriteXdr for [u8; N] { } impl ReadXdr for [T; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let mut vec = Vec::with_capacity(N); @@ -909,7 +907,7 @@ impl ReadXdr for [T; N] { } impl WriteXdr for [T; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { for t in self { @@ -1268,7 +1266,7 @@ impl<'a, const MAX: u32> TryFrom<&'a VecM> for &'a str { } impl ReadXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1295,7 +1293,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1315,7 +1313,7 @@ impl WriteXdr for VecM { } impl ReadXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len = u32::read_xdr(r)?; @@ -1335,7 +1333,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1708,7 +1706,7 @@ impl<'a, const MAX: u32> TryFrom<&'a BytesM> for &'a str { } impl ReadXdr for BytesM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1735,7 +1733,7 @@ impl ReadXdr for BytesM { } impl WriteXdr for BytesM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2111,7 +2109,7 @@ impl<'a, const MAX: u32> TryFrom<&'a StringM> for &'a str { } impl ReadXdr for StringM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -2138,7 +2136,7 @@ impl ReadXdr for StringM { } impl WriteXdr for StringM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2184,7 +2182,7 @@ impl ReadXdr for Frame where T: ReadXdr, { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { // Read the frame header value that contains 1 flag-bit and a 33-bit length. // - The 1 flag bit is 0 when there are more frames for the same record. @@ -2204,7 +2202,7 @@ where } } -#[cfg(all(test, feature = "alloc"))] +#[cfg(all(test, any(feature = "std", feature = "embedded_io")))] mod tests { use super::*; @@ -2314,7 +2312,7 @@ mod tests { } } -#[cfg(all(test, feature = "alloc"))] +#[cfg(all(test, any(feature = "std", feature = "embedded_io")))] mod test { use super::*; @@ -2827,6 +2825,219 @@ mod test { } } +#[cfg(all(test, any(feature = "std", feature = "embedded_io")))] +mod test_io { + // We will use different IO libraries according to the feature, + // we hope the selected IO library can work as expected + + use super::*; + + #[test] + fn test_read_exact_success() { + let data = b"The quick brown fox jumps over the lazy dog."; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 19]; // Exactly the length of "The quick brown fox" + + // Attempt to read exactly 19 bytes + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"The quick brown fox"); + assert_eq!(cursor.position(), 19); + } + + #[test] + fn test_read_exact_less_than_available() { + let data = b"Hello, Rust!"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 5]; + + // Attempt to read 5 bytes from the start + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Hello"); + assert_eq!(cursor.position(), 5); + } + + #[test] + fn test_read_exact_exact_eof() { + let data = b"Data"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 4]; + + // Attempt to read exactly 4 bytes, which is the entire buffer + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Data"); + assert_eq!(cursor.position(), 4); + + // Further attempt to read should fail with EOF + let mut buffer_eof = [0u8; 1]; + let result = cursor.read_exact(&mut buffer_eof); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 4); // Position should remain at EOF + } + + #[test] + fn test_read_exact_past_eof() { + let data = b"Short"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 10]; // Requesting more bytes than available + + // Attempt to read 10 bytes from a 5-byte buffer + let result = cursor.read_exact(&mut buffer); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 5); // Position should move to EOF + } + + #[test] + fn test_read_exact_empty_buffer() { + let data = b"Non-empty"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 0]; // Zero-length buffer + + // Attempt to read zero bytes + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(cursor.position(), 0); // Position should remain unchanged + } + + #[test] + fn test_read_exact_from_empty_cursor() { + let data: &[u8] = b""; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 5]; + + // Attempt to read from an empty cursor + let result = cursor.read_exact(&mut buffer); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 0); // Position remains at 0 + } + + #[test] + fn test_read_exact_multiple_reads() { + let data = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + let mut cursor = Cursor::new(data); + + let mut buffer1 = [0u8; 10]; + let mut buffer2 = [0u8; 10]; + let mut buffer3 = [0u8; 10]; // Only 6 bytes left + + // First read: 10 bytes + assert!(cursor.read_exact(&mut buffer1).is_ok()); + assert_eq!(&buffer1, b"ABCDEFGHIJ"); + assert_eq!(cursor.position(), 10); + + // Second read: 10 bytes + assert!(cursor.read_exact(&mut buffer2).is_ok()); + assert_eq!(&buffer2, b"KLMNOPQRST"); + assert_eq!(cursor.position(), 20); + + // Third read: Attempt to read 10 bytes, but only 6 are available + let result = cursor.read_exact(&mut buffer3); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + // read_exact makes no promises about the content of the buffer on error + // assert_eq!(&buffer3[..6], b"UVWXYZ"); + assert_eq!(cursor.position(), 26); // Position should be at EOF + } + + #[test] + fn test_cursor_read_exact_after_eof() { + let data = b"End"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 3]; + + // First read: read the entire buffer + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"End"); + assert_eq!(cursor.position(), 3); + + // Second read: attempt to read again, should fail + let mut buffer_eof = [0u8; 1]; + let result = cursor.read_exact(&mut buffer_eof); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 3); // Position remains at EOF + } + + #[test] + fn test_slice_read_exact_success() { + let data = b"SliceReadTest"; + let mut slice = &data[..]; + let mut buffer = [0u8; 13]; // Exact length + + // Using Read trait directly on slice + assert!(slice.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"SliceReadTest"); + } + + #[test] + fn test_slice_read_exact_partial() { + let data = b"SlicePartial"; + let mut slice = &data[..]; + let mut buffer = [0u8; 20]; // Request more bytes than available + + // Using Read trait directly on slice + let result = slice.read_exact(&mut buffer); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + // read_exact makes no promises about the content of the buffer on error + } +} + /// Int64 is an XDR Typedef defines as: /// /// ```text @@ -2860,7 +3071,7 @@ pub struct MyStruct { } impl ReadXdr for MyStruct { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { Ok(Self{ @@ -2875,7 +3086,7 @@ max_string: StringM::<100>::read_xdr(r)?, } impl WriteXdr for MyStruct { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { self.some_int.write_xdr(w)?; @@ -2976,7 +3187,7 @@ TypeVariant::MyStruct, ]; pub const VARIANTS_STR: [&'static str; 2] = [ "Int64", "MyStruct", ]; - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] #[allow(clippy::too_many_lines)] pub fn read_xdr(v: TypeVariant, r: &mut Limited) -> Result { match v { @@ -2992,7 +3203,7 @@ TypeVariant::MyStruct => r.with_limited_depth(|r| Ok(Self::MyStruct(Box::new(MyS Ok(t) } - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] pub fn read_xdr_to_end(v: TypeVariant, r: &mut Limited) -> Result { let s = Self::read_xdr(v, r)?; // Check that any further reads, such as this read of one byte, read no @@ -3039,7 +3250,7 @@ TypeVariant::MyStruct => Box::new(ReadXdrIter::<_, MyStruct>::new(dec, r.limits. } } - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] pub fn from_xdr>(v: TypeVariant, bytes: B, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(v, &mut cursor)?; @@ -3128,7 +3339,7 @@ Self::MyStruct(_) => TypeVariant::MyStruct, } impl WriteXdr for Type { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] #[allow(clippy::too_many_lines)] fn write_xdr(&self, w: &mut Limited) -> Result<()> { match self { diff --git a/spec/output/generator_spec_rust_custom_jsonschema_impls/test.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_jsonschema_impls/test.x/MyXDR.rs index f76a26c4d..8fef6da29 100644 --- a/spec/output/generator_spec_rust_custom_jsonschema_impls/test.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_jsonschema_impls/test.x/MyXDR.rs @@ -50,7 +50,7 @@ use std::{ io::{BufRead, BufReader, Cursor, Read, Write}, }; -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] use embedded_io_extras::{Cursor, Error as _, ErrorType, Read, Write}; /// Error contains all errors returned by functions in this crate. It can be @@ -68,7 +68,7 @@ pub enum Error { InvalidHex, #[cfg(feature = "std")] Io(io::Error), - #[cfg(all(not(feature = "std"), feature = "alloc"))] + #[cfg(feature = "embedded_io")] Io(embedded_io_extras::ErrorKind), DepthLimitExceeded, #[cfg(feature = "serde_json")] @@ -86,15 +86,14 @@ impl PartialEq for Error { // case for comparing errors outputted by the XDR library is for // error case testing, and a lack of the ability to compare has a // detrimental affect on failure testing, so this is a tradeoff. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] (Self::Io(l), Self::Io(r)) => l.kind() == r.kind(), _ => core::mem::discriminant(self) == core::mem::discriminant(other), } } } - -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl embedded_io_extras::Error for Error { fn kind(&self) -> embedded_io_extras::ErrorKind { match self { @@ -104,7 +103,7 @@ impl embedded_io_extras::Error for Error { } } -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl From> for Error { fn from(value: embedded_io_extras::ReadExactError) -> Self { match value { @@ -140,7 +139,7 @@ impl fmt::Display for Error { Error::InvalidHex => write!(f, "hex invalid"), #[cfg(feature = "std")] Error::Io(e) => write!(f, "{e}"), - #[cfg(all(not(feature = "std"), feature = "alloc"))] + #[cfg(feature = "embedded_io")] Error::Io(_) => write!(f, "io error"), Error::DepthLimitExceeded => write!(f, "depth limit exceeded"), #[cfg(feature = "serde_json")] @@ -194,7 +193,7 @@ impl From for () { #[allow(dead_code)] type Result = core::result::Result; -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl ErrorType for Limited { type Error = Error; } /// Name defines types that assign a static name to their value, such as the @@ -230,7 +229,7 @@ where /// `Limits` contains the limits that a limited reader or writer will be /// constrained to. -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] #[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct Limits { /// Defines the maximum depth for recursive calls in `Read/WriteXdr` to @@ -247,7 +246,7 @@ pub struct Limits { pub len: usize, } -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] impl Limits { #[must_use] pub fn none() -> Self { @@ -278,13 +277,13 @@ impl Limits { /// /// Intended for use with readers and writers and limiting their reads and /// writes. -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] pub struct Limited { pub inner: L, pub(crate) limits: Limits, } -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] impl Limited { /// Constructs a new `Limited`. /// @@ -337,8 +336,7 @@ impl Read for Limited { } } - -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl Read for Limited { /// Forwards the read operation to the wrapped object. fn read(&mut self, buf: &mut [u8]) -> core::result::Result { @@ -372,7 +370,7 @@ impl Write for Limited { } } -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl Write for Limited { /// Forwards the write operation to the wrapped object. fn write(&mut self, buf: &[u8]) -> core::result::Result { @@ -457,7 +455,7 @@ where /// /// Use [`ReadXdR: Read_xdr_to_end`] when the intent is for all bytes in the /// read implementation to be consumed by the read. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result; /// Construct the type from the XDR bytes base64 encoded. @@ -492,7 +490,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr_to_end(r: &mut Limited) -> Result { let s = Self::read_xdr(r)?; // Check that any further reads, such as this read of one byte, read no @@ -532,7 +530,7 @@ where /// /// Use [`ReadXdR: Read_xdr_into_to_end`] when the intent is for all bytes /// in the read implementation to be consumed by the read. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr_into(&mut self, r: &mut Limited) -> Result<()> { *self = Self::read_xdr(r)?; Ok(()) @@ -556,7 +554,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr_into_to_end(&mut self, r: &mut Limited) -> Result<()> { Self::read_xdr_into(self, r)?; // Check that any further reads, such as this read of one byte, read no @@ -605,7 +603,7 @@ where /// /// An error is returned if the bytes are not completely consumed by the /// deserialization. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn from_xdr(bytes: impl AsRef<[u8]>, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(&mut cursor)?; @@ -629,10 +627,10 @@ where } pub trait WriteXdr { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()>; - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn to_xdr(&self, limits: Limits) -> Result> { let mut cursor = Limited::new(Cursor::new(vec![]), limits); self.write_xdr(&mut cursor)?; @@ -654,13 +652,13 @@ pub trait WriteXdr { /// `Pad_len` returns the number of bytes to pad an XDR value of the given /// length to make the final serialized size a multiple of 4. -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] fn pad_len(len: usize) -> usize { (4 - (len % 4)) % 4 } impl ReadXdr for i32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -672,7 +670,7 @@ impl ReadXdr for i32 { } impl WriteXdr for i32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -683,7 +681,7 @@ impl WriteXdr for i32 { } impl ReadXdr for u32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -695,7 +693,7 @@ impl ReadXdr for u32 { } impl WriteXdr for u32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -706,7 +704,7 @@ impl WriteXdr for u32 { } impl ReadXdr for i64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -718,7 +716,7 @@ impl ReadXdr for i64 { } impl WriteXdr for i64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -729,7 +727,7 @@ impl WriteXdr for i64 { } impl ReadXdr for u64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -741,7 +739,7 @@ impl ReadXdr for u64 { } impl WriteXdr for u64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -752,35 +750,35 @@ impl WriteXdr for u64 { } impl ReadXdr for f32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for f64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for bool { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -791,7 +789,7 @@ impl ReadXdr for bool { } impl WriteXdr for bool { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i = u32::from(*self); // true = 1, false = 0 @@ -801,7 +799,7 @@ impl WriteXdr for bool { } impl ReadXdr for Option { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -818,7 +816,7 @@ impl ReadXdr for Option { } impl WriteXdr for Option { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { if let Some(t) = self { @@ -833,35 +831,35 @@ impl WriteXdr for Option { } impl ReadXdr for Box { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| Ok(Box::new(T::read_xdr(r)?))) } } impl WriteXdr for Box { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| T::write_xdr(self, w)) } } impl ReadXdr for () { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(_r: &mut Limited) -> Result { Ok(()) } } impl WriteXdr for () { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { Ok(()) } } impl ReadXdr for [u8; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { r.consume_len(N)?; @@ -880,7 +878,7 @@ impl ReadXdr for [u8; N] { } impl WriteXdr for [u8; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { w.consume_len(N)?; @@ -894,7 +892,7 @@ impl WriteXdr for [u8; N] { } impl ReadXdr for [T; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let mut vec = Vec::with_capacity(N); @@ -909,7 +907,7 @@ impl ReadXdr for [T; N] { } impl WriteXdr for [T; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { for t in self { @@ -1268,7 +1266,7 @@ impl<'a, const MAX: u32> TryFrom<&'a VecM> for &'a str { } impl ReadXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1295,7 +1293,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1315,7 +1313,7 @@ impl WriteXdr for VecM { } impl ReadXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len = u32::read_xdr(r)?; @@ -1335,7 +1333,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1708,7 +1706,7 @@ impl<'a, const MAX: u32> TryFrom<&'a BytesM> for &'a str { } impl ReadXdr for BytesM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1735,7 +1733,7 @@ impl ReadXdr for BytesM { } impl WriteXdr for BytesM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2111,7 +2109,7 @@ impl<'a, const MAX: u32> TryFrom<&'a StringM> for &'a str { } impl ReadXdr for StringM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -2138,7 +2136,7 @@ impl ReadXdr for StringM { } impl WriteXdr for StringM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2184,7 +2182,7 @@ impl ReadXdr for Frame where T: ReadXdr, { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { // Read the frame header value that contains 1 flag-bit and a 33-bit length. // - The 1 flag bit is 0 when there are more frames for the same record. @@ -2204,7 +2202,7 @@ where } } -#[cfg(all(test, feature = "alloc"))] +#[cfg(all(test, any(feature = "std", feature = "embedded_io")))] mod tests { use super::*; @@ -2314,7 +2312,7 @@ mod tests { } } -#[cfg(all(test, feature = "alloc"))] +#[cfg(all(test, any(feature = "std", feature = "embedded_io")))] mod test { use super::*; @@ -2827,6 +2825,219 @@ mod test { } } +#[cfg(all(test, any(feature = "std", feature = "embedded_io")))] +mod test_io { + // We will use different IO libraries according to the feature, + // we hope the selected IO library can work as expected + + use super::*; + + #[test] + fn test_read_exact_success() { + let data = b"The quick brown fox jumps over the lazy dog."; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 19]; // Exactly the length of "The quick brown fox" + + // Attempt to read exactly 19 bytes + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"The quick brown fox"); + assert_eq!(cursor.position(), 19); + } + + #[test] + fn test_read_exact_less_than_available() { + let data = b"Hello, Rust!"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 5]; + + // Attempt to read 5 bytes from the start + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Hello"); + assert_eq!(cursor.position(), 5); + } + + #[test] + fn test_read_exact_exact_eof() { + let data = b"Data"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 4]; + + // Attempt to read exactly 4 bytes, which is the entire buffer + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Data"); + assert_eq!(cursor.position(), 4); + + // Further attempt to read should fail with EOF + let mut buffer_eof = [0u8; 1]; + let result = cursor.read_exact(&mut buffer_eof); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 4); // Position should remain at EOF + } + + #[test] + fn test_read_exact_past_eof() { + let data = b"Short"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 10]; // Requesting more bytes than available + + // Attempt to read 10 bytes from a 5-byte buffer + let result = cursor.read_exact(&mut buffer); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 5); // Position should move to EOF + } + + #[test] + fn test_read_exact_empty_buffer() { + let data = b"Non-empty"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 0]; // Zero-length buffer + + // Attempt to read zero bytes + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(cursor.position(), 0); // Position should remain unchanged + } + + #[test] + fn test_read_exact_from_empty_cursor() { + let data: &[u8] = b""; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 5]; + + // Attempt to read from an empty cursor + let result = cursor.read_exact(&mut buffer); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 0); // Position remains at 0 + } + + #[test] + fn test_read_exact_multiple_reads() { + let data = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + let mut cursor = Cursor::new(data); + + let mut buffer1 = [0u8; 10]; + let mut buffer2 = [0u8; 10]; + let mut buffer3 = [0u8; 10]; // Only 6 bytes left + + // First read: 10 bytes + assert!(cursor.read_exact(&mut buffer1).is_ok()); + assert_eq!(&buffer1, b"ABCDEFGHIJ"); + assert_eq!(cursor.position(), 10); + + // Second read: 10 bytes + assert!(cursor.read_exact(&mut buffer2).is_ok()); + assert_eq!(&buffer2, b"KLMNOPQRST"); + assert_eq!(cursor.position(), 20); + + // Third read: Attempt to read 10 bytes, but only 6 are available + let result = cursor.read_exact(&mut buffer3); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + // read_exact makes no promises about the content of the buffer on error + // assert_eq!(&buffer3[..6], b"UVWXYZ"); + assert_eq!(cursor.position(), 26); // Position should be at EOF + } + + #[test] + fn test_cursor_read_exact_after_eof() { + let data = b"End"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 3]; + + // First read: read the entire buffer + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"End"); + assert_eq!(cursor.position(), 3); + + // Second read: attempt to read again, should fail + let mut buffer_eof = [0u8; 1]; + let result = cursor.read_exact(&mut buffer_eof); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 3); // Position remains at EOF + } + + #[test] + fn test_slice_read_exact_success() { + let data = b"SliceReadTest"; + let mut slice = &data[..]; + let mut buffer = [0u8; 13]; // Exact length + + // Using Read trait directly on slice + assert!(slice.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"SliceReadTest"); + } + + #[test] + fn test_slice_read_exact_partial() { + let data = b"SlicePartial"; + let mut slice = &data[..]; + let mut buffer = [0u8; 20]; // Request more bytes than available + + // Using Read trait directly on slice + let result = slice.read_exact(&mut buffer); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + // read_exact makes no promises about the content of the buffer on error + } +} + /// Uint512 is an XDR Typedef defines as: /// /// ```text @@ -2921,7 +3132,7 @@ impl AsRef<[u8; 64]> for Uint512 { } impl ReadXdr for Uint512 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = <[u8; 64]>::read_xdr(r)?; @@ -2932,7 +3143,7 @@ impl ReadXdr for Uint512 { } impl WriteXdr for Uint512 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w|{ self.0.write_xdr(w) }) } @@ -3011,7 +3222,7 @@ impl AsRef> for Uint513 { } impl ReadXdr for Uint513 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = BytesM::<64>::read_xdr(r)?; @@ -3022,7 +3233,7 @@ impl ReadXdr for Uint513 { } impl WriteXdr for Uint513 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w|{ self.0.write_xdr(w) }) } @@ -3113,7 +3324,7 @@ impl AsRef for Uint514 { } impl ReadXdr for Uint514 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = BytesM::read_xdr(r)?; @@ -3124,7 +3335,7 @@ impl ReadXdr for Uint514 { } impl WriteXdr for Uint514 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w|{ self.0.write_xdr(w) }) } @@ -3215,7 +3426,7 @@ impl AsRef> for Str { } impl ReadXdr for Str { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = StringM::<64>::read_xdr(r)?; @@ -3226,7 +3437,7 @@ impl ReadXdr for Str { } impl WriteXdr for Str { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w|{ self.0.write_xdr(w) }) } @@ -3317,7 +3528,7 @@ impl AsRef for Str2 { } impl ReadXdr for Str2 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = StringM::read_xdr(r)?; @@ -3328,7 +3539,7 @@ impl ReadXdr for Str2 { } impl WriteXdr for Str2 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w|{ self.0.write_xdr(w) }) } @@ -3477,7 +3688,7 @@ impl AsRef<[u8; 32]> for Hash { } impl ReadXdr for Hash { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = <[u8; 32]>::read_xdr(r)?; @@ -3488,7 +3699,7 @@ impl ReadXdr for Hash { } impl WriteXdr for Hash { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w|{ self.0.write_xdr(w) }) } @@ -3566,7 +3777,7 @@ impl AsRef<[Hash; 12]> for Hashes1 { } impl ReadXdr for Hashes1 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = <[Hash; 12]>::read_xdr(r)?; @@ -3577,7 +3788,7 @@ impl ReadXdr for Hashes1 { } impl WriteXdr for Hashes1 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w|{ self.0.write_xdr(w) }) } @@ -3656,7 +3867,7 @@ impl AsRef> for Hashes2 { } impl ReadXdr for Hashes2 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = VecM::::read_xdr(r)?; @@ -3667,7 +3878,7 @@ impl ReadXdr for Hashes2 { } impl WriteXdr for Hashes2 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w|{ self.0.write_xdr(w) }) } @@ -3758,7 +3969,7 @@ impl AsRef> for Hashes3 { } impl ReadXdr for Hashes3 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = VecM::::read_xdr(r)?; @@ -3769,7 +3980,7 @@ impl ReadXdr for Hashes3 { } impl WriteXdr for Hashes3 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w|{ self.0.write_xdr(w) }) } @@ -3859,7 +4070,7 @@ impl AsRef> for OptHash1 { } impl ReadXdr for OptHash1 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = Option::::read_xdr(r)?; @@ -3870,7 +4081,7 @@ impl ReadXdr for OptHash1 { } impl WriteXdr for OptHash1 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w|{ self.0.write_xdr(w) }) } @@ -3911,7 +4122,7 @@ impl AsRef> for OptHash2 { } impl ReadXdr for OptHash2 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = Option::::read_xdr(r)?; @@ -3922,7 +4133,7 @@ impl ReadXdr for OptHash2 { } impl WriteXdr for OptHash2 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w|{ self.0.write_xdr(w) }) } @@ -3989,7 +4200,7 @@ pub struct MyStruct { } impl ReadXdr for MyStruct { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { Ok(Self{ @@ -4006,7 +4217,7 @@ field7: bool::read_xdr(r)?, } impl WriteXdr for MyStruct { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { self.field1.write_xdr(w)?; @@ -4038,7 +4249,7 @@ pub struct LotsOfMyStructs { } impl ReadXdr for LotsOfMyStructs { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { Ok(Self{ @@ -4049,7 +4260,7 @@ impl ReadXdr for LotsOfMyStructs { } impl WriteXdr for LotsOfMyStructs { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { self.members.write_xdr(w)?; @@ -4076,7 +4287,7 @@ pub struct HasStuff { } impl ReadXdr for HasStuff { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { Ok(Self{ @@ -4087,7 +4298,7 @@ impl ReadXdr for HasStuff { } impl WriteXdr for HasStuff { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { self.data.write_xdr(w)?; @@ -4185,7 +4396,7 @@ Self::Green => "Green", } impl ReadXdr for Color { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let e = i32::read_xdr(r)?; @@ -4196,7 +4407,7 @@ Self::Green => "Green", } impl WriteXdr for Color { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i: i32 = (*self).into(); @@ -4304,7 +4515,7 @@ Self::B2 => "B2", } impl ReadXdr for NesterNestedEnum { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let e = i32::read_xdr(r)?; @@ -4315,7 +4526,7 @@ Self::B2 => "B2", } impl WriteXdr for NesterNestedEnum { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i: i32 = (*self).into(); @@ -4341,7 +4552,7 @@ pub struct NesterNestedStruct { } impl ReadXdr for NesterNestedStruct { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { Ok(Self{ @@ -4352,7 +4563,7 @@ impl ReadXdr for NesterNestedStruct { } impl WriteXdr for NesterNestedStruct { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { self.blah.write_xdr(w)?; @@ -4434,7 +4645,7 @@ impl Variants for NesterNestedUnion { impl Union for NesterNestedUnion {} impl ReadXdr for NesterNestedUnion { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let dv: Color = ::read_xdr(r)?; @@ -4450,7 +4661,7 @@ impl ReadXdr for NesterNestedUnion { } impl WriteXdr for NesterNestedUnion { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { self.discriminant().write_xdr(w)?; @@ -4499,7 +4710,7 @@ pub struct Nester { } impl ReadXdr for Nester { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { Ok(Self{ @@ -4512,7 +4723,7 @@ nested_union: NesterNestedUnion::read_xdr(r)?, } impl WriteXdr for Nester { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { self.nested_enum.write_xdr(w)?; @@ -4800,7 +5011,7 @@ TypeVariant::NesterNestedUnion, ]; "NesterNestedStruct", "NesterNestedUnion", ]; - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] #[allow(clippy::too_many_lines)] pub fn read_xdr(v: TypeVariant, r: &mut Limited) -> Result { match v { @@ -4837,7 +5048,7 @@ TypeVariant::NesterNestedUnion => r.with_limited_depth(|r| Ok(Self::NesterNested Ok(t) } - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] pub fn read_xdr_to_end(v: TypeVariant, r: &mut Limited) -> Result { let s = Self::read_xdr(v, r)?; // Check that any further reads, such as this read of one byte, read no @@ -4947,7 +5158,7 @@ TypeVariant::NesterNestedUnion => Box::new(ReadXdrIter::<_, NesterNestedUnion>:: } } - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] pub fn from_xdr>(v: TypeVariant, bytes: B, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(v, &mut cursor)?; @@ -5141,7 +5352,7 @@ Self::NesterNestedUnion(_) => TypeVariant::NesterNestedUnion, } impl WriteXdr for Type { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] #[allow(clippy::too_many_lines)] fn write_xdr(&self, w: &mut Limited) -> Result<()> { match self { diff --git a/spec/output/generator_spec_rust_custom_jsonschema_impls/union.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_jsonschema_impls/union.x/MyXDR.rs index bf9c226a7..80e68e93d 100644 --- a/spec/output/generator_spec_rust_custom_jsonschema_impls/union.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_jsonschema_impls/union.x/MyXDR.rs @@ -50,7 +50,7 @@ use std::{ io::{BufRead, BufReader, Cursor, Read, Write}, }; -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] use embedded_io_extras::{Cursor, Error as _, ErrorType, Read, Write}; /// Error contains all errors returned by functions in this crate. It can be @@ -68,7 +68,7 @@ pub enum Error { InvalidHex, #[cfg(feature = "std")] Io(io::Error), - #[cfg(all(not(feature = "std"), feature = "alloc"))] + #[cfg(feature = "embedded_io")] Io(embedded_io_extras::ErrorKind), DepthLimitExceeded, #[cfg(feature = "serde_json")] @@ -86,15 +86,14 @@ impl PartialEq for Error { // case for comparing errors outputted by the XDR library is for // error case testing, and a lack of the ability to compare has a // detrimental affect on failure testing, so this is a tradeoff. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] (Self::Io(l), Self::Io(r)) => l.kind() == r.kind(), _ => core::mem::discriminant(self) == core::mem::discriminant(other), } } } - -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl embedded_io_extras::Error for Error { fn kind(&self) -> embedded_io_extras::ErrorKind { match self { @@ -104,7 +103,7 @@ impl embedded_io_extras::Error for Error { } } -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl From> for Error { fn from(value: embedded_io_extras::ReadExactError) -> Self { match value { @@ -140,7 +139,7 @@ impl fmt::Display for Error { Error::InvalidHex => write!(f, "hex invalid"), #[cfg(feature = "std")] Error::Io(e) => write!(f, "{e}"), - #[cfg(all(not(feature = "std"), feature = "alloc"))] + #[cfg(feature = "embedded_io")] Error::Io(_) => write!(f, "io error"), Error::DepthLimitExceeded => write!(f, "depth limit exceeded"), #[cfg(feature = "serde_json")] @@ -194,7 +193,7 @@ impl From for () { #[allow(dead_code)] type Result = core::result::Result; -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl ErrorType for Limited { type Error = Error; } /// Name defines types that assign a static name to their value, such as the @@ -230,7 +229,7 @@ where /// `Limits` contains the limits that a limited reader or writer will be /// constrained to. -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] #[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct Limits { /// Defines the maximum depth for recursive calls in `Read/WriteXdr` to @@ -247,7 +246,7 @@ pub struct Limits { pub len: usize, } -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] impl Limits { #[must_use] pub fn none() -> Self { @@ -278,13 +277,13 @@ impl Limits { /// /// Intended for use with readers and writers and limiting their reads and /// writes. -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] pub struct Limited { pub inner: L, pub(crate) limits: Limits, } -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] impl Limited { /// Constructs a new `Limited`. /// @@ -337,8 +336,7 @@ impl Read for Limited { } } - -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl Read for Limited { /// Forwards the read operation to the wrapped object. fn read(&mut self, buf: &mut [u8]) -> core::result::Result { @@ -372,7 +370,7 @@ impl Write for Limited { } } -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl Write for Limited { /// Forwards the write operation to the wrapped object. fn write(&mut self, buf: &[u8]) -> core::result::Result { @@ -457,7 +455,7 @@ where /// /// Use [`ReadXdR: Read_xdr_to_end`] when the intent is for all bytes in the /// read implementation to be consumed by the read. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result; /// Construct the type from the XDR bytes base64 encoded. @@ -492,7 +490,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr_to_end(r: &mut Limited) -> Result { let s = Self::read_xdr(r)?; // Check that any further reads, such as this read of one byte, read no @@ -532,7 +530,7 @@ where /// /// Use [`ReadXdR: Read_xdr_into_to_end`] when the intent is for all bytes /// in the read implementation to be consumed by the read. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr_into(&mut self, r: &mut Limited) -> Result<()> { *self = Self::read_xdr(r)?; Ok(()) @@ -556,7 +554,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr_into_to_end(&mut self, r: &mut Limited) -> Result<()> { Self::read_xdr_into(self, r)?; // Check that any further reads, such as this read of one byte, read no @@ -605,7 +603,7 @@ where /// /// An error is returned if the bytes are not completely consumed by the /// deserialization. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn from_xdr(bytes: impl AsRef<[u8]>, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(&mut cursor)?; @@ -629,10 +627,10 @@ where } pub trait WriteXdr { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()>; - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn to_xdr(&self, limits: Limits) -> Result> { let mut cursor = Limited::new(Cursor::new(vec![]), limits); self.write_xdr(&mut cursor)?; @@ -654,13 +652,13 @@ pub trait WriteXdr { /// `Pad_len` returns the number of bytes to pad an XDR value of the given /// length to make the final serialized size a multiple of 4. -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] fn pad_len(len: usize) -> usize { (4 - (len % 4)) % 4 } impl ReadXdr for i32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -672,7 +670,7 @@ impl ReadXdr for i32 { } impl WriteXdr for i32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -683,7 +681,7 @@ impl WriteXdr for i32 { } impl ReadXdr for u32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -695,7 +693,7 @@ impl ReadXdr for u32 { } impl WriteXdr for u32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -706,7 +704,7 @@ impl WriteXdr for u32 { } impl ReadXdr for i64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -718,7 +716,7 @@ impl ReadXdr for i64 { } impl WriteXdr for i64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -729,7 +727,7 @@ impl WriteXdr for i64 { } impl ReadXdr for u64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -741,7 +739,7 @@ impl ReadXdr for u64 { } impl WriteXdr for u64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -752,35 +750,35 @@ impl WriteXdr for u64 { } impl ReadXdr for f32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for f64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for bool { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -791,7 +789,7 @@ impl ReadXdr for bool { } impl WriteXdr for bool { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i = u32::from(*self); // true = 1, false = 0 @@ -801,7 +799,7 @@ impl WriteXdr for bool { } impl ReadXdr for Option { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -818,7 +816,7 @@ impl ReadXdr for Option { } impl WriteXdr for Option { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { if let Some(t) = self { @@ -833,35 +831,35 @@ impl WriteXdr for Option { } impl ReadXdr for Box { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| Ok(Box::new(T::read_xdr(r)?))) } } impl WriteXdr for Box { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| T::write_xdr(self, w)) } } impl ReadXdr for () { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(_r: &mut Limited) -> Result { Ok(()) } } impl WriteXdr for () { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { Ok(()) } } impl ReadXdr for [u8; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { r.consume_len(N)?; @@ -880,7 +878,7 @@ impl ReadXdr for [u8; N] { } impl WriteXdr for [u8; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { w.consume_len(N)?; @@ -894,7 +892,7 @@ impl WriteXdr for [u8; N] { } impl ReadXdr for [T; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let mut vec = Vec::with_capacity(N); @@ -909,7 +907,7 @@ impl ReadXdr for [T; N] { } impl WriteXdr for [T; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { for t in self { @@ -1268,7 +1266,7 @@ impl<'a, const MAX: u32> TryFrom<&'a VecM> for &'a str { } impl ReadXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1295,7 +1293,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1315,7 +1313,7 @@ impl WriteXdr for VecM { } impl ReadXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len = u32::read_xdr(r)?; @@ -1335,7 +1333,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1708,7 +1706,7 @@ impl<'a, const MAX: u32> TryFrom<&'a BytesM> for &'a str { } impl ReadXdr for BytesM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1735,7 +1733,7 @@ impl ReadXdr for BytesM { } impl WriteXdr for BytesM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2111,7 +2109,7 @@ impl<'a, const MAX: u32> TryFrom<&'a StringM> for &'a str { } impl ReadXdr for StringM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -2138,7 +2136,7 @@ impl ReadXdr for StringM { } impl WriteXdr for StringM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2184,7 +2182,7 @@ impl ReadXdr for Frame where T: ReadXdr, { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { // Read the frame header value that contains 1 flag-bit and a 33-bit length. // - The 1 flag bit is 0 when there are more frames for the same record. @@ -2204,7 +2202,7 @@ where } } -#[cfg(all(test, feature = "alloc"))] +#[cfg(all(test, any(feature = "std", feature = "embedded_io")))] mod tests { use super::*; @@ -2314,7 +2312,7 @@ mod tests { } } -#[cfg(all(test, feature = "alloc"))] +#[cfg(all(test, any(feature = "std", feature = "embedded_io")))] mod test { use super::*; @@ -2827,6 +2825,219 @@ mod test { } } +#[cfg(all(test, any(feature = "std", feature = "embedded_io")))] +mod test_io { + // We will use different IO libraries according to the feature, + // we hope the selected IO library can work as expected + + use super::*; + + #[test] + fn test_read_exact_success() { + let data = b"The quick brown fox jumps over the lazy dog."; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 19]; // Exactly the length of "The quick brown fox" + + // Attempt to read exactly 19 bytes + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"The quick brown fox"); + assert_eq!(cursor.position(), 19); + } + + #[test] + fn test_read_exact_less_than_available() { + let data = b"Hello, Rust!"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 5]; + + // Attempt to read 5 bytes from the start + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Hello"); + assert_eq!(cursor.position(), 5); + } + + #[test] + fn test_read_exact_exact_eof() { + let data = b"Data"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 4]; + + // Attempt to read exactly 4 bytes, which is the entire buffer + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Data"); + assert_eq!(cursor.position(), 4); + + // Further attempt to read should fail with EOF + let mut buffer_eof = [0u8; 1]; + let result = cursor.read_exact(&mut buffer_eof); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 4); // Position should remain at EOF + } + + #[test] + fn test_read_exact_past_eof() { + let data = b"Short"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 10]; // Requesting more bytes than available + + // Attempt to read 10 bytes from a 5-byte buffer + let result = cursor.read_exact(&mut buffer); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 5); // Position should move to EOF + } + + #[test] + fn test_read_exact_empty_buffer() { + let data = b"Non-empty"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 0]; // Zero-length buffer + + // Attempt to read zero bytes + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(cursor.position(), 0); // Position should remain unchanged + } + + #[test] + fn test_read_exact_from_empty_cursor() { + let data: &[u8] = b""; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 5]; + + // Attempt to read from an empty cursor + let result = cursor.read_exact(&mut buffer); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 0); // Position remains at 0 + } + + #[test] + fn test_read_exact_multiple_reads() { + let data = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + let mut cursor = Cursor::new(data); + + let mut buffer1 = [0u8; 10]; + let mut buffer2 = [0u8; 10]; + let mut buffer3 = [0u8; 10]; // Only 6 bytes left + + // First read: 10 bytes + assert!(cursor.read_exact(&mut buffer1).is_ok()); + assert_eq!(&buffer1, b"ABCDEFGHIJ"); + assert_eq!(cursor.position(), 10); + + // Second read: 10 bytes + assert!(cursor.read_exact(&mut buffer2).is_ok()); + assert_eq!(&buffer2, b"KLMNOPQRST"); + assert_eq!(cursor.position(), 20); + + // Third read: Attempt to read 10 bytes, but only 6 are available + let result = cursor.read_exact(&mut buffer3); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + // read_exact makes no promises about the content of the buffer on error + // assert_eq!(&buffer3[..6], b"UVWXYZ"); + assert_eq!(cursor.position(), 26); // Position should be at EOF + } + + #[test] + fn test_cursor_read_exact_after_eof() { + let data = b"End"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 3]; + + // First read: read the entire buffer + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"End"); + assert_eq!(cursor.position(), 3); + + // Second read: attempt to read again, should fail + let mut buffer_eof = [0u8; 1]; + let result = cursor.read_exact(&mut buffer_eof); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 3); // Position remains at EOF + } + + #[test] + fn test_slice_read_exact_success() { + let data = b"SliceReadTest"; + let mut slice = &data[..]; + let mut buffer = [0u8; 13]; // Exact length + + // Using Read trait directly on slice + assert!(slice.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"SliceReadTest"); + } + + #[test] + fn test_slice_read_exact_partial() { + let data = b"SlicePartial"; + let mut slice = &data[..]; + let mut buffer = [0u8; 20]; // Request more bytes than available + + // Using Read trait directly on slice + let result = slice.read_exact(&mut buffer); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + // read_exact makes no promises about the content of the buffer on error + } +} + /// SError is an XDR Typedef defines as: /// /// ```text @@ -2925,7 +3136,7 @@ Self::Multi => "Multi", } impl ReadXdr for UnionKey { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let e = i32::read_xdr(r)?; @@ -2936,7 +3147,7 @@ Self::Multi => "Multi", } impl WriteXdr for UnionKey { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i: i32 = (*self).into(); @@ -3025,7 +3236,7 @@ Self::Multi(_) => UnionKey::Multi, impl Union for MyUnion {} impl ReadXdr for MyUnion { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let dv: UnionKey = ::read_xdr(r)?; @@ -3042,7 +3253,7 @@ UnionKey::Multi => Self::Multi(VecM::::read_xdr(r)?), } impl WriteXdr for MyUnion { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { self.discriminant().write_xdr(w)?; @@ -3136,7 +3347,7 @@ Self::V1(_) => 1, impl Union for IntUnion {} impl ReadXdr for IntUnion { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let dv: i32 = ::read_xdr(r)?; @@ -3153,7 +3364,7 @@ Self::V1(_) => 1, } impl WriteXdr for IntUnion { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { self.discriminant().write_xdr(w)?; @@ -3202,7 +3413,7 @@ impl AsRef for IntUnion2 { } impl ReadXdr for IntUnion2 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = IntUnion::read_xdr(r)?; @@ -3213,7 +3424,7 @@ impl ReadXdr for IntUnion2 { } impl WriteXdr for IntUnion2 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w|{ self.0.write_xdr(w) }) } @@ -3343,7 +3554,7 @@ TypeVariant::IntUnion2, ]; "IntUnion", "IntUnion2", ]; - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] #[allow(clippy::too_many_lines)] pub fn read_xdr(v: TypeVariant, r: &mut Limited) -> Result { match v { @@ -3363,7 +3574,7 @@ TypeVariant::IntUnion2 => r.with_limited_depth(|r| Ok(Self::IntUnion2(Box::new(I Ok(t) } - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] pub fn read_xdr_to_end(v: TypeVariant, r: &mut Limited) -> Result { let s = Self::read_xdr(v, r)?; // Check that any further reads, such as this read of one byte, read no @@ -3422,7 +3633,7 @@ TypeVariant::IntUnion2 => Box::new(ReadXdrIter::<_, IntUnion2>::new(dec, r.limit } } - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] pub fn from_xdr>(v: TypeVariant, bytes: B, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(v, &mut cursor)?; @@ -3531,7 +3742,7 @@ Self::IntUnion2(_) => TypeVariant::IntUnion2, } impl WriteXdr for Type { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] #[allow(clippy::too_many_lines)] fn write_xdr(&self, w: &mut Limited) -> Result<()> { match self { diff --git a/spec/output/generator_spec_rust_custom_str_impls/block_comments.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_str_impls/block_comments.x/MyXDR.rs index 925e06c32..b219d1dd8 100644 --- a/spec/output/generator_spec_rust_custom_str_impls/block_comments.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_str_impls/block_comments.x/MyXDR.rs @@ -50,7 +50,7 @@ use std::{ io::{BufRead, BufReader, Cursor, Read, Write}, }; -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] use embedded_io_extras::{Cursor, Error as _, ErrorType, Read, Write}; /// Error contains all errors returned by functions in this crate. It can be @@ -68,7 +68,7 @@ pub enum Error { InvalidHex, #[cfg(feature = "std")] Io(io::Error), - #[cfg(all(not(feature = "std"), feature = "alloc"))] + #[cfg(feature = "embedded_io")] Io(embedded_io_extras::ErrorKind), DepthLimitExceeded, #[cfg(feature = "serde_json")] @@ -86,15 +86,14 @@ impl PartialEq for Error { // case for comparing errors outputted by the XDR library is for // error case testing, and a lack of the ability to compare has a // detrimental affect on failure testing, so this is a tradeoff. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] (Self::Io(l), Self::Io(r)) => l.kind() == r.kind(), _ => core::mem::discriminant(self) == core::mem::discriminant(other), } } } - -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl embedded_io_extras::Error for Error { fn kind(&self) -> embedded_io_extras::ErrorKind { match self { @@ -104,7 +103,7 @@ impl embedded_io_extras::Error for Error { } } -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl From> for Error { fn from(value: embedded_io_extras::ReadExactError) -> Self { match value { @@ -140,7 +139,7 @@ impl fmt::Display for Error { Error::InvalidHex => write!(f, "hex invalid"), #[cfg(feature = "std")] Error::Io(e) => write!(f, "{e}"), - #[cfg(all(not(feature = "std"), feature = "alloc"))] + #[cfg(feature = "embedded_io")] Error::Io(_) => write!(f, "io error"), Error::DepthLimitExceeded => write!(f, "depth limit exceeded"), #[cfg(feature = "serde_json")] @@ -194,7 +193,7 @@ impl From for () { #[allow(dead_code)] type Result = core::result::Result; -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl ErrorType for Limited { type Error = Error; } /// Name defines types that assign a static name to their value, such as the @@ -230,7 +229,7 @@ where /// `Limits` contains the limits that a limited reader or writer will be /// constrained to. -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] #[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct Limits { /// Defines the maximum depth for recursive calls in `Read/WriteXdr` to @@ -247,7 +246,7 @@ pub struct Limits { pub len: usize, } -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] impl Limits { #[must_use] pub fn none() -> Self { @@ -278,13 +277,13 @@ impl Limits { /// /// Intended for use with readers and writers and limiting their reads and /// writes. -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] pub struct Limited { pub inner: L, pub(crate) limits: Limits, } -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] impl Limited { /// Constructs a new `Limited`. /// @@ -337,8 +336,7 @@ impl Read for Limited { } } - -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl Read for Limited { /// Forwards the read operation to the wrapped object. fn read(&mut self, buf: &mut [u8]) -> core::result::Result { @@ -372,7 +370,7 @@ impl Write for Limited { } } -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl Write for Limited { /// Forwards the write operation to the wrapped object. fn write(&mut self, buf: &[u8]) -> core::result::Result { @@ -457,7 +455,7 @@ where /// /// Use [`ReadXdR: Read_xdr_to_end`] when the intent is for all bytes in the /// read implementation to be consumed by the read. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result; /// Construct the type from the XDR bytes base64 encoded. @@ -492,7 +490,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr_to_end(r: &mut Limited) -> Result { let s = Self::read_xdr(r)?; // Check that any further reads, such as this read of one byte, read no @@ -532,7 +530,7 @@ where /// /// Use [`ReadXdR: Read_xdr_into_to_end`] when the intent is for all bytes /// in the read implementation to be consumed by the read. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr_into(&mut self, r: &mut Limited) -> Result<()> { *self = Self::read_xdr(r)?; Ok(()) @@ -556,7 +554,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr_into_to_end(&mut self, r: &mut Limited) -> Result<()> { Self::read_xdr_into(self, r)?; // Check that any further reads, such as this read of one byte, read no @@ -605,7 +603,7 @@ where /// /// An error is returned if the bytes are not completely consumed by the /// deserialization. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn from_xdr(bytes: impl AsRef<[u8]>, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(&mut cursor)?; @@ -629,10 +627,10 @@ where } pub trait WriteXdr { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()>; - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn to_xdr(&self, limits: Limits) -> Result> { let mut cursor = Limited::new(Cursor::new(vec![]), limits); self.write_xdr(&mut cursor)?; @@ -654,13 +652,13 @@ pub trait WriteXdr { /// `Pad_len` returns the number of bytes to pad an XDR value of the given /// length to make the final serialized size a multiple of 4. -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] fn pad_len(len: usize) -> usize { (4 - (len % 4)) % 4 } impl ReadXdr for i32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -672,7 +670,7 @@ impl ReadXdr for i32 { } impl WriteXdr for i32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -683,7 +681,7 @@ impl WriteXdr for i32 { } impl ReadXdr for u32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -695,7 +693,7 @@ impl ReadXdr for u32 { } impl WriteXdr for u32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -706,7 +704,7 @@ impl WriteXdr for u32 { } impl ReadXdr for i64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -718,7 +716,7 @@ impl ReadXdr for i64 { } impl WriteXdr for i64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -729,7 +727,7 @@ impl WriteXdr for i64 { } impl ReadXdr for u64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -741,7 +739,7 @@ impl ReadXdr for u64 { } impl WriteXdr for u64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -752,35 +750,35 @@ impl WriteXdr for u64 { } impl ReadXdr for f32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for f64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for bool { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -791,7 +789,7 @@ impl ReadXdr for bool { } impl WriteXdr for bool { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i = u32::from(*self); // true = 1, false = 0 @@ -801,7 +799,7 @@ impl WriteXdr for bool { } impl ReadXdr for Option { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -818,7 +816,7 @@ impl ReadXdr for Option { } impl WriteXdr for Option { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { if let Some(t) = self { @@ -833,35 +831,35 @@ impl WriteXdr for Option { } impl ReadXdr for Box { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| Ok(Box::new(T::read_xdr(r)?))) } } impl WriteXdr for Box { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| T::write_xdr(self, w)) } } impl ReadXdr for () { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(_r: &mut Limited) -> Result { Ok(()) } } impl WriteXdr for () { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { Ok(()) } } impl ReadXdr for [u8; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { r.consume_len(N)?; @@ -880,7 +878,7 @@ impl ReadXdr for [u8; N] { } impl WriteXdr for [u8; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { w.consume_len(N)?; @@ -894,7 +892,7 @@ impl WriteXdr for [u8; N] { } impl ReadXdr for [T; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let mut vec = Vec::with_capacity(N); @@ -909,7 +907,7 @@ impl ReadXdr for [T; N] { } impl WriteXdr for [T; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { for t in self { @@ -1268,7 +1266,7 @@ impl<'a, const MAX: u32> TryFrom<&'a VecM> for &'a str { } impl ReadXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1295,7 +1293,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1315,7 +1313,7 @@ impl WriteXdr for VecM { } impl ReadXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len = u32::read_xdr(r)?; @@ -1335,7 +1333,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1708,7 +1706,7 @@ impl<'a, const MAX: u32> TryFrom<&'a BytesM> for &'a str { } impl ReadXdr for BytesM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1735,7 +1733,7 @@ impl ReadXdr for BytesM { } impl WriteXdr for BytesM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2111,7 +2109,7 @@ impl<'a, const MAX: u32> TryFrom<&'a StringM> for &'a str { } impl ReadXdr for StringM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -2138,7 +2136,7 @@ impl ReadXdr for StringM { } impl WriteXdr for StringM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2184,7 +2182,7 @@ impl ReadXdr for Frame where T: ReadXdr, { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { // Read the frame header value that contains 1 flag-bit and a 33-bit length. // - The 1 flag bit is 0 when there are more frames for the same record. @@ -2204,7 +2202,7 @@ where } } -#[cfg(all(test, feature = "alloc"))] +#[cfg(all(test, any(feature = "std", feature = "embedded_io")))] mod tests { use super::*; @@ -2314,7 +2312,7 @@ mod tests { } } -#[cfg(all(test, feature = "alloc"))] +#[cfg(all(test, any(feature = "std", feature = "embedded_io")))] mod test { use super::*; @@ -2827,6 +2825,219 @@ mod test { } } +#[cfg(all(test, any(feature = "std", feature = "embedded_io")))] +mod test_io { + // We will use different IO libraries according to the feature, + // we hope the selected IO library can work as expected + + use super::*; + + #[test] + fn test_read_exact_success() { + let data = b"The quick brown fox jumps over the lazy dog."; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 19]; // Exactly the length of "The quick brown fox" + + // Attempt to read exactly 19 bytes + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"The quick brown fox"); + assert_eq!(cursor.position(), 19); + } + + #[test] + fn test_read_exact_less_than_available() { + let data = b"Hello, Rust!"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 5]; + + // Attempt to read 5 bytes from the start + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Hello"); + assert_eq!(cursor.position(), 5); + } + + #[test] + fn test_read_exact_exact_eof() { + let data = b"Data"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 4]; + + // Attempt to read exactly 4 bytes, which is the entire buffer + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Data"); + assert_eq!(cursor.position(), 4); + + // Further attempt to read should fail with EOF + let mut buffer_eof = [0u8; 1]; + let result = cursor.read_exact(&mut buffer_eof); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 4); // Position should remain at EOF + } + + #[test] + fn test_read_exact_past_eof() { + let data = b"Short"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 10]; // Requesting more bytes than available + + // Attempt to read 10 bytes from a 5-byte buffer + let result = cursor.read_exact(&mut buffer); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 5); // Position should move to EOF + } + + #[test] + fn test_read_exact_empty_buffer() { + let data = b"Non-empty"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 0]; // Zero-length buffer + + // Attempt to read zero bytes + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(cursor.position(), 0); // Position should remain unchanged + } + + #[test] + fn test_read_exact_from_empty_cursor() { + let data: &[u8] = b""; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 5]; + + // Attempt to read from an empty cursor + let result = cursor.read_exact(&mut buffer); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 0); // Position remains at 0 + } + + #[test] + fn test_read_exact_multiple_reads() { + let data = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + let mut cursor = Cursor::new(data); + + let mut buffer1 = [0u8; 10]; + let mut buffer2 = [0u8; 10]; + let mut buffer3 = [0u8; 10]; // Only 6 bytes left + + // First read: 10 bytes + assert!(cursor.read_exact(&mut buffer1).is_ok()); + assert_eq!(&buffer1, b"ABCDEFGHIJ"); + assert_eq!(cursor.position(), 10); + + // Second read: 10 bytes + assert!(cursor.read_exact(&mut buffer2).is_ok()); + assert_eq!(&buffer2, b"KLMNOPQRST"); + assert_eq!(cursor.position(), 20); + + // Third read: Attempt to read 10 bytes, but only 6 are available + let result = cursor.read_exact(&mut buffer3); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + // read_exact makes no promises about the content of the buffer on error + // assert_eq!(&buffer3[..6], b"UVWXYZ"); + assert_eq!(cursor.position(), 26); // Position should be at EOF + } + + #[test] + fn test_cursor_read_exact_after_eof() { + let data = b"End"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 3]; + + // First read: read the entire buffer + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"End"); + assert_eq!(cursor.position(), 3); + + // Second read: attempt to read again, should fail + let mut buffer_eof = [0u8; 1]; + let result = cursor.read_exact(&mut buffer_eof); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 3); // Position remains at EOF + } + + #[test] + fn test_slice_read_exact_success() { + let data = b"SliceReadTest"; + let mut slice = &data[..]; + let mut buffer = [0u8; 13]; // Exact length + + // Using Read trait directly on slice + assert!(slice.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"SliceReadTest"); + } + + #[test] + fn test_slice_read_exact_partial() { + let data = b"SlicePartial"; + let mut slice = &data[..]; + let mut buffer = [0u8; 20]; // Request more bytes than available + + // Using Read trait directly on slice + let result = slice.read_exact(&mut buffer); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + // read_exact makes no promises about the content of the buffer on error + } +} + /// AccountFlags is an XDR Enum defines as: /// /// ```text @@ -2905,7 +3116,7 @@ impl From for i32 { } impl ReadXdr for AccountFlags { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let e = i32::read_xdr(r)?; @@ -2916,7 +3127,7 @@ impl ReadXdr for AccountFlags { } impl WriteXdr for AccountFlags { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i: i32 = (*self).into(); @@ -3004,7 +3215,7 @@ impl Type { pub const VARIANTS: [TypeVariant; 1] = [ TypeVariant::AccountFlags, ]; pub const VARIANTS_STR: [&'static str; 1] = [ "AccountFlags", ]; - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] #[allow(clippy::too_many_lines)] pub fn read_xdr(v: TypeVariant, r: &mut Limited) -> Result { match v { @@ -3019,7 +3230,7 @@ impl Type { Ok(t) } - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] pub fn read_xdr_to_end(v: TypeVariant, r: &mut Limited) -> Result { let s = Self::read_xdr(v, r)?; // Check that any further reads, such as this read of one byte, read no @@ -3063,7 +3274,7 @@ impl Type { } } - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] pub fn from_xdr>(v: TypeVariant, bytes: B, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(v, &mut cursor)?; @@ -3147,7 +3358,7 @@ impl Variants for Type { } impl WriteXdr for Type { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] #[allow(clippy::too_many_lines)] fn write_xdr(&self, w: &mut Limited) -> Result<()> { match self { diff --git a/spec/output/generator_spec_rust_custom_str_impls/const.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_str_impls/const.x/MyXDR.rs index 735e0265e..fbe2a13d8 100644 --- a/spec/output/generator_spec_rust_custom_str_impls/const.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_str_impls/const.x/MyXDR.rs @@ -50,7 +50,7 @@ use std::{ io::{BufRead, BufReader, Cursor, Read, Write}, }; -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] use embedded_io_extras::{Cursor, Error as _, ErrorType, Read, Write}; /// Error contains all errors returned by functions in this crate. It can be @@ -68,7 +68,7 @@ pub enum Error { InvalidHex, #[cfg(feature = "std")] Io(io::Error), - #[cfg(all(not(feature = "std"), feature = "alloc"))] + #[cfg(feature = "embedded_io")] Io(embedded_io_extras::ErrorKind), DepthLimitExceeded, #[cfg(feature = "serde_json")] @@ -86,15 +86,14 @@ impl PartialEq for Error { // case for comparing errors outputted by the XDR library is for // error case testing, and a lack of the ability to compare has a // detrimental affect on failure testing, so this is a tradeoff. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] (Self::Io(l), Self::Io(r)) => l.kind() == r.kind(), _ => core::mem::discriminant(self) == core::mem::discriminant(other), } } } - -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl embedded_io_extras::Error for Error { fn kind(&self) -> embedded_io_extras::ErrorKind { match self { @@ -104,7 +103,7 @@ impl embedded_io_extras::Error for Error { } } -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl From> for Error { fn from(value: embedded_io_extras::ReadExactError) -> Self { match value { @@ -140,7 +139,7 @@ impl fmt::Display for Error { Error::InvalidHex => write!(f, "hex invalid"), #[cfg(feature = "std")] Error::Io(e) => write!(f, "{e}"), - #[cfg(all(not(feature = "std"), feature = "alloc"))] + #[cfg(feature = "embedded_io")] Error::Io(_) => write!(f, "io error"), Error::DepthLimitExceeded => write!(f, "depth limit exceeded"), #[cfg(feature = "serde_json")] @@ -194,7 +193,7 @@ impl From for () { #[allow(dead_code)] type Result = core::result::Result; -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl ErrorType for Limited { type Error = Error; } /// Name defines types that assign a static name to their value, such as the @@ -230,7 +229,7 @@ where /// `Limits` contains the limits that a limited reader or writer will be /// constrained to. -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] #[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct Limits { /// Defines the maximum depth for recursive calls in `Read/WriteXdr` to @@ -247,7 +246,7 @@ pub struct Limits { pub len: usize, } -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] impl Limits { #[must_use] pub fn none() -> Self { @@ -278,13 +277,13 @@ impl Limits { /// /// Intended for use with readers and writers and limiting their reads and /// writes. -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] pub struct Limited { pub inner: L, pub(crate) limits: Limits, } -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] impl Limited { /// Constructs a new `Limited`. /// @@ -337,8 +336,7 @@ impl Read for Limited { } } - -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl Read for Limited { /// Forwards the read operation to the wrapped object. fn read(&mut self, buf: &mut [u8]) -> core::result::Result { @@ -372,7 +370,7 @@ impl Write for Limited { } } -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl Write for Limited { /// Forwards the write operation to the wrapped object. fn write(&mut self, buf: &[u8]) -> core::result::Result { @@ -457,7 +455,7 @@ where /// /// Use [`ReadXdR: Read_xdr_to_end`] when the intent is for all bytes in the /// read implementation to be consumed by the read. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result; /// Construct the type from the XDR bytes base64 encoded. @@ -492,7 +490,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr_to_end(r: &mut Limited) -> Result { let s = Self::read_xdr(r)?; // Check that any further reads, such as this read of one byte, read no @@ -532,7 +530,7 @@ where /// /// Use [`ReadXdR: Read_xdr_into_to_end`] when the intent is for all bytes /// in the read implementation to be consumed by the read. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr_into(&mut self, r: &mut Limited) -> Result<()> { *self = Self::read_xdr(r)?; Ok(()) @@ -556,7 +554,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr_into_to_end(&mut self, r: &mut Limited) -> Result<()> { Self::read_xdr_into(self, r)?; // Check that any further reads, such as this read of one byte, read no @@ -605,7 +603,7 @@ where /// /// An error is returned if the bytes are not completely consumed by the /// deserialization. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn from_xdr(bytes: impl AsRef<[u8]>, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(&mut cursor)?; @@ -629,10 +627,10 @@ where } pub trait WriteXdr { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()>; - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn to_xdr(&self, limits: Limits) -> Result> { let mut cursor = Limited::new(Cursor::new(vec![]), limits); self.write_xdr(&mut cursor)?; @@ -654,13 +652,13 @@ pub trait WriteXdr { /// `Pad_len` returns the number of bytes to pad an XDR value of the given /// length to make the final serialized size a multiple of 4. -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] fn pad_len(len: usize) -> usize { (4 - (len % 4)) % 4 } impl ReadXdr for i32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -672,7 +670,7 @@ impl ReadXdr for i32 { } impl WriteXdr for i32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -683,7 +681,7 @@ impl WriteXdr for i32 { } impl ReadXdr for u32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -695,7 +693,7 @@ impl ReadXdr for u32 { } impl WriteXdr for u32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -706,7 +704,7 @@ impl WriteXdr for u32 { } impl ReadXdr for i64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -718,7 +716,7 @@ impl ReadXdr for i64 { } impl WriteXdr for i64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -729,7 +727,7 @@ impl WriteXdr for i64 { } impl ReadXdr for u64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -741,7 +739,7 @@ impl ReadXdr for u64 { } impl WriteXdr for u64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -752,35 +750,35 @@ impl WriteXdr for u64 { } impl ReadXdr for f32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for f64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for bool { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -791,7 +789,7 @@ impl ReadXdr for bool { } impl WriteXdr for bool { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i = u32::from(*self); // true = 1, false = 0 @@ -801,7 +799,7 @@ impl WriteXdr for bool { } impl ReadXdr for Option { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -818,7 +816,7 @@ impl ReadXdr for Option { } impl WriteXdr for Option { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { if let Some(t) = self { @@ -833,35 +831,35 @@ impl WriteXdr for Option { } impl ReadXdr for Box { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| Ok(Box::new(T::read_xdr(r)?))) } } impl WriteXdr for Box { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| T::write_xdr(self, w)) } } impl ReadXdr for () { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(_r: &mut Limited) -> Result { Ok(()) } } impl WriteXdr for () { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { Ok(()) } } impl ReadXdr for [u8; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { r.consume_len(N)?; @@ -880,7 +878,7 @@ impl ReadXdr for [u8; N] { } impl WriteXdr for [u8; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { w.consume_len(N)?; @@ -894,7 +892,7 @@ impl WriteXdr for [u8; N] { } impl ReadXdr for [T; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let mut vec = Vec::with_capacity(N); @@ -909,7 +907,7 @@ impl ReadXdr for [T; N] { } impl WriteXdr for [T; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { for t in self { @@ -1268,7 +1266,7 @@ impl<'a, const MAX: u32> TryFrom<&'a VecM> for &'a str { } impl ReadXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1295,7 +1293,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1315,7 +1313,7 @@ impl WriteXdr for VecM { } impl ReadXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len = u32::read_xdr(r)?; @@ -1335,7 +1333,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1708,7 +1706,7 @@ impl<'a, const MAX: u32> TryFrom<&'a BytesM> for &'a str { } impl ReadXdr for BytesM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1735,7 +1733,7 @@ impl ReadXdr for BytesM { } impl WriteXdr for BytesM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2111,7 +2109,7 @@ impl<'a, const MAX: u32> TryFrom<&'a StringM> for &'a str { } impl ReadXdr for StringM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -2138,7 +2136,7 @@ impl ReadXdr for StringM { } impl WriteXdr for StringM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2184,7 +2182,7 @@ impl ReadXdr for Frame where T: ReadXdr, { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { // Read the frame header value that contains 1 flag-bit and a 33-bit length. // - The 1 flag bit is 0 when there are more frames for the same record. @@ -2204,7 +2202,7 @@ where } } -#[cfg(all(test, feature = "alloc"))] +#[cfg(all(test, any(feature = "std", feature = "embedded_io")))] mod tests { use super::*; @@ -2314,7 +2312,7 @@ mod tests { } } -#[cfg(all(test, feature = "alloc"))] +#[cfg(all(test, any(feature = "std", feature = "embedded_io")))] mod test { use super::*; @@ -2827,6 +2825,219 @@ mod test { } } +#[cfg(all(test, any(feature = "std", feature = "embedded_io")))] +mod test_io { + // We will use different IO libraries according to the feature, + // we hope the selected IO library can work as expected + + use super::*; + + #[test] + fn test_read_exact_success() { + let data = b"The quick brown fox jumps over the lazy dog."; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 19]; // Exactly the length of "The quick brown fox" + + // Attempt to read exactly 19 bytes + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"The quick brown fox"); + assert_eq!(cursor.position(), 19); + } + + #[test] + fn test_read_exact_less_than_available() { + let data = b"Hello, Rust!"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 5]; + + // Attempt to read 5 bytes from the start + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Hello"); + assert_eq!(cursor.position(), 5); + } + + #[test] + fn test_read_exact_exact_eof() { + let data = b"Data"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 4]; + + // Attempt to read exactly 4 bytes, which is the entire buffer + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Data"); + assert_eq!(cursor.position(), 4); + + // Further attempt to read should fail with EOF + let mut buffer_eof = [0u8; 1]; + let result = cursor.read_exact(&mut buffer_eof); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 4); // Position should remain at EOF + } + + #[test] + fn test_read_exact_past_eof() { + let data = b"Short"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 10]; // Requesting more bytes than available + + // Attempt to read 10 bytes from a 5-byte buffer + let result = cursor.read_exact(&mut buffer); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 5); // Position should move to EOF + } + + #[test] + fn test_read_exact_empty_buffer() { + let data = b"Non-empty"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 0]; // Zero-length buffer + + // Attempt to read zero bytes + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(cursor.position(), 0); // Position should remain unchanged + } + + #[test] + fn test_read_exact_from_empty_cursor() { + let data: &[u8] = b""; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 5]; + + // Attempt to read from an empty cursor + let result = cursor.read_exact(&mut buffer); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 0); // Position remains at 0 + } + + #[test] + fn test_read_exact_multiple_reads() { + let data = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + let mut cursor = Cursor::new(data); + + let mut buffer1 = [0u8; 10]; + let mut buffer2 = [0u8; 10]; + let mut buffer3 = [0u8; 10]; // Only 6 bytes left + + // First read: 10 bytes + assert!(cursor.read_exact(&mut buffer1).is_ok()); + assert_eq!(&buffer1, b"ABCDEFGHIJ"); + assert_eq!(cursor.position(), 10); + + // Second read: 10 bytes + assert!(cursor.read_exact(&mut buffer2).is_ok()); + assert_eq!(&buffer2, b"KLMNOPQRST"); + assert_eq!(cursor.position(), 20); + + // Third read: Attempt to read 10 bytes, but only 6 are available + let result = cursor.read_exact(&mut buffer3); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + // read_exact makes no promises about the content of the buffer on error + // assert_eq!(&buffer3[..6], b"UVWXYZ"); + assert_eq!(cursor.position(), 26); // Position should be at EOF + } + + #[test] + fn test_cursor_read_exact_after_eof() { + let data = b"End"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 3]; + + // First read: read the entire buffer + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"End"); + assert_eq!(cursor.position(), 3); + + // Second read: attempt to read again, should fail + let mut buffer_eof = [0u8; 1]; + let result = cursor.read_exact(&mut buffer_eof); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 3); // Position remains at EOF + } + + #[test] + fn test_slice_read_exact_success() { + let data = b"SliceReadTest"; + let mut slice = &data[..]; + let mut buffer = [0u8; 13]; // Exact length + + // Using Read trait directly on slice + assert!(slice.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"SliceReadTest"); + } + + #[test] + fn test_slice_read_exact_partial() { + let data = b"SlicePartial"; + let mut slice = &data[..]; + let mut buffer = [0u8; 20]; // Request more bytes than available + + // Using Read trait directly on slice + let result = slice.read_exact(&mut buffer); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + // read_exact makes no promises about the content of the buffer on error + } +} + /// Foo is an XDR Const defines as: /// /// ```text @@ -2939,7 +3150,7 @@ TypeVariant::TestArray2, ]; pub const VARIANTS_STR: [&'static str; 2] = [ "TestArray", "TestArray2", ]; - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] #[allow(clippy::too_many_lines)] pub fn read_xdr(v: TypeVariant, r: &mut Limited) -> Result { match v { @@ -2955,7 +3166,7 @@ TypeVariant::TestArray2 => r.with_limited_depth(|r| Ok(Self::TestArray2(Box::new Ok(t) } - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] pub fn read_xdr_to_end(v: TypeVariant, r: &mut Limited) -> Result { let s = Self::read_xdr(v, r)?; // Check that any further reads, such as this read of one byte, read no @@ -3002,7 +3213,7 @@ TypeVariant::TestArray2 => Box::new(ReadXdrIter::<_, TestArray2>::new(dec, r.lim } } - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] pub fn from_xdr>(v: TypeVariant, bytes: B, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(v, &mut cursor)?; @@ -3091,7 +3302,7 @@ Self::TestArray2(_) => TypeVariant::TestArray2, } impl WriteXdr for Type { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] #[allow(clippy::too_many_lines)] fn write_xdr(&self, w: &mut Limited) -> Result<()> { match self { diff --git a/spec/output/generator_spec_rust_custom_str_impls/enum.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_str_impls/enum.x/MyXDR.rs index 43e09ebca..d2f00861c 100644 --- a/spec/output/generator_spec_rust_custom_str_impls/enum.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_str_impls/enum.x/MyXDR.rs @@ -50,7 +50,7 @@ use std::{ io::{BufRead, BufReader, Cursor, Read, Write}, }; -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] use embedded_io_extras::{Cursor, Error as _, ErrorType, Read, Write}; /// Error contains all errors returned by functions in this crate. It can be @@ -68,7 +68,7 @@ pub enum Error { InvalidHex, #[cfg(feature = "std")] Io(io::Error), - #[cfg(all(not(feature = "std"), feature = "alloc"))] + #[cfg(feature = "embedded_io")] Io(embedded_io_extras::ErrorKind), DepthLimitExceeded, #[cfg(feature = "serde_json")] @@ -86,15 +86,14 @@ impl PartialEq for Error { // case for comparing errors outputted by the XDR library is for // error case testing, and a lack of the ability to compare has a // detrimental affect on failure testing, so this is a tradeoff. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] (Self::Io(l), Self::Io(r)) => l.kind() == r.kind(), _ => core::mem::discriminant(self) == core::mem::discriminant(other), } } } - -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl embedded_io_extras::Error for Error { fn kind(&self) -> embedded_io_extras::ErrorKind { match self { @@ -104,7 +103,7 @@ impl embedded_io_extras::Error for Error { } } -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl From> for Error { fn from(value: embedded_io_extras::ReadExactError) -> Self { match value { @@ -140,7 +139,7 @@ impl fmt::Display for Error { Error::InvalidHex => write!(f, "hex invalid"), #[cfg(feature = "std")] Error::Io(e) => write!(f, "{e}"), - #[cfg(all(not(feature = "std"), feature = "alloc"))] + #[cfg(feature = "embedded_io")] Error::Io(_) => write!(f, "io error"), Error::DepthLimitExceeded => write!(f, "depth limit exceeded"), #[cfg(feature = "serde_json")] @@ -194,7 +193,7 @@ impl From for () { #[allow(dead_code)] type Result = core::result::Result; -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl ErrorType for Limited { type Error = Error; } /// Name defines types that assign a static name to their value, such as the @@ -230,7 +229,7 @@ where /// `Limits` contains the limits that a limited reader or writer will be /// constrained to. -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] #[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct Limits { /// Defines the maximum depth for recursive calls in `Read/WriteXdr` to @@ -247,7 +246,7 @@ pub struct Limits { pub len: usize, } -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] impl Limits { #[must_use] pub fn none() -> Self { @@ -278,13 +277,13 @@ impl Limits { /// /// Intended for use with readers and writers and limiting their reads and /// writes. -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] pub struct Limited { pub inner: L, pub(crate) limits: Limits, } -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] impl Limited { /// Constructs a new `Limited`. /// @@ -337,8 +336,7 @@ impl Read for Limited { } } - -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl Read for Limited { /// Forwards the read operation to the wrapped object. fn read(&mut self, buf: &mut [u8]) -> core::result::Result { @@ -372,7 +370,7 @@ impl Write for Limited { } } -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl Write for Limited { /// Forwards the write operation to the wrapped object. fn write(&mut self, buf: &[u8]) -> core::result::Result { @@ -457,7 +455,7 @@ where /// /// Use [`ReadXdR: Read_xdr_to_end`] when the intent is for all bytes in the /// read implementation to be consumed by the read. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result; /// Construct the type from the XDR bytes base64 encoded. @@ -492,7 +490,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr_to_end(r: &mut Limited) -> Result { let s = Self::read_xdr(r)?; // Check that any further reads, such as this read of one byte, read no @@ -532,7 +530,7 @@ where /// /// Use [`ReadXdR: Read_xdr_into_to_end`] when the intent is for all bytes /// in the read implementation to be consumed by the read. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr_into(&mut self, r: &mut Limited) -> Result<()> { *self = Self::read_xdr(r)?; Ok(()) @@ -556,7 +554,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr_into_to_end(&mut self, r: &mut Limited) -> Result<()> { Self::read_xdr_into(self, r)?; // Check that any further reads, such as this read of one byte, read no @@ -605,7 +603,7 @@ where /// /// An error is returned if the bytes are not completely consumed by the /// deserialization. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn from_xdr(bytes: impl AsRef<[u8]>, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(&mut cursor)?; @@ -629,10 +627,10 @@ where } pub trait WriteXdr { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()>; - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn to_xdr(&self, limits: Limits) -> Result> { let mut cursor = Limited::new(Cursor::new(vec![]), limits); self.write_xdr(&mut cursor)?; @@ -654,13 +652,13 @@ pub trait WriteXdr { /// `Pad_len` returns the number of bytes to pad an XDR value of the given /// length to make the final serialized size a multiple of 4. -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] fn pad_len(len: usize) -> usize { (4 - (len % 4)) % 4 } impl ReadXdr for i32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -672,7 +670,7 @@ impl ReadXdr for i32 { } impl WriteXdr for i32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -683,7 +681,7 @@ impl WriteXdr for i32 { } impl ReadXdr for u32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -695,7 +693,7 @@ impl ReadXdr for u32 { } impl WriteXdr for u32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -706,7 +704,7 @@ impl WriteXdr for u32 { } impl ReadXdr for i64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -718,7 +716,7 @@ impl ReadXdr for i64 { } impl WriteXdr for i64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -729,7 +727,7 @@ impl WriteXdr for i64 { } impl ReadXdr for u64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -741,7 +739,7 @@ impl ReadXdr for u64 { } impl WriteXdr for u64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -752,35 +750,35 @@ impl WriteXdr for u64 { } impl ReadXdr for f32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for f64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for bool { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -791,7 +789,7 @@ impl ReadXdr for bool { } impl WriteXdr for bool { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i = u32::from(*self); // true = 1, false = 0 @@ -801,7 +799,7 @@ impl WriteXdr for bool { } impl ReadXdr for Option { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -818,7 +816,7 @@ impl ReadXdr for Option { } impl WriteXdr for Option { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { if let Some(t) = self { @@ -833,35 +831,35 @@ impl WriteXdr for Option { } impl ReadXdr for Box { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| Ok(Box::new(T::read_xdr(r)?))) } } impl WriteXdr for Box { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| T::write_xdr(self, w)) } } impl ReadXdr for () { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(_r: &mut Limited) -> Result { Ok(()) } } impl WriteXdr for () { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { Ok(()) } } impl ReadXdr for [u8; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { r.consume_len(N)?; @@ -880,7 +878,7 @@ impl ReadXdr for [u8; N] { } impl WriteXdr for [u8; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { w.consume_len(N)?; @@ -894,7 +892,7 @@ impl WriteXdr for [u8; N] { } impl ReadXdr for [T; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let mut vec = Vec::with_capacity(N); @@ -909,7 +907,7 @@ impl ReadXdr for [T; N] { } impl WriteXdr for [T; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { for t in self { @@ -1268,7 +1266,7 @@ impl<'a, const MAX: u32> TryFrom<&'a VecM> for &'a str { } impl ReadXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1295,7 +1293,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1315,7 +1313,7 @@ impl WriteXdr for VecM { } impl ReadXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len = u32::read_xdr(r)?; @@ -1335,7 +1333,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1708,7 +1706,7 @@ impl<'a, const MAX: u32> TryFrom<&'a BytesM> for &'a str { } impl ReadXdr for BytesM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1735,7 +1733,7 @@ impl ReadXdr for BytesM { } impl WriteXdr for BytesM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2111,7 +2109,7 @@ impl<'a, const MAX: u32> TryFrom<&'a StringM> for &'a str { } impl ReadXdr for StringM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -2138,7 +2136,7 @@ impl ReadXdr for StringM { } impl WriteXdr for StringM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2184,7 +2182,7 @@ impl ReadXdr for Frame where T: ReadXdr, { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { // Read the frame header value that contains 1 flag-bit and a 33-bit length. // - The 1 flag bit is 0 when there are more frames for the same record. @@ -2204,7 +2202,7 @@ where } } -#[cfg(all(test, feature = "alloc"))] +#[cfg(all(test, any(feature = "std", feature = "embedded_io")))] mod tests { use super::*; @@ -2314,7 +2312,7 @@ mod tests { } } -#[cfg(all(test, feature = "alloc"))] +#[cfg(all(test, any(feature = "std", feature = "embedded_io")))] mod test { use super::*; @@ -2827,6 +2825,219 @@ mod test { } } +#[cfg(all(test, any(feature = "std", feature = "embedded_io")))] +mod test_io { + // We will use different IO libraries according to the feature, + // we hope the selected IO library can work as expected + + use super::*; + + #[test] + fn test_read_exact_success() { + let data = b"The quick brown fox jumps over the lazy dog."; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 19]; // Exactly the length of "The quick brown fox" + + // Attempt to read exactly 19 bytes + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"The quick brown fox"); + assert_eq!(cursor.position(), 19); + } + + #[test] + fn test_read_exact_less_than_available() { + let data = b"Hello, Rust!"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 5]; + + // Attempt to read 5 bytes from the start + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Hello"); + assert_eq!(cursor.position(), 5); + } + + #[test] + fn test_read_exact_exact_eof() { + let data = b"Data"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 4]; + + // Attempt to read exactly 4 bytes, which is the entire buffer + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Data"); + assert_eq!(cursor.position(), 4); + + // Further attempt to read should fail with EOF + let mut buffer_eof = [0u8; 1]; + let result = cursor.read_exact(&mut buffer_eof); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 4); // Position should remain at EOF + } + + #[test] + fn test_read_exact_past_eof() { + let data = b"Short"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 10]; // Requesting more bytes than available + + // Attempt to read 10 bytes from a 5-byte buffer + let result = cursor.read_exact(&mut buffer); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 5); // Position should move to EOF + } + + #[test] + fn test_read_exact_empty_buffer() { + let data = b"Non-empty"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 0]; // Zero-length buffer + + // Attempt to read zero bytes + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(cursor.position(), 0); // Position should remain unchanged + } + + #[test] + fn test_read_exact_from_empty_cursor() { + let data: &[u8] = b""; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 5]; + + // Attempt to read from an empty cursor + let result = cursor.read_exact(&mut buffer); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 0); // Position remains at 0 + } + + #[test] + fn test_read_exact_multiple_reads() { + let data = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + let mut cursor = Cursor::new(data); + + let mut buffer1 = [0u8; 10]; + let mut buffer2 = [0u8; 10]; + let mut buffer3 = [0u8; 10]; // Only 6 bytes left + + // First read: 10 bytes + assert!(cursor.read_exact(&mut buffer1).is_ok()); + assert_eq!(&buffer1, b"ABCDEFGHIJ"); + assert_eq!(cursor.position(), 10); + + // Second read: 10 bytes + assert!(cursor.read_exact(&mut buffer2).is_ok()); + assert_eq!(&buffer2, b"KLMNOPQRST"); + assert_eq!(cursor.position(), 20); + + // Third read: Attempt to read 10 bytes, but only 6 are available + let result = cursor.read_exact(&mut buffer3); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + // read_exact makes no promises about the content of the buffer on error + // assert_eq!(&buffer3[..6], b"UVWXYZ"); + assert_eq!(cursor.position(), 26); // Position should be at EOF + } + + #[test] + fn test_cursor_read_exact_after_eof() { + let data = b"End"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 3]; + + // First read: read the entire buffer + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"End"); + assert_eq!(cursor.position(), 3); + + // Second read: attempt to read again, should fail + let mut buffer_eof = [0u8; 1]; + let result = cursor.read_exact(&mut buffer_eof); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 3); // Position remains at EOF + } + + #[test] + fn test_slice_read_exact_success() { + let data = b"SliceReadTest"; + let mut slice = &data[..]; + let mut buffer = [0u8; 13]; // Exact length + + // Using Read trait directly on slice + assert!(slice.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"SliceReadTest"); + } + + #[test] + fn test_slice_read_exact_partial() { + let data = b"SlicePartial"; + let mut slice = &data[..]; + let mut buffer = [0u8; 20]; // Request more bytes than available + + // Using Read trait directly on slice + let result = slice.read_exact(&mut buffer); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + // read_exact makes no promises about the content of the buffer on error + } +} + /// MessageType is an XDR Enum defines as: /// /// ```text @@ -2989,7 +3200,7 @@ Self::FbaMessage => "FbaMessage", } impl ReadXdr for MessageType { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let e = i32::read_xdr(r)?; @@ -3000,7 +3211,7 @@ Self::FbaMessage => "FbaMessage", } impl WriteXdr for MessageType { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i: i32 = (*self).into(); @@ -3098,7 +3309,7 @@ Self::Blue => "Blue", } impl ReadXdr for Color { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let e = i32::read_xdr(r)?; @@ -3109,7 +3320,7 @@ Self::Blue => "Blue", } impl WriteXdr for Color { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i: i32 = (*self).into(); @@ -3207,7 +3418,7 @@ Self::Blue2 => "Blue2", } impl ReadXdr for Color2 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let e = i32::read_xdr(r)?; @@ -3218,7 +3429,7 @@ Self::Blue2 => "Blue2", } impl WriteXdr for Color2 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i: i32 = (*self).into(); @@ -3316,7 +3527,7 @@ Self::R3 => "R3", } impl ReadXdr for Color3 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let e = i32::read_xdr(r)?; @@ -3327,7 +3538,7 @@ Self::R3 => "R3", } impl WriteXdr for Color3 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i: i32 = (*self).into(); @@ -3442,7 +3653,7 @@ TypeVariant::Color3, ]; "Color2", "Color3", ]; - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] #[allow(clippy::too_many_lines)] pub fn read_xdr(v: TypeVariant, r: &mut Limited) -> Result { match v { @@ -3460,7 +3671,7 @@ TypeVariant::Color3 => r.with_limited_depth(|r| Ok(Self::Color3(Box::new(Color3: Ok(t) } - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] pub fn read_xdr_to_end(v: TypeVariant, r: &mut Limited) -> Result { let s = Self::read_xdr(v, r)?; // Check that any further reads, such as this read of one byte, read no @@ -3513,7 +3724,7 @@ TypeVariant::Color3 => Box::new(ReadXdrIter::<_, Color3>::new(dec, r.limits.clon } } - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] pub fn from_xdr>(v: TypeVariant, bytes: B, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(v, &mut cursor)?; @@ -3612,7 +3823,7 @@ Self::Color3(_) => TypeVariant::Color3, } impl WriteXdr for Type { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] #[allow(clippy::too_many_lines)] fn write_xdr(&self, w: &mut Limited) -> Result<()> { match self { diff --git a/spec/output/generator_spec_rust_custom_str_impls/nesting.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_str_impls/nesting.x/MyXDR.rs index 5a29f359f..8eacf9b79 100644 --- a/spec/output/generator_spec_rust_custom_str_impls/nesting.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_str_impls/nesting.x/MyXDR.rs @@ -50,7 +50,7 @@ use std::{ io::{BufRead, BufReader, Cursor, Read, Write}, }; -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] use embedded_io_extras::{Cursor, Error as _, ErrorType, Read, Write}; /// Error contains all errors returned by functions in this crate. It can be @@ -68,7 +68,7 @@ pub enum Error { InvalidHex, #[cfg(feature = "std")] Io(io::Error), - #[cfg(all(not(feature = "std"), feature = "alloc"))] + #[cfg(feature = "embedded_io")] Io(embedded_io_extras::ErrorKind), DepthLimitExceeded, #[cfg(feature = "serde_json")] @@ -86,15 +86,14 @@ impl PartialEq for Error { // case for comparing errors outputted by the XDR library is for // error case testing, and a lack of the ability to compare has a // detrimental affect on failure testing, so this is a tradeoff. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] (Self::Io(l), Self::Io(r)) => l.kind() == r.kind(), _ => core::mem::discriminant(self) == core::mem::discriminant(other), } } } - -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl embedded_io_extras::Error for Error { fn kind(&self) -> embedded_io_extras::ErrorKind { match self { @@ -104,7 +103,7 @@ impl embedded_io_extras::Error for Error { } } -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl From> for Error { fn from(value: embedded_io_extras::ReadExactError) -> Self { match value { @@ -140,7 +139,7 @@ impl fmt::Display for Error { Error::InvalidHex => write!(f, "hex invalid"), #[cfg(feature = "std")] Error::Io(e) => write!(f, "{e}"), - #[cfg(all(not(feature = "std"), feature = "alloc"))] + #[cfg(feature = "embedded_io")] Error::Io(_) => write!(f, "io error"), Error::DepthLimitExceeded => write!(f, "depth limit exceeded"), #[cfg(feature = "serde_json")] @@ -194,7 +193,7 @@ impl From for () { #[allow(dead_code)] type Result = core::result::Result; -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl ErrorType for Limited { type Error = Error; } /// Name defines types that assign a static name to their value, such as the @@ -230,7 +229,7 @@ where /// `Limits` contains the limits that a limited reader or writer will be /// constrained to. -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] #[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct Limits { /// Defines the maximum depth for recursive calls in `Read/WriteXdr` to @@ -247,7 +246,7 @@ pub struct Limits { pub len: usize, } -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] impl Limits { #[must_use] pub fn none() -> Self { @@ -278,13 +277,13 @@ impl Limits { /// /// Intended for use with readers and writers and limiting their reads and /// writes. -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] pub struct Limited { pub inner: L, pub(crate) limits: Limits, } -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] impl Limited { /// Constructs a new `Limited`. /// @@ -337,8 +336,7 @@ impl Read for Limited { } } - -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl Read for Limited { /// Forwards the read operation to the wrapped object. fn read(&mut self, buf: &mut [u8]) -> core::result::Result { @@ -372,7 +370,7 @@ impl Write for Limited { } } -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl Write for Limited { /// Forwards the write operation to the wrapped object. fn write(&mut self, buf: &[u8]) -> core::result::Result { @@ -457,7 +455,7 @@ where /// /// Use [`ReadXdR: Read_xdr_to_end`] when the intent is for all bytes in the /// read implementation to be consumed by the read. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result; /// Construct the type from the XDR bytes base64 encoded. @@ -492,7 +490,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr_to_end(r: &mut Limited) -> Result { let s = Self::read_xdr(r)?; // Check that any further reads, such as this read of one byte, read no @@ -532,7 +530,7 @@ where /// /// Use [`ReadXdR: Read_xdr_into_to_end`] when the intent is for all bytes /// in the read implementation to be consumed by the read. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr_into(&mut self, r: &mut Limited) -> Result<()> { *self = Self::read_xdr(r)?; Ok(()) @@ -556,7 +554,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr_into_to_end(&mut self, r: &mut Limited) -> Result<()> { Self::read_xdr_into(self, r)?; // Check that any further reads, such as this read of one byte, read no @@ -605,7 +603,7 @@ where /// /// An error is returned if the bytes are not completely consumed by the /// deserialization. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn from_xdr(bytes: impl AsRef<[u8]>, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(&mut cursor)?; @@ -629,10 +627,10 @@ where } pub trait WriteXdr { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()>; - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn to_xdr(&self, limits: Limits) -> Result> { let mut cursor = Limited::new(Cursor::new(vec![]), limits); self.write_xdr(&mut cursor)?; @@ -654,13 +652,13 @@ pub trait WriteXdr { /// `Pad_len` returns the number of bytes to pad an XDR value of the given /// length to make the final serialized size a multiple of 4. -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] fn pad_len(len: usize) -> usize { (4 - (len % 4)) % 4 } impl ReadXdr for i32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -672,7 +670,7 @@ impl ReadXdr for i32 { } impl WriteXdr for i32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -683,7 +681,7 @@ impl WriteXdr for i32 { } impl ReadXdr for u32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -695,7 +693,7 @@ impl ReadXdr for u32 { } impl WriteXdr for u32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -706,7 +704,7 @@ impl WriteXdr for u32 { } impl ReadXdr for i64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -718,7 +716,7 @@ impl ReadXdr for i64 { } impl WriteXdr for i64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -729,7 +727,7 @@ impl WriteXdr for i64 { } impl ReadXdr for u64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -741,7 +739,7 @@ impl ReadXdr for u64 { } impl WriteXdr for u64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -752,35 +750,35 @@ impl WriteXdr for u64 { } impl ReadXdr for f32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for f64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for bool { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -791,7 +789,7 @@ impl ReadXdr for bool { } impl WriteXdr for bool { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i = u32::from(*self); // true = 1, false = 0 @@ -801,7 +799,7 @@ impl WriteXdr for bool { } impl ReadXdr for Option { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -818,7 +816,7 @@ impl ReadXdr for Option { } impl WriteXdr for Option { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { if let Some(t) = self { @@ -833,35 +831,35 @@ impl WriteXdr for Option { } impl ReadXdr for Box { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| Ok(Box::new(T::read_xdr(r)?))) } } impl WriteXdr for Box { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| T::write_xdr(self, w)) } } impl ReadXdr for () { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(_r: &mut Limited) -> Result { Ok(()) } } impl WriteXdr for () { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { Ok(()) } } impl ReadXdr for [u8; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { r.consume_len(N)?; @@ -880,7 +878,7 @@ impl ReadXdr for [u8; N] { } impl WriteXdr for [u8; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { w.consume_len(N)?; @@ -894,7 +892,7 @@ impl WriteXdr for [u8; N] { } impl ReadXdr for [T; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let mut vec = Vec::with_capacity(N); @@ -909,7 +907,7 @@ impl ReadXdr for [T; N] { } impl WriteXdr for [T; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { for t in self { @@ -1268,7 +1266,7 @@ impl<'a, const MAX: u32> TryFrom<&'a VecM> for &'a str { } impl ReadXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1295,7 +1293,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1315,7 +1313,7 @@ impl WriteXdr for VecM { } impl ReadXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len = u32::read_xdr(r)?; @@ -1335,7 +1333,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1708,7 +1706,7 @@ impl<'a, const MAX: u32> TryFrom<&'a BytesM> for &'a str { } impl ReadXdr for BytesM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1735,7 +1733,7 @@ impl ReadXdr for BytesM { } impl WriteXdr for BytesM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2111,7 +2109,7 @@ impl<'a, const MAX: u32> TryFrom<&'a StringM> for &'a str { } impl ReadXdr for StringM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -2138,7 +2136,7 @@ impl ReadXdr for StringM { } impl WriteXdr for StringM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2184,7 +2182,7 @@ impl ReadXdr for Frame where T: ReadXdr, { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { // Read the frame header value that contains 1 flag-bit and a 33-bit length. // - The 1 flag bit is 0 when there are more frames for the same record. @@ -2204,7 +2202,7 @@ where } } -#[cfg(all(test, feature = "alloc"))] +#[cfg(all(test, any(feature = "std", feature = "embedded_io")))] mod tests { use super::*; @@ -2314,7 +2312,7 @@ mod tests { } } -#[cfg(all(test, feature = "alloc"))] +#[cfg(all(test, any(feature = "std", feature = "embedded_io")))] mod test { use super::*; @@ -2827,6 +2825,219 @@ mod test { } } +#[cfg(all(test, any(feature = "std", feature = "embedded_io")))] +mod test_io { + // We will use different IO libraries according to the feature, + // we hope the selected IO library can work as expected + + use super::*; + + #[test] + fn test_read_exact_success() { + let data = b"The quick brown fox jumps over the lazy dog."; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 19]; // Exactly the length of "The quick brown fox" + + // Attempt to read exactly 19 bytes + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"The quick brown fox"); + assert_eq!(cursor.position(), 19); + } + + #[test] + fn test_read_exact_less_than_available() { + let data = b"Hello, Rust!"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 5]; + + // Attempt to read 5 bytes from the start + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Hello"); + assert_eq!(cursor.position(), 5); + } + + #[test] + fn test_read_exact_exact_eof() { + let data = b"Data"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 4]; + + // Attempt to read exactly 4 bytes, which is the entire buffer + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Data"); + assert_eq!(cursor.position(), 4); + + // Further attempt to read should fail with EOF + let mut buffer_eof = [0u8; 1]; + let result = cursor.read_exact(&mut buffer_eof); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 4); // Position should remain at EOF + } + + #[test] + fn test_read_exact_past_eof() { + let data = b"Short"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 10]; // Requesting more bytes than available + + // Attempt to read 10 bytes from a 5-byte buffer + let result = cursor.read_exact(&mut buffer); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 5); // Position should move to EOF + } + + #[test] + fn test_read_exact_empty_buffer() { + let data = b"Non-empty"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 0]; // Zero-length buffer + + // Attempt to read zero bytes + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(cursor.position(), 0); // Position should remain unchanged + } + + #[test] + fn test_read_exact_from_empty_cursor() { + let data: &[u8] = b""; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 5]; + + // Attempt to read from an empty cursor + let result = cursor.read_exact(&mut buffer); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 0); // Position remains at 0 + } + + #[test] + fn test_read_exact_multiple_reads() { + let data = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + let mut cursor = Cursor::new(data); + + let mut buffer1 = [0u8; 10]; + let mut buffer2 = [0u8; 10]; + let mut buffer3 = [0u8; 10]; // Only 6 bytes left + + // First read: 10 bytes + assert!(cursor.read_exact(&mut buffer1).is_ok()); + assert_eq!(&buffer1, b"ABCDEFGHIJ"); + assert_eq!(cursor.position(), 10); + + // Second read: 10 bytes + assert!(cursor.read_exact(&mut buffer2).is_ok()); + assert_eq!(&buffer2, b"KLMNOPQRST"); + assert_eq!(cursor.position(), 20); + + // Third read: Attempt to read 10 bytes, but only 6 are available + let result = cursor.read_exact(&mut buffer3); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + // read_exact makes no promises about the content of the buffer on error + // assert_eq!(&buffer3[..6], b"UVWXYZ"); + assert_eq!(cursor.position(), 26); // Position should be at EOF + } + + #[test] + fn test_cursor_read_exact_after_eof() { + let data = b"End"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 3]; + + // First read: read the entire buffer + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"End"); + assert_eq!(cursor.position(), 3); + + // Second read: attempt to read again, should fail + let mut buffer_eof = [0u8; 1]; + let result = cursor.read_exact(&mut buffer_eof); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 3); // Position remains at EOF + } + + #[test] + fn test_slice_read_exact_success() { + let data = b"SliceReadTest"; + let mut slice = &data[..]; + let mut buffer = [0u8; 13]; // Exact length + + // Using Read trait directly on slice + assert!(slice.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"SliceReadTest"); + } + + #[test] + fn test_slice_read_exact_partial() { + let data = b"SlicePartial"; + let mut slice = &data[..]; + let mut buffer = [0u8; 20]; // Request more bytes than available + + // Using Read trait directly on slice + let result = slice.read_exact(&mut buffer); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + // read_exact makes no promises about the content of the buffer on error + } +} + /// UnionKey is an XDR Enum defines as: /// /// ```text @@ -2916,7 +3127,7 @@ Self::Offer => "Offer", } impl ReadXdr for UnionKey { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let e = i32::read_xdr(r)?; @@ -2927,7 +3138,7 @@ Self::Offer => "Offer", } impl WriteXdr for UnionKey { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i: i32 = (*self).into(); @@ -2961,7 +3172,7 @@ pub struct MyUnionOne { } impl ReadXdr for MyUnionOne { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { Ok(Self{ @@ -2972,7 +3183,7 @@ impl ReadXdr for MyUnionOne { } impl WriteXdr for MyUnionOne { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { self.some_int.write_xdr(w)?; @@ -3000,7 +3211,7 @@ pub struct MyUnionTwo { } impl ReadXdr for MyUnionTwo { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { Ok(Self{ @@ -3012,7 +3223,7 @@ foo: i32::read_xdr(r)?, } impl WriteXdr for MyUnionTwo { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { self.some_int.write_xdr(w)?; @@ -3115,7 +3326,7 @@ Self::Offer => UnionKey::Offer, impl Union for MyUnion {} impl ReadXdr for MyUnion { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let dv: UnionKey = ::read_xdr(r)?; @@ -3133,7 +3344,7 @@ UnionKey::Offer => Self::Offer, } impl WriteXdr for MyUnion { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { self.discriminant().write_xdr(w)?; @@ -3263,7 +3474,7 @@ TypeVariant::MyUnionTwo, ]; "MyUnionOne", "MyUnionTwo", ]; - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] #[allow(clippy::too_many_lines)] pub fn read_xdr(v: TypeVariant, r: &mut Limited) -> Result { match v { @@ -3282,7 +3493,7 @@ TypeVariant::MyUnionTwo => r.with_limited_depth(|r| Ok(Self::MyUnionTwo(Box::new Ok(t) } - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] pub fn read_xdr_to_end(v: TypeVariant, r: &mut Limited) -> Result { let s = Self::read_xdr(v, r)?; // Check that any further reads, such as this read of one byte, read no @@ -3338,7 +3549,7 @@ TypeVariant::MyUnionTwo => Box::new(ReadXdrIter::<_, MyUnionTwo>::new(dec, r.lim } } - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] pub fn from_xdr>(v: TypeVariant, bytes: B, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(v, &mut cursor)?; @@ -3442,7 +3653,7 @@ Self::MyUnionTwo(_) => TypeVariant::MyUnionTwo, } impl WriteXdr for Type { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] #[allow(clippy::too_many_lines)] fn write_xdr(&self, w: &mut Limited) -> Result<()> { match self { diff --git a/spec/output/generator_spec_rust_custom_str_impls/optional.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_str_impls/optional.x/MyXDR.rs index 57f860332..1f19a9b70 100644 --- a/spec/output/generator_spec_rust_custom_str_impls/optional.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_str_impls/optional.x/MyXDR.rs @@ -50,7 +50,7 @@ use std::{ io::{BufRead, BufReader, Cursor, Read, Write}, }; -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] use embedded_io_extras::{Cursor, Error as _, ErrorType, Read, Write}; /// Error contains all errors returned by functions in this crate. It can be @@ -68,7 +68,7 @@ pub enum Error { InvalidHex, #[cfg(feature = "std")] Io(io::Error), - #[cfg(all(not(feature = "std"), feature = "alloc"))] + #[cfg(feature = "embedded_io")] Io(embedded_io_extras::ErrorKind), DepthLimitExceeded, #[cfg(feature = "serde_json")] @@ -86,15 +86,14 @@ impl PartialEq for Error { // case for comparing errors outputted by the XDR library is for // error case testing, and a lack of the ability to compare has a // detrimental affect on failure testing, so this is a tradeoff. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] (Self::Io(l), Self::Io(r)) => l.kind() == r.kind(), _ => core::mem::discriminant(self) == core::mem::discriminant(other), } } } - -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl embedded_io_extras::Error for Error { fn kind(&self) -> embedded_io_extras::ErrorKind { match self { @@ -104,7 +103,7 @@ impl embedded_io_extras::Error for Error { } } -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl From> for Error { fn from(value: embedded_io_extras::ReadExactError) -> Self { match value { @@ -140,7 +139,7 @@ impl fmt::Display for Error { Error::InvalidHex => write!(f, "hex invalid"), #[cfg(feature = "std")] Error::Io(e) => write!(f, "{e}"), - #[cfg(all(not(feature = "std"), feature = "alloc"))] + #[cfg(feature = "embedded_io")] Error::Io(_) => write!(f, "io error"), Error::DepthLimitExceeded => write!(f, "depth limit exceeded"), #[cfg(feature = "serde_json")] @@ -194,7 +193,7 @@ impl From for () { #[allow(dead_code)] type Result = core::result::Result; -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl ErrorType for Limited { type Error = Error; } /// Name defines types that assign a static name to their value, such as the @@ -230,7 +229,7 @@ where /// `Limits` contains the limits that a limited reader or writer will be /// constrained to. -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] #[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct Limits { /// Defines the maximum depth for recursive calls in `Read/WriteXdr` to @@ -247,7 +246,7 @@ pub struct Limits { pub len: usize, } -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] impl Limits { #[must_use] pub fn none() -> Self { @@ -278,13 +277,13 @@ impl Limits { /// /// Intended for use with readers and writers and limiting their reads and /// writes. -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] pub struct Limited { pub inner: L, pub(crate) limits: Limits, } -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] impl Limited { /// Constructs a new `Limited`. /// @@ -337,8 +336,7 @@ impl Read for Limited { } } - -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl Read for Limited { /// Forwards the read operation to the wrapped object. fn read(&mut self, buf: &mut [u8]) -> core::result::Result { @@ -372,7 +370,7 @@ impl Write for Limited { } } -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl Write for Limited { /// Forwards the write operation to the wrapped object. fn write(&mut self, buf: &[u8]) -> core::result::Result { @@ -457,7 +455,7 @@ where /// /// Use [`ReadXdR: Read_xdr_to_end`] when the intent is for all bytes in the /// read implementation to be consumed by the read. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result; /// Construct the type from the XDR bytes base64 encoded. @@ -492,7 +490,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr_to_end(r: &mut Limited) -> Result { let s = Self::read_xdr(r)?; // Check that any further reads, such as this read of one byte, read no @@ -532,7 +530,7 @@ where /// /// Use [`ReadXdR: Read_xdr_into_to_end`] when the intent is for all bytes /// in the read implementation to be consumed by the read. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr_into(&mut self, r: &mut Limited) -> Result<()> { *self = Self::read_xdr(r)?; Ok(()) @@ -556,7 +554,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr_into_to_end(&mut self, r: &mut Limited) -> Result<()> { Self::read_xdr_into(self, r)?; // Check that any further reads, such as this read of one byte, read no @@ -605,7 +603,7 @@ where /// /// An error is returned if the bytes are not completely consumed by the /// deserialization. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn from_xdr(bytes: impl AsRef<[u8]>, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(&mut cursor)?; @@ -629,10 +627,10 @@ where } pub trait WriteXdr { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()>; - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn to_xdr(&self, limits: Limits) -> Result> { let mut cursor = Limited::new(Cursor::new(vec![]), limits); self.write_xdr(&mut cursor)?; @@ -654,13 +652,13 @@ pub trait WriteXdr { /// `Pad_len` returns the number of bytes to pad an XDR value of the given /// length to make the final serialized size a multiple of 4. -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] fn pad_len(len: usize) -> usize { (4 - (len % 4)) % 4 } impl ReadXdr for i32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -672,7 +670,7 @@ impl ReadXdr for i32 { } impl WriteXdr for i32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -683,7 +681,7 @@ impl WriteXdr for i32 { } impl ReadXdr for u32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -695,7 +693,7 @@ impl ReadXdr for u32 { } impl WriteXdr for u32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -706,7 +704,7 @@ impl WriteXdr for u32 { } impl ReadXdr for i64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -718,7 +716,7 @@ impl ReadXdr for i64 { } impl WriteXdr for i64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -729,7 +727,7 @@ impl WriteXdr for i64 { } impl ReadXdr for u64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -741,7 +739,7 @@ impl ReadXdr for u64 { } impl WriteXdr for u64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -752,35 +750,35 @@ impl WriteXdr for u64 { } impl ReadXdr for f32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for f64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for bool { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -791,7 +789,7 @@ impl ReadXdr for bool { } impl WriteXdr for bool { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i = u32::from(*self); // true = 1, false = 0 @@ -801,7 +799,7 @@ impl WriteXdr for bool { } impl ReadXdr for Option { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -818,7 +816,7 @@ impl ReadXdr for Option { } impl WriteXdr for Option { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { if let Some(t) = self { @@ -833,35 +831,35 @@ impl WriteXdr for Option { } impl ReadXdr for Box { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| Ok(Box::new(T::read_xdr(r)?))) } } impl WriteXdr for Box { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| T::write_xdr(self, w)) } } impl ReadXdr for () { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(_r: &mut Limited) -> Result { Ok(()) } } impl WriteXdr for () { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { Ok(()) } } impl ReadXdr for [u8; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { r.consume_len(N)?; @@ -880,7 +878,7 @@ impl ReadXdr for [u8; N] { } impl WriteXdr for [u8; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { w.consume_len(N)?; @@ -894,7 +892,7 @@ impl WriteXdr for [u8; N] { } impl ReadXdr for [T; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let mut vec = Vec::with_capacity(N); @@ -909,7 +907,7 @@ impl ReadXdr for [T; N] { } impl WriteXdr for [T; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { for t in self { @@ -1268,7 +1266,7 @@ impl<'a, const MAX: u32> TryFrom<&'a VecM> for &'a str { } impl ReadXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1295,7 +1293,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1315,7 +1313,7 @@ impl WriteXdr for VecM { } impl ReadXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len = u32::read_xdr(r)?; @@ -1335,7 +1333,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1708,7 +1706,7 @@ impl<'a, const MAX: u32> TryFrom<&'a BytesM> for &'a str { } impl ReadXdr for BytesM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1735,7 +1733,7 @@ impl ReadXdr for BytesM { } impl WriteXdr for BytesM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2111,7 +2109,7 @@ impl<'a, const MAX: u32> TryFrom<&'a StringM> for &'a str { } impl ReadXdr for StringM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -2138,7 +2136,7 @@ impl ReadXdr for StringM { } impl WriteXdr for StringM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2184,7 +2182,7 @@ impl ReadXdr for Frame where T: ReadXdr, { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { // Read the frame header value that contains 1 flag-bit and a 33-bit length. // - The 1 flag bit is 0 when there are more frames for the same record. @@ -2204,7 +2202,7 @@ where } } -#[cfg(all(test, feature = "alloc"))] +#[cfg(all(test, any(feature = "std", feature = "embedded_io")))] mod tests { use super::*; @@ -2314,7 +2312,7 @@ mod tests { } } -#[cfg(all(test, feature = "alloc"))] +#[cfg(all(test, any(feature = "std", feature = "embedded_io")))] mod test { use super::*; @@ -2827,6 +2825,219 @@ mod test { } } +#[cfg(all(test, any(feature = "std", feature = "embedded_io")))] +mod test_io { + // We will use different IO libraries according to the feature, + // we hope the selected IO library can work as expected + + use super::*; + + #[test] + fn test_read_exact_success() { + let data = b"The quick brown fox jumps over the lazy dog."; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 19]; // Exactly the length of "The quick brown fox" + + // Attempt to read exactly 19 bytes + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"The quick brown fox"); + assert_eq!(cursor.position(), 19); + } + + #[test] + fn test_read_exact_less_than_available() { + let data = b"Hello, Rust!"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 5]; + + // Attempt to read 5 bytes from the start + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Hello"); + assert_eq!(cursor.position(), 5); + } + + #[test] + fn test_read_exact_exact_eof() { + let data = b"Data"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 4]; + + // Attempt to read exactly 4 bytes, which is the entire buffer + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Data"); + assert_eq!(cursor.position(), 4); + + // Further attempt to read should fail with EOF + let mut buffer_eof = [0u8; 1]; + let result = cursor.read_exact(&mut buffer_eof); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 4); // Position should remain at EOF + } + + #[test] + fn test_read_exact_past_eof() { + let data = b"Short"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 10]; // Requesting more bytes than available + + // Attempt to read 10 bytes from a 5-byte buffer + let result = cursor.read_exact(&mut buffer); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 5); // Position should move to EOF + } + + #[test] + fn test_read_exact_empty_buffer() { + let data = b"Non-empty"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 0]; // Zero-length buffer + + // Attempt to read zero bytes + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(cursor.position(), 0); // Position should remain unchanged + } + + #[test] + fn test_read_exact_from_empty_cursor() { + let data: &[u8] = b""; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 5]; + + // Attempt to read from an empty cursor + let result = cursor.read_exact(&mut buffer); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 0); // Position remains at 0 + } + + #[test] + fn test_read_exact_multiple_reads() { + let data = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + let mut cursor = Cursor::new(data); + + let mut buffer1 = [0u8; 10]; + let mut buffer2 = [0u8; 10]; + let mut buffer3 = [0u8; 10]; // Only 6 bytes left + + // First read: 10 bytes + assert!(cursor.read_exact(&mut buffer1).is_ok()); + assert_eq!(&buffer1, b"ABCDEFGHIJ"); + assert_eq!(cursor.position(), 10); + + // Second read: 10 bytes + assert!(cursor.read_exact(&mut buffer2).is_ok()); + assert_eq!(&buffer2, b"KLMNOPQRST"); + assert_eq!(cursor.position(), 20); + + // Third read: Attempt to read 10 bytes, but only 6 are available + let result = cursor.read_exact(&mut buffer3); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + // read_exact makes no promises about the content of the buffer on error + // assert_eq!(&buffer3[..6], b"UVWXYZ"); + assert_eq!(cursor.position(), 26); // Position should be at EOF + } + + #[test] + fn test_cursor_read_exact_after_eof() { + let data = b"End"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 3]; + + // First read: read the entire buffer + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"End"); + assert_eq!(cursor.position(), 3); + + // Second read: attempt to read again, should fail + let mut buffer_eof = [0u8; 1]; + let result = cursor.read_exact(&mut buffer_eof); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 3); // Position remains at EOF + } + + #[test] + fn test_slice_read_exact_success() { + let data = b"SliceReadTest"; + let mut slice = &data[..]; + let mut buffer = [0u8; 13]; // Exact length + + // Using Read trait directly on slice + assert!(slice.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"SliceReadTest"); + } + + #[test] + fn test_slice_read_exact_partial() { + let data = b"SlicePartial"; + let mut slice = &data[..]; + let mut buffer = [0u8; 20]; // Request more bytes than available + + // Using Read trait directly on slice + let result = slice.read_exact(&mut buffer); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + // read_exact makes no promises about the content of the buffer on error + } +} + /// Arr is an XDR Typedef defines as: /// /// ```text @@ -2857,7 +3068,7 @@ pub struct HasOptions { } impl ReadXdr for HasOptions { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { Ok(Self{ @@ -2870,7 +3081,7 @@ third_option: Option::::read_xdr(r)?, } impl WriteXdr for HasOptions { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { self.first_option.write_xdr(w)?; @@ -2969,7 +3180,7 @@ TypeVariant::HasOptions, ]; pub const VARIANTS_STR: [&'static str; 2] = [ "Arr", "HasOptions", ]; - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] #[allow(clippy::too_many_lines)] pub fn read_xdr(v: TypeVariant, r: &mut Limited) -> Result { match v { @@ -2985,7 +3196,7 @@ TypeVariant::HasOptions => r.with_limited_depth(|r| Ok(Self::HasOptions(Box::new Ok(t) } - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] pub fn read_xdr_to_end(v: TypeVariant, r: &mut Limited) -> Result { let s = Self::read_xdr(v, r)?; // Check that any further reads, such as this read of one byte, read no @@ -3032,7 +3243,7 @@ TypeVariant::HasOptions => Box::new(ReadXdrIter::<_, HasOptions>::new(dec, r.lim } } - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] pub fn from_xdr>(v: TypeVariant, bytes: B, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(v, &mut cursor)?; @@ -3121,7 +3332,7 @@ Self::HasOptions(_) => TypeVariant::HasOptions, } impl WriteXdr for Type { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] #[allow(clippy::too_many_lines)] fn write_xdr(&self, w: &mut Limited) -> Result<()> { match self { diff --git a/spec/output/generator_spec_rust_custom_str_impls/struct.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_str_impls/struct.x/MyXDR.rs index 09e40232a..1959f9c3a 100644 --- a/spec/output/generator_spec_rust_custom_str_impls/struct.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_str_impls/struct.x/MyXDR.rs @@ -50,7 +50,7 @@ use std::{ io::{BufRead, BufReader, Cursor, Read, Write}, }; -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] use embedded_io_extras::{Cursor, Error as _, ErrorType, Read, Write}; /// Error contains all errors returned by functions in this crate. It can be @@ -68,7 +68,7 @@ pub enum Error { InvalidHex, #[cfg(feature = "std")] Io(io::Error), - #[cfg(all(not(feature = "std"), feature = "alloc"))] + #[cfg(feature = "embedded_io")] Io(embedded_io_extras::ErrorKind), DepthLimitExceeded, #[cfg(feature = "serde_json")] @@ -86,15 +86,14 @@ impl PartialEq for Error { // case for comparing errors outputted by the XDR library is for // error case testing, and a lack of the ability to compare has a // detrimental affect on failure testing, so this is a tradeoff. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] (Self::Io(l), Self::Io(r)) => l.kind() == r.kind(), _ => core::mem::discriminant(self) == core::mem::discriminant(other), } } } - -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl embedded_io_extras::Error for Error { fn kind(&self) -> embedded_io_extras::ErrorKind { match self { @@ -104,7 +103,7 @@ impl embedded_io_extras::Error for Error { } } -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl From> for Error { fn from(value: embedded_io_extras::ReadExactError) -> Self { match value { @@ -140,7 +139,7 @@ impl fmt::Display for Error { Error::InvalidHex => write!(f, "hex invalid"), #[cfg(feature = "std")] Error::Io(e) => write!(f, "{e}"), - #[cfg(all(not(feature = "std"), feature = "alloc"))] + #[cfg(feature = "embedded_io")] Error::Io(_) => write!(f, "io error"), Error::DepthLimitExceeded => write!(f, "depth limit exceeded"), #[cfg(feature = "serde_json")] @@ -194,7 +193,7 @@ impl From for () { #[allow(dead_code)] type Result = core::result::Result; -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl ErrorType for Limited { type Error = Error; } /// Name defines types that assign a static name to their value, such as the @@ -230,7 +229,7 @@ where /// `Limits` contains the limits that a limited reader or writer will be /// constrained to. -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] #[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct Limits { /// Defines the maximum depth for recursive calls in `Read/WriteXdr` to @@ -247,7 +246,7 @@ pub struct Limits { pub len: usize, } -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] impl Limits { #[must_use] pub fn none() -> Self { @@ -278,13 +277,13 @@ impl Limits { /// /// Intended for use with readers and writers and limiting their reads and /// writes. -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] pub struct Limited { pub inner: L, pub(crate) limits: Limits, } -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] impl Limited { /// Constructs a new `Limited`. /// @@ -337,8 +336,7 @@ impl Read for Limited { } } - -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl Read for Limited { /// Forwards the read operation to the wrapped object. fn read(&mut self, buf: &mut [u8]) -> core::result::Result { @@ -372,7 +370,7 @@ impl Write for Limited { } } -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl Write for Limited { /// Forwards the write operation to the wrapped object. fn write(&mut self, buf: &[u8]) -> core::result::Result { @@ -457,7 +455,7 @@ where /// /// Use [`ReadXdR: Read_xdr_to_end`] when the intent is for all bytes in the /// read implementation to be consumed by the read. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result; /// Construct the type from the XDR bytes base64 encoded. @@ -492,7 +490,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr_to_end(r: &mut Limited) -> Result { let s = Self::read_xdr(r)?; // Check that any further reads, such as this read of one byte, read no @@ -532,7 +530,7 @@ where /// /// Use [`ReadXdR: Read_xdr_into_to_end`] when the intent is for all bytes /// in the read implementation to be consumed by the read. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr_into(&mut self, r: &mut Limited) -> Result<()> { *self = Self::read_xdr(r)?; Ok(()) @@ -556,7 +554,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr_into_to_end(&mut self, r: &mut Limited) -> Result<()> { Self::read_xdr_into(self, r)?; // Check that any further reads, such as this read of one byte, read no @@ -605,7 +603,7 @@ where /// /// An error is returned if the bytes are not completely consumed by the /// deserialization. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn from_xdr(bytes: impl AsRef<[u8]>, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(&mut cursor)?; @@ -629,10 +627,10 @@ where } pub trait WriteXdr { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()>; - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn to_xdr(&self, limits: Limits) -> Result> { let mut cursor = Limited::new(Cursor::new(vec![]), limits); self.write_xdr(&mut cursor)?; @@ -654,13 +652,13 @@ pub trait WriteXdr { /// `Pad_len` returns the number of bytes to pad an XDR value of the given /// length to make the final serialized size a multiple of 4. -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] fn pad_len(len: usize) -> usize { (4 - (len % 4)) % 4 } impl ReadXdr for i32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -672,7 +670,7 @@ impl ReadXdr for i32 { } impl WriteXdr for i32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -683,7 +681,7 @@ impl WriteXdr for i32 { } impl ReadXdr for u32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -695,7 +693,7 @@ impl ReadXdr for u32 { } impl WriteXdr for u32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -706,7 +704,7 @@ impl WriteXdr for u32 { } impl ReadXdr for i64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -718,7 +716,7 @@ impl ReadXdr for i64 { } impl WriteXdr for i64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -729,7 +727,7 @@ impl WriteXdr for i64 { } impl ReadXdr for u64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -741,7 +739,7 @@ impl ReadXdr for u64 { } impl WriteXdr for u64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -752,35 +750,35 @@ impl WriteXdr for u64 { } impl ReadXdr for f32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for f64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for bool { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -791,7 +789,7 @@ impl ReadXdr for bool { } impl WriteXdr for bool { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i = u32::from(*self); // true = 1, false = 0 @@ -801,7 +799,7 @@ impl WriteXdr for bool { } impl ReadXdr for Option { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -818,7 +816,7 @@ impl ReadXdr for Option { } impl WriteXdr for Option { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { if let Some(t) = self { @@ -833,35 +831,35 @@ impl WriteXdr for Option { } impl ReadXdr for Box { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| Ok(Box::new(T::read_xdr(r)?))) } } impl WriteXdr for Box { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| T::write_xdr(self, w)) } } impl ReadXdr for () { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(_r: &mut Limited) -> Result { Ok(()) } } impl WriteXdr for () { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { Ok(()) } } impl ReadXdr for [u8; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { r.consume_len(N)?; @@ -880,7 +878,7 @@ impl ReadXdr for [u8; N] { } impl WriteXdr for [u8; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { w.consume_len(N)?; @@ -894,7 +892,7 @@ impl WriteXdr for [u8; N] { } impl ReadXdr for [T; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let mut vec = Vec::with_capacity(N); @@ -909,7 +907,7 @@ impl ReadXdr for [T; N] { } impl WriteXdr for [T; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { for t in self { @@ -1268,7 +1266,7 @@ impl<'a, const MAX: u32> TryFrom<&'a VecM> for &'a str { } impl ReadXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1295,7 +1293,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1315,7 +1313,7 @@ impl WriteXdr for VecM { } impl ReadXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len = u32::read_xdr(r)?; @@ -1335,7 +1333,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1708,7 +1706,7 @@ impl<'a, const MAX: u32> TryFrom<&'a BytesM> for &'a str { } impl ReadXdr for BytesM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1735,7 +1733,7 @@ impl ReadXdr for BytesM { } impl WriteXdr for BytesM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2111,7 +2109,7 @@ impl<'a, const MAX: u32> TryFrom<&'a StringM> for &'a str { } impl ReadXdr for StringM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -2138,7 +2136,7 @@ impl ReadXdr for StringM { } impl WriteXdr for StringM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2184,7 +2182,7 @@ impl ReadXdr for Frame where T: ReadXdr, { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { // Read the frame header value that contains 1 flag-bit and a 33-bit length. // - The 1 flag bit is 0 when there are more frames for the same record. @@ -2204,7 +2202,7 @@ where } } -#[cfg(all(test, feature = "alloc"))] +#[cfg(all(test, any(feature = "std", feature = "embedded_io")))] mod tests { use super::*; @@ -2314,7 +2312,7 @@ mod tests { } } -#[cfg(all(test, feature = "alloc"))] +#[cfg(all(test, any(feature = "std", feature = "embedded_io")))] mod test { use super::*; @@ -2827,6 +2825,219 @@ mod test { } } +#[cfg(all(test, any(feature = "std", feature = "embedded_io")))] +mod test_io { + // We will use different IO libraries according to the feature, + // we hope the selected IO library can work as expected + + use super::*; + + #[test] + fn test_read_exact_success() { + let data = b"The quick brown fox jumps over the lazy dog."; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 19]; // Exactly the length of "The quick brown fox" + + // Attempt to read exactly 19 bytes + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"The quick brown fox"); + assert_eq!(cursor.position(), 19); + } + + #[test] + fn test_read_exact_less_than_available() { + let data = b"Hello, Rust!"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 5]; + + // Attempt to read 5 bytes from the start + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Hello"); + assert_eq!(cursor.position(), 5); + } + + #[test] + fn test_read_exact_exact_eof() { + let data = b"Data"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 4]; + + // Attempt to read exactly 4 bytes, which is the entire buffer + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Data"); + assert_eq!(cursor.position(), 4); + + // Further attempt to read should fail with EOF + let mut buffer_eof = [0u8; 1]; + let result = cursor.read_exact(&mut buffer_eof); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 4); // Position should remain at EOF + } + + #[test] + fn test_read_exact_past_eof() { + let data = b"Short"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 10]; // Requesting more bytes than available + + // Attempt to read 10 bytes from a 5-byte buffer + let result = cursor.read_exact(&mut buffer); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 5); // Position should move to EOF + } + + #[test] + fn test_read_exact_empty_buffer() { + let data = b"Non-empty"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 0]; // Zero-length buffer + + // Attempt to read zero bytes + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(cursor.position(), 0); // Position should remain unchanged + } + + #[test] + fn test_read_exact_from_empty_cursor() { + let data: &[u8] = b""; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 5]; + + // Attempt to read from an empty cursor + let result = cursor.read_exact(&mut buffer); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 0); // Position remains at 0 + } + + #[test] + fn test_read_exact_multiple_reads() { + let data = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + let mut cursor = Cursor::new(data); + + let mut buffer1 = [0u8; 10]; + let mut buffer2 = [0u8; 10]; + let mut buffer3 = [0u8; 10]; // Only 6 bytes left + + // First read: 10 bytes + assert!(cursor.read_exact(&mut buffer1).is_ok()); + assert_eq!(&buffer1, b"ABCDEFGHIJ"); + assert_eq!(cursor.position(), 10); + + // Second read: 10 bytes + assert!(cursor.read_exact(&mut buffer2).is_ok()); + assert_eq!(&buffer2, b"KLMNOPQRST"); + assert_eq!(cursor.position(), 20); + + // Third read: Attempt to read 10 bytes, but only 6 are available + let result = cursor.read_exact(&mut buffer3); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + // read_exact makes no promises about the content of the buffer on error + // assert_eq!(&buffer3[..6], b"UVWXYZ"); + assert_eq!(cursor.position(), 26); // Position should be at EOF + } + + #[test] + fn test_cursor_read_exact_after_eof() { + let data = b"End"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 3]; + + // First read: read the entire buffer + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"End"); + assert_eq!(cursor.position(), 3); + + // Second read: attempt to read again, should fail + let mut buffer_eof = [0u8; 1]; + let result = cursor.read_exact(&mut buffer_eof); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 3); // Position remains at EOF + } + + #[test] + fn test_slice_read_exact_success() { + let data = b"SliceReadTest"; + let mut slice = &data[..]; + let mut buffer = [0u8; 13]; // Exact length + + // Using Read trait directly on slice + assert!(slice.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"SliceReadTest"); + } + + #[test] + fn test_slice_read_exact_partial() { + let data = b"SlicePartial"; + let mut slice = &data[..]; + let mut buffer = [0u8; 20]; // Request more bytes than available + + // Using Read trait directly on slice + let result = slice.read_exact(&mut buffer); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + // read_exact makes no promises about the content of the buffer on error + } +} + /// Int64 is an XDR Typedef defines as: /// /// ```text @@ -2861,7 +3072,7 @@ pub struct MyStruct { } impl ReadXdr for MyStruct { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { Ok(Self{ @@ -2876,7 +3087,7 @@ max_string: StringM::<100>::read_xdr(r)?, } impl WriteXdr for MyStruct { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { self.some_int.write_xdr(w)?; @@ -2977,7 +3188,7 @@ TypeVariant::MyStruct, ]; pub const VARIANTS_STR: [&'static str; 2] = [ "Int64", "MyStruct", ]; - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] #[allow(clippy::too_many_lines)] pub fn read_xdr(v: TypeVariant, r: &mut Limited) -> Result { match v { @@ -2993,7 +3204,7 @@ TypeVariant::MyStruct => r.with_limited_depth(|r| Ok(Self::MyStruct(Box::new(MyS Ok(t) } - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] pub fn read_xdr_to_end(v: TypeVariant, r: &mut Limited) -> Result { let s = Self::read_xdr(v, r)?; // Check that any further reads, such as this read of one byte, read no @@ -3040,7 +3251,7 @@ TypeVariant::MyStruct => Box::new(ReadXdrIter::<_, MyStruct>::new(dec, r.limits. } } - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] pub fn from_xdr>(v: TypeVariant, bytes: B, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(v, &mut cursor)?; @@ -3129,7 +3340,7 @@ Self::MyStruct(_) => TypeVariant::MyStruct, } impl WriteXdr for Type { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] #[allow(clippy::too_many_lines)] fn write_xdr(&self, w: &mut Limited) -> Result<()> { match self { diff --git a/spec/output/generator_spec_rust_custom_str_impls/test.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_str_impls/test.x/MyXDR.rs index be4c6845c..79f395343 100644 --- a/spec/output/generator_spec_rust_custom_str_impls/test.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_str_impls/test.x/MyXDR.rs @@ -50,7 +50,7 @@ use std::{ io::{BufRead, BufReader, Cursor, Read, Write}, }; -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] use embedded_io_extras::{Cursor, Error as _, ErrorType, Read, Write}; /// Error contains all errors returned by functions in this crate. It can be @@ -68,7 +68,7 @@ pub enum Error { InvalidHex, #[cfg(feature = "std")] Io(io::Error), - #[cfg(all(not(feature = "std"), feature = "alloc"))] + #[cfg(feature = "embedded_io")] Io(embedded_io_extras::ErrorKind), DepthLimitExceeded, #[cfg(feature = "serde_json")] @@ -86,15 +86,14 @@ impl PartialEq for Error { // case for comparing errors outputted by the XDR library is for // error case testing, and a lack of the ability to compare has a // detrimental affect on failure testing, so this is a tradeoff. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] (Self::Io(l), Self::Io(r)) => l.kind() == r.kind(), _ => core::mem::discriminant(self) == core::mem::discriminant(other), } } } - -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl embedded_io_extras::Error for Error { fn kind(&self) -> embedded_io_extras::ErrorKind { match self { @@ -104,7 +103,7 @@ impl embedded_io_extras::Error for Error { } } -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl From> for Error { fn from(value: embedded_io_extras::ReadExactError) -> Self { match value { @@ -140,7 +139,7 @@ impl fmt::Display for Error { Error::InvalidHex => write!(f, "hex invalid"), #[cfg(feature = "std")] Error::Io(e) => write!(f, "{e}"), - #[cfg(all(not(feature = "std"), feature = "alloc"))] + #[cfg(feature = "embedded_io")] Error::Io(_) => write!(f, "io error"), Error::DepthLimitExceeded => write!(f, "depth limit exceeded"), #[cfg(feature = "serde_json")] @@ -194,7 +193,7 @@ impl From for () { #[allow(dead_code)] type Result = core::result::Result; -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl ErrorType for Limited { type Error = Error; } /// Name defines types that assign a static name to their value, such as the @@ -230,7 +229,7 @@ where /// `Limits` contains the limits that a limited reader or writer will be /// constrained to. -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] #[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct Limits { /// Defines the maximum depth for recursive calls in `Read/WriteXdr` to @@ -247,7 +246,7 @@ pub struct Limits { pub len: usize, } -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] impl Limits { #[must_use] pub fn none() -> Self { @@ -278,13 +277,13 @@ impl Limits { /// /// Intended for use with readers and writers and limiting their reads and /// writes. -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] pub struct Limited { pub inner: L, pub(crate) limits: Limits, } -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] impl Limited { /// Constructs a new `Limited`. /// @@ -337,8 +336,7 @@ impl Read for Limited { } } - -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl Read for Limited { /// Forwards the read operation to the wrapped object. fn read(&mut self, buf: &mut [u8]) -> core::result::Result { @@ -372,7 +370,7 @@ impl Write for Limited { } } -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl Write for Limited { /// Forwards the write operation to the wrapped object. fn write(&mut self, buf: &[u8]) -> core::result::Result { @@ -457,7 +455,7 @@ where /// /// Use [`ReadXdR: Read_xdr_to_end`] when the intent is for all bytes in the /// read implementation to be consumed by the read. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result; /// Construct the type from the XDR bytes base64 encoded. @@ -492,7 +490,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr_to_end(r: &mut Limited) -> Result { let s = Self::read_xdr(r)?; // Check that any further reads, such as this read of one byte, read no @@ -532,7 +530,7 @@ where /// /// Use [`ReadXdR: Read_xdr_into_to_end`] when the intent is for all bytes /// in the read implementation to be consumed by the read. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr_into(&mut self, r: &mut Limited) -> Result<()> { *self = Self::read_xdr(r)?; Ok(()) @@ -556,7 +554,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr_into_to_end(&mut self, r: &mut Limited) -> Result<()> { Self::read_xdr_into(self, r)?; // Check that any further reads, such as this read of one byte, read no @@ -605,7 +603,7 @@ where /// /// An error is returned if the bytes are not completely consumed by the /// deserialization. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn from_xdr(bytes: impl AsRef<[u8]>, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(&mut cursor)?; @@ -629,10 +627,10 @@ where } pub trait WriteXdr { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()>; - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn to_xdr(&self, limits: Limits) -> Result> { let mut cursor = Limited::new(Cursor::new(vec![]), limits); self.write_xdr(&mut cursor)?; @@ -654,13 +652,13 @@ pub trait WriteXdr { /// `Pad_len` returns the number of bytes to pad an XDR value of the given /// length to make the final serialized size a multiple of 4. -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] fn pad_len(len: usize) -> usize { (4 - (len % 4)) % 4 } impl ReadXdr for i32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -672,7 +670,7 @@ impl ReadXdr for i32 { } impl WriteXdr for i32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -683,7 +681,7 @@ impl WriteXdr for i32 { } impl ReadXdr for u32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -695,7 +693,7 @@ impl ReadXdr for u32 { } impl WriteXdr for u32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -706,7 +704,7 @@ impl WriteXdr for u32 { } impl ReadXdr for i64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -718,7 +716,7 @@ impl ReadXdr for i64 { } impl WriteXdr for i64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -729,7 +727,7 @@ impl WriteXdr for i64 { } impl ReadXdr for u64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -741,7 +739,7 @@ impl ReadXdr for u64 { } impl WriteXdr for u64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -752,35 +750,35 @@ impl WriteXdr for u64 { } impl ReadXdr for f32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for f64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for bool { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -791,7 +789,7 @@ impl ReadXdr for bool { } impl WriteXdr for bool { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i = u32::from(*self); // true = 1, false = 0 @@ -801,7 +799,7 @@ impl WriteXdr for bool { } impl ReadXdr for Option { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -818,7 +816,7 @@ impl ReadXdr for Option { } impl WriteXdr for Option { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { if let Some(t) = self { @@ -833,35 +831,35 @@ impl WriteXdr for Option { } impl ReadXdr for Box { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| Ok(Box::new(T::read_xdr(r)?))) } } impl WriteXdr for Box { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| T::write_xdr(self, w)) } } impl ReadXdr for () { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(_r: &mut Limited) -> Result { Ok(()) } } impl WriteXdr for () { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { Ok(()) } } impl ReadXdr for [u8; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { r.consume_len(N)?; @@ -880,7 +878,7 @@ impl ReadXdr for [u8; N] { } impl WriteXdr for [u8; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { w.consume_len(N)?; @@ -894,7 +892,7 @@ impl WriteXdr for [u8; N] { } impl ReadXdr for [T; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let mut vec = Vec::with_capacity(N); @@ -909,7 +907,7 @@ impl ReadXdr for [T; N] { } impl WriteXdr for [T; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { for t in self { @@ -1268,7 +1266,7 @@ impl<'a, const MAX: u32> TryFrom<&'a VecM> for &'a str { } impl ReadXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1295,7 +1293,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1315,7 +1313,7 @@ impl WriteXdr for VecM { } impl ReadXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len = u32::read_xdr(r)?; @@ -1335,7 +1333,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1708,7 +1706,7 @@ impl<'a, const MAX: u32> TryFrom<&'a BytesM> for &'a str { } impl ReadXdr for BytesM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1735,7 +1733,7 @@ impl ReadXdr for BytesM { } impl WriteXdr for BytesM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2111,7 +2109,7 @@ impl<'a, const MAX: u32> TryFrom<&'a StringM> for &'a str { } impl ReadXdr for StringM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -2138,7 +2136,7 @@ impl ReadXdr for StringM { } impl WriteXdr for StringM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2184,7 +2182,7 @@ impl ReadXdr for Frame where T: ReadXdr, { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { // Read the frame header value that contains 1 flag-bit and a 33-bit length. // - The 1 flag bit is 0 when there are more frames for the same record. @@ -2204,7 +2202,7 @@ where } } -#[cfg(all(test, feature = "alloc"))] +#[cfg(all(test, any(feature = "std", feature = "embedded_io")))] mod tests { use super::*; @@ -2314,7 +2312,7 @@ mod tests { } } -#[cfg(all(test, feature = "alloc"))] +#[cfg(all(test, any(feature = "std", feature = "embedded_io")))] mod test { use super::*; @@ -2827,6 +2825,219 @@ mod test { } } +#[cfg(all(test, any(feature = "std", feature = "embedded_io")))] +mod test_io { + // We will use different IO libraries according to the feature, + // we hope the selected IO library can work as expected + + use super::*; + + #[test] + fn test_read_exact_success() { + let data = b"The quick brown fox jumps over the lazy dog."; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 19]; // Exactly the length of "The quick brown fox" + + // Attempt to read exactly 19 bytes + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"The quick brown fox"); + assert_eq!(cursor.position(), 19); + } + + #[test] + fn test_read_exact_less_than_available() { + let data = b"Hello, Rust!"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 5]; + + // Attempt to read 5 bytes from the start + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Hello"); + assert_eq!(cursor.position(), 5); + } + + #[test] + fn test_read_exact_exact_eof() { + let data = b"Data"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 4]; + + // Attempt to read exactly 4 bytes, which is the entire buffer + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Data"); + assert_eq!(cursor.position(), 4); + + // Further attempt to read should fail with EOF + let mut buffer_eof = [0u8; 1]; + let result = cursor.read_exact(&mut buffer_eof); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 4); // Position should remain at EOF + } + + #[test] + fn test_read_exact_past_eof() { + let data = b"Short"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 10]; // Requesting more bytes than available + + // Attempt to read 10 bytes from a 5-byte buffer + let result = cursor.read_exact(&mut buffer); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 5); // Position should move to EOF + } + + #[test] + fn test_read_exact_empty_buffer() { + let data = b"Non-empty"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 0]; // Zero-length buffer + + // Attempt to read zero bytes + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(cursor.position(), 0); // Position should remain unchanged + } + + #[test] + fn test_read_exact_from_empty_cursor() { + let data: &[u8] = b""; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 5]; + + // Attempt to read from an empty cursor + let result = cursor.read_exact(&mut buffer); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 0); // Position remains at 0 + } + + #[test] + fn test_read_exact_multiple_reads() { + let data = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + let mut cursor = Cursor::new(data); + + let mut buffer1 = [0u8; 10]; + let mut buffer2 = [0u8; 10]; + let mut buffer3 = [0u8; 10]; // Only 6 bytes left + + // First read: 10 bytes + assert!(cursor.read_exact(&mut buffer1).is_ok()); + assert_eq!(&buffer1, b"ABCDEFGHIJ"); + assert_eq!(cursor.position(), 10); + + // Second read: 10 bytes + assert!(cursor.read_exact(&mut buffer2).is_ok()); + assert_eq!(&buffer2, b"KLMNOPQRST"); + assert_eq!(cursor.position(), 20); + + // Third read: Attempt to read 10 bytes, but only 6 are available + let result = cursor.read_exact(&mut buffer3); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + // read_exact makes no promises about the content of the buffer on error + // assert_eq!(&buffer3[..6], b"UVWXYZ"); + assert_eq!(cursor.position(), 26); // Position should be at EOF + } + + #[test] + fn test_cursor_read_exact_after_eof() { + let data = b"End"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 3]; + + // First read: read the entire buffer + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"End"); + assert_eq!(cursor.position(), 3); + + // Second read: attempt to read again, should fail + let mut buffer_eof = [0u8; 1]; + let result = cursor.read_exact(&mut buffer_eof); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 3); // Position remains at EOF + } + + #[test] + fn test_slice_read_exact_success() { + let data = b"SliceReadTest"; + let mut slice = &data[..]; + let mut buffer = [0u8; 13]; // Exact length + + // Using Read trait directly on slice + assert!(slice.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"SliceReadTest"); + } + + #[test] + fn test_slice_read_exact_partial() { + let data = b"SlicePartial"; + let mut slice = &data[..]; + let mut buffer = [0u8; 20]; // Request more bytes than available + + // Using Read trait directly on slice + let result = slice.read_exact(&mut buffer); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + // read_exact makes no promises about the content of the buffer on error + } +} + /// Uint512 is an XDR Typedef defines as: /// /// ```text @@ -2921,7 +3132,7 @@ impl AsRef<[u8; 64]> for Uint512 { } impl ReadXdr for Uint512 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = <[u8; 64]>::read_xdr(r)?; @@ -2932,7 +3143,7 @@ impl ReadXdr for Uint512 { } impl WriteXdr for Uint512 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w|{ self.0.write_xdr(w) }) } @@ -3011,7 +3222,7 @@ impl AsRef> for Uint513 { } impl ReadXdr for Uint513 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = BytesM::<64>::read_xdr(r)?; @@ -3022,7 +3233,7 @@ impl ReadXdr for Uint513 { } impl WriteXdr for Uint513 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w|{ self.0.write_xdr(w) }) } @@ -3113,7 +3324,7 @@ impl AsRef for Uint514 { } impl ReadXdr for Uint514 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = BytesM::read_xdr(r)?; @@ -3124,7 +3335,7 @@ impl ReadXdr for Uint514 { } impl WriteXdr for Uint514 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w|{ self.0.write_xdr(w) }) } @@ -3215,7 +3426,7 @@ impl AsRef> for Str { } impl ReadXdr for Str { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = StringM::<64>::read_xdr(r)?; @@ -3226,7 +3437,7 @@ impl ReadXdr for Str { } impl WriteXdr for Str { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w|{ self.0.write_xdr(w) }) } @@ -3317,7 +3528,7 @@ impl AsRef for Str2 { } impl ReadXdr for Str2 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = StringM::read_xdr(r)?; @@ -3328,7 +3539,7 @@ impl ReadXdr for Str2 { } impl WriteXdr for Str2 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w|{ self.0.write_xdr(w) }) } @@ -3477,7 +3688,7 @@ impl AsRef<[u8; 32]> for Hash { } impl ReadXdr for Hash { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = <[u8; 32]>::read_xdr(r)?; @@ -3488,7 +3699,7 @@ impl ReadXdr for Hash { } impl WriteXdr for Hash { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w|{ self.0.write_xdr(w) }) } @@ -3566,7 +3777,7 @@ impl AsRef<[Hash; 12]> for Hashes1 { } impl ReadXdr for Hashes1 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = <[Hash; 12]>::read_xdr(r)?; @@ -3577,7 +3788,7 @@ impl ReadXdr for Hashes1 { } impl WriteXdr for Hashes1 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w|{ self.0.write_xdr(w) }) } @@ -3656,7 +3867,7 @@ impl AsRef> for Hashes2 { } impl ReadXdr for Hashes2 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = VecM::::read_xdr(r)?; @@ -3667,7 +3878,7 @@ impl ReadXdr for Hashes2 { } impl WriteXdr for Hashes2 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w|{ self.0.write_xdr(w) }) } @@ -3758,7 +3969,7 @@ impl AsRef> for Hashes3 { } impl ReadXdr for Hashes3 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = VecM::::read_xdr(r)?; @@ -3769,7 +3980,7 @@ impl ReadXdr for Hashes3 { } impl WriteXdr for Hashes3 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w|{ self.0.write_xdr(w) }) } @@ -3859,7 +4070,7 @@ impl AsRef> for OptHash1 { } impl ReadXdr for OptHash1 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = Option::::read_xdr(r)?; @@ -3870,7 +4081,7 @@ impl ReadXdr for OptHash1 { } impl WriteXdr for OptHash1 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w|{ self.0.write_xdr(w) }) } @@ -3911,7 +4122,7 @@ impl AsRef> for OptHash2 { } impl ReadXdr for OptHash2 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = Option::::read_xdr(r)?; @@ -3922,7 +4133,7 @@ impl ReadXdr for OptHash2 { } impl WriteXdr for OptHash2 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w|{ self.0.write_xdr(w) }) } @@ -3990,7 +4201,7 @@ pub struct MyStruct { } impl ReadXdr for MyStruct { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { Ok(Self{ @@ -4007,7 +4218,7 @@ field7: bool::read_xdr(r)?, } impl WriteXdr for MyStruct { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { self.field1.write_xdr(w)?; @@ -4040,7 +4251,7 @@ pub struct LotsOfMyStructs { } impl ReadXdr for LotsOfMyStructs { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { Ok(Self{ @@ -4051,7 +4262,7 @@ impl ReadXdr for LotsOfMyStructs { } impl WriteXdr for LotsOfMyStructs { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { self.members.write_xdr(w)?; @@ -4078,7 +4289,7 @@ pub struct HasStuff { } impl ReadXdr for HasStuff { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { Ok(Self{ @@ -4089,7 +4300,7 @@ impl ReadXdr for HasStuff { } impl WriteXdr for HasStuff { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { self.data.write_xdr(w)?; @@ -4187,7 +4398,7 @@ Self::Green => "Green", } impl ReadXdr for Color { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let e = i32::read_xdr(r)?; @@ -4198,7 +4409,7 @@ Self::Green => "Green", } impl WriteXdr for Color { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i: i32 = (*self).into(); @@ -4306,7 +4517,7 @@ Self::B2 => "B2", } impl ReadXdr for NesterNestedEnum { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let e = i32::read_xdr(r)?; @@ -4317,7 +4528,7 @@ Self::B2 => "B2", } impl WriteXdr for NesterNestedEnum { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i: i32 = (*self).into(); @@ -4343,7 +4554,7 @@ pub struct NesterNestedStruct { } impl ReadXdr for NesterNestedStruct { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { Ok(Self{ @@ -4354,7 +4565,7 @@ impl ReadXdr for NesterNestedStruct { } impl WriteXdr for NesterNestedStruct { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { self.blah.write_xdr(w)?; @@ -4436,7 +4647,7 @@ impl Variants for NesterNestedUnion { impl Union for NesterNestedUnion {} impl ReadXdr for NesterNestedUnion { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let dv: Color = ::read_xdr(r)?; @@ -4452,7 +4663,7 @@ impl ReadXdr for NesterNestedUnion { } impl WriteXdr for NesterNestedUnion { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { self.discriminant().write_xdr(w)?; @@ -4501,7 +4712,7 @@ pub struct Nester { } impl ReadXdr for Nester { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { Ok(Self{ @@ -4514,7 +4725,7 @@ nested_union: NesterNestedUnion::read_xdr(r)?, } impl WriteXdr for Nester { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { self.nested_enum.write_xdr(w)?; @@ -4802,7 +5013,7 @@ TypeVariant::NesterNestedUnion, ]; "NesterNestedStruct", "NesterNestedUnion", ]; - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] #[allow(clippy::too_many_lines)] pub fn read_xdr(v: TypeVariant, r: &mut Limited) -> Result { match v { @@ -4839,7 +5050,7 @@ TypeVariant::NesterNestedUnion => r.with_limited_depth(|r| Ok(Self::NesterNested Ok(t) } - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] pub fn read_xdr_to_end(v: TypeVariant, r: &mut Limited) -> Result { let s = Self::read_xdr(v, r)?; // Check that any further reads, such as this read of one byte, read no @@ -4949,7 +5160,7 @@ TypeVariant::NesterNestedUnion => Box::new(ReadXdrIter::<_, NesterNestedUnion>:: } } - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] pub fn from_xdr>(v: TypeVariant, bytes: B, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(v, &mut cursor)?; @@ -5143,7 +5354,7 @@ Self::NesterNestedUnion(_) => TypeVariant::NesterNestedUnion, } impl WriteXdr for Type { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] #[allow(clippy::too_many_lines)] fn write_xdr(&self, w: &mut Limited) -> Result<()> { match self { diff --git a/spec/output/generator_spec_rust_custom_str_impls/union.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_str_impls/union.x/MyXDR.rs index 853087ece..5503c2897 100644 --- a/spec/output/generator_spec_rust_custom_str_impls/union.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_str_impls/union.x/MyXDR.rs @@ -50,7 +50,7 @@ use std::{ io::{BufRead, BufReader, Cursor, Read, Write}, }; -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] use embedded_io_extras::{Cursor, Error as _, ErrorType, Read, Write}; /// Error contains all errors returned by functions in this crate. It can be @@ -68,7 +68,7 @@ pub enum Error { InvalidHex, #[cfg(feature = "std")] Io(io::Error), - #[cfg(all(not(feature = "std"), feature = "alloc"))] + #[cfg(feature = "embedded_io")] Io(embedded_io_extras::ErrorKind), DepthLimitExceeded, #[cfg(feature = "serde_json")] @@ -86,15 +86,14 @@ impl PartialEq for Error { // case for comparing errors outputted by the XDR library is for // error case testing, and a lack of the ability to compare has a // detrimental affect on failure testing, so this is a tradeoff. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] (Self::Io(l), Self::Io(r)) => l.kind() == r.kind(), _ => core::mem::discriminant(self) == core::mem::discriminant(other), } } } - -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl embedded_io_extras::Error for Error { fn kind(&self) -> embedded_io_extras::ErrorKind { match self { @@ -104,7 +103,7 @@ impl embedded_io_extras::Error for Error { } } -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl From> for Error { fn from(value: embedded_io_extras::ReadExactError) -> Self { match value { @@ -140,7 +139,7 @@ impl fmt::Display for Error { Error::InvalidHex => write!(f, "hex invalid"), #[cfg(feature = "std")] Error::Io(e) => write!(f, "{e}"), - #[cfg(all(not(feature = "std"), feature = "alloc"))] + #[cfg(feature = "embedded_io")] Error::Io(_) => write!(f, "io error"), Error::DepthLimitExceeded => write!(f, "depth limit exceeded"), #[cfg(feature = "serde_json")] @@ -194,7 +193,7 @@ impl From for () { #[allow(dead_code)] type Result = core::result::Result; -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl ErrorType for Limited { type Error = Error; } /// Name defines types that assign a static name to their value, such as the @@ -230,7 +229,7 @@ where /// `Limits` contains the limits that a limited reader or writer will be /// constrained to. -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] #[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct Limits { /// Defines the maximum depth for recursive calls in `Read/WriteXdr` to @@ -247,7 +246,7 @@ pub struct Limits { pub len: usize, } -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] impl Limits { #[must_use] pub fn none() -> Self { @@ -278,13 +277,13 @@ impl Limits { /// /// Intended for use with readers and writers and limiting their reads and /// writes. -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] pub struct Limited { pub inner: L, pub(crate) limits: Limits, } -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] impl Limited { /// Constructs a new `Limited`. /// @@ -337,8 +336,7 @@ impl Read for Limited { } } - -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl Read for Limited { /// Forwards the read operation to the wrapped object. fn read(&mut self, buf: &mut [u8]) -> core::result::Result { @@ -372,7 +370,7 @@ impl Write for Limited { } } -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(feature = "embedded_io")] impl Write for Limited { /// Forwards the write operation to the wrapped object. fn write(&mut self, buf: &[u8]) -> core::result::Result { @@ -457,7 +455,7 @@ where /// /// Use [`ReadXdR: Read_xdr_to_end`] when the intent is for all bytes in the /// read implementation to be consumed by the read. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result; /// Construct the type from the XDR bytes base64 encoded. @@ -492,7 +490,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr_to_end(r: &mut Limited) -> Result { let s = Self::read_xdr(r)?; // Check that any further reads, such as this read of one byte, read no @@ -532,7 +530,7 @@ where /// /// Use [`ReadXdR: Read_xdr_into_to_end`] when the intent is for all bytes /// in the read implementation to be consumed by the read. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr_into(&mut self, r: &mut Limited) -> Result<()> { *self = Self::read_xdr(r)?; Ok(()) @@ -556,7 +554,7 @@ where /// /// All implementations should continue if the read implementation returns /// [`ErrorKind::Interrupted`](std::io::ErrorKind::Interrupted). - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr_into_to_end(&mut self, r: &mut Limited) -> Result<()> { Self::read_xdr_into(self, r)?; // Check that any further reads, such as this read of one byte, read no @@ -605,7 +603,7 @@ where /// /// An error is returned if the bytes are not completely consumed by the /// deserialization. - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn from_xdr(bytes: impl AsRef<[u8]>, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(&mut cursor)?; @@ -629,10 +627,10 @@ where } pub trait WriteXdr { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()>; - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn to_xdr(&self, limits: Limits) -> Result> { let mut cursor = Limited::new(Cursor::new(vec![]), limits); self.write_xdr(&mut cursor)?; @@ -654,13 +652,13 @@ pub trait WriteXdr { /// `Pad_len` returns the number of bytes to pad an XDR value of the given /// length to make the final serialized size a multiple of 4. -#[cfg(feature = "alloc")] +#[cfg(any(feature = "std", feature = "embedded_io"))] fn pad_len(len: usize) -> usize { (4 - (len % 4)) % 4 } impl ReadXdr for i32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -672,7 +670,7 @@ impl ReadXdr for i32 { } impl WriteXdr for i32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -683,7 +681,7 @@ impl WriteXdr for i32 { } impl ReadXdr for u32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 4]; r.with_limited_depth(|r| { @@ -695,7 +693,7 @@ impl ReadXdr for u32 { } impl WriteXdr for u32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 4] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -706,7 +704,7 @@ impl WriteXdr for u32 { } impl ReadXdr for i64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -718,7 +716,7 @@ impl ReadXdr for i64 { } impl WriteXdr for i64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -729,7 +727,7 @@ impl WriteXdr for i64 { } impl ReadXdr for u64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { let mut b = [0u8; 8]; r.with_limited_depth(|r| { @@ -741,7 +739,7 @@ impl ReadXdr for u64 { } impl WriteXdr for u64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { let b: [u8; 8] = self.to_be_bytes(); w.with_limited_depth(|w| { @@ -752,35 +750,35 @@ impl WriteXdr for u64 { } impl ReadXdr for f32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f32 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for f64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(_r: &mut Limited) -> Result { todo!() } } impl WriteXdr for f64 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { todo!() } } impl ReadXdr for bool { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -791,7 +789,7 @@ impl ReadXdr for bool { } impl WriteXdr for bool { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i = u32::from(*self); // true = 1, false = 0 @@ -801,7 +799,7 @@ impl WriteXdr for bool { } impl ReadXdr for Option { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = u32::read_xdr(r)?; @@ -818,7 +816,7 @@ impl ReadXdr for Option { } impl WriteXdr for Option { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { if let Some(t) = self { @@ -833,35 +831,35 @@ impl WriteXdr for Option { } impl ReadXdr for Box { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| Ok(Box::new(T::read_xdr(r)?))) } } impl WriteXdr for Box { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| T::write_xdr(self, w)) } } impl ReadXdr for () { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(_r: &mut Limited) -> Result { Ok(()) } } impl WriteXdr for () { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, _w: &mut Limited) -> Result<()> { Ok(()) } } impl ReadXdr for [u8; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { r.consume_len(N)?; @@ -880,7 +878,7 @@ impl ReadXdr for [u8; N] { } impl WriteXdr for [u8; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { w.consume_len(N)?; @@ -894,7 +892,7 @@ impl WriteXdr for [u8; N] { } impl ReadXdr for [T; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let mut vec = Vec::with_capacity(N); @@ -909,7 +907,7 @@ impl ReadXdr for [T; N] { } impl WriteXdr for [T; N] { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { for t in self { @@ -1268,7 +1266,7 @@ impl<'a, const MAX: u32> TryFrom<&'a VecM> for &'a str { } impl ReadXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1295,7 +1293,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1315,7 +1313,7 @@ impl WriteXdr for VecM { } impl ReadXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len = u32::read_xdr(r)?; @@ -1335,7 +1333,7 @@ impl ReadXdr for VecM { } impl WriteXdr for VecM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1708,7 +1706,7 @@ impl<'a, const MAX: u32> TryFrom<&'a BytesM> for &'a str { } impl ReadXdr for BytesM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -1735,7 +1733,7 @@ impl ReadXdr for BytesM { } impl WriteXdr for BytesM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2111,7 +2109,7 @@ impl<'a, const MAX: u32> TryFrom<&'a StringM> for &'a str { } impl ReadXdr for StringM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let len: u32 = u32::read_xdr(r)?; @@ -2138,7 +2136,7 @@ impl ReadXdr for StringM { } impl WriteXdr for StringM { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -2184,7 +2182,7 @@ impl ReadXdr for Frame where T: ReadXdr, { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { // Read the frame header value that contains 1 flag-bit and a 33-bit length. // - The 1 flag bit is 0 when there are more frames for the same record. @@ -2204,7 +2202,7 @@ where } } -#[cfg(all(test, feature = "alloc"))] +#[cfg(all(test, any(feature = "std", feature = "embedded_io")))] mod tests { use super::*; @@ -2314,7 +2312,7 @@ mod tests { } } -#[cfg(all(test, feature = "alloc"))] +#[cfg(all(test, any(feature = "std", feature = "embedded_io")))] mod test { use super::*; @@ -2827,6 +2825,219 @@ mod test { } } +#[cfg(all(test, any(feature = "std", feature = "embedded_io")))] +mod test_io { + // We will use different IO libraries according to the feature, + // we hope the selected IO library can work as expected + + use super::*; + + #[test] + fn test_read_exact_success() { + let data = b"The quick brown fox jumps over the lazy dog."; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 19]; // Exactly the length of "The quick brown fox" + + // Attempt to read exactly 19 bytes + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"The quick brown fox"); + assert_eq!(cursor.position(), 19); + } + + #[test] + fn test_read_exact_less_than_available() { + let data = b"Hello, Rust!"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 5]; + + // Attempt to read 5 bytes from the start + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Hello"); + assert_eq!(cursor.position(), 5); + } + + #[test] + fn test_read_exact_exact_eof() { + let data = b"Data"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 4]; + + // Attempt to read exactly 4 bytes, which is the entire buffer + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Data"); + assert_eq!(cursor.position(), 4); + + // Further attempt to read should fail with EOF + let mut buffer_eof = [0u8; 1]; + let result = cursor.read_exact(&mut buffer_eof); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 4); // Position should remain at EOF + } + + #[test] + fn test_read_exact_past_eof() { + let data = b"Short"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 10]; // Requesting more bytes than available + + // Attempt to read 10 bytes from a 5-byte buffer + let result = cursor.read_exact(&mut buffer); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 5); // Position should move to EOF + } + + #[test] + fn test_read_exact_empty_buffer() { + let data = b"Non-empty"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 0]; // Zero-length buffer + + // Attempt to read zero bytes + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(cursor.position(), 0); // Position should remain unchanged + } + + #[test] + fn test_read_exact_from_empty_cursor() { + let data: &[u8] = b""; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 5]; + + // Attempt to read from an empty cursor + let result = cursor.read_exact(&mut buffer); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 0); // Position remains at 0 + } + + #[test] + fn test_read_exact_multiple_reads() { + let data = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + let mut cursor = Cursor::new(data); + + let mut buffer1 = [0u8; 10]; + let mut buffer2 = [0u8; 10]; + let mut buffer3 = [0u8; 10]; // Only 6 bytes left + + // First read: 10 bytes + assert!(cursor.read_exact(&mut buffer1).is_ok()); + assert_eq!(&buffer1, b"ABCDEFGHIJ"); + assert_eq!(cursor.position(), 10); + + // Second read: 10 bytes + assert!(cursor.read_exact(&mut buffer2).is_ok()); + assert_eq!(&buffer2, b"KLMNOPQRST"); + assert_eq!(cursor.position(), 20); + + // Third read: Attempt to read 10 bytes, but only 6 are available + let result = cursor.read_exact(&mut buffer3); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + // read_exact makes no promises about the content of the buffer on error + // assert_eq!(&buffer3[..6], b"UVWXYZ"); + assert_eq!(cursor.position(), 26); // Position should be at EOF + } + + #[test] + fn test_cursor_read_exact_after_eof() { + let data = b"End"; + let mut cursor = Cursor::new(data); + let mut buffer = [0u8; 3]; + + // First read: read the entire buffer + assert!(cursor.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"End"); + assert_eq!(cursor.position(), 3); + + // Second read: attempt to read again, should fail + let mut buffer_eof = [0u8; 1]; + let result = cursor.read_exact(&mut buffer_eof); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + assert_eq!(cursor.position(), 3); // Position remains at EOF + } + + #[test] + fn test_slice_read_exact_success() { + let data = b"SliceReadTest"; + let mut slice = &data[..]; + let mut buffer = [0u8; 13]; // Exact length + + // Using Read trait directly on slice + assert!(slice.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"SliceReadTest"); + } + + #[test] + fn test_slice_read_exact_partial() { + let data = b"SlicePartial"; + let mut slice = &data[..]; + let mut buffer = [0u8; 20]; // Request more bytes than available + + // Using Read trait directly on slice + let result = slice.read_exact(&mut buffer); + assert!(result.is_err()); + #[cfg(feature = "std")] + assert_eq!( + result.unwrap_err().kind(), + std::io::ErrorKind::UnexpectedEof + ); + #[cfg(feature = "embedded_io")] + assert_eq!( + result.unwrap_err(), + embedded_io_extras::ReadExactError::UnexpectedEof + ); + // read_exact makes no promises about the content of the buffer on error + } +} + /// SError is an XDR Typedef defines as: /// /// ```text @@ -2926,7 +3137,7 @@ Self::Multi => "Multi", } impl ReadXdr for UnionKey { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let e = i32::read_xdr(r)?; @@ -2937,7 +3148,7 @@ Self::Multi => "Multi", } impl WriteXdr for UnionKey { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { let i: i32 = (*self).into(); @@ -3027,7 +3238,7 @@ Self::Multi(_) => UnionKey::Multi, impl Union for MyUnion {} impl ReadXdr for MyUnion { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let dv: UnionKey = ::read_xdr(r)?; @@ -3044,7 +3255,7 @@ UnionKey::Multi => Self::Multi(VecM::::read_xdr(r)?), } impl WriteXdr for MyUnion { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { self.discriminant().write_xdr(w)?; @@ -3138,7 +3349,7 @@ Self::V1(_) => 1, impl Union for IntUnion {} impl ReadXdr for IntUnion { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let dv: i32 = ::read_xdr(r)?; @@ -3155,7 +3366,7 @@ Self::V1(_) => 1, } impl WriteXdr for IntUnion { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w| { self.discriminant().write_xdr(w)?; @@ -3204,7 +3415,7 @@ impl AsRef for IntUnion2 { } impl ReadXdr for IntUnion2 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn read_xdr(r: &mut Limited) -> Result { r.with_limited_depth(|r| { let i = IntUnion::read_xdr(r)?; @@ -3215,7 +3426,7 @@ impl ReadXdr for IntUnion2 { } impl WriteXdr for IntUnion2 { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] fn write_xdr(&self, w: &mut Limited) -> Result<()> { w.with_limited_depth(|w|{ self.0.write_xdr(w) }) } @@ -3345,7 +3556,7 @@ TypeVariant::IntUnion2, ]; "IntUnion", "IntUnion2", ]; - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] #[allow(clippy::too_many_lines)] pub fn read_xdr(v: TypeVariant, r: &mut Limited) -> Result { match v { @@ -3365,7 +3576,7 @@ TypeVariant::IntUnion2 => r.with_limited_depth(|r| Ok(Self::IntUnion2(Box::new(I Ok(t) } - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] pub fn read_xdr_to_end(v: TypeVariant, r: &mut Limited) -> Result { let s = Self::read_xdr(v, r)?; // Check that any further reads, such as this read of one byte, read no @@ -3424,7 +3635,7 @@ TypeVariant::IntUnion2 => Box::new(ReadXdrIter::<_, IntUnion2>::new(dec, r.limit } } - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] pub fn from_xdr>(v: TypeVariant, bytes: B, limits: Limits) -> Result { let mut cursor = Limited::new(Cursor::new(bytes.as_ref()), limits); let t = Self::read_xdr_to_end(v, &mut cursor)?; @@ -3533,7 +3744,7 @@ Self::IntUnion2(_) => TypeVariant::IntUnion2, } impl WriteXdr for Type { - #[cfg(feature = "alloc")] + #[cfg(any(feature = "std", feature = "embedded_io"))] #[allow(clippy::too_many_lines)] fn write_xdr(&self, w: &mut Limited) -> Result<()> { match self { From d7b6f935e7c026901a7d9958e5700a8caca344f8 Mon Sep 17 00:00:00 2001 From: Jun Luo <4catcode@gmail.com> Date: Sat, 21 Sep 2024 10:46:08 +0800 Subject: [PATCH 6/9] add todo --- lib/xdrgen/generators/rust/src/types.rs | 1 + spec/output/generator_spec_rust/block_comments.x/MyXDR.rs | 1 + spec/output/generator_spec_rust/const.x/MyXDR.rs | 1 + spec/output/generator_spec_rust/enum.x/MyXDR.rs | 1 + spec/output/generator_spec_rust/nesting.x/MyXDR.rs | 1 + spec/output/generator_spec_rust/optional.x/MyXDR.rs | 1 + spec/output/generator_spec_rust/struct.x/MyXDR.rs | 1 + spec/output/generator_spec_rust/test.x/MyXDR.rs | 1 + spec/output/generator_spec_rust/union.x/MyXDR.rs | 1 + .../block_comments.x/MyXDR.rs | 1 + .../generator_spec_rust_custom_jsonschema_impls/const.x/MyXDR.rs | 1 + .../generator_spec_rust_custom_jsonschema_impls/enum.x/MyXDR.rs | 1 + .../nesting.x/MyXDR.rs | 1 + .../optional.x/MyXDR.rs | 1 + .../struct.x/MyXDR.rs | 1 + .../generator_spec_rust_custom_jsonschema_impls/test.x/MyXDR.rs | 1 + .../generator_spec_rust_custom_jsonschema_impls/union.x/MyXDR.rs | 1 + .../block_comments.x/MyXDR.rs | 1 + .../output/generator_spec_rust_custom_str_impls/const.x/MyXDR.rs | 1 + spec/output/generator_spec_rust_custom_str_impls/enum.x/MyXDR.rs | 1 + .../generator_spec_rust_custom_str_impls/nesting.x/MyXDR.rs | 1 + .../generator_spec_rust_custom_str_impls/optional.x/MyXDR.rs | 1 + .../generator_spec_rust_custom_str_impls/struct.x/MyXDR.rs | 1 + spec/output/generator_spec_rust_custom_str_impls/test.x/MyXDR.rs | 1 + .../output/generator_spec_rust_custom_str_impls/union.x/MyXDR.rs | 1 + 25 files changed, 25 insertions(+) diff --git a/lib/xdrgen/generators/rust/src/types.rs b/lib/xdrgen/generators/rust/src/types.rs index 73313bd1d..648f1f9d4 100644 --- a/lib/xdrgen/generators/rust/src/types.rs +++ b/lib/xdrgen/generators/rust/src/types.rs @@ -97,6 +97,7 @@ impl embedded_io_extras::Error for Error { impl From> for Error { fn from(value: embedded_io_extras::ReadExactError) -> Self { match value { + // TODO: maybe we should map the error to a more specific error? embedded_io_extras::ReadExactError::UnexpectedEof => Error::Io(embedded_io_extras::ErrorKind::Other), embedded_io_extras::ReadExactError::Other(e) => e } diff --git a/spec/output/generator_spec_rust/block_comments.x/MyXDR.rs b/spec/output/generator_spec_rust/block_comments.x/MyXDR.rs index b219d1dd8..a3409c6aa 100644 --- a/spec/output/generator_spec_rust/block_comments.x/MyXDR.rs +++ b/spec/output/generator_spec_rust/block_comments.x/MyXDR.rs @@ -107,6 +107,7 @@ impl embedded_io_extras::Error for Error { impl From> for Error { fn from(value: embedded_io_extras::ReadExactError) -> Self { match value { + // TODO: maybe we should map the error to a more specific error? embedded_io_extras::ReadExactError::UnexpectedEof => Error::Io(embedded_io_extras::ErrorKind::Other), embedded_io_extras::ReadExactError::Other(e) => e } diff --git a/spec/output/generator_spec_rust/const.x/MyXDR.rs b/spec/output/generator_spec_rust/const.x/MyXDR.rs index fbe2a13d8..968379ae7 100644 --- a/spec/output/generator_spec_rust/const.x/MyXDR.rs +++ b/spec/output/generator_spec_rust/const.x/MyXDR.rs @@ -107,6 +107,7 @@ impl embedded_io_extras::Error for Error { impl From> for Error { fn from(value: embedded_io_extras::ReadExactError) -> Self { match value { + // TODO: maybe we should map the error to a more specific error? embedded_io_extras::ReadExactError::UnexpectedEof => Error::Io(embedded_io_extras::ErrorKind::Other), embedded_io_extras::ReadExactError::Other(e) => e } diff --git a/spec/output/generator_spec_rust/enum.x/MyXDR.rs b/spec/output/generator_spec_rust/enum.x/MyXDR.rs index 598a798fb..ac734778f 100644 --- a/spec/output/generator_spec_rust/enum.x/MyXDR.rs +++ b/spec/output/generator_spec_rust/enum.x/MyXDR.rs @@ -107,6 +107,7 @@ impl embedded_io_extras::Error for Error { impl From> for Error { fn from(value: embedded_io_extras::ReadExactError) -> Self { match value { + // TODO: maybe we should map the error to a more specific error? embedded_io_extras::ReadExactError::UnexpectedEof => Error::Io(embedded_io_extras::ErrorKind::Other), embedded_io_extras::ReadExactError::Other(e) => e } diff --git a/spec/output/generator_spec_rust/nesting.x/MyXDR.rs b/spec/output/generator_spec_rust/nesting.x/MyXDR.rs index be4ca56e5..277e993d3 100644 --- a/spec/output/generator_spec_rust/nesting.x/MyXDR.rs +++ b/spec/output/generator_spec_rust/nesting.x/MyXDR.rs @@ -107,6 +107,7 @@ impl embedded_io_extras::Error for Error { impl From> for Error { fn from(value: embedded_io_extras::ReadExactError) -> Self { match value { + // TODO: maybe we should map the error to a more specific error? embedded_io_extras::ReadExactError::UnexpectedEof => Error::Io(embedded_io_extras::ErrorKind::Other), embedded_io_extras::ReadExactError::Other(e) => e } diff --git a/spec/output/generator_spec_rust/optional.x/MyXDR.rs b/spec/output/generator_spec_rust/optional.x/MyXDR.rs index fbc4a1bf2..1b20720a6 100644 --- a/spec/output/generator_spec_rust/optional.x/MyXDR.rs +++ b/spec/output/generator_spec_rust/optional.x/MyXDR.rs @@ -107,6 +107,7 @@ impl embedded_io_extras::Error for Error { impl From> for Error { fn from(value: embedded_io_extras::ReadExactError) -> Self { match value { + // TODO: maybe we should map the error to a more specific error? embedded_io_extras::ReadExactError::UnexpectedEof => Error::Io(embedded_io_extras::ErrorKind::Other), embedded_io_extras::ReadExactError::Other(e) => e } diff --git a/spec/output/generator_spec_rust/struct.x/MyXDR.rs b/spec/output/generator_spec_rust/struct.x/MyXDR.rs index 908fed8d5..2a1e97fd3 100644 --- a/spec/output/generator_spec_rust/struct.x/MyXDR.rs +++ b/spec/output/generator_spec_rust/struct.x/MyXDR.rs @@ -107,6 +107,7 @@ impl embedded_io_extras::Error for Error { impl From> for Error { fn from(value: embedded_io_extras::ReadExactError) -> Self { match value { + // TODO: maybe we should map the error to a more specific error? embedded_io_extras::ReadExactError::UnexpectedEof => Error::Io(embedded_io_extras::ErrorKind::Other), embedded_io_extras::ReadExactError::Other(e) => e } diff --git a/spec/output/generator_spec_rust/test.x/MyXDR.rs b/spec/output/generator_spec_rust/test.x/MyXDR.rs index 95ab6e44b..212f498f2 100644 --- a/spec/output/generator_spec_rust/test.x/MyXDR.rs +++ b/spec/output/generator_spec_rust/test.x/MyXDR.rs @@ -107,6 +107,7 @@ impl embedded_io_extras::Error for Error { impl From> for Error { fn from(value: embedded_io_extras::ReadExactError) -> Self { match value { + // TODO: maybe we should map the error to a more specific error? embedded_io_extras::ReadExactError::UnexpectedEof => Error::Io(embedded_io_extras::ErrorKind::Other), embedded_io_extras::ReadExactError::Other(e) => e } diff --git a/spec/output/generator_spec_rust/union.x/MyXDR.rs b/spec/output/generator_spec_rust/union.x/MyXDR.rs index ae06d165a..7754e5301 100644 --- a/spec/output/generator_spec_rust/union.x/MyXDR.rs +++ b/spec/output/generator_spec_rust/union.x/MyXDR.rs @@ -107,6 +107,7 @@ impl embedded_io_extras::Error for Error { impl From> for Error { fn from(value: embedded_io_extras::ReadExactError) -> Self { match value { + // TODO: maybe we should map the error to a more specific error? embedded_io_extras::ReadExactError::UnexpectedEof => Error::Io(embedded_io_extras::ErrorKind::Other), embedded_io_extras::ReadExactError::Other(e) => e } diff --git a/spec/output/generator_spec_rust_custom_jsonschema_impls/block_comments.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_jsonschema_impls/block_comments.x/MyXDR.rs index b219d1dd8..a3409c6aa 100644 --- a/spec/output/generator_spec_rust_custom_jsonschema_impls/block_comments.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_jsonschema_impls/block_comments.x/MyXDR.rs @@ -107,6 +107,7 @@ impl embedded_io_extras::Error for Error { impl From> for Error { fn from(value: embedded_io_extras::ReadExactError) -> Self { match value { + // TODO: maybe we should map the error to a more specific error? embedded_io_extras::ReadExactError::UnexpectedEof => Error::Io(embedded_io_extras::ErrorKind::Other), embedded_io_extras::ReadExactError::Other(e) => e } diff --git a/spec/output/generator_spec_rust_custom_jsonschema_impls/const.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_jsonschema_impls/const.x/MyXDR.rs index fbe2a13d8..968379ae7 100644 --- a/spec/output/generator_spec_rust_custom_jsonschema_impls/const.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_jsonschema_impls/const.x/MyXDR.rs @@ -107,6 +107,7 @@ impl embedded_io_extras::Error for Error { impl From> for Error { fn from(value: embedded_io_extras::ReadExactError) -> Self { match value { + // TODO: maybe we should map the error to a more specific error? embedded_io_extras::ReadExactError::UnexpectedEof => Error::Io(embedded_io_extras::ErrorKind::Other), embedded_io_extras::ReadExactError::Other(e) => e } diff --git a/spec/output/generator_spec_rust_custom_jsonschema_impls/enum.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_jsonschema_impls/enum.x/MyXDR.rs index 5585727d9..1d0ba7c58 100644 --- a/spec/output/generator_spec_rust_custom_jsonschema_impls/enum.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_jsonschema_impls/enum.x/MyXDR.rs @@ -107,6 +107,7 @@ impl embedded_io_extras::Error for Error { impl From> for Error { fn from(value: embedded_io_extras::ReadExactError) -> Self { match value { + // TODO: maybe we should map the error to a more specific error? embedded_io_extras::ReadExactError::UnexpectedEof => Error::Io(embedded_io_extras::ErrorKind::Other), embedded_io_extras::ReadExactError::Other(e) => e } diff --git a/spec/output/generator_spec_rust_custom_jsonschema_impls/nesting.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_jsonschema_impls/nesting.x/MyXDR.rs index 5cf38ade8..bed911e47 100644 --- a/spec/output/generator_spec_rust_custom_jsonschema_impls/nesting.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_jsonschema_impls/nesting.x/MyXDR.rs @@ -107,6 +107,7 @@ impl embedded_io_extras::Error for Error { impl From> for Error { fn from(value: embedded_io_extras::ReadExactError) -> Self { match value { + // TODO: maybe we should map the error to a more specific error? embedded_io_extras::ReadExactError::UnexpectedEof => Error::Io(embedded_io_extras::ErrorKind::Other), embedded_io_extras::ReadExactError::Other(e) => e } diff --git a/spec/output/generator_spec_rust_custom_jsonschema_impls/optional.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_jsonschema_impls/optional.x/MyXDR.rs index 19aaa676c..2935df915 100644 --- a/spec/output/generator_spec_rust_custom_jsonschema_impls/optional.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_jsonschema_impls/optional.x/MyXDR.rs @@ -107,6 +107,7 @@ impl embedded_io_extras::Error for Error { impl From> for Error { fn from(value: embedded_io_extras::ReadExactError) -> Self { match value { + // TODO: maybe we should map the error to a more specific error? embedded_io_extras::ReadExactError::UnexpectedEof => Error::Io(embedded_io_extras::ErrorKind::Other), embedded_io_extras::ReadExactError::Other(e) => e } diff --git a/spec/output/generator_spec_rust_custom_jsonschema_impls/struct.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_jsonschema_impls/struct.x/MyXDR.rs index 86a157170..95376fab4 100644 --- a/spec/output/generator_spec_rust_custom_jsonschema_impls/struct.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_jsonschema_impls/struct.x/MyXDR.rs @@ -107,6 +107,7 @@ impl embedded_io_extras::Error for Error { impl From> for Error { fn from(value: embedded_io_extras::ReadExactError) -> Self { match value { + // TODO: maybe we should map the error to a more specific error? embedded_io_extras::ReadExactError::UnexpectedEof => Error::Io(embedded_io_extras::ErrorKind::Other), embedded_io_extras::ReadExactError::Other(e) => e } diff --git a/spec/output/generator_spec_rust_custom_jsonschema_impls/test.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_jsonschema_impls/test.x/MyXDR.rs index 8fef6da29..d3edc44f6 100644 --- a/spec/output/generator_spec_rust_custom_jsonschema_impls/test.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_jsonschema_impls/test.x/MyXDR.rs @@ -107,6 +107,7 @@ impl embedded_io_extras::Error for Error { impl From> for Error { fn from(value: embedded_io_extras::ReadExactError) -> Self { match value { + // TODO: maybe we should map the error to a more specific error? embedded_io_extras::ReadExactError::UnexpectedEof => Error::Io(embedded_io_extras::ErrorKind::Other), embedded_io_extras::ReadExactError::Other(e) => e } diff --git a/spec/output/generator_spec_rust_custom_jsonschema_impls/union.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_jsonschema_impls/union.x/MyXDR.rs index 80e68e93d..99a252cfd 100644 --- a/spec/output/generator_spec_rust_custom_jsonschema_impls/union.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_jsonschema_impls/union.x/MyXDR.rs @@ -107,6 +107,7 @@ impl embedded_io_extras::Error for Error { impl From> for Error { fn from(value: embedded_io_extras::ReadExactError) -> Self { match value { + // TODO: maybe we should map the error to a more specific error? embedded_io_extras::ReadExactError::UnexpectedEof => Error::Io(embedded_io_extras::ErrorKind::Other), embedded_io_extras::ReadExactError::Other(e) => e } diff --git a/spec/output/generator_spec_rust_custom_str_impls/block_comments.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_str_impls/block_comments.x/MyXDR.rs index b219d1dd8..a3409c6aa 100644 --- a/spec/output/generator_spec_rust_custom_str_impls/block_comments.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_str_impls/block_comments.x/MyXDR.rs @@ -107,6 +107,7 @@ impl embedded_io_extras::Error for Error { impl From> for Error { fn from(value: embedded_io_extras::ReadExactError) -> Self { match value { + // TODO: maybe we should map the error to a more specific error? embedded_io_extras::ReadExactError::UnexpectedEof => Error::Io(embedded_io_extras::ErrorKind::Other), embedded_io_extras::ReadExactError::Other(e) => e } diff --git a/spec/output/generator_spec_rust_custom_str_impls/const.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_str_impls/const.x/MyXDR.rs index fbe2a13d8..968379ae7 100644 --- a/spec/output/generator_spec_rust_custom_str_impls/const.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_str_impls/const.x/MyXDR.rs @@ -107,6 +107,7 @@ impl embedded_io_extras::Error for Error { impl From> for Error { fn from(value: embedded_io_extras::ReadExactError) -> Self { match value { + // TODO: maybe we should map the error to a more specific error? embedded_io_extras::ReadExactError::UnexpectedEof => Error::Io(embedded_io_extras::ErrorKind::Other), embedded_io_extras::ReadExactError::Other(e) => e } diff --git a/spec/output/generator_spec_rust_custom_str_impls/enum.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_str_impls/enum.x/MyXDR.rs index d2f00861c..8c94410c0 100644 --- a/spec/output/generator_spec_rust_custom_str_impls/enum.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_str_impls/enum.x/MyXDR.rs @@ -107,6 +107,7 @@ impl embedded_io_extras::Error for Error { impl From> for Error { fn from(value: embedded_io_extras::ReadExactError) -> Self { match value { + // TODO: maybe we should map the error to a more specific error? embedded_io_extras::ReadExactError::UnexpectedEof => Error::Io(embedded_io_extras::ErrorKind::Other), embedded_io_extras::ReadExactError::Other(e) => e } diff --git a/spec/output/generator_spec_rust_custom_str_impls/nesting.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_str_impls/nesting.x/MyXDR.rs index 8eacf9b79..6939b8195 100644 --- a/spec/output/generator_spec_rust_custom_str_impls/nesting.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_str_impls/nesting.x/MyXDR.rs @@ -107,6 +107,7 @@ impl embedded_io_extras::Error for Error { impl From> for Error { fn from(value: embedded_io_extras::ReadExactError) -> Self { match value { + // TODO: maybe we should map the error to a more specific error? embedded_io_extras::ReadExactError::UnexpectedEof => Error::Io(embedded_io_extras::ErrorKind::Other), embedded_io_extras::ReadExactError::Other(e) => e } diff --git a/spec/output/generator_spec_rust_custom_str_impls/optional.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_str_impls/optional.x/MyXDR.rs index 1f19a9b70..df7c4c332 100644 --- a/spec/output/generator_spec_rust_custom_str_impls/optional.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_str_impls/optional.x/MyXDR.rs @@ -107,6 +107,7 @@ impl embedded_io_extras::Error for Error { impl From> for Error { fn from(value: embedded_io_extras::ReadExactError) -> Self { match value { + // TODO: maybe we should map the error to a more specific error? embedded_io_extras::ReadExactError::UnexpectedEof => Error::Io(embedded_io_extras::ErrorKind::Other), embedded_io_extras::ReadExactError::Other(e) => e } diff --git a/spec/output/generator_spec_rust_custom_str_impls/struct.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_str_impls/struct.x/MyXDR.rs index 1959f9c3a..b6a0d1eb1 100644 --- a/spec/output/generator_spec_rust_custom_str_impls/struct.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_str_impls/struct.x/MyXDR.rs @@ -107,6 +107,7 @@ impl embedded_io_extras::Error for Error { impl From> for Error { fn from(value: embedded_io_extras::ReadExactError) -> Self { match value { + // TODO: maybe we should map the error to a more specific error? embedded_io_extras::ReadExactError::UnexpectedEof => Error::Io(embedded_io_extras::ErrorKind::Other), embedded_io_extras::ReadExactError::Other(e) => e } diff --git a/spec/output/generator_spec_rust_custom_str_impls/test.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_str_impls/test.x/MyXDR.rs index 79f395343..d9f6ae1f2 100644 --- a/spec/output/generator_spec_rust_custom_str_impls/test.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_str_impls/test.x/MyXDR.rs @@ -107,6 +107,7 @@ impl embedded_io_extras::Error for Error { impl From> for Error { fn from(value: embedded_io_extras::ReadExactError) -> Self { match value { + // TODO: maybe we should map the error to a more specific error? embedded_io_extras::ReadExactError::UnexpectedEof => Error::Io(embedded_io_extras::ErrorKind::Other), embedded_io_extras::ReadExactError::Other(e) => e } diff --git a/spec/output/generator_spec_rust_custom_str_impls/union.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_str_impls/union.x/MyXDR.rs index 5503c2897..029f95ecc 100644 --- a/spec/output/generator_spec_rust_custom_str_impls/union.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_str_impls/union.x/MyXDR.rs @@ -107,6 +107,7 @@ impl embedded_io_extras::Error for Error { impl From> for Error { fn from(value: embedded_io_extras::ReadExactError) -> Self { match value { + // TODO: maybe we should map the error to a more specific error? embedded_io_extras::ReadExactError::UnexpectedEof => Error::Io(embedded_io_extras::ErrorKind::Other), embedded_io_extras::ReadExactError::Other(e) => e } From cd72b3f1c17b34b92e3de10b44efe7290b95695d Mon Sep 17 00:00:00 2001 From: Jun Luo <4catcode@gmail.com> Date: Sat, 21 Sep 2024 11:16:54 +0800 Subject: [PATCH 7/9] make clippy happy --- lib/xdrgen/generators/rust/src/types.rs | 3 ++- spec/output/generator_spec_rust/block_comments.x/MyXDR.rs | 3 ++- spec/output/generator_spec_rust/const.x/MyXDR.rs | 3 ++- spec/output/generator_spec_rust/enum.x/MyXDR.rs | 3 ++- spec/output/generator_spec_rust/nesting.x/MyXDR.rs | 3 ++- spec/output/generator_spec_rust/optional.x/MyXDR.rs | 3 ++- spec/output/generator_spec_rust/struct.x/MyXDR.rs | 3 ++- spec/output/generator_spec_rust/test.x/MyXDR.rs | 3 ++- spec/output/generator_spec_rust/union.x/MyXDR.rs | 3 ++- .../block_comments.x/MyXDR.rs | 3 ++- .../const.x/MyXDR.rs | 3 ++- .../enum.x/MyXDR.rs | 3 ++- .../nesting.x/MyXDR.rs | 3 ++- .../optional.x/MyXDR.rs | 3 ++- .../struct.x/MyXDR.rs | 3 ++- .../test.x/MyXDR.rs | 3 ++- .../union.x/MyXDR.rs | 3 ++- .../block_comments.x/MyXDR.rs | 3 ++- .../generator_spec_rust_custom_str_impls/const.x/MyXDR.rs | 3 ++- .../generator_spec_rust_custom_str_impls/enum.x/MyXDR.rs | 3 ++- .../generator_spec_rust_custom_str_impls/nesting.x/MyXDR.rs | 3 ++- .../generator_spec_rust_custom_str_impls/optional.x/MyXDR.rs | 3 ++- .../generator_spec_rust_custom_str_impls/struct.x/MyXDR.rs | 3 ++- .../generator_spec_rust_custom_str_impls/test.x/MyXDR.rs | 3 ++- .../generator_spec_rust_custom_str_impls/union.x/MyXDR.rs | 3 ++- 25 files changed, 50 insertions(+), 25 deletions(-) diff --git a/lib/xdrgen/generators/rust/src/types.rs b/lib/xdrgen/generators/rust/src/types.rs index 648f1f9d4..540dfca7a 100644 --- a/lib/xdrgen/generators/rust/src/types.rs +++ b/lib/xdrgen/generators/rust/src/types.rs @@ -25,7 +25,6 @@ use alloc::{ borrow::ToOwned, boxed::Box, string::{FromUtf8Error, String}, - vec, vec::Vec, }; #[cfg(feature = "std")] @@ -42,6 +41,8 @@ use std::{ #[cfg(feature = "embedded_io")] use embedded_io_extras::{Cursor, Error as _, ErrorType, Read, Write}; +#[cfg(feature = "embedded_io")] +use alloc::vec; /// Error contains all errors returned by functions in this crate. It can be /// compared via `PartialEq`, however any contained IO errors will only be diff --git a/spec/output/generator_spec_rust/block_comments.x/MyXDR.rs b/spec/output/generator_spec_rust/block_comments.x/MyXDR.rs index a3409c6aa..2b9de8c27 100644 --- a/spec/output/generator_spec_rust/block_comments.x/MyXDR.rs +++ b/spec/output/generator_spec_rust/block_comments.x/MyXDR.rs @@ -35,7 +35,6 @@ use alloc::{ borrow::ToOwned, boxed::Box, string::{FromUtf8Error, String}, - vec, vec::Vec, }; #[cfg(feature = "std")] @@ -52,6 +51,8 @@ use std::{ #[cfg(feature = "embedded_io")] use embedded_io_extras::{Cursor, Error as _, ErrorType, Read, Write}; +#[cfg(feature = "embedded_io")] +use alloc::vec; /// Error contains all errors returned by functions in this crate. It can be /// compared via `PartialEq`, however any contained IO errors will only be diff --git a/spec/output/generator_spec_rust/const.x/MyXDR.rs b/spec/output/generator_spec_rust/const.x/MyXDR.rs index 968379ae7..0b80a5d3f 100644 --- a/spec/output/generator_spec_rust/const.x/MyXDR.rs +++ b/spec/output/generator_spec_rust/const.x/MyXDR.rs @@ -35,7 +35,6 @@ use alloc::{ borrow::ToOwned, boxed::Box, string::{FromUtf8Error, String}, - vec, vec::Vec, }; #[cfg(feature = "std")] @@ -52,6 +51,8 @@ use std::{ #[cfg(feature = "embedded_io")] use embedded_io_extras::{Cursor, Error as _, ErrorType, Read, Write}; +#[cfg(feature = "embedded_io")] +use alloc::vec; /// Error contains all errors returned by functions in this crate. It can be /// compared via `PartialEq`, however any contained IO errors will only be diff --git a/spec/output/generator_spec_rust/enum.x/MyXDR.rs b/spec/output/generator_spec_rust/enum.x/MyXDR.rs index ac734778f..ed96f0d60 100644 --- a/spec/output/generator_spec_rust/enum.x/MyXDR.rs +++ b/spec/output/generator_spec_rust/enum.x/MyXDR.rs @@ -35,7 +35,6 @@ use alloc::{ borrow::ToOwned, boxed::Box, string::{FromUtf8Error, String}, - vec, vec::Vec, }; #[cfg(feature = "std")] @@ -52,6 +51,8 @@ use std::{ #[cfg(feature = "embedded_io")] use embedded_io_extras::{Cursor, Error as _, ErrorType, Read, Write}; +#[cfg(feature = "embedded_io")] +use alloc::vec; /// Error contains all errors returned by functions in this crate. It can be /// compared via `PartialEq`, however any contained IO errors will only be diff --git a/spec/output/generator_spec_rust/nesting.x/MyXDR.rs b/spec/output/generator_spec_rust/nesting.x/MyXDR.rs index 277e993d3..7d4c93717 100644 --- a/spec/output/generator_spec_rust/nesting.x/MyXDR.rs +++ b/spec/output/generator_spec_rust/nesting.x/MyXDR.rs @@ -35,7 +35,6 @@ use alloc::{ borrow::ToOwned, boxed::Box, string::{FromUtf8Error, String}, - vec, vec::Vec, }; #[cfg(feature = "std")] @@ -52,6 +51,8 @@ use std::{ #[cfg(feature = "embedded_io")] use embedded_io_extras::{Cursor, Error as _, ErrorType, Read, Write}; +#[cfg(feature = "embedded_io")] +use alloc::vec; /// Error contains all errors returned by functions in this crate. It can be /// compared via `PartialEq`, however any contained IO errors will only be diff --git a/spec/output/generator_spec_rust/optional.x/MyXDR.rs b/spec/output/generator_spec_rust/optional.x/MyXDR.rs index 1b20720a6..ca1a018d6 100644 --- a/spec/output/generator_spec_rust/optional.x/MyXDR.rs +++ b/spec/output/generator_spec_rust/optional.x/MyXDR.rs @@ -35,7 +35,6 @@ use alloc::{ borrow::ToOwned, boxed::Box, string::{FromUtf8Error, String}, - vec, vec::Vec, }; #[cfg(feature = "std")] @@ -52,6 +51,8 @@ use std::{ #[cfg(feature = "embedded_io")] use embedded_io_extras::{Cursor, Error as _, ErrorType, Read, Write}; +#[cfg(feature = "embedded_io")] +use alloc::vec; /// Error contains all errors returned by functions in this crate. It can be /// compared via `PartialEq`, however any contained IO errors will only be diff --git a/spec/output/generator_spec_rust/struct.x/MyXDR.rs b/spec/output/generator_spec_rust/struct.x/MyXDR.rs index 2a1e97fd3..e48a6fe44 100644 --- a/spec/output/generator_spec_rust/struct.x/MyXDR.rs +++ b/spec/output/generator_spec_rust/struct.x/MyXDR.rs @@ -35,7 +35,6 @@ use alloc::{ borrow::ToOwned, boxed::Box, string::{FromUtf8Error, String}, - vec, vec::Vec, }; #[cfg(feature = "std")] @@ -52,6 +51,8 @@ use std::{ #[cfg(feature = "embedded_io")] use embedded_io_extras::{Cursor, Error as _, ErrorType, Read, Write}; +#[cfg(feature = "embedded_io")] +use alloc::vec; /// Error contains all errors returned by functions in this crate. It can be /// compared via `PartialEq`, however any contained IO errors will only be diff --git a/spec/output/generator_spec_rust/test.x/MyXDR.rs b/spec/output/generator_spec_rust/test.x/MyXDR.rs index 212f498f2..0bae473d1 100644 --- a/spec/output/generator_spec_rust/test.x/MyXDR.rs +++ b/spec/output/generator_spec_rust/test.x/MyXDR.rs @@ -35,7 +35,6 @@ use alloc::{ borrow::ToOwned, boxed::Box, string::{FromUtf8Error, String}, - vec, vec::Vec, }; #[cfg(feature = "std")] @@ -52,6 +51,8 @@ use std::{ #[cfg(feature = "embedded_io")] use embedded_io_extras::{Cursor, Error as _, ErrorType, Read, Write}; +#[cfg(feature = "embedded_io")] +use alloc::vec; /// Error contains all errors returned by functions in this crate. It can be /// compared via `PartialEq`, however any contained IO errors will only be diff --git a/spec/output/generator_spec_rust/union.x/MyXDR.rs b/spec/output/generator_spec_rust/union.x/MyXDR.rs index 7754e5301..3ab0369a5 100644 --- a/spec/output/generator_spec_rust/union.x/MyXDR.rs +++ b/spec/output/generator_spec_rust/union.x/MyXDR.rs @@ -35,7 +35,6 @@ use alloc::{ borrow::ToOwned, boxed::Box, string::{FromUtf8Error, String}, - vec, vec::Vec, }; #[cfg(feature = "std")] @@ -52,6 +51,8 @@ use std::{ #[cfg(feature = "embedded_io")] use embedded_io_extras::{Cursor, Error as _, ErrorType, Read, Write}; +#[cfg(feature = "embedded_io")] +use alloc::vec; /// Error contains all errors returned by functions in this crate. It can be /// compared via `PartialEq`, however any contained IO errors will only be diff --git a/spec/output/generator_spec_rust_custom_jsonschema_impls/block_comments.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_jsonschema_impls/block_comments.x/MyXDR.rs index a3409c6aa..2b9de8c27 100644 --- a/spec/output/generator_spec_rust_custom_jsonschema_impls/block_comments.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_jsonschema_impls/block_comments.x/MyXDR.rs @@ -35,7 +35,6 @@ use alloc::{ borrow::ToOwned, boxed::Box, string::{FromUtf8Error, String}, - vec, vec::Vec, }; #[cfg(feature = "std")] @@ -52,6 +51,8 @@ use std::{ #[cfg(feature = "embedded_io")] use embedded_io_extras::{Cursor, Error as _, ErrorType, Read, Write}; +#[cfg(feature = "embedded_io")] +use alloc::vec; /// Error contains all errors returned by functions in this crate. It can be /// compared via `PartialEq`, however any contained IO errors will only be diff --git a/spec/output/generator_spec_rust_custom_jsonschema_impls/const.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_jsonschema_impls/const.x/MyXDR.rs index 968379ae7..0b80a5d3f 100644 --- a/spec/output/generator_spec_rust_custom_jsonschema_impls/const.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_jsonschema_impls/const.x/MyXDR.rs @@ -35,7 +35,6 @@ use alloc::{ borrow::ToOwned, boxed::Box, string::{FromUtf8Error, String}, - vec, vec::Vec, }; #[cfg(feature = "std")] @@ -52,6 +51,8 @@ use std::{ #[cfg(feature = "embedded_io")] use embedded_io_extras::{Cursor, Error as _, ErrorType, Read, Write}; +#[cfg(feature = "embedded_io")] +use alloc::vec; /// Error contains all errors returned by functions in this crate. It can be /// compared via `PartialEq`, however any contained IO errors will only be diff --git a/spec/output/generator_spec_rust_custom_jsonschema_impls/enum.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_jsonschema_impls/enum.x/MyXDR.rs index 1d0ba7c58..cadf5fcc7 100644 --- a/spec/output/generator_spec_rust_custom_jsonschema_impls/enum.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_jsonschema_impls/enum.x/MyXDR.rs @@ -35,7 +35,6 @@ use alloc::{ borrow::ToOwned, boxed::Box, string::{FromUtf8Error, String}, - vec, vec::Vec, }; #[cfg(feature = "std")] @@ -52,6 +51,8 @@ use std::{ #[cfg(feature = "embedded_io")] use embedded_io_extras::{Cursor, Error as _, ErrorType, Read, Write}; +#[cfg(feature = "embedded_io")] +use alloc::vec; /// Error contains all errors returned by functions in this crate. It can be /// compared via `PartialEq`, however any contained IO errors will only be diff --git a/spec/output/generator_spec_rust_custom_jsonschema_impls/nesting.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_jsonschema_impls/nesting.x/MyXDR.rs index bed911e47..478d81d48 100644 --- a/spec/output/generator_spec_rust_custom_jsonschema_impls/nesting.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_jsonschema_impls/nesting.x/MyXDR.rs @@ -35,7 +35,6 @@ use alloc::{ borrow::ToOwned, boxed::Box, string::{FromUtf8Error, String}, - vec, vec::Vec, }; #[cfg(feature = "std")] @@ -52,6 +51,8 @@ use std::{ #[cfg(feature = "embedded_io")] use embedded_io_extras::{Cursor, Error as _, ErrorType, Read, Write}; +#[cfg(feature = "embedded_io")] +use alloc::vec; /// Error contains all errors returned by functions in this crate. It can be /// compared via `PartialEq`, however any contained IO errors will only be diff --git a/spec/output/generator_spec_rust_custom_jsonschema_impls/optional.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_jsonschema_impls/optional.x/MyXDR.rs index 2935df915..1a89ac298 100644 --- a/spec/output/generator_spec_rust_custom_jsonschema_impls/optional.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_jsonschema_impls/optional.x/MyXDR.rs @@ -35,7 +35,6 @@ use alloc::{ borrow::ToOwned, boxed::Box, string::{FromUtf8Error, String}, - vec, vec::Vec, }; #[cfg(feature = "std")] @@ -52,6 +51,8 @@ use std::{ #[cfg(feature = "embedded_io")] use embedded_io_extras::{Cursor, Error as _, ErrorType, Read, Write}; +#[cfg(feature = "embedded_io")] +use alloc::vec; /// Error contains all errors returned by functions in this crate. It can be /// compared via `PartialEq`, however any contained IO errors will only be diff --git a/spec/output/generator_spec_rust_custom_jsonschema_impls/struct.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_jsonschema_impls/struct.x/MyXDR.rs index 95376fab4..83e18bab4 100644 --- a/spec/output/generator_spec_rust_custom_jsonschema_impls/struct.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_jsonschema_impls/struct.x/MyXDR.rs @@ -35,7 +35,6 @@ use alloc::{ borrow::ToOwned, boxed::Box, string::{FromUtf8Error, String}, - vec, vec::Vec, }; #[cfg(feature = "std")] @@ -52,6 +51,8 @@ use std::{ #[cfg(feature = "embedded_io")] use embedded_io_extras::{Cursor, Error as _, ErrorType, Read, Write}; +#[cfg(feature = "embedded_io")] +use alloc::vec; /// Error contains all errors returned by functions in this crate. It can be /// compared via `PartialEq`, however any contained IO errors will only be diff --git a/spec/output/generator_spec_rust_custom_jsonschema_impls/test.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_jsonschema_impls/test.x/MyXDR.rs index d3edc44f6..5a3e78240 100644 --- a/spec/output/generator_spec_rust_custom_jsonschema_impls/test.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_jsonschema_impls/test.x/MyXDR.rs @@ -35,7 +35,6 @@ use alloc::{ borrow::ToOwned, boxed::Box, string::{FromUtf8Error, String}, - vec, vec::Vec, }; #[cfg(feature = "std")] @@ -52,6 +51,8 @@ use std::{ #[cfg(feature = "embedded_io")] use embedded_io_extras::{Cursor, Error as _, ErrorType, Read, Write}; +#[cfg(feature = "embedded_io")] +use alloc::vec; /// Error contains all errors returned by functions in this crate. It can be /// compared via `PartialEq`, however any contained IO errors will only be diff --git a/spec/output/generator_spec_rust_custom_jsonschema_impls/union.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_jsonschema_impls/union.x/MyXDR.rs index 99a252cfd..1c13213f5 100644 --- a/spec/output/generator_spec_rust_custom_jsonschema_impls/union.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_jsonschema_impls/union.x/MyXDR.rs @@ -35,7 +35,6 @@ use alloc::{ borrow::ToOwned, boxed::Box, string::{FromUtf8Error, String}, - vec, vec::Vec, }; #[cfg(feature = "std")] @@ -52,6 +51,8 @@ use std::{ #[cfg(feature = "embedded_io")] use embedded_io_extras::{Cursor, Error as _, ErrorType, Read, Write}; +#[cfg(feature = "embedded_io")] +use alloc::vec; /// Error contains all errors returned by functions in this crate. It can be /// compared via `PartialEq`, however any contained IO errors will only be diff --git a/spec/output/generator_spec_rust_custom_str_impls/block_comments.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_str_impls/block_comments.x/MyXDR.rs index a3409c6aa..2b9de8c27 100644 --- a/spec/output/generator_spec_rust_custom_str_impls/block_comments.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_str_impls/block_comments.x/MyXDR.rs @@ -35,7 +35,6 @@ use alloc::{ borrow::ToOwned, boxed::Box, string::{FromUtf8Error, String}, - vec, vec::Vec, }; #[cfg(feature = "std")] @@ -52,6 +51,8 @@ use std::{ #[cfg(feature = "embedded_io")] use embedded_io_extras::{Cursor, Error as _, ErrorType, Read, Write}; +#[cfg(feature = "embedded_io")] +use alloc::vec; /// Error contains all errors returned by functions in this crate. It can be /// compared via `PartialEq`, however any contained IO errors will only be diff --git a/spec/output/generator_spec_rust_custom_str_impls/const.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_str_impls/const.x/MyXDR.rs index 968379ae7..0b80a5d3f 100644 --- a/spec/output/generator_spec_rust_custom_str_impls/const.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_str_impls/const.x/MyXDR.rs @@ -35,7 +35,6 @@ use alloc::{ borrow::ToOwned, boxed::Box, string::{FromUtf8Error, String}, - vec, vec::Vec, }; #[cfg(feature = "std")] @@ -52,6 +51,8 @@ use std::{ #[cfg(feature = "embedded_io")] use embedded_io_extras::{Cursor, Error as _, ErrorType, Read, Write}; +#[cfg(feature = "embedded_io")] +use alloc::vec; /// Error contains all errors returned by functions in this crate. It can be /// compared via `PartialEq`, however any contained IO errors will only be diff --git a/spec/output/generator_spec_rust_custom_str_impls/enum.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_str_impls/enum.x/MyXDR.rs index 8c94410c0..b157adef4 100644 --- a/spec/output/generator_spec_rust_custom_str_impls/enum.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_str_impls/enum.x/MyXDR.rs @@ -35,7 +35,6 @@ use alloc::{ borrow::ToOwned, boxed::Box, string::{FromUtf8Error, String}, - vec, vec::Vec, }; #[cfg(feature = "std")] @@ -52,6 +51,8 @@ use std::{ #[cfg(feature = "embedded_io")] use embedded_io_extras::{Cursor, Error as _, ErrorType, Read, Write}; +#[cfg(feature = "embedded_io")] +use alloc::vec; /// Error contains all errors returned by functions in this crate. It can be /// compared via `PartialEq`, however any contained IO errors will only be diff --git a/spec/output/generator_spec_rust_custom_str_impls/nesting.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_str_impls/nesting.x/MyXDR.rs index 6939b8195..7827028ac 100644 --- a/spec/output/generator_spec_rust_custom_str_impls/nesting.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_str_impls/nesting.x/MyXDR.rs @@ -35,7 +35,6 @@ use alloc::{ borrow::ToOwned, boxed::Box, string::{FromUtf8Error, String}, - vec, vec::Vec, }; #[cfg(feature = "std")] @@ -52,6 +51,8 @@ use std::{ #[cfg(feature = "embedded_io")] use embedded_io_extras::{Cursor, Error as _, ErrorType, Read, Write}; +#[cfg(feature = "embedded_io")] +use alloc::vec; /// Error contains all errors returned by functions in this crate. It can be /// compared via `PartialEq`, however any contained IO errors will only be diff --git a/spec/output/generator_spec_rust_custom_str_impls/optional.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_str_impls/optional.x/MyXDR.rs index df7c4c332..867ecf91c 100644 --- a/spec/output/generator_spec_rust_custom_str_impls/optional.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_str_impls/optional.x/MyXDR.rs @@ -35,7 +35,6 @@ use alloc::{ borrow::ToOwned, boxed::Box, string::{FromUtf8Error, String}, - vec, vec::Vec, }; #[cfg(feature = "std")] @@ -52,6 +51,8 @@ use std::{ #[cfg(feature = "embedded_io")] use embedded_io_extras::{Cursor, Error as _, ErrorType, Read, Write}; +#[cfg(feature = "embedded_io")] +use alloc::vec; /// Error contains all errors returned by functions in this crate. It can be /// compared via `PartialEq`, however any contained IO errors will only be diff --git a/spec/output/generator_spec_rust_custom_str_impls/struct.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_str_impls/struct.x/MyXDR.rs index b6a0d1eb1..7dd6a2193 100644 --- a/spec/output/generator_spec_rust_custom_str_impls/struct.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_str_impls/struct.x/MyXDR.rs @@ -35,7 +35,6 @@ use alloc::{ borrow::ToOwned, boxed::Box, string::{FromUtf8Error, String}, - vec, vec::Vec, }; #[cfg(feature = "std")] @@ -52,6 +51,8 @@ use std::{ #[cfg(feature = "embedded_io")] use embedded_io_extras::{Cursor, Error as _, ErrorType, Read, Write}; +#[cfg(feature = "embedded_io")] +use alloc::vec; /// Error contains all errors returned by functions in this crate. It can be /// compared via `PartialEq`, however any contained IO errors will only be diff --git a/spec/output/generator_spec_rust_custom_str_impls/test.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_str_impls/test.x/MyXDR.rs index d9f6ae1f2..682e0e665 100644 --- a/spec/output/generator_spec_rust_custom_str_impls/test.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_str_impls/test.x/MyXDR.rs @@ -35,7 +35,6 @@ use alloc::{ borrow::ToOwned, boxed::Box, string::{FromUtf8Error, String}, - vec, vec::Vec, }; #[cfg(feature = "std")] @@ -52,6 +51,8 @@ use std::{ #[cfg(feature = "embedded_io")] use embedded_io_extras::{Cursor, Error as _, ErrorType, Read, Write}; +#[cfg(feature = "embedded_io")] +use alloc::vec; /// Error contains all errors returned by functions in this crate. It can be /// compared via `PartialEq`, however any contained IO errors will only be diff --git a/spec/output/generator_spec_rust_custom_str_impls/union.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_str_impls/union.x/MyXDR.rs index 029f95ecc..7f170b97d 100644 --- a/spec/output/generator_spec_rust_custom_str_impls/union.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_str_impls/union.x/MyXDR.rs @@ -35,7 +35,6 @@ use alloc::{ borrow::ToOwned, boxed::Box, string::{FromUtf8Error, String}, - vec, vec::Vec, }; #[cfg(feature = "std")] @@ -52,6 +51,8 @@ use std::{ #[cfg(feature = "embedded_io")] use embedded_io_extras::{Cursor, Error as _, ErrorType, Read, Write}; +#[cfg(feature = "embedded_io")] +use alloc::vec; /// Error contains all errors returned by functions in this crate. It can be /// compared via `PartialEq`, however any contained IO errors will only be From 1907cf80feb4e9f25d98f5f970db206ad4135282 Mon Sep 17 00:00:00 2001 From: Jun Luo <4catcode@gmail.com> Date: Sat, 21 Sep 2024 15:24:36 +0800 Subject: [PATCH 8/9] add tests --- lib/xdrgen/generators/rust/src/types.rs | 301 ++++++++++++------ .../block_comments.x/MyXDR.rs | 301 ++++++++++++------ .../generator_spec_rust/const.x/MyXDR.rs | 301 ++++++++++++------ .../generator_spec_rust/enum.x/MyXDR.rs | 301 ++++++++++++------ .../generator_spec_rust/nesting.x/MyXDR.rs | 301 ++++++++++++------ .../generator_spec_rust/optional.x/MyXDR.rs | 301 ++++++++++++------ .../generator_spec_rust/struct.x/MyXDR.rs | 301 ++++++++++++------ .../generator_spec_rust/test.x/MyXDR.rs | 301 ++++++++++++------ .../generator_spec_rust/union.x/MyXDR.rs | 301 ++++++++++++------ .../block_comments.x/MyXDR.rs | 301 ++++++++++++------ .../const.x/MyXDR.rs | 301 ++++++++++++------ .../enum.x/MyXDR.rs | 301 ++++++++++++------ .../nesting.x/MyXDR.rs | 301 ++++++++++++------ .../optional.x/MyXDR.rs | 301 ++++++++++++------ .../struct.x/MyXDR.rs | 301 ++++++++++++------ .../test.x/MyXDR.rs | 301 ++++++++++++------ .../union.x/MyXDR.rs | 301 ++++++++++++------ .../block_comments.x/MyXDR.rs | 301 ++++++++++++------ .../const.x/MyXDR.rs | 301 ++++++++++++------ .../enum.x/MyXDR.rs | 301 ++++++++++++------ .../nesting.x/MyXDR.rs | 301 ++++++++++++------ .../optional.x/MyXDR.rs | 301 ++++++++++++------ .../struct.x/MyXDR.rs | 301 ++++++++++++------ .../test.x/MyXDR.rs | 301 ++++++++++++------ .../union.x/MyXDR.rs | 301 ++++++++++++------ 25 files changed, 5250 insertions(+), 2275 deletions(-) diff --git a/lib/xdrgen/generators/rust/src/types.rs b/lib/xdrgen/generators/rust/src/types.rs index 540dfca7a..b247a1492 100644 --- a/lib/xdrgen/generators/rust/src/types.rs +++ b/lib/xdrgen/generators/rust/src/types.rs @@ -2824,11 +2824,25 @@ mod test_io { use super::*; + macro_rules! assert_unexpected_eof { + ($result:expr) => {{ + let err = $result.unwrap_err(); + #[cfg(feature = "std")] + { + assert_eq!(err.kind(), io::ErrorKind::UnexpectedEof); + } + #[cfg(feature = "embedded_io")] + { + assert_eq!(err, embedded_io_extras::ReadExactError::UnexpectedEof); + } + }}; + } + #[test] - fn test_read_exact_success() { + fn test_cursor_read_exact_success() { let data = b"The quick brown fox jumps over the lazy dog."; let mut cursor = Cursor::new(data); - let mut buffer = [0u8; 19]; // Exactly the length of "The quick brown fox" + let mut buffer = [0u8; 19]; // Attempt to read exactly 19 bytes assert!(cursor.read_exact(&mut buffer).is_ok()); @@ -2837,8 +2851,8 @@ mod test_io { } #[test] - fn test_read_exact_less_than_available() { - let data = b"Hello, Rust!"; + fn test_cursor_read_exact_less_than_available() { + let data = b"Hello, Stellar!"; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 5]; @@ -2849,7 +2863,7 @@ mod test_io { } #[test] - fn test_read_exact_exact_eof() { + fn test_cursor_read_exact_exact_eof() { let data = b"Data"; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 4]; @@ -2863,21 +2877,12 @@ mod test_io { let mut buffer_eof = [0u8; 1]; let result = cursor.read_exact(&mut buffer_eof); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); assert_eq!(cursor.position(), 4); // Position should remain at EOF } #[test] - fn test_read_exact_past_eof() { + fn test_cursor_read_exact_past_eof() { let data = b"Short"; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 10]; // Requesting more bytes than available @@ -2885,24 +2890,15 @@ mod test_io { // Attempt to read 10 bytes from a 5-byte buffer let result = cursor.read_exact(&mut buffer); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); assert_eq!(cursor.position(), 5); // Position should move to EOF } #[test] - fn test_read_exact_empty_buffer() { + fn test_cursor_read_exact_empty_buffer() { let data = b"Non-empty"; let mut cursor = Cursor::new(data); - let mut buffer = [0u8; 0]; // Zero-length buffer + let mut buffer = [0u8; 0]; // Attempt to read zero bytes assert!(cursor.read_exact(&mut buffer).is_ok()); @@ -2910,7 +2906,7 @@ mod test_io { } #[test] - fn test_read_exact_from_empty_cursor() { + fn test_cursor_read_exact_from_empty_cursor() { let data: &[u8] = b""; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 5]; @@ -2918,21 +2914,12 @@ mod test_io { // Attempt to read from an empty cursor let result = cursor.read_exact(&mut buffer); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); assert_eq!(cursor.position(), 0); // Position remains at 0 } #[test] - fn test_read_exact_multiple_reads() { + fn test_cursor_read_exact_multiple_reads() { let data = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; let mut cursor = Cursor::new(data); @@ -2953,79 +2940,211 @@ mod test_io { // Third read: Attempt to read 10 bytes, but only 6 are available let result = cursor.read_exact(&mut buffer3); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); // read_exact makes no promises about the content of the buffer on error + // https://github.com/rust-lang/rust/blob/84ac80f1921afc243d71fd0caaa4f2838c294102/library/std/src/io/impls.rs#L287 // assert_eq!(&buffer3[..6], b"UVWXYZ"); assert_eq!(cursor.position(), 26); // Position should be at EOF } #[test] - fn test_cursor_read_exact_after_eof() { - let data = b"End"; - let mut cursor = Cursor::new(data); - let mut buffer = [0u8; 3]; + fn test_slice_read_exact_success() { + let data: &[u8] = b"The quick brown fox jumps over the lazy dog."; + let mut reader = data; + let mut buffer = [0u8; 19]; - // First read: read the entire buffer - assert!(cursor.read_exact(&mut buffer).is_ok()); - assert_eq!(&buffer, b"End"); - assert_eq!(cursor.position(), 3); + // Attempt to read exactly 19 bytes + assert!(reader.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"The quick brown fox"); + } + + #[test] + fn test_slice_read_exact_less_than_available() { + let data: &[u8] = b"Hello, Stellar!"; + let mut reader = data; + let mut buffer = [0u8; 5]; + + // Attempt to read 5 bytes from the start + assert!(reader.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Hello"); + } + + #[test] + fn test_slice_read_exact_exact_eof() { + let data: &[u8] = b"Data"; + let mut reader = data; + let mut buffer = [0u8; 4]; + + // Attempt to read exactly 4 bytes, which is the entire slice + assert!(reader.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Data"); - // Second read: attempt to read again, should fail + // Further attempt to read should fail with EOF let mut buffer_eof = [0u8; 1]; - let result = cursor.read_exact(&mut buffer_eof); + let result = reader.read_exact(&mut buffer_eof); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); - assert_eq!(cursor.position(), 3); // Position remains at EOF + assert_unexpected_eof!(result); } #[test] - fn test_slice_read_exact_success() { - let data = b"SliceReadTest"; - let mut slice = &data[..]; - let mut buffer = [0u8; 13]; // Exact length + fn test_slice_read_exact_past_eof() { + let data: &[u8] = b"Short"; + let mut reader = data; + let mut buffer = [0u8; 10]; // Requesting more bytes than available - // Using Read trait directly on slice - assert!(slice.read_exact(&mut buffer).is_ok()); - assert_eq!(&buffer, b"SliceReadTest"); + // Attempt to read 10 bytes from a 5-byte slice + let result = reader.read_exact(&mut buffer); + assert!(result.is_err()); + assert_unexpected_eof!(result); } #[test] - fn test_slice_read_exact_partial() { - let data = b"SlicePartial"; - let mut slice = &data[..]; - let mut buffer = [0u8; 20]; // Request more bytes than available + fn test_slice_read_exact_empty_buffer() { + let data: &[u8] = b"Non-empty"; + let mut reader = data; + let mut buffer = [0u8; 0]; // Zero-length buffer + + // Attempt to read zero bytes + assert!(reader.read_exact(&mut buffer).is_ok()); + } + + #[test] + fn test_slice_read_exact_from_empty_slice() { + let data: &[u8] = b""; + let mut reader = data; + let mut buffer = [0u8; 5]; + + // Attempt to read from an empty slice + let result = reader.read_exact(&mut buffer); + assert!(result.is_err()); + assert_unexpected_eof!(result); + } + + #[test] + fn test_slice_read_exact_multiple_reads() { + let data: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + let mut reader = data; + + let mut buffer1 = [0u8; 10]; + let mut buffer2 = [0u8; 10]; + let mut buffer3 = [0u8; 10]; // Only 6 bytes left + + // First read: 10 bytes + assert!(reader.read_exact(&mut buffer1).is_ok()); + assert_eq!(&buffer1, b"ABCDEFGHIJ"); + + // Second read: 10 bytes + assert!(reader.read_exact(&mut buffer2).is_ok()); + assert_eq!(&buffer2, b"KLMNOPQRST"); + + // Third read: Attempt to read 10 bytes, but only 6 are available + let result = reader.read_exact(&mut buffer3); + assert!(result.is_err()); + assert_unexpected_eof!(result); + } + + #[test] + fn test_cursor_write_success() { + let data = Vec::with_capacity(100); + let mut cursor = Cursor::new(data); + let write_data = b"Hello, Stellar!"; + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(&cursor.get_ref()[..], write_data); + assert_eq!(cursor.position(), write_data.len() as u64); + } - // Using Read trait directly on slice - let result = slice.read_exact(&mut buffer); + #[test] + fn test_cursor_write_multiple_writes() { + let data = Vec::with_capacity(100); + let mut cursor = Cursor::new(data); + let write_data1: &[u8] = b"Hello, "; + let write_data2: &[u8] = b"Rust!"; + + // First write + assert!(cursor.write_all(write_data1).is_ok()); + assert_eq!(&cursor.get_ref()[..], write_data1); + assert_eq!(cursor.position(), write_data1.len() as u64); + + // Second write + assert!(cursor.write_all(write_data2).is_ok()); + let mut expected = Vec::new(); + expected.extend_from_slice(write_data1); + expected.extend_from_slice(write_data2); + assert_eq!(&cursor.get_ref()[..], expected.as_slice()); + assert_eq!(cursor.position(), expected.len() as u64); + } + + #[test] + fn test_cursor_write_empty() { + let data = Vec::with_capacity(100); + let mut cursor = Cursor::new(data); + let write_data = b""; + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(cursor.get_ref().len(), 0); + assert_eq!(cursor.position(), 0); + } + + #[test] + fn test_cursor_write_at_position() { + let mut data = vec![0u8; 10]; + { + let mut cursor = Cursor::new(&mut data[..]); + let write_data = b"Rust"; + + // Move cursor to position 6 + cursor.set_position(6); + assert_eq!(cursor.position(), 6); + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(cursor.position(), 10); + } + + let mut expected = vec![0u8; 10]; + expected[6..10].copy_from_slice(b"Rust"); + assert_eq!(&data[..], &expected[..]); + } + + #[test] + fn test_cursor_write_overflow() { + let mut data = vec![0u8; 5]; + let mut cursor = Cursor::new(&mut data[..]); + let write_data = b"Too long data"; + + let result = cursor.write_all(write_data); assert!(result.is_err()); + #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); + assert_eq!(result.unwrap_err().kind(), io::ErrorKind::WriteZero); #[cfg(feature = "embedded_io")] assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof + result.unwrap_err().kind(), + embedded_io_extras::ErrorKind::WriteZero ); - // read_exact makes no promises about the content of the buffer on error + } + + #[test] + fn test_cursor_write_from_empty_cursor() { + let data = Vec::new(); + let mut cursor = Cursor::new(data); + let write_data = b"Initial Data"; + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(&cursor.get_ref()[..], write_data); + assert_eq!(cursor.position(), write_data.len() as u64); + } + + #[test] + fn test_cursor_write_partial() { + let mut data = [0u8; 5]; + let mut cursor = Cursor::new(&mut data[..]); + let write_data = b"Hello, Stellar!"; + + // Attempt to write data that exceeds the buffer size + // using `write` instead of `write_all` + let result = cursor.write(&write_data[..7]).unwrap(); + assert_eq!(result, 5); + assert_eq!(&cursor.get_ref()[..], b"Hello"); } } diff --git a/spec/output/generator_spec_rust/block_comments.x/MyXDR.rs b/spec/output/generator_spec_rust/block_comments.x/MyXDR.rs index 2b9de8c27..a2906d184 100644 --- a/spec/output/generator_spec_rust/block_comments.x/MyXDR.rs +++ b/spec/output/generator_spec_rust/block_comments.x/MyXDR.rs @@ -2834,11 +2834,25 @@ mod test_io { use super::*; + macro_rules! assert_unexpected_eof { + ($result:expr) => {{ + let err = $result.unwrap_err(); + #[cfg(feature = "std")] + { + assert_eq!(err.kind(), io::ErrorKind::UnexpectedEof); + } + #[cfg(feature = "embedded_io")] + { + assert_eq!(err, embedded_io_extras::ReadExactError::UnexpectedEof); + } + }}; + } + #[test] - fn test_read_exact_success() { + fn test_cursor_read_exact_success() { let data = b"The quick brown fox jumps over the lazy dog."; let mut cursor = Cursor::new(data); - let mut buffer = [0u8; 19]; // Exactly the length of "The quick brown fox" + let mut buffer = [0u8; 19]; // Attempt to read exactly 19 bytes assert!(cursor.read_exact(&mut buffer).is_ok()); @@ -2847,8 +2861,8 @@ mod test_io { } #[test] - fn test_read_exact_less_than_available() { - let data = b"Hello, Rust!"; + fn test_cursor_read_exact_less_than_available() { + let data = b"Hello, Stellar!"; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 5]; @@ -2859,7 +2873,7 @@ mod test_io { } #[test] - fn test_read_exact_exact_eof() { + fn test_cursor_read_exact_exact_eof() { let data = b"Data"; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 4]; @@ -2873,21 +2887,12 @@ mod test_io { let mut buffer_eof = [0u8; 1]; let result = cursor.read_exact(&mut buffer_eof); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); assert_eq!(cursor.position(), 4); // Position should remain at EOF } #[test] - fn test_read_exact_past_eof() { + fn test_cursor_read_exact_past_eof() { let data = b"Short"; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 10]; // Requesting more bytes than available @@ -2895,24 +2900,15 @@ mod test_io { // Attempt to read 10 bytes from a 5-byte buffer let result = cursor.read_exact(&mut buffer); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); assert_eq!(cursor.position(), 5); // Position should move to EOF } #[test] - fn test_read_exact_empty_buffer() { + fn test_cursor_read_exact_empty_buffer() { let data = b"Non-empty"; let mut cursor = Cursor::new(data); - let mut buffer = [0u8; 0]; // Zero-length buffer + let mut buffer = [0u8; 0]; // Attempt to read zero bytes assert!(cursor.read_exact(&mut buffer).is_ok()); @@ -2920,7 +2916,7 @@ mod test_io { } #[test] - fn test_read_exact_from_empty_cursor() { + fn test_cursor_read_exact_from_empty_cursor() { let data: &[u8] = b""; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 5]; @@ -2928,21 +2924,12 @@ mod test_io { // Attempt to read from an empty cursor let result = cursor.read_exact(&mut buffer); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); assert_eq!(cursor.position(), 0); // Position remains at 0 } #[test] - fn test_read_exact_multiple_reads() { + fn test_cursor_read_exact_multiple_reads() { let data = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; let mut cursor = Cursor::new(data); @@ -2963,80 +2950,212 @@ mod test_io { // Third read: Attempt to read 10 bytes, but only 6 are available let result = cursor.read_exact(&mut buffer3); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); // read_exact makes no promises about the content of the buffer on error + // https://github.com/rust-lang/rust/blob/84ac80f1921afc243d71fd0caaa4f2838c294102/library/std/src/io/impls.rs#L287 // assert_eq!(&buffer3[..6], b"UVWXYZ"); assert_eq!(cursor.position(), 26); // Position should be at EOF } #[test] - fn test_cursor_read_exact_after_eof() { - let data = b"End"; - let mut cursor = Cursor::new(data); - let mut buffer = [0u8; 3]; + fn test_slice_read_exact_success() { + let data: &[u8] = b"The quick brown fox jumps over the lazy dog."; + let mut reader = data; + let mut buffer = [0u8; 19]; - // First read: read the entire buffer - assert!(cursor.read_exact(&mut buffer).is_ok()); - assert_eq!(&buffer, b"End"); - assert_eq!(cursor.position(), 3); + // Attempt to read exactly 19 bytes + assert!(reader.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"The quick brown fox"); + } - // Second read: attempt to read again, should fail + #[test] + fn test_slice_read_exact_less_than_available() { + let data: &[u8] = b"Hello, Stellar!"; + let mut reader = data; + let mut buffer = [0u8; 5]; + + // Attempt to read 5 bytes from the start + assert!(reader.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Hello"); + } + + #[test] + fn test_slice_read_exact_exact_eof() { + let data: &[u8] = b"Data"; + let mut reader = data; + let mut buffer = [0u8; 4]; + + // Attempt to read exactly 4 bytes, which is the entire slice + assert!(reader.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Data"); + + // Further attempt to read should fail with EOF let mut buffer_eof = [0u8; 1]; - let result = cursor.read_exact(&mut buffer_eof); + let result = reader.read_exact(&mut buffer_eof); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); - assert_eq!(cursor.position(), 3); // Position remains at EOF + assert_unexpected_eof!(result); } #[test] - fn test_slice_read_exact_success() { - let data = b"SliceReadTest"; - let mut slice = &data[..]; - let mut buffer = [0u8; 13]; // Exact length + fn test_slice_read_exact_past_eof() { + let data: &[u8] = b"Short"; + let mut reader = data; + let mut buffer = [0u8; 10]; // Requesting more bytes than available - // Using Read trait directly on slice - assert!(slice.read_exact(&mut buffer).is_ok()); - assert_eq!(&buffer, b"SliceReadTest"); + // Attempt to read 10 bytes from a 5-byte slice + let result = reader.read_exact(&mut buffer); + assert!(result.is_err()); + assert_unexpected_eof!(result); } #[test] - fn test_slice_read_exact_partial() { - let data = b"SlicePartial"; - let mut slice = &data[..]; - let mut buffer = [0u8; 20]; // Request more bytes than available + fn test_slice_read_exact_empty_buffer() { + let data: &[u8] = b"Non-empty"; + let mut reader = data; + let mut buffer = [0u8; 0]; // Zero-length buffer - // Using Read trait directly on slice - let result = slice.read_exact(&mut buffer); + // Attempt to read zero bytes + assert!(reader.read_exact(&mut buffer).is_ok()); + } + + #[test] + fn test_slice_read_exact_from_empty_slice() { + let data: &[u8] = b""; + let mut reader = data; + let mut buffer = [0u8; 5]; + + // Attempt to read from an empty slice + let result = reader.read_exact(&mut buffer); assert!(result.is_err()); + assert_unexpected_eof!(result); + } + + #[test] + fn test_slice_read_exact_multiple_reads() { + let data: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + let mut reader = data; + + let mut buffer1 = [0u8; 10]; + let mut buffer2 = [0u8; 10]; + let mut buffer3 = [0u8; 10]; // Only 6 bytes left + + // First read: 10 bytes + assert!(reader.read_exact(&mut buffer1).is_ok()); + assert_eq!(&buffer1, b"ABCDEFGHIJ"); + + // Second read: 10 bytes + assert!(reader.read_exact(&mut buffer2).is_ok()); + assert_eq!(&buffer2, b"KLMNOPQRST"); + + // Third read: Attempt to read 10 bytes, but only 6 are available + let result = reader.read_exact(&mut buffer3); + assert!(result.is_err()); + assert_unexpected_eof!(result); + } + + #[test] + fn test_cursor_write_success() { + let data = Vec::with_capacity(100); + let mut cursor = Cursor::new(data); + let write_data = b"Hello, Stellar!"; + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(&cursor.get_ref()[..], write_data); + assert_eq!(cursor.position(), write_data.len() as u64); + } + + #[test] + fn test_cursor_write_multiple_writes() { + let data = Vec::with_capacity(100); + let mut cursor = Cursor::new(data); + let write_data1: &[u8] = b"Hello, "; + let write_data2: &[u8] = b"Rust!"; + + // First write + assert!(cursor.write_all(write_data1).is_ok()); + assert_eq!(&cursor.get_ref()[..], write_data1); + assert_eq!(cursor.position(), write_data1.len() as u64); + + // Second write + assert!(cursor.write_all(write_data2).is_ok()); + let mut expected = Vec::new(); + expected.extend_from_slice(write_data1); + expected.extend_from_slice(write_data2); + assert_eq!(&cursor.get_ref()[..], expected.as_slice()); + assert_eq!(cursor.position(), expected.len() as u64); + } + + #[test] + fn test_cursor_write_empty() { + let data = Vec::with_capacity(100); + let mut cursor = Cursor::new(data); + let write_data = b""; + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(cursor.get_ref().len(), 0); + assert_eq!(cursor.position(), 0); + } + + #[test] + fn test_cursor_write_at_position() { + let mut data = vec![0u8; 10]; + { + let mut cursor = Cursor::new(&mut data[..]); + let write_data = b"Rust"; + + // Move cursor to position 6 + cursor.set_position(6); + assert_eq!(cursor.position(), 6); + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(cursor.position(), 10); + } + + let mut expected = vec![0u8; 10]; + expected[6..10].copy_from_slice(b"Rust"); + assert_eq!(&data[..], &expected[..]); + } + + #[test] + fn test_cursor_write_overflow() { + let mut data = vec![0u8; 5]; + let mut cursor = Cursor::new(&mut data[..]); + let write_data = b"Too long data"; + + let result = cursor.write_all(write_data); + assert!(result.is_err()); + #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); + assert_eq!(result.unwrap_err().kind(), io::ErrorKind::WriteZero); #[cfg(feature = "embedded_io")] assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof + result.unwrap_err().kind(), + embedded_io_extras::ErrorKind::WriteZero ); - // read_exact makes no promises about the content of the buffer on error + } + + #[test] + fn test_cursor_write_from_empty_cursor() { + let data = Vec::new(); + let mut cursor = Cursor::new(data); + let write_data = b"Initial Data"; + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(&cursor.get_ref()[..], write_data); + assert_eq!(cursor.position(), write_data.len() as u64); + } + + #[test] + fn test_cursor_write_partial() { + let mut data = [0u8; 5]; + let mut cursor = Cursor::new(&mut data[..]); + let write_data = b"Hello, Stellar!"; + + // Attempt to write data that exceeds the buffer size + // using `write` instead of `write_all` + let result = cursor.write(&write_data[..7]).unwrap(); + assert_eq!(result, 5); + assert_eq!(&cursor.get_ref()[..], b"Hello"); } } diff --git a/spec/output/generator_spec_rust/const.x/MyXDR.rs b/spec/output/generator_spec_rust/const.x/MyXDR.rs index 0b80a5d3f..40946ac79 100644 --- a/spec/output/generator_spec_rust/const.x/MyXDR.rs +++ b/spec/output/generator_spec_rust/const.x/MyXDR.rs @@ -2834,11 +2834,25 @@ mod test_io { use super::*; + macro_rules! assert_unexpected_eof { + ($result:expr) => {{ + let err = $result.unwrap_err(); + #[cfg(feature = "std")] + { + assert_eq!(err.kind(), io::ErrorKind::UnexpectedEof); + } + #[cfg(feature = "embedded_io")] + { + assert_eq!(err, embedded_io_extras::ReadExactError::UnexpectedEof); + } + }}; + } + #[test] - fn test_read_exact_success() { + fn test_cursor_read_exact_success() { let data = b"The quick brown fox jumps over the lazy dog."; let mut cursor = Cursor::new(data); - let mut buffer = [0u8; 19]; // Exactly the length of "The quick brown fox" + let mut buffer = [0u8; 19]; // Attempt to read exactly 19 bytes assert!(cursor.read_exact(&mut buffer).is_ok()); @@ -2847,8 +2861,8 @@ mod test_io { } #[test] - fn test_read_exact_less_than_available() { - let data = b"Hello, Rust!"; + fn test_cursor_read_exact_less_than_available() { + let data = b"Hello, Stellar!"; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 5]; @@ -2859,7 +2873,7 @@ mod test_io { } #[test] - fn test_read_exact_exact_eof() { + fn test_cursor_read_exact_exact_eof() { let data = b"Data"; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 4]; @@ -2873,21 +2887,12 @@ mod test_io { let mut buffer_eof = [0u8; 1]; let result = cursor.read_exact(&mut buffer_eof); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); assert_eq!(cursor.position(), 4); // Position should remain at EOF } #[test] - fn test_read_exact_past_eof() { + fn test_cursor_read_exact_past_eof() { let data = b"Short"; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 10]; // Requesting more bytes than available @@ -2895,24 +2900,15 @@ mod test_io { // Attempt to read 10 bytes from a 5-byte buffer let result = cursor.read_exact(&mut buffer); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); assert_eq!(cursor.position(), 5); // Position should move to EOF } #[test] - fn test_read_exact_empty_buffer() { + fn test_cursor_read_exact_empty_buffer() { let data = b"Non-empty"; let mut cursor = Cursor::new(data); - let mut buffer = [0u8; 0]; // Zero-length buffer + let mut buffer = [0u8; 0]; // Attempt to read zero bytes assert!(cursor.read_exact(&mut buffer).is_ok()); @@ -2920,7 +2916,7 @@ mod test_io { } #[test] - fn test_read_exact_from_empty_cursor() { + fn test_cursor_read_exact_from_empty_cursor() { let data: &[u8] = b""; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 5]; @@ -2928,21 +2924,12 @@ mod test_io { // Attempt to read from an empty cursor let result = cursor.read_exact(&mut buffer); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); assert_eq!(cursor.position(), 0); // Position remains at 0 } #[test] - fn test_read_exact_multiple_reads() { + fn test_cursor_read_exact_multiple_reads() { let data = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; let mut cursor = Cursor::new(data); @@ -2963,80 +2950,212 @@ mod test_io { // Third read: Attempt to read 10 bytes, but only 6 are available let result = cursor.read_exact(&mut buffer3); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); // read_exact makes no promises about the content of the buffer on error + // https://github.com/rust-lang/rust/blob/84ac80f1921afc243d71fd0caaa4f2838c294102/library/std/src/io/impls.rs#L287 // assert_eq!(&buffer3[..6], b"UVWXYZ"); assert_eq!(cursor.position(), 26); // Position should be at EOF } #[test] - fn test_cursor_read_exact_after_eof() { - let data = b"End"; - let mut cursor = Cursor::new(data); - let mut buffer = [0u8; 3]; + fn test_slice_read_exact_success() { + let data: &[u8] = b"The quick brown fox jumps over the lazy dog."; + let mut reader = data; + let mut buffer = [0u8; 19]; - // First read: read the entire buffer - assert!(cursor.read_exact(&mut buffer).is_ok()); - assert_eq!(&buffer, b"End"); - assert_eq!(cursor.position(), 3); + // Attempt to read exactly 19 bytes + assert!(reader.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"The quick brown fox"); + } - // Second read: attempt to read again, should fail + #[test] + fn test_slice_read_exact_less_than_available() { + let data: &[u8] = b"Hello, Stellar!"; + let mut reader = data; + let mut buffer = [0u8; 5]; + + // Attempt to read 5 bytes from the start + assert!(reader.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Hello"); + } + + #[test] + fn test_slice_read_exact_exact_eof() { + let data: &[u8] = b"Data"; + let mut reader = data; + let mut buffer = [0u8; 4]; + + // Attempt to read exactly 4 bytes, which is the entire slice + assert!(reader.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Data"); + + // Further attempt to read should fail with EOF let mut buffer_eof = [0u8; 1]; - let result = cursor.read_exact(&mut buffer_eof); + let result = reader.read_exact(&mut buffer_eof); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); - assert_eq!(cursor.position(), 3); // Position remains at EOF + assert_unexpected_eof!(result); } #[test] - fn test_slice_read_exact_success() { - let data = b"SliceReadTest"; - let mut slice = &data[..]; - let mut buffer = [0u8; 13]; // Exact length + fn test_slice_read_exact_past_eof() { + let data: &[u8] = b"Short"; + let mut reader = data; + let mut buffer = [0u8; 10]; // Requesting more bytes than available - // Using Read trait directly on slice - assert!(slice.read_exact(&mut buffer).is_ok()); - assert_eq!(&buffer, b"SliceReadTest"); + // Attempt to read 10 bytes from a 5-byte slice + let result = reader.read_exact(&mut buffer); + assert!(result.is_err()); + assert_unexpected_eof!(result); } #[test] - fn test_slice_read_exact_partial() { - let data = b"SlicePartial"; - let mut slice = &data[..]; - let mut buffer = [0u8; 20]; // Request more bytes than available + fn test_slice_read_exact_empty_buffer() { + let data: &[u8] = b"Non-empty"; + let mut reader = data; + let mut buffer = [0u8; 0]; // Zero-length buffer - // Using Read trait directly on slice - let result = slice.read_exact(&mut buffer); + // Attempt to read zero bytes + assert!(reader.read_exact(&mut buffer).is_ok()); + } + + #[test] + fn test_slice_read_exact_from_empty_slice() { + let data: &[u8] = b""; + let mut reader = data; + let mut buffer = [0u8; 5]; + + // Attempt to read from an empty slice + let result = reader.read_exact(&mut buffer); assert!(result.is_err()); + assert_unexpected_eof!(result); + } + + #[test] + fn test_slice_read_exact_multiple_reads() { + let data: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + let mut reader = data; + + let mut buffer1 = [0u8; 10]; + let mut buffer2 = [0u8; 10]; + let mut buffer3 = [0u8; 10]; // Only 6 bytes left + + // First read: 10 bytes + assert!(reader.read_exact(&mut buffer1).is_ok()); + assert_eq!(&buffer1, b"ABCDEFGHIJ"); + + // Second read: 10 bytes + assert!(reader.read_exact(&mut buffer2).is_ok()); + assert_eq!(&buffer2, b"KLMNOPQRST"); + + // Third read: Attempt to read 10 bytes, but only 6 are available + let result = reader.read_exact(&mut buffer3); + assert!(result.is_err()); + assert_unexpected_eof!(result); + } + + #[test] + fn test_cursor_write_success() { + let data = Vec::with_capacity(100); + let mut cursor = Cursor::new(data); + let write_data = b"Hello, Stellar!"; + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(&cursor.get_ref()[..], write_data); + assert_eq!(cursor.position(), write_data.len() as u64); + } + + #[test] + fn test_cursor_write_multiple_writes() { + let data = Vec::with_capacity(100); + let mut cursor = Cursor::new(data); + let write_data1: &[u8] = b"Hello, "; + let write_data2: &[u8] = b"Rust!"; + + // First write + assert!(cursor.write_all(write_data1).is_ok()); + assert_eq!(&cursor.get_ref()[..], write_data1); + assert_eq!(cursor.position(), write_data1.len() as u64); + + // Second write + assert!(cursor.write_all(write_data2).is_ok()); + let mut expected = Vec::new(); + expected.extend_from_slice(write_data1); + expected.extend_from_slice(write_data2); + assert_eq!(&cursor.get_ref()[..], expected.as_slice()); + assert_eq!(cursor.position(), expected.len() as u64); + } + + #[test] + fn test_cursor_write_empty() { + let data = Vec::with_capacity(100); + let mut cursor = Cursor::new(data); + let write_data = b""; + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(cursor.get_ref().len(), 0); + assert_eq!(cursor.position(), 0); + } + + #[test] + fn test_cursor_write_at_position() { + let mut data = vec![0u8; 10]; + { + let mut cursor = Cursor::new(&mut data[..]); + let write_data = b"Rust"; + + // Move cursor to position 6 + cursor.set_position(6); + assert_eq!(cursor.position(), 6); + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(cursor.position(), 10); + } + + let mut expected = vec![0u8; 10]; + expected[6..10].copy_from_slice(b"Rust"); + assert_eq!(&data[..], &expected[..]); + } + + #[test] + fn test_cursor_write_overflow() { + let mut data = vec![0u8; 5]; + let mut cursor = Cursor::new(&mut data[..]); + let write_data = b"Too long data"; + + let result = cursor.write_all(write_data); + assert!(result.is_err()); + #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); + assert_eq!(result.unwrap_err().kind(), io::ErrorKind::WriteZero); #[cfg(feature = "embedded_io")] assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof + result.unwrap_err().kind(), + embedded_io_extras::ErrorKind::WriteZero ); - // read_exact makes no promises about the content of the buffer on error + } + + #[test] + fn test_cursor_write_from_empty_cursor() { + let data = Vec::new(); + let mut cursor = Cursor::new(data); + let write_data = b"Initial Data"; + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(&cursor.get_ref()[..], write_data); + assert_eq!(cursor.position(), write_data.len() as u64); + } + + #[test] + fn test_cursor_write_partial() { + let mut data = [0u8; 5]; + let mut cursor = Cursor::new(&mut data[..]); + let write_data = b"Hello, Stellar!"; + + // Attempt to write data that exceeds the buffer size + // using `write` instead of `write_all` + let result = cursor.write(&write_data[..7]).unwrap(); + assert_eq!(result, 5); + assert_eq!(&cursor.get_ref()[..], b"Hello"); } } diff --git a/spec/output/generator_spec_rust/enum.x/MyXDR.rs b/spec/output/generator_spec_rust/enum.x/MyXDR.rs index ed96f0d60..cfa08956e 100644 --- a/spec/output/generator_spec_rust/enum.x/MyXDR.rs +++ b/spec/output/generator_spec_rust/enum.x/MyXDR.rs @@ -2834,11 +2834,25 @@ mod test_io { use super::*; + macro_rules! assert_unexpected_eof { + ($result:expr) => {{ + let err = $result.unwrap_err(); + #[cfg(feature = "std")] + { + assert_eq!(err.kind(), io::ErrorKind::UnexpectedEof); + } + #[cfg(feature = "embedded_io")] + { + assert_eq!(err, embedded_io_extras::ReadExactError::UnexpectedEof); + } + }}; + } + #[test] - fn test_read_exact_success() { + fn test_cursor_read_exact_success() { let data = b"The quick brown fox jumps over the lazy dog."; let mut cursor = Cursor::new(data); - let mut buffer = [0u8; 19]; // Exactly the length of "The quick brown fox" + let mut buffer = [0u8; 19]; // Attempt to read exactly 19 bytes assert!(cursor.read_exact(&mut buffer).is_ok()); @@ -2847,8 +2861,8 @@ mod test_io { } #[test] - fn test_read_exact_less_than_available() { - let data = b"Hello, Rust!"; + fn test_cursor_read_exact_less_than_available() { + let data = b"Hello, Stellar!"; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 5]; @@ -2859,7 +2873,7 @@ mod test_io { } #[test] - fn test_read_exact_exact_eof() { + fn test_cursor_read_exact_exact_eof() { let data = b"Data"; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 4]; @@ -2873,21 +2887,12 @@ mod test_io { let mut buffer_eof = [0u8; 1]; let result = cursor.read_exact(&mut buffer_eof); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); assert_eq!(cursor.position(), 4); // Position should remain at EOF } #[test] - fn test_read_exact_past_eof() { + fn test_cursor_read_exact_past_eof() { let data = b"Short"; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 10]; // Requesting more bytes than available @@ -2895,24 +2900,15 @@ mod test_io { // Attempt to read 10 bytes from a 5-byte buffer let result = cursor.read_exact(&mut buffer); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); assert_eq!(cursor.position(), 5); // Position should move to EOF } #[test] - fn test_read_exact_empty_buffer() { + fn test_cursor_read_exact_empty_buffer() { let data = b"Non-empty"; let mut cursor = Cursor::new(data); - let mut buffer = [0u8; 0]; // Zero-length buffer + let mut buffer = [0u8; 0]; // Attempt to read zero bytes assert!(cursor.read_exact(&mut buffer).is_ok()); @@ -2920,7 +2916,7 @@ mod test_io { } #[test] - fn test_read_exact_from_empty_cursor() { + fn test_cursor_read_exact_from_empty_cursor() { let data: &[u8] = b""; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 5]; @@ -2928,21 +2924,12 @@ mod test_io { // Attempt to read from an empty cursor let result = cursor.read_exact(&mut buffer); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); assert_eq!(cursor.position(), 0); // Position remains at 0 } #[test] - fn test_read_exact_multiple_reads() { + fn test_cursor_read_exact_multiple_reads() { let data = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; let mut cursor = Cursor::new(data); @@ -2963,80 +2950,212 @@ mod test_io { // Third read: Attempt to read 10 bytes, but only 6 are available let result = cursor.read_exact(&mut buffer3); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); // read_exact makes no promises about the content of the buffer on error + // https://github.com/rust-lang/rust/blob/84ac80f1921afc243d71fd0caaa4f2838c294102/library/std/src/io/impls.rs#L287 // assert_eq!(&buffer3[..6], b"UVWXYZ"); assert_eq!(cursor.position(), 26); // Position should be at EOF } #[test] - fn test_cursor_read_exact_after_eof() { - let data = b"End"; - let mut cursor = Cursor::new(data); - let mut buffer = [0u8; 3]; + fn test_slice_read_exact_success() { + let data: &[u8] = b"The quick brown fox jumps over the lazy dog."; + let mut reader = data; + let mut buffer = [0u8; 19]; - // First read: read the entire buffer - assert!(cursor.read_exact(&mut buffer).is_ok()); - assert_eq!(&buffer, b"End"); - assert_eq!(cursor.position(), 3); + // Attempt to read exactly 19 bytes + assert!(reader.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"The quick brown fox"); + } - // Second read: attempt to read again, should fail + #[test] + fn test_slice_read_exact_less_than_available() { + let data: &[u8] = b"Hello, Stellar!"; + let mut reader = data; + let mut buffer = [0u8; 5]; + + // Attempt to read 5 bytes from the start + assert!(reader.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Hello"); + } + + #[test] + fn test_slice_read_exact_exact_eof() { + let data: &[u8] = b"Data"; + let mut reader = data; + let mut buffer = [0u8; 4]; + + // Attempt to read exactly 4 bytes, which is the entire slice + assert!(reader.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Data"); + + // Further attempt to read should fail with EOF let mut buffer_eof = [0u8; 1]; - let result = cursor.read_exact(&mut buffer_eof); + let result = reader.read_exact(&mut buffer_eof); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); - assert_eq!(cursor.position(), 3); // Position remains at EOF + assert_unexpected_eof!(result); } #[test] - fn test_slice_read_exact_success() { - let data = b"SliceReadTest"; - let mut slice = &data[..]; - let mut buffer = [0u8; 13]; // Exact length + fn test_slice_read_exact_past_eof() { + let data: &[u8] = b"Short"; + let mut reader = data; + let mut buffer = [0u8; 10]; // Requesting more bytes than available - // Using Read trait directly on slice - assert!(slice.read_exact(&mut buffer).is_ok()); - assert_eq!(&buffer, b"SliceReadTest"); + // Attempt to read 10 bytes from a 5-byte slice + let result = reader.read_exact(&mut buffer); + assert!(result.is_err()); + assert_unexpected_eof!(result); } #[test] - fn test_slice_read_exact_partial() { - let data = b"SlicePartial"; - let mut slice = &data[..]; - let mut buffer = [0u8; 20]; // Request more bytes than available + fn test_slice_read_exact_empty_buffer() { + let data: &[u8] = b"Non-empty"; + let mut reader = data; + let mut buffer = [0u8; 0]; // Zero-length buffer - // Using Read trait directly on slice - let result = slice.read_exact(&mut buffer); + // Attempt to read zero bytes + assert!(reader.read_exact(&mut buffer).is_ok()); + } + + #[test] + fn test_slice_read_exact_from_empty_slice() { + let data: &[u8] = b""; + let mut reader = data; + let mut buffer = [0u8; 5]; + + // Attempt to read from an empty slice + let result = reader.read_exact(&mut buffer); assert!(result.is_err()); + assert_unexpected_eof!(result); + } + + #[test] + fn test_slice_read_exact_multiple_reads() { + let data: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + let mut reader = data; + + let mut buffer1 = [0u8; 10]; + let mut buffer2 = [0u8; 10]; + let mut buffer3 = [0u8; 10]; // Only 6 bytes left + + // First read: 10 bytes + assert!(reader.read_exact(&mut buffer1).is_ok()); + assert_eq!(&buffer1, b"ABCDEFGHIJ"); + + // Second read: 10 bytes + assert!(reader.read_exact(&mut buffer2).is_ok()); + assert_eq!(&buffer2, b"KLMNOPQRST"); + + // Third read: Attempt to read 10 bytes, but only 6 are available + let result = reader.read_exact(&mut buffer3); + assert!(result.is_err()); + assert_unexpected_eof!(result); + } + + #[test] + fn test_cursor_write_success() { + let data = Vec::with_capacity(100); + let mut cursor = Cursor::new(data); + let write_data = b"Hello, Stellar!"; + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(&cursor.get_ref()[..], write_data); + assert_eq!(cursor.position(), write_data.len() as u64); + } + + #[test] + fn test_cursor_write_multiple_writes() { + let data = Vec::with_capacity(100); + let mut cursor = Cursor::new(data); + let write_data1: &[u8] = b"Hello, "; + let write_data2: &[u8] = b"Rust!"; + + // First write + assert!(cursor.write_all(write_data1).is_ok()); + assert_eq!(&cursor.get_ref()[..], write_data1); + assert_eq!(cursor.position(), write_data1.len() as u64); + + // Second write + assert!(cursor.write_all(write_data2).is_ok()); + let mut expected = Vec::new(); + expected.extend_from_slice(write_data1); + expected.extend_from_slice(write_data2); + assert_eq!(&cursor.get_ref()[..], expected.as_slice()); + assert_eq!(cursor.position(), expected.len() as u64); + } + + #[test] + fn test_cursor_write_empty() { + let data = Vec::with_capacity(100); + let mut cursor = Cursor::new(data); + let write_data = b""; + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(cursor.get_ref().len(), 0); + assert_eq!(cursor.position(), 0); + } + + #[test] + fn test_cursor_write_at_position() { + let mut data = vec![0u8; 10]; + { + let mut cursor = Cursor::new(&mut data[..]); + let write_data = b"Rust"; + + // Move cursor to position 6 + cursor.set_position(6); + assert_eq!(cursor.position(), 6); + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(cursor.position(), 10); + } + + let mut expected = vec![0u8; 10]; + expected[6..10].copy_from_slice(b"Rust"); + assert_eq!(&data[..], &expected[..]); + } + + #[test] + fn test_cursor_write_overflow() { + let mut data = vec![0u8; 5]; + let mut cursor = Cursor::new(&mut data[..]); + let write_data = b"Too long data"; + + let result = cursor.write_all(write_data); + assert!(result.is_err()); + #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); + assert_eq!(result.unwrap_err().kind(), io::ErrorKind::WriteZero); #[cfg(feature = "embedded_io")] assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof + result.unwrap_err().kind(), + embedded_io_extras::ErrorKind::WriteZero ); - // read_exact makes no promises about the content of the buffer on error + } + + #[test] + fn test_cursor_write_from_empty_cursor() { + let data = Vec::new(); + let mut cursor = Cursor::new(data); + let write_data = b"Initial Data"; + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(&cursor.get_ref()[..], write_data); + assert_eq!(cursor.position(), write_data.len() as u64); + } + + #[test] + fn test_cursor_write_partial() { + let mut data = [0u8; 5]; + let mut cursor = Cursor::new(&mut data[..]); + let write_data = b"Hello, Stellar!"; + + // Attempt to write data that exceeds the buffer size + // using `write` instead of `write_all` + let result = cursor.write(&write_data[..7]).unwrap(); + assert_eq!(result, 5); + assert_eq!(&cursor.get_ref()[..], b"Hello"); } } diff --git a/spec/output/generator_spec_rust/nesting.x/MyXDR.rs b/spec/output/generator_spec_rust/nesting.x/MyXDR.rs index 7d4c93717..c44e89dfd 100644 --- a/spec/output/generator_spec_rust/nesting.x/MyXDR.rs +++ b/spec/output/generator_spec_rust/nesting.x/MyXDR.rs @@ -2834,11 +2834,25 @@ mod test_io { use super::*; + macro_rules! assert_unexpected_eof { + ($result:expr) => {{ + let err = $result.unwrap_err(); + #[cfg(feature = "std")] + { + assert_eq!(err.kind(), io::ErrorKind::UnexpectedEof); + } + #[cfg(feature = "embedded_io")] + { + assert_eq!(err, embedded_io_extras::ReadExactError::UnexpectedEof); + } + }}; + } + #[test] - fn test_read_exact_success() { + fn test_cursor_read_exact_success() { let data = b"The quick brown fox jumps over the lazy dog."; let mut cursor = Cursor::new(data); - let mut buffer = [0u8; 19]; // Exactly the length of "The quick brown fox" + let mut buffer = [0u8; 19]; // Attempt to read exactly 19 bytes assert!(cursor.read_exact(&mut buffer).is_ok()); @@ -2847,8 +2861,8 @@ mod test_io { } #[test] - fn test_read_exact_less_than_available() { - let data = b"Hello, Rust!"; + fn test_cursor_read_exact_less_than_available() { + let data = b"Hello, Stellar!"; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 5]; @@ -2859,7 +2873,7 @@ mod test_io { } #[test] - fn test_read_exact_exact_eof() { + fn test_cursor_read_exact_exact_eof() { let data = b"Data"; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 4]; @@ -2873,21 +2887,12 @@ mod test_io { let mut buffer_eof = [0u8; 1]; let result = cursor.read_exact(&mut buffer_eof); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); assert_eq!(cursor.position(), 4); // Position should remain at EOF } #[test] - fn test_read_exact_past_eof() { + fn test_cursor_read_exact_past_eof() { let data = b"Short"; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 10]; // Requesting more bytes than available @@ -2895,24 +2900,15 @@ mod test_io { // Attempt to read 10 bytes from a 5-byte buffer let result = cursor.read_exact(&mut buffer); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); assert_eq!(cursor.position(), 5); // Position should move to EOF } #[test] - fn test_read_exact_empty_buffer() { + fn test_cursor_read_exact_empty_buffer() { let data = b"Non-empty"; let mut cursor = Cursor::new(data); - let mut buffer = [0u8; 0]; // Zero-length buffer + let mut buffer = [0u8; 0]; // Attempt to read zero bytes assert!(cursor.read_exact(&mut buffer).is_ok()); @@ -2920,7 +2916,7 @@ mod test_io { } #[test] - fn test_read_exact_from_empty_cursor() { + fn test_cursor_read_exact_from_empty_cursor() { let data: &[u8] = b""; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 5]; @@ -2928,21 +2924,12 @@ mod test_io { // Attempt to read from an empty cursor let result = cursor.read_exact(&mut buffer); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); assert_eq!(cursor.position(), 0); // Position remains at 0 } #[test] - fn test_read_exact_multiple_reads() { + fn test_cursor_read_exact_multiple_reads() { let data = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; let mut cursor = Cursor::new(data); @@ -2963,80 +2950,212 @@ mod test_io { // Third read: Attempt to read 10 bytes, but only 6 are available let result = cursor.read_exact(&mut buffer3); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); // read_exact makes no promises about the content of the buffer on error + // https://github.com/rust-lang/rust/blob/84ac80f1921afc243d71fd0caaa4f2838c294102/library/std/src/io/impls.rs#L287 // assert_eq!(&buffer3[..6], b"UVWXYZ"); assert_eq!(cursor.position(), 26); // Position should be at EOF } #[test] - fn test_cursor_read_exact_after_eof() { - let data = b"End"; - let mut cursor = Cursor::new(data); - let mut buffer = [0u8; 3]; + fn test_slice_read_exact_success() { + let data: &[u8] = b"The quick brown fox jumps over the lazy dog."; + let mut reader = data; + let mut buffer = [0u8; 19]; - // First read: read the entire buffer - assert!(cursor.read_exact(&mut buffer).is_ok()); - assert_eq!(&buffer, b"End"); - assert_eq!(cursor.position(), 3); + // Attempt to read exactly 19 bytes + assert!(reader.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"The quick brown fox"); + } - // Second read: attempt to read again, should fail + #[test] + fn test_slice_read_exact_less_than_available() { + let data: &[u8] = b"Hello, Stellar!"; + let mut reader = data; + let mut buffer = [0u8; 5]; + + // Attempt to read 5 bytes from the start + assert!(reader.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Hello"); + } + + #[test] + fn test_slice_read_exact_exact_eof() { + let data: &[u8] = b"Data"; + let mut reader = data; + let mut buffer = [0u8; 4]; + + // Attempt to read exactly 4 bytes, which is the entire slice + assert!(reader.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Data"); + + // Further attempt to read should fail with EOF let mut buffer_eof = [0u8; 1]; - let result = cursor.read_exact(&mut buffer_eof); + let result = reader.read_exact(&mut buffer_eof); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); - assert_eq!(cursor.position(), 3); // Position remains at EOF + assert_unexpected_eof!(result); } #[test] - fn test_slice_read_exact_success() { - let data = b"SliceReadTest"; - let mut slice = &data[..]; - let mut buffer = [0u8; 13]; // Exact length + fn test_slice_read_exact_past_eof() { + let data: &[u8] = b"Short"; + let mut reader = data; + let mut buffer = [0u8; 10]; // Requesting more bytes than available - // Using Read trait directly on slice - assert!(slice.read_exact(&mut buffer).is_ok()); - assert_eq!(&buffer, b"SliceReadTest"); + // Attempt to read 10 bytes from a 5-byte slice + let result = reader.read_exact(&mut buffer); + assert!(result.is_err()); + assert_unexpected_eof!(result); } #[test] - fn test_slice_read_exact_partial() { - let data = b"SlicePartial"; - let mut slice = &data[..]; - let mut buffer = [0u8; 20]; // Request more bytes than available + fn test_slice_read_exact_empty_buffer() { + let data: &[u8] = b"Non-empty"; + let mut reader = data; + let mut buffer = [0u8; 0]; // Zero-length buffer - // Using Read trait directly on slice - let result = slice.read_exact(&mut buffer); + // Attempt to read zero bytes + assert!(reader.read_exact(&mut buffer).is_ok()); + } + + #[test] + fn test_slice_read_exact_from_empty_slice() { + let data: &[u8] = b""; + let mut reader = data; + let mut buffer = [0u8; 5]; + + // Attempt to read from an empty slice + let result = reader.read_exact(&mut buffer); assert!(result.is_err()); + assert_unexpected_eof!(result); + } + + #[test] + fn test_slice_read_exact_multiple_reads() { + let data: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + let mut reader = data; + + let mut buffer1 = [0u8; 10]; + let mut buffer2 = [0u8; 10]; + let mut buffer3 = [0u8; 10]; // Only 6 bytes left + + // First read: 10 bytes + assert!(reader.read_exact(&mut buffer1).is_ok()); + assert_eq!(&buffer1, b"ABCDEFGHIJ"); + + // Second read: 10 bytes + assert!(reader.read_exact(&mut buffer2).is_ok()); + assert_eq!(&buffer2, b"KLMNOPQRST"); + + // Third read: Attempt to read 10 bytes, but only 6 are available + let result = reader.read_exact(&mut buffer3); + assert!(result.is_err()); + assert_unexpected_eof!(result); + } + + #[test] + fn test_cursor_write_success() { + let data = Vec::with_capacity(100); + let mut cursor = Cursor::new(data); + let write_data = b"Hello, Stellar!"; + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(&cursor.get_ref()[..], write_data); + assert_eq!(cursor.position(), write_data.len() as u64); + } + + #[test] + fn test_cursor_write_multiple_writes() { + let data = Vec::with_capacity(100); + let mut cursor = Cursor::new(data); + let write_data1: &[u8] = b"Hello, "; + let write_data2: &[u8] = b"Rust!"; + + // First write + assert!(cursor.write_all(write_data1).is_ok()); + assert_eq!(&cursor.get_ref()[..], write_data1); + assert_eq!(cursor.position(), write_data1.len() as u64); + + // Second write + assert!(cursor.write_all(write_data2).is_ok()); + let mut expected = Vec::new(); + expected.extend_from_slice(write_data1); + expected.extend_from_slice(write_data2); + assert_eq!(&cursor.get_ref()[..], expected.as_slice()); + assert_eq!(cursor.position(), expected.len() as u64); + } + + #[test] + fn test_cursor_write_empty() { + let data = Vec::with_capacity(100); + let mut cursor = Cursor::new(data); + let write_data = b""; + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(cursor.get_ref().len(), 0); + assert_eq!(cursor.position(), 0); + } + + #[test] + fn test_cursor_write_at_position() { + let mut data = vec![0u8; 10]; + { + let mut cursor = Cursor::new(&mut data[..]); + let write_data = b"Rust"; + + // Move cursor to position 6 + cursor.set_position(6); + assert_eq!(cursor.position(), 6); + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(cursor.position(), 10); + } + + let mut expected = vec![0u8; 10]; + expected[6..10].copy_from_slice(b"Rust"); + assert_eq!(&data[..], &expected[..]); + } + + #[test] + fn test_cursor_write_overflow() { + let mut data = vec![0u8; 5]; + let mut cursor = Cursor::new(&mut data[..]); + let write_data = b"Too long data"; + + let result = cursor.write_all(write_data); + assert!(result.is_err()); + #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); + assert_eq!(result.unwrap_err().kind(), io::ErrorKind::WriteZero); #[cfg(feature = "embedded_io")] assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof + result.unwrap_err().kind(), + embedded_io_extras::ErrorKind::WriteZero ); - // read_exact makes no promises about the content of the buffer on error + } + + #[test] + fn test_cursor_write_from_empty_cursor() { + let data = Vec::new(); + let mut cursor = Cursor::new(data); + let write_data = b"Initial Data"; + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(&cursor.get_ref()[..], write_data); + assert_eq!(cursor.position(), write_data.len() as u64); + } + + #[test] + fn test_cursor_write_partial() { + let mut data = [0u8; 5]; + let mut cursor = Cursor::new(&mut data[..]); + let write_data = b"Hello, Stellar!"; + + // Attempt to write data that exceeds the buffer size + // using `write` instead of `write_all` + let result = cursor.write(&write_data[..7]).unwrap(); + assert_eq!(result, 5); + assert_eq!(&cursor.get_ref()[..], b"Hello"); } } diff --git a/spec/output/generator_spec_rust/optional.x/MyXDR.rs b/spec/output/generator_spec_rust/optional.x/MyXDR.rs index ca1a018d6..e606898a2 100644 --- a/spec/output/generator_spec_rust/optional.x/MyXDR.rs +++ b/spec/output/generator_spec_rust/optional.x/MyXDR.rs @@ -2834,11 +2834,25 @@ mod test_io { use super::*; + macro_rules! assert_unexpected_eof { + ($result:expr) => {{ + let err = $result.unwrap_err(); + #[cfg(feature = "std")] + { + assert_eq!(err.kind(), io::ErrorKind::UnexpectedEof); + } + #[cfg(feature = "embedded_io")] + { + assert_eq!(err, embedded_io_extras::ReadExactError::UnexpectedEof); + } + }}; + } + #[test] - fn test_read_exact_success() { + fn test_cursor_read_exact_success() { let data = b"The quick brown fox jumps over the lazy dog."; let mut cursor = Cursor::new(data); - let mut buffer = [0u8; 19]; // Exactly the length of "The quick brown fox" + let mut buffer = [0u8; 19]; // Attempt to read exactly 19 bytes assert!(cursor.read_exact(&mut buffer).is_ok()); @@ -2847,8 +2861,8 @@ mod test_io { } #[test] - fn test_read_exact_less_than_available() { - let data = b"Hello, Rust!"; + fn test_cursor_read_exact_less_than_available() { + let data = b"Hello, Stellar!"; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 5]; @@ -2859,7 +2873,7 @@ mod test_io { } #[test] - fn test_read_exact_exact_eof() { + fn test_cursor_read_exact_exact_eof() { let data = b"Data"; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 4]; @@ -2873,21 +2887,12 @@ mod test_io { let mut buffer_eof = [0u8; 1]; let result = cursor.read_exact(&mut buffer_eof); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); assert_eq!(cursor.position(), 4); // Position should remain at EOF } #[test] - fn test_read_exact_past_eof() { + fn test_cursor_read_exact_past_eof() { let data = b"Short"; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 10]; // Requesting more bytes than available @@ -2895,24 +2900,15 @@ mod test_io { // Attempt to read 10 bytes from a 5-byte buffer let result = cursor.read_exact(&mut buffer); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); assert_eq!(cursor.position(), 5); // Position should move to EOF } #[test] - fn test_read_exact_empty_buffer() { + fn test_cursor_read_exact_empty_buffer() { let data = b"Non-empty"; let mut cursor = Cursor::new(data); - let mut buffer = [0u8; 0]; // Zero-length buffer + let mut buffer = [0u8; 0]; // Attempt to read zero bytes assert!(cursor.read_exact(&mut buffer).is_ok()); @@ -2920,7 +2916,7 @@ mod test_io { } #[test] - fn test_read_exact_from_empty_cursor() { + fn test_cursor_read_exact_from_empty_cursor() { let data: &[u8] = b""; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 5]; @@ -2928,21 +2924,12 @@ mod test_io { // Attempt to read from an empty cursor let result = cursor.read_exact(&mut buffer); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); assert_eq!(cursor.position(), 0); // Position remains at 0 } #[test] - fn test_read_exact_multiple_reads() { + fn test_cursor_read_exact_multiple_reads() { let data = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; let mut cursor = Cursor::new(data); @@ -2963,80 +2950,212 @@ mod test_io { // Third read: Attempt to read 10 bytes, but only 6 are available let result = cursor.read_exact(&mut buffer3); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); // read_exact makes no promises about the content of the buffer on error + // https://github.com/rust-lang/rust/blob/84ac80f1921afc243d71fd0caaa4f2838c294102/library/std/src/io/impls.rs#L287 // assert_eq!(&buffer3[..6], b"UVWXYZ"); assert_eq!(cursor.position(), 26); // Position should be at EOF } #[test] - fn test_cursor_read_exact_after_eof() { - let data = b"End"; - let mut cursor = Cursor::new(data); - let mut buffer = [0u8; 3]; + fn test_slice_read_exact_success() { + let data: &[u8] = b"The quick brown fox jumps over the lazy dog."; + let mut reader = data; + let mut buffer = [0u8; 19]; - // First read: read the entire buffer - assert!(cursor.read_exact(&mut buffer).is_ok()); - assert_eq!(&buffer, b"End"); - assert_eq!(cursor.position(), 3); + // Attempt to read exactly 19 bytes + assert!(reader.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"The quick brown fox"); + } - // Second read: attempt to read again, should fail + #[test] + fn test_slice_read_exact_less_than_available() { + let data: &[u8] = b"Hello, Stellar!"; + let mut reader = data; + let mut buffer = [0u8; 5]; + + // Attempt to read 5 bytes from the start + assert!(reader.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Hello"); + } + + #[test] + fn test_slice_read_exact_exact_eof() { + let data: &[u8] = b"Data"; + let mut reader = data; + let mut buffer = [0u8; 4]; + + // Attempt to read exactly 4 bytes, which is the entire slice + assert!(reader.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Data"); + + // Further attempt to read should fail with EOF let mut buffer_eof = [0u8; 1]; - let result = cursor.read_exact(&mut buffer_eof); + let result = reader.read_exact(&mut buffer_eof); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); - assert_eq!(cursor.position(), 3); // Position remains at EOF + assert_unexpected_eof!(result); } #[test] - fn test_slice_read_exact_success() { - let data = b"SliceReadTest"; - let mut slice = &data[..]; - let mut buffer = [0u8; 13]; // Exact length + fn test_slice_read_exact_past_eof() { + let data: &[u8] = b"Short"; + let mut reader = data; + let mut buffer = [0u8; 10]; // Requesting more bytes than available - // Using Read trait directly on slice - assert!(slice.read_exact(&mut buffer).is_ok()); - assert_eq!(&buffer, b"SliceReadTest"); + // Attempt to read 10 bytes from a 5-byte slice + let result = reader.read_exact(&mut buffer); + assert!(result.is_err()); + assert_unexpected_eof!(result); } #[test] - fn test_slice_read_exact_partial() { - let data = b"SlicePartial"; - let mut slice = &data[..]; - let mut buffer = [0u8; 20]; // Request more bytes than available + fn test_slice_read_exact_empty_buffer() { + let data: &[u8] = b"Non-empty"; + let mut reader = data; + let mut buffer = [0u8; 0]; // Zero-length buffer - // Using Read trait directly on slice - let result = slice.read_exact(&mut buffer); + // Attempt to read zero bytes + assert!(reader.read_exact(&mut buffer).is_ok()); + } + + #[test] + fn test_slice_read_exact_from_empty_slice() { + let data: &[u8] = b""; + let mut reader = data; + let mut buffer = [0u8; 5]; + + // Attempt to read from an empty slice + let result = reader.read_exact(&mut buffer); assert!(result.is_err()); + assert_unexpected_eof!(result); + } + + #[test] + fn test_slice_read_exact_multiple_reads() { + let data: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + let mut reader = data; + + let mut buffer1 = [0u8; 10]; + let mut buffer2 = [0u8; 10]; + let mut buffer3 = [0u8; 10]; // Only 6 bytes left + + // First read: 10 bytes + assert!(reader.read_exact(&mut buffer1).is_ok()); + assert_eq!(&buffer1, b"ABCDEFGHIJ"); + + // Second read: 10 bytes + assert!(reader.read_exact(&mut buffer2).is_ok()); + assert_eq!(&buffer2, b"KLMNOPQRST"); + + // Third read: Attempt to read 10 bytes, but only 6 are available + let result = reader.read_exact(&mut buffer3); + assert!(result.is_err()); + assert_unexpected_eof!(result); + } + + #[test] + fn test_cursor_write_success() { + let data = Vec::with_capacity(100); + let mut cursor = Cursor::new(data); + let write_data = b"Hello, Stellar!"; + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(&cursor.get_ref()[..], write_data); + assert_eq!(cursor.position(), write_data.len() as u64); + } + + #[test] + fn test_cursor_write_multiple_writes() { + let data = Vec::with_capacity(100); + let mut cursor = Cursor::new(data); + let write_data1: &[u8] = b"Hello, "; + let write_data2: &[u8] = b"Rust!"; + + // First write + assert!(cursor.write_all(write_data1).is_ok()); + assert_eq!(&cursor.get_ref()[..], write_data1); + assert_eq!(cursor.position(), write_data1.len() as u64); + + // Second write + assert!(cursor.write_all(write_data2).is_ok()); + let mut expected = Vec::new(); + expected.extend_from_slice(write_data1); + expected.extend_from_slice(write_data2); + assert_eq!(&cursor.get_ref()[..], expected.as_slice()); + assert_eq!(cursor.position(), expected.len() as u64); + } + + #[test] + fn test_cursor_write_empty() { + let data = Vec::with_capacity(100); + let mut cursor = Cursor::new(data); + let write_data = b""; + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(cursor.get_ref().len(), 0); + assert_eq!(cursor.position(), 0); + } + + #[test] + fn test_cursor_write_at_position() { + let mut data = vec![0u8; 10]; + { + let mut cursor = Cursor::new(&mut data[..]); + let write_data = b"Rust"; + + // Move cursor to position 6 + cursor.set_position(6); + assert_eq!(cursor.position(), 6); + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(cursor.position(), 10); + } + + let mut expected = vec![0u8; 10]; + expected[6..10].copy_from_slice(b"Rust"); + assert_eq!(&data[..], &expected[..]); + } + + #[test] + fn test_cursor_write_overflow() { + let mut data = vec![0u8; 5]; + let mut cursor = Cursor::new(&mut data[..]); + let write_data = b"Too long data"; + + let result = cursor.write_all(write_data); + assert!(result.is_err()); + #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); + assert_eq!(result.unwrap_err().kind(), io::ErrorKind::WriteZero); #[cfg(feature = "embedded_io")] assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof + result.unwrap_err().kind(), + embedded_io_extras::ErrorKind::WriteZero ); - // read_exact makes no promises about the content of the buffer on error + } + + #[test] + fn test_cursor_write_from_empty_cursor() { + let data = Vec::new(); + let mut cursor = Cursor::new(data); + let write_data = b"Initial Data"; + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(&cursor.get_ref()[..], write_data); + assert_eq!(cursor.position(), write_data.len() as u64); + } + + #[test] + fn test_cursor_write_partial() { + let mut data = [0u8; 5]; + let mut cursor = Cursor::new(&mut data[..]); + let write_data = b"Hello, Stellar!"; + + // Attempt to write data that exceeds the buffer size + // using `write` instead of `write_all` + let result = cursor.write(&write_data[..7]).unwrap(); + assert_eq!(result, 5); + assert_eq!(&cursor.get_ref()[..], b"Hello"); } } diff --git a/spec/output/generator_spec_rust/struct.x/MyXDR.rs b/spec/output/generator_spec_rust/struct.x/MyXDR.rs index e48a6fe44..d75ee36aa 100644 --- a/spec/output/generator_spec_rust/struct.x/MyXDR.rs +++ b/spec/output/generator_spec_rust/struct.x/MyXDR.rs @@ -2834,11 +2834,25 @@ mod test_io { use super::*; + macro_rules! assert_unexpected_eof { + ($result:expr) => {{ + let err = $result.unwrap_err(); + #[cfg(feature = "std")] + { + assert_eq!(err.kind(), io::ErrorKind::UnexpectedEof); + } + #[cfg(feature = "embedded_io")] + { + assert_eq!(err, embedded_io_extras::ReadExactError::UnexpectedEof); + } + }}; + } + #[test] - fn test_read_exact_success() { + fn test_cursor_read_exact_success() { let data = b"The quick brown fox jumps over the lazy dog."; let mut cursor = Cursor::new(data); - let mut buffer = [0u8; 19]; // Exactly the length of "The quick brown fox" + let mut buffer = [0u8; 19]; // Attempt to read exactly 19 bytes assert!(cursor.read_exact(&mut buffer).is_ok()); @@ -2847,8 +2861,8 @@ mod test_io { } #[test] - fn test_read_exact_less_than_available() { - let data = b"Hello, Rust!"; + fn test_cursor_read_exact_less_than_available() { + let data = b"Hello, Stellar!"; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 5]; @@ -2859,7 +2873,7 @@ mod test_io { } #[test] - fn test_read_exact_exact_eof() { + fn test_cursor_read_exact_exact_eof() { let data = b"Data"; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 4]; @@ -2873,21 +2887,12 @@ mod test_io { let mut buffer_eof = [0u8; 1]; let result = cursor.read_exact(&mut buffer_eof); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); assert_eq!(cursor.position(), 4); // Position should remain at EOF } #[test] - fn test_read_exact_past_eof() { + fn test_cursor_read_exact_past_eof() { let data = b"Short"; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 10]; // Requesting more bytes than available @@ -2895,24 +2900,15 @@ mod test_io { // Attempt to read 10 bytes from a 5-byte buffer let result = cursor.read_exact(&mut buffer); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); assert_eq!(cursor.position(), 5); // Position should move to EOF } #[test] - fn test_read_exact_empty_buffer() { + fn test_cursor_read_exact_empty_buffer() { let data = b"Non-empty"; let mut cursor = Cursor::new(data); - let mut buffer = [0u8; 0]; // Zero-length buffer + let mut buffer = [0u8; 0]; // Attempt to read zero bytes assert!(cursor.read_exact(&mut buffer).is_ok()); @@ -2920,7 +2916,7 @@ mod test_io { } #[test] - fn test_read_exact_from_empty_cursor() { + fn test_cursor_read_exact_from_empty_cursor() { let data: &[u8] = b""; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 5]; @@ -2928,21 +2924,12 @@ mod test_io { // Attempt to read from an empty cursor let result = cursor.read_exact(&mut buffer); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); assert_eq!(cursor.position(), 0); // Position remains at 0 } #[test] - fn test_read_exact_multiple_reads() { + fn test_cursor_read_exact_multiple_reads() { let data = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; let mut cursor = Cursor::new(data); @@ -2963,80 +2950,212 @@ mod test_io { // Third read: Attempt to read 10 bytes, but only 6 are available let result = cursor.read_exact(&mut buffer3); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); // read_exact makes no promises about the content of the buffer on error + // https://github.com/rust-lang/rust/blob/84ac80f1921afc243d71fd0caaa4f2838c294102/library/std/src/io/impls.rs#L287 // assert_eq!(&buffer3[..6], b"UVWXYZ"); assert_eq!(cursor.position(), 26); // Position should be at EOF } #[test] - fn test_cursor_read_exact_after_eof() { - let data = b"End"; - let mut cursor = Cursor::new(data); - let mut buffer = [0u8; 3]; + fn test_slice_read_exact_success() { + let data: &[u8] = b"The quick brown fox jumps over the lazy dog."; + let mut reader = data; + let mut buffer = [0u8; 19]; - // First read: read the entire buffer - assert!(cursor.read_exact(&mut buffer).is_ok()); - assert_eq!(&buffer, b"End"); - assert_eq!(cursor.position(), 3); + // Attempt to read exactly 19 bytes + assert!(reader.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"The quick brown fox"); + } - // Second read: attempt to read again, should fail + #[test] + fn test_slice_read_exact_less_than_available() { + let data: &[u8] = b"Hello, Stellar!"; + let mut reader = data; + let mut buffer = [0u8; 5]; + + // Attempt to read 5 bytes from the start + assert!(reader.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Hello"); + } + + #[test] + fn test_slice_read_exact_exact_eof() { + let data: &[u8] = b"Data"; + let mut reader = data; + let mut buffer = [0u8; 4]; + + // Attempt to read exactly 4 bytes, which is the entire slice + assert!(reader.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Data"); + + // Further attempt to read should fail with EOF let mut buffer_eof = [0u8; 1]; - let result = cursor.read_exact(&mut buffer_eof); + let result = reader.read_exact(&mut buffer_eof); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); - assert_eq!(cursor.position(), 3); // Position remains at EOF + assert_unexpected_eof!(result); } #[test] - fn test_slice_read_exact_success() { - let data = b"SliceReadTest"; - let mut slice = &data[..]; - let mut buffer = [0u8; 13]; // Exact length + fn test_slice_read_exact_past_eof() { + let data: &[u8] = b"Short"; + let mut reader = data; + let mut buffer = [0u8; 10]; // Requesting more bytes than available - // Using Read trait directly on slice - assert!(slice.read_exact(&mut buffer).is_ok()); - assert_eq!(&buffer, b"SliceReadTest"); + // Attempt to read 10 bytes from a 5-byte slice + let result = reader.read_exact(&mut buffer); + assert!(result.is_err()); + assert_unexpected_eof!(result); } #[test] - fn test_slice_read_exact_partial() { - let data = b"SlicePartial"; - let mut slice = &data[..]; - let mut buffer = [0u8; 20]; // Request more bytes than available + fn test_slice_read_exact_empty_buffer() { + let data: &[u8] = b"Non-empty"; + let mut reader = data; + let mut buffer = [0u8; 0]; // Zero-length buffer - // Using Read trait directly on slice - let result = slice.read_exact(&mut buffer); + // Attempt to read zero bytes + assert!(reader.read_exact(&mut buffer).is_ok()); + } + + #[test] + fn test_slice_read_exact_from_empty_slice() { + let data: &[u8] = b""; + let mut reader = data; + let mut buffer = [0u8; 5]; + + // Attempt to read from an empty slice + let result = reader.read_exact(&mut buffer); assert!(result.is_err()); + assert_unexpected_eof!(result); + } + + #[test] + fn test_slice_read_exact_multiple_reads() { + let data: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + let mut reader = data; + + let mut buffer1 = [0u8; 10]; + let mut buffer2 = [0u8; 10]; + let mut buffer3 = [0u8; 10]; // Only 6 bytes left + + // First read: 10 bytes + assert!(reader.read_exact(&mut buffer1).is_ok()); + assert_eq!(&buffer1, b"ABCDEFGHIJ"); + + // Second read: 10 bytes + assert!(reader.read_exact(&mut buffer2).is_ok()); + assert_eq!(&buffer2, b"KLMNOPQRST"); + + // Third read: Attempt to read 10 bytes, but only 6 are available + let result = reader.read_exact(&mut buffer3); + assert!(result.is_err()); + assert_unexpected_eof!(result); + } + + #[test] + fn test_cursor_write_success() { + let data = Vec::with_capacity(100); + let mut cursor = Cursor::new(data); + let write_data = b"Hello, Stellar!"; + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(&cursor.get_ref()[..], write_data); + assert_eq!(cursor.position(), write_data.len() as u64); + } + + #[test] + fn test_cursor_write_multiple_writes() { + let data = Vec::with_capacity(100); + let mut cursor = Cursor::new(data); + let write_data1: &[u8] = b"Hello, "; + let write_data2: &[u8] = b"Rust!"; + + // First write + assert!(cursor.write_all(write_data1).is_ok()); + assert_eq!(&cursor.get_ref()[..], write_data1); + assert_eq!(cursor.position(), write_data1.len() as u64); + + // Second write + assert!(cursor.write_all(write_data2).is_ok()); + let mut expected = Vec::new(); + expected.extend_from_slice(write_data1); + expected.extend_from_slice(write_data2); + assert_eq!(&cursor.get_ref()[..], expected.as_slice()); + assert_eq!(cursor.position(), expected.len() as u64); + } + + #[test] + fn test_cursor_write_empty() { + let data = Vec::with_capacity(100); + let mut cursor = Cursor::new(data); + let write_data = b""; + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(cursor.get_ref().len(), 0); + assert_eq!(cursor.position(), 0); + } + + #[test] + fn test_cursor_write_at_position() { + let mut data = vec![0u8; 10]; + { + let mut cursor = Cursor::new(&mut data[..]); + let write_data = b"Rust"; + + // Move cursor to position 6 + cursor.set_position(6); + assert_eq!(cursor.position(), 6); + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(cursor.position(), 10); + } + + let mut expected = vec![0u8; 10]; + expected[6..10].copy_from_slice(b"Rust"); + assert_eq!(&data[..], &expected[..]); + } + + #[test] + fn test_cursor_write_overflow() { + let mut data = vec![0u8; 5]; + let mut cursor = Cursor::new(&mut data[..]); + let write_data = b"Too long data"; + + let result = cursor.write_all(write_data); + assert!(result.is_err()); + #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); + assert_eq!(result.unwrap_err().kind(), io::ErrorKind::WriteZero); #[cfg(feature = "embedded_io")] assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof + result.unwrap_err().kind(), + embedded_io_extras::ErrorKind::WriteZero ); - // read_exact makes no promises about the content of the buffer on error + } + + #[test] + fn test_cursor_write_from_empty_cursor() { + let data = Vec::new(); + let mut cursor = Cursor::new(data); + let write_data = b"Initial Data"; + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(&cursor.get_ref()[..], write_data); + assert_eq!(cursor.position(), write_data.len() as u64); + } + + #[test] + fn test_cursor_write_partial() { + let mut data = [0u8; 5]; + let mut cursor = Cursor::new(&mut data[..]); + let write_data = b"Hello, Stellar!"; + + // Attempt to write data that exceeds the buffer size + // using `write` instead of `write_all` + let result = cursor.write(&write_data[..7]).unwrap(); + assert_eq!(result, 5); + assert_eq!(&cursor.get_ref()[..], b"Hello"); } } diff --git a/spec/output/generator_spec_rust/test.x/MyXDR.rs b/spec/output/generator_spec_rust/test.x/MyXDR.rs index 0bae473d1..e02327632 100644 --- a/spec/output/generator_spec_rust/test.x/MyXDR.rs +++ b/spec/output/generator_spec_rust/test.x/MyXDR.rs @@ -2834,11 +2834,25 @@ mod test_io { use super::*; + macro_rules! assert_unexpected_eof { + ($result:expr) => {{ + let err = $result.unwrap_err(); + #[cfg(feature = "std")] + { + assert_eq!(err.kind(), io::ErrorKind::UnexpectedEof); + } + #[cfg(feature = "embedded_io")] + { + assert_eq!(err, embedded_io_extras::ReadExactError::UnexpectedEof); + } + }}; + } + #[test] - fn test_read_exact_success() { + fn test_cursor_read_exact_success() { let data = b"The quick brown fox jumps over the lazy dog."; let mut cursor = Cursor::new(data); - let mut buffer = [0u8; 19]; // Exactly the length of "The quick brown fox" + let mut buffer = [0u8; 19]; // Attempt to read exactly 19 bytes assert!(cursor.read_exact(&mut buffer).is_ok()); @@ -2847,8 +2861,8 @@ mod test_io { } #[test] - fn test_read_exact_less_than_available() { - let data = b"Hello, Rust!"; + fn test_cursor_read_exact_less_than_available() { + let data = b"Hello, Stellar!"; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 5]; @@ -2859,7 +2873,7 @@ mod test_io { } #[test] - fn test_read_exact_exact_eof() { + fn test_cursor_read_exact_exact_eof() { let data = b"Data"; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 4]; @@ -2873,21 +2887,12 @@ mod test_io { let mut buffer_eof = [0u8; 1]; let result = cursor.read_exact(&mut buffer_eof); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); assert_eq!(cursor.position(), 4); // Position should remain at EOF } #[test] - fn test_read_exact_past_eof() { + fn test_cursor_read_exact_past_eof() { let data = b"Short"; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 10]; // Requesting more bytes than available @@ -2895,24 +2900,15 @@ mod test_io { // Attempt to read 10 bytes from a 5-byte buffer let result = cursor.read_exact(&mut buffer); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); assert_eq!(cursor.position(), 5); // Position should move to EOF } #[test] - fn test_read_exact_empty_buffer() { + fn test_cursor_read_exact_empty_buffer() { let data = b"Non-empty"; let mut cursor = Cursor::new(data); - let mut buffer = [0u8; 0]; // Zero-length buffer + let mut buffer = [0u8; 0]; // Attempt to read zero bytes assert!(cursor.read_exact(&mut buffer).is_ok()); @@ -2920,7 +2916,7 @@ mod test_io { } #[test] - fn test_read_exact_from_empty_cursor() { + fn test_cursor_read_exact_from_empty_cursor() { let data: &[u8] = b""; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 5]; @@ -2928,21 +2924,12 @@ mod test_io { // Attempt to read from an empty cursor let result = cursor.read_exact(&mut buffer); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); assert_eq!(cursor.position(), 0); // Position remains at 0 } #[test] - fn test_read_exact_multiple_reads() { + fn test_cursor_read_exact_multiple_reads() { let data = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; let mut cursor = Cursor::new(data); @@ -2963,80 +2950,212 @@ mod test_io { // Third read: Attempt to read 10 bytes, but only 6 are available let result = cursor.read_exact(&mut buffer3); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); // read_exact makes no promises about the content of the buffer on error + // https://github.com/rust-lang/rust/blob/84ac80f1921afc243d71fd0caaa4f2838c294102/library/std/src/io/impls.rs#L287 // assert_eq!(&buffer3[..6], b"UVWXYZ"); assert_eq!(cursor.position(), 26); // Position should be at EOF } #[test] - fn test_cursor_read_exact_after_eof() { - let data = b"End"; - let mut cursor = Cursor::new(data); - let mut buffer = [0u8; 3]; + fn test_slice_read_exact_success() { + let data: &[u8] = b"The quick brown fox jumps over the lazy dog."; + let mut reader = data; + let mut buffer = [0u8; 19]; - // First read: read the entire buffer - assert!(cursor.read_exact(&mut buffer).is_ok()); - assert_eq!(&buffer, b"End"); - assert_eq!(cursor.position(), 3); + // Attempt to read exactly 19 bytes + assert!(reader.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"The quick brown fox"); + } + + #[test] + fn test_slice_read_exact_less_than_available() { + let data: &[u8] = b"Hello, Stellar!"; + let mut reader = data; + let mut buffer = [0u8; 5]; + + // Attempt to read 5 bytes from the start + assert!(reader.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Hello"); + } + + #[test] + fn test_slice_read_exact_exact_eof() { + let data: &[u8] = b"Data"; + let mut reader = data; + let mut buffer = [0u8; 4]; + + // Attempt to read exactly 4 bytes, which is the entire slice + assert!(reader.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Data"); - // Second read: attempt to read again, should fail + // Further attempt to read should fail with EOF let mut buffer_eof = [0u8; 1]; - let result = cursor.read_exact(&mut buffer_eof); + let result = reader.read_exact(&mut buffer_eof); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); - assert_eq!(cursor.position(), 3); // Position remains at EOF + assert_unexpected_eof!(result); } #[test] - fn test_slice_read_exact_success() { - let data = b"SliceReadTest"; - let mut slice = &data[..]; - let mut buffer = [0u8; 13]; // Exact length + fn test_slice_read_exact_past_eof() { + let data: &[u8] = b"Short"; + let mut reader = data; + let mut buffer = [0u8; 10]; // Requesting more bytes than available - // Using Read trait directly on slice - assert!(slice.read_exact(&mut buffer).is_ok()); - assert_eq!(&buffer, b"SliceReadTest"); + // Attempt to read 10 bytes from a 5-byte slice + let result = reader.read_exact(&mut buffer); + assert!(result.is_err()); + assert_unexpected_eof!(result); } #[test] - fn test_slice_read_exact_partial() { - let data = b"SlicePartial"; - let mut slice = &data[..]; - let mut buffer = [0u8; 20]; // Request more bytes than available + fn test_slice_read_exact_empty_buffer() { + let data: &[u8] = b"Non-empty"; + let mut reader = data; + let mut buffer = [0u8; 0]; // Zero-length buffer + + // Attempt to read zero bytes + assert!(reader.read_exact(&mut buffer).is_ok()); + } + + #[test] + fn test_slice_read_exact_from_empty_slice() { + let data: &[u8] = b""; + let mut reader = data; + let mut buffer = [0u8; 5]; + + // Attempt to read from an empty slice + let result = reader.read_exact(&mut buffer); + assert!(result.is_err()); + assert_unexpected_eof!(result); + } + + #[test] + fn test_slice_read_exact_multiple_reads() { + let data: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + let mut reader = data; + + let mut buffer1 = [0u8; 10]; + let mut buffer2 = [0u8; 10]; + let mut buffer3 = [0u8; 10]; // Only 6 bytes left + + // First read: 10 bytes + assert!(reader.read_exact(&mut buffer1).is_ok()); + assert_eq!(&buffer1, b"ABCDEFGHIJ"); + + // Second read: 10 bytes + assert!(reader.read_exact(&mut buffer2).is_ok()); + assert_eq!(&buffer2, b"KLMNOPQRST"); + + // Third read: Attempt to read 10 bytes, but only 6 are available + let result = reader.read_exact(&mut buffer3); + assert!(result.is_err()); + assert_unexpected_eof!(result); + } + + #[test] + fn test_cursor_write_success() { + let data = Vec::with_capacity(100); + let mut cursor = Cursor::new(data); + let write_data = b"Hello, Stellar!"; + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(&cursor.get_ref()[..], write_data); + assert_eq!(cursor.position(), write_data.len() as u64); + } - // Using Read trait directly on slice - let result = slice.read_exact(&mut buffer); + #[test] + fn test_cursor_write_multiple_writes() { + let data = Vec::with_capacity(100); + let mut cursor = Cursor::new(data); + let write_data1: &[u8] = b"Hello, "; + let write_data2: &[u8] = b"Rust!"; + + // First write + assert!(cursor.write_all(write_data1).is_ok()); + assert_eq!(&cursor.get_ref()[..], write_data1); + assert_eq!(cursor.position(), write_data1.len() as u64); + + // Second write + assert!(cursor.write_all(write_data2).is_ok()); + let mut expected = Vec::new(); + expected.extend_from_slice(write_data1); + expected.extend_from_slice(write_data2); + assert_eq!(&cursor.get_ref()[..], expected.as_slice()); + assert_eq!(cursor.position(), expected.len() as u64); + } + + #[test] + fn test_cursor_write_empty() { + let data = Vec::with_capacity(100); + let mut cursor = Cursor::new(data); + let write_data = b""; + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(cursor.get_ref().len(), 0); + assert_eq!(cursor.position(), 0); + } + + #[test] + fn test_cursor_write_at_position() { + let mut data = vec![0u8; 10]; + { + let mut cursor = Cursor::new(&mut data[..]); + let write_data = b"Rust"; + + // Move cursor to position 6 + cursor.set_position(6); + assert_eq!(cursor.position(), 6); + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(cursor.position(), 10); + } + + let mut expected = vec![0u8; 10]; + expected[6..10].copy_from_slice(b"Rust"); + assert_eq!(&data[..], &expected[..]); + } + + #[test] + fn test_cursor_write_overflow() { + let mut data = vec![0u8; 5]; + let mut cursor = Cursor::new(&mut data[..]); + let write_data = b"Too long data"; + + let result = cursor.write_all(write_data); assert!(result.is_err()); + #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); + assert_eq!(result.unwrap_err().kind(), io::ErrorKind::WriteZero); #[cfg(feature = "embedded_io")] assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof + result.unwrap_err().kind(), + embedded_io_extras::ErrorKind::WriteZero ); - // read_exact makes no promises about the content of the buffer on error + } + + #[test] + fn test_cursor_write_from_empty_cursor() { + let data = Vec::new(); + let mut cursor = Cursor::new(data); + let write_data = b"Initial Data"; + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(&cursor.get_ref()[..], write_data); + assert_eq!(cursor.position(), write_data.len() as u64); + } + + #[test] + fn test_cursor_write_partial() { + let mut data = [0u8; 5]; + let mut cursor = Cursor::new(&mut data[..]); + let write_data = b"Hello, Stellar!"; + + // Attempt to write data that exceeds the buffer size + // using `write` instead of `write_all` + let result = cursor.write(&write_data[..7]).unwrap(); + assert_eq!(result, 5); + assert_eq!(&cursor.get_ref()[..], b"Hello"); } } diff --git a/spec/output/generator_spec_rust/union.x/MyXDR.rs b/spec/output/generator_spec_rust/union.x/MyXDR.rs index 3ab0369a5..8d775325d 100644 --- a/spec/output/generator_spec_rust/union.x/MyXDR.rs +++ b/spec/output/generator_spec_rust/union.x/MyXDR.rs @@ -2834,11 +2834,25 @@ mod test_io { use super::*; + macro_rules! assert_unexpected_eof { + ($result:expr) => {{ + let err = $result.unwrap_err(); + #[cfg(feature = "std")] + { + assert_eq!(err.kind(), io::ErrorKind::UnexpectedEof); + } + #[cfg(feature = "embedded_io")] + { + assert_eq!(err, embedded_io_extras::ReadExactError::UnexpectedEof); + } + }}; + } + #[test] - fn test_read_exact_success() { + fn test_cursor_read_exact_success() { let data = b"The quick brown fox jumps over the lazy dog."; let mut cursor = Cursor::new(data); - let mut buffer = [0u8; 19]; // Exactly the length of "The quick brown fox" + let mut buffer = [0u8; 19]; // Attempt to read exactly 19 bytes assert!(cursor.read_exact(&mut buffer).is_ok()); @@ -2847,8 +2861,8 @@ mod test_io { } #[test] - fn test_read_exact_less_than_available() { - let data = b"Hello, Rust!"; + fn test_cursor_read_exact_less_than_available() { + let data = b"Hello, Stellar!"; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 5]; @@ -2859,7 +2873,7 @@ mod test_io { } #[test] - fn test_read_exact_exact_eof() { + fn test_cursor_read_exact_exact_eof() { let data = b"Data"; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 4]; @@ -2873,21 +2887,12 @@ mod test_io { let mut buffer_eof = [0u8; 1]; let result = cursor.read_exact(&mut buffer_eof); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); assert_eq!(cursor.position(), 4); // Position should remain at EOF } #[test] - fn test_read_exact_past_eof() { + fn test_cursor_read_exact_past_eof() { let data = b"Short"; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 10]; // Requesting more bytes than available @@ -2895,24 +2900,15 @@ mod test_io { // Attempt to read 10 bytes from a 5-byte buffer let result = cursor.read_exact(&mut buffer); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); assert_eq!(cursor.position(), 5); // Position should move to EOF } #[test] - fn test_read_exact_empty_buffer() { + fn test_cursor_read_exact_empty_buffer() { let data = b"Non-empty"; let mut cursor = Cursor::new(data); - let mut buffer = [0u8; 0]; // Zero-length buffer + let mut buffer = [0u8; 0]; // Attempt to read zero bytes assert!(cursor.read_exact(&mut buffer).is_ok()); @@ -2920,7 +2916,7 @@ mod test_io { } #[test] - fn test_read_exact_from_empty_cursor() { + fn test_cursor_read_exact_from_empty_cursor() { let data: &[u8] = b""; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 5]; @@ -2928,21 +2924,12 @@ mod test_io { // Attempt to read from an empty cursor let result = cursor.read_exact(&mut buffer); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); assert_eq!(cursor.position(), 0); // Position remains at 0 } #[test] - fn test_read_exact_multiple_reads() { + fn test_cursor_read_exact_multiple_reads() { let data = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; let mut cursor = Cursor::new(data); @@ -2963,80 +2950,212 @@ mod test_io { // Third read: Attempt to read 10 bytes, but only 6 are available let result = cursor.read_exact(&mut buffer3); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); // read_exact makes no promises about the content of the buffer on error + // https://github.com/rust-lang/rust/blob/84ac80f1921afc243d71fd0caaa4f2838c294102/library/std/src/io/impls.rs#L287 // assert_eq!(&buffer3[..6], b"UVWXYZ"); assert_eq!(cursor.position(), 26); // Position should be at EOF } #[test] - fn test_cursor_read_exact_after_eof() { - let data = b"End"; - let mut cursor = Cursor::new(data); - let mut buffer = [0u8; 3]; + fn test_slice_read_exact_success() { + let data: &[u8] = b"The quick brown fox jumps over the lazy dog."; + let mut reader = data; + let mut buffer = [0u8; 19]; - // First read: read the entire buffer - assert!(cursor.read_exact(&mut buffer).is_ok()); - assert_eq!(&buffer, b"End"); - assert_eq!(cursor.position(), 3); + // Attempt to read exactly 19 bytes + assert!(reader.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"The quick brown fox"); + } - // Second read: attempt to read again, should fail + #[test] + fn test_slice_read_exact_less_than_available() { + let data: &[u8] = b"Hello, Stellar!"; + let mut reader = data; + let mut buffer = [0u8; 5]; + + // Attempt to read 5 bytes from the start + assert!(reader.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Hello"); + } + + #[test] + fn test_slice_read_exact_exact_eof() { + let data: &[u8] = b"Data"; + let mut reader = data; + let mut buffer = [0u8; 4]; + + // Attempt to read exactly 4 bytes, which is the entire slice + assert!(reader.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Data"); + + // Further attempt to read should fail with EOF let mut buffer_eof = [0u8; 1]; - let result = cursor.read_exact(&mut buffer_eof); + let result = reader.read_exact(&mut buffer_eof); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); - assert_eq!(cursor.position(), 3); // Position remains at EOF + assert_unexpected_eof!(result); } #[test] - fn test_slice_read_exact_success() { - let data = b"SliceReadTest"; - let mut slice = &data[..]; - let mut buffer = [0u8; 13]; // Exact length + fn test_slice_read_exact_past_eof() { + let data: &[u8] = b"Short"; + let mut reader = data; + let mut buffer = [0u8; 10]; // Requesting more bytes than available - // Using Read trait directly on slice - assert!(slice.read_exact(&mut buffer).is_ok()); - assert_eq!(&buffer, b"SliceReadTest"); + // Attempt to read 10 bytes from a 5-byte slice + let result = reader.read_exact(&mut buffer); + assert!(result.is_err()); + assert_unexpected_eof!(result); } #[test] - fn test_slice_read_exact_partial() { - let data = b"SlicePartial"; - let mut slice = &data[..]; - let mut buffer = [0u8; 20]; // Request more bytes than available + fn test_slice_read_exact_empty_buffer() { + let data: &[u8] = b"Non-empty"; + let mut reader = data; + let mut buffer = [0u8; 0]; // Zero-length buffer - // Using Read trait directly on slice - let result = slice.read_exact(&mut buffer); + // Attempt to read zero bytes + assert!(reader.read_exact(&mut buffer).is_ok()); + } + + #[test] + fn test_slice_read_exact_from_empty_slice() { + let data: &[u8] = b""; + let mut reader = data; + let mut buffer = [0u8; 5]; + + // Attempt to read from an empty slice + let result = reader.read_exact(&mut buffer); assert!(result.is_err()); + assert_unexpected_eof!(result); + } + + #[test] + fn test_slice_read_exact_multiple_reads() { + let data: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + let mut reader = data; + + let mut buffer1 = [0u8; 10]; + let mut buffer2 = [0u8; 10]; + let mut buffer3 = [0u8; 10]; // Only 6 bytes left + + // First read: 10 bytes + assert!(reader.read_exact(&mut buffer1).is_ok()); + assert_eq!(&buffer1, b"ABCDEFGHIJ"); + + // Second read: 10 bytes + assert!(reader.read_exact(&mut buffer2).is_ok()); + assert_eq!(&buffer2, b"KLMNOPQRST"); + + // Third read: Attempt to read 10 bytes, but only 6 are available + let result = reader.read_exact(&mut buffer3); + assert!(result.is_err()); + assert_unexpected_eof!(result); + } + + #[test] + fn test_cursor_write_success() { + let data = Vec::with_capacity(100); + let mut cursor = Cursor::new(data); + let write_data = b"Hello, Stellar!"; + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(&cursor.get_ref()[..], write_data); + assert_eq!(cursor.position(), write_data.len() as u64); + } + + #[test] + fn test_cursor_write_multiple_writes() { + let data = Vec::with_capacity(100); + let mut cursor = Cursor::new(data); + let write_data1: &[u8] = b"Hello, "; + let write_data2: &[u8] = b"Rust!"; + + // First write + assert!(cursor.write_all(write_data1).is_ok()); + assert_eq!(&cursor.get_ref()[..], write_data1); + assert_eq!(cursor.position(), write_data1.len() as u64); + + // Second write + assert!(cursor.write_all(write_data2).is_ok()); + let mut expected = Vec::new(); + expected.extend_from_slice(write_data1); + expected.extend_from_slice(write_data2); + assert_eq!(&cursor.get_ref()[..], expected.as_slice()); + assert_eq!(cursor.position(), expected.len() as u64); + } + + #[test] + fn test_cursor_write_empty() { + let data = Vec::with_capacity(100); + let mut cursor = Cursor::new(data); + let write_data = b""; + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(cursor.get_ref().len(), 0); + assert_eq!(cursor.position(), 0); + } + + #[test] + fn test_cursor_write_at_position() { + let mut data = vec![0u8; 10]; + { + let mut cursor = Cursor::new(&mut data[..]); + let write_data = b"Rust"; + + // Move cursor to position 6 + cursor.set_position(6); + assert_eq!(cursor.position(), 6); + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(cursor.position(), 10); + } + + let mut expected = vec![0u8; 10]; + expected[6..10].copy_from_slice(b"Rust"); + assert_eq!(&data[..], &expected[..]); + } + + #[test] + fn test_cursor_write_overflow() { + let mut data = vec![0u8; 5]; + let mut cursor = Cursor::new(&mut data[..]); + let write_data = b"Too long data"; + + let result = cursor.write_all(write_data); + assert!(result.is_err()); + #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); + assert_eq!(result.unwrap_err().kind(), io::ErrorKind::WriteZero); #[cfg(feature = "embedded_io")] assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof + result.unwrap_err().kind(), + embedded_io_extras::ErrorKind::WriteZero ); - // read_exact makes no promises about the content of the buffer on error + } + + #[test] + fn test_cursor_write_from_empty_cursor() { + let data = Vec::new(); + let mut cursor = Cursor::new(data); + let write_data = b"Initial Data"; + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(&cursor.get_ref()[..], write_data); + assert_eq!(cursor.position(), write_data.len() as u64); + } + + #[test] + fn test_cursor_write_partial() { + let mut data = [0u8; 5]; + let mut cursor = Cursor::new(&mut data[..]); + let write_data = b"Hello, Stellar!"; + + // Attempt to write data that exceeds the buffer size + // using `write` instead of `write_all` + let result = cursor.write(&write_data[..7]).unwrap(); + assert_eq!(result, 5); + assert_eq!(&cursor.get_ref()[..], b"Hello"); } } diff --git a/spec/output/generator_spec_rust_custom_jsonschema_impls/block_comments.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_jsonschema_impls/block_comments.x/MyXDR.rs index 2b9de8c27..a2906d184 100644 --- a/spec/output/generator_spec_rust_custom_jsonschema_impls/block_comments.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_jsonschema_impls/block_comments.x/MyXDR.rs @@ -2834,11 +2834,25 @@ mod test_io { use super::*; + macro_rules! assert_unexpected_eof { + ($result:expr) => {{ + let err = $result.unwrap_err(); + #[cfg(feature = "std")] + { + assert_eq!(err.kind(), io::ErrorKind::UnexpectedEof); + } + #[cfg(feature = "embedded_io")] + { + assert_eq!(err, embedded_io_extras::ReadExactError::UnexpectedEof); + } + }}; + } + #[test] - fn test_read_exact_success() { + fn test_cursor_read_exact_success() { let data = b"The quick brown fox jumps over the lazy dog."; let mut cursor = Cursor::new(data); - let mut buffer = [0u8; 19]; // Exactly the length of "The quick brown fox" + let mut buffer = [0u8; 19]; // Attempt to read exactly 19 bytes assert!(cursor.read_exact(&mut buffer).is_ok()); @@ -2847,8 +2861,8 @@ mod test_io { } #[test] - fn test_read_exact_less_than_available() { - let data = b"Hello, Rust!"; + fn test_cursor_read_exact_less_than_available() { + let data = b"Hello, Stellar!"; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 5]; @@ -2859,7 +2873,7 @@ mod test_io { } #[test] - fn test_read_exact_exact_eof() { + fn test_cursor_read_exact_exact_eof() { let data = b"Data"; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 4]; @@ -2873,21 +2887,12 @@ mod test_io { let mut buffer_eof = [0u8; 1]; let result = cursor.read_exact(&mut buffer_eof); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); assert_eq!(cursor.position(), 4); // Position should remain at EOF } #[test] - fn test_read_exact_past_eof() { + fn test_cursor_read_exact_past_eof() { let data = b"Short"; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 10]; // Requesting more bytes than available @@ -2895,24 +2900,15 @@ mod test_io { // Attempt to read 10 bytes from a 5-byte buffer let result = cursor.read_exact(&mut buffer); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); assert_eq!(cursor.position(), 5); // Position should move to EOF } #[test] - fn test_read_exact_empty_buffer() { + fn test_cursor_read_exact_empty_buffer() { let data = b"Non-empty"; let mut cursor = Cursor::new(data); - let mut buffer = [0u8; 0]; // Zero-length buffer + let mut buffer = [0u8; 0]; // Attempt to read zero bytes assert!(cursor.read_exact(&mut buffer).is_ok()); @@ -2920,7 +2916,7 @@ mod test_io { } #[test] - fn test_read_exact_from_empty_cursor() { + fn test_cursor_read_exact_from_empty_cursor() { let data: &[u8] = b""; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 5]; @@ -2928,21 +2924,12 @@ mod test_io { // Attempt to read from an empty cursor let result = cursor.read_exact(&mut buffer); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); assert_eq!(cursor.position(), 0); // Position remains at 0 } #[test] - fn test_read_exact_multiple_reads() { + fn test_cursor_read_exact_multiple_reads() { let data = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; let mut cursor = Cursor::new(data); @@ -2963,80 +2950,212 @@ mod test_io { // Third read: Attempt to read 10 bytes, but only 6 are available let result = cursor.read_exact(&mut buffer3); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); // read_exact makes no promises about the content of the buffer on error + // https://github.com/rust-lang/rust/blob/84ac80f1921afc243d71fd0caaa4f2838c294102/library/std/src/io/impls.rs#L287 // assert_eq!(&buffer3[..6], b"UVWXYZ"); assert_eq!(cursor.position(), 26); // Position should be at EOF } #[test] - fn test_cursor_read_exact_after_eof() { - let data = b"End"; - let mut cursor = Cursor::new(data); - let mut buffer = [0u8; 3]; + fn test_slice_read_exact_success() { + let data: &[u8] = b"The quick brown fox jumps over the lazy dog."; + let mut reader = data; + let mut buffer = [0u8; 19]; - // First read: read the entire buffer - assert!(cursor.read_exact(&mut buffer).is_ok()); - assert_eq!(&buffer, b"End"); - assert_eq!(cursor.position(), 3); + // Attempt to read exactly 19 bytes + assert!(reader.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"The quick brown fox"); + } - // Second read: attempt to read again, should fail + #[test] + fn test_slice_read_exact_less_than_available() { + let data: &[u8] = b"Hello, Stellar!"; + let mut reader = data; + let mut buffer = [0u8; 5]; + + // Attempt to read 5 bytes from the start + assert!(reader.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Hello"); + } + + #[test] + fn test_slice_read_exact_exact_eof() { + let data: &[u8] = b"Data"; + let mut reader = data; + let mut buffer = [0u8; 4]; + + // Attempt to read exactly 4 bytes, which is the entire slice + assert!(reader.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Data"); + + // Further attempt to read should fail with EOF let mut buffer_eof = [0u8; 1]; - let result = cursor.read_exact(&mut buffer_eof); + let result = reader.read_exact(&mut buffer_eof); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); - assert_eq!(cursor.position(), 3); // Position remains at EOF + assert_unexpected_eof!(result); } #[test] - fn test_slice_read_exact_success() { - let data = b"SliceReadTest"; - let mut slice = &data[..]; - let mut buffer = [0u8; 13]; // Exact length + fn test_slice_read_exact_past_eof() { + let data: &[u8] = b"Short"; + let mut reader = data; + let mut buffer = [0u8; 10]; // Requesting more bytes than available - // Using Read trait directly on slice - assert!(slice.read_exact(&mut buffer).is_ok()); - assert_eq!(&buffer, b"SliceReadTest"); + // Attempt to read 10 bytes from a 5-byte slice + let result = reader.read_exact(&mut buffer); + assert!(result.is_err()); + assert_unexpected_eof!(result); } #[test] - fn test_slice_read_exact_partial() { - let data = b"SlicePartial"; - let mut slice = &data[..]; - let mut buffer = [0u8; 20]; // Request more bytes than available + fn test_slice_read_exact_empty_buffer() { + let data: &[u8] = b"Non-empty"; + let mut reader = data; + let mut buffer = [0u8; 0]; // Zero-length buffer - // Using Read trait directly on slice - let result = slice.read_exact(&mut buffer); + // Attempt to read zero bytes + assert!(reader.read_exact(&mut buffer).is_ok()); + } + + #[test] + fn test_slice_read_exact_from_empty_slice() { + let data: &[u8] = b""; + let mut reader = data; + let mut buffer = [0u8; 5]; + + // Attempt to read from an empty slice + let result = reader.read_exact(&mut buffer); assert!(result.is_err()); + assert_unexpected_eof!(result); + } + + #[test] + fn test_slice_read_exact_multiple_reads() { + let data: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + let mut reader = data; + + let mut buffer1 = [0u8; 10]; + let mut buffer2 = [0u8; 10]; + let mut buffer3 = [0u8; 10]; // Only 6 bytes left + + // First read: 10 bytes + assert!(reader.read_exact(&mut buffer1).is_ok()); + assert_eq!(&buffer1, b"ABCDEFGHIJ"); + + // Second read: 10 bytes + assert!(reader.read_exact(&mut buffer2).is_ok()); + assert_eq!(&buffer2, b"KLMNOPQRST"); + + // Third read: Attempt to read 10 bytes, but only 6 are available + let result = reader.read_exact(&mut buffer3); + assert!(result.is_err()); + assert_unexpected_eof!(result); + } + + #[test] + fn test_cursor_write_success() { + let data = Vec::with_capacity(100); + let mut cursor = Cursor::new(data); + let write_data = b"Hello, Stellar!"; + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(&cursor.get_ref()[..], write_data); + assert_eq!(cursor.position(), write_data.len() as u64); + } + + #[test] + fn test_cursor_write_multiple_writes() { + let data = Vec::with_capacity(100); + let mut cursor = Cursor::new(data); + let write_data1: &[u8] = b"Hello, "; + let write_data2: &[u8] = b"Rust!"; + + // First write + assert!(cursor.write_all(write_data1).is_ok()); + assert_eq!(&cursor.get_ref()[..], write_data1); + assert_eq!(cursor.position(), write_data1.len() as u64); + + // Second write + assert!(cursor.write_all(write_data2).is_ok()); + let mut expected = Vec::new(); + expected.extend_from_slice(write_data1); + expected.extend_from_slice(write_data2); + assert_eq!(&cursor.get_ref()[..], expected.as_slice()); + assert_eq!(cursor.position(), expected.len() as u64); + } + + #[test] + fn test_cursor_write_empty() { + let data = Vec::with_capacity(100); + let mut cursor = Cursor::new(data); + let write_data = b""; + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(cursor.get_ref().len(), 0); + assert_eq!(cursor.position(), 0); + } + + #[test] + fn test_cursor_write_at_position() { + let mut data = vec![0u8; 10]; + { + let mut cursor = Cursor::new(&mut data[..]); + let write_data = b"Rust"; + + // Move cursor to position 6 + cursor.set_position(6); + assert_eq!(cursor.position(), 6); + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(cursor.position(), 10); + } + + let mut expected = vec![0u8; 10]; + expected[6..10].copy_from_slice(b"Rust"); + assert_eq!(&data[..], &expected[..]); + } + + #[test] + fn test_cursor_write_overflow() { + let mut data = vec![0u8; 5]; + let mut cursor = Cursor::new(&mut data[..]); + let write_data = b"Too long data"; + + let result = cursor.write_all(write_data); + assert!(result.is_err()); + #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); + assert_eq!(result.unwrap_err().kind(), io::ErrorKind::WriteZero); #[cfg(feature = "embedded_io")] assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof + result.unwrap_err().kind(), + embedded_io_extras::ErrorKind::WriteZero ); - // read_exact makes no promises about the content of the buffer on error + } + + #[test] + fn test_cursor_write_from_empty_cursor() { + let data = Vec::new(); + let mut cursor = Cursor::new(data); + let write_data = b"Initial Data"; + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(&cursor.get_ref()[..], write_data); + assert_eq!(cursor.position(), write_data.len() as u64); + } + + #[test] + fn test_cursor_write_partial() { + let mut data = [0u8; 5]; + let mut cursor = Cursor::new(&mut data[..]); + let write_data = b"Hello, Stellar!"; + + // Attempt to write data that exceeds the buffer size + // using `write` instead of `write_all` + let result = cursor.write(&write_data[..7]).unwrap(); + assert_eq!(result, 5); + assert_eq!(&cursor.get_ref()[..], b"Hello"); } } diff --git a/spec/output/generator_spec_rust_custom_jsonschema_impls/const.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_jsonschema_impls/const.x/MyXDR.rs index 0b80a5d3f..40946ac79 100644 --- a/spec/output/generator_spec_rust_custom_jsonschema_impls/const.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_jsonschema_impls/const.x/MyXDR.rs @@ -2834,11 +2834,25 @@ mod test_io { use super::*; + macro_rules! assert_unexpected_eof { + ($result:expr) => {{ + let err = $result.unwrap_err(); + #[cfg(feature = "std")] + { + assert_eq!(err.kind(), io::ErrorKind::UnexpectedEof); + } + #[cfg(feature = "embedded_io")] + { + assert_eq!(err, embedded_io_extras::ReadExactError::UnexpectedEof); + } + }}; + } + #[test] - fn test_read_exact_success() { + fn test_cursor_read_exact_success() { let data = b"The quick brown fox jumps over the lazy dog."; let mut cursor = Cursor::new(data); - let mut buffer = [0u8; 19]; // Exactly the length of "The quick brown fox" + let mut buffer = [0u8; 19]; // Attempt to read exactly 19 bytes assert!(cursor.read_exact(&mut buffer).is_ok()); @@ -2847,8 +2861,8 @@ mod test_io { } #[test] - fn test_read_exact_less_than_available() { - let data = b"Hello, Rust!"; + fn test_cursor_read_exact_less_than_available() { + let data = b"Hello, Stellar!"; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 5]; @@ -2859,7 +2873,7 @@ mod test_io { } #[test] - fn test_read_exact_exact_eof() { + fn test_cursor_read_exact_exact_eof() { let data = b"Data"; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 4]; @@ -2873,21 +2887,12 @@ mod test_io { let mut buffer_eof = [0u8; 1]; let result = cursor.read_exact(&mut buffer_eof); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); assert_eq!(cursor.position(), 4); // Position should remain at EOF } #[test] - fn test_read_exact_past_eof() { + fn test_cursor_read_exact_past_eof() { let data = b"Short"; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 10]; // Requesting more bytes than available @@ -2895,24 +2900,15 @@ mod test_io { // Attempt to read 10 bytes from a 5-byte buffer let result = cursor.read_exact(&mut buffer); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); assert_eq!(cursor.position(), 5); // Position should move to EOF } #[test] - fn test_read_exact_empty_buffer() { + fn test_cursor_read_exact_empty_buffer() { let data = b"Non-empty"; let mut cursor = Cursor::new(data); - let mut buffer = [0u8; 0]; // Zero-length buffer + let mut buffer = [0u8; 0]; // Attempt to read zero bytes assert!(cursor.read_exact(&mut buffer).is_ok()); @@ -2920,7 +2916,7 @@ mod test_io { } #[test] - fn test_read_exact_from_empty_cursor() { + fn test_cursor_read_exact_from_empty_cursor() { let data: &[u8] = b""; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 5]; @@ -2928,21 +2924,12 @@ mod test_io { // Attempt to read from an empty cursor let result = cursor.read_exact(&mut buffer); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); assert_eq!(cursor.position(), 0); // Position remains at 0 } #[test] - fn test_read_exact_multiple_reads() { + fn test_cursor_read_exact_multiple_reads() { let data = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; let mut cursor = Cursor::new(data); @@ -2963,80 +2950,212 @@ mod test_io { // Third read: Attempt to read 10 bytes, but only 6 are available let result = cursor.read_exact(&mut buffer3); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); // read_exact makes no promises about the content of the buffer on error + // https://github.com/rust-lang/rust/blob/84ac80f1921afc243d71fd0caaa4f2838c294102/library/std/src/io/impls.rs#L287 // assert_eq!(&buffer3[..6], b"UVWXYZ"); assert_eq!(cursor.position(), 26); // Position should be at EOF } #[test] - fn test_cursor_read_exact_after_eof() { - let data = b"End"; - let mut cursor = Cursor::new(data); - let mut buffer = [0u8; 3]; + fn test_slice_read_exact_success() { + let data: &[u8] = b"The quick brown fox jumps over the lazy dog."; + let mut reader = data; + let mut buffer = [0u8; 19]; - // First read: read the entire buffer - assert!(cursor.read_exact(&mut buffer).is_ok()); - assert_eq!(&buffer, b"End"); - assert_eq!(cursor.position(), 3); + // Attempt to read exactly 19 bytes + assert!(reader.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"The quick brown fox"); + } - // Second read: attempt to read again, should fail + #[test] + fn test_slice_read_exact_less_than_available() { + let data: &[u8] = b"Hello, Stellar!"; + let mut reader = data; + let mut buffer = [0u8; 5]; + + // Attempt to read 5 bytes from the start + assert!(reader.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Hello"); + } + + #[test] + fn test_slice_read_exact_exact_eof() { + let data: &[u8] = b"Data"; + let mut reader = data; + let mut buffer = [0u8; 4]; + + // Attempt to read exactly 4 bytes, which is the entire slice + assert!(reader.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Data"); + + // Further attempt to read should fail with EOF let mut buffer_eof = [0u8; 1]; - let result = cursor.read_exact(&mut buffer_eof); + let result = reader.read_exact(&mut buffer_eof); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); - assert_eq!(cursor.position(), 3); // Position remains at EOF + assert_unexpected_eof!(result); } #[test] - fn test_slice_read_exact_success() { - let data = b"SliceReadTest"; - let mut slice = &data[..]; - let mut buffer = [0u8; 13]; // Exact length + fn test_slice_read_exact_past_eof() { + let data: &[u8] = b"Short"; + let mut reader = data; + let mut buffer = [0u8; 10]; // Requesting more bytes than available - // Using Read trait directly on slice - assert!(slice.read_exact(&mut buffer).is_ok()); - assert_eq!(&buffer, b"SliceReadTest"); + // Attempt to read 10 bytes from a 5-byte slice + let result = reader.read_exact(&mut buffer); + assert!(result.is_err()); + assert_unexpected_eof!(result); } #[test] - fn test_slice_read_exact_partial() { - let data = b"SlicePartial"; - let mut slice = &data[..]; - let mut buffer = [0u8; 20]; // Request more bytes than available + fn test_slice_read_exact_empty_buffer() { + let data: &[u8] = b"Non-empty"; + let mut reader = data; + let mut buffer = [0u8; 0]; // Zero-length buffer - // Using Read trait directly on slice - let result = slice.read_exact(&mut buffer); + // Attempt to read zero bytes + assert!(reader.read_exact(&mut buffer).is_ok()); + } + + #[test] + fn test_slice_read_exact_from_empty_slice() { + let data: &[u8] = b""; + let mut reader = data; + let mut buffer = [0u8; 5]; + + // Attempt to read from an empty slice + let result = reader.read_exact(&mut buffer); assert!(result.is_err()); + assert_unexpected_eof!(result); + } + + #[test] + fn test_slice_read_exact_multiple_reads() { + let data: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + let mut reader = data; + + let mut buffer1 = [0u8; 10]; + let mut buffer2 = [0u8; 10]; + let mut buffer3 = [0u8; 10]; // Only 6 bytes left + + // First read: 10 bytes + assert!(reader.read_exact(&mut buffer1).is_ok()); + assert_eq!(&buffer1, b"ABCDEFGHIJ"); + + // Second read: 10 bytes + assert!(reader.read_exact(&mut buffer2).is_ok()); + assert_eq!(&buffer2, b"KLMNOPQRST"); + + // Third read: Attempt to read 10 bytes, but only 6 are available + let result = reader.read_exact(&mut buffer3); + assert!(result.is_err()); + assert_unexpected_eof!(result); + } + + #[test] + fn test_cursor_write_success() { + let data = Vec::with_capacity(100); + let mut cursor = Cursor::new(data); + let write_data = b"Hello, Stellar!"; + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(&cursor.get_ref()[..], write_data); + assert_eq!(cursor.position(), write_data.len() as u64); + } + + #[test] + fn test_cursor_write_multiple_writes() { + let data = Vec::with_capacity(100); + let mut cursor = Cursor::new(data); + let write_data1: &[u8] = b"Hello, "; + let write_data2: &[u8] = b"Rust!"; + + // First write + assert!(cursor.write_all(write_data1).is_ok()); + assert_eq!(&cursor.get_ref()[..], write_data1); + assert_eq!(cursor.position(), write_data1.len() as u64); + + // Second write + assert!(cursor.write_all(write_data2).is_ok()); + let mut expected = Vec::new(); + expected.extend_from_slice(write_data1); + expected.extend_from_slice(write_data2); + assert_eq!(&cursor.get_ref()[..], expected.as_slice()); + assert_eq!(cursor.position(), expected.len() as u64); + } + + #[test] + fn test_cursor_write_empty() { + let data = Vec::with_capacity(100); + let mut cursor = Cursor::new(data); + let write_data = b""; + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(cursor.get_ref().len(), 0); + assert_eq!(cursor.position(), 0); + } + + #[test] + fn test_cursor_write_at_position() { + let mut data = vec![0u8; 10]; + { + let mut cursor = Cursor::new(&mut data[..]); + let write_data = b"Rust"; + + // Move cursor to position 6 + cursor.set_position(6); + assert_eq!(cursor.position(), 6); + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(cursor.position(), 10); + } + + let mut expected = vec![0u8; 10]; + expected[6..10].copy_from_slice(b"Rust"); + assert_eq!(&data[..], &expected[..]); + } + + #[test] + fn test_cursor_write_overflow() { + let mut data = vec![0u8; 5]; + let mut cursor = Cursor::new(&mut data[..]); + let write_data = b"Too long data"; + + let result = cursor.write_all(write_data); + assert!(result.is_err()); + #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); + assert_eq!(result.unwrap_err().kind(), io::ErrorKind::WriteZero); #[cfg(feature = "embedded_io")] assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof + result.unwrap_err().kind(), + embedded_io_extras::ErrorKind::WriteZero ); - // read_exact makes no promises about the content of the buffer on error + } + + #[test] + fn test_cursor_write_from_empty_cursor() { + let data = Vec::new(); + let mut cursor = Cursor::new(data); + let write_data = b"Initial Data"; + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(&cursor.get_ref()[..], write_data); + assert_eq!(cursor.position(), write_data.len() as u64); + } + + #[test] + fn test_cursor_write_partial() { + let mut data = [0u8; 5]; + let mut cursor = Cursor::new(&mut data[..]); + let write_data = b"Hello, Stellar!"; + + // Attempt to write data that exceeds the buffer size + // using `write` instead of `write_all` + let result = cursor.write(&write_data[..7]).unwrap(); + assert_eq!(result, 5); + assert_eq!(&cursor.get_ref()[..], b"Hello"); } } diff --git a/spec/output/generator_spec_rust_custom_jsonschema_impls/enum.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_jsonschema_impls/enum.x/MyXDR.rs index cadf5fcc7..dcec6cdc8 100644 --- a/spec/output/generator_spec_rust_custom_jsonschema_impls/enum.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_jsonschema_impls/enum.x/MyXDR.rs @@ -2834,11 +2834,25 @@ mod test_io { use super::*; + macro_rules! assert_unexpected_eof { + ($result:expr) => {{ + let err = $result.unwrap_err(); + #[cfg(feature = "std")] + { + assert_eq!(err.kind(), io::ErrorKind::UnexpectedEof); + } + #[cfg(feature = "embedded_io")] + { + assert_eq!(err, embedded_io_extras::ReadExactError::UnexpectedEof); + } + }}; + } + #[test] - fn test_read_exact_success() { + fn test_cursor_read_exact_success() { let data = b"The quick brown fox jumps over the lazy dog."; let mut cursor = Cursor::new(data); - let mut buffer = [0u8; 19]; // Exactly the length of "The quick brown fox" + let mut buffer = [0u8; 19]; // Attempt to read exactly 19 bytes assert!(cursor.read_exact(&mut buffer).is_ok()); @@ -2847,8 +2861,8 @@ mod test_io { } #[test] - fn test_read_exact_less_than_available() { - let data = b"Hello, Rust!"; + fn test_cursor_read_exact_less_than_available() { + let data = b"Hello, Stellar!"; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 5]; @@ -2859,7 +2873,7 @@ mod test_io { } #[test] - fn test_read_exact_exact_eof() { + fn test_cursor_read_exact_exact_eof() { let data = b"Data"; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 4]; @@ -2873,21 +2887,12 @@ mod test_io { let mut buffer_eof = [0u8; 1]; let result = cursor.read_exact(&mut buffer_eof); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); assert_eq!(cursor.position(), 4); // Position should remain at EOF } #[test] - fn test_read_exact_past_eof() { + fn test_cursor_read_exact_past_eof() { let data = b"Short"; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 10]; // Requesting more bytes than available @@ -2895,24 +2900,15 @@ mod test_io { // Attempt to read 10 bytes from a 5-byte buffer let result = cursor.read_exact(&mut buffer); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); assert_eq!(cursor.position(), 5); // Position should move to EOF } #[test] - fn test_read_exact_empty_buffer() { + fn test_cursor_read_exact_empty_buffer() { let data = b"Non-empty"; let mut cursor = Cursor::new(data); - let mut buffer = [0u8; 0]; // Zero-length buffer + let mut buffer = [0u8; 0]; // Attempt to read zero bytes assert!(cursor.read_exact(&mut buffer).is_ok()); @@ -2920,7 +2916,7 @@ mod test_io { } #[test] - fn test_read_exact_from_empty_cursor() { + fn test_cursor_read_exact_from_empty_cursor() { let data: &[u8] = b""; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 5]; @@ -2928,21 +2924,12 @@ mod test_io { // Attempt to read from an empty cursor let result = cursor.read_exact(&mut buffer); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); assert_eq!(cursor.position(), 0); // Position remains at 0 } #[test] - fn test_read_exact_multiple_reads() { + fn test_cursor_read_exact_multiple_reads() { let data = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; let mut cursor = Cursor::new(data); @@ -2963,80 +2950,212 @@ mod test_io { // Third read: Attempt to read 10 bytes, but only 6 are available let result = cursor.read_exact(&mut buffer3); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); // read_exact makes no promises about the content of the buffer on error + // https://github.com/rust-lang/rust/blob/84ac80f1921afc243d71fd0caaa4f2838c294102/library/std/src/io/impls.rs#L287 // assert_eq!(&buffer3[..6], b"UVWXYZ"); assert_eq!(cursor.position(), 26); // Position should be at EOF } #[test] - fn test_cursor_read_exact_after_eof() { - let data = b"End"; - let mut cursor = Cursor::new(data); - let mut buffer = [0u8; 3]; + fn test_slice_read_exact_success() { + let data: &[u8] = b"The quick brown fox jumps over the lazy dog."; + let mut reader = data; + let mut buffer = [0u8; 19]; - // First read: read the entire buffer - assert!(cursor.read_exact(&mut buffer).is_ok()); - assert_eq!(&buffer, b"End"); - assert_eq!(cursor.position(), 3); + // Attempt to read exactly 19 bytes + assert!(reader.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"The quick brown fox"); + } - // Second read: attempt to read again, should fail + #[test] + fn test_slice_read_exact_less_than_available() { + let data: &[u8] = b"Hello, Stellar!"; + let mut reader = data; + let mut buffer = [0u8; 5]; + + // Attempt to read 5 bytes from the start + assert!(reader.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Hello"); + } + + #[test] + fn test_slice_read_exact_exact_eof() { + let data: &[u8] = b"Data"; + let mut reader = data; + let mut buffer = [0u8; 4]; + + // Attempt to read exactly 4 bytes, which is the entire slice + assert!(reader.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Data"); + + // Further attempt to read should fail with EOF let mut buffer_eof = [0u8; 1]; - let result = cursor.read_exact(&mut buffer_eof); + let result = reader.read_exact(&mut buffer_eof); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); - assert_eq!(cursor.position(), 3); // Position remains at EOF + assert_unexpected_eof!(result); } #[test] - fn test_slice_read_exact_success() { - let data = b"SliceReadTest"; - let mut slice = &data[..]; - let mut buffer = [0u8; 13]; // Exact length + fn test_slice_read_exact_past_eof() { + let data: &[u8] = b"Short"; + let mut reader = data; + let mut buffer = [0u8; 10]; // Requesting more bytes than available - // Using Read trait directly on slice - assert!(slice.read_exact(&mut buffer).is_ok()); - assert_eq!(&buffer, b"SliceReadTest"); + // Attempt to read 10 bytes from a 5-byte slice + let result = reader.read_exact(&mut buffer); + assert!(result.is_err()); + assert_unexpected_eof!(result); } #[test] - fn test_slice_read_exact_partial() { - let data = b"SlicePartial"; - let mut slice = &data[..]; - let mut buffer = [0u8; 20]; // Request more bytes than available + fn test_slice_read_exact_empty_buffer() { + let data: &[u8] = b"Non-empty"; + let mut reader = data; + let mut buffer = [0u8; 0]; // Zero-length buffer - // Using Read trait directly on slice - let result = slice.read_exact(&mut buffer); + // Attempt to read zero bytes + assert!(reader.read_exact(&mut buffer).is_ok()); + } + + #[test] + fn test_slice_read_exact_from_empty_slice() { + let data: &[u8] = b""; + let mut reader = data; + let mut buffer = [0u8; 5]; + + // Attempt to read from an empty slice + let result = reader.read_exact(&mut buffer); assert!(result.is_err()); + assert_unexpected_eof!(result); + } + + #[test] + fn test_slice_read_exact_multiple_reads() { + let data: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + let mut reader = data; + + let mut buffer1 = [0u8; 10]; + let mut buffer2 = [0u8; 10]; + let mut buffer3 = [0u8; 10]; // Only 6 bytes left + + // First read: 10 bytes + assert!(reader.read_exact(&mut buffer1).is_ok()); + assert_eq!(&buffer1, b"ABCDEFGHIJ"); + + // Second read: 10 bytes + assert!(reader.read_exact(&mut buffer2).is_ok()); + assert_eq!(&buffer2, b"KLMNOPQRST"); + + // Third read: Attempt to read 10 bytes, but only 6 are available + let result = reader.read_exact(&mut buffer3); + assert!(result.is_err()); + assert_unexpected_eof!(result); + } + + #[test] + fn test_cursor_write_success() { + let data = Vec::with_capacity(100); + let mut cursor = Cursor::new(data); + let write_data = b"Hello, Stellar!"; + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(&cursor.get_ref()[..], write_data); + assert_eq!(cursor.position(), write_data.len() as u64); + } + + #[test] + fn test_cursor_write_multiple_writes() { + let data = Vec::with_capacity(100); + let mut cursor = Cursor::new(data); + let write_data1: &[u8] = b"Hello, "; + let write_data2: &[u8] = b"Rust!"; + + // First write + assert!(cursor.write_all(write_data1).is_ok()); + assert_eq!(&cursor.get_ref()[..], write_data1); + assert_eq!(cursor.position(), write_data1.len() as u64); + + // Second write + assert!(cursor.write_all(write_data2).is_ok()); + let mut expected = Vec::new(); + expected.extend_from_slice(write_data1); + expected.extend_from_slice(write_data2); + assert_eq!(&cursor.get_ref()[..], expected.as_slice()); + assert_eq!(cursor.position(), expected.len() as u64); + } + + #[test] + fn test_cursor_write_empty() { + let data = Vec::with_capacity(100); + let mut cursor = Cursor::new(data); + let write_data = b""; + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(cursor.get_ref().len(), 0); + assert_eq!(cursor.position(), 0); + } + + #[test] + fn test_cursor_write_at_position() { + let mut data = vec![0u8; 10]; + { + let mut cursor = Cursor::new(&mut data[..]); + let write_data = b"Rust"; + + // Move cursor to position 6 + cursor.set_position(6); + assert_eq!(cursor.position(), 6); + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(cursor.position(), 10); + } + + let mut expected = vec![0u8; 10]; + expected[6..10].copy_from_slice(b"Rust"); + assert_eq!(&data[..], &expected[..]); + } + + #[test] + fn test_cursor_write_overflow() { + let mut data = vec![0u8; 5]; + let mut cursor = Cursor::new(&mut data[..]); + let write_data = b"Too long data"; + + let result = cursor.write_all(write_data); + assert!(result.is_err()); + #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); + assert_eq!(result.unwrap_err().kind(), io::ErrorKind::WriteZero); #[cfg(feature = "embedded_io")] assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof + result.unwrap_err().kind(), + embedded_io_extras::ErrorKind::WriteZero ); - // read_exact makes no promises about the content of the buffer on error + } + + #[test] + fn test_cursor_write_from_empty_cursor() { + let data = Vec::new(); + let mut cursor = Cursor::new(data); + let write_data = b"Initial Data"; + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(&cursor.get_ref()[..], write_data); + assert_eq!(cursor.position(), write_data.len() as u64); + } + + #[test] + fn test_cursor_write_partial() { + let mut data = [0u8; 5]; + let mut cursor = Cursor::new(&mut data[..]); + let write_data = b"Hello, Stellar!"; + + // Attempt to write data that exceeds the buffer size + // using `write` instead of `write_all` + let result = cursor.write(&write_data[..7]).unwrap(); + assert_eq!(result, 5); + assert_eq!(&cursor.get_ref()[..], b"Hello"); } } diff --git a/spec/output/generator_spec_rust_custom_jsonschema_impls/nesting.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_jsonschema_impls/nesting.x/MyXDR.rs index 478d81d48..16a0e8e39 100644 --- a/spec/output/generator_spec_rust_custom_jsonschema_impls/nesting.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_jsonschema_impls/nesting.x/MyXDR.rs @@ -2834,11 +2834,25 @@ mod test_io { use super::*; + macro_rules! assert_unexpected_eof { + ($result:expr) => {{ + let err = $result.unwrap_err(); + #[cfg(feature = "std")] + { + assert_eq!(err.kind(), io::ErrorKind::UnexpectedEof); + } + #[cfg(feature = "embedded_io")] + { + assert_eq!(err, embedded_io_extras::ReadExactError::UnexpectedEof); + } + }}; + } + #[test] - fn test_read_exact_success() { + fn test_cursor_read_exact_success() { let data = b"The quick brown fox jumps over the lazy dog."; let mut cursor = Cursor::new(data); - let mut buffer = [0u8; 19]; // Exactly the length of "The quick brown fox" + let mut buffer = [0u8; 19]; // Attempt to read exactly 19 bytes assert!(cursor.read_exact(&mut buffer).is_ok()); @@ -2847,8 +2861,8 @@ mod test_io { } #[test] - fn test_read_exact_less_than_available() { - let data = b"Hello, Rust!"; + fn test_cursor_read_exact_less_than_available() { + let data = b"Hello, Stellar!"; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 5]; @@ -2859,7 +2873,7 @@ mod test_io { } #[test] - fn test_read_exact_exact_eof() { + fn test_cursor_read_exact_exact_eof() { let data = b"Data"; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 4]; @@ -2873,21 +2887,12 @@ mod test_io { let mut buffer_eof = [0u8; 1]; let result = cursor.read_exact(&mut buffer_eof); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); assert_eq!(cursor.position(), 4); // Position should remain at EOF } #[test] - fn test_read_exact_past_eof() { + fn test_cursor_read_exact_past_eof() { let data = b"Short"; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 10]; // Requesting more bytes than available @@ -2895,24 +2900,15 @@ mod test_io { // Attempt to read 10 bytes from a 5-byte buffer let result = cursor.read_exact(&mut buffer); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); assert_eq!(cursor.position(), 5); // Position should move to EOF } #[test] - fn test_read_exact_empty_buffer() { + fn test_cursor_read_exact_empty_buffer() { let data = b"Non-empty"; let mut cursor = Cursor::new(data); - let mut buffer = [0u8; 0]; // Zero-length buffer + let mut buffer = [0u8; 0]; // Attempt to read zero bytes assert!(cursor.read_exact(&mut buffer).is_ok()); @@ -2920,7 +2916,7 @@ mod test_io { } #[test] - fn test_read_exact_from_empty_cursor() { + fn test_cursor_read_exact_from_empty_cursor() { let data: &[u8] = b""; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 5]; @@ -2928,21 +2924,12 @@ mod test_io { // Attempt to read from an empty cursor let result = cursor.read_exact(&mut buffer); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); assert_eq!(cursor.position(), 0); // Position remains at 0 } #[test] - fn test_read_exact_multiple_reads() { + fn test_cursor_read_exact_multiple_reads() { let data = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; let mut cursor = Cursor::new(data); @@ -2963,80 +2950,212 @@ mod test_io { // Third read: Attempt to read 10 bytes, but only 6 are available let result = cursor.read_exact(&mut buffer3); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); // read_exact makes no promises about the content of the buffer on error + // https://github.com/rust-lang/rust/blob/84ac80f1921afc243d71fd0caaa4f2838c294102/library/std/src/io/impls.rs#L287 // assert_eq!(&buffer3[..6], b"UVWXYZ"); assert_eq!(cursor.position(), 26); // Position should be at EOF } #[test] - fn test_cursor_read_exact_after_eof() { - let data = b"End"; - let mut cursor = Cursor::new(data); - let mut buffer = [0u8; 3]; + fn test_slice_read_exact_success() { + let data: &[u8] = b"The quick brown fox jumps over the lazy dog."; + let mut reader = data; + let mut buffer = [0u8; 19]; - // First read: read the entire buffer - assert!(cursor.read_exact(&mut buffer).is_ok()); - assert_eq!(&buffer, b"End"); - assert_eq!(cursor.position(), 3); + // Attempt to read exactly 19 bytes + assert!(reader.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"The quick brown fox"); + } - // Second read: attempt to read again, should fail + #[test] + fn test_slice_read_exact_less_than_available() { + let data: &[u8] = b"Hello, Stellar!"; + let mut reader = data; + let mut buffer = [0u8; 5]; + + // Attempt to read 5 bytes from the start + assert!(reader.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Hello"); + } + + #[test] + fn test_slice_read_exact_exact_eof() { + let data: &[u8] = b"Data"; + let mut reader = data; + let mut buffer = [0u8; 4]; + + // Attempt to read exactly 4 bytes, which is the entire slice + assert!(reader.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Data"); + + // Further attempt to read should fail with EOF let mut buffer_eof = [0u8; 1]; - let result = cursor.read_exact(&mut buffer_eof); + let result = reader.read_exact(&mut buffer_eof); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); - assert_eq!(cursor.position(), 3); // Position remains at EOF + assert_unexpected_eof!(result); } #[test] - fn test_slice_read_exact_success() { - let data = b"SliceReadTest"; - let mut slice = &data[..]; - let mut buffer = [0u8; 13]; // Exact length + fn test_slice_read_exact_past_eof() { + let data: &[u8] = b"Short"; + let mut reader = data; + let mut buffer = [0u8; 10]; // Requesting more bytes than available - // Using Read trait directly on slice - assert!(slice.read_exact(&mut buffer).is_ok()); - assert_eq!(&buffer, b"SliceReadTest"); + // Attempt to read 10 bytes from a 5-byte slice + let result = reader.read_exact(&mut buffer); + assert!(result.is_err()); + assert_unexpected_eof!(result); } #[test] - fn test_slice_read_exact_partial() { - let data = b"SlicePartial"; - let mut slice = &data[..]; - let mut buffer = [0u8; 20]; // Request more bytes than available + fn test_slice_read_exact_empty_buffer() { + let data: &[u8] = b"Non-empty"; + let mut reader = data; + let mut buffer = [0u8; 0]; // Zero-length buffer - // Using Read trait directly on slice - let result = slice.read_exact(&mut buffer); + // Attempt to read zero bytes + assert!(reader.read_exact(&mut buffer).is_ok()); + } + + #[test] + fn test_slice_read_exact_from_empty_slice() { + let data: &[u8] = b""; + let mut reader = data; + let mut buffer = [0u8; 5]; + + // Attempt to read from an empty slice + let result = reader.read_exact(&mut buffer); assert!(result.is_err()); + assert_unexpected_eof!(result); + } + + #[test] + fn test_slice_read_exact_multiple_reads() { + let data: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + let mut reader = data; + + let mut buffer1 = [0u8; 10]; + let mut buffer2 = [0u8; 10]; + let mut buffer3 = [0u8; 10]; // Only 6 bytes left + + // First read: 10 bytes + assert!(reader.read_exact(&mut buffer1).is_ok()); + assert_eq!(&buffer1, b"ABCDEFGHIJ"); + + // Second read: 10 bytes + assert!(reader.read_exact(&mut buffer2).is_ok()); + assert_eq!(&buffer2, b"KLMNOPQRST"); + + // Third read: Attempt to read 10 bytes, but only 6 are available + let result = reader.read_exact(&mut buffer3); + assert!(result.is_err()); + assert_unexpected_eof!(result); + } + + #[test] + fn test_cursor_write_success() { + let data = Vec::with_capacity(100); + let mut cursor = Cursor::new(data); + let write_data = b"Hello, Stellar!"; + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(&cursor.get_ref()[..], write_data); + assert_eq!(cursor.position(), write_data.len() as u64); + } + + #[test] + fn test_cursor_write_multiple_writes() { + let data = Vec::with_capacity(100); + let mut cursor = Cursor::new(data); + let write_data1: &[u8] = b"Hello, "; + let write_data2: &[u8] = b"Rust!"; + + // First write + assert!(cursor.write_all(write_data1).is_ok()); + assert_eq!(&cursor.get_ref()[..], write_data1); + assert_eq!(cursor.position(), write_data1.len() as u64); + + // Second write + assert!(cursor.write_all(write_data2).is_ok()); + let mut expected = Vec::new(); + expected.extend_from_slice(write_data1); + expected.extend_from_slice(write_data2); + assert_eq!(&cursor.get_ref()[..], expected.as_slice()); + assert_eq!(cursor.position(), expected.len() as u64); + } + + #[test] + fn test_cursor_write_empty() { + let data = Vec::with_capacity(100); + let mut cursor = Cursor::new(data); + let write_data = b""; + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(cursor.get_ref().len(), 0); + assert_eq!(cursor.position(), 0); + } + + #[test] + fn test_cursor_write_at_position() { + let mut data = vec![0u8; 10]; + { + let mut cursor = Cursor::new(&mut data[..]); + let write_data = b"Rust"; + + // Move cursor to position 6 + cursor.set_position(6); + assert_eq!(cursor.position(), 6); + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(cursor.position(), 10); + } + + let mut expected = vec![0u8; 10]; + expected[6..10].copy_from_slice(b"Rust"); + assert_eq!(&data[..], &expected[..]); + } + + #[test] + fn test_cursor_write_overflow() { + let mut data = vec![0u8; 5]; + let mut cursor = Cursor::new(&mut data[..]); + let write_data = b"Too long data"; + + let result = cursor.write_all(write_data); + assert!(result.is_err()); + #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); + assert_eq!(result.unwrap_err().kind(), io::ErrorKind::WriteZero); #[cfg(feature = "embedded_io")] assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof + result.unwrap_err().kind(), + embedded_io_extras::ErrorKind::WriteZero ); - // read_exact makes no promises about the content of the buffer on error + } + + #[test] + fn test_cursor_write_from_empty_cursor() { + let data = Vec::new(); + let mut cursor = Cursor::new(data); + let write_data = b"Initial Data"; + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(&cursor.get_ref()[..], write_data); + assert_eq!(cursor.position(), write_data.len() as u64); + } + + #[test] + fn test_cursor_write_partial() { + let mut data = [0u8; 5]; + let mut cursor = Cursor::new(&mut data[..]); + let write_data = b"Hello, Stellar!"; + + // Attempt to write data that exceeds the buffer size + // using `write` instead of `write_all` + let result = cursor.write(&write_data[..7]).unwrap(); + assert_eq!(result, 5); + assert_eq!(&cursor.get_ref()[..], b"Hello"); } } diff --git a/spec/output/generator_spec_rust_custom_jsonschema_impls/optional.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_jsonschema_impls/optional.x/MyXDR.rs index 1a89ac298..0272543c0 100644 --- a/spec/output/generator_spec_rust_custom_jsonschema_impls/optional.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_jsonschema_impls/optional.x/MyXDR.rs @@ -2834,11 +2834,25 @@ mod test_io { use super::*; + macro_rules! assert_unexpected_eof { + ($result:expr) => {{ + let err = $result.unwrap_err(); + #[cfg(feature = "std")] + { + assert_eq!(err.kind(), io::ErrorKind::UnexpectedEof); + } + #[cfg(feature = "embedded_io")] + { + assert_eq!(err, embedded_io_extras::ReadExactError::UnexpectedEof); + } + }}; + } + #[test] - fn test_read_exact_success() { + fn test_cursor_read_exact_success() { let data = b"The quick brown fox jumps over the lazy dog."; let mut cursor = Cursor::new(data); - let mut buffer = [0u8; 19]; // Exactly the length of "The quick brown fox" + let mut buffer = [0u8; 19]; // Attempt to read exactly 19 bytes assert!(cursor.read_exact(&mut buffer).is_ok()); @@ -2847,8 +2861,8 @@ mod test_io { } #[test] - fn test_read_exact_less_than_available() { - let data = b"Hello, Rust!"; + fn test_cursor_read_exact_less_than_available() { + let data = b"Hello, Stellar!"; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 5]; @@ -2859,7 +2873,7 @@ mod test_io { } #[test] - fn test_read_exact_exact_eof() { + fn test_cursor_read_exact_exact_eof() { let data = b"Data"; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 4]; @@ -2873,21 +2887,12 @@ mod test_io { let mut buffer_eof = [0u8; 1]; let result = cursor.read_exact(&mut buffer_eof); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); assert_eq!(cursor.position(), 4); // Position should remain at EOF } #[test] - fn test_read_exact_past_eof() { + fn test_cursor_read_exact_past_eof() { let data = b"Short"; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 10]; // Requesting more bytes than available @@ -2895,24 +2900,15 @@ mod test_io { // Attempt to read 10 bytes from a 5-byte buffer let result = cursor.read_exact(&mut buffer); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); assert_eq!(cursor.position(), 5); // Position should move to EOF } #[test] - fn test_read_exact_empty_buffer() { + fn test_cursor_read_exact_empty_buffer() { let data = b"Non-empty"; let mut cursor = Cursor::new(data); - let mut buffer = [0u8; 0]; // Zero-length buffer + let mut buffer = [0u8; 0]; // Attempt to read zero bytes assert!(cursor.read_exact(&mut buffer).is_ok()); @@ -2920,7 +2916,7 @@ mod test_io { } #[test] - fn test_read_exact_from_empty_cursor() { + fn test_cursor_read_exact_from_empty_cursor() { let data: &[u8] = b""; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 5]; @@ -2928,21 +2924,12 @@ mod test_io { // Attempt to read from an empty cursor let result = cursor.read_exact(&mut buffer); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); assert_eq!(cursor.position(), 0); // Position remains at 0 } #[test] - fn test_read_exact_multiple_reads() { + fn test_cursor_read_exact_multiple_reads() { let data = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; let mut cursor = Cursor::new(data); @@ -2963,80 +2950,212 @@ mod test_io { // Third read: Attempt to read 10 bytes, but only 6 are available let result = cursor.read_exact(&mut buffer3); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); // read_exact makes no promises about the content of the buffer on error + // https://github.com/rust-lang/rust/blob/84ac80f1921afc243d71fd0caaa4f2838c294102/library/std/src/io/impls.rs#L287 // assert_eq!(&buffer3[..6], b"UVWXYZ"); assert_eq!(cursor.position(), 26); // Position should be at EOF } #[test] - fn test_cursor_read_exact_after_eof() { - let data = b"End"; - let mut cursor = Cursor::new(data); - let mut buffer = [0u8; 3]; + fn test_slice_read_exact_success() { + let data: &[u8] = b"The quick brown fox jumps over the lazy dog."; + let mut reader = data; + let mut buffer = [0u8; 19]; - // First read: read the entire buffer - assert!(cursor.read_exact(&mut buffer).is_ok()); - assert_eq!(&buffer, b"End"); - assert_eq!(cursor.position(), 3); + // Attempt to read exactly 19 bytes + assert!(reader.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"The quick brown fox"); + } - // Second read: attempt to read again, should fail + #[test] + fn test_slice_read_exact_less_than_available() { + let data: &[u8] = b"Hello, Stellar!"; + let mut reader = data; + let mut buffer = [0u8; 5]; + + // Attempt to read 5 bytes from the start + assert!(reader.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Hello"); + } + + #[test] + fn test_slice_read_exact_exact_eof() { + let data: &[u8] = b"Data"; + let mut reader = data; + let mut buffer = [0u8; 4]; + + // Attempt to read exactly 4 bytes, which is the entire slice + assert!(reader.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Data"); + + // Further attempt to read should fail with EOF let mut buffer_eof = [0u8; 1]; - let result = cursor.read_exact(&mut buffer_eof); + let result = reader.read_exact(&mut buffer_eof); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); - assert_eq!(cursor.position(), 3); // Position remains at EOF + assert_unexpected_eof!(result); } #[test] - fn test_slice_read_exact_success() { - let data = b"SliceReadTest"; - let mut slice = &data[..]; - let mut buffer = [0u8; 13]; // Exact length + fn test_slice_read_exact_past_eof() { + let data: &[u8] = b"Short"; + let mut reader = data; + let mut buffer = [0u8; 10]; // Requesting more bytes than available - // Using Read trait directly on slice - assert!(slice.read_exact(&mut buffer).is_ok()); - assert_eq!(&buffer, b"SliceReadTest"); + // Attempt to read 10 bytes from a 5-byte slice + let result = reader.read_exact(&mut buffer); + assert!(result.is_err()); + assert_unexpected_eof!(result); } #[test] - fn test_slice_read_exact_partial() { - let data = b"SlicePartial"; - let mut slice = &data[..]; - let mut buffer = [0u8; 20]; // Request more bytes than available + fn test_slice_read_exact_empty_buffer() { + let data: &[u8] = b"Non-empty"; + let mut reader = data; + let mut buffer = [0u8; 0]; // Zero-length buffer - // Using Read trait directly on slice - let result = slice.read_exact(&mut buffer); + // Attempt to read zero bytes + assert!(reader.read_exact(&mut buffer).is_ok()); + } + + #[test] + fn test_slice_read_exact_from_empty_slice() { + let data: &[u8] = b""; + let mut reader = data; + let mut buffer = [0u8; 5]; + + // Attempt to read from an empty slice + let result = reader.read_exact(&mut buffer); assert!(result.is_err()); + assert_unexpected_eof!(result); + } + + #[test] + fn test_slice_read_exact_multiple_reads() { + let data: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + let mut reader = data; + + let mut buffer1 = [0u8; 10]; + let mut buffer2 = [0u8; 10]; + let mut buffer3 = [0u8; 10]; // Only 6 bytes left + + // First read: 10 bytes + assert!(reader.read_exact(&mut buffer1).is_ok()); + assert_eq!(&buffer1, b"ABCDEFGHIJ"); + + // Second read: 10 bytes + assert!(reader.read_exact(&mut buffer2).is_ok()); + assert_eq!(&buffer2, b"KLMNOPQRST"); + + // Third read: Attempt to read 10 bytes, but only 6 are available + let result = reader.read_exact(&mut buffer3); + assert!(result.is_err()); + assert_unexpected_eof!(result); + } + + #[test] + fn test_cursor_write_success() { + let data = Vec::with_capacity(100); + let mut cursor = Cursor::new(data); + let write_data = b"Hello, Stellar!"; + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(&cursor.get_ref()[..], write_data); + assert_eq!(cursor.position(), write_data.len() as u64); + } + + #[test] + fn test_cursor_write_multiple_writes() { + let data = Vec::with_capacity(100); + let mut cursor = Cursor::new(data); + let write_data1: &[u8] = b"Hello, "; + let write_data2: &[u8] = b"Rust!"; + + // First write + assert!(cursor.write_all(write_data1).is_ok()); + assert_eq!(&cursor.get_ref()[..], write_data1); + assert_eq!(cursor.position(), write_data1.len() as u64); + + // Second write + assert!(cursor.write_all(write_data2).is_ok()); + let mut expected = Vec::new(); + expected.extend_from_slice(write_data1); + expected.extend_from_slice(write_data2); + assert_eq!(&cursor.get_ref()[..], expected.as_slice()); + assert_eq!(cursor.position(), expected.len() as u64); + } + + #[test] + fn test_cursor_write_empty() { + let data = Vec::with_capacity(100); + let mut cursor = Cursor::new(data); + let write_data = b""; + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(cursor.get_ref().len(), 0); + assert_eq!(cursor.position(), 0); + } + + #[test] + fn test_cursor_write_at_position() { + let mut data = vec![0u8; 10]; + { + let mut cursor = Cursor::new(&mut data[..]); + let write_data = b"Rust"; + + // Move cursor to position 6 + cursor.set_position(6); + assert_eq!(cursor.position(), 6); + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(cursor.position(), 10); + } + + let mut expected = vec![0u8; 10]; + expected[6..10].copy_from_slice(b"Rust"); + assert_eq!(&data[..], &expected[..]); + } + + #[test] + fn test_cursor_write_overflow() { + let mut data = vec![0u8; 5]; + let mut cursor = Cursor::new(&mut data[..]); + let write_data = b"Too long data"; + + let result = cursor.write_all(write_data); + assert!(result.is_err()); + #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); + assert_eq!(result.unwrap_err().kind(), io::ErrorKind::WriteZero); #[cfg(feature = "embedded_io")] assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof + result.unwrap_err().kind(), + embedded_io_extras::ErrorKind::WriteZero ); - // read_exact makes no promises about the content of the buffer on error + } + + #[test] + fn test_cursor_write_from_empty_cursor() { + let data = Vec::new(); + let mut cursor = Cursor::new(data); + let write_data = b"Initial Data"; + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(&cursor.get_ref()[..], write_data); + assert_eq!(cursor.position(), write_data.len() as u64); + } + + #[test] + fn test_cursor_write_partial() { + let mut data = [0u8; 5]; + let mut cursor = Cursor::new(&mut data[..]); + let write_data = b"Hello, Stellar!"; + + // Attempt to write data that exceeds the buffer size + // using `write` instead of `write_all` + let result = cursor.write(&write_data[..7]).unwrap(); + assert_eq!(result, 5); + assert_eq!(&cursor.get_ref()[..], b"Hello"); } } diff --git a/spec/output/generator_spec_rust_custom_jsonschema_impls/struct.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_jsonschema_impls/struct.x/MyXDR.rs index 83e18bab4..b7fc89ddf 100644 --- a/spec/output/generator_spec_rust_custom_jsonschema_impls/struct.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_jsonschema_impls/struct.x/MyXDR.rs @@ -2834,11 +2834,25 @@ mod test_io { use super::*; + macro_rules! assert_unexpected_eof { + ($result:expr) => {{ + let err = $result.unwrap_err(); + #[cfg(feature = "std")] + { + assert_eq!(err.kind(), io::ErrorKind::UnexpectedEof); + } + #[cfg(feature = "embedded_io")] + { + assert_eq!(err, embedded_io_extras::ReadExactError::UnexpectedEof); + } + }}; + } + #[test] - fn test_read_exact_success() { + fn test_cursor_read_exact_success() { let data = b"The quick brown fox jumps over the lazy dog."; let mut cursor = Cursor::new(data); - let mut buffer = [0u8; 19]; // Exactly the length of "The quick brown fox" + let mut buffer = [0u8; 19]; // Attempt to read exactly 19 bytes assert!(cursor.read_exact(&mut buffer).is_ok()); @@ -2847,8 +2861,8 @@ mod test_io { } #[test] - fn test_read_exact_less_than_available() { - let data = b"Hello, Rust!"; + fn test_cursor_read_exact_less_than_available() { + let data = b"Hello, Stellar!"; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 5]; @@ -2859,7 +2873,7 @@ mod test_io { } #[test] - fn test_read_exact_exact_eof() { + fn test_cursor_read_exact_exact_eof() { let data = b"Data"; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 4]; @@ -2873,21 +2887,12 @@ mod test_io { let mut buffer_eof = [0u8; 1]; let result = cursor.read_exact(&mut buffer_eof); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); assert_eq!(cursor.position(), 4); // Position should remain at EOF } #[test] - fn test_read_exact_past_eof() { + fn test_cursor_read_exact_past_eof() { let data = b"Short"; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 10]; // Requesting more bytes than available @@ -2895,24 +2900,15 @@ mod test_io { // Attempt to read 10 bytes from a 5-byte buffer let result = cursor.read_exact(&mut buffer); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); assert_eq!(cursor.position(), 5); // Position should move to EOF } #[test] - fn test_read_exact_empty_buffer() { + fn test_cursor_read_exact_empty_buffer() { let data = b"Non-empty"; let mut cursor = Cursor::new(data); - let mut buffer = [0u8; 0]; // Zero-length buffer + let mut buffer = [0u8; 0]; // Attempt to read zero bytes assert!(cursor.read_exact(&mut buffer).is_ok()); @@ -2920,7 +2916,7 @@ mod test_io { } #[test] - fn test_read_exact_from_empty_cursor() { + fn test_cursor_read_exact_from_empty_cursor() { let data: &[u8] = b""; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 5]; @@ -2928,21 +2924,12 @@ mod test_io { // Attempt to read from an empty cursor let result = cursor.read_exact(&mut buffer); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); assert_eq!(cursor.position(), 0); // Position remains at 0 } #[test] - fn test_read_exact_multiple_reads() { + fn test_cursor_read_exact_multiple_reads() { let data = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; let mut cursor = Cursor::new(data); @@ -2963,80 +2950,212 @@ mod test_io { // Third read: Attempt to read 10 bytes, but only 6 are available let result = cursor.read_exact(&mut buffer3); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); // read_exact makes no promises about the content of the buffer on error + // https://github.com/rust-lang/rust/blob/84ac80f1921afc243d71fd0caaa4f2838c294102/library/std/src/io/impls.rs#L287 // assert_eq!(&buffer3[..6], b"UVWXYZ"); assert_eq!(cursor.position(), 26); // Position should be at EOF } #[test] - fn test_cursor_read_exact_after_eof() { - let data = b"End"; - let mut cursor = Cursor::new(data); - let mut buffer = [0u8; 3]; + fn test_slice_read_exact_success() { + let data: &[u8] = b"The quick brown fox jumps over the lazy dog."; + let mut reader = data; + let mut buffer = [0u8; 19]; - // First read: read the entire buffer - assert!(cursor.read_exact(&mut buffer).is_ok()); - assert_eq!(&buffer, b"End"); - assert_eq!(cursor.position(), 3); + // Attempt to read exactly 19 bytes + assert!(reader.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"The quick brown fox"); + } - // Second read: attempt to read again, should fail + #[test] + fn test_slice_read_exact_less_than_available() { + let data: &[u8] = b"Hello, Stellar!"; + let mut reader = data; + let mut buffer = [0u8; 5]; + + // Attempt to read 5 bytes from the start + assert!(reader.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Hello"); + } + + #[test] + fn test_slice_read_exact_exact_eof() { + let data: &[u8] = b"Data"; + let mut reader = data; + let mut buffer = [0u8; 4]; + + // Attempt to read exactly 4 bytes, which is the entire slice + assert!(reader.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Data"); + + // Further attempt to read should fail with EOF let mut buffer_eof = [0u8; 1]; - let result = cursor.read_exact(&mut buffer_eof); + let result = reader.read_exact(&mut buffer_eof); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); - assert_eq!(cursor.position(), 3); // Position remains at EOF + assert_unexpected_eof!(result); } #[test] - fn test_slice_read_exact_success() { - let data = b"SliceReadTest"; - let mut slice = &data[..]; - let mut buffer = [0u8; 13]; // Exact length + fn test_slice_read_exact_past_eof() { + let data: &[u8] = b"Short"; + let mut reader = data; + let mut buffer = [0u8; 10]; // Requesting more bytes than available - // Using Read trait directly on slice - assert!(slice.read_exact(&mut buffer).is_ok()); - assert_eq!(&buffer, b"SliceReadTest"); + // Attempt to read 10 bytes from a 5-byte slice + let result = reader.read_exact(&mut buffer); + assert!(result.is_err()); + assert_unexpected_eof!(result); } #[test] - fn test_slice_read_exact_partial() { - let data = b"SlicePartial"; - let mut slice = &data[..]; - let mut buffer = [0u8; 20]; // Request more bytes than available + fn test_slice_read_exact_empty_buffer() { + let data: &[u8] = b"Non-empty"; + let mut reader = data; + let mut buffer = [0u8; 0]; // Zero-length buffer - // Using Read trait directly on slice - let result = slice.read_exact(&mut buffer); + // Attempt to read zero bytes + assert!(reader.read_exact(&mut buffer).is_ok()); + } + + #[test] + fn test_slice_read_exact_from_empty_slice() { + let data: &[u8] = b""; + let mut reader = data; + let mut buffer = [0u8; 5]; + + // Attempt to read from an empty slice + let result = reader.read_exact(&mut buffer); assert!(result.is_err()); + assert_unexpected_eof!(result); + } + + #[test] + fn test_slice_read_exact_multiple_reads() { + let data: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + let mut reader = data; + + let mut buffer1 = [0u8; 10]; + let mut buffer2 = [0u8; 10]; + let mut buffer3 = [0u8; 10]; // Only 6 bytes left + + // First read: 10 bytes + assert!(reader.read_exact(&mut buffer1).is_ok()); + assert_eq!(&buffer1, b"ABCDEFGHIJ"); + + // Second read: 10 bytes + assert!(reader.read_exact(&mut buffer2).is_ok()); + assert_eq!(&buffer2, b"KLMNOPQRST"); + + // Third read: Attempt to read 10 bytes, but only 6 are available + let result = reader.read_exact(&mut buffer3); + assert!(result.is_err()); + assert_unexpected_eof!(result); + } + + #[test] + fn test_cursor_write_success() { + let data = Vec::with_capacity(100); + let mut cursor = Cursor::new(data); + let write_data = b"Hello, Stellar!"; + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(&cursor.get_ref()[..], write_data); + assert_eq!(cursor.position(), write_data.len() as u64); + } + + #[test] + fn test_cursor_write_multiple_writes() { + let data = Vec::with_capacity(100); + let mut cursor = Cursor::new(data); + let write_data1: &[u8] = b"Hello, "; + let write_data2: &[u8] = b"Rust!"; + + // First write + assert!(cursor.write_all(write_data1).is_ok()); + assert_eq!(&cursor.get_ref()[..], write_data1); + assert_eq!(cursor.position(), write_data1.len() as u64); + + // Second write + assert!(cursor.write_all(write_data2).is_ok()); + let mut expected = Vec::new(); + expected.extend_from_slice(write_data1); + expected.extend_from_slice(write_data2); + assert_eq!(&cursor.get_ref()[..], expected.as_slice()); + assert_eq!(cursor.position(), expected.len() as u64); + } + + #[test] + fn test_cursor_write_empty() { + let data = Vec::with_capacity(100); + let mut cursor = Cursor::new(data); + let write_data = b""; + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(cursor.get_ref().len(), 0); + assert_eq!(cursor.position(), 0); + } + + #[test] + fn test_cursor_write_at_position() { + let mut data = vec![0u8; 10]; + { + let mut cursor = Cursor::new(&mut data[..]); + let write_data = b"Rust"; + + // Move cursor to position 6 + cursor.set_position(6); + assert_eq!(cursor.position(), 6); + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(cursor.position(), 10); + } + + let mut expected = vec![0u8; 10]; + expected[6..10].copy_from_slice(b"Rust"); + assert_eq!(&data[..], &expected[..]); + } + + #[test] + fn test_cursor_write_overflow() { + let mut data = vec![0u8; 5]; + let mut cursor = Cursor::new(&mut data[..]); + let write_data = b"Too long data"; + + let result = cursor.write_all(write_data); + assert!(result.is_err()); + #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); + assert_eq!(result.unwrap_err().kind(), io::ErrorKind::WriteZero); #[cfg(feature = "embedded_io")] assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof + result.unwrap_err().kind(), + embedded_io_extras::ErrorKind::WriteZero ); - // read_exact makes no promises about the content of the buffer on error + } + + #[test] + fn test_cursor_write_from_empty_cursor() { + let data = Vec::new(); + let mut cursor = Cursor::new(data); + let write_data = b"Initial Data"; + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(&cursor.get_ref()[..], write_data); + assert_eq!(cursor.position(), write_data.len() as u64); + } + + #[test] + fn test_cursor_write_partial() { + let mut data = [0u8; 5]; + let mut cursor = Cursor::new(&mut data[..]); + let write_data = b"Hello, Stellar!"; + + // Attempt to write data that exceeds the buffer size + // using `write` instead of `write_all` + let result = cursor.write(&write_data[..7]).unwrap(); + assert_eq!(result, 5); + assert_eq!(&cursor.get_ref()[..], b"Hello"); } } diff --git a/spec/output/generator_spec_rust_custom_jsonschema_impls/test.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_jsonschema_impls/test.x/MyXDR.rs index 5a3e78240..87899ae0d 100644 --- a/spec/output/generator_spec_rust_custom_jsonschema_impls/test.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_jsonschema_impls/test.x/MyXDR.rs @@ -2834,11 +2834,25 @@ mod test_io { use super::*; + macro_rules! assert_unexpected_eof { + ($result:expr) => {{ + let err = $result.unwrap_err(); + #[cfg(feature = "std")] + { + assert_eq!(err.kind(), io::ErrorKind::UnexpectedEof); + } + #[cfg(feature = "embedded_io")] + { + assert_eq!(err, embedded_io_extras::ReadExactError::UnexpectedEof); + } + }}; + } + #[test] - fn test_read_exact_success() { + fn test_cursor_read_exact_success() { let data = b"The quick brown fox jumps over the lazy dog."; let mut cursor = Cursor::new(data); - let mut buffer = [0u8; 19]; // Exactly the length of "The quick brown fox" + let mut buffer = [0u8; 19]; // Attempt to read exactly 19 bytes assert!(cursor.read_exact(&mut buffer).is_ok()); @@ -2847,8 +2861,8 @@ mod test_io { } #[test] - fn test_read_exact_less_than_available() { - let data = b"Hello, Rust!"; + fn test_cursor_read_exact_less_than_available() { + let data = b"Hello, Stellar!"; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 5]; @@ -2859,7 +2873,7 @@ mod test_io { } #[test] - fn test_read_exact_exact_eof() { + fn test_cursor_read_exact_exact_eof() { let data = b"Data"; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 4]; @@ -2873,21 +2887,12 @@ mod test_io { let mut buffer_eof = [0u8; 1]; let result = cursor.read_exact(&mut buffer_eof); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); assert_eq!(cursor.position(), 4); // Position should remain at EOF } #[test] - fn test_read_exact_past_eof() { + fn test_cursor_read_exact_past_eof() { let data = b"Short"; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 10]; // Requesting more bytes than available @@ -2895,24 +2900,15 @@ mod test_io { // Attempt to read 10 bytes from a 5-byte buffer let result = cursor.read_exact(&mut buffer); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); assert_eq!(cursor.position(), 5); // Position should move to EOF } #[test] - fn test_read_exact_empty_buffer() { + fn test_cursor_read_exact_empty_buffer() { let data = b"Non-empty"; let mut cursor = Cursor::new(data); - let mut buffer = [0u8; 0]; // Zero-length buffer + let mut buffer = [0u8; 0]; // Attempt to read zero bytes assert!(cursor.read_exact(&mut buffer).is_ok()); @@ -2920,7 +2916,7 @@ mod test_io { } #[test] - fn test_read_exact_from_empty_cursor() { + fn test_cursor_read_exact_from_empty_cursor() { let data: &[u8] = b""; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 5]; @@ -2928,21 +2924,12 @@ mod test_io { // Attempt to read from an empty cursor let result = cursor.read_exact(&mut buffer); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); assert_eq!(cursor.position(), 0); // Position remains at 0 } #[test] - fn test_read_exact_multiple_reads() { + fn test_cursor_read_exact_multiple_reads() { let data = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; let mut cursor = Cursor::new(data); @@ -2963,80 +2950,212 @@ mod test_io { // Third read: Attempt to read 10 bytes, but only 6 are available let result = cursor.read_exact(&mut buffer3); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); // read_exact makes no promises about the content of the buffer on error + // https://github.com/rust-lang/rust/blob/84ac80f1921afc243d71fd0caaa4f2838c294102/library/std/src/io/impls.rs#L287 // assert_eq!(&buffer3[..6], b"UVWXYZ"); assert_eq!(cursor.position(), 26); // Position should be at EOF } #[test] - fn test_cursor_read_exact_after_eof() { - let data = b"End"; - let mut cursor = Cursor::new(data); - let mut buffer = [0u8; 3]; + fn test_slice_read_exact_success() { + let data: &[u8] = b"The quick brown fox jumps over the lazy dog."; + let mut reader = data; + let mut buffer = [0u8; 19]; - // First read: read the entire buffer - assert!(cursor.read_exact(&mut buffer).is_ok()); - assert_eq!(&buffer, b"End"); - assert_eq!(cursor.position(), 3); + // Attempt to read exactly 19 bytes + assert!(reader.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"The quick brown fox"); + } + + #[test] + fn test_slice_read_exact_less_than_available() { + let data: &[u8] = b"Hello, Stellar!"; + let mut reader = data; + let mut buffer = [0u8; 5]; + + // Attempt to read 5 bytes from the start + assert!(reader.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Hello"); + } + + #[test] + fn test_slice_read_exact_exact_eof() { + let data: &[u8] = b"Data"; + let mut reader = data; + let mut buffer = [0u8; 4]; + + // Attempt to read exactly 4 bytes, which is the entire slice + assert!(reader.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Data"); - // Second read: attempt to read again, should fail + // Further attempt to read should fail with EOF let mut buffer_eof = [0u8; 1]; - let result = cursor.read_exact(&mut buffer_eof); + let result = reader.read_exact(&mut buffer_eof); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); - assert_eq!(cursor.position(), 3); // Position remains at EOF + assert_unexpected_eof!(result); } #[test] - fn test_slice_read_exact_success() { - let data = b"SliceReadTest"; - let mut slice = &data[..]; - let mut buffer = [0u8; 13]; // Exact length + fn test_slice_read_exact_past_eof() { + let data: &[u8] = b"Short"; + let mut reader = data; + let mut buffer = [0u8; 10]; // Requesting more bytes than available - // Using Read trait directly on slice - assert!(slice.read_exact(&mut buffer).is_ok()); - assert_eq!(&buffer, b"SliceReadTest"); + // Attempt to read 10 bytes from a 5-byte slice + let result = reader.read_exact(&mut buffer); + assert!(result.is_err()); + assert_unexpected_eof!(result); } #[test] - fn test_slice_read_exact_partial() { - let data = b"SlicePartial"; - let mut slice = &data[..]; - let mut buffer = [0u8; 20]; // Request more bytes than available + fn test_slice_read_exact_empty_buffer() { + let data: &[u8] = b"Non-empty"; + let mut reader = data; + let mut buffer = [0u8; 0]; // Zero-length buffer + + // Attempt to read zero bytes + assert!(reader.read_exact(&mut buffer).is_ok()); + } + + #[test] + fn test_slice_read_exact_from_empty_slice() { + let data: &[u8] = b""; + let mut reader = data; + let mut buffer = [0u8; 5]; + + // Attempt to read from an empty slice + let result = reader.read_exact(&mut buffer); + assert!(result.is_err()); + assert_unexpected_eof!(result); + } + + #[test] + fn test_slice_read_exact_multiple_reads() { + let data: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + let mut reader = data; + + let mut buffer1 = [0u8; 10]; + let mut buffer2 = [0u8; 10]; + let mut buffer3 = [0u8; 10]; // Only 6 bytes left + + // First read: 10 bytes + assert!(reader.read_exact(&mut buffer1).is_ok()); + assert_eq!(&buffer1, b"ABCDEFGHIJ"); + + // Second read: 10 bytes + assert!(reader.read_exact(&mut buffer2).is_ok()); + assert_eq!(&buffer2, b"KLMNOPQRST"); + + // Third read: Attempt to read 10 bytes, but only 6 are available + let result = reader.read_exact(&mut buffer3); + assert!(result.is_err()); + assert_unexpected_eof!(result); + } + + #[test] + fn test_cursor_write_success() { + let data = Vec::with_capacity(100); + let mut cursor = Cursor::new(data); + let write_data = b"Hello, Stellar!"; + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(&cursor.get_ref()[..], write_data); + assert_eq!(cursor.position(), write_data.len() as u64); + } - // Using Read trait directly on slice - let result = slice.read_exact(&mut buffer); + #[test] + fn test_cursor_write_multiple_writes() { + let data = Vec::with_capacity(100); + let mut cursor = Cursor::new(data); + let write_data1: &[u8] = b"Hello, "; + let write_data2: &[u8] = b"Rust!"; + + // First write + assert!(cursor.write_all(write_data1).is_ok()); + assert_eq!(&cursor.get_ref()[..], write_data1); + assert_eq!(cursor.position(), write_data1.len() as u64); + + // Second write + assert!(cursor.write_all(write_data2).is_ok()); + let mut expected = Vec::new(); + expected.extend_from_slice(write_data1); + expected.extend_from_slice(write_data2); + assert_eq!(&cursor.get_ref()[..], expected.as_slice()); + assert_eq!(cursor.position(), expected.len() as u64); + } + + #[test] + fn test_cursor_write_empty() { + let data = Vec::with_capacity(100); + let mut cursor = Cursor::new(data); + let write_data = b""; + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(cursor.get_ref().len(), 0); + assert_eq!(cursor.position(), 0); + } + + #[test] + fn test_cursor_write_at_position() { + let mut data = vec![0u8; 10]; + { + let mut cursor = Cursor::new(&mut data[..]); + let write_data = b"Rust"; + + // Move cursor to position 6 + cursor.set_position(6); + assert_eq!(cursor.position(), 6); + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(cursor.position(), 10); + } + + let mut expected = vec![0u8; 10]; + expected[6..10].copy_from_slice(b"Rust"); + assert_eq!(&data[..], &expected[..]); + } + + #[test] + fn test_cursor_write_overflow() { + let mut data = vec![0u8; 5]; + let mut cursor = Cursor::new(&mut data[..]); + let write_data = b"Too long data"; + + let result = cursor.write_all(write_data); assert!(result.is_err()); + #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); + assert_eq!(result.unwrap_err().kind(), io::ErrorKind::WriteZero); #[cfg(feature = "embedded_io")] assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof + result.unwrap_err().kind(), + embedded_io_extras::ErrorKind::WriteZero ); - // read_exact makes no promises about the content of the buffer on error + } + + #[test] + fn test_cursor_write_from_empty_cursor() { + let data = Vec::new(); + let mut cursor = Cursor::new(data); + let write_data = b"Initial Data"; + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(&cursor.get_ref()[..], write_data); + assert_eq!(cursor.position(), write_data.len() as u64); + } + + #[test] + fn test_cursor_write_partial() { + let mut data = [0u8; 5]; + let mut cursor = Cursor::new(&mut data[..]); + let write_data = b"Hello, Stellar!"; + + // Attempt to write data that exceeds the buffer size + // using `write` instead of `write_all` + let result = cursor.write(&write_data[..7]).unwrap(); + assert_eq!(result, 5); + assert_eq!(&cursor.get_ref()[..], b"Hello"); } } diff --git a/spec/output/generator_spec_rust_custom_jsonschema_impls/union.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_jsonschema_impls/union.x/MyXDR.rs index 1c13213f5..63979c68e 100644 --- a/spec/output/generator_spec_rust_custom_jsonschema_impls/union.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_jsonschema_impls/union.x/MyXDR.rs @@ -2834,11 +2834,25 @@ mod test_io { use super::*; + macro_rules! assert_unexpected_eof { + ($result:expr) => {{ + let err = $result.unwrap_err(); + #[cfg(feature = "std")] + { + assert_eq!(err.kind(), io::ErrorKind::UnexpectedEof); + } + #[cfg(feature = "embedded_io")] + { + assert_eq!(err, embedded_io_extras::ReadExactError::UnexpectedEof); + } + }}; + } + #[test] - fn test_read_exact_success() { + fn test_cursor_read_exact_success() { let data = b"The quick brown fox jumps over the lazy dog."; let mut cursor = Cursor::new(data); - let mut buffer = [0u8; 19]; // Exactly the length of "The quick brown fox" + let mut buffer = [0u8; 19]; // Attempt to read exactly 19 bytes assert!(cursor.read_exact(&mut buffer).is_ok()); @@ -2847,8 +2861,8 @@ mod test_io { } #[test] - fn test_read_exact_less_than_available() { - let data = b"Hello, Rust!"; + fn test_cursor_read_exact_less_than_available() { + let data = b"Hello, Stellar!"; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 5]; @@ -2859,7 +2873,7 @@ mod test_io { } #[test] - fn test_read_exact_exact_eof() { + fn test_cursor_read_exact_exact_eof() { let data = b"Data"; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 4]; @@ -2873,21 +2887,12 @@ mod test_io { let mut buffer_eof = [0u8; 1]; let result = cursor.read_exact(&mut buffer_eof); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); assert_eq!(cursor.position(), 4); // Position should remain at EOF } #[test] - fn test_read_exact_past_eof() { + fn test_cursor_read_exact_past_eof() { let data = b"Short"; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 10]; // Requesting more bytes than available @@ -2895,24 +2900,15 @@ mod test_io { // Attempt to read 10 bytes from a 5-byte buffer let result = cursor.read_exact(&mut buffer); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); assert_eq!(cursor.position(), 5); // Position should move to EOF } #[test] - fn test_read_exact_empty_buffer() { + fn test_cursor_read_exact_empty_buffer() { let data = b"Non-empty"; let mut cursor = Cursor::new(data); - let mut buffer = [0u8; 0]; // Zero-length buffer + let mut buffer = [0u8; 0]; // Attempt to read zero bytes assert!(cursor.read_exact(&mut buffer).is_ok()); @@ -2920,7 +2916,7 @@ mod test_io { } #[test] - fn test_read_exact_from_empty_cursor() { + fn test_cursor_read_exact_from_empty_cursor() { let data: &[u8] = b""; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 5]; @@ -2928,21 +2924,12 @@ mod test_io { // Attempt to read from an empty cursor let result = cursor.read_exact(&mut buffer); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); assert_eq!(cursor.position(), 0); // Position remains at 0 } #[test] - fn test_read_exact_multiple_reads() { + fn test_cursor_read_exact_multiple_reads() { let data = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; let mut cursor = Cursor::new(data); @@ -2963,80 +2950,212 @@ mod test_io { // Third read: Attempt to read 10 bytes, but only 6 are available let result = cursor.read_exact(&mut buffer3); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); // read_exact makes no promises about the content of the buffer on error + // https://github.com/rust-lang/rust/blob/84ac80f1921afc243d71fd0caaa4f2838c294102/library/std/src/io/impls.rs#L287 // assert_eq!(&buffer3[..6], b"UVWXYZ"); assert_eq!(cursor.position(), 26); // Position should be at EOF } #[test] - fn test_cursor_read_exact_after_eof() { - let data = b"End"; - let mut cursor = Cursor::new(data); - let mut buffer = [0u8; 3]; + fn test_slice_read_exact_success() { + let data: &[u8] = b"The quick brown fox jumps over the lazy dog."; + let mut reader = data; + let mut buffer = [0u8; 19]; - // First read: read the entire buffer - assert!(cursor.read_exact(&mut buffer).is_ok()); - assert_eq!(&buffer, b"End"); - assert_eq!(cursor.position(), 3); + // Attempt to read exactly 19 bytes + assert!(reader.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"The quick brown fox"); + } - // Second read: attempt to read again, should fail + #[test] + fn test_slice_read_exact_less_than_available() { + let data: &[u8] = b"Hello, Stellar!"; + let mut reader = data; + let mut buffer = [0u8; 5]; + + // Attempt to read 5 bytes from the start + assert!(reader.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Hello"); + } + + #[test] + fn test_slice_read_exact_exact_eof() { + let data: &[u8] = b"Data"; + let mut reader = data; + let mut buffer = [0u8; 4]; + + // Attempt to read exactly 4 bytes, which is the entire slice + assert!(reader.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Data"); + + // Further attempt to read should fail with EOF let mut buffer_eof = [0u8; 1]; - let result = cursor.read_exact(&mut buffer_eof); + let result = reader.read_exact(&mut buffer_eof); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); - assert_eq!(cursor.position(), 3); // Position remains at EOF + assert_unexpected_eof!(result); } #[test] - fn test_slice_read_exact_success() { - let data = b"SliceReadTest"; - let mut slice = &data[..]; - let mut buffer = [0u8; 13]; // Exact length + fn test_slice_read_exact_past_eof() { + let data: &[u8] = b"Short"; + let mut reader = data; + let mut buffer = [0u8; 10]; // Requesting more bytes than available - // Using Read trait directly on slice - assert!(slice.read_exact(&mut buffer).is_ok()); - assert_eq!(&buffer, b"SliceReadTest"); + // Attempt to read 10 bytes from a 5-byte slice + let result = reader.read_exact(&mut buffer); + assert!(result.is_err()); + assert_unexpected_eof!(result); } #[test] - fn test_slice_read_exact_partial() { - let data = b"SlicePartial"; - let mut slice = &data[..]; - let mut buffer = [0u8; 20]; // Request more bytes than available + fn test_slice_read_exact_empty_buffer() { + let data: &[u8] = b"Non-empty"; + let mut reader = data; + let mut buffer = [0u8; 0]; // Zero-length buffer - // Using Read trait directly on slice - let result = slice.read_exact(&mut buffer); + // Attempt to read zero bytes + assert!(reader.read_exact(&mut buffer).is_ok()); + } + + #[test] + fn test_slice_read_exact_from_empty_slice() { + let data: &[u8] = b""; + let mut reader = data; + let mut buffer = [0u8; 5]; + + // Attempt to read from an empty slice + let result = reader.read_exact(&mut buffer); assert!(result.is_err()); + assert_unexpected_eof!(result); + } + + #[test] + fn test_slice_read_exact_multiple_reads() { + let data: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + let mut reader = data; + + let mut buffer1 = [0u8; 10]; + let mut buffer2 = [0u8; 10]; + let mut buffer3 = [0u8; 10]; // Only 6 bytes left + + // First read: 10 bytes + assert!(reader.read_exact(&mut buffer1).is_ok()); + assert_eq!(&buffer1, b"ABCDEFGHIJ"); + + // Second read: 10 bytes + assert!(reader.read_exact(&mut buffer2).is_ok()); + assert_eq!(&buffer2, b"KLMNOPQRST"); + + // Third read: Attempt to read 10 bytes, but only 6 are available + let result = reader.read_exact(&mut buffer3); + assert!(result.is_err()); + assert_unexpected_eof!(result); + } + + #[test] + fn test_cursor_write_success() { + let data = Vec::with_capacity(100); + let mut cursor = Cursor::new(data); + let write_data = b"Hello, Stellar!"; + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(&cursor.get_ref()[..], write_data); + assert_eq!(cursor.position(), write_data.len() as u64); + } + + #[test] + fn test_cursor_write_multiple_writes() { + let data = Vec::with_capacity(100); + let mut cursor = Cursor::new(data); + let write_data1: &[u8] = b"Hello, "; + let write_data2: &[u8] = b"Rust!"; + + // First write + assert!(cursor.write_all(write_data1).is_ok()); + assert_eq!(&cursor.get_ref()[..], write_data1); + assert_eq!(cursor.position(), write_data1.len() as u64); + + // Second write + assert!(cursor.write_all(write_data2).is_ok()); + let mut expected = Vec::new(); + expected.extend_from_slice(write_data1); + expected.extend_from_slice(write_data2); + assert_eq!(&cursor.get_ref()[..], expected.as_slice()); + assert_eq!(cursor.position(), expected.len() as u64); + } + + #[test] + fn test_cursor_write_empty() { + let data = Vec::with_capacity(100); + let mut cursor = Cursor::new(data); + let write_data = b""; + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(cursor.get_ref().len(), 0); + assert_eq!(cursor.position(), 0); + } + + #[test] + fn test_cursor_write_at_position() { + let mut data = vec![0u8; 10]; + { + let mut cursor = Cursor::new(&mut data[..]); + let write_data = b"Rust"; + + // Move cursor to position 6 + cursor.set_position(6); + assert_eq!(cursor.position(), 6); + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(cursor.position(), 10); + } + + let mut expected = vec![0u8; 10]; + expected[6..10].copy_from_slice(b"Rust"); + assert_eq!(&data[..], &expected[..]); + } + + #[test] + fn test_cursor_write_overflow() { + let mut data = vec![0u8; 5]; + let mut cursor = Cursor::new(&mut data[..]); + let write_data = b"Too long data"; + + let result = cursor.write_all(write_data); + assert!(result.is_err()); + #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); + assert_eq!(result.unwrap_err().kind(), io::ErrorKind::WriteZero); #[cfg(feature = "embedded_io")] assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof + result.unwrap_err().kind(), + embedded_io_extras::ErrorKind::WriteZero ); - // read_exact makes no promises about the content of the buffer on error + } + + #[test] + fn test_cursor_write_from_empty_cursor() { + let data = Vec::new(); + let mut cursor = Cursor::new(data); + let write_data = b"Initial Data"; + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(&cursor.get_ref()[..], write_data); + assert_eq!(cursor.position(), write_data.len() as u64); + } + + #[test] + fn test_cursor_write_partial() { + let mut data = [0u8; 5]; + let mut cursor = Cursor::new(&mut data[..]); + let write_data = b"Hello, Stellar!"; + + // Attempt to write data that exceeds the buffer size + // using `write` instead of `write_all` + let result = cursor.write(&write_data[..7]).unwrap(); + assert_eq!(result, 5); + assert_eq!(&cursor.get_ref()[..], b"Hello"); } } diff --git a/spec/output/generator_spec_rust_custom_str_impls/block_comments.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_str_impls/block_comments.x/MyXDR.rs index 2b9de8c27..a2906d184 100644 --- a/spec/output/generator_spec_rust_custom_str_impls/block_comments.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_str_impls/block_comments.x/MyXDR.rs @@ -2834,11 +2834,25 @@ mod test_io { use super::*; + macro_rules! assert_unexpected_eof { + ($result:expr) => {{ + let err = $result.unwrap_err(); + #[cfg(feature = "std")] + { + assert_eq!(err.kind(), io::ErrorKind::UnexpectedEof); + } + #[cfg(feature = "embedded_io")] + { + assert_eq!(err, embedded_io_extras::ReadExactError::UnexpectedEof); + } + }}; + } + #[test] - fn test_read_exact_success() { + fn test_cursor_read_exact_success() { let data = b"The quick brown fox jumps over the lazy dog."; let mut cursor = Cursor::new(data); - let mut buffer = [0u8; 19]; // Exactly the length of "The quick brown fox" + let mut buffer = [0u8; 19]; // Attempt to read exactly 19 bytes assert!(cursor.read_exact(&mut buffer).is_ok()); @@ -2847,8 +2861,8 @@ mod test_io { } #[test] - fn test_read_exact_less_than_available() { - let data = b"Hello, Rust!"; + fn test_cursor_read_exact_less_than_available() { + let data = b"Hello, Stellar!"; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 5]; @@ -2859,7 +2873,7 @@ mod test_io { } #[test] - fn test_read_exact_exact_eof() { + fn test_cursor_read_exact_exact_eof() { let data = b"Data"; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 4]; @@ -2873,21 +2887,12 @@ mod test_io { let mut buffer_eof = [0u8; 1]; let result = cursor.read_exact(&mut buffer_eof); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); assert_eq!(cursor.position(), 4); // Position should remain at EOF } #[test] - fn test_read_exact_past_eof() { + fn test_cursor_read_exact_past_eof() { let data = b"Short"; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 10]; // Requesting more bytes than available @@ -2895,24 +2900,15 @@ mod test_io { // Attempt to read 10 bytes from a 5-byte buffer let result = cursor.read_exact(&mut buffer); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); assert_eq!(cursor.position(), 5); // Position should move to EOF } #[test] - fn test_read_exact_empty_buffer() { + fn test_cursor_read_exact_empty_buffer() { let data = b"Non-empty"; let mut cursor = Cursor::new(data); - let mut buffer = [0u8; 0]; // Zero-length buffer + let mut buffer = [0u8; 0]; // Attempt to read zero bytes assert!(cursor.read_exact(&mut buffer).is_ok()); @@ -2920,7 +2916,7 @@ mod test_io { } #[test] - fn test_read_exact_from_empty_cursor() { + fn test_cursor_read_exact_from_empty_cursor() { let data: &[u8] = b""; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 5]; @@ -2928,21 +2924,12 @@ mod test_io { // Attempt to read from an empty cursor let result = cursor.read_exact(&mut buffer); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); assert_eq!(cursor.position(), 0); // Position remains at 0 } #[test] - fn test_read_exact_multiple_reads() { + fn test_cursor_read_exact_multiple_reads() { let data = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; let mut cursor = Cursor::new(data); @@ -2963,80 +2950,212 @@ mod test_io { // Third read: Attempt to read 10 bytes, but only 6 are available let result = cursor.read_exact(&mut buffer3); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); // read_exact makes no promises about the content of the buffer on error + // https://github.com/rust-lang/rust/blob/84ac80f1921afc243d71fd0caaa4f2838c294102/library/std/src/io/impls.rs#L287 // assert_eq!(&buffer3[..6], b"UVWXYZ"); assert_eq!(cursor.position(), 26); // Position should be at EOF } #[test] - fn test_cursor_read_exact_after_eof() { - let data = b"End"; - let mut cursor = Cursor::new(data); - let mut buffer = [0u8; 3]; + fn test_slice_read_exact_success() { + let data: &[u8] = b"The quick brown fox jumps over the lazy dog."; + let mut reader = data; + let mut buffer = [0u8; 19]; - // First read: read the entire buffer - assert!(cursor.read_exact(&mut buffer).is_ok()); - assert_eq!(&buffer, b"End"); - assert_eq!(cursor.position(), 3); + // Attempt to read exactly 19 bytes + assert!(reader.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"The quick brown fox"); + } - // Second read: attempt to read again, should fail + #[test] + fn test_slice_read_exact_less_than_available() { + let data: &[u8] = b"Hello, Stellar!"; + let mut reader = data; + let mut buffer = [0u8; 5]; + + // Attempt to read 5 bytes from the start + assert!(reader.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Hello"); + } + + #[test] + fn test_slice_read_exact_exact_eof() { + let data: &[u8] = b"Data"; + let mut reader = data; + let mut buffer = [0u8; 4]; + + // Attempt to read exactly 4 bytes, which is the entire slice + assert!(reader.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Data"); + + // Further attempt to read should fail with EOF let mut buffer_eof = [0u8; 1]; - let result = cursor.read_exact(&mut buffer_eof); + let result = reader.read_exact(&mut buffer_eof); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); - assert_eq!(cursor.position(), 3); // Position remains at EOF + assert_unexpected_eof!(result); } #[test] - fn test_slice_read_exact_success() { - let data = b"SliceReadTest"; - let mut slice = &data[..]; - let mut buffer = [0u8; 13]; // Exact length + fn test_slice_read_exact_past_eof() { + let data: &[u8] = b"Short"; + let mut reader = data; + let mut buffer = [0u8; 10]; // Requesting more bytes than available - // Using Read trait directly on slice - assert!(slice.read_exact(&mut buffer).is_ok()); - assert_eq!(&buffer, b"SliceReadTest"); + // Attempt to read 10 bytes from a 5-byte slice + let result = reader.read_exact(&mut buffer); + assert!(result.is_err()); + assert_unexpected_eof!(result); } #[test] - fn test_slice_read_exact_partial() { - let data = b"SlicePartial"; - let mut slice = &data[..]; - let mut buffer = [0u8; 20]; // Request more bytes than available + fn test_slice_read_exact_empty_buffer() { + let data: &[u8] = b"Non-empty"; + let mut reader = data; + let mut buffer = [0u8; 0]; // Zero-length buffer - // Using Read trait directly on slice - let result = slice.read_exact(&mut buffer); + // Attempt to read zero bytes + assert!(reader.read_exact(&mut buffer).is_ok()); + } + + #[test] + fn test_slice_read_exact_from_empty_slice() { + let data: &[u8] = b""; + let mut reader = data; + let mut buffer = [0u8; 5]; + + // Attempt to read from an empty slice + let result = reader.read_exact(&mut buffer); assert!(result.is_err()); + assert_unexpected_eof!(result); + } + + #[test] + fn test_slice_read_exact_multiple_reads() { + let data: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + let mut reader = data; + + let mut buffer1 = [0u8; 10]; + let mut buffer2 = [0u8; 10]; + let mut buffer3 = [0u8; 10]; // Only 6 bytes left + + // First read: 10 bytes + assert!(reader.read_exact(&mut buffer1).is_ok()); + assert_eq!(&buffer1, b"ABCDEFGHIJ"); + + // Second read: 10 bytes + assert!(reader.read_exact(&mut buffer2).is_ok()); + assert_eq!(&buffer2, b"KLMNOPQRST"); + + // Third read: Attempt to read 10 bytes, but only 6 are available + let result = reader.read_exact(&mut buffer3); + assert!(result.is_err()); + assert_unexpected_eof!(result); + } + + #[test] + fn test_cursor_write_success() { + let data = Vec::with_capacity(100); + let mut cursor = Cursor::new(data); + let write_data = b"Hello, Stellar!"; + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(&cursor.get_ref()[..], write_data); + assert_eq!(cursor.position(), write_data.len() as u64); + } + + #[test] + fn test_cursor_write_multiple_writes() { + let data = Vec::with_capacity(100); + let mut cursor = Cursor::new(data); + let write_data1: &[u8] = b"Hello, "; + let write_data2: &[u8] = b"Rust!"; + + // First write + assert!(cursor.write_all(write_data1).is_ok()); + assert_eq!(&cursor.get_ref()[..], write_data1); + assert_eq!(cursor.position(), write_data1.len() as u64); + + // Second write + assert!(cursor.write_all(write_data2).is_ok()); + let mut expected = Vec::new(); + expected.extend_from_slice(write_data1); + expected.extend_from_slice(write_data2); + assert_eq!(&cursor.get_ref()[..], expected.as_slice()); + assert_eq!(cursor.position(), expected.len() as u64); + } + + #[test] + fn test_cursor_write_empty() { + let data = Vec::with_capacity(100); + let mut cursor = Cursor::new(data); + let write_data = b""; + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(cursor.get_ref().len(), 0); + assert_eq!(cursor.position(), 0); + } + + #[test] + fn test_cursor_write_at_position() { + let mut data = vec![0u8; 10]; + { + let mut cursor = Cursor::new(&mut data[..]); + let write_data = b"Rust"; + + // Move cursor to position 6 + cursor.set_position(6); + assert_eq!(cursor.position(), 6); + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(cursor.position(), 10); + } + + let mut expected = vec![0u8; 10]; + expected[6..10].copy_from_slice(b"Rust"); + assert_eq!(&data[..], &expected[..]); + } + + #[test] + fn test_cursor_write_overflow() { + let mut data = vec![0u8; 5]; + let mut cursor = Cursor::new(&mut data[..]); + let write_data = b"Too long data"; + + let result = cursor.write_all(write_data); + assert!(result.is_err()); + #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); + assert_eq!(result.unwrap_err().kind(), io::ErrorKind::WriteZero); #[cfg(feature = "embedded_io")] assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof + result.unwrap_err().kind(), + embedded_io_extras::ErrorKind::WriteZero ); - // read_exact makes no promises about the content of the buffer on error + } + + #[test] + fn test_cursor_write_from_empty_cursor() { + let data = Vec::new(); + let mut cursor = Cursor::new(data); + let write_data = b"Initial Data"; + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(&cursor.get_ref()[..], write_data); + assert_eq!(cursor.position(), write_data.len() as u64); + } + + #[test] + fn test_cursor_write_partial() { + let mut data = [0u8; 5]; + let mut cursor = Cursor::new(&mut data[..]); + let write_data = b"Hello, Stellar!"; + + // Attempt to write data that exceeds the buffer size + // using `write` instead of `write_all` + let result = cursor.write(&write_data[..7]).unwrap(); + assert_eq!(result, 5); + assert_eq!(&cursor.get_ref()[..], b"Hello"); } } diff --git a/spec/output/generator_spec_rust_custom_str_impls/const.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_str_impls/const.x/MyXDR.rs index 0b80a5d3f..40946ac79 100644 --- a/spec/output/generator_spec_rust_custom_str_impls/const.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_str_impls/const.x/MyXDR.rs @@ -2834,11 +2834,25 @@ mod test_io { use super::*; + macro_rules! assert_unexpected_eof { + ($result:expr) => {{ + let err = $result.unwrap_err(); + #[cfg(feature = "std")] + { + assert_eq!(err.kind(), io::ErrorKind::UnexpectedEof); + } + #[cfg(feature = "embedded_io")] + { + assert_eq!(err, embedded_io_extras::ReadExactError::UnexpectedEof); + } + }}; + } + #[test] - fn test_read_exact_success() { + fn test_cursor_read_exact_success() { let data = b"The quick brown fox jumps over the lazy dog."; let mut cursor = Cursor::new(data); - let mut buffer = [0u8; 19]; // Exactly the length of "The quick brown fox" + let mut buffer = [0u8; 19]; // Attempt to read exactly 19 bytes assert!(cursor.read_exact(&mut buffer).is_ok()); @@ -2847,8 +2861,8 @@ mod test_io { } #[test] - fn test_read_exact_less_than_available() { - let data = b"Hello, Rust!"; + fn test_cursor_read_exact_less_than_available() { + let data = b"Hello, Stellar!"; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 5]; @@ -2859,7 +2873,7 @@ mod test_io { } #[test] - fn test_read_exact_exact_eof() { + fn test_cursor_read_exact_exact_eof() { let data = b"Data"; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 4]; @@ -2873,21 +2887,12 @@ mod test_io { let mut buffer_eof = [0u8; 1]; let result = cursor.read_exact(&mut buffer_eof); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); assert_eq!(cursor.position(), 4); // Position should remain at EOF } #[test] - fn test_read_exact_past_eof() { + fn test_cursor_read_exact_past_eof() { let data = b"Short"; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 10]; // Requesting more bytes than available @@ -2895,24 +2900,15 @@ mod test_io { // Attempt to read 10 bytes from a 5-byte buffer let result = cursor.read_exact(&mut buffer); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); assert_eq!(cursor.position(), 5); // Position should move to EOF } #[test] - fn test_read_exact_empty_buffer() { + fn test_cursor_read_exact_empty_buffer() { let data = b"Non-empty"; let mut cursor = Cursor::new(data); - let mut buffer = [0u8; 0]; // Zero-length buffer + let mut buffer = [0u8; 0]; // Attempt to read zero bytes assert!(cursor.read_exact(&mut buffer).is_ok()); @@ -2920,7 +2916,7 @@ mod test_io { } #[test] - fn test_read_exact_from_empty_cursor() { + fn test_cursor_read_exact_from_empty_cursor() { let data: &[u8] = b""; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 5]; @@ -2928,21 +2924,12 @@ mod test_io { // Attempt to read from an empty cursor let result = cursor.read_exact(&mut buffer); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); assert_eq!(cursor.position(), 0); // Position remains at 0 } #[test] - fn test_read_exact_multiple_reads() { + fn test_cursor_read_exact_multiple_reads() { let data = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; let mut cursor = Cursor::new(data); @@ -2963,80 +2950,212 @@ mod test_io { // Third read: Attempt to read 10 bytes, but only 6 are available let result = cursor.read_exact(&mut buffer3); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); // read_exact makes no promises about the content of the buffer on error + // https://github.com/rust-lang/rust/blob/84ac80f1921afc243d71fd0caaa4f2838c294102/library/std/src/io/impls.rs#L287 // assert_eq!(&buffer3[..6], b"UVWXYZ"); assert_eq!(cursor.position(), 26); // Position should be at EOF } #[test] - fn test_cursor_read_exact_after_eof() { - let data = b"End"; - let mut cursor = Cursor::new(data); - let mut buffer = [0u8; 3]; + fn test_slice_read_exact_success() { + let data: &[u8] = b"The quick brown fox jumps over the lazy dog."; + let mut reader = data; + let mut buffer = [0u8; 19]; - // First read: read the entire buffer - assert!(cursor.read_exact(&mut buffer).is_ok()); - assert_eq!(&buffer, b"End"); - assert_eq!(cursor.position(), 3); + // Attempt to read exactly 19 bytes + assert!(reader.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"The quick brown fox"); + } - // Second read: attempt to read again, should fail + #[test] + fn test_slice_read_exact_less_than_available() { + let data: &[u8] = b"Hello, Stellar!"; + let mut reader = data; + let mut buffer = [0u8; 5]; + + // Attempt to read 5 bytes from the start + assert!(reader.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Hello"); + } + + #[test] + fn test_slice_read_exact_exact_eof() { + let data: &[u8] = b"Data"; + let mut reader = data; + let mut buffer = [0u8; 4]; + + // Attempt to read exactly 4 bytes, which is the entire slice + assert!(reader.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Data"); + + // Further attempt to read should fail with EOF let mut buffer_eof = [0u8; 1]; - let result = cursor.read_exact(&mut buffer_eof); + let result = reader.read_exact(&mut buffer_eof); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); - assert_eq!(cursor.position(), 3); // Position remains at EOF + assert_unexpected_eof!(result); } #[test] - fn test_slice_read_exact_success() { - let data = b"SliceReadTest"; - let mut slice = &data[..]; - let mut buffer = [0u8; 13]; // Exact length + fn test_slice_read_exact_past_eof() { + let data: &[u8] = b"Short"; + let mut reader = data; + let mut buffer = [0u8; 10]; // Requesting more bytes than available - // Using Read trait directly on slice - assert!(slice.read_exact(&mut buffer).is_ok()); - assert_eq!(&buffer, b"SliceReadTest"); + // Attempt to read 10 bytes from a 5-byte slice + let result = reader.read_exact(&mut buffer); + assert!(result.is_err()); + assert_unexpected_eof!(result); } #[test] - fn test_slice_read_exact_partial() { - let data = b"SlicePartial"; - let mut slice = &data[..]; - let mut buffer = [0u8; 20]; // Request more bytes than available + fn test_slice_read_exact_empty_buffer() { + let data: &[u8] = b"Non-empty"; + let mut reader = data; + let mut buffer = [0u8; 0]; // Zero-length buffer - // Using Read trait directly on slice - let result = slice.read_exact(&mut buffer); + // Attempt to read zero bytes + assert!(reader.read_exact(&mut buffer).is_ok()); + } + + #[test] + fn test_slice_read_exact_from_empty_slice() { + let data: &[u8] = b""; + let mut reader = data; + let mut buffer = [0u8; 5]; + + // Attempt to read from an empty slice + let result = reader.read_exact(&mut buffer); assert!(result.is_err()); + assert_unexpected_eof!(result); + } + + #[test] + fn test_slice_read_exact_multiple_reads() { + let data: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + let mut reader = data; + + let mut buffer1 = [0u8; 10]; + let mut buffer2 = [0u8; 10]; + let mut buffer3 = [0u8; 10]; // Only 6 bytes left + + // First read: 10 bytes + assert!(reader.read_exact(&mut buffer1).is_ok()); + assert_eq!(&buffer1, b"ABCDEFGHIJ"); + + // Second read: 10 bytes + assert!(reader.read_exact(&mut buffer2).is_ok()); + assert_eq!(&buffer2, b"KLMNOPQRST"); + + // Third read: Attempt to read 10 bytes, but only 6 are available + let result = reader.read_exact(&mut buffer3); + assert!(result.is_err()); + assert_unexpected_eof!(result); + } + + #[test] + fn test_cursor_write_success() { + let data = Vec::with_capacity(100); + let mut cursor = Cursor::new(data); + let write_data = b"Hello, Stellar!"; + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(&cursor.get_ref()[..], write_data); + assert_eq!(cursor.position(), write_data.len() as u64); + } + + #[test] + fn test_cursor_write_multiple_writes() { + let data = Vec::with_capacity(100); + let mut cursor = Cursor::new(data); + let write_data1: &[u8] = b"Hello, "; + let write_data2: &[u8] = b"Rust!"; + + // First write + assert!(cursor.write_all(write_data1).is_ok()); + assert_eq!(&cursor.get_ref()[..], write_data1); + assert_eq!(cursor.position(), write_data1.len() as u64); + + // Second write + assert!(cursor.write_all(write_data2).is_ok()); + let mut expected = Vec::new(); + expected.extend_from_slice(write_data1); + expected.extend_from_slice(write_data2); + assert_eq!(&cursor.get_ref()[..], expected.as_slice()); + assert_eq!(cursor.position(), expected.len() as u64); + } + + #[test] + fn test_cursor_write_empty() { + let data = Vec::with_capacity(100); + let mut cursor = Cursor::new(data); + let write_data = b""; + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(cursor.get_ref().len(), 0); + assert_eq!(cursor.position(), 0); + } + + #[test] + fn test_cursor_write_at_position() { + let mut data = vec![0u8; 10]; + { + let mut cursor = Cursor::new(&mut data[..]); + let write_data = b"Rust"; + + // Move cursor to position 6 + cursor.set_position(6); + assert_eq!(cursor.position(), 6); + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(cursor.position(), 10); + } + + let mut expected = vec![0u8; 10]; + expected[6..10].copy_from_slice(b"Rust"); + assert_eq!(&data[..], &expected[..]); + } + + #[test] + fn test_cursor_write_overflow() { + let mut data = vec![0u8; 5]; + let mut cursor = Cursor::new(&mut data[..]); + let write_data = b"Too long data"; + + let result = cursor.write_all(write_data); + assert!(result.is_err()); + #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); + assert_eq!(result.unwrap_err().kind(), io::ErrorKind::WriteZero); #[cfg(feature = "embedded_io")] assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof + result.unwrap_err().kind(), + embedded_io_extras::ErrorKind::WriteZero ); - // read_exact makes no promises about the content of the buffer on error + } + + #[test] + fn test_cursor_write_from_empty_cursor() { + let data = Vec::new(); + let mut cursor = Cursor::new(data); + let write_data = b"Initial Data"; + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(&cursor.get_ref()[..], write_data); + assert_eq!(cursor.position(), write_data.len() as u64); + } + + #[test] + fn test_cursor_write_partial() { + let mut data = [0u8; 5]; + let mut cursor = Cursor::new(&mut data[..]); + let write_data = b"Hello, Stellar!"; + + // Attempt to write data that exceeds the buffer size + // using `write` instead of `write_all` + let result = cursor.write(&write_data[..7]).unwrap(); + assert_eq!(result, 5); + assert_eq!(&cursor.get_ref()[..], b"Hello"); } } diff --git a/spec/output/generator_spec_rust_custom_str_impls/enum.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_str_impls/enum.x/MyXDR.rs index b157adef4..50ab8abfd 100644 --- a/spec/output/generator_spec_rust_custom_str_impls/enum.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_str_impls/enum.x/MyXDR.rs @@ -2834,11 +2834,25 @@ mod test_io { use super::*; + macro_rules! assert_unexpected_eof { + ($result:expr) => {{ + let err = $result.unwrap_err(); + #[cfg(feature = "std")] + { + assert_eq!(err.kind(), io::ErrorKind::UnexpectedEof); + } + #[cfg(feature = "embedded_io")] + { + assert_eq!(err, embedded_io_extras::ReadExactError::UnexpectedEof); + } + }}; + } + #[test] - fn test_read_exact_success() { + fn test_cursor_read_exact_success() { let data = b"The quick brown fox jumps over the lazy dog."; let mut cursor = Cursor::new(data); - let mut buffer = [0u8; 19]; // Exactly the length of "The quick brown fox" + let mut buffer = [0u8; 19]; // Attempt to read exactly 19 bytes assert!(cursor.read_exact(&mut buffer).is_ok()); @@ -2847,8 +2861,8 @@ mod test_io { } #[test] - fn test_read_exact_less_than_available() { - let data = b"Hello, Rust!"; + fn test_cursor_read_exact_less_than_available() { + let data = b"Hello, Stellar!"; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 5]; @@ -2859,7 +2873,7 @@ mod test_io { } #[test] - fn test_read_exact_exact_eof() { + fn test_cursor_read_exact_exact_eof() { let data = b"Data"; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 4]; @@ -2873,21 +2887,12 @@ mod test_io { let mut buffer_eof = [0u8; 1]; let result = cursor.read_exact(&mut buffer_eof); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); assert_eq!(cursor.position(), 4); // Position should remain at EOF } #[test] - fn test_read_exact_past_eof() { + fn test_cursor_read_exact_past_eof() { let data = b"Short"; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 10]; // Requesting more bytes than available @@ -2895,24 +2900,15 @@ mod test_io { // Attempt to read 10 bytes from a 5-byte buffer let result = cursor.read_exact(&mut buffer); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); assert_eq!(cursor.position(), 5); // Position should move to EOF } #[test] - fn test_read_exact_empty_buffer() { + fn test_cursor_read_exact_empty_buffer() { let data = b"Non-empty"; let mut cursor = Cursor::new(data); - let mut buffer = [0u8; 0]; // Zero-length buffer + let mut buffer = [0u8; 0]; // Attempt to read zero bytes assert!(cursor.read_exact(&mut buffer).is_ok()); @@ -2920,7 +2916,7 @@ mod test_io { } #[test] - fn test_read_exact_from_empty_cursor() { + fn test_cursor_read_exact_from_empty_cursor() { let data: &[u8] = b""; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 5]; @@ -2928,21 +2924,12 @@ mod test_io { // Attempt to read from an empty cursor let result = cursor.read_exact(&mut buffer); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); assert_eq!(cursor.position(), 0); // Position remains at 0 } #[test] - fn test_read_exact_multiple_reads() { + fn test_cursor_read_exact_multiple_reads() { let data = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; let mut cursor = Cursor::new(data); @@ -2963,80 +2950,212 @@ mod test_io { // Third read: Attempt to read 10 bytes, but only 6 are available let result = cursor.read_exact(&mut buffer3); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); // read_exact makes no promises about the content of the buffer on error + // https://github.com/rust-lang/rust/blob/84ac80f1921afc243d71fd0caaa4f2838c294102/library/std/src/io/impls.rs#L287 // assert_eq!(&buffer3[..6], b"UVWXYZ"); assert_eq!(cursor.position(), 26); // Position should be at EOF } #[test] - fn test_cursor_read_exact_after_eof() { - let data = b"End"; - let mut cursor = Cursor::new(data); - let mut buffer = [0u8; 3]; + fn test_slice_read_exact_success() { + let data: &[u8] = b"The quick brown fox jumps over the lazy dog."; + let mut reader = data; + let mut buffer = [0u8; 19]; - // First read: read the entire buffer - assert!(cursor.read_exact(&mut buffer).is_ok()); - assert_eq!(&buffer, b"End"); - assert_eq!(cursor.position(), 3); + // Attempt to read exactly 19 bytes + assert!(reader.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"The quick brown fox"); + } - // Second read: attempt to read again, should fail + #[test] + fn test_slice_read_exact_less_than_available() { + let data: &[u8] = b"Hello, Stellar!"; + let mut reader = data; + let mut buffer = [0u8; 5]; + + // Attempt to read 5 bytes from the start + assert!(reader.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Hello"); + } + + #[test] + fn test_slice_read_exact_exact_eof() { + let data: &[u8] = b"Data"; + let mut reader = data; + let mut buffer = [0u8; 4]; + + // Attempt to read exactly 4 bytes, which is the entire slice + assert!(reader.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Data"); + + // Further attempt to read should fail with EOF let mut buffer_eof = [0u8; 1]; - let result = cursor.read_exact(&mut buffer_eof); + let result = reader.read_exact(&mut buffer_eof); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); - assert_eq!(cursor.position(), 3); // Position remains at EOF + assert_unexpected_eof!(result); } #[test] - fn test_slice_read_exact_success() { - let data = b"SliceReadTest"; - let mut slice = &data[..]; - let mut buffer = [0u8; 13]; // Exact length + fn test_slice_read_exact_past_eof() { + let data: &[u8] = b"Short"; + let mut reader = data; + let mut buffer = [0u8; 10]; // Requesting more bytes than available - // Using Read trait directly on slice - assert!(slice.read_exact(&mut buffer).is_ok()); - assert_eq!(&buffer, b"SliceReadTest"); + // Attempt to read 10 bytes from a 5-byte slice + let result = reader.read_exact(&mut buffer); + assert!(result.is_err()); + assert_unexpected_eof!(result); } #[test] - fn test_slice_read_exact_partial() { - let data = b"SlicePartial"; - let mut slice = &data[..]; - let mut buffer = [0u8; 20]; // Request more bytes than available + fn test_slice_read_exact_empty_buffer() { + let data: &[u8] = b"Non-empty"; + let mut reader = data; + let mut buffer = [0u8; 0]; // Zero-length buffer - // Using Read trait directly on slice - let result = slice.read_exact(&mut buffer); + // Attempt to read zero bytes + assert!(reader.read_exact(&mut buffer).is_ok()); + } + + #[test] + fn test_slice_read_exact_from_empty_slice() { + let data: &[u8] = b""; + let mut reader = data; + let mut buffer = [0u8; 5]; + + // Attempt to read from an empty slice + let result = reader.read_exact(&mut buffer); assert!(result.is_err()); + assert_unexpected_eof!(result); + } + + #[test] + fn test_slice_read_exact_multiple_reads() { + let data: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + let mut reader = data; + + let mut buffer1 = [0u8; 10]; + let mut buffer2 = [0u8; 10]; + let mut buffer3 = [0u8; 10]; // Only 6 bytes left + + // First read: 10 bytes + assert!(reader.read_exact(&mut buffer1).is_ok()); + assert_eq!(&buffer1, b"ABCDEFGHIJ"); + + // Second read: 10 bytes + assert!(reader.read_exact(&mut buffer2).is_ok()); + assert_eq!(&buffer2, b"KLMNOPQRST"); + + // Third read: Attempt to read 10 bytes, but only 6 are available + let result = reader.read_exact(&mut buffer3); + assert!(result.is_err()); + assert_unexpected_eof!(result); + } + + #[test] + fn test_cursor_write_success() { + let data = Vec::with_capacity(100); + let mut cursor = Cursor::new(data); + let write_data = b"Hello, Stellar!"; + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(&cursor.get_ref()[..], write_data); + assert_eq!(cursor.position(), write_data.len() as u64); + } + + #[test] + fn test_cursor_write_multiple_writes() { + let data = Vec::with_capacity(100); + let mut cursor = Cursor::new(data); + let write_data1: &[u8] = b"Hello, "; + let write_data2: &[u8] = b"Rust!"; + + // First write + assert!(cursor.write_all(write_data1).is_ok()); + assert_eq!(&cursor.get_ref()[..], write_data1); + assert_eq!(cursor.position(), write_data1.len() as u64); + + // Second write + assert!(cursor.write_all(write_data2).is_ok()); + let mut expected = Vec::new(); + expected.extend_from_slice(write_data1); + expected.extend_from_slice(write_data2); + assert_eq!(&cursor.get_ref()[..], expected.as_slice()); + assert_eq!(cursor.position(), expected.len() as u64); + } + + #[test] + fn test_cursor_write_empty() { + let data = Vec::with_capacity(100); + let mut cursor = Cursor::new(data); + let write_data = b""; + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(cursor.get_ref().len(), 0); + assert_eq!(cursor.position(), 0); + } + + #[test] + fn test_cursor_write_at_position() { + let mut data = vec![0u8; 10]; + { + let mut cursor = Cursor::new(&mut data[..]); + let write_data = b"Rust"; + + // Move cursor to position 6 + cursor.set_position(6); + assert_eq!(cursor.position(), 6); + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(cursor.position(), 10); + } + + let mut expected = vec![0u8; 10]; + expected[6..10].copy_from_slice(b"Rust"); + assert_eq!(&data[..], &expected[..]); + } + + #[test] + fn test_cursor_write_overflow() { + let mut data = vec![0u8; 5]; + let mut cursor = Cursor::new(&mut data[..]); + let write_data = b"Too long data"; + + let result = cursor.write_all(write_data); + assert!(result.is_err()); + #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); + assert_eq!(result.unwrap_err().kind(), io::ErrorKind::WriteZero); #[cfg(feature = "embedded_io")] assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof + result.unwrap_err().kind(), + embedded_io_extras::ErrorKind::WriteZero ); - // read_exact makes no promises about the content of the buffer on error + } + + #[test] + fn test_cursor_write_from_empty_cursor() { + let data = Vec::new(); + let mut cursor = Cursor::new(data); + let write_data = b"Initial Data"; + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(&cursor.get_ref()[..], write_data); + assert_eq!(cursor.position(), write_data.len() as u64); + } + + #[test] + fn test_cursor_write_partial() { + let mut data = [0u8; 5]; + let mut cursor = Cursor::new(&mut data[..]); + let write_data = b"Hello, Stellar!"; + + // Attempt to write data that exceeds the buffer size + // using `write` instead of `write_all` + let result = cursor.write(&write_data[..7]).unwrap(); + assert_eq!(result, 5); + assert_eq!(&cursor.get_ref()[..], b"Hello"); } } diff --git a/spec/output/generator_spec_rust_custom_str_impls/nesting.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_str_impls/nesting.x/MyXDR.rs index 7827028ac..e2420824c 100644 --- a/spec/output/generator_spec_rust_custom_str_impls/nesting.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_str_impls/nesting.x/MyXDR.rs @@ -2834,11 +2834,25 @@ mod test_io { use super::*; + macro_rules! assert_unexpected_eof { + ($result:expr) => {{ + let err = $result.unwrap_err(); + #[cfg(feature = "std")] + { + assert_eq!(err.kind(), io::ErrorKind::UnexpectedEof); + } + #[cfg(feature = "embedded_io")] + { + assert_eq!(err, embedded_io_extras::ReadExactError::UnexpectedEof); + } + }}; + } + #[test] - fn test_read_exact_success() { + fn test_cursor_read_exact_success() { let data = b"The quick brown fox jumps over the lazy dog."; let mut cursor = Cursor::new(data); - let mut buffer = [0u8; 19]; // Exactly the length of "The quick brown fox" + let mut buffer = [0u8; 19]; // Attempt to read exactly 19 bytes assert!(cursor.read_exact(&mut buffer).is_ok()); @@ -2847,8 +2861,8 @@ mod test_io { } #[test] - fn test_read_exact_less_than_available() { - let data = b"Hello, Rust!"; + fn test_cursor_read_exact_less_than_available() { + let data = b"Hello, Stellar!"; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 5]; @@ -2859,7 +2873,7 @@ mod test_io { } #[test] - fn test_read_exact_exact_eof() { + fn test_cursor_read_exact_exact_eof() { let data = b"Data"; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 4]; @@ -2873,21 +2887,12 @@ mod test_io { let mut buffer_eof = [0u8; 1]; let result = cursor.read_exact(&mut buffer_eof); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); assert_eq!(cursor.position(), 4); // Position should remain at EOF } #[test] - fn test_read_exact_past_eof() { + fn test_cursor_read_exact_past_eof() { let data = b"Short"; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 10]; // Requesting more bytes than available @@ -2895,24 +2900,15 @@ mod test_io { // Attempt to read 10 bytes from a 5-byte buffer let result = cursor.read_exact(&mut buffer); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); assert_eq!(cursor.position(), 5); // Position should move to EOF } #[test] - fn test_read_exact_empty_buffer() { + fn test_cursor_read_exact_empty_buffer() { let data = b"Non-empty"; let mut cursor = Cursor::new(data); - let mut buffer = [0u8; 0]; // Zero-length buffer + let mut buffer = [0u8; 0]; // Attempt to read zero bytes assert!(cursor.read_exact(&mut buffer).is_ok()); @@ -2920,7 +2916,7 @@ mod test_io { } #[test] - fn test_read_exact_from_empty_cursor() { + fn test_cursor_read_exact_from_empty_cursor() { let data: &[u8] = b""; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 5]; @@ -2928,21 +2924,12 @@ mod test_io { // Attempt to read from an empty cursor let result = cursor.read_exact(&mut buffer); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); assert_eq!(cursor.position(), 0); // Position remains at 0 } #[test] - fn test_read_exact_multiple_reads() { + fn test_cursor_read_exact_multiple_reads() { let data = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; let mut cursor = Cursor::new(data); @@ -2963,80 +2950,212 @@ mod test_io { // Third read: Attempt to read 10 bytes, but only 6 are available let result = cursor.read_exact(&mut buffer3); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); // read_exact makes no promises about the content of the buffer on error + // https://github.com/rust-lang/rust/blob/84ac80f1921afc243d71fd0caaa4f2838c294102/library/std/src/io/impls.rs#L287 // assert_eq!(&buffer3[..6], b"UVWXYZ"); assert_eq!(cursor.position(), 26); // Position should be at EOF } #[test] - fn test_cursor_read_exact_after_eof() { - let data = b"End"; - let mut cursor = Cursor::new(data); - let mut buffer = [0u8; 3]; + fn test_slice_read_exact_success() { + let data: &[u8] = b"The quick brown fox jumps over the lazy dog."; + let mut reader = data; + let mut buffer = [0u8; 19]; - // First read: read the entire buffer - assert!(cursor.read_exact(&mut buffer).is_ok()); - assert_eq!(&buffer, b"End"); - assert_eq!(cursor.position(), 3); + // Attempt to read exactly 19 bytes + assert!(reader.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"The quick brown fox"); + } - // Second read: attempt to read again, should fail + #[test] + fn test_slice_read_exact_less_than_available() { + let data: &[u8] = b"Hello, Stellar!"; + let mut reader = data; + let mut buffer = [0u8; 5]; + + // Attempt to read 5 bytes from the start + assert!(reader.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Hello"); + } + + #[test] + fn test_slice_read_exact_exact_eof() { + let data: &[u8] = b"Data"; + let mut reader = data; + let mut buffer = [0u8; 4]; + + // Attempt to read exactly 4 bytes, which is the entire slice + assert!(reader.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Data"); + + // Further attempt to read should fail with EOF let mut buffer_eof = [0u8; 1]; - let result = cursor.read_exact(&mut buffer_eof); + let result = reader.read_exact(&mut buffer_eof); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); - assert_eq!(cursor.position(), 3); // Position remains at EOF + assert_unexpected_eof!(result); } #[test] - fn test_slice_read_exact_success() { - let data = b"SliceReadTest"; - let mut slice = &data[..]; - let mut buffer = [0u8; 13]; // Exact length + fn test_slice_read_exact_past_eof() { + let data: &[u8] = b"Short"; + let mut reader = data; + let mut buffer = [0u8; 10]; // Requesting more bytes than available - // Using Read trait directly on slice - assert!(slice.read_exact(&mut buffer).is_ok()); - assert_eq!(&buffer, b"SliceReadTest"); + // Attempt to read 10 bytes from a 5-byte slice + let result = reader.read_exact(&mut buffer); + assert!(result.is_err()); + assert_unexpected_eof!(result); } #[test] - fn test_slice_read_exact_partial() { - let data = b"SlicePartial"; - let mut slice = &data[..]; - let mut buffer = [0u8; 20]; // Request more bytes than available + fn test_slice_read_exact_empty_buffer() { + let data: &[u8] = b"Non-empty"; + let mut reader = data; + let mut buffer = [0u8; 0]; // Zero-length buffer - // Using Read trait directly on slice - let result = slice.read_exact(&mut buffer); + // Attempt to read zero bytes + assert!(reader.read_exact(&mut buffer).is_ok()); + } + + #[test] + fn test_slice_read_exact_from_empty_slice() { + let data: &[u8] = b""; + let mut reader = data; + let mut buffer = [0u8; 5]; + + // Attempt to read from an empty slice + let result = reader.read_exact(&mut buffer); assert!(result.is_err()); + assert_unexpected_eof!(result); + } + + #[test] + fn test_slice_read_exact_multiple_reads() { + let data: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + let mut reader = data; + + let mut buffer1 = [0u8; 10]; + let mut buffer2 = [0u8; 10]; + let mut buffer3 = [0u8; 10]; // Only 6 bytes left + + // First read: 10 bytes + assert!(reader.read_exact(&mut buffer1).is_ok()); + assert_eq!(&buffer1, b"ABCDEFGHIJ"); + + // Second read: 10 bytes + assert!(reader.read_exact(&mut buffer2).is_ok()); + assert_eq!(&buffer2, b"KLMNOPQRST"); + + // Third read: Attempt to read 10 bytes, but only 6 are available + let result = reader.read_exact(&mut buffer3); + assert!(result.is_err()); + assert_unexpected_eof!(result); + } + + #[test] + fn test_cursor_write_success() { + let data = Vec::with_capacity(100); + let mut cursor = Cursor::new(data); + let write_data = b"Hello, Stellar!"; + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(&cursor.get_ref()[..], write_data); + assert_eq!(cursor.position(), write_data.len() as u64); + } + + #[test] + fn test_cursor_write_multiple_writes() { + let data = Vec::with_capacity(100); + let mut cursor = Cursor::new(data); + let write_data1: &[u8] = b"Hello, "; + let write_data2: &[u8] = b"Rust!"; + + // First write + assert!(cursor.write_all(write_data1).is_ok()); + assert_eq!(&cursor.get_ref()[..], write_data1); + assert_eq!(cursor.position(), write_data1.len() as u64); + + // Second write + assert!(cursor.write_all(write_data2).is_ok()); + let mut expected = Vec::new(); + expected.extend_from_slice(write_data1); + expected.extend_from_slice(write_data2); + assert_eq!(&cursor.get_ref()[..], expected.as_slice()); + assert_eq!(cursor.position(), expected.len() as u64); + } + + #[test] + fn test_cursor_write_empty() { + let data = Vec::with_capacity(100); + let mut cursor = Cursor::new(data); + let write_data = b""; + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(cursor.get_ref().len(), 0); + assert_eq!(cursor.position(), 0); + } + + #[test] + fn test_cursor_write_at_position() { + let mut data = vec![0u8; 10]; + { + let mut cursor = Cursor::new(&mut data[..]); + let write_data = b"Rust"; + + // Move cursor to position 6 + cursor.set_position(6); + assert_eq!(cursor.position(), 6); + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(cursor.position(), 10); + } + + let mut expected = vec![0u8; 10]; + expected[6..10].copy_from_slice(b"Rust"); + assert_eq!(&data[..], &expected[..]); + } + + #[test] + fn test_cursor_write_overflow() { + let mut data = vec![0u8; 5]; + let mut cursor = Cursor::new(&mut data[..]); + let write_data = b"Too long data"; + + let result = cursor.write_all(write_data); + assert!(result.is_err()); + #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); + assert_eq!(result.unwrap_err().kind(), io::ErrorKind::WriteZero); #[cfg(feature = "embedded_io")] assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof + result.unwrap_err().kind(), + embedded_io_extras::ErrorKind::WriteZero ); - // read_exact makes no promises about the content of the buffer on error + } + + #[test] + fn test_cursor_write_from_empty_cursor() { + let data = Vec::new(); + let mut cursor = Cursor::new(data); + let write_data = b"Initial Data"; + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(&cursor.get_ref()[..], write_data); + assert_eq!(cursor.position(), write_data.len() as u64); + } + + #[test] + fn test_cursor_write_partial() { + let mut data = [0u8; 5]; + let mut cursor = Cursor::new(&mut data[..]); + let write_data = b"Hello, Stellar!"; + + // Attempt to write data that exceeds the buffer size + // using `write` instead of `write_all` + let result = cursor.write(&write_data[..7]).unwrap(); + assert_eq!(result, 5); + assert_eq!(&cursor.get_ref()[..], b"Hello"); } } diff --git a/spec/output/generator_spec_rust_custom_str_impls/optional.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_str_impls/optional.x/MyXDR.rs index 867ecf91c..a88836d79 100644 --- a/spec/output/generator_spec_rust_custom_str_impls/optional.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_str_impls/optional.x/MyXDR.rs @@ -2834,11 +2834,25 @@ mod test_io { use super::*; + macro_rules! assert_unexpected_eof { + ($result:expr) => {{ + let err = $result.unwrap_err(); + #[cfg(feature = "std")] + { + assert_eq!(err.kind(), io::ErrorKind::UnexpectedEof); + } + #[cfg(feature = "embedded_io")] + { + assert_eq!(err, embedded_io_extras::ReadExactError::UnexpectedEof); + } + }}; + } + #[test] - fn test_read_exact_success() { + fn test_cursor_read_exact_success() { let data = b"The quick brown fox jumps over the lazy dog."; let mut cursor = Cursor::new(data); - let mut buffer = [0u8; 19]; // Exactly the length of "The quick brown fox" + let mut buffer = [0u8; 19]; // Attempt to read exactly 19 bytes assert!(cursor.read_exact(&mut buffer).is_ok()); @@ -2847,8 +2861,8 @@ mod test_io { } #[test] - fn test_read_exact_less_than_available() { - let data = b"Hello, Rust!"; + fn test_cursor_read_exact_less_than_available() { + let data = b"Hello, Stellar!"; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 5]; @@ -2859,7 +2873,7 @@ mod test_io { } #[test] - fn test_read_exact_exact_eof() { + fn test_cursor_read_exact_exact_eof() { let data = b"Data"; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 4]; @@ -2873,21 +2887,12 @@ mod test_io { let mut buffer_eof = [0u8; 1]; let result = cursor.read_exact(&mut buffer_eof); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); assert_eq!(cursor.position(), 4); // Position should remain at EOF } #[test] - fn test_read_exact_past_eof() { + fn test_cursor_read_exact_past_eof() { let data = b"Short"; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 10]; // Requesting more bytes than available @@ -2895,24 +2900,15 @@ mod test_io { // Attempt to read 10 bytes from a 5-byte buffer let result = cursor.read_exact(&mut buffer); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); assert_eq!(cursor.position(), 5); // Position should move to EOF } #[test] - fn test_read_exact_empty_buffer() { + fn test_cursor_read_exact_empty_buffer() { let data = b"Non-empty"; let mut cursor = Cursor::new(data); - let mut buffer = [0u8; 0]; // Zero-length buffer + let mut buffer = [0u8; 0]; // Attempt to read zero bytes assert!(cursor.read_exact(&mut buffer).is_ok()); @@ -2920,7 +2916,7 @@ mod test_io { } #[test] - fn test_read_exact_from_empty_cursor() { + fn test_cursor_read_exact_from_empty_cursor() { let data: &[u8] = b""; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 5]; @@ -2928,21 +2924,12 @@ mod test_io { // Attempt to read from an empty cursor let result = cursor.read_exact(&mut buffer); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); assert_eq!(cursor.position(), 0); // Position remains at 0 } #[test] - fn test_read_exact_multiple_reads() { + fn test_cursor_read_exact_multiple_reads() { let data = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; let mut cursor = Cursor::new(data); @@ -2963,80 +2950,212 @@ mod test_io { // Third read: Attempt to read 10 bytes, but only 6 are available let result = cursor.read_exact(&mut buffer3); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); // read_exact makes no promises about the content of the buffer on error + // https://github.com/rust-lang/rust/blob/84ac80f1921afc243d71fd0caaa4f2838c294102/library/std/src/io/impls.rs#L287 // assert_eq!(&buffer3[..6], b"UVWXYZ"); assert_eq!(cursor.position(), 26); // Position should be at EOF } #[test] - fn test_cursor_read_exact_after_eof() { - let data = b"End"; - let mut cursor = Cursor::new(data); - let mut buffer = [0u8; 3]; + fn test_slice_read_exact_success() { + let data: &[u8] = b"The quick brown fox jumps over the lazy dog."; + let mut reader = data; + let mut buffer = [0u8; 19]; - // First read: read the entire buffer - assert!(cursor.read_exact(&mut buffer).is_ok()); - assert_eq!(&buffer, b"End"); - assert_eq!(cursor.position(), 3); + // Attempt to read exactly 19 bytes + assert!(reader.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"The quick brown fox"); + } - // Second read: attempt to read again, should fail + #[test] + fn test_slice_read_exact_less_than_available() { + let data: &[u8] = b"Hello, Stellar!"; + let mut reader = data; + let mut buffer = [0u8; 5]; + + // Attempt to read 5 bytes from the start + assert!(reader.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Hello"); + } + + #[test] + fn test_slice_read_exact_exact_eof() { + let data: &[u8] = b"Data"; + let mut reader = data; + let mut buffer = [0u8; 4]; + + // Attempt to read exactly 4 bytes, which is the entire slice + assert!(reader.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Data"); + + // Further attempt to read should fail with EOF let mut buffer_eof = [0u8; 1]; - let result = cursor.read_exact(&mut buffer_eof); + let result = reader.read_exact(&mut buffer_eof); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); - assert_eq!(cursor.position(), 3); // Position remains at EOF + assert_unexpected_eof!(result); } #[test] - fn test_slice_read_exact_success() { - let data = b"SliceReadTest"; - let mut slice = &data[..]; - let mut buffer = [0u8; 13]; // Exact length + fn test_slice_read_exact_past_eof() { + let data: &[u8] = b"Short"; + let mut reader = data; + let mut buffer = [0u8; 10]; // Requesting more bytes than available - // Using Read trait directly on slice - assert!(slice.read_exact(&mut buffer).is_ok()); - assert_eq!(&buffer, b"SliceReadTest"); + // Attempt to read 10 bytes from a 5-byte slice + let result = reader.read_exact(&mut buffer); + assert!(result.is_err()); + assert_unexpected_eof!(result); } #[test] - fn test_slice_read_exact_partial() { - let data = b"SlicePartial"; - let mut slice = &data[..]; - let mut buffer = [0u8; 20]; // Request more bytes than available + fn test_slice_read_exact_empty_buffer() { + let data: &[u8] = b"Non-empty"; + let mut reader = data; + let mut buffer = [0u8; 0]; // Zero-length buffer - // Using Read trait directly on slice - let result = slice.read_exact(&mut buffer); + // Attempt to read zero bytes + assert!(reader.read_exact(&mut buffer).is_ok()); + } + + #[test] + fn test_slice_read_exact_from_empty_slice() { + let data: &[u8] = b""; + let mut reader = data; + let mut buffer = [0u8; 5]; + + // Attempt to read from an empty slice + let result = reader.read_exact(&mut buffer); assert!(result.is_err()); + assert_unexpected_eof!(result); + } + + #[test] + fn test_slice_read_exact_multiple_reads() { + let data: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + let mut reader = data; + + let mut buffer1 = [0u8; 10]; + let mut buffer2 = [0u8; 10]; + let mut buffer3 = [0u8; 10]; // Only 6 bytes left + + // First read: 10 bytes + assert!(reader.read_exact(&mut buffer1).is_ok()); + assert_eq!(&buffer1, b"ABCDEFGHIJ"); + + // Second read: 10 bytes + assert!(reader.read_exact(&mut buffer2).is_ok()); + assert_eq!(&buffer2, b"KLMNOPQRST"); + + // Third read: Attempt to read 10 bytes, but only 6 are available + let result = reader.read_exact(&mut buffer3); + assert!(result.is_err()); + assert_unexpected_eof!(result); + } + + #[test] + fn test_cursor_write_success() { + let data = Vec::with_capacity(100); + let mut cursor = Cursor::new(data); + let write_data = b"Hello, Stellar!"; + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(&cursor.get_ref()[..], write_data); + assert_eq!(cursor.position(), write_data.len() as u64); + } + + #[test] + fn test_cursor_write_multiple_writes() { + let data = Vec::with_capacity(100); + let mut cursor = Cursor::new(data); + let write_data1: &[u8] = b"Hello, "; + let write_data2: &[u8] = b"Rust!"; + + // First write + assert!(cursor.write_all(write_data1).is_ok()); + assert_eq!(&cursor.get_ref()[..], write_data1); + assert_eq!(cursor.position(), write_data1.len() as u64); + + // Second write + assert!(cursor.write_all(write_data2).is_ok()); + let mut expected = Vec::new(); + expected.extend_from_slice(write_data1); + expected.extend_from_slice(write_data2); + assert_eq!(&cursor.get_ref()[..], expected.as_slice()); + assert_eq!(cursor.position(), expected.len() as u64); + } + + #[test] + fn test_cursor_write_empty() { + let data = Vec::with_capacity(100); + let mut cursor = Cursor::new(data); + let write_data = b""; + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(cursor.get_ref().len(), 0); + assert_eq!(cursor.position(), 0); + } + + #[test] + fn test_cursor_write_at_position() { + let mut data = vec![0u8; 10]; + { + let mut cursor = Cursor::new(&mut data[..]); + let write_data = b"Rust"; + + // Move cursor to position 6 + cursor.set_position(6); + assert_eq!(cursor.position(), 6); + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(cursor.position(), 10); + } + + let mut expected = vec![0u8; 10]; + expected[6..10].copy_from_slice(b"Rust"); + assert_eq!(&data[..], &expected[..]); + } + + #[test] + fn test_cursor_write_overflow() { + let mut data = vec![0u8; 5]; + let mut cursor = Cursor::new(&mut data[..]); + let write_data = b"Too long data"; + + let result = cursor.write_all(write_data); + assert!(result.is_err()); + #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); + assert_eq!(result.unwrap_err().kind(), io::ErrorKind::WriteZero); #[cfg(feature = "embedded_io")] assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof + result.unwrap_err().kind(), + embedded_io_extras::ErrorKind::WriteZero ); - // read_exact makes no promises about the content of the buffer on error + } + + #[test] + fn test_cursor_write_from_empty_cursor() { + let data = Vec::new(); + let mut cursor = Cursor::new(data); + let write_data = b"Initial Data"; + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(&cursor.get_ref()[..], write_data); + assert_eq!(cursor.position(), write_data.len() as u64); + } + + #[test] + fn test_cursor_write_partial() { + let mut data = [0u8; 5]; + let mut cursor = Cursor::new(&mut data[..]); + let write_data = b"Hello, Stellar!"; + + // Attempt to write data that exceeds the buffer size + // using `write` instead of `write_all` + let result = cursor.write(&write_data[..7]).unwrap(); + assert_eq!(result, 5); + assert_eq!(&cursor.get_ref()[..], b"Hello"); } } diff --git a/spec/output/generator_spec_rust_custom_str_impls/struct.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_str_impls/struct.x/MyXDR.rs index 7dd6a2193..ceb64478c 100644 --- a/spec/output/generator_spec_rust_custom_str_impls/struct.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_str_impls/struct.x/MyXDR.rs @@ -2834,11 +2834,25 @@ mod test_io { use super::*; + macro_rules! assert_unexpected_eof { + ($result:expr) => {{ + let err = $result.unwrap_err(); + #[cfg(feature = "std")] + { + assert_eq!(err.kind(), io::ErrorKind::UnexpectedEof); + } + #[cfg(feature = "embedded_io")] + { + assert_eq!(err, embedded_io_extras::ReadExactError::UnexpectedEof); + } + }}; + } + #[test] - fn test_read_exact_success() { + fn test_cursor_read_exact_success() { let data = b"The quick brown fox jumps over the lazy dog."; let mut cursor = Cursor::new(data); - let mut buffer = [0u8; 19]; // Exactly the length of "The quick brown fox" + let mut buffer = [0u8; 19]; // Attempt to read exactly 19 bytes assert!(cursor.read_exact(&mut buffer).is_ok()); @@ -2847,8 +2861,8 @@ mod test_io { } #[test] - fn test_read_exact_less_than_available() { - let data = b"Hello, Rust!"; + fn test_cursor_read_exact_less_than_available() { + let data = b"Hello, Stellar!"; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 5]; @@ -2859,7 +2873,7 @@ mod test_io { } #[test] - fn test_read_exact_exact_eof() { + fn test_cursor_read_exact_exact_eof() { let data = b"Data"; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 4]; @@ -2873,21 +2887,12 @@ mod test_io { let mut buffer_eof = [0u8; 1]; let result = cursor.read_exact(&mut buffer_eof); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); assert_eq!(cursor.position(), 4); // Position should remain at EOF } #[test] - fn test_read_exact_past_eof() { + fn test_cursor_read_exact_past_eof() { let data = b"Short"; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 10]; // Requesting more bytes than available @@ -2895,24 +2900,15 @@ mod test_io { // Attempt to read 10 bytes from a 5-byte buffer let result = cursor.read_exact(&mut buffer); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); assert_eq!(cursor.position(), 5); // Position should move to EOF } #[test] - fn test_read_exact_empty_buffer() { + fn test_cursor_read_exact_empty_buffer() { let data = b"Non-empty"; let mut cursor = Cursor::new(data); - let mut buffer = [0u8; 0]; // Zero-length buffer + let mut buffer = [0u8; 0]; // Attempt to read zero bytes assert!(cursor.read_exact(&mut buffer).is_ok()); @@ -2920,7 +2916,7 @@ mod test_io { } #[test] - fn test_read_exact_from_empty_cursor() { + fn test_cursor_read_exact_from_empty_cursor() { let data: &[u8] = b""; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 5]; @@ -2928,21 +2924,12 @@ mod test_io { // Attempt to read from an empty cursor let result = cursor.read_exact(&mut buffer); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); assert_eq!(cursor.position(), 0); // Position remains at 0 } #[test] - fn test_read_exact_multiple_reads() { + fn test_cursor_read_exact_multiple_reads() { let data = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; let mut cursor = Cursor::new(data); @@ -2963,80 +2950,212 @@ mod test_io { // Third read: Attempt to read 10 bytes, but only 6 are available let result = cursor.read_exact(&mut buffer3); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); // read_exact makes no promises about the content of the buffer on error + // https://github.com/rust-lang/rust/blob/84ac80f1921afc243d71fd0caaa4f2838c294102/library/std/src/io/impls.rs#L287 // assert_eq!(&buffer3[..6], b"UVWXYZ"); assert_eq!(cursor.position(), 26); // Position should be at EOF } #[test] - fn test_cursor_read_exact_after_eof() { - let data = b"End"; - let mut cursor = Cursor::new(data); - let mut buffer = [0u8; 3]; + fn test_slice_read_exact_success() { + let data: &[u8] = b"The quick brown fox jumps over the lazy dog."; + let mut reader = data; + let mut buffer = [0u8; 19]; - // First read: read the entire buffer - assert!(cursor.read_exact(&mut buffer).is_ok()); - assert_eq!(&buffer, b"End"); - assert_eq!(cursor.position(), 3); + // Attempt to read exactly 19 bytes + assert!(reader.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"The quick brown fox"); + } - // Second read: attempt to read again, should fail + #[test] + fn test_slice_read_exact_less_than_available() { + let data: &[u8] = b"Hello, Stellar!"; + let mut reader = data; + let mut buffer = [0u8; 5]; + + // Attempt to read 5 bytes from the start + assert!(reader.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Hello"); + } + + #[test] + fn test_slice_read_exact_exact_eof() { + let data: &[u8] = b"Data"; + let mut reader = data; + let mut buffer = [0u8; 4]; + + // Attempt to read exactly 4 bytes, which is the entire slice + assert!(reader.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Data"); + + // Further attempt to read should fail with EOF let mut buffer_eof = [0u8; 1]; - let result = cursor.read_exact(&mut buffer_eof); + let result = reader.read_exact(&mut buffer_eof); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); - assert_eq!(cursor.position(), 3); // Position remains at EOF + assert_unexpected_eof!(result); } #[test] - fn test_slice_read_exact_success() { - let data = b"SliceReadTest"; - let mut slice = &data[..]; - let mut buffer = [0u8; 13]; // Exact length + fn test_slice_read_exact_past_eof() { + let data: &[u8] = b"Short"; + let mut reader = data; + let mut buffer = [0u8; 10]; // Requesting more bytes than available - // Using Read trait directly on slice - assert!(slice.read_exact(&mut buffer).is_ok()); - assert_eq!(&buffer, b"SliceReadTest"); + // Attempt to read 10 bytes from a 5-byte slice + let result = reader.read_exact(&mut buffer); + assert!(result.is_err()); + assert_unexpected_eof!(result); } #[test] - fn test_slice_read_exact_partial() { - let data = b"SlicePartial"; - let mut slice = &data[..]; - let mut buffer = [0u8; 20]; // Request more bytes than available + fn test_slice_read_exact_empty_buffer() { + let data: &[u8] = b"Non-empty"; + let mut reader = data; + let mut buffer = [0u8; 0]; // Zero-length buffer - // Using Read trait directly on slice - let result = slice.read_exact(&mut buffer); + // Attempt to read zero bytes + assert!(reader.read_exact(&mut buffer).is_ok()); + } + + #[test] + fn test_slice_read_exact_from_empty_slice() { + let data: &[u8] = b""; + let mut reader = data; + let mut buffer = [0u8; 5]; + + // Attempt to read from an empty slice + let result = reader.read_exact(&mut buffer); assert!(result.is_err()); + assert_unexpected_eof!(result); + } + + #[test] + fn test_slice_read_exact_multiple_reads() { + let data: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + let mut reader = data; + + let mut buffer1 = [0u8; 10]; + let mut buffer2 = [0u8; 10]; + let mut buffer3 = [0u8; 10]; // Only 6 bytes left + + // First read: 10 bytes + assert!(reader.read_exact(&mut buffer1).is_ok()); + assert_eq!(&buffer1, b"ABCDEFGHIJ"); + + // Second read: 10 bytes + assert!(reader.read_exact(&mut buffer2).is_ok()); + assert_eq!(&buffer2, b"KLMNOPQRST"); + + // Third read: Attempt to read 10 bytes, but only 6 are available + let result = reader.read_exact(&mut buffer3); + assert!(result.is_err()); + assert_unexpected_eof!(result); + } + + #[test] + fn test_cursor_write_success() { + let data = Vec::with_capacity(100); + let mut cursor = Cursor::new(data); + let write_data = b"Hello, Stellar!"; + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(&cursor.get_ref()[..], write_data); + assert_eq!(cursor.position(), write_data.len() as u64); + } + + #[test] + fn test_cursor_write_multiple_writes() { + let data = Vec::with_capacity(100); + let mut cursor = Cursor::new(data); + let write_data1: &[u8] = b"Hello, "; + let write_data2: &[u8] = b"Rust!"; + + // First write + assert!(cursor.write_all(write_data1).is_ok()); + assert_eq!(&cursor.get_ref()[..], write_data1); + assert_eq!(cursor.position(), write_data1.len() as u64); + + // Second write + assert!(cursor.write_all(write_data2).is_ok()); + let mut expected = Vec::new(); + expected.extend_from_slice(write_data1); + expected.extend_from_slice(write_data2); + assert_eq!(&cursor.get_ref()[..], expected.as_slice()); + assert_eq!(cursor.position(), expected.len() as u64); + } + + #[test] + fn test_cursor_write_empty() { + let data = Vec::with_capacity(100); + let mut cursor = Cursor::new(data); + let write_data = b""; + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(cursor.get_ref().len(), 0); + assert_eq!(cursor.position(), 0); + } + + #[test] + fn test_cursor_write_at_position() { + let mut data = vec![0u8; 10]; + { + let mut cursor = Cursor::new(&mut data[..]); + let write_data = b"Rust"; + + // Move cursor to position 6 + cursor.set_position(6); + assert_eq!(cursor.position(), 6); + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(cursor.position(), 10); + } + + let mut expected = vec![0u8; 10]; + expected[6..10].copy_from_slice(b"Rust"); + assert_eq!(&data[..], &expected[..]); + } + + #[test] + fn test_cursor_write_overflow() { + let mut data = vec![0u8; 5]; + let mut cursor = Cursor::new(&mut data[..]); + let write_data = b"Too long data"; + + let result = cursor.write_all(write_data); + assert!(result.is_err()); + #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); + assert_eq!(result.unwrap_err().kind(), io::ErrorKind::WriteZero); #[cfg(feature = "embedded_io")] assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof + result.unwrap_err().kind(), + embedded_io_extras::ErrorKind::WriteZero ); - // read_exact makes no promises about the content of the buffer on error + } + + #[test] + fn test_cursor_write_from_empty_cursor() { + let data = Vec::new(); + let mut cursor = Cursor::new(data); + let write_data = b"Initial Data"; + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(&cursor.get_ref()[..], write_data); + assert_eq!(cursor.position(), write_data.len() as u64); + } + + #[test] + fn test_cursor_write_partial() { + let mut data = [0u8; 5]; + let mut cursor = Cursor::new(&mut data[..]); + let write_data = b"Hello, Stellar!"; + + // Attempt to write data that exceeds the buffer size + // using `write` instead of `write_all` + let result = cursor.write(&write_data[..7]).unwrap(); + assert_eq!(result, 5); + assert_eq!(&cursor.get_ref()[..], b"Hello"); } } diff --git a/spec/output/generator_spec_rust_custom_str_impls/test.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_str_impls/test.x/MyXDR.rs index 682e0e665..14786d898 100644 --- a/spec/output/generator_spec_rust_custom_str_impls/test.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_str_impls/test.x/MyXDR.rs @@ -2834,11 +2834,25 @@ mod test_io { use super::*; + macro_rules! assert_unexpected_eof { + ($result:expr) => {{ + let err = $result.unwrap_err(); + #[cfg(feature = "std")] + { + assert_eq!(err.kind(), io::ErrorKind::UnexpectedEof); + } + #[cfg(feature = "embedded_io")] + { + assert_eq!(err, embedded_io_extras::ReadExactError::UnexpectedEof); + } + }}; + } + #[test] - fn test_read_exact_success() { + fn test_cursor_read_exact_success() { let data = b"The quick brown fox jumps over the lazy dog."; let mut cursor = Cursor::new(data); - let mut buffer = [0u8; 19]; // Exactly the length of "The quick brown fox" + let mut buffer = [0u8; 19]; // Attempt to read exactly 19 bytes assert!(cursor.read_exact(&mut buffer).is_ok()); @@ -2847,8 +2861,8 @@ mod test_io { } #[test] - fn test_read_exact_less_than_available() { - let data = b"Hello, Rust!"; + fn test_cursor_read_exact_less_than_available() { + let data = b"Hello, Stellar!"; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 5]; @@ -2859,7 +2873,7 @@ mod test_io { } #[test] - fn test_read_exact_exact_eof() { + fn test_cursor_read_exact_exact_eof() { let data = b"Data"; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 4]; @@ -2873,21 +2887,12 @@ mod test_io { let mut buffer_eof = [0u8; 1]; let result = cursor.read_exact(&mut buffer_eof); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); assert_eq!(cursor.position(), 4); // Position should remain at EOF } #[test] - fn test_read_exact_past_eof() { + fn test_cursor_read_exact_past_eof() { let data = b"Short"; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 10]; // Requesting more bytes than available @@ -2895,24 +2900,15 @@ mod test_io { // Attempt to read 10 bytes from a 5-byte buffer let result = cursor.read_exact(&mut buffer); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); assert_eq!(cursor.position(), 5); // Position should move to EOF } #[test] - fn test_read_exact_empty_buffer() { + fn test_cursor_read_exact_empty_buffer() { let data = b"Non-empty"; let mut cursor = Cursor::new(data); - let mut buffer = [0u8; 0]; // Zero-length buffer + let mut buffer = [0u8; 0]; // Attempt to read zero bytes assert!(cursor.read_exact(&mut buffer).is_ok()); @@ -2920,7 +2916,7 @@ mod test_io { } #[test] - fn test_read_exact_from_empty_cursor() { + fn test_cursor_read_exact_from_empty_cursor() { let data: &[u8] = b""; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 5]; @@ -2928,21 +2924,12 @@ mod test_io { // Attempt to read from an empty cursor let result = cursor.read_exact(&mut buffer); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); assert_eq!(cursor.position(), 0); // Position remains at 0 } #[test] - fn test_read_exact_multiple_reads() { + fn test_cursor_read_exact_multiple_reads() { let data = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; let mut cursor = Cursor::new(data); @@ -2963,80 +2950,212 @@ mod test_io { // Third read: Attempt to read 10 bytes, but only 6 are available let result = cursor.read_exact(&mut buffer3); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); // read_exact makes no promises about the content of the buffer on error + // https://github.com/rust-lang/rust/blob/84ac80f1921afc243d71fd0caaa4f2838c294102/library/std/src/io/impls.rs#L287 // assert_eq!(&buffer3[..6], b"UVWXYZ"); assert_eq!(cursor.position(), 26); // Position should be at EOF } #[test] - fn test_cursor_read_exact_after_eof() { - let data = b"End"; - let mut cursor = Cursor::new(data); - let mut buffer = [0u8; 3]; + fn test_slice_read_exact_success() { + let data: &[u8] = b"The quick brown fox jumps over the lazy dog."; + let mut reader = data; + let mut buffer = [0u8; 19]; - // First read: read the entire buffer - assert!(cursor.read_exact(&mut buffer).is_ok()); - assert_eq!(&buffer, b"End"); - assert_eq!(cursor.position(), 3); + // Attempt to read exactly 19 bytes + assert!(reader.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"The quick brown fox"); + } + + #[test] + fn test_slice_read_exact_less_than_available() { + let data: &[u8] = b"Hello, Stellar!"; + let mut reader = data; + let mut buffer = [0u8; 5]; + + // Attempt to read 5 bytes from the start + assert!(reader.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Hello"); + } + + #[test] + fn test_slice_read_exact_exact_eof() { + let data: &[u8] = b"Data"; + let mut reader = data; + let mut buffer = [0u8; 4]; + + // Attempt to read exactly 4 bytes, which is the entire slice + assert!(reader.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Data"); - // Second read: attempt to read again, should fail + // Further attempt to read should fail with EOF let mut buffer_eof = [0u8; 1]; - let result = cursor.read_exact(&mut buffer_eof); + let result = reader.read_exact(&mut buffer_eof); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); - assert_eq!(cursor.position(), 3); // Position remains at EOF + assert_unexpected_eof!(result); } #[test] - fn test_slice_read_exact_success() { - let data = b"SliceReadTest"; - let mut slice = &data[..]; - let mut buffer = [0u8; 13]; // Exact length + fn test_slice_read_exact_past_eof() { + let data: &[u8] = b"Short"; + let mut reader = data; + let mut buffer = [0u8; 10]; // Requesting more bytes than available - // Using Read trait directly on slice - assert!(slice.read_exact(&mut buffer).is_ok()); - assert_eq!(&buffer, b"SliceReadTest"); + // Attempt to read 10 bytes from a 5-byte slice + let result = reader.read_exact(&mut buffer); + assert!(result.is_err()); + assert_unexpected_eof!(result); } #[test] - fn test_slice_read_exact_partial() { - let data = b"SlicePartial"; - let mut slice = &data[..]; - let mut buffer = [0u8; 20]; // Request more bytes than available + fn test_slice_read_exact_empty_buffer() { + let data: &[u8] = b"Non-empty"; + let mut reader = data; + let mut buffer = [0u8; 0]; // Zero-length buffer + + // Attempt to read zero bytes + assert!(reader.read_exact(&mut buffer).is_ok()); + } + + #[test] + fn test_slice_read_exact_from_empty_slice() { + let data: &[u8] = b""; + let mut reader = data; + let mut buffer = [0u8; 5]; + + // Attempt to read from an empty slice + let result = reader.read_exact(&mut buffer); + assert!(result.is_err()); + assert_unexpected_eof!(result); + } + + #[test] + fn test_slice_read_exact_multiple_reads() { + let data: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + let mut reader = data; + + let mut buffer1 = [0u8; 10]; + let mut buffer2 = [0u8; 10]; + let mut buffer3 = [0u8; 10]; // Only 6 bytes left + + // First read: 10 bytes + assert!(reader.read_exact(&mut buffer1).is_ok()); + assert_eq!(&buffer1, b"ABCDEFGHIJ"); + + // Second read: 10 bytes + assert!(reader.read_exact(&mut buffer2).is_ok()); + assert_eq!(&buffer2, b"KLMNOPQRST"); + + // Third read: Attempt to read 10 bytes, but only 6 are available + let result = reader.read_exact(&mut buffer3); + assert!(result.is_err()); + assert_unexpected_eof!(result); + } + + #[test] + fn test_cursor_write_success() { + let data = Vec::with_capacity(100); + let mut cursor = Cursor::new(data); + let write_data = b"Hello, Stellar!"; + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(&cursor.get_ref()[..], write_data); + assert_eq!(cursor.position(), write_data.len() as u64); + } - // Using Read trait directly on slice - let result = slice.read_exact(&mut buffer); + #[test] + fn test_cursor_write_multiple_writes() { + let data = Vec::with_capacity(100); + let mut cursor = Cursor::new(data); + let write_data1: &[u8] = b"Hello, "; + let write_data2: &[u8] = b"Rust!"; + + // First write + assert!(cursor.write_all(write_data1).is_ok()); + assert_eq!(&cursor.get_ref()[..], write_data1); + assert_eq!(cursor.position(), write_data1.len() as u64); + + // Second write + assert!(cursor.write_all(write_data2).is_ok()); + let mut expected = Vec::new(); + expected.extend_from_slice(write_data1); + expected.extend_from_slice(write_data2); + assert_eq!(&cursor.get_ref()[..], expected.as_slice()); + assert_eq!(cursor.position(), expected.len() as u64); + } + + #[test] + fn test_cursor_write_empty() { + let data = Vec::with_capacity(100); + let mut cursor = Cursor::new(data); + let write_data = b""; + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(cursor.get_ref().len(), 0); + assert_eq!(cursor.position(), 0); + } + + #[test] + fn test_cursor_write_at_position() { + let mut data = vec![0u8; 10]; + { + let mut cursor = Cursor::new(&mut data[..]); + let write_data = b"Rust"; + + // Move cursor to position 6 + cursor.set_position(6); + assert_eq!(cursor.position(), 6); + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(cursor.position(), 10); + } + + let mut expected = vec![0u8; 10]; + expected[6..10].copy_from_slice(b"Rust"); + assert_eq!(&data[..], &expected[..]); + } + + #[test] + fn test_cursor_write_overflow() { + let mut data = vec![0u8; 5]; + let mut cursor = Cursor::new(&mut data[..]); + let write_data = b"Too long data"; + + let result = cursor.write_all(write_data); assert!(result.is_err()); + #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); + assert_eq!(result.unwrap_err().kind(), io::ErrorKind::WriteZero); #[cfg(feature = "embedded_io")] assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof + result.unwrap_err().kind(), + embedded_io_extras::ErrorKind::WriteZero ); - // read_exact makes no promises about the content of the buffer on error + } + + #[test] + fn test_cursor_write_from_empty_cursor() { + let data = Vec::new(); + let mut cursor = Cursor::new(data); + let write_data = b"Initial Data"; + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(&cursor.get_ref()[..], write_data); + assert_eq!(cursor.position(), write_data.len() as u64); + } + + #[test] + fn test_cursor_write_partial() { + let mut data = [0u8; 5]; + let mut cursor = Cursor::new(&mut data[..]); + let write_data = b"Hello, Stellar!"; + + // Attempt to write data that exceeds the buffer size + // using `write` instead of `write_all` + let result = cursor.write(&write_data[..7]).unwrap(); + assert_eq!(result, 5); + assert_eq!(&cursor.get_ref()[..], b"Hello"); } } diff --git a/spec/output/generator_spec_rust_custom_str_impls/union.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_str_impls/union.x/MyXDR.rs index 7f170b97d..b388e3a75 100644 --- a/spec/output/generator_spec_rust_custom_str_impls/union.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_str_impls/union.x/MyXDR.rs @@ -2834,11 +2834,25 @@ mod test_io { use super::*; + macro_rules! assert_unexpected_eof { + ($result:expr) => {{ + let err = $result.unwrap_err(); + #[cfg(feature = "std")] + { + assert_eq!(err.kind(), io::ErrorKind::UnexpectedEof); + } + #[cfg(feature = "embedded_io")] + { + assert_eq!(err, embedded_io_extras::ReadExactError::UnexpectedEof); + } + }}; + } + #[test] - fn test_read_exact_success() { + fn test_cursor_read_exact_success() { let data = b"The quick brown fox jumps over the lazy dog."; let mut cursor = Cursor::new(data); - let mut buffer = [0u8; 19]; // Exactly the length of "The quick brown fox" + let mut buffer = [0u8; 19]; // Attempt to read exactly 19 bytes assert!(cursor.read_exact(&mut buffer).is_ok()); @@ -2847,8 +2861,8 @@ mod test_io { } #[test] - fn test_read_exact_less_than_available() { - let data = b"Hello, Rust!"; + fn test_cursor_read_exact_less_than_available() { + let data = b"Hello, Stellar!"; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 5]; @@ -2859,7 +2873,7 @@ mod test_io { } #[test] - fn test_read_exact_exact_eof() { + fn test_cursor_read_exact_exact_eof() { let data = b"Data"; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 4]; @@ -2873,21 +2887,12 @@ mod test_io { let mut buffer_eof = [0u8; 1]; let result = cursor.read_exact(&mut buffer_eof); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); assert_eq!(cursor.position(), 4); // Position should remain at EOF } #[test] - fn test_read_exact_past_eof() { + fn test_cursor_read_exact_past_eof() { let data = b"Short"; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 10]; // Requesting more bytes than available @@ -2895,24 +2900,15 @@ mod test_io { // Attempt to read 10 bytes from a 5-byte buffer let result = cursor.read_exact(&mut buffer); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); assert_eq!(cursor.position(), 5); // Position should move to EOF } #[test] - fn test_read_exact_empty_buffer() { + fn test_cursor_read_exact_empty_buffer() { let data = b"Non-empty"; let mut cursor = Cursor::new(data); - let mut buffer = [0u8; 0]; // Zero-length buffer + let mut buffer = [0u8; 0]; // Attempt to read zero bytes assert!(cursor.read_exact(&mut buffer).is_ok()); @@ -2920,7 +2916,7 @@ mod test_io { } #[test] - fn test_read_exact_from_empty_cursor() { + fn test_cursor_read_exact_from_empty_cursor() { let data: &[u8] = b""; let mut cursor = Cursor::new(data); let mut buffer = [0u8; 5]; @@ -2928,21 +2924,12 @@ mod test_io { // Attempt to read from an empty cursor let result = cursor.read_exact(&mut buffer); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); assert_eq!(cursor.position(), 0); // Position remains at 0 } #[test] - fn test_read_exact_multiple_reads() { + fn test_cursor_read_exact_multiple_reads() { let data = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; let mut cursor = Cursor::new(data); @@ -2963,80 +2950,212 @@ mod test_io { // Third read: Attempt to read 10 bytes, but only 6 are available let result = cursor.read_exact(&mut buffer3); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); + assert_unexpected_eof!(result); // read_exact makes no promises about the content of the buffer on error + // https://github.com/rust-lang/rust/blob/84ac80f1921afc243d71fd0caaa4f2838c294102/library/std/src/io/impls.rs#L287 // assert_eq!(&buffer3[..6], b"UVWXYZ"); assert_eq!(cursor.position(), 26); // Position should be at EOF } #[test] - fn test_cursor_read_exact_after_eof() { - let data = b"End"; - let mut cursor = Cursor::new(data); - let mut buffer = [0u8; 3]; + fn test_slice_read_exact_success() { + let data: &[u8] = b"The quick brown fox jumps over the lazy dog."; + let mut reader = data; + let mut buffer = [0u8; 19]; - // First read: read the entire buffer - assert!(cursor.read_exact(&mut buffer).is_ok()); - assert_eq!(&buffer, b"End"); - assert_eq!(cursor.position(), 3); + // Attempt to read exactly 19 bytes + assert!(reader.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"The quick brown fox"); + } - // Second read: attempt to read again, should fail + #[test] + fn test_slice_read_exact_less_than_available() { + let data: &[u8] = b"Hello, Stellar!"; + let mut reader = data; + let mut buffer = [0u8; 5]; + + // Attempt to read 5 bytes from the start + assert!(reader.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Hello"); + } + + #[test] + fn test_slice_read_exact_exact_eof() { + let data: &[u8] = b"Data"; + let mut reader = data; + let mut buffer = [0u8; 4]; + + // Attempt to read exactly 4 bytes, which is the entire slice + assert!(reader.read_exact(&mut buffer).is_ok()); + assert_eq!(&buffer, b"Data"); + + // Further attempt to read should fail with EOF let mut buffer_eof = [0u8; 1]; - let result = cursor.read_exact(&mut buffer_eof); + let result = reader.read_exact(&mut buffer_eof); assert!(result.is_err()); - #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); - #[cfg(feature = "embedded_io")] - assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof - ); - assert_eq!(cursor.position(), 3); // Position remains at EOF + assert_unexpected_eof!(result); } #[test] - fn test_slice_read_exact_success() { - let data = b"SliceReadTest"; - let mut slice = &data[..]; - let mut buffer = [0u8; 13]; // Exact length + fn test_slice_read_exact_past_eof() { + let data: &[u8] = b"Short"; + let mut reader = data; + let mut buffer = [0u8; 10]; // Requesting more bytes than available - // Using Read trait directly on slice - assert!(slice.read_exact(&mut buffer).is_ok()); - assert_eq!(&buffer, b"SliceReadTest"); + // Attempt to read 10 bytes from a 5-byte slice + let result = reader.read_exact(&mut buffer); + assert!(result.is_err()); + assert_unexpected_eof!(result); } #[test] - fn test_slice_read_exact_partial() { - let data = b"SlicePartial"; - let mut slice = &data[..]; - let mut buffer = [0u8; 20]; // Request more bytes than available + fn test_slice_read_exact_empty_buffer() { + let data: &[u8] = b"Non-empty"; + let mut reader = data; + let mut buffer = [0u8; 0]; // Zero-length buffer - // Using Read trait directly on slice - let result = slice.read_exact(&mut buffer); + // Attempt to read zero bytes + assert!(reader.read_exact(&mut buffer).is_ok()); + } + + #[test] + fn test_slice_read_exact_from_empty_slice() { + let data: &[u8] = b""; + let mut reader = data; + let mut buffer = [0u8; 5]; + + // Attempt to read from an empty slice + let result = reader.read_exact(&mut buffer); assert!(result.is_err()); + assert_unexpected_eof!(result); + } + + #[test] + fn test_slice_read_exact_multiple_reads() { + let data: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + let mut reader = data; + + let mut buffer1 = [0u8; 10]; + let mut buffer2 = [0u8; 10]; + let mut buffer3 = [0u8; 10]; // Only 6 bytes left + + // First read: 10 bytes + assert!(reader.read_exact(&mut buffer1).is_ok()); + assert_eq!(&buffer1, b"ABCDEFGHIJ"); + + // Second read: 10 bytes + assert!(reader.read_exact(&mut buffer2).is_ok()); + assert_eq!(&buffer2, b"KLMNOPQRST"); + + // Third read: Attempt to read 10 bytes, but only 6 are available + let result = reader.read_exact(&mut buffer3); + assert!(result.is_err()); + assert_unexpected_eof!(result); + } + + #[test] + fn test_cursor_write_success() { + let data = Vec::with_capacity(100); + let mut cursor = Cursor::new(data); + let write_data = b"Hello, Stellar!"; + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(&cursor.get_ref()[..], write_data); + assert_eq!(cursor.position(), write_data.len() as u64); + } + + #[test] + fn test_cursor_write_multiple_writes() { + let data = Vec::with_capacity(100); + let mut cursor = Cursor::new(data); + let write_data1: &[u8] = b"Hello, "; + let write_data2: &[u8] = b"Rust!"; + + // First write + assert!(cursor.write_all(write_data1).is_ok()); + assert_eq!(&cursor.get_ref()[..], write_data1); + assert_eq!(cursor.position(), write_data1.len() as u64); + + // Second write + assert!(cursor.write_all(write_data2).is_ok()); + let mut expected = Vec::new(); + expected.extend_from_slice(write_data1); + expected.extend_from_slice(write_data2); + assert_eq!(&cursor.get_ref()[..], expected.as_slice()); + assert_eq!(cursor.position(), expected.len() as u64); + } + + #[test] + fn test_cursor_write_empty() { + let data = Vec::with_capacity(100); + let mut cursor = Cursor::new(data); + let write_data = b""; + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(cursor.get_ref().len(), 0); + assert_eq!(cursor.position(), 0); + } + + #[test] + fn test_cursor_write_at_position() { + let mut data = vec![0u8; 10]; + { + let mut cursor = Cursor::new(&mut data[..]); + let write_data = b"Rust"; + + // Move cursor to position 6 + cursor.set_position(6); + assert_eq!(cursor.position(), 6); + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(cursor.position(), 10); + } + + let mut expected = vec![0u8; 10]; + expected[6..10].copy_from_slice(b"Rust"); + assert_eq!(&data[..], &expected[..]); + } + + #[test] + fn test_cursor_write_overflow() { + let mut data = vec![0u8; 5]; + let mut cursor = Cursor::new(&mut data[..]); + let write_data = b"Too long data"; + + let result = cursor.write_all(write_data); + assert!(result.is_err()); + #[cfg(feature = "std")] - assert_eq!( - result.unwrap_err().kind(), - std::io::ErrorKind::UnexpectedEof - ); + assert_eq!(result.unwrap_err().kind(), io::ErrorKind::WriteZero); #[cfg(feature = "embedded_io")] assert_eq!( - result.unwrap_err(), - embedded_io_extras::ReadExactError::UnexpectedEof + result.unwrap_err().kind(), + embedded_io_extras::ErrorKind::WriteZero ); - // read_exact makes no promises about the content of the buffer on error + } + + #[test] + fn test_cursor_write_from_empty_cursor() { + let data = Vec::new(); + let mut cursor = Cursor::new(data); + let write_data = b"Initial Data"; + + assert!(cursor.write_all(write_data).is_ok()); + assert_eq!(&cursor.get_ref()[..], write_data); + assert_eq!(cursor.position(), write_data.len() as u64); + } + + #[test] + fn test_cursor_write_partial() { + let mut data = [0u8; 5]; + let mut cursor = Cursor::new(&mut data[..]); + let write_data = b"Hello, Stellar!"; + + // Attempt to write data that exceeds the buffer size + // using `write` instead of `write_all` + let result = cursor.write(&write_data[..7]).unwrap(); + assert_eq!(result, 5); + assert_eq!(&cursor.get_ref()[..], b"Hello"); } } From e57dfa9199f476acde88ddb096699c829ad86c28 Mon Sep 17 00:00:00 2001 From: Jun Luo <4catcode@gmail.com> Date: Sat, 21 Sep 2024 15:35:41 +0800 Subject: [PATCH 9/9] make clippy happy --- lib/xdrgen/generators/rust/src/types.rs | 6 +++--- spec/output/generator_spec_rust/block_comments.x/MyXDR.rs | 6 +++--- spec/output/generator_spec_rust/const.x/MyXDR.rs | 6 +++--- spec/output/generator_spec_rust/enum.x/MyXDR.rs | 6 +++--- spec/output/generator_spec_rust/nesting.x/MyXDR.rs | 6 +++--- spec/output/generator_spec_rust/optional.x/MyXDR.rs | 6 +++--- spec/output/generator_spec_rust/struct.x/MyXDR.rs | 6 +++--- spec/output/generator_spec_rust/test.x/MyXDR.rs | 6 +++--- spec/output/generator_spec_rust/union.x/MyXDR.rs | 6 +++--- .../block_comments.x/MyXDR.rs | 6 +++--- .../const.x/MyXDR.rs | 6 +++--- .../enum.x/MyXDR.rs | 6 +++--- .../nesting.x/MyXDR.rs | 6 +++--- .../optional.x/MyXDR.rs | 6 +++--- .../struct.x/MyXDR.rs | 6 +++--- .../test.x/MyXDR.rs | 6 +++--- .../union.x/MyXDR.rs | 6 +++--- .../block_comments.x/MyXDR.rs | 6 +++--- .../generator_spec_rust_custom_str_impls/const.x/MyXDR.rs | 6 +++--- .../generator_spec_rust_custom_str_impls/enum.x/MyXDR.rs | 6 +++--- .../generator_spec_rust_custom_str_impls/nesting.x/MyXDR.rs | 6 +++--- .../optional.x/MyXDR.rs | 6 +++--- .../generator_spec_rust_custom_str_impls/struct.x/MyXDR.rs | 6 +++--- .../generator_spec_rust_custom_str_impls/test.x/MyXDR.rs | 6 +++--- .../generator_spec_rust_custom_str_impls/union.x/MyXDR.rs | 6 +++--- 25 files changed, 75 insertions(+), 75 deletions(-) diff --git a/lib/xdrgen/generators/rust/src/types.rs b/lib/xdrgen/generators/rust/src/types.rs index b247a1492..ccf139f32 100644 --- a/lib/xdrgen/generators/rust/src/types.rs +++ b/lib/xdrgen/generators/rust/src/types.rs @@ -3088,7 +3088,7 @@ mod test_io { #[test] fn test_cursor_write_at_position() { - let mut data = vec![0u8; 10]; + let mut data = [0u8; 10]; { let mut cursor = Cursor::new(&mut data[..]); let write_data = b"Rust"; @@ -3101,14 +3101,14 @@ mod test_io { assert_eq!(cursor.position(), 10); } - let mut expected = vec![0u8; 10]; + let mut expected = [0u8; 10]; expected[6..10].copy_from_slice(b"Rust"); assert_eq!(&data[..], &expected[..]); } #[test] fn test_cursor_write_overflow() { - let mut data = vec![0u8; 5]; + let mut data = [0u8; 5]; let mut cursor = Cursor::new(&mut data[..]); let write_data = b"Too long data"; diff --git a/spec/output/generator_spec_rust/block_comments.x/MyXDR.rs b/spec/output/generator_spec_rust/block_comments.x/MyXDR.rs index a2906d184..de07f4fcb 100644 --- a/spec/output/generator_spec_rust/block_comments.x/MyXDR.rs +++ b/spec/output/generator_spec_rust/block_comments.x/MyXDR.rs @@ -3098,7 +3098,7 @@ mod test_io { #[test] fn test_cursor_write_at_position() { - let mut data = vec![0u8; 10]; + let mut data = [0u8; 10]; { let mut cursor = Cursor::new(&mut data[..]); let write_data = b"Rust"; @@ -3111,14 +3111,14 @@ mod test_io { assert_eq!(cursor.position(), 10); } - let mut expected = vec![0u8; 10]; + let mut expected = [0u8; 10]; expected[6..10].copy_from_slice(b"Rust"); assert_eq!(&data[..], &expected[..]); } #[test] fn test_cursor_write_overflow() { - let mut data = vec![0u8; 5]; + let mut data = [0u8; 5]; let mut cursor = Cursor::new(&mut data[..]); let write_data = b"Too long data"; diff --git a/spec/output/generator_spec_rust/const.x/MyXDR.rs b/spec/output/generator_spec_rust/const.x/MyXDR.rs index 40946ac79..60fb45f34 100644 --- a/spec/output/generator_spec_rust/const.x/MyXDR.rs +++ b/spec/output/generator_spec_rust/const.x/MyXDR.rs @@ -3098,7 +3098,7 @@ mod test_io { #[test] fn test_cursor_write_at_position() { - let mut data = vec![0u8; 10]; + let mut data = [0u8; 10]; { let mut cursor = Cursor::new(&mut data[..]); let write_data = b"Rust"; @@ -3111,14 +3111,14 @@ mod test_io { assert_eq!(cursor.position(), 10); } - let mut expected = vec![0u8; 10]; + let mut expected = [0u8; 10]; expected[6..10].copy_from_slice(b"Rust"); assert_eq!(&data[..], &expected[..]); } #[test] fn test_cursor_write_overflow() { - let mut data = vec![0u8; 5]; + let mut data = [0u8; 5]; let mut cursor = Cursor::new(&mut data[..]); let write_data = b"Too long data"; diff --git a/spec/output/generator_spec_rust/enum.x/MyXDR.rs b/spec/output/generator_spec_rust/enum.x/MyXDR.rs index cfa08956e..ae497de05 100644 --- a/spec/output/generator_spec_rust/enum.x/MyXDR.rs +++ b/spec/output/generator_spec_rust/enum.x/MyXDR.rs @@ -3098,7 +3098,7 @@ mod test_io { #[test] fn test_cursor_write_at_position() { - let mut data = vec![0u8; 10]; + let mut data = [0u8; 10]; { let mut cursor = Cursor::new(&mut data[..]); let write_data = b"Rust"; @@ -3111,14 +3111,14 @@ mod test_io { assert_eq!(cursor.position(), 10); } - let mut expected = vec![0u8; 10]; + let mut expected = [0u8; 10]; expected[6..10].copy_from_slice(b"Rust"); assert_eq!(&data[..], &expected[..]); } #[test] fn test_cursor_write_overflow() { - let mut data = vec![0u8; 5]; + let mut data = [0u8; 5]; let mut cursor = Cursor::new(&mut data[..]); let write_data = b"Too long data"; diff --git a/spec/output/generator_spec_rust/nesting.x/MyXDR.rs b/spec/output/generator_spec_rust/nesting.x/MyXDR.rs index c44e89dfd..0074d1a05 100644 --- a/spec/output/generator_spec_rust/nesting.x/MyXDR.rs +++ b/spec/output/generator_spec_rust/nesting.x/MyXDR.rs @@ -3098,7 +3098,7 @@ mod test_io { #[test] fn test_cursor_write_at_position() { - let mut data = vec![0u8; 10]; + let mut data = [0u8; 10]; { let mut cursor = Cursor::new(&mut data[..]); let write_data = b"Rust"; @@ -3111,14 +3111,14 @@ mod test_io { assert_eq!(cursor.position(), 10); } - let mut expected = vec![0u8; 10]; + let mut expected = [0u8; 10]; expected[6..10].copy_from_slice(b"Rust"); assert_eq!(&data[..], &expected[..]); } #[test] fn test_cursor_write_overflow() { - let mut data = vec![0u8; 5]; + let mut data = [0u8; 5]; let mut cursor = Cursor::new(&mut data[..]); let write_data = b"Too long data"; diff --git a/spec/output/generator_spec_rust/optional.x/MyXDR.rs b/spec/output/generator_spec_rust/optional.x/MyXDR.rs index e606898a2..83faca17e 100644 --- a/spec/output/generator_spec_rust/optional.x/MyXDR.rs +++ b/spec/output/generator_spec_rust/optional.x/MyXDR.rs @@ -3098,7 +3098,7 @@ mod test_io { #[test] fn test_cursor_write_at_position() { - let mut data = vec![0u8; 10]; + let mut data = [0u8; 10]; { let mut cursor = Cursor::new(&mut data[..]); let write_data = b"Rust"; @@ -3111,14 +3111,14 @@ mod test_io { assert_eq!(cursor.position(), 10); } - let mut expected = vec![0u8; 10]; + let mut expected = [0u8; 10]; expected[6..10].copy_from_slice(b"Rust"); assert_eq!(&data[..], &expected[..]); } #[test] fn test_cursor_write_overflow() { - let mut data = vec![0u8; 5]; + let mut data = [0u8; 5]; let mut cursor = Cursor::new(&mut data[..]); let write_data = b"Too long data"; diff --git a/spec/output/generator_spec_rust/struct.x/MyXDR.rs b/spec/output/generator_spec_rust/struct.x/MyXDR.rs index d75ee36aa..39123298f 100644 --- a/spec/output/generator_spec_rust/struct.x/MyXDR.rs +++ b/spec/output/generator_spec_rust/struct.x/MyXDR.rs @@ -3098,7 +3098,7 @@ mod test_io { #[test] fn test_cursor_write_at_position() { - let mut data = vec![0u8; 10]; + let mut data = [0u8; 10]; { let mut cursor = Cursor::new(&mut data[..]); let write_data = b"Rust"; @@ -3111,14 +3111,14 @@ mod test_io { assert_eq!(cursor.position(), 10); } - let mut expected = vec![0u8; 10]; + let mut expected = [0u8; 10]; expected[6..10].copy_from_slice(b"Rust"); assert_eq!(&data[..], &expected[..]); } #[test] fn test_cursor_write_overflow() { - let mut data = vec![0u8; 5]; + let mut data = [0u8; 5]; let mut cursor = Cursor::new(&mut data[..]); let write_data = b"Too long data"; diff --git a/spec/output/generator_spec_rust/test.x/MyXDR.rs b/spec/output/generator_spec_rust/test.x/MyXDR.rs index e02327632..f8397c2b4 100644 --- a/spec/output/generator_spec_rust/test.x/MyXDR.rs +++ b/spec/output/generator_spec_rust/test.x/MyXDR.rs @@ -3098,7 +3098,7 @@ mod test_io { #[test] fn test_cursor_write_at_position() { - let mut data = vec![0u8; 10]; + let mut data = [0u8; 10]; { let mut cursor = Cursor::new(&mut data[..]); let write_data = b"Rust"; @@ -3111,14 +3111,14 @@ mod test_io { assert_eq!(cursor.position(), 10); } - let mut expected = vec![0u8; 10]; + let mut expected = [0u8; 10]; expected[6..10].copy_from_slice(b"Rust"); assert_eq!(&data[..], &expected[..]); } #[test] fn test_cursor_write_overflow() { - let mut data = vec![0u8; 5]; + let mut data = [0u8; 5]; let mut cursor = Cursor::new(&mut data[..]); let write_data = b"Too long data"; diff --git a/spec/output/generator_spec_rust/union.x/MyXDR.rs b/spec/output/generator_spec_rust/union.x/MyXDR.rs index 8d775325d..68c0c2f96 100644 --- a/spec/output/generator_spec_rust/union.x/MyXDR.rs +++ b/spec/output/generator_spec_rust/union.x/MyXDR.rs @@ -3098,7 +3098,7 @@ mod test_io { #[test] fn test_cursor_write_at_position() { - let mut data = vec![0u8; 10]; + let mut data = [0u8; 10]; { let mut cursor = Cursor::new(&mut data[..]); let write_data = b"Rust"; @@ -3111,14 +3111,14 @@ mod test_io { assert_eq!(cursor.position(), 10); } - let mut expected = vec![0u8; 10]; + let mut expected = [0u8; 10]; expected[6..10].copy_from_slice(b"Rust"); assert_eq!(&data[..], &expected[..]); } #[test] fn test_cursor_write_overflow() { - let mut data = vec![0u8; 5]; + let mut data = [0u8; 5]; let mut cursor = Cursor::new(&mut data[..]); let write_data = b"Too long data"; diff --git a/spec/output/generator_spec_rust_custom_jsonschema_impls/block_comments.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_jsonschema_impls/block_comments.x/MyXDR.rs index a2906d184..de07f4fcb 100644 --- a/spec/output/generator_spec_rust_custom_jsonschema_impls/block_comments.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_jsonschema_impls/block_comments.x/MyXDR.rs @@ -3098,7 +3098,7 @@ mod test_io { #[test] fn test_cursor_write_at_position() { - let mut data = vec![0u8; 10]; + let mut data = [0u8; 10]; { let mut cursor = Cursor::new(&mut data[..]); let write_data = b"Rust"; @@ -3111,14 +3111,14 @@ mod test_io { assert_eq!(cursor.position(), 10); } - let mut expected = vec![0u8; 10]; + let mut expected = [0u8; 10]; expected[6..10].copy_from_slice(b"Rust"); assert_eq!(&data[..], &expected[..]); } #[test] fn test_cursor_write_overflow() { - let mut data = vec![0u8; 5]; + let mut data = [0u8; 5]; let mut cursor = Cursor::new(&mut data[..]); let write_data = b"Too long data"; diff --git a/spec/output/generator_spec_rust_custom_jsonschema_impls/const.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_jsonschema_impls/const.x/MyXDR.rs index 40946ac79..60fb45f34 100644 --- a/spec/output/generator_spec_rust_custom_jsonschema_impls/const.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_jsonschema_impls/const.x/MyXDR.rs @@ -3098,7 +3098,7 @@ mod test_io { #[test] fn test_cursor_write_at_position() { - let mut data = vec![0u8; 10]; + let mut data = [0u8; 10]; { let mut cursor = Cursor::new(&mut data[..]); let write_data = b"Rust"; @@ -3111,14 +3111,14 @@ mod test_io { assert_eq!(cursor.position(), 10); } - let mut expected = vec![0u8; 10]; + let mut expected = [0u8; 10]; expected[6..10].copy_from_slice(b"Rust"); assert_eq!(&data[..], &expected[..]); } #[test] fn test_cursor_write_overflow() { - let mut data = vec![0u8; 5]; + let mut data = [0u8; 5]; let mut cursor = Cursor::new(&mut data[..]); let write_data = b"Too long data"; diff --git a/spec/output/generator_spec_rust_custom_jsonschema_impls/enum.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_jsonschema_impls/enum.x/MyXDR.rs index dcec6cdc8..1d02858cd 100644 --- a/spec/output/generator_spec_rust_custom_jsonschema_impls/enum.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_jsonschema_impls/enum.x/MyXDR.rs @@ -3098,7 +3098,7 @@ mod test_io { #[test] fn test_cursor_write_at_position() { - let mut data = vec![0u8; 10]; + let mut data = [0u8; 10]; { let mut cursor = Cursor::new(&mut data[..]); let write_data = b"Rust"; @@ -3111,14 +3111,14 @@ mod test_io { assert_eq!(cursor.position(), 10); } - let mut expected = vec![0u8; 10]; + let mut expected = [0u8; 10]; expected[6..10].copy_from_slice(b"Rust"); assert_eq!(&data[..], &expected[..]); } #[test] fn test_cursor_write_overflow() { - let mut data = vec![0u8; 5]; + let mut data = [0u8; 5]; let mut cursor = Cursor::new(&mut data[..]); let write_data = b"Too long data"; diff --git a/spec/output/generator_spec_rust_custom_jsonschema_impls/nesting.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_jsonschema_impls/nesting.x/MyXDR.rs index 16a0e8e39..b0c8be9ca 100644 --- a/spec/output/generator_spec_rust_custom_jsonschema_impls/nesting.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_jsonschema_impls/nesting.x/MyXDR.rs @@ -3098,7 +3098,7 @@ mod test_io { #[test] fn test_cursor_write_at_position() { - let mut data = vec![0u8; 10]; + let mut data = [0u8; 10]; { let mut cursor = Cursor::new(&mut data[..]); let write_data = b"Rust"; @@ -3111,14 +3111,14 @@ mod test_io { assert_eq!(cursor.position(), 10); } - let mut expected = vec![0u8; 10]; + let mut expected = [0u8; 10]; expected[6..10].copy_from_slice(b"Rust"); assert_eq!(&data[..], &expected[..]); } #[test] fn test_cursor_write_overflow() { - let mut data = vec![0u8; 5]; + let mut data = [0u8; 5]; let mut cursor = Cursor::new(&mut data[..]); let write_data = b"Too long data"; diff --git a/spec/output/generator_spec_rust_custom_jsonschema_impls/optional.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_jsonschema_impls/optional.x/MyXDR.rs index 0272543c0..d20779ca3 100644 --- a/spec/output/generator_spec_rust_custom_jsonschema_impls/optional.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_jsonschema_impls/optional.x/MyXDR.rs @@ -3098,7 +3098,7 @@ mod test_io { #[test] fn test_cursor_write_at_position() { - let mut data = vec![0u8; 10]; + let mut data = [0u8; 10]; { let mut cursor = Cursor::new(&mut data[..]); let write_data = b"Rust"; @@ -3111,14 +3111,14 @@ mod test_io { assert_eq!(cursor.position(), 10); } - let mut expected = vec![0u8; 10]; + let mut expected = [0u8; 10]; expected[6..10].copy_from_slice(b"Rust"); assert_eq!(&data[..], &expected[..]); } #[test] fn test_cursor_write_overflow() { - let mut data = vec![0u8; 5]; + let mut data = [0u8; 5]; let mut cursor = Cursor::new(&mut data[..]); let write_data = b"Too long data"; diff --git a/spec/output/generator_spec_rust_custom_jsonschema_impls/struct.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_jsonschema_impls/struct.x/MyXDR.rs index b7fc89ddf..0624e0af2 100644 --- a/spec/output/generator_spec_rust_custom_jsonschema_impls/struct.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_jsonschema_impls/struct.x/MyXDR.rs @@ -3098,7 +3098,7 @@ mod test_io { #[test] fn test_cursor_write_at_position() { - let mut data = vec![0u8; 10]; + let mut data = [0u8; 10]; { let mut cursor = Cursor::new(&mut data[..]); let write_data = b"Rust"; @@ -3111,14 +3111,14 @@ mod test_io { assert_eq!(cursor.position(), 10); } - let mut expected = vec![0u8; 10]; + let mut expected = [0u8; 10]; expected[6..10].copy_from_slice(b"Rust"); assert_eq!(&data[..], &expected[..]); } #[test] fn test_cursor_write_overflow() { - let mut data = vec![0u8; 5]; + let mut data = [0u8; 5]; let mut cursor = Cursor::new(&mut data[..]); let write_data = b"Too long data"; diff --git a/spec/output/generator_spec_rust_custom_jsonschema_impls/test.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_jsonschema_impls/test.x/MyXDR.rs index 87899ae0d..a5810baad 100644 --- a/spec/output/generator_spec_rust_custom_jsonschema_impls/test.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_jsonschema_impls/test.x/MyXDR.rs @@ -3098,7 +3098,7 @@ mod test_io { #[test] fn test_cursor_write_at_position() { - let mut data = vec![0u8; 10]; + let mut data = [0u8; 10]; { let mut cursor = Cursor::new(&mut data[..]); let write_data = b"Rust"; @@ -3111,14 +3111,14 @@ mod test_io { assert_eq!(cursor.position(), 10); } - let mut expected = vec![0u8; 10]; + let mut expected = [0u8; 10]; expected[6..10].copy_from_slice(b"Rust"); assert_eq!(&data[..], &expected[..]); } #[test] fn test_cursor_write_overflow() { - let mut data = vec![0u8; 5]; + let mut data = [0u8; 5]; let mut cursor = Cursor::new(&mut data[..]); let write_data = b"Too long data"; diff --git a/spec/output/generator_spec_rust_custom_jsonschema_impls/union.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_jsonschema_impls/union.x/MyXDR.rs index 63979c68e..aa6620724 100644 --- a/spec/output/generator_spec_rust_custom_jsonschema_impls/union.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_jsonschema_impls/union.x/MyXDR.rs @@ -3098,7 +3098,7 @@ mod test_io { #[test] fn test_cursor_write_at_position() { - let mut data = vec![0u8; 10]; + let mut data = [0u8; 10]; { let mut cursor = Cursor::new(&mut data[..]); let write_data = b"Rust"; @@ -3111,14 +3111,14 @@ mod test_io { assert_eq!(cursor.position(), 10); } - let mut expected = vec![0u8; 10]; + let mut expected = [0u8; 10]; expected[6..10].copy_from_slice(b"Rust"); assert_eq!(&data[..], &expected[..]); } #[test] fn test_cursor_write_overflow() { - let mut data = vec![0u8; 5]; + let mut data = [0u8; 5]; let mut cursor = Cursor::new(&mut data[..]); let write_data = b"Too long data"; diff --git a/spec/output/generator_spec_rust_custom_str_impls/block_comments.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_str_impls/block_comments.x/MyXDR.rs index a2906d184..de07f4fcb 100644 --- a/spec/output/generator_spec_rust_custom_str_impls/block_comments.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_str_impls/block_comments.x/MyXDR.rs @@ -3098,7 +3098,7 @@ mod test_io { #[test] fn test_cursor_write_at_position() { - let mut data = vec![0u8; 10]; + let mut data = [0u8; 10]; { let mut cursor = Cursor::new(&mut data[..]); let write_data = b"Rust"; @@ -3111,14 +3111,14 @@ mod test_io { assert_eq!(cursor.position(), 10); } - let mut expected = vec![0u8; 10]; + let mut expected = [0u8; 10]; expected[6..10].copy_from_slice(b"Rust"); assert_eq!(&data[..], &expected[..]); } #[test] fn test_cursor_write_overflow() { - let mut data = vec![0u8; 5]; + let mut data = [0u8; 5]; let mut cursor = Cursor::new(&mut data[..]); let write_data = b"Too long data"; diff --git a/spec/output/generator_spec_rust_custom_str_impls/const.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_str_impls/const.x/MyXDR.rs index 40946ac79..60fb45f34 100644 --- a/spec/output/generator_spec_rust_custom_str_impls/const.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_str_impls/const.x/MyXDR.rs @@ -3098,7 +3098,7 @@ mod test_io { #[test] fn test_cursor_write_at_position() { - let mut data = vec![0u8; 10]; + let mut data = [0u8; 10]; { let mut cursor = Cursor::new(&mut data[..]); let write_data = b"Rust"; @@ -3111,14 +3111,14 @@ mod test_io { assert_eq!(cursor.position(), 10); } - let mut expected = vec![0u8; 10]; + let mut expected = [0u8; 10]; expected[6..10].copy_from_slice(b"Rust"); assert_eq!(&data[..], &expected[..]); } #[test] fn test_cursor_write_overflow() { - let mut data = vec![0u8; 5]; + let mut data = [0u8; 5]; let mut cursor = Cursor::new(&mut data[..]); let write_data = b"Too long data"; diff --git a/spec/output/generator_spec_rust_custom_str_impls/enum.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_str_impls/enum.x/MyXDR.rs index 50ab8abfd..d071894b1 100644 --- a/spec/output/generator_spec_rust_custom_str_impls/enum.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_str_impls/enum.x/MyXDR.rs @@ -3098,7 +3098,7 @@ mod test_io { #[test] fn test_cursor_write_at_position() { - let mut data = vec![0u8; 10]; + let mut data = [0u8; 10]; { let mut cursor = Cursor::new(&mut data[..]); let write_data = b"Rust"; @@ -3111,14 +3111,14 @@ mod test_io { assert_eq!(cursor.position(), 10); } - let mut expected = vec![0u8; 10]; + let mut expected = [0u8; 10]; expected[6..10].copy_from_slice(b"Rust"); assert_eq!(&data[..], &expected[..]); } #[test] fn test_cursor_write_overflow() { - let mut data = vec![0u8; 5]; + let mut data = [0u8; 5]; let mut cursor = Cursor::new(&mut data[..]); let write_data = b"Too long data"; diff --git a/spec/output/generator_spec_rust_custom_str_impls/nesting.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_str_impls/nesting.x/MyXDR.rs index e2420824c..5b6ec062b 100644 --- a/spec/output/generator_spec_rust_custom_str_impls/nesting.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_str_impls/nesting.x/MyXDR.rs @@ -3098,7 +3098,7 @@ mod test_io { #[test] fn test_cursor_write_at_position() { - let mut data = vec![0u8; 10]; + let mut data = [0u8; 10]; { let mut cursor = Cursor::new(&mut data[..]); let write_data = b"Rust"; @@ -3111,14 +3111,14 @@ mod test_io { assert_eq!(cursor.position(), 10); } - let mut expected = vec![0u8; 10]; + let mut expected = [0u8; 10]; expected[6..10].copy_from_slice(b"Rust"); assert_eq!(&data[..], &expected[..]); } #[test] fn test_cursor_write_overflow() { - let mut data = vec![0u8; 5]; + let mut data = [0u8; 5]; let mut cursor = Cursor::new(&mut data[..]); let write_data = b"Too long data"; diff --git a/spec/output/generator_spec_rust_custom_str_impls/optional.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_str_impls/optional.x/MyXDR.rs index a88836d79..8e40dde5d 100644 --- a/spec/output/generator_spec_rust_custom_str_impls/optional.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_str_impls/optional.x/MyXDR.rs @@ -3098,7 +3098,7 @@ mod test_io { #[test] fn test_cursor_write_at_position() { - let mut data = vec![0u8; 10]; + let mut data = [0u8; 10]; { let mut cursor = Cursor::new(&mut data[..]); let write_data = b"Rust"; @@ -3111,14 +3111,14 @@ mod test_io { assert_eq!(cursor.position(), 10); } - let mut expected = vec![0u8; 10]; + let mut expected = [0u8; 10]; expected[6..10].copy_from_slice(b"Rust"); assert_eq!(&data[..], &expected[..]); } #[test] fn test_cursor_write_overflow() { - let mut data = vec![0u8; 5]; + let mut data = [0u8; 5]; let mut cursor = Cursor::new(&mut data[..]); let write_data = b"Too long data"; diff --git a/spec/output/generator_spec_rust_custom_str_impls/struct.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_str_impls/struct.x/MyXDR.rs index ceb64478c..cd458840a 100644 --- a/spec/output/generator_spec_rust_custom_str_impls/struct.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_str_impls/struct.x/MyXDR.rs @@ -3098,7 +3098,7 @@ mod test_io { #[test] fn test_cursor_write_at_position() { - let mut data = vec![0u8; 10]; + let mut data = [0u8; 10]; { let mut cursor = Cursor::new(&mut data[..]); let write_data = b"Rust"; @@ -3111,14 +3111,14 @@ mod test_io { assert_eq!(cursor.position(), 10); } - let mut expected = vec![0u8; 10]; + let mut expected = [0u8; 10]; expected[6..10].copy_from_slice(b"Rust"); assert_eq!(&data[..], &expected[..]); } #[test] fn test_cursor_write_overflow() { - let mut data = vec![0u8; 5]; + let mut data = [0u8; 5]; let mut cursor = Cursor::new(&mut data[..]); let write_data = b"Too long data"; diff --git a/spec/output/generator_spec_rust_custom_str_impls/test.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_str_impls/test.x/MyXDR.rs index 14786d898..052796e22 100644 --- a/spec/output/generator_spec_rust_custom_str_impls/test.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_str_impls/test.x/MyXDR.rs @@ -3098,7 +3098,7 @@ mod test_io { #[test] fn test_cursor_write_at_position() { - let mut data = vec![0u8; 10]; + let mut data = [0u8; 10]; { let mut cursor = Cursor::new(&mut data[..]); let write_data = b"Rust"; @@ -3111,14 +3111,14 @@ mod test_io { assert_eq!(cursor.position(), 10); } - let mut expected = vec![0u8; 10]; + let mut expected = [0u8; 10]; expected[6..10].copy_from_slice(b"Rust"); assert_eq!(&data[..], &expected[..]); } #[test] fn test_cursor_write_overflow() { - let mut data = vec![0u8; 5]; + let mut data = [0u8; 5]; let mut cursor = Cursor::new(&mut data[..]); let write_data = b"Too long data"; diff --git a/spec/output/generator_spec_rust_custom_str_impls/union.x/MyXDR.rs b/spec/output/generator_spec_rust_custom_str_impls/union.x/MyXDR.rs index b388e3a75..7af495ec5 100644 --- a/spec/output/generator_spec_rust_custom_str_impls/union.x/MyXDR.rs +++ b/spec/output/generator_spec_rust_custom_str_impls/union.x/MyXDR.rs @@ -3098,7 +3098,7 @@ mod test_io { #[test] fn test_cursor_write_at_position() { - let mut data = vec![0u8; 10]; + let mut data = [0u8; 10]; { let mut cursor = Cursor::new(&mut data[..]); let write_data = b"Rust"; @@ -3111,14 +3111,14 @@ mod test_io { assert_eq!(cursor.position(), 10); } - let mut expected = vec![0u8; 10]; + let mut expected = [0u8; 10]; expected[6..10].copy_from_slice(b"Rust"); assert_eq!(&data[..], &expected[..]); } #[test] fn test_cursor_write_overflow() { - let mut data = vec![0u8; 5]; + let mut data = [0u8; 5]; let mut cursor = Cursor::new(&mut data[..]); let write_data = b"Too long data";