#![doc(html_root_url = "https://docs.rs/minisofh/")]
#![warn(missing_docs)]
#![deny(
unused,
missing_debug_implementations,
unsafe_op_in_unsafe_fn,
rustdoc::broken_intra_doc_links,
//missing_docs,
unconditional_recursion,
unstable_name_collisions,
clippy::useless_conversion,
clippy::missing_panics_doc,
clippy::mixed_case_hex_literals,
clippy::needless_bool,
clippy::needless_lifetimes
)]
#![cfg_attr(doc_cfg, feature(doc_cfg))]
mod encoding_type;
mod frame;
#[cfg(feature = "utils-tokio-codec")]
mod tokio_codec;
pub use encoding_type::EncodingType;
pub use frame::Frame;
use std::convert::TryInto;
use std::io;
use thiserror::Error;
#[cfg(feature = "utils-tokio-codec")]
pub use tokio_codec::TokioCodec;
#[derive(Debug, Error)]
pub enum Error {
#[error("The SOFH-enclosed message's length is outside the legal range.")]
InvalidMessageLength,
#[error(
"The SOFH-enclosed message is incomplete. {needed} more bytes are needed."
)]
Incomplete {
needed: usize,
},
#[error("I/O related error.")]
Io(#[from] io::Error),
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
struct Header {
pub nominal_message_length_in_bytes: usize,
pub encoding_type: u16,
}
impl Header {
const LENGTH_IN_BYTES: usize = 6;
fn to_bytes(self) -> [u8; Self::LENGTH_IN_BYTES] {
let mut bytes = [0u8; Self::LENGTH_IN_BYTES];
let (a, b) = bytes.split_at_mut(4);
a.copy_from_slice(
&(self.nominal_message_length_in_bytes as u32).to_be_bytes(),
);
b.copy_from_slice(&self.encoding_type.to_be_bytes());
bytes
}
fn from_bytes(bytes: &[u8]) -> Result<Self, Error> {
let err_incomplete = || Error::Incomplete {
needed: Self::LENGTH_IN_BYTES - bytes.len(),
};
let header = bytes
.get(..Self::LENGTH_IN_BYTES)
.ok_or_else(err_incomplete)?
.try_into()
.map(|header_bytes: &[u8; Self::LENGTH_IN_BYTES]| {
let nominal_message_length_in_bytes =
u32::from_be_bytes(header_bytes[0..4].try_into().unwrap())
as usize;
let encoding_type =
u16::from_be_bytes(header_bytes[4..6].try_into().unwrap());
Self { nominal_message_length_in_bytes, encoding_type }
})
.map_err(|_| err_incomplete())?;
if header.nominal_message_length_in_bytes < Self::LENGTH_IN_BYTES {
Err(Error::InvalidMessageLength)
} else {
Ok(header)
}
}
}