Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a tool for writing descriptors with lengths not known at compile time #46

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
112 changes: 112 additions & 0 deletions src/descriptor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,104 @@ pub struct DescriptorWriter<'a> {
write_iads: bool,
}

/// Write arbitrary sequences of bytes to descriptors with tools for delayed length writing
/// If there is an error it is delayed until the end of writing when finish is called
pub struct ByteWriter<'a, 'b> {
parent_writer: &'a mut DescriptorWriter<'b>,
result: Result<()>,
}

impl<'a, 'b> ByteWriter<'a, 'b> {
fn new(parent: &'a mut DescriptorWriter<'b>) -> Self {
ByteWriter {
parent_writer: parent,
result: Ok(()),
}
}

/// Write a single byte
pub fn byte(&mut self, b: u8) -> &mut Self {
if self.result.is_ok() {
let mut parent = &mut self.parent_writer;
if (parent.position + 1) >= parent.buf.len() {
self.result = Err(UsbError::BufferOverflow);
return self; // Delayed Error
}

parent.buf[parent.position] = b;
parent.position += 1;
}
self
}

/// Write a slice of bytes
pub fn arr(&mut self, bs: &[u8]) -> &mut Self {
if self.result.is_ok() {
let mut parent = &mut self.parent_writer;
let length = bs.len();
if (parent.position + length) >= parent.buf.len() {
self.result = Err(UsbError::BufferOverflow);
return self; // Delayed Error
}

let start = parent.position;
parent.buf[start..start + length].copy_from_slice(bs);
parent.position += length;
}
self
}

/// current position in the parent buffer
pub fn position(&self) -> usize {
self.parent_writer.position
}

/// Rserve space, do some writes, produce a value, then write something in that space using that value
pub fn delayed_write<W, V, D>(&mut self, size: usize, w: W, delayed: D) -> &mut Self
where
W: FnOnce(&mut ByteWriter<'_, '_>) -> V,
D: FnOnce(&mut [u8], V),
{
if self.result.is_ok() {
if (self.parent_writer.position + size) >= self.parent_writer.buf.len() {
self.result = Err(UsbError::BufferOverflow);
return self; // Delayed Error
}

let start = self.parent_writer.position;
self.parent_writer.position += size;

let v = w(self);
delayed(&mut self.parent_writer.buf[start..start + size], v);
}

self
}

/// Store the current position and advance by 1, write some bytes
/// then when leaving the functon write the length of those bytes, including the length byte
pub fn delayed_length<W>(&mut self, w: W) -> &mut Self
where
W: FnOnce(&mut ByteWriter<'_, '_>),
{
let start = self.position();
self.delayed_write(
1,
|bw| {
w(bw);
(bw.position() - start) as u8
},
|buf, length| buf[0] = length,
);
self
}

#[must_use]
fn finish(self) -> Result<()> {
self.result
}
}

impl DescriptorWriter<'_> {
pub(crate) fn new(buf: &mut [u8]) -> DescriptorWriter<'_> {
DescriptorWriter {
Expand Down Expand Up @@ -79,6 +177,20 @@ impl DescriptorWriter<'_> {
Ok(())
}

/// Write an arbiutrary sequence of bytes without needing to know the length at compile time
pub fn writer<W>(&mut self, w: W) -> Result<()>
where
W: FnOnce(&mut ByteWriter<'_, '_>),
{
if self.position > self.buf.len() {
return Err(UsbError::BufferOverflow);
}

let mut bb = ByteWriter::new(self);
w(&mut bb);
bb.finish()
}

pub(crate) fn device(&mut self, config: &device::Config) -> Result<()> {
self.write(
descriptor_type::DEVICE,
Expand Down