From b4e2fa84de94b360058e558b5184dfd70a7aa72d Mon Sep 17 00:00:00 2001 From: Nicolas Stalder Date: Sun, 3 May 2020 02:17:04 +0200 Subject: [PATCH] Some ergonomics improvements --- Cargo.toml | 4 +++ src/lib.rs | 93 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 96 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 8eaf8d9..0c21324 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,6 +10,10 @@ repository = "https://github.com/ycrypto/heapless-bytes" readme = "README.md" edition = "2018" +[dependencies] +ufmt = "0.1.0" +typenum = "1.11.2" + [dependencies.heapless] version = "0.5.1" default-features = false diff --git a/src/lib.rs b/src/lib.rs index e77994b..894a087 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -14,6 +14,10 @@ use core::{ pub use heapless::consts; pub use heapless::ArrayLength; +// bring trait in scope to use `consts::Uxx::USIZE` etc., +// to get the corresponding size of Bytes. +pub use typenum::Unsigned; + use heapless::Vec; use serde::{ @@ -26,6 +30,17 @@ pub struct Bytes> { bytes: Vec, } +pub type Bytes8 = Bytes; +pub type Bytes16 = Bytes; +pub type Bytes32 = Bytes; +pub type Bytes64 = Bytes; + +impl> From> for Bytes { + fn from(vec: Vec) -> Self { + Self { bytes: vec } + } +} + impl> Bytes { /// Construct a new, empty `Bytes`. pub fn new() -> Self { @@ -49,6 +64,13 @@ impl> Bytes { self.bytes } + /// Low-noise conversion between lengths. + /// + /// We can't implement TryInto since it would clash with blanket implementations. + pub fn try_convert_into>(&self) -> Result, ()> { + Bytes::::try_from_slice(self) + } + // #[doc(hidden)] // pub fn into_iter(self) -> as IntoIterator>::IntoIter { // self.bytes.into_iter() @@ -60,6 +82,43 @@ impl> Bytes { Ok(Self::from(bytes)) } + /// Some APIs offer an interface of the form `f(&mut [u8]) -> Result`, + /// with the contract that the Ok-value signals how many bytes were written. + /// + /// This constructor allows wrapping such interfaces in a more ergonomic way, + /// returning a Bytes willed using `f`. + /// + /// It seems it's not possible to do this as an actual `TryFrom` implementation. + pub fn try_from( + f: impl FnOnce(&mut [u8]) -> core::result::Result + ) + -> core::result::Result + { + let mut data = Self::new(); + data.resize_to_capacity(); + let result = f(&mut data); + + result.map(|count| { + data.resize_default(count).unwrap(); + data + }) + } + + // pub fn try_from<'a, E>( + // f: impl FnOnce(&'a mut [u8]) -> core::result::Result<&'a mut [u8], E> + // ) + // -> core::result::Result + // { + // let mut data = Self::new(); + // data.resize_to_capacity(); + // let result = f(&mut data); + + // result.map(|count| { + // data.resize_default(count).unwrap(); + // data + // }) + // } + // cf. https://internals.rust-lang.org/t/add-vec-insert-slice-at-to-insert-the-content-of-a-slice-at-an-arbitrary-index/11008/3 pub fn insert_slice_at(&mut self, slice: &[u8], at: usize) -> core::result::Result<(), ()> { let l = slice.len(); @@ -83,7 +142,7 @@ impl> Bytes { } pub fn resize_to_capacity(&mut self) { - self.bytes.resize_default(self.bytes.len()).ok(); + self.bytes.resize_default(self.bytes.capacity()).ok(); } // pub fn deref_mut(&mut self) -> &mut [u8] { @@ -113,6 +172,26 @@ impl> Bytes { } } +// impl TryFrom for Bytes +// where +// N: ArrayLength, +// F: FnOnce(&mut [u8]) -> Result, +// { +// type Error = E; + +// fn try_from(f: F) -> Result { + +// let mut data = Self::new(); +// data.resize_to_capacity(); +// let result = f(&mut data); + +// result.map(|count| { +// data.resize_default(count).unwrap(); +// data +// }) +// } +// } + impl> Debug for Bytes { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { // TODO: There has to be a better way :'-) @@ -131,6 +210,18 @@ impl> Debug for Bytes { } } +impl ufmt::uDebug for Bytes +where + N: ArrayLength, +{ + fn fmt(&self, f: &mut ufmt::Formatter<'_, W>) -> Result<(), W::Error> + where + W: ufmt::uWrite + ?Sized, + { + <[u8] as ufmt::uDebug>::fmt(self, f) + } +} + impl> AsRef<[u8]> for Bytes { fn as_ref(&self) -> &[u8] { &self.bytes