Skip to content

Commit

Permalink
add option to parse borrowed data
Browse files Browse the repository at this point in the history
  • Loading branch information
ARogovskyy authored and ancwrd1 committed Mar 20, 2024
1 parent 77444d2 commit b965f84
Show file tree
Hide file tree
Showing 2 changed files with 116 additions and 12 deletions.
101 changes: 95 additions & 6 deletions ipp/src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use crate::{
reader::IppReader,
request::IppRequestResponse,
value::IppValue,
FromPrimitive as _,
FromPrimitive as _, IppHeader,
};

/// Parse error enum
Expand Down Expand Up @@ -149,7 +149,7 @@ pub struct AsyncIppParser<R> {
#[cfg(feature = "async")]
impl<R> AsyncIppParser<R>
where
R: 'static + AsyncRead + Send + Sync + Unpin,
R: AsyncRead + Send + Sync + Unpin,
{
/// Create IPP parser from AsyncIppReader
pub fn new<T>(reader: T) -> AsyncIppParser<R>
Expand All @@ -170,8 +170,7 @@ where
self.state.parse_value(tag, name, value)
}

/// Parse IPP stream
pub async fn parse(mut self) -> Result<IppRequestResponse, IppParseError> {
async fn parse_header_attributes(&mut self) -> Result<IppHeader, IppParseError> {
let header = self.reader.read_header().await?;
trace!("IPP header: {:?}", header);

Expand All @@ -189,6 +188,22 @@ where
}
}

Ok(header)
}

/// Parse IPP stream without reading beyond the end of the attributes. The payload stays untouched.
pub async fn parse_parts(mut self) -> Result<(IppHeader, IppAttributes, AsyncIppReader<R>), IppParseError> {
let header = self.parse_header_attributes().await?;
Ok((header, self.state.attributes, self.reader))
}

