summaryrefslogtreecommitdiff
path: root/crates/windlass/src/encoding.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/windlass/src/encoding.rs')
-rw-r--r--crates/windlass/src/encoding.rs274
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),
}