ctaphid-types 0.2.0

Data types for the CTAPHID protocol
Documentation
// Copyright (C) 2022 Robin Krahl <robin.krahl@ireas.org>
// SPDX-License-Identifier: Apache-2.0 or MIT

use core::convert::TryInto as _;

use crate::error::{ParseError, SerializationError};

pub struct Serializer<'a> {
    buffer: &'a mut [u8],
    bytes_written: usize,
}

impl<'a> Serializer<'a> {
    pub fn new(buffer: &'a mut [u8]) -> Self {
        buffer.into()
    }

    pub fn push_slice(&mut self, data: &[u8]) -> Result<(), SerializationError> {
        let n = data.len();
        if self.bytes_written + n <= self.buffer.len() {
            self.buffer[self.bytes_written..self.bytes_written + n].copy_from_slice(data);
            self.bytes_written += n;
            Ok(())
        } else {
            Err(SerializationError::BufferTooSmall)
        }
    }

    pub fn bytes_written(&self) -> usize {
        self.bytes_written
    }
}

impl<'a> From<&'a mut [u8]> for Serializer<'a> {
    fn from(buffer: &'a mut [u8]) -> Self {
        Self {
            buffer,
            bytes_written: 0,
        }
    }
}

pub struct Parser<'a> {
    data: &'a [u8],
    offset: usize,
}

impl<'a> Parser<'a> {
    pub fn new(data: &'a [u8]) -> Self {
        data.into()
    }

    pub fn take(&mut self) -> Result<u8, ParseError> {
        if self.data.len() > self.offset {
            let data = self.data[self.offset];
            self.offset += 1;
            Ok(data)
        } else {
            Err(ParseError::NotEnoughData)
        }
    }

    pub fn take_array_ref<const N: usize>(&mut self) -> Result<&'a [u8; N], ParseError> {
        if self.data.len() >= self.offset + N {
            let data = self.data[self.offset..self.offset + N]
                .try_into()
                .map_err(|_| ParseError::NotEnoughData)?;
            self.offset += N;
            Ok(data)
        } else {
            Err(ParseError::NotEnoughData)
        }
    }

    pub fn take_array<const N: usize>(&mut self) -> Result<[u8; N], ParseError> {
        self.take_array_ref().map(|data| *data)
    }

    pub fn take_into<const N: usize, R: From<&'a [u8; N]>>(&mut self) -> Result<R, ParseError> {
        self.take_array_ref().map(From::from)
    }

    pub fn into_rest(self) -> &'a [u8] {
        &self.data[self.offset..]
    }
}

impl<'a> From<&'a [u8]> for Parser<'a> {
    fn from(data: &'a [u8]) -> Self {
        Self { data, offset: 0 }
    }
}