1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
//!
//! # UAVCAN data type serialization and deserialization
//!

#![cfg_attr(not(test), no_std)]
#![deny(missing_docs)]

extern crate half;
extern crate zerocopy;

pub mod bits;
mod cursor;

pub use crate::cursor::deserialize::ReadCursor;
pub use crate::cursor::serialize::WriteCursor;
use core::cmp;
use zerocopy::{AsBytes, FromBytes};

/// Trait for types that can be encoded into UAVCAN transfers, or decoded from transfers
pub trait DataType {
    /// The sealed or delimited property of this type
    const EXTENT_BYTES: Option<u32>;
}

/// Trait for types that can be serialized into UAVCAN transfers
pub trait Serialize: DataType {
    /// Returns the size of the encoded form of this value, in bits
    ///
    /// For composite types, this must be a multiple of 8.
    fn size_bits(&self) -> usize;

    /// Serializes this value into a buffer
    ///
    /// The provided cursor will allow writing at least the number of bits returned by the
    /// [`size_bits()`](#tymethod.size_bits) function.
    fn serialize(&self, cursor: &mut WriteCursor<'_>);

    /// A convenience function that creates a cursor around the provided bytes and calls
    /// [`serialize`](#tymethod.serialize)
    fn serialize_to_bytes(&self, bytes: &mut [u8]) {
        let mut cursor = WriteCursor::new(bytes);
        self.serialize(&mut cursor);
    }
}

/// Trait for types that can be deserialized from UAVCAN transfers
pub trait Deserialize: DataType {
    /// Deserializes a value and returns it
    fn deserialize(cursor: &mut ReadCursor<'_>) -> Result<Self, DeserializeError>
    where
        Self: Sized;

    /// Deserializes a value from a slice of bytes and returns it
    ///
    /// This is available only for types that implement [`Sized`], [`AsBytes`], and [`FromBytes`].
    ///
    /// # Panics
    ///
    /// This function panics if the provided cursor is not aligned to a byte boundary.
    fn deserialize_zero_copy(cursor: &mut ReadCursor<'_>) -> Self
    where
        Self: Sized + AsBytes + FromBytes,
    {
        // This isn't quite zero-copy. It's one-copy, but it eliminates handling each field
        // individually.
        let cursor_bytes = cursor.as_bytes().expect("Cursor not aligned");
        let mut value = Self::new_zeroed();

        let value_bytes = value.as_bytes_mut();
        // To apply implicit truncation and zero extension, copy whatever bytes we can
        let bytes_to_copy = cmp::min(value_bytes.len(), cursor_bytes.len());
        value_bytes[..bytes_to_copy].copy_from_slice(&cursor_bytes[..bytes_to_copy]);

        cursor.advance_bytes(bytes_to_copy);

        value
    }

    /// A convenience function that creates a cursor around the provided bytes and calls
    /// [`deserialize`](#tymethod.deserialize)
    fn deserialize_from_bytes(bytes: &[u8]) -> Result<Self, DeserializeError>
    where
        Self: Sized,
    {
        let mut cursor = ReadCursor::new(bytes);
        Self::deserialize(&mut cursor)
    }
}

/// Marker for message data types
pub trait Message {}
/// Marker for service request data types
pub trait Request {}
/// Marker for service response data types
pub trait Response {}

/// Errors that can occur when deserializing
#[non_exhaustive]
#[derive(Debug)]
pub enum DeserializeError {
    /// A variable-length array length field was greater than the maximum allowed length
    ArrayLength,
    /// A union tag field did not correspond to a known variant
    UnionTag,
    /// A delimiter header had a length that was not valid for the expected type
    DelimitedLength,
}