/// Parse IPP stream
pub async fn parse(mut self) -> Result<IppRequestResponse, IppParseError>
where
R: 'static,
{
let header = self.parse_header_attributes().await?;

Ok(IppRequestResponse {
header,
attributes: self.state.attributes,
Expand Down Expand Up @@ -226,8 +241,7 @@ where
self.state.parse_value(tag, name, value)
}

/// Parse IPP stream
pub fn parse(mut self) -> Result<IppRequestResponse, IppParseError> {
fn parse_header_attributes(&mut self) -> Result<IppHeader, IppParseError> {
let header = self.reader.read_header()?;
trace!("IPP header: {:?}", header);

Expand All @@ -245,6 +259,22 @@ where
}
}

Ok(header)
}

/// Parse IPP stream without reading beyond the end of the attributes. The payload stays untouched.
pub fn parse_parts(mut self) -> Result<(IppHeader, IppAttributes, IppReader<R>), IppParseError> {
let header = self.parse_header_attributes()?;
Ok((header, self.state.attributes, self.reader))
}

/// Parse IPP stream
pub fn parse(mut self) -> Result<IppRequestResponse, IppParseError>
where
R: 'static,
{
let header = self.parse_header_attributes()?;

Ok(IppRequestResponse {
header,
attributes: self.state.attributes,
Expand All @@ -255,6 +285,8 @@ where

#[cfg(test)]
mod tests {
use crate::prelude::IppVersion;

use super::*;

#[cfg(feature = "async")]
Expand Down Expand Up @@ -361,6 +393,7 @@ mod tests {
assert!(result.is_ok());

let res = result.ok().unwrap();
assert_eq!(res.header.version, IppVersion::v1_1());
let attrs = res
.attributes
.groups_of(DelimiterTag::PrinterAttributes)
Expand All @@ -375,6 +408,35 @@ mod tests {
assert_eq!(cursor.into_inner(), b"foo");
}

#[cfg(feature = "async")]
#[tokio::test]
async fn test_async_parse_parts() {
let data = vec![
1, 1, 0, 0, 0, 0, 0, 0, 4, 0x21, 0x00, 0x04, b't', b'e', b's', b't', 0x00, 0x04, 0x12, 0x34, 0x56, 0x78, 3,
b'f', b'o', b'o',
];

let result = AsyncIppParser::new(AsyncIppReader::new(futures_util::io::Cursor::new(data)))
.parse_parts()
.await;
assert!(result.is_ok());

let (header, attributes, reader) = result.ok().unwrap();
assert_eq!(header.version, IppVersion::v1_1());
let attrs = attributes
.groups_of(DelimiterTag::PrinterAttributes)
.next()
.unwrap()
.attributes();
let attr = attrs.get("test").unwrap();
assert_eq!(attr.value().as_integer(), Some(&0x1234_5678));

let mut payload = reader.into_payload();
let mut cursor = io::Cursor::new(Vec::new());
io::copy(&mut payload, &mut cursor).unwrap();
assert_eq!(cursor.into_inner(), b"foo");
}

#[test]
fn test_parse_no_attributes() {
let data = &[1, 1, 0, 0, 0, 0, 0, 0, 3];
Expand Down Expand Up @@ -464,6 +526,7 @@ mod tests {
assert!(result.is_ok());

let mut res = result.ok().unwrap();
assert_eq!(res.header.version, IppVersion::v1_1());
let attrs = res
.attributes
.groups_of(DelimiterTag::PrinterAttributes)
Expand All @@ -478,6 +541,32 @@ mod tests {
assert_eq!(cursor.into_inner(), b"foo");
}

#[test]
fn test_parse_parts() {
let data = vec![
1, 1, 0, 0, 0, 0, 0, 0, 4, 0x21, 0x00, 0x04, b't', b'e', b's', b't', 0x00, 0x04, 0x12, 0x34, 0x56, 0x78, 3,
b'f', b'o', b'o',
];

let result = IppParser::new(IppReader::new(io::Cursor::new(data))).parse_parts();
assert!(result.is_ok());

let (header, attributes, reader) = result.ok().unwrap();
assert_eq!(header.version, IppVersion::v1_1());
let attrs = attributes
.groups_of(DelimiterTag::PrinterAttributes)
.next()
.unwrap()
.attributes();
let attr = attrs.get("test").unwrap();
assert_eq!(attr.value().as_integer(), Some(&0x1234_5678));

let mut payload = reader.into_payload();
let mut cursor = io::Cursor::new(Vec::new());
io::copy(&mut payload, &mut cursor).unwrap();
assert_eq!(cursor.into_inner(), b"foo");
}

#[test]
fn test_parse_groups() {
let data = vec![
Expand Down
27 changes: 21 additions & 6 deletions ipp/src/reader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ pub struct AsyncIppReader<R> {
#[cfg(feature = "async")]
impl<R> AsyncIppReader<R>
where
R: 'static + AsyncRead + Send + Sync + Unpin,
R: AsyncRead + Send + Sync + Unpin,
{
/// Create IppReader from AsyncRead instance
pub fn new(inner: R) -> Self {
Expand Down Expand Up @@ -83,15 +83,18 @@ where
}

/// Convert the remaining inner stream into IppPayload
pub fn into_payload(self) -> IppPayload {
pub fn into_payload(self) -> IppPayload
where
R: 'static,
{
IppPayload::new_async(self.inner)
}
}

#[cfg(feature = "async")]
impl<R> From<R> for AsyncIppReader<R>
where
R: 'static + AsyncRead + Send + Sync + Unpin,
R: AsyncRead + Send + Sync + Unpin,
{
fn from(r: R) -> Self {
AsyncIppReader::new(r)
Expand All @@ -105,7 +108,7 @@ pub struct IppReader<R> {

impl<R> IppReader<R>
where
R: 'static + Read + Send + Sync,
R: Read + Send + Sync,
{
/// Create IppReader from Read instance
pub fn new(inner: R) -> Self {
Expand Down Expand Up @@ -167,14 +170,17 @@ where
}

/// Convert the remaining inner stream into IppPayload
pub fn into_payload(self) -> IppPayload {
pub fn into_payload(self) -> IppPayload
where
R: 'static,
{
IppPayload::new(self.inner)
}
}

impl<R> From<R> for IppReader<R>
where
R: 'static + Read + Send + Sync,
R: Read + Send + Sync,
{
fn from(r: R) -> Self {
IppReader::new(r)
Expand Down Expand Up @@ -202,6 +208,15 @@ mod tests {
assert_eq!(value.as_ref(), b"test");
}

#[test]
fn test_read_borrowed_value() {
let data = vec![0x00, 0x04, b't', b'e', b's', b't'];
let data = io::Cursor::new(&data);
let mut reader = IppReader::new(data);
let value = reader.read_value().unwrap();
assert_eq!(value.as_ref(), b"test");
}

#[test]
fn test_read_header() {
let data = io::Cursor::new(vec![0x01, 0x01, 0x04, 0x01, 0x11, 0x22, 0x33, 0x44]);
Expand Down

0 comments on commit b965f84

Please sign in to comment.