Add a `bitcoin_io` crate
In order to support standard (de)serialization of structs, the `rust-bitcoin` ecosystem uses the standard `std::io::{Read,Write}` traits. This works great for environments with `std`, however sadly the `std::io` module has not yet been added to the `core` crate. Thus, in `no-std`, the `rust-bitcoin` ecosystem has historically used the `core2` crate to provide copies of the `std::io` module without any major dependencies. Sadly, its one dependency, `memchr`, recently broke our MSRV. Worse, because we didn't want to take on any excess dependencies for `std` builds, `rust-bitcoin` has had to have mutually-exclusive `std` and `no-std` builds. This breaks general assumptions about how features work in Rust, causing substantial pain for applications far downstream of `rust-bitcoin` crates. Here, we add a new `bitcoin_io` crate, making it an unconditional dependency and using its `io` module in the in-repository crates in place of `std::io` and `core2::io`. As it is not substantial additional code, the `hashes` io implementations are no longer feature-gated. This doesn't actually accomplish anything on its own, only adding the new crate which still depends on `core2`.
This commit is contained in:
parent
4fb91277f0
commit
27c7c4e26a
|
@ -38,9 +38,9 @@ dependencies = [
|
||||||
"bech32",
|
"bech32",
|
||||||
"bincode",
|
"bincode",
|
||||||
"bitcoin-internals",
|
"bitcoin-internals",
|
||||||
|
"bitcoin-io",
|
||||||
"bitcoin_hashes",
|
"bitcoin_hashes",
|
||||||
"bitcoinconsensus",
|
"bitcoinconsensus",
|
||||||
"core2",
|
|
||||||
"hex-conservative",
|
"hex-conservative",
|
||||||
"hex_lit",
|
"hex_lit",
|
||||||
"mutagen",
|
"mutagen",
|
||||||
|
@ -69,11 +69,18 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bitcoin-io"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"core2",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitcoin_hashes"
|
name = "bitcoin_hashes"
|
||||||
version = "0.13.0"
|
version = "0.13.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"core2",
|
"bitcoin-io",
|
||||||
"hex-conservative",
|
"hex-conservative",
|
||||||
"schemars",
|
"schemars",
|
||||||
"serde",
|
"serde",
|
||||||
|
|
|
@ -37,9 +37,9 @@ dependencies = [
|
||||||
"bech32",
|
"bech32",
|
||||||
"bincode",
|
"bincode",
|
||||||
"bitcoin-internals",
|
"bitcoin-internals",
|
||||||
|
"bitcoin-io",
|
||||||
"bitcoin_hashes",
|
"bitcoin_hashes",
|
||||||
"bitcoinconsensus",
|
"bitcoinconsensus",
|
||||||
"core2",
|
|
||||||
"hex-conservative",
|
"hex-conservative",
|
||||||
"hex_lit",
|
"hex_lit",
|
||||||
"mutagen",
|
"mutagen",
|
||||||
|
@ -68,11 +68,18 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bitcoin-io"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"core2",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitcoin_hashes"
|
name = "bitcoin_hashes"
|
||||||
version = "0.13.0"
|
version = "0.13.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"core2",
|
"bitcoin-io",
|
||||||
"hex-conservative",
|
"hex-conservative",
|
||||||
"schemars",
|
"schemars",
|
||||||
"serde",
|
"serde",
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
[workspace]
|
[workspace]
|
||||||
members = ["bitcoin", "hashes", "internals", "fuzz"]
|
members = ["bitcoin", "hashes", "internals", "fuzz", "io"]
|
||||||
|
|
||||||
[patch.crates-io.bitcoin]
|
[patch.crates-io.bitcoin]
|
||||||
path = "bitcoin"
|
path = "bitcoin"
|
||||||
|
@ -9,3 +9,6 @@ path = "hashes"
|
||||||
|
|
||||||
[patch.crates-io.bitcoin-internals]
|
[patch.crates-io.bitcoin-internals]
|
||||||
path = "internals"
|
path = "internals"
|
||||||
|
|
||||||
|
[patch.crates-io.bitcoin-io]
|
||||||
|
path = "io"
|
||||||
|
|
|
@ -26,8 +26,8 @@ bitcoinconsensus-std = ["bitcoinconsensus/std", "std"]
|
||||||
# The no-std feature doesn't disable std - you need to turn off the std feature for that by disabling default.
|
# The no-std feature doesn't disable std - you need to turn off the std feature for that by disabling default.
|
||||||
# Instead no-std enables additional features required for this crate to be usable without std.
|
# Instead no-std enables additional features required for this crate to be usable without std.
|
||||||
# As a result, both can be enabled without conflict.
|
# As a result, both can be enabled without conflict.
|
||||||
std = ["secp256k1/std", "hashes/std", "bech32/std", "internals/std", "hex/std"]
|
std = ["secp256k1/std", "bitcoin-io/std", "hashes/std", "bech32/std", "internals/std", "hex/std"]
|
||||||
no-std = ["core2", "hashes/alloc", "hashes/core2", "bech32/alloc", "secp256k1/alloc", "hex/alloc", "hex/core2"]
|
no-std = ["hashes/alloc", "hashes/core2", "bitcoin-io/core2", "bitcoin-io/alloc", "bech32/alloc", "secp256k1/alloc", "hex/alloc", "hex/core2"]
|
||||||
|
|
||||||
[package.metadata.docs.rs]
|
[package.metadata.docs.rs]
|
||||||
all-features = true
|
all-features = true
|
||||||
|
@ -41,12 +41,12 @@ hashes = { package = "bitcoin_hashes", version = "0.13.0", default-features = fa
|
||||||
secp256k1 = { version = "0.28.0", default-features = false, features = ["hashes"] }
|
secp256k1 = { version = "0.28.0", default-features = false, features = ["hashes"] }
|
||||||
hex_lit = "0.1.1"
|
hex_lit = "0.1.1"
|
||||||
|
|
||||||
|
bitcoin-io = { version = "0.1", default-features = false }
|
||||||
|
|
||||||
base64 = { version = "0.21.3", optional = true }
|
base64 = { version = "0.21.3", optional = true }
|
||||||
# Only use this feature for no-std builds, otherwise use bitcoinconsensus-std.
|
# Only use this feature for no-std builds, otherwise use bitcoinconsensus-std.
|
||||||
bitcoinconsensus = { version = "0.20.2-0.5.0", default-features = false, optional = true }
|
bitcoinconsensus = { version = "0.20.2-0.5.0", default-features = false, optional = true }
|
||||||
|
|
||||||
# There is no reason to use this dependency directly, it is activated by the "no-std" feature.
|
|
||||||
core2 = { version = "0.3.2", default-features = false, features = ["alloc"], optional = true }
|
|
||||||
# Do NOT use this as a feature! Use the `serde` feature instead.
|
# Do NOT use this as a feature! Use the `serde` feature instead.
|
||||||
actual-serde = { package = "serde", version = "1.0.103", default-features = false, features = [ "derive", "alloc" ], optional = true }
|
actual-serde = { package = "serde", version = "1.0.103", default-features = false, features = [ "derive", "alloc" ], optional = true }
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,6 @@ panic-halt = "0.2.0"
|
||||||
alloc-cortex-m = "0.4.1"
|
alloc-cortex-m = "0.4.1"
|
||||||
bitcoin = { path="../", default-features = false, features = ["no-std", "secp-lowmemory"] }
|
bitcoin = { path="../", default-features = false, features = ["no-std", "secp-lowmemory"] }
|
||||||
|
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "embedded"
|
name = "embedded"
|
||||||
test = false
|
test = false
|
||||||
|
@ -33,3 +32,6 @@ path = "../../hashes"
|
||||||
|
|
||||||
[patch.crates-io.bitcoin-internals]
|
[patch.crates-io.bitcoin-internals]
|
||||||
path = "../../internals"
|
path = "../../internals"
|
||||||
|
|
||||||
|
[patch.crates-io.bitcoin-io]
|
||||||
|
path = "../../io"
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
//! deserialization.
|
//! deserialization.
|
||||||
//! * `secp-lowmemory` - optimizations for low-memory devices.
|
//! * `secp-lowmemory` - optimizations for low-memory devices.
|
||||||
//! * `no-std` - enables additional features required for this crate to be usable
|
//! * `no-std` - enables additional features required for this crate to be usable
|
||||||
//! without std. Does **not** disable `std`. Depends on `core2`.
|
//! without std. Does **not** disable `std`.
|
||||||
//! * `bitcoinconsensus-std` - enables `std` in `bitcoinconsensus` and communicates it
|
//! * `bitcoinconsensus-std` - enables `std` in `bitcoinconsensus` and communicates it
|
||||||
//! to this crate so it knows how to implement
|
//! to this crate so it knows how to implement
|
||||||
//! `std::error::Error`. At this time there's a hack to
|
//! `std::error::Error`. At this time there's a hack to
|
||||||
|
@ -68,9 +68,6 @@ pub extern crate bech32;
|
||||||
/// Bitcoin's libbitcoinconsensus with Rust binding.
|
/// Bitcoin's libbitcoinconsensus with Rust binding.
|
||||||
pub extern crate bitcoinconsensus;
|
pub extern crate bitcoinconsensus;
|
||||||
|
|
||||||
#[cfg(not(feature = "std"))]
|
|
||||||
extern crate core2;
|
|
||||||
|
|
||||||
/// Rust implementation of cryptographic hash function algorithems.
|
/// Rust implementation of cryptographic hash function algorithems.
|
||||||
pub extern crate hashes;
|
pub extern crate hashes;
|
||||||
|
|
||||||
|
@ -118,16 +115,8 @@ pub mod taproot;
|
||||||
|
|
||||||
// May depend on crate features and we don't want to bother with it
|
// May depend on crate features and we don't want to bother with it
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
#[cfg(feature = "std")]
|
use bitcoin_io::error::Error as StdError;
|
||||||
use std::error::Error as StdError;
|
use bitcoin_io::io;
|
||||||
#[cfg(feature = "std")]
|
|
||||||
use std::io;
|
|
||||||
|
|
||||||
#[allow(unused)]
|
|
||||||
#[cfg(not(feature = "std"))]
|
|
||||||
use core2::error::Error as StdError;
|
|
||||||
#[cfg(not(feature = "std"))]
|
|
||||||
use core2::io;
|
|
||||||
|
|
||||||
pub use crate::address::{Address, AddressType};
|
pub use crate::address::{Address, AddressType};
|
||||||
pub use crate::amount::{Amount, Denomination, SignedAmount};
|
pub use crate::amount::{Amount, Denomination, SignedAmount};
|
||||||
|
@ -163,6 +152,8 @@ pub use crate::taproot::{
|
||||||
|
|
||||||
#[cfg(not(feature = "std"))]
|
#[cfg(not(feature = "std"))]
|
||||||
mod io_extras {
|
mod io_extras {
|
||||||
|
use crate::io;
|
||||||
|
|
||||||
/// A writer which will move data into the void.
|
/// A writer which will move data into the void.
|
||||||
pub struct Sink {
|
pub struct Sink {
|
||||||
_priv: (),
|
_priv: (),
|
||||||
|
@ -171,12 +162,12 @@ mod io_extras {
|
||||||
/// Creates an instance of a writer which will successfully consume all data.
|
/// Creates an instance of a writer which will successfully consume all data.
|
||||||
pub const fn sink() -> Sink { Sink { _priv: () } }
|
pub const fn sink() -> Sink { Sink { _priv: () } }
|
||||||
|
|
||||||
impl core2::io::Write for Sink {
|
impl io::Write for Sink {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn write(&mut self, buf: &[u8]) -> core2::io::Result<usize> { Ok(buf.len()) }
|
fn write(&mut self, buf: &[u8]) -> io::Result<usize> { Ok(buf.len()) }
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn flush(&mut self) -> core2::io::Result<()> { Ok(()) }
|
fn flush(&mut self) -> io::Result<()> { Ok(()) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,11 +14,11 @@ exclude = ["tests", "contrib"]
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["std"]
|
default = ["std"]
|
||||||
std = ["alloc", "hex/std"]
|
std = ["alloc", "hex/std", "bitcoin-io/std"]
|
||||||
alloc = ["hex/alloc"]
|
alloc = ["hex/alloc"]
|
||||||
serde-std = ["serde/std"]
|
serde-std = ["serde/std"]
|
||||||
# If you want I/O you must enable either "std" or "core2".
|
# If you want I/O you must enable either "std" or "core2".
|
||||||
core2 = ["actual-core2", "hex/core2"]
|
core2 = ["bitcoin-io/core2", "hex/core2"]
|
||||||
# Smaller (but slower) implementation of sha256, sha512 and ripemd160
|
# Smaller (but slower) implementation of sha256, sha512 and ripemd160
|
||||||
small-hash = []
|
small-hash = []
|
||||||
|
|
||||||
|
@ -29,13 +29,12 @@ rustdoc-args = ["--cfg", "docsrs"]
|
||||||
[dependencies]
|
[dependencies]
|
||||||
hex = { package = "hex-conservative", version = "0.1.1", default-features = false }
|
hex = { package = "hex-conservative", version = "0.1.1", default-features = false }
|
||||||
|
|
||||||
|
bitcoin-io = { version = "0.1", default-features = false, optional = true }
|
||||||
|
|
||||||
schemars = { version = "0.8.3", optional = true }
|
schemars = { version = "0.8.3", optional = true }
|
||||||
# Only enable this if you explicitly do not want to use "std", otherwise enable "serde-std".
|
# Only enable this if you explicitly do not want to use "std", otherwise enable "serde-std".
|
||||||
serde = { version = "1.0", default-features = false, optional = true }
|
serde = { version = "1.0", default-features = false, optional = true }
|
||||||
|
|
||||||
# Do NOT use this feature! Use the "core2" feature instead.
|
|
||||||
actual-core2 = { package = "core2", version = "0.3.2", default-features = false, optional = true }
|
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
serde_test = "1.0"
|
serde_test = "1.0"
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
|
|
|
@ -19,7 +19,7 @@ cortex-m-semihosting = "0.3.3"
|
||||||
panic-halt = "0.2.0"
|
panic-halt = "0.2.0"
|
||||||
alloc-cortex-m = { version = "0.4.1", optional = true }
|
alloc-cortex-m = { version = "0.4.1", optional = true }
|
||||||
bitcoin_hashes = { path="../", default-features = false, features = ["core2"] }
|
bitcoin_hashes = { path="../", default-features = false, features = ["core2"] }
|
||||||
core2 = { version = "0.3.0", default_features = false }
|
bitcoin-io = { path = "../../io", default_features = false }
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "embedded"
|
name = "embedded"
|
||||||
|
@ -33,3 +33,6 @@ lto = true # better optimizations
|
||||||
|
|
||||||
[patch.crates-io.bitcoin-internals]
|
[patch.crates-io.bitcoin-internals]
|
||||||
path = "../../internals"
|
path = "../../internals"
|
||||||
|
|
||||||
|
[patch.crates-io.bitcoin-io]
|
||||||
|
path = "../../io"
|
||||||
|
|
|
@ -10,7 +10,7 @@ extern crate bitcoin_hashes;
|
||||||
#[cfg(feature = "alloc")] use alloc::string::ToString;
|
#[cfg(feature = "alloc")] use alloc::string::ToString;
|
||||||
|
|
||||||
use bitcoin_hashes::{sha256, Hash, HashEngine};
|
use bitcoin_hashes::{sha256, Hash, HashEngine};
|
||||||
use core2::io::Write;
|
use bitcoin_io::io::Write;
|
||||||
use core::str::FromStr;
|
use core::str::FromStr;
|
||||||
use cortex_m_rt::entry;
|
use cortex_m_rt::entry;
|
||||||
use cortex_m_semihosting::{debug, hprintln};
|
use cortex_m_semihosting::{debug, hprintln};
|
||||||
|
|
|
@ -21,3 +21,6 @@ serde_json = "1.0"
|
||||||
|
|
||||||
[patch.crates-io.bitcoin-internals]
|
[patch.crates-io.bitcoin-internals]
|
||||||
path = "../../../internals"
|
path = "../../../internals"
|
||||||
|
|
||||||
|
[patch.crates-io.bitcoin-io]
|
||||||
|
path = "../../../io"
|
||||||
|
|
|
@ -81,8 +81,6 @@
|
||||||
// Exclude clippy lints we don't think are valuable
|
// Exclude clippy lints we don't think are valuable
|
||||||
#![allow(clippy::needless_question_mark)] // https://github.com/rust-bitcoin/rust-bitcoin/pull/2134
|
#![allow(clippy::needless_question_mark)] // https://github.com/rust-bitcoin/rust-bitcoin/pull/2134
|
||||||
|
|
||||||
#[cfg(all(not(test), not(feature = "std"), feature = "core2"))]
|
|
||||||
extern crate actual_core2 as core2;
|
|
||||||
#[cfg(all(feature = "alloc", not(feature = "std")))]
|
#[cfg(all(feature = "alloc", not(feature = "std")))]
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
#[cfg(any(test, feature = "std"))]
|
#[cfg(any(test, feature = "std"))]
|
||||||
|
@ -119,7 +117,7 @@ pub mod serde_macros;
|
||||||
pub mod cmp;
|
pub mod cmp;
|
||||||
pub mod hash160;
|
pub mod hash160;
|
||||||
pub mod hmac;
|
pub mod hmac;
|
||||||
#[cfg(any(test, feature = "std", feature = "core2"))]
|
#[cfg(feature = "bitcoin-io")]
|
||||||
mod impls;
|
mod impls;
|
||||||
pub mod ripemd160;
|
pub mod ripemd160;
|
||||||
pub mod sha1;
|
pub mod sha1;
|
||||||
|
@ -131,12 +129,10 @@ pub mod sha512_256;
|
||||||
pub mod siphash24;
|
pub mod siphash24;
|
||||||
|
|
||||||
use core::{borrow, fmt, hash, ops};
|
use core::{borrow, fmt, hash, ops};
|
||||||
// You get I/O if you enable "std" or "core2" (as well as during testing).
|
|
||||||
#[cfg(any(test, feature = "std"))]
|
|
||||||
use std::io;
|
|
||||||
|
|
||||||
#[cfg(all(not(test), not(feature = "std"), feature = "core2"))]
|
// You get I/O if you enable "std" or "core2" (as well as during testing).
|
||||||
use core2::io;
|
#[cfg(feature = "bitcoin-io")]
|
||||||
|
use bitcoin_io::io;
|
||||||
pub use hmac::{Hmac, HmacEngine};
|
pub use hmac::{Hmac, HmacEngine};
|
||||||
|
|
||||||
/// A hashing engine which bytes can be serialized into.
|
/// A hashing engine which bytes can be serialized into.
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
[package]
|
||||||
|
name = "bitcoin-io"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Matt Corallo <birchneutea@mattcorallo.com>"]
|
||||||
|
license = "CC0-1.0"
|
||||||
|
repository = "https://github.com/rust-bitcoin/rust-bitcoin"
|
||||||
|
documentation = "https://docs.rs/bitcoin-io/"
|
||||||
|
description = "Simple I/O traits for no-std (and std) environments"
|
||||||
|
categories = ["no-std"]
|
||||||
|
keywords = [ "io", "no-std" ]
|
||||||
|
readme = "README.md"
|
||||||
|
edition = "2018"
|
||||||
|
exclude = ["tests", "contrib"]
|
||||||
|
|
||||||
|
[features]
|
||||||
|
default = ["std"]
|
||||||
|
std = []
|
||||||
|
alloc = ["core2/alloc"]
|
||||||
|
|
||||||
|
[package.metadata.docs.rs]
|
||||||
|
all-features = true
|
||||||
|
rustdoc-args = ["--cfg", "docsrs"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
core2 = { version = "0.3", default-features = false, optional = true }
|
|
@ -0,0 +1,32 @@
|
||||||
|
//! Rust-Bitcoin IO Library
|
||||||
|
//!
|
||||||
|
//! Because the core `std::io` module is not yet exposed in `no-std` Rust, building `no-std`
|
||||||
|
//! applications which require reading and writing objects via standard traits is not generally
|
||||||
|
//! possible. While there is ongoing work to improve this situation, this module is not likely to
|
||||||
|
//! be available for applications with broad rustc version support for some time.
|
||||||
|
//!
|
||||||
|
//! Thus, this library exists to export a minmal version of `std::io`'s traits which `no-std`
|
||||||
|
//! applications may need. With the `std` feature, these traits are also implemented for the
|
||||||
|
//! `std::io` traits, allowing standard objects to be used wherever the traits from this crate are
|
||||||
|
//! required.
|
||||||
|
//!
|
||||||
|
//! This traits are not one-for-one drop-ins, but are as close as possible while still implementing
|
||||||
|
//! `std::io`'s traits without unnecessary complexity.
|
||||||
|
|
||||||
|
// Experimental features we need.
|
||||||
|
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
|
||||||
|
|
||||||
|
#![cfg_attr(not(feature = "std"), no_std)]
|
||||||
|
|
||||||
|
#[cfg(all(not(feature = "std"), not(feature = "core2")))]
|
||||||
|
compile_error!("At least one of std or core2 must be enabled");
|
||||||
|
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
pub use std::io;
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
pub use std::error;
|
||||||
|
|
||||||
|
#[cfg(not(feature = "std"))]
|
||||||
|
pub use core2::io;
|
||||||
|
#[cfg(not(feature = "std"))]
|
||||||
|
pub use core2::error;
|
Loading…
Reference in New Issue