diff options
Diffstat (limited to 'crates/windlass/src/encoding.rs')
-rw-r--r-- | crates/windlass/src/encoding.rs | 274 |
1 files changed, 146 insertions, 128 deletions
diff --git a/crates/windlass/src/encoding.rs b/crates/windlass/src/encoding.rs index 0950956..27238c0 100644 --- a/crates/windlass/src/encoding.rs +++ b/crates/windlass/src/encoding.rs @@ -2,17 +2,19 @@ use std::fmt::Display; use crate::messages::MessageSkipperError; -/// Message decoding error -#[derive(thiserror::Error, Debug, Clone)] -pub enum MessageDecodeError { - /// More data was expected but none is available - #[error("eof unexpected")] - UnexpectedEof, - /// A received string could not be decoded as UTF8 - #[error("invalid utf8 string")] - Utf8Error(#[from] std::str::Utf8Error), +/// Calculate the CRC-16 of the given buffer +pub(crate) fn crc16(buf: &[u8]) -> u16 { + let mut crc = 0xFFFFu16; + for b in buf { + let b = *b ^ ((crc & 0xFF) as u8); + let b = b ^ (b << 4); + let b16 = b as u16; + crc = (b16 << 8 | crc >> 8) ^ (b16 >> 4) ^ (b16 << 3); + } + crc } +/// Encode the given integer as a [VLQ](https://www.klipper3d.org/Protocol.html#variable-length-quantities), pushing it to the back of `output`. pub(crate) fn encode_vlq_int(output: &mut Vec<u8>, v: u32) { let sv = v as i32; if !(-(1 << 26)..(3 << 26)).contains(&sv) { @@ -30,16 +32,7 @@ pub(crate) fn encode_vlq_int(output: &mut Vec<u8>, v: u32) { output.push((sv & 0x7F) as u8); } -pub(crate) fn next_byte(data: &mut &[u8]) -> Result<u8, MessageDecodeError> { - if data.is_empty() { - Err(MessageDecodeError::UnexpectedEof) - } else { - let v = data[0]; - *data = &data[1..]; - Ok(v) - } -} - +/// Parse a [VLQ](https://www.klipper3d.org/Protocol.html#variable-length-quantities) from the top of `data`. pub(crate) fn parse_vlq_int(data: &mut &[u8]) -> Result<u32, MessageDecodeError> { let mut c = next_byte(data)? as u32; let mut v = c & 0x7F; @@ -54,16 +47,35 @@ pub(crate) fn parse_vlq_int(data: &mut &[u8]) -> Result<u32, MessageDecodeError> Ok(v) } +/// Read the next byte from `data`, or error +pub(crate) fn next_byte(data: &mut &[u8]) -> Result<u8, MessageDecodeError> { + if data.is_empty() { + Err(MessageDecodeError::UnexpectedEof) + } else { + let v = data[0]; + *data = &data[1..]; + Ok(v) + } +} + +/// A type which can possibly be read from the top of a data buffer. pub trait Readable<'de>: Sized { + /// Attempt to deserialise a value from the top of `data`. fn read(data: &mut &'de [u8]) -> Result<Self, MessageDecodeError>; - fn skip(data: &mut &[u8]) -> Result<(), MessageDecodeError>; + /// Skip over a value of this type at the top of `data`. + fn skip(data: &mut &'de [u8]) -> Result<(), MessageDecodeError> { + Self::read(data).map(|_| ()) + } } +/// A type which can be written to the back of a data buffer. pub trait Writable: Sized { + /// Write this type to the back of `output`. fn write(&self, output: &mut Vec<u8>); } +/// TODO: Docs pub trait Borrowable: Sized { type Borrowed<'a> where @@ -71,20 +83,121 @@ pub trait Borrowable: Sized { fn from_borrowed(src: Self::Borrowed<'_>) -> Self; } +/// The type of an encoded field +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub enum FieldType { + U32, + I32, + U16, + I16, + U8, + String, + ByteArray, +} + +impl FieldType { + /// Skip over a field of this type at the top of `input`. + pub(crate) fn skip(&self, input: &mut &[u8]) -> Result<(), MessageDecodeError> { + match self { + Self::U32 => <u32 as Readable>::skip(input), + Self::I32 => <i32 as Readable>::skip(input), + Self::U16 => <u16 as Readable>::skip(input), + Self::I16 => <i16 as Readable>::skip(input), + Self::U8 => <u8 as Readable>::skip(input), + Self::String => <&str as Readable>::skip(input), + Self::ByteArray => <&[u8] as Readable>::skip(input), + } + } + + /// Read a field of this type from the top of `input`. + pub(crate) fn read(&self, input: &mut &[u8]) -> Result<FieldValue, MessageDecodeError> { + Ok(match self { + Self::U32 => FieldValue::U32(<u32 as Readable>::read(input)?), + Self::I32 => FieldValue::I32(<i32 as Readable>::read(input)?), + Self::U16 => FieldValue::U16(<u16 as Readable>::read(input)?), + Self::I16 => FieldValue::I16(<i16 as Readable>::read(input)?), + Self::U8 => FieldValue::U8(<u8 as Readable>::read(input)?), + Self::String => FieldValue::String(<&str as Readable>::read(input)?.into()), + Self::ByteArray => FieldValue::ByteArray(<&[u8] as Readable>::read(input)?.into()), + }) + } + + /// Deserialise the field type from a printf style declaration + pub(crate) fn from_msg(s: &str) -> Result<Self, MessageSkipperError> { + match s { + "%u" => Ok(Self::U32), + "%i" => Ok(Self::I32), + "%hu" => Ok(Self::U16), + "%hi" => Ok(Self::I16), + "%c" => Ok(Self::U8), + "%s" => Ok(Self::String), + "%*s" => Ok(Self::ByteArray), + "%.*s" => Ok(Self::ByteArray), + s => Err(MessageSkipperError::InvalidFormatFieldType(s.to_string())), + } + } + + /// Deserialise the next field type from a printf style declaration, also returning the rest of the string. + pub(crate) fn from_format(s: &str) -> Result<(Self, &str), MessageSkipperError> { + if let Some(rest) = s.strip_prefix("%u") { + Ok((Self::U32, rest)) + } else if let Some(rest) = s.strip_prefix("%i") { + Ok((Self::I32, rest)) + } else if let Some(rest) = s.strip_prefix("%hu") { + Ok((Self::U16, rest)) + } else if let Some(rest) = s.strip_prefix("%hi") { + Ok((Self::I16, rest)) + } else if let Some(rest) = s.strip_prefix("%c") { + Ok((Self::U8, rest)) + } else if let Some(rest) = s.strip_prefix("%.*s") { + Ok((Self::ByteArray, rest)) + } else if let Some(rest) = s.strip_prefix("%*s") { + Ok((Self::String, rest)) + } else { + Err(MessageSkipperError::InvalidFormatFieldType(s.to_string())) + } + } +} + +/// The decoded value of a field +#[derive(Debug)] +pub enum FieldValue { + U32(u32), + I32(i32), + U16(u16), + I16(i16), + U8(u8), + String(String), + ByteArray(Vec<u8>), +} + +impl Display for FieldValue { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::U32(v) => write!(f, "{}", v), + Self::I32(v) => write!(f, "{}", v), + Self::U16(v) => write!(f, "{}", v), + Self::I16(v) => write!(f, "{}", v), + Self::U8(v) => write!(f, "{}", v), + Self::String(v) => write!(f, "{}", v), + Self::ByteArray(v) => write!(f, "{:?}", v), + } + } +} + +/// A type which can be expressed as a [`FieldType`] pub trait ToFieldType: Sized { + /// Get the corresponding [`FieldType`]. fn as_field_type() -> FieldType; } +/// Implements [`Readable`], [`Writable`], and [`ToFieldType`] for the given integer type. macro_rules! int_readwrite { ( $type:tt, $field_type:expr ) => { impl Readable<'_> for $type { fn read(data: &mut &[u8]) -> Result<Self, MessageDecodeError> { parse_vlq_int(data).map(|v| v as $type) } - - fn skip(data: &mut &[u8]) -> Result<(), MessageDecodeError> { - parse_vlq_int(data).map(|_| ()) - } } impl Writable for $type { @@ -118,10 +231,6 @@ impl Readable<'_> for bool { fn read(data: &mut &[u8]) -> Result<Self, MessageDecodeError> { parse_vlq_int(data).map(|v| v != 0) } - - fn skip(data: &mut &[u8]) -> Result<(), MessageDecodeError> { - parse_vlq_int(data).map(|_| ()) - } } impl Writable for bool { @@ -217,111 +326,20 @@ impl Writable for &str { } } -impl Borrowable for String { - type Borrowed<'a> = &'a str; - fn from_borrowed(src: Self::Borrowed<'_>) -> Self { - src.to_string() - } -} - impl ToFieldType for String { fn as_field_type() -> FieldType { FieldType::String } } -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub enum FieldType { - U32, - I32, - U16, - I16, - U8, - String, - ByteArray, -} - -impl FieldType { - pub(crate) fn skip(&self, input: &mut &[u8]) -> Result<(), MessageDecodeError> { - match self { - Self::U32 => <u32 as Readable>::skip(input), - Self::I32 => <i32 as Readable>::skip(input), - Self::U16 => <u16 as Readable>::skip(input), - Self::I16 => <i16 as Readable>::skip(input), - Self::U8 => <u8 as Readable>::skip(input), - Self::String => <&str as Readable>::skip(input), - Self::ByteArray => <&[u8] as Readable>::skip(input), - } - } - - pub(crate) fn read(&self, input: &mut &[u8]) -> Result<FieldValue, MessageDecodeError> { - Ok(match self { - Self::U32 => FieldValue::U32(<u32 as Readable>::read(input)?), - Self::I32 => FieldValue::I32(<i32 as Readable>::read(input)?), - Self::U16 => FieldValue::U16(<u16 as Readable>::read(input)?), - Self::I16 => FieldValue::I16(<i16 as Readable>::read(input)?), - Self::U8 => FieldValue::U8(<u8 as Readable>::read(input)?), - Self::String => FieldValue::String(<&str as Readable>::read(input)?.into()), - Self::ByteArray => FieldValue::ByteArray(<&[u8] as Readable>::read(input)?.into()), - }) - } - - pub(crate) fn from_msg(s: &str) -> Result<Self, MessageSkipperError> { - match s { - "%u" => Ok(Self::U32), - "%i" => Ok(Self::I32), - "%hu" => Ok(Self::U16), - "%hi" => Ok(Self::I16), - "%c" => Ok(Self::U8), - "%s" => Ok(Self::String), - "%*s" => Ok(Self::ByteArray), - "%.*s" => Ok(Self::ByteArray), - s => Err(MessageSkipperError::InvalidFormatFieldType(s.to_string())), - } - } - - pub(crate) fn from_format(s: &str) -> Result<(Self, &str), MessageSkipperError> { - if let Some(rest) = s.strip_prefix("%u") { - Ok((Self::U32, rest)) - } else if let Some(rest) = s.strip_prefix("%i") { - Ok((Self::I32, rest)) - } else if let Some(rest) = s.strip_prefix("%hu") { - Ok((Self::U16, rest)) - } else if let Some(rest) = s.strip_prefix("%hi") { - Ok((Self::I16, rest)) - } else if let Some(rest) = s.strip_prefix("%c") { - Ok((Self::U8, rest)) - } else if let Some(rest) = s.strip_prefix("%.*s") { - Ok((Self::ByteArray, rest)) - } else if let Some(rest) = s.strip_prefix("%*s") { - Ok((Self::String, rest)) - } else { - Err(MessageSkipperError::InvalidFormatFieldType(s.to_string())) - } - } -} - -#[derive(Debug)] -pub enum FieldValue { - U32(u32), - I32(i32), - U16(u16), - I16(i16), - U8(u8), - String(String), - ByteArray(Vec<u8>), -} +/// Error encountered when decoding a message +#[derive(thiserror::Error, Debug, Clone)] +pub enum MessageDecodeError { + /// More data was expected but none is available + #[error("eof unexpected")] + UnexpectedEof, -impl Display for FieldValue { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Self::U32(v) => write!(f, "{}", v), - Self::I32(v) => write!(f, "{}", v), - Self::U16(v) => write!(f, "{}", v), - Self::I16(v) => write!(f, "{}", v), - Self::U8(v) => write!(f, "{}", v), - Self::String(v) => write!(f, "{}", v), - Self::ByteArray(v) => write!(f, "{:?}", v), - } - } + /// A received string could not be decoded as UTF8 + #[error("invalid utf8 string")] + Utf8Error(#[from] std::str::Utf8Error), } |