diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index ea7beb0..4840537 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -101,5 +101,9 @@ jobs: RUSTFLAGS: "-C link-arg=-Tlink.x" CARGO_TARGET_THUMBV7M_NONE_EABI_RUNNER: "qemu-system-arm -cpu cortex-m3 -machine lm3s6965evb -nographic -semihosting-config enable=on,target=native -kernel" run: cd embedded && cargo run --target thumbv7m-none-eabi - + - name: Run with alloc + env: + RUSTFLAGS: "-C link-arg=-Tlink.x" + CARGO_TARGET_THUMBV7M_NONE_EABI_RUNNER: "qemu-system-arm -cpu cortex-m3 -machine lm3s6965evb -nographic -semihosting-config enable=on,target=native -kernel" + run: cd embedded && cargo run --target thumbv7m-none-eabi --features=alloc diff --git a/Cargo.toml b/Cargo.toml index 294df8f..0d81787 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,14 +15,19 @@ name = "bitcoin_hashes" path = "src/lib.rs" [features] -default = [ "std" ] +default = ["std"] std = [] +# If you disable std, you can still use a Write trait via the core2 feature. +# You can also use ToHex via the alloc feature, as it requires Vec/String. +# And you can still just disable std by disabling default features, without enabling these two. +alloc = ["core2/alloc"] serde-std = ["serde/std"] unstable = [] # for benchmarking [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" diff --git a/embedded/Cargo.toml b/embedded/Cargo.toml index f753bf8..eecf96d 100644 --- a/embedded/Cargo.toml +++ b/embedded/Cargo.toml @@ -5,13 +5,17 @@ readme = "README.md" name = "embedded" version = "0.1.0" +[features] +alloc = ["alloc-cortex-m", "bitcoin_hashes/alloc"] + [dependencies] cortex-m = "0.6.0" cortex-m-rt = "0.6.10" cortex-m-semihosting = "0.3.3" panic-halt = "0.2.0" -alloc-cortex-m = "0.4.1" -bitcoin_hashes = { path="../", default-features = false } +alloc-cortex-m = { version = "0.4.1", optional = true } +bitcoin_hashes = { path="../", default-features = false, features = ["core2"] } +core2 = { version = "0.3.0-alpha.1", default_features = false } [[bin]] name = "embedded" diff --git a/embedded/src/main.rs b/embedded/src/main.rs index 6b5940a..30921a0 100644 --- a/embedded/src/main.rs +++ b/embedded/src/main.rs @@ -1,17 +1,19 @@ -#![feature(alloc_error_handler)] +#![cfg_attr(feature = "alloc", feature(alloc_error_handler))] #![no_std] #![no_main] #[macro_use] extern crate bitcoin_hashes; -extern crate alloc; +#[cfg(feature = "alloc")] extern crate alloc; +#[cfg(feature = "alloc")] use alloc_cortex_m::CortexMHeap; +#[cfg(feature = "alloc")] use core::alloc::Layout; +#[cfg(feature = "alloc")] use cortex_m::asm; +#[cfg(feature = "alloc")] use bitcoin_hashes::hex::ToHex; -use alloc_cortex_m::CortexMHeap; use bitcoin_hashes::{sha256, Hash, HashEngine}; -use core::alloc::Layout; +use core2::io::Write; use core::str::FromStr; -use cortex_m::asm; use cortex_m_rt::entry; use cortex_m_semihosting::{debug, hprintln}; use panic_halt as _; @@ -19,33 +21,49 @@ use panic_halt as _; hash_newtype!(TestType, sha256::Hash, 32, doc = "test"); // this is the allocator the application will use +#[cfg(feature = "alloc")] #[global_allocator] static ALLOCATOR: CortexMHeap = CortexMHeap::empty(); +#[cfg(feature = "alloc")] const HEAP_SIZE: usize = 1024; // in bytes #[entry] fn main() -> ! { + #[cfg(feature = "alloc")] unsafe { ALLOCATOR.init(cortex_m_rt::heap_start() as usize, HEAP_SIZE) } + let mut engine = TestType::engine(); + engine.write_all(b"abc").unwrap(); + check_result(engine); + let mut engine = TestType::engine(); engine.input(b"abc"); + check_result(engine); + + debug::exit(debug::EXIT_SUCCESS); + loop {} +} + +fn check_result(engine: sha256::HashEngine) { let hash = TestType::from_engine(engine); let hash_check = TestType::from_str("ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad") .unwrap(); hprintln!("hash:{} hash_check:{}", hash, hash_check).unwrap(); - if hash == hash_check { - debug::exit(debug::EXIT_SUCCESS); - } else { + if hash != hash_check { debug::exit(debug::EXIT_FAILURE); } - loop {} + #[cfg(feature = "alloc")] + if hash.to_hex() != hash_check.to_hex() { + debug::exit(debug::EXIT_FAILURE); + } } // define what happens in an Out Of Memory (OOM) condition +#[cfg(feature = "alloc")] #[alloc_error_handler] fn alloc_error(_layout: Layout) -> ! { asm::bkpt(); diff --git a/src/hex.rs b/src/hex.rs index 8f3fb9f..d39031d 100644 --- a/src/hex.rs +++ b/src/hex.rs @@ -15,6 +15,11 @@ //! # Hex encoding and decoding //! +#[cfg(any(feature = "std", feature = "alloc"))] +use alloc::{string::String, vec::Vec}; +#[cfg(feature = "alloc")] +use alloc::format; + use core::{fmt, str}; use Hash; @@ -40,7 +45,7 @@ impl fmt::Display for Error { } /// Trait for objects that can be serialized as hex strings -#[cfg(any(test, feature = "std"))] +#[cfg(any(test, feature = "std", feature = "alloc"))] pub trait ToHex { /// Hex representation of the object fn to_hex(&self) -> String; @@ -60,7 +65,7 @@ pub trait FromHex: Sized { } } -#[cfg(any(test, feature = "std"))] +#[cfg(any(test, feature = "std", feature = "alloc"))] impl ToHex for T { /// Outputs the hash in hexadecimal form fn to_hex(&self) -> String { @@ -174,7 +179,7 @@ pub fn format_hex_reverse(data: &[u8], f: &mut fmt::Formatter) -> fmt::Result { Ok(()) } -#[cfg(any(test, feature = "std"))] +#[cfg(any(test, feature = "alloc", feature = "std"))] impl ToHex for [u8] { fn to_hex(&self) -> String { use core::fmt::Write; @@ -186,7 +191,7 @@ impl ToHex for [u8] { } } -#[cfg(any(test, feature = "std"))] +#[cfg(any(test, feature = "std", feature = "alloc"))] impl FromHex for Vec { fn from_byte_iter(iter: I) -> Result where I: Iterator> + diff --git a/src/std_impls.rs b/src/impls.rs similarity index 93% rename from src/std_impls.rs rename to src/impls.rs index aa87c30..b069e80 100644 --- a/src/std_impls.rs +++ b/src/impls.rs @@ -12,23 +12,31 @@ // If not, see . // -//! `std` Impls +//! `std` / `core2` Impls //! -//! impls of traits defined in `std` and not `core` +//! impls of traits defined in `std` / `core2` and not in `core` +#[cfg(feature = "std")] use std::{error, io}; +#[cfg(not(feature = "std"))] +use core2::{error, io}; + use {hex, sha1, sha256, sha512, ripemd160, siphash24}; use HashEngine; use Error; impl error::Error for Error { + #[cfg(feature = "std")] fn cause(&self) -> Option<&error::Error> { None } + #[cfg(feature = "std")] fn description(&self) -> &str { "`std::error::description` is deprecated" } } impl error::Error for hex::Error { + #[cfg(feature = "std")] fn cause(&self) -> Option<&error::Error> { None } + #[cfg(feature = "std")] fn description(&self) -> &str { "`std::error::description` is deprecated" } } @@ -79,7 +87,7 @@ impl io::Write for siphash24::HashEngine { #[cfg(test)] mod tests { - use std::io::Write; + use super::io::Write; use {sha1, sha256, sha256d, sha512, ripemd160, hash160, siphash24}; use Hash; diff --git a/src/lib.rs b/src/lib.rs index 11a56b5..5f10e87 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -38,6 +38,9 @@ #[cfg(all(test, feature = "unstable"))] extern crate test; #[cfg(any(test, feature="std"))] extern crate core; +#[cfg(feature="core2")] extern crate core2; +#[cfg(any(feature = "alloc"))] extern crate alloc; +#[cfg(any(feature = "std"))] use std as alloc; #[cfg(feature="serde")] pub extern crate serde; #[cfg(all(test,feature="serde"))] extern crate serde_test; @@ -53,7 +56,7 @@ pub mod _export { #[macro_use] mod util; #[macro_use] pub mod serde_macros; -#[cfg(any(test, feature = "std"))] mod std_impls; +#[cfg(any(feature = "std", feature = "core2"))] mod impls; pub mod error; pub mod hex; pub mod hash160;