use crate::error::{Error, Result};
use cobs::{EncoderState, PushResult};
use core::marker::PhantomData;
use core::ops::Index;
use core::ops::IndexMut;
#[cfg(feature = "heapless")]
pub use heapless_vec::*;
#[cfg(feature = "use-std")]
pub use std_vec::*;
#[cfg(feature = "alloc")]
pub use alloc_vec::*;
#[cfg(feature = "alloc")]
extern crate alloc;
pub trait Flavor {
type Output;
#[inline]
fn try_extend(&mut self, data: &[u8]) -> Result<()> {
data.iter().try_for_each(|d| self.try_push(*d))
}
fn try_push(&mut self, data: u8) -> Result<()>;
fn finalize(self) -> Result<Self::Output>;
}
pub struct Slice<'a> {
start: *mut u8,
cursor: *mut u8,
end: *mut u8,
_pl: PhantomData<&'a [u8]>,
}
impl<'a> Slice<'a> {
pub fn new(buf: &'a mut [u8]) -> Self {
let ptr = buf.as_mut_ptr();
Slice {
start: ptr,
cursor: ptr,
end: unsafe { ptr.add(buf.len()) },
_pl: PhantomData,
}
}
}
impl<'a> Flavor for Slice<'a> {
type Output = &'a mut [u8];
#[inline(always)]
fn try_push(&mut self, b: u8) -> Result<()> {
if self.cursor == self.end {
Err(Error::SerializeBufferFull)
} else {
unsafe {
self.cursor.write(b);
self.cursor = self.cursor.add(1);
}
Ok(())
}
}
#[inline(always)]
fn try_extend(&mut self, b: &[u8]) -> Result<()> {
let remain = (self.end as usize) - (self.cursor as usize);
let blen = b.len();
if blen > remain {
Err(Error::SerializeBufferFull)
} else {
unsafe {
core::ptr::copy_nonoverlapping(b.as_ptr(), self.cursor, blen);
self.cursor = self.cursor.add(blen);
}
Ok(())
}
}
fn finalize(self) -> Result<Self::Output> {
let used = (self.cursor as usize) - (self.start as usize);
let sli = unsafe { core::slice::from_raw_parts_mut(self.start, used) };
Ok(sli)
}
}
impl<'a> Index<usize> for Slice<'a> {
type Output = u8;
fn index(&self, idx: usize) -> &u8 {
let len = (self.end as usize) - (self.start as usize);
assert!(idx < len);
unsafe { &*self.start.add(idx) }
}
}
impl<'a> IndexMut<usize> for Slice<'a> {
fn index_mut(&mut self, idx: usize) -> &mut u8 {
let len = (self.end as usize) - (self.start as usize);
assert!(idx < len);
unsafe { &mut *self.start.add(idx) }
}
}
pub struct ExtendFlavor<T> {
iter: T,
}
impl<T> ExtendFlavor<T>
where
T: core::iter::Extend<u8>,
{
pub fn new(iter: T) -> Self {
Self { iter }
}
}
impl<T> Flavor for ExtendFlavor<T>
where
T: core::iter::Extend<u8>,
{
type Output = T;
#[inline(always)]
fn try_push(&mut self, data: u8) -> Result<()> {
self.iter.extend([data]);
Ok(())
}
#[inline(always)]
fn try_extend(&mut self, b: &[u8]) -> Result<()> {
self.iter.extend(b.iter().cloned());
Ok(())
}
fn finalize(self) -> Result<Self::Output> {
Ok(self.iter)
}
}
#[cfg(any(feature = "embedded-io-04", feature = "embedded-io-06"))]
pub mod eio {
use super::Flavor;
use crate::{Error, Result};
pub struct WriteFlavor<T> {
writer: T,
}
impl<T> WriteFlavor<T>
where
T: crate::eio::Write,
{
pub fn new(writer: T) -> Self {
Self { writer }
}
}
impl<T> Flavor for WriteFlavor<T>
where
T: crate::eio::Write,
{
type Output = T;
#[inline(always)]
fn try_push(&mut self, data: u8) -> Result<()> {
self.writer
.write_all(&[data])
.map_err(|_| Error::SerializeBufferFull)?;
Ok(())
}
#[inline(always)]
fn try_extend(&mut self, b: &[u8]) -> Result<()> {
self.writer
.write_all(b)
.map_err(|_| Error::SerializeBufferFull)?;
Ok(())
}
fn finalize(mut self) -> Result<Self::Output> {
self.writer
.flush()
.map_err(|_| Error::SerializeBufferFull)?;
Ok(self.writer)
}
}
}
#[cfg(feature = "use-std")]
pub mod io {
use super::Flavor;
use crate::{Error, Result};
pub struct WriteFlavor<T> {
writer: T,
}
impl<T> WriteFlavor<T>
where
T: std::io::Write,
{
pub fn new(writer: T) -> Self {
Self { writer }
}
}
impl<T> Flavor for WriteFlavor<T>
where
T: std::io::Write,
{
type Output = T;
#[inline(always)]
fn try_push(&mut self, data: u8) -> Result<()> {
self.writer
.write_all(&[data])
.map_err(|_| Error::SerializeBufferFull)?;
Ok(())
}
#[inline(always)]
fn try_extend(&mut self, b: &[u8]) -> Result<()> {
self.writer
.write_all(b)
.map_err(|_| Error::SerializeBufferFull)?;
Ok(())
}
fn finalize(mut self) -> Result<Self::Output> {
self.writer
.flush()
.map_err(|_| Error::SerializeBufferFull)?;
Ok(self.writer)
}
}
}
#[cfg(feature = "heapless")]
mod heapless_vec {
use super::Flavor;
use super::Index;
use super::IndexMut;
use crate::{Error, Result};
use heapless::Vec;
#[derive(Default)]
pub struct HVec<const B: usize> {
vec: Vec<u8, B>,
}
impl<const B: usize> HVec<B> {
pub fn new() -> Self {
Self::default()
}
}
impl<const B: usize> Flavor for HVec<B> {
type Output = Vec<u8, B>;
#[inline(always)]
fn try_extend(&mut self, data: &[u8]) -> Result<()> {
self.vec
.extend_from_slice(data)
.map_err(|_| Error::SerializeBufferFull)
}
#[inline(always)]
fn try_push(&mut self, data: u8) -> Result<()> {
self.vec.push(data).map_err(|_| Error::SerializeBufferFull)
}
fn finalize(self) -> Result<Vec<u8, B>> {
Ok(self.vec)
}
}
impl<const B: usize> Index<usize> for HVec<B> {
type Output = u8;
fn index(&self, idx: usize) -> &u8 {
&self.vec[idx]
}
}
impl<const B: usize> IndexMut<usize> for HVec<B> {
fn index_mut(&mut self, idx: usize) -> &mut u8 {
&mut self.vec[idx]
}
}
}
#[cfg(feature = "use-std")]
mod std_vec {
pub type StdVec = super::alloc_vec::AllocVec;
}
#[cfg(feature = "alloc")]
mod alloc_vec {
extern crate alloc;
use super::Flavor;
use super::Index;
use super::IndexMut;
use crate::Result;
use alloc::vec::Vec;
#[derive(Default)]
pub struct AllocVec {
vec: Vec<u8>,
}
impl AllocVec {
pub fn new() -> Self {
Self::default()
}
}
impl Flavor for AllocVec {
type Output = Vec<u8>;
#[inline(always)]
fn try_extend(&mut self, data: &[u8]) -> Result<()> {
self.vec.extend_from_slice(data);
Ok(())
}
#[inline(always)]
fn try_push(&mut self, data: u8) -> Result<()> {
self.vec.push(data);
Ok(())
}
fn finalize(self) -> Result<Self::Output> {
Ok(self.vec)
}
}
impl Index<usize> for AllocVec {
type Output = u8;
#[inline]
fn index(&self, idx: usize) -> &u8 {
&self.vec[idx]
}
}
impl IndexMut<usize> for AllocVec {
#[inline]
fn index_mut(&mut self, idx: usize) -> &mut u8 {
&mut self.vec[idx]
}
}
}
pub struct Cobs<B>
where
B: Flavor + IndexMut<usize, Output = u8>,
{
flav: B,
cobs: EncoderState,
}
impl<B> Cobs<B>
where
B: Flavor + IndexMut<usize, Output = u8>,
{
pub fn try_new(mut bee: B) -> Result<Self> {
bee.try_push(0).map_err(|_| Error::SerializeBufferFull)?;
Ok(Self {
flav: bee,
cobs: EncoderState::default(),
})
}
}
impl<B> Flavor for Cobs<B>
where
B: Flavor + IndexMut<usize, Output = u8>,
{
type Output = <B as Flavor>::Output;
#[inline(always)]
fn try_push(&mut self, data: u8) -> Result<()> {
use PushResult::*;
match self.cobs.push(data) {
AddSingle(n) => self.flav.try_push(n),
ModifyFromStartAndSkip((idx, mval)) => {
self.flav[idx] = mval;
self.flav.try_push(0)
}
ModifyFromStartAndPushAndSkip((idx, mval, nval)) => {
self.flav[idx] = mval;
self.flav.try_push(nval)?;
self.flav.try_push(0)
}
}
}
fn finalize(mut self) -> Result<Self::Output> {
let (idx, mval) = self.cobs.finalize();
self.flav[idx] = mval;
self.flav.try_push(0)?;
self.flav.finalize()
}
}
#[cfg(feature = "use-crc")]
#[cfg_attr(docsrs, doc(cfg(feature = "use-crc")))]
pub mod crc {
use crc::Digest;
use crc::Width;
use serde::Serialize;
#[cfg(feature = "alloc")]
use super::alloc;
use super::Flavor;
use super::Slice;
use crate::serialize_with_flavor;
use crate::Result;
use paste::paste;
pub struct CrcModifier<'a, B, W>
where
B: Flavor,
W: Width,
{
flav: B,
digest: Digest<'a, W>,
}
impl<'a, B, W> CrcModifier<'a, B, W>
where
B: Flavor,
W: Width,
{
pub fn new(bee: B, digest: Digest<'a, W>) -> Self {
Self { flav: bee, digest }
}
}
macro_rules! impl_flavor {
($( $int:ty ),*) => {
$(
paste! {
impl<'a, B> Flavor for CrcModifier<'a, B, $int>
where
B: Flavor,
{
type Output = <B as Flavor>::Output;
#[inline(always)]
fn try_push(&mut self, data: u8) -> Result<()> {
self.digest.update(&[data]);
self.flav.try_push(data)
}
fn finalize(mut self) -> Result<Self::Output> {
let crc = self.digest.finalize();
for byte in crc.to_le_bytes() {
self.flav.try_push(byte)?;
}
self.flav.finalize()
}
}
pub fn [<to_slice_ $int>]<'a, T>(
value: &T,
buf: &'a mut [u8],
digest: Digest<'_, $int>,
) -> Result<&'a mut [u8]>
where
T: Serialize + ?Sized,
{
serialize_with_flavor(value, CrcModifier::new(Slice::new(buf), digest))
}
#[cfg(feature = "heapless")]
#[cfg_attr(docsrs, doc(cfg(feature = "heapless")))]
pub fn [<to_vec_ $int>]<T, const B: usize>(
value: &T,
digest: Digest<'_, $int>,
) -> Result<heapless::Vec<u8, B>>
where
T: Serialize + ?Sized,
{
use super::HVec;
serialize_with_flavor(value, CrcModifier::new(HVec::default(), digest))
}
#[cfg(feature = "alloc")]
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
pub fn [<to_allocvec_ $int>]<T>(value: &T, digest: Digest<'_, $int>) -> Result<alloc::vec::Vec<u8>>
where
T: Serialize + ?Sized,
{
use super::AllocVec;
serialize_with_flavor(value, CrcModifier::new(AllocVec::new(), digest))
}
}
)*
};
}
impl_flavor![u8, u16, u32, u64, u128];
}
#[derive(Default)]
pub struct Size {
size: usize,
}
impl Flavor for Size {
type Output = usize;
#[inline(always)]
fn try_push(&mut self, _b: u8) -> Result<()> {
self.size += 1;
Ok(())
}
#[inline(always)]
fn try_extend(&mut self, b: &[u8]) -> Result<()> {
self.size += b.len();
Ok(())
}
fn finalize(self) -> Result<Self::Output> {
Ok(self.size)
}
}