Skip to content
This repository was archived by the owner on Nov 30, 2022. It is now read-only.

new literacy::{Read, Write} traits to handle std/no_std (alternative) #127

Closed
wants to merge 14 commits into from
Closed
Show file tree
Hide file tree
Changes from 2 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
1 change: 1 addition & 0 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ jobs:
- 1.29.0
- beta
- stable
fail-fast: false
steps:
- name: Checkout Crate
uses: actions/checkout@v2
Expand Down
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,12 @@ default = [ "std" ]
std = []
serde-std = ["serde/std"]
unstable = [] # for benchmarking
use-core2 = ["core2"]

[dependencies]
serde = { version = "1.0", default-features = false, optional = true }
schemars = { version = "0.8.0", optional = true }
core2 = { version="0.3.0-alpha.1", optional= true, default-features = false }

[dev-dependencies]
serde_test = "1.0"
Expand Down
5 changes: 3 additions & 2 deletions embedded/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ extern crate bitcoin_hashes;
extern crate alloc;

use alloc_cortex_m::CortexMHeap;
use bitcoin_hashes::{sha256, Hash, HashEngine};
use bitcoin_hashes::{sha256, Hash};
use bitcoin_hashes::literacy::Write;
use core::alloc::Layout;
use core::str::FromStr;
use cortex_m::asm;
Expand All @@ -29,7 +30,7 @@ fn main() -> ! {
unsafe { ALLOCATOR.init(cortex_m_rt::heap_start() as usize, HEAP_SIZE) }

let mut engine = TestType::engine();
engine.input(b"abc");
engine.write(b"abc").unwrap();
let hash = TestType::from_engine(engine);

let hash_check =
Expand Down
60 changes: 34 additions & 26 deletions src/std_impls.rs → src/impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,71 +16,79 @@
//!
//! impls of traits defined in `std` and not `core`

use std::{error, io};
use {sha1, sha256, sha512, ripemd160, siphash24};
use ::{HashEngine, literacy};

use {hex, sha1, sha256, sha512, ripemd160, siphash24};
use HashEngine;
use Error;

impl error::Error for Error {
fn cause(&self) -> Option<&error::Error> { None }
#[cfg(any(test, feature = "std"))]
impl ::std::error::Error for ::Error {
fn cause(&self) -> Option<&::std::error::Error> { None }
fn description(&self) -> &str { "`std::error::description` is deprecated" }
}

impl error::Error for hex::Error {
fn cause(&self) -> Option<&error::Error> { None }
#[cfg(any(test, feature = "std"))]
impl ::std::error::Error for ::hex::Error {
fn cause(&self) -> Option<&::std::error::Error> { None }
fn description(&self) -> &str { "`std::error::description` is deprecated" }
}

impl io::Write for sha1::HashEngine {
fn flush(&mut self) -> io::Result<()> { Ok(()) }
impl literacy::Write for sha1::HashEngine {
type Error = ();

fn flush(&mut self) -> ::core::result::Result<(), ()> { Ok(()) }

fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
fn write(&mut self, buf: &[u8]) -> ::core::result::Result<usize, ()> {
self.input(buf);
Ok(buf.len())
}
}

impl io::Write for sha256::HashEngine {
fn flush(&mut self) -> io::Result<()> { Ok(()) }
impl literacy::Write for sha256::HashEngine {
type Error = ();

fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
fn flush(&mut self) -> ::core::result::Result<(), ()> { Ok(()) }

fn write(&mut self, buf: &[u8]) -> ::core::result::Result<usize, ()> {
self.input(buf);
Ok(buf.len())
}
}

impl io::Write for sha512::HashEngine {
fn flush(&mut self) -> io::Result<()> { Ok(()) }
impl literacy::Write for sha512::HashEngine {
type Error = ();

fn flush(&mut self) -> ::core::result::Result<(), ()> { Ok(()) }

fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
fn write(&mut self, buf: &[u8]) -> ::core::result::Result<usize, ()> {
self.input(buf);
Ok(buf.len())
}
}

impl io::Write for ripemd160::HashEngine {
fn flush(&mut self) -> io::Result<()> { Ok(()) }
impl literacy::Write for ripemd160::HashEngine {
type Error = ();

fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
fn flush(&mut self) -> ::core::result::Result<(), ()> { Ok(()) }

fn write(&mut self, buf: &[u8]) -> ::core::result::Result<usize, ()> {
self.input(buf);
Ok(buf.len())
}
}

impl io::Write for siphash24::HashEngine {
fn flush(&mut self) -> io::Result<()> { Ok(()) }
impl literacy::Write for siphash24::HashEngine {
type Error = ();

fn flush(&mut self) -> ::core::result::Result<(), ()> { Ok(()) }

fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
fn write(&mut self, buf: &[u8]) -> ::core::result::Result<usize, ()> {
self.input(buf);
Ok(buf.len())
}
}

#[cfg(test)]
mod tests {
use std::io::Write;

use ::literacy::Write;
use {sha1, sha256, sha256d, sha512, ripemd160, hash160, siphash24};
use Hash;

Expand Down
5 changes: 3 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
#![deny(non_camel_case_types)]
#![deny(non_snake_case)]
#![deny(unused_mut)]
#![deny(missing_docs)]
//#![deny(missing_docs)]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I hope you didn't intend to land this :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed, and added doc where missing in 8bf2f9e


// In general, rust is absolutely horrid at supporting users doing things like,
// for example, compiling Rust code for real environments. Disable useless lints
Expand Down Expand Up @@ -53,7 +53,7 @@ pub mod _export {

#[macro_use] mod util;
#[macro_use] pub mod serde_macros;
#[cfg(any(test, feature = "std"))] mod std_impls;
mod impls;
pub mod error;
pub mod hex;
pub mod hash160;
Expand All @@ -66,6 +66,7 @@ pub mod sha256t;
pub mod siphash24;
pub mod sha512;
pub mod cmp;
pub mod literacy;

use core::{borrow, fmt, hash, ops};

Expand Down
123 changes: 123 additions & 0 deletions src/literacy.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
#[cfg(all(feature = "std", feature = "use-core2"))]
compile_error!("feature \"std\" and \"use-core2\" cannot be enabled together.");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should "default" to core2 in this case - if we already are building against the core2 dep, we might as well just assume the user set core2/std and then the core2 impl is the same as doing the std impl.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree but there are some implementation issue, in particular

we might as well just assume the user set core2/std

How so? with another feature use-core2-std = ["core2/std"]? This would cause other issues in feature combinations...
The other option, using std = ["core2/std"] will cause problem in default features compilation on rust 1.29

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

like you said in chat....

ugh, I wish there were a way in cargo.toml to say "if core2 && std -> require core2/std"

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How so? with another feature use-core2-std = ["core2/std"]? This would cause other issues in feature combinations...

We don't have to specify it ourselves for core2/std to be enabled by some other dependency path. Its probably neater to just impl for std and not core2 than to compile-error, and if users intended to use core2 they can always fix it by, themselves, directly requiring core2/std. This avoids the issue of having some crate that depends on A and B and A enables std and B enables core2, giving the user no way to fix the issue aside from patching either A or B.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, removed the compile_error and implementing std impl only if there is std but not core2



pub trait Read{
type Error;
fn read(&mut self, buf: &mut [u8]) -> ::core::result::Result<usize, Self::Error>;
}

pub trait Write {
type Error;
fn write(&mut self, buf: &[u8]) -> ::core::result::Result<usize, Self::Error>;
fn flush(&mut self) -> ::core::result::Result<(), Self::Error>;
fn write_all(&mut self, mut buf: &[u8]) -> ::core::result::Result<(), Self::Error> {
while !buf.is_empty() {
match self.write(buf) {
/*Ok(0) => {
return Err(Error::new(ErrorKind::WriteZero, "failed to write whole buffer"));
}*/
Ok(n) => buf = &buf[n..],
//Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
Err(e) => return Err(e),
}
}
Ok(())
}
}

#[cfg(feature = "std")]
mod std_impl {
use super::{Read, Write};

impl<R: ::std::io::Read> Read for R {
type Error = ::std::io::Error;

fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
Ok(<Self as ::std::io::Read>::read(self, buf)?)
}
}

impl<W: ::std::io::Write> Write for W {
type Error = ::std::io::Error;

fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
<Self as ::std::io::Write>::write(self, buf)
}

fn flush(&mut self) -> Result<(), Self::Error> {
<Self as ::std::io::Write>::flush(self)
}
}
}

#[cfg(feature = "use-core2")]
mod core2_impl {
use super::{Read, Write};

impl<R: core2::io::Read> Read for R {
type Error = core2::io::Error;

fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
Ok(<Self as core2::io::Read>::read(self, buf)?)
}
}

impl<W: core2::io::Write> Write for W {
type Error = core2::io::Error;

fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
Ok(<Self as core2::io::Write>::write(self, buf)?)
}

fn flush(&mut self) -> Result<(), Self::Error> {
Ok(<Self as core2::io::Write>::flush(self)?)
}
}
}

#[cfg(test)]
mod tests {

#[cfg(feature = "std")]
mod std_test {
use ::literacy::{Read, Write};

#[test]
fn test_std_read() {
let mut cursor = ::std::io::Cursor::new(vec![10u8]);
let mut buf = [0u8; 1];
cursor.read(&mut buf).unwrap();
assert_eq!(buf, [10u8]);
}

#[test]
fn test_std_write() {
let mut cursor = ::std::io::Cursor::new(vec![]);
let mut buf = [10u8; 1];
cursor.write(&mut buf).unwrap();
assert_eq!(cursor.into_inner(), vec![10u8]);
}
}

#[cfg(feature = "use-core2")]
mod tests {
use ::literacy::{Read, Write};

#[test]
fn test_core2_read() {
let mut cursor = core2::io::Cursor::new(vec![10u8]);
let mut buf = [0u8; 1];
cursor.read(&mut buf).unwrap();
assert_eq!(buf, [10u8]);
}

#[test]
fn test_core2_write() {
let mut cursor = core2::io::Cursor::new(vec![]);
let mut buf = [10u8; 1];
cursor.write(&mut buf).unwrap();
assert_eq!(cursor.into_inner(), vec![10u8]);
}
}
}