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
108
//! Traits used to pack/unpack structs and enums from EtherCAT packets on the wire.
//!
//! This crate is designed for use with [`ethercrab`](https://docs.rs/ethercrab) but can be
//! used standalone too.
//!
//! While these traits can be implemented by hand as normal, it is recommended to derive them using
//! [`ethercrab-wire-derive`](https://docs.rs/ethercrab-wire-derive) where possible.
//!
//! # Experimental
//!
//! This crate is in its early stages and may contain bugs or publish breaking changes at any time.
//! It is in use by [`ethercrab`](https://docs.rs/ethercrab) and is well exercised there,
//! but please use with caution in your own code.

#![cfg_attr(not(feature = "std"), no_std)]
#![deny(missing_docs)]
#![deny(missing_copy_implementations)]
#![deny(trivial_casts)]
#![deny(trivial_numeric_casts)]
#![deny(unused_import_braces)]
#![deny(unused_qualifications)]
#![deny(rustdoc::broken_intra_doc_links)]
#![deny(rustdoc::private_intra_doc_links)]

mod error;
mod impls;

pub use error::WireError;
pub use ethercrab_wire_derive::{EtherCrabWireRead, EtherCrabWireReadWrite, EtherCrabWireWrite};

/// A type to be received from the wire, according to EtherCAT spec rules (packed bits, little
/// endian).
///
/// This trait is [derivable](https://docs.rs/ethercrab-wire-derive).
pub trait EtherCrabWireRead: Sized {
    /// Unpack this type from the beginning of the given buffer.
    fn unpack_from_slice(buf: &[u8]) -> Result<Self, WireError>;
}

/// A type to be sent/received on the wire, according to EtherCAT spec rules (packed bits, little
/// endian).
///
/// This trait is [derivable](https://docs.rs/ethercrab-wire-derive).
pub trait EtherCrabWireWrite {
    /// Pack the type and write it into the beginning of `buf`.
    ///
    /// The default implementation of this method will return an error if the buffer is not long
    /// enough.
    fn pack_to_slice<'buf>(&self, buf: &'buf mut [u8]) -> Result<&'buf [u8], WireError> {
        if buf.len() < self.packed_len() {
            return Err(WireError::WriteBufferTooShort {
                expected: self.packed_len(),
                got: buf.len(),
            });
        }

        Ok(self.pack_to_slice_unchecked(buf))
    }

    /// Pack the type and write it into the beginning of `buf`.
    ///
    /// # Panics
    ///
    /// This method must panic if `buf` is too short to hold the packed data.
    fn pack_to_slice_unchecked<'buf>(&self, buf: &'buf mut [u8]) -> &'buf [u8];

    /// Get the length in bytes of this item when packed.
    fn packed_len(&self) -> usize;
}

/// A type that can be both written to the wire and read back from it.
///
/// This trait is [derivable](https://docs.rs/ethercrab-wire-derive).
pub trait EtherCrabWireReadWrite: EtherCrabWireRead + EtherCrabWireWrite {}

impl<T> EtherCrabWireReadWrite for T where T: EtherCrabWireRead + EtherCrabWireWrite {}

/// Implemented for types with a known size at compile time.
///
/// This trait is implemented automatically if [`EtherCrabWireRead`], [`EtherCrabWireWrite`] or
/// [`EtherCrabWireReadWrite`] is [derived](https://docs.rs/ethercrab-wire-derive).
pub trait EtherCrabWireSized {
    /// Packed size in bytes.
    const PACKED_LEN: usize;

    /// Used to define an array of the correct length. This type should be an array `[u8; N]` where
    /// `N` is a fixed value or const generic as per the type this trait is implemented on.
    type Buffer: AsRef<[u8]> + AsMut<[u8]>;

    /// Create a buffer sized to contain the packed representation of this item.
    fn buffer() -> Self::Buffer;
}

/// Implemented for writeable types with a known size at compile time.
///
/// This trait is implemented automatically if [`EtherCrabWireWrite`] or [`EtherCrabWireReadWrite`]
/// is [derived](https://docs.rs/ethercrab-wire-derive).
pub trait EtherCrabWireWriteSized: EtherCrabWireSized {
    /// Pack this item to a fixed sized array.
    fn pack(&self) -> Self::Buffer;
}

/// A readable type that has a size known at compile time.
///
/// This trait is [derivable](https://docs.rs/ethercrab-wire-derive).
pub trait EtherCrabWireReadSized: EtherCrabWireRead + EtherCrabWireSized {}

impl<T> EtherCrabWireReadSized for T where T: EtherCrabWireRead + EtherCrabWireSized {}