use std::io::{self, Read, Write};
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
pub mod data_types;
pub mod messages;
pub const NEGOEXTS_MESSAGE_SIGNATURE: u64 = 0x535458454f47454e;
pub const CHECKSUM_SCHEME_RFC3961: u32 = 0x1;
pub const PROTOCOL_VERSION: u64 = 0;
pub const RANDOM_ARRAY_SIZE: usize = 32;
pub trait NegoexMessage
where
Self: Sized,
{
type Error;
fn decode(message: &[u8]) -> Result<Self, Self::Error>;
fn encode(&self, to: impl Write) -> Result<(), Self::Error>;
}
pub trait NegoexDataType
where
Self: Sized,
{
type Error;
fn size(&self) -> usize;
fn decode(from: impl Read, message: &[u8]) -> Result<Self, Self::Error>;
fn encode(&self, to: impl Write) -> Result<(), Self::Error>;
fn encode_with_payload(&self, offset: usize, to: impl Write, data: impl Write) -> Result<usize, Self::Error>;
}
impl NegoexDataType for u8 {
type Error = io::Error;
fn size(&self) -> usize {
1
}
fn decode(mut from: impl Read, _message: &[u8]) -> Result<Self, Self::Error> {
from.read_u8()
}
fn encode_with_payload(&self, _offset: usize, mut to: impl Write, _data: impl Write) -> Result<usize, Self::Error> {
to.write_u8(*self)?;
Ok(0)
}
fn encode(&self, to: impl Write) -> Result<(), Self::Error> {
self.encode_with_payload(0, to, &mut [] as &mut [u8])?;
Ok(())
}
}
impl<T: NegoexDataType<Error = io::Error>> NegoexDataType for Vec<T> {
type Error = io::Error;
fn size(&self) -> usize {
4 +
4 +
self.first().map(|e| e.size()).unwrap_or_default() * self.len()
}
fn decode(mut from: impl Read, message: &[u8]) -> Result<Self, Self::Error> {
let message_offset = from.read_u32::<LittleEndian>()? as usize;
let count = from.read_u32::<LittleEndian>()? as usize;
let mut reader = &message[message_offset..];
let mut elements = Vec::with_capacity(count);
for _ in 0..count {
elements.push(T::decode(&mut reader, message)?);
}
Ok(elements)
}
fn encode_with_payload(
&self,
offset: usize,
mut to: impl Write,
mut data: impl Write,
) -> Result<usize, Self::Error> {
if self.is_empty() {
to.write_u32::<LittleEndian>(0)?;
} else {
to.write_u32::<LittleEndian>(offset as u32)?;
}
to.write_u32::<LittleEndian>(self.len() as u32)?;
let mut elements_headers = Vec::new();
let mut elements_data = Vec::new();
let mut written = 0;
for element in self.iter() {
written += element.size();
element.encode_with_payload(offset + written, &mut elements_headers, &mut elements_data)?;
}
data.write_all(&elements_headers)?;
data.write_all(&elements_data)?;
Ok(written)
}
fn encode(&self, mut to: impl Write) -> Result<(), Self::Error> {
let mut header = Vec::new();
let mut data = Vec::new();
self.encode_with_payload(0, &mut header, &mut data)?;
to.write_all(&header)?;
to.write_all(&data)?;
Ok(())
}
}