Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions ethercrab-wire/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ Primarily used by `ethercrab`.

- [#230](https://github.com/ethercrab-rs/ethercrab/pull/230) **(breaking)** Increase MSRV from 1.77
to 1.79.
- [#360](https://github.com/ethercrab-rs/ethercrab/pull/360) Support types other than `u8` in
`[T; N]`.

## [0.2.0] - 2024-07-28

Expand Down
78 changes: 62 additions & 16 deletions ethercrab-wire/src/impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -219,22 +219,6 @@ impl EtherCrabWireWriteSized for () {
}
}

impl<const N: usize> EtherCrabWireWrite for [u8; N] {
fn pack_to_slice_unchecked<'buf>(&self, buf: &'buf mut [u8]) -> &'buf [u8] {
let Some(chunk) = buf.first_chunk_mut::<N>() else {
unreachable!()
};

*chunk = *self;

chunk
}

fn packed_len(&self) -> usize {
N
}
}

impl EtherCrabWireWrite for &[u8] {
fn pack_to_slice_unchecked<'buf>(&self, buf: &'buf mut [u8]) -> &'buf [u8] {
let buf = &mut buf[0..self.len()];
Expand Down Expand Up @@ -279,6 +263,33 @@ where
}
}

impl<const N: usize, T> EtherCrabWireWrite for [T; N]
where
T: EtherCrabWireWrite,
{
fn pack_to_slice_unchecked<'buf>(&self, buf: &'buf mut [u8]) -> &'buf [u8] {
let Some(chunk_size) = self.get(0).map(|v| v.packed_len()) else {
return &mut buf[0..0];
};

let buf = &mut buf[0..self.packed_len()];

let mut chunk = &mut buf[..];

for i in self.iter() {
let _item_bytes = i.pack_to_slice_unchecked(chunk);

chunk = &mut chunk[chunk_size..];
}

buf
}

fn packed_len(&self) -> usize {
self.get(0).map(|v| v.packed_len()).unwrap_or(0) * N
}
}

// --- heapless::Vec ---

impl<const N: usize, T> EtherCrabWireRead for heapless::Vec<T, N>
Expand Down Expand Up @@ -382,4 +393,39 @@ mod tests {

assert_eq!(written, &[0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x34, 0x12]);
}

#[test]
fn pack_byte_array() {
let mut buf = [0u8; 32];

let data = [0xaau8; 4];

assert_eq!(data.packed_len(), 4);

let written = data.pack_to_slice_unchecked(&mut buf);

assert_eq!(written, &[0xaa, 0xaa, 0xaa, 0xaa]);
}

#[test]
fn unpack_byte_array() {
let data = &[0xaau8, 0xaa, 0xaa, 0xaa];

let unpacked = <[u8; 4]>::unpack_from_slice(data).unwrap();

assert_eq!(unpacked, [0xaau8, 0xaa, 0xaa, 0xaa]);
}

#[test]
fn pack_empty_byte_array() {
let mut buf = [0u8; 32];

let data = [0xaau8; 0];

assert_eq!(data.packed_len(), 0);

let written = data.pack_to_slice_unchecked(&mut buf);

assert_eq!(written, &[]);
}
}
60 changes: 60 additions & 0 deletions ethercrab-wire/tests/unpack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,3 +116,63 @@ fn nested_structs() {

assert_eq!(out, &expected);
}

#[test]
fn array_of_structs() {
#[derive(Default, Debug, EtherCrabWireReadWrite)]
#[wire(bits = 104)]
struct Check {
#[wire(bits = 32)]
foo: u32,
#[wire(bits = 24)]
control: Inner,
#[wire(bits = 48)]
status: [Inner; 2],
}

#[derive(Default, Debug, Copy, Clone, EtherCrabWireReadWrite)]
#[wire(bits = 24)]
struct Inner {
#[wire(bits = 1)]
yes: bool,
#[wire(bits = 1)]
no: bool,
#[wire(pre_skip = 6, bits = 16)]
stuff: u16,
}

let mut buf = [0u8; 13];

let packed = Check::default().pack_to_slice(&mut buf);

assert!(packed.is_ok());
}

#[test]
fn struct_array() {
#[derive(Debug, Default, ethercrab_wire_derive::EtherCrabWireWrite)]
#[wire(bytes = 3)]
struct Foo {
#[wire(bytes = 2)]
a: u16,
#[wire(bytes = 1)]
b: u8,
}

let mut buf = [0u8; 32];

let data = [
Foo { a: 0x1100, b: 0x22 },
Foo { a: 0x4433, b: 0x55 },
Foo { a: 0x7766, b: 0x88 },
];

assert_eq!(data.packed_len(), 9);

let written = data.pack_to_slice_unchecked(&mut buf);

assert_eq!(
written,
&[0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88]
);
}
6 changes: 5 additions & 1 deletion src/pdu_loop/storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,11 @@ mod tests {
let mut frame = pdu_loop.alloc_frame().expect("Allocate first frame");

frame
.push_pdu(Command::bwr(0x1000).into(), [0xaa, 0xbb, 0xcc, 0xdd], None)
.push_pdu(
Command::bwr(0x1000).into(),
[0xaau8, 0xbb, 0xcc, 0xdd],
None,
)
.unwrap();

// Drop frame future to reset its state to `FrameState::None`
Expand Down