use core::convert::{TryFrom, TryInto};
use crate::{
channel::Channel,
error::{ParseError, SerializationError},
util::{Parser, Serializer},
};
#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
pub struct InitResponse<T: AsRef<[u8]>> {
pub nonce: [u8; 8],
pub channel: Channel,
pub protocol_version: u8,
pub device_version: DeviceVersion,
pub capabilities: Capabilities,
pub rest: T,
}
impl<T: AsRef<[u8]>> InitResponse<T> {
pub fn serialize(&self, buffer: &mut [u8]) -> Result<usize, SerializationError> {
let mut serializer = Serializer::new(buffer);
serializer.push_slice(&self.nonce)?;
serializer.push_slice(&self.channel.to_bytes())?;
serializer.push_slice(&[self.protocol_version])?;
serializer.push_slice(&self.device_version.to_bytes())?;
serializer.push_slice(&[self.capabilities.bits()])?;
serializer.push_slice(self.rest.as_ref())?;
Ok(serializer.bytes_written())
}
}
impl<'a, T: AsRef<[u8]> + TryFrom<&'a [u8]>> TryFrom<&'a [u8]> for InitResponse<T> {
type Error = ParseError;
fn try_from(data: &'a [u8]) -> Result<Self, Self::Error> {
let mut parser = Parser::new(data);
let nonce = parser.take_array()?;
let channel = parser.take_into()?;
let protocol_version = parser.take()?;
let device_version = parser.take_into()?;
let capabilities = parser.take()?;
let rest = parser.into_rest();
Ok(Self {
nonce,
channel,
protocol_version,
device_version,
capabilities: Capabilities::from_bits_truncate(capabilities),
rest: rest
.try_into()
.map_err(|_| ParseError::BufferCreationFailed)?,
})
}
}
#[derive(Clone, Copy, Debug, Default, Eq, Ord, PartialEq, PartialOrd)]
pub struct DeviceVersion {
pub major: u8,
pub minor: u8,
pub build: u8,
}
impl DeviceVersion {
pub fn to_bytes(self) -> [u8; 3] {
self.into()
}
}
impl From<DeviceVersion> for [u8; 3] {
fn from(version: DeviceVersion) -> Self {
[version.major, version.minor, version.build]
}
}
impl From<&[u8; 3]> for DeviceVersion {
fn from(data: &[u8; 3]) -> Self {
Self {
major: data[0],
minor: data[1],
build: data[2],
}
}
}
bitflags::bitflags! {
#[derive(Default)]
pub struct Capabilities: u8 {
const WINK = 0x01;
const CBOR = 0x04;
const NMSG = 0x08;
}
}
impl Capabilities {
pub fn has_wink(&self) -> bool {
self.contains(Self::WINK)
}
pub fn has_cbor(&self) -> bool {
self.contains(Self::CBOR)
}
pub fn has_msg(&self) -> bool {
!self.contains(Self::NMSG)
}
}
#[cfg(test)]
mod tests {
use std::convert::TryFrom as _;
use quickcheck::{Arbitrary, TestResult};
use super::{Capabilities, DeviceVersion, InitResponse};
impl Arbitrary for Capabilities {
fn arbitrary(g: &mut quickcheck::Gen) -> Self {
Self::from_bits_truncate(Arbitrary::arbitrary(g))
}
}
impl Arbitrary for DeviceVersion {
fn arbitrary(g: &mut quickcheck::Gen) -> Self {
Self {
major: Arbitrary::arbitrary(g),
minor: Arbitrary::arbitrary(g),
build: Arbitrary::arbitrary(g),
}
}
}
impl Arbitrary for InitResponse<Vec<u8>> {
fn arbitrary(g: &mut quickcheck::Gen) -> Self {
Self {
nonce: [
Arbitrary::arbitrary(g),
Arbitrary::arbitrary(g),
Arbitrary::arbitrary(g),
Arbitrary::arbitrary(g),
Arbitrary::arbitrary(g),
Arbitrary::arbitrary(g),
Arbitrary::arbitrary(g),
Arbitrary::arbitrary(g),
],
channel: Arbitrary::arbitrary(g),
protocol_version: Arbitrary::arbitrary(g),
device_version: Arbitrary::arbitrary(g),
capabilities: Arbitrary::arbitrary(g),
rest: Arbitrary::arbitrary(g),
}
}
fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
let nonce = self.nonce;
let channel = self.channel;
let protocol_version = self.protocol_version;
let device_version = self.device_version;
let capabilities = self.capabilities;
Box::new(self.rest.shrink().map(move |rest| Self {
nonce,
channel,
protocol_version,
device_version,
capabilities,
rest,
}))
}
}
quickcheck::quickcheck! {
fn parse_init(data: Vec<u8>) -> bool {
let _ = InitResponse::<Vec<u8>>::try_from(data.as_slice());
true
}
}
quickcheck::quickcheck! {
fn serialize_init(init: InitResponse<Vec<u8>>) -> bool {
let mut buffer = vec![0; init.rest.len() + 17];
let _ = init.serialize(&mut buffer);
true
}
}
quickcheck::quickcheck! {
fn serialize_parse_init(init: InitResponse<Vec<u8>>) -> TestResult {
let mut buffer = vec![0; init.rest.len() + 17];
let n = init.serialize(&mut buffer).unwrap();
let parsed = InitResponse::try_from(&buffer[..n]).unwrap();
TestResult::from_bool(init == parsed)
}
}
}