diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 8f584268d..41e38cfc1 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -63,3 +63,24 @@ jobs: with: command: clippy args: -- -D warnings + + Embedded: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + - name: Set up QEMU + run: sudo apt install qemu-system-arm + - name: Checkout Toolchain + uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: nightly + override: true + components: rust-src + target: thumbv7m-none-eabi + - name: Run + 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 diff --git a/.gitignore b/.gitignore index f20e818c7..15df54398 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ **/target *.o /Cargo.lock + +/embedded/Cargo.lock +/embedded/.cargo diff --git a/Cargo.toml b/Cargo.toml index a8838366f..31ff3a176 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,6 +10,8 @@ categories = ["encoding"] license = "MIT" [features] +default = ["std"] +std = [] # Only for CI to make all warnings errors, do not activate otherwise (may break forward compatibility) strict = [] diff --git a/embedded/Cargo.toml b/embedded/Cargo.toml new file mode 100644 index 000000000..d2aaf6079 --- /dev/null +++ b/embedded/Cargo.toml @@ -0,0 +1,24 @@ +[package] +authors = ["Riccardo Casatta "] +edition = "2018" +readme = "README.md" +name = "embedded" +version = "0.1.0" + +[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" +bech32 = { path="../", default-features = false } + +[[bin]] +name = "embedded" +test = false +bench = false + +[profile.release] +codegen-units = 1 # better optimizations +debug = true # symbols are nice and they don't increase the size on Flash +lto = true # better optimizations diff --git a/embedded/memory.x b/embedded/memory.x new file mode 100644 index 000000000..3b91d8dea --- /dev/null +++ b/embedded/memory.x @@ -0,0 +1,6 @@ +MEMORY +{ + + FLASH : ORIGIN = 0x00000000, LENGTH = 256K + RAM : ORIGIN = 0x20000000, LENGTH = 64K +} diff --git a/embedded/src/main.rs b/embedded/src/main.rs new file mode 100644 index 000000000..8f9fbcf83 --- /dev/null +++ b/embedded/src/main.rs @@ -0,0 +1,62 @@ +#![feature(alloc_error_handler)] +#![no_main] +#![no_std] + +extern crate alloc; +use panic_halt as _; + +use self::alloc::string::ToString; +use self::alloc::vec; +use self::alloc::vec::Vec; +use core::alloc::Layout; + +use alloc_cortex_m::CortexMHeap; +use bech32::{self, FromBase32, ToBase32, Variant}; +use cortex_m::asm; +use cortex_m_rt::entry; +use cortex_m_semihosting::{debug, hprintln}; + +#[global_allocator] +static ALLOCATOR: CortexMHeap = CortexMHeap::empty(); + +const HEAP_SIZE: usize = 1024; // in bytes + +#[entry] +fn main() -> ! { + // Initialize the allocator BEFORE you use it + unsafe { ALLOCATOR.init(cortex_m_rt::heap_start() as usize, HEAP_SIZE) } + + let encoded = bech32::encode( + "bech32", + vec![0x00, 0x01, 0x02].to_base32(), + Variant::Bech32, + ) + .unwrap(); + test(encoded == "bech321qqqsyrhqy2a".to_string()); + + hprintln!("{}", encoded).unwrap(); + + let (hrp, data, variant) = bech32::decode(&encoded).unwrap(); + test(hrp == "bech32"); + test(Vec::::from_base32(&data).unwrap() == vec![0x00, 0x01, 0x02]); + test(variant == Variant::Bech32); + + debug::exit(debug::EXIT_SUCCESS); + + loop {} +} + +fn test(result: bool) { + if !result { + debug::exit(debug::EXIT_FAILURE); + } +} + +// define what happens in an Out Of Memory (OOM) condition +#[alloc_error_handler] +fn alloc_error(layout: Layout) -> ! { + hprintln!("{:?}", layout); + asm::bkpt(); + + loop {} +} diff --git a/src/lib.rs b/src/lib.rs index 715d242e9..aec5f454c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -29,19 +29,21 @@ //! The original description in [BIP-0173](https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki) //! has more details. //! -//! # Examples -//! -//! ``` -//! use bech32::{self, FromBase32, ToBase32, Variant}; -//! -//! let encoded = bech32::encode("bech32", vec![0x00, 0x01, 0x02].to_base32(), Variant::Bech32).unwrap(); -//! assert_eq!(encoded, "bech321qqqsyrhqy2a".to_string()); -//! -//! let (hrp, data, variant) = bech32::decode(&encoded).unwrap(); -//! assert_eq!(hrp, "bech32"); -//! assert_eq!(Vec::::from_base32(&data).unwrap(), vec![0x00, 0x01, 0x02]); -//! assert_eq!(variant, Variant::Bech32); -//! ``` +#![cfg_attr( + feature = "std", + doc = " +# Examples +``` +use bech32::{self, FromBase32, ToBase32, Variant}; +let encoded = bech32::encode(\"bech32\", vec![0x00, 0x01, 0x02].to_base32(), Variant::Bech32).unwrap(); +assert_eq!(encoded, \"bech321qqqsyrhqy2a\".to_string()); +let (hrp, data, variant) = bech32::decode(&encoded).unwrap(); +assert_eq!(hrp, \"bech32\"); +assert_eq!(Vec::::from_base32(&data).unwrap(), vec![0x00, 0x01, 0x02]); +assert_eq!(variant, Variant::Bech32); +``` +" +)] //! // Allow trait objects without dyn on nightly and make 1.22 ignore the unknown lint @@ -53,13 +55,23 @@ #![deny(non_snake_case)] #![deny(unused_mut)] #![cfg_attr(feature = "strict", deny(warnings))] +#![cfg_attr(all(not(feature = "std"), not(test)), no_std)] + +#[cfg(all(not(feature = "std"), not(test)))] +extern crate alloc; + +#[cfg(any(test, feature = "std"))] +extern crate core; + +#[cfg(all(not(feature = "std"), not(test)))] +use alloc::{string::String, vec::Vec}; +#[cfg(all(not(feature = "std"), not(test)))] +use alloc::borrow::Cow; +#[cfg(any(feature = "std", test))] use std::borrow::Cow; -use std::{error, fmt}; -// AsciiExt is needed for Rust 1.14 but not for newer versions -#[allow(unused_imports, deprecated)] -use std::ascii::AsciiExt; +use core::{fmt, mem}; /// Integer in the range `0..32` #[derive(PartialEq, Eq, Debug, Copy, Clone, Default, PartialOrd, Ord, Hash)] @@ -169,7 +181,7 @@ impl<'a> Bech32Writer<'a> { /// Write out the checksum at the end. If this method isn't called this will happen on drop. pub fn finalize(mut self) -> fmt::Result { self.inner_finalize()?; - std::mem::forget(self); + mem::forget(self); Ok(()) } @@ -626,7 +638,8 @@ impl fmt::Display for Error { } } -impl error::Error for Error { +#[cfg(any(feature = "std", test))] +impl std::error::Error for Error { fn description(&self) -> &str { match *self { Error::MissingSeparator => "missing human-readable separator",