Merge rust-bitcoin/rust-bitcoin#2066: Add a `bitcoin-io` crate
add371d263
Remove `core2` dependency entirely (Matt Corallo)b7dd16da99
[IO] Use our own io::Error type (Matt Corallo)c95b59327a
Explicitly use `std::io::Error` when implementing `std` traits (Matt Corallo)9e1cd372cb
Use `io::Error::get_ref()` over `std::error::Error::source()` (Matt Corallo)3caaadf9bb
[IO] Replace the `io::Cursor` re-export with our own `Cursor` (Matt Corallo)141343edb4
[IO] Move to custom `Read` trait mirroring `std::io::Read` (Matt Corallo)7395093f94
Stop relying on `Take`'s `by_ref` method (Matt Corallo)2364e1a877
Stop relying on blanket Read impl for all &mut Read (Matt Corallo)6aa7ccf841
[IO] Replace `std::io::Sink` usage with our own trivial impl (Matt Corallo)7eb5d65bda
[IO] Provide a macro which implements `io::Write` for types (Matt Corallo)ac678bb435
[IO] Move to custom `Write` trait mirroring `std::io::Write` (Matt Corallo)5f2395ce56
Add missing `?Sized` bounds to `io::Write` parameters (Matt Corallo)2348449d2a
Stop relying on `std::io::Write`'s `&mut Write` blanket impl (Matt Corallo)5e0209569c
Use `io::sink` rather than our custom `EmptyWrite` utility (Matt Corallo)a0ade883b6
[IO] Move io module into selected re-exports (Matt Corallo)27c7c4e26a
Add a `bitcoin_io` crate (Matt Corallo) Pull request description: 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. This is mostly done, I'm still finalizing the `io::Error` commit at the end to drop the `core2` required dep in no-std, but its getting there. Would love further feedback on the approach or code-level review on these first handful of commits. ACKs for top commit: tcharding: ACKadd371d263
apoelstra: ACKadd371d263
Kixunil: ACKadd371d263
Tree-SHA512: 18698ea8b1b65108ee0f695d5062d2562c8df2f50bf85d93442648da3b35a4184a5d5d2a493aed0adaadc83f663f0cd2ac735c34941cc9a6fa58d826e548e091
This commit is contained in:
commit
675da34127
|
@ -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,15 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bitcoin-io"
|
||||||
|
version = "0.1.0"
|
||||||
|
|
||||||
[[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",
|
||||||
|
@ -109,15 +113,6 @@ version = "0.1.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de"
|
checksum = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "core2"
|
|
||||||
version = "0.3.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "2cf12d2dad3ed124aa116f59561428478993d69ab81ae4d30e5349c9c5b5a5f6"
|
|
||||||
dependencies = [
|
|
||||||
"memchr",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dyn-clone"
|
name = "dyn-clone"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
|
@ -146,9 +141,6 @@ name = "hex-conservative"
|
||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "30ed443af458ccb6d81c1e7e661545f94d3176752fb1df2f543b902a1e0f51e2"
|
checksum = "30ed443af458ccb6d81c1e7e661545f94d3176752fb1df2f543b902a1e0f51e2"
|
||||||
dependencies = [
|
|
||||||
"core2",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hex_lit"
|
name = "hex_lit"
|
||||||
|
@ -191,12 +183,6 @@ version = "0.2.64"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "74dfca3d9957906e8d1e6a0b641dc9a59848e793f1da2165889fd4f62d10d79c"
|
checksum = "74dfca3d9957906e8d1e6a0b641dc9a59848e793f1da2165889fd4f62d10d79c"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "memchr"
|
|
||||||
version = "2.0.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e01e64d9017d18e7fc09d8e4fe0e28ff6931019e979fb8019319db7ca827f8a6"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "memmap2"
|
name = "memmap2"
|
||||||
version = "0.5.10"
|
version = "0.5.10"
|
||||||
|
|
|
@ -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,15 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bitcoin-io"
|
||||||
|
version = "0.1.0"
|
||||||
|
|
||||||
[[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",
|
||||||
|
@ -108,15 +112,6 @@ version = "1.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "core2"
|
|
||||||
version = "0.3.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "239fa3ae9b63c2dc74bd3fa852d4792b8b305ae64eeede946265b6af62f1fff3"
|
|
||||||
dependencies = [
|
|
||||||
"memchr",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dyn-clone"
|
name = "dyn-clone"
|
||||||
version = "1.0.11"
|
version = "1.0.11"
|
||||||
|
@ -145,9 +140,6 @@ name = "hex-conservative"
|
||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "30ed443af458ccb6d81c1e7e661545f94d3176752fb1df2f543b902a1e0f51e2"
|
checksum = "30ed443af458ccb6d81c1e7e661545f94d3176752fb1df2f543b902a1e0f51e2"
|
||||||
dependencies = [
|
|
||||||
"core2",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hex_lit"
|
name = "hex_lit"
|
||||||
|
@ -190,12 +182,6 @@ version = "0.2.142"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6a987beff54b60ffa6d51982e1aa1146bc42f19bd26be28b0586f252fccf5317"
|
checksum = "6a987beff54b60ffa6d51982e1aa1146bc42f19bd26be28b0586f252fccf5317"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "memchr"
|
|
||||||
version = "2.5.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "memmap2"
|
name = "memmap2"
|
||||||
version = "0.5.10"
|
version = "0.5.10"
|
||||||
|
|
|
@ -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/io", "bitcoin-io/alloc", "bech32/alloc", "secp256k1/alloc", "hex/alloc"]
|
||||||
|
|
||||||
[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"
|
||||||
|
|
|
@ -271,9 +271,7 @@ impl GcsFilterReader {
|
||||||
I::Item: Borrow<[u8]>,
|
I::Item: Borrow<[u8]>,
|
||||||
R: io::Read + ?Sized,
|
R: io::Read + ?Sized,
|
||||||
{
|
{
|
||||||
let mut decoder = reader;
|
let n_elements: VarInt = Decodable::consensus_decode(reader).unwrap_or(VarInt(0));
|
||||||
let n_elements: VarInt = Decodable::consensus_decode(&mut decoder).unwrap_or(VarInt(0));
|
|
||||||
let reader = &mut decoder;
|
|
||||||
// map hashes to [0, n_elements << grp]
|
// map hashes to [0, n_elements << grp]
|
||||||
let nm = n_elements.0 * self.m;
|
let nm = n_elements.0 * self.m;
|
||||||
let mut mapped =
|
let mut mapped =
|
||||||
|
@ -316,9 +314,7 @@ impl GcsFilterReader {
|
||||||
I::Item: Borrow<[u8]>,
|
I::Item: Borrow<[u8]>,
|
||||||
R: io::Read + ?Sized,
|
R: io::Read + ?Sized,
|
||||||
{
|
{
|
||||||
let mut decoder = reader;
|
let n_elements: VarInt = Decodable::consensus_decode(reader).unwrap_or(VarInt(0));
|
||||||
let n_elements: VarInt = Decodable::consensus_decode(&mut decoder).unwrap_or(VarInt(0));
|
|
||||||
let reader = &mut decoder;
|
|
||||||
// map hashes to [0, n_elements << grp]
|
// map hashes to [0, n_elements << grp]
|
||||||
let nm = n_elements.0 * self.m;
|
let nm = n_elements.0 * self.m;
|
||||||
let mut mapped =
|
let mut mapped =
|
||||||
|
@ -393,7 +389,7 @@ impl<'a, W: io::Write> GcsFilterWriter<'a, W> {
|
||||||
mapped.sort_unstable();
|
mapped.sort_unstable();
|
||||||
|
|
||||||
// write number of elements as varint
|
// write number of elements as varint
|
||||||
let mut wrote = VarInt::from(mapped.len()).consensus_encode(&mut self.writer)?;
|
let mut wrote = VarInt::from(mapped.len()).consensus_encode(self.writer)?;
|
||||||
|
|
||||||
// write out deltas of sorted values into a Golonb-Rice coded bit stream
|
// write out deltas of sorted values into a Golonb-Rice coded bit stream
|
||||||
let mut writer = BitStreamWriter::new(self.writer);
|
let mut writer = BitStreamWriter::new(self.writer);
|
||||||
|
@ -442,7 +438,7 @@ impl GcsFilter {
|
||||||
/// Golomb-Rice decodes a number from a bit stream (parameter 2^k).
|
/// Golomb-Rice decodes a number from a bit stream (parameter 2^k).
|
||||||
fn golomb_rice_decode<R>(&self, reader: &mut BitStreamReader<R>) -> Result<u64, io::Error>
|
fn golomb_rice_decode<R>(&self, reader: &mut BitStreamReader<R>) -> Result<u64, io::Error>
|
||||||
where
|
where
|
||||||
R: io::Read,
|
R: io::Read + ?Sized,
|
||||||
{
|
{
|
||||||
let mut q = 0u64;
|
let mut q = 0u64;
|
||||||
while reader.read(1)? == 1 {
|
while reader.read(1)? == 1 {
|
||||||
|
@ -459,13 +455,13 @@ impl GcsFilter {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Bitwise stream reader.
|
/// Bitwise stream reader.
|
||||||
pub struct BitStreamReader<'a, R> {
|
pub struct BitStreamReader<'a, R: ?Sized> {
|
||||||
buffer: [u8; 1],
|
buffer: [u8; 1],
|
||||||
offset: u8,
|
offset: u8,
|
||||||
reader: &'a mut R,
|
reader: &'a mut R,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, R: io::Read> BitStreamReader<'a, R> {
|
impl<'a, R: io::Read + ?Sized> BitStreamReader<'a, R> {
|
||||||
/// Creates a new [`BitStreamReader`] that reads bitwise from a given `reader`.
|
/// Creates a new [`BitStreamReader`] that reads bitwise from a given `reader`.
|
||||||
pub fn new(reader: &'a mut R) -> BitStreamReader<'a, R> {
|
pub fn new(reader: &'a mut R) -> BitStreamReader<'a, R> {
|
||||||
BitStreamReader { buffer: [0u8], reader, offset: 8 }
|
BitStreamReader { buffer: [0u8], reader, offset: 8 }
|
||||||
|
|
|
@ -647,7 +647,7 @@ mod benches {
|
||||||
|
|
||||||
use super::Block;
|
use super::Block;
|
||||||
use crate::consensus::{deserialize, Decodable, Encodable};
|
use crate::consensus::{deserialize, Decodable, Encodable};
|
||||||
use crate::EmptyWrite;
|
use crate::io::sink;
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
pub fn bench_stream_reader(bh: &mut Bencher) {
|
pub fn bench_stream_reader(bh: &mut Bencher) {
|
||||||
|
@ -684,7 +684,7 @@ mod benches {
|
||||||
let block: Block = deserialize(&raw_block[..]).unwrap();
|
let block: Block = deserialize(&raw_block[..]).unwrap();
|
||||||
|
|
||||||
bh.iter(|| {
|
bh.iter(|| {
|
||||||
let size = block.consensus_encode(&mut EmptyWrite);
|
let size = block.consensus_encode(&mut sink());
|
||||||
black_box(&size);
|
black_box(&size);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -2156,7 +2156,7 @@ mod benches {
|
||||||
|
|
||||||
use super::Transaction;
|
use super::Transaction;
|
||||||
use crate::consensus::{deserialize, Encodable};
|
use crate::consensus::{deserialize, Encodable};
|
||||||
use crate::EmptyWrite;
|
use crate::io::sink;
|
||||||
|
|
||||||
const SOME_TX: &str = "0100000001a15d57094aa7a21a28cb20b59aab8fc7d1149a3bdbcddba9c622e4f5f6a99ece010000006c493046022100f93bb0e7d8db7bd46e40132d1f8242026e045f03a0efe71bbb8e3f475e970d790221009337cd7f1f929f00cc6ff01f03729b069a7c21b59b1736ddfee5db5946c5da8c0121033b9b137ee87d5a812d6f506efdd37f0affa7ffc310711c06c7f3e097c9447c52ffffffff0100e1f505000000001976a9140389035a9225b3839e2bbf32d826a1e222031fd888ac00000000";
|
const SOME_TX: &str = "0100000001a15d57094aa7a21a28cb20b59aab8fc7d1149a3bdbcddba9c622e4f5f6a99ece010000006c493046022100f93bb0e7d8db7bd46e40132d1f8242026e045f03a0efe71bbb8e3f475e970d790221009337cd7f1f929f00cc6ff01f03729b069a7c21b59b1736ddfee5db5946c5da8c0121033b9b137ee87d5a812d6f506efdd37f0affa7ffc310711c06c7f3e097c9447c52ffffffff0100e1f505000000001976a9140389035a9225b3839e2bbf32d826a1e222031fd888ac00000000";
|
||||||
|
|
||||||
|
@ -2191,7 +2191,7 @@ mod benches {
|
||||||
let tx: Transaction = deserialize(&raw_tx).unwrap();
|
let tx: Transaction = deserialize(&raw_tx).unwrap();
|
||||||
|
|
||||||
bh.iter(|| {
|
bh.iter(|| {
|
||||||
let size = tx.consensus_encode(&mut EmptyWrite);
|
let size = tx.consensus_encode(&mut sink());
|
||||||
black_box(&size);
|
black_box(&size);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -320,7 +320,7 @@ pub trait Decodable: Sized {
|
||||||
/// instead.
|
/// instead.
|
||||||
#[inline]
|
#[inline]
|
||||||
fn consensus_decode<R: io::Read + ?Sized>(reader: &mut R) -> Result<Self, Error> {
|
fn consensus_decode<R: io::Read + ?Sized>(reader: &mut R) -> Result<Self, Error> {
|
||||||
Self::consensus_decode_from_finite_reader(reader.take(MAX_VEC_SIZE as u64).by_ref())
|
Self::consensus_decode_from_finite_reader(&mut reader.take(MAX_VEC_SIZE as u64))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -643,11 +643,11 @@ impl_vec!((u32, Address));
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
impl_vec!(AddrV2Message);
|
impl_vec!(AddrV2Message);
|
||||||
|
|
||||||
pub(crate) fn consensus_encode_with_size<W: io::Write>(
|
pub(crate) fn consensus_encode_with_size<W: io::Write + ?Sized>(
|
||||||
data: &[u8],
|
data: &[u8],
|
||||||
mut w: W,
|
w: &mut W,
|
||||||
) -> Result<usize, io::Error> {
|
) -> Result<usize, io::Error> {
|
||||||
let vi_len = VarInt(data.len() as u64).consensus_encode(&mut w)?;
|
let vi_len = VarInt(data.len() as u64).consensus_encode(w)?;
|
||||||
w.emit_slice(data)?;
|
w.emit_slice(data)?;
|
||||||
Ok(vi_len + data.len())
|
Ok(vi_len + data.len())
|
||||||
}
|
}
|
||||||
|
@ -662,8 +662,8 @@ struct ReadBytesFromFiniteReaderOpts {
|
||||||
/// This function relies on reader being bound in amount of data
|
/// This function relies on reader being bound in amount of data
|
||||||
/// it returns for OOM protection. See [`Decodable::consensus_decode_from_finite_reader`].
|
/// it returns for OOM protection. See [`Decodable::consensus_decode_from_finite_reader`].
|
||||||
#[inline]
|
#[inline]
|
||||||
fn read_bytes_from_finite_reader<D: io::Read>(
|
fn read_bytes_from_finite_reader<D: io::Read + ?Sized>(
|
||||||
mut d: D,
|
d: &mut D,
|
||||||
mut opts: ReadBytesFromFiniteReaderOpts,
|
mut opts: ReadBytesFromFiniteReaderOpts,
|
||||||
) -> Result<Vec<u8>, Error> {
|
) -> Result<Vec<u8>, Error> {
|
||||||
let mut ret = vec![];
|
let mut ret = vec![];
|
||||||
|
@ -1234,7 +1234,7 @@ mod tests {
|
||||||
for chunk_size in 1..20 {
|
for chunk_size in 1..20 {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
read_bytes_from_finite_reader(
|
read_bytes_from_finite_reader(
|
||||||
io::Cursor::new(&data),
|
&mut io::Cursor::new(&data),
|
||||||
ReadBytesFromFiniteReaderOpts { len: data.len(), chunk_size }
|
ReadBytesFromFiniteReaderOpts { len: data.len(), chunk_size }
|
||||||
)
|
)
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
|
|
|
@ -174,10 +174,8 @@ impl<'a, T: 'a + Encodable, E: ByteEncoder> fmt::Display for DisplayWrapper<'a,
|
||||||
self.0.consensus_encode(&mut writer).map_err(|error| {
|
self.0.consensus_encode(&mut writer).map_err(|error| {
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
{
|
{
|
||||||
use crate::StdError;
|
|
||||||
|
|
||||||
if error.kind() != io::ErrorKind::Other
|
if error.kind() != io::ErrorKind::Other
|
||||||
|| error.source().is_some()
|
|| error.get_ref().is_some()
|
||||||
|| !writer.writer.was_error
|
|| !writer.writer.was_error
|
||||||
{
|
{
|
||||||
panic!(
|
panic!(
|
||||||
|
@ -429,8 +427,6 @@ impl<E: fmt::Debug, I: Iterator<Item = Result<u8, E>>> IterReader<E, I> {
|
||||||
fn new(iterator: I) -> Self { IterReader { iterator: iterator.fuse(), error: None } }
|
fn new(iterator: I) -> Self { IterReader { iterator: iterator.fuse(), error: None } }
|
||||||
|
|
||||||
fn decode<T: Decodable>(mut self) -> Result<T, DecodeError<E>> {
|
fn decode<T: Decodable>(mut self) -> Result<T, DecodeError<E>> {
|
||||||
use crate::StdError;
|
|
||||||
|
|
||||||
let result = T::consensus_decode(&mut self);
|
let result = T::consensus_decode(&mut self);
|
||||||
match (result, self.error) {
|
match (result, self.error) {
|
||||||
(Ok(_), None) if self.iterator.next().is_some() => {
|
(Ok(_), None) if self.iterator.next().is_some() => {
|
||||||
|
@ -438,7 +434,7 @@ impl<E: fmt::Debug, I: Iterator<Item = Result<u8, E>>> IterReader<E, I> {
|
||||||
},
|
},
|
||||||
(Ok(value), None) => Ok(value),
|
(Ok(value), None) => Ok(value),
|
||||||
(Ok(_), Some(error)) => panic!("{} silently ate the error: {:?}", core::any::type_name::<T>(), error),
|
(Ok(_), Some(error)) => panic!("{} silently ate the error: {:?}", core::any::type_name::<T>(), error),
|
||||||
(Err(ConsensusError::Io(io_error)), Some(de_error)) if io_error.kind() == io::ErrorKind::Other && io_error.source().is_none() => Err(DecodeError::Other(de_error)),
|
(Err(ConsensusError::Io(io_error)), Some(de_error)) if io_error.kind() == io::ErrorKind::Other && io_error.get_ref().is_none() => Err(DecodeError::Other(de_error)),
|
||||||
(Err(consensus_error), None) => Err(DecodeError::Consensus(consensus_error)),
|
(Err(consensus_error), None) => Err(DecodeError::Consensus(consensus_error)),
|
||||||
(Err(ConsensusError::Io(io_error)), de_error) => panic!("Unexpected IO error {:?} returned from {}::consensus_decode(), deserialization error: {:?}", io_error, core::any::type_name::<T>(), de_error),
|
(Err(ConsensusError::Io(io_error)), de_error) => panic!("Unexpected IO error {:?} returned from {}::consensus_decode(), deserialization error: {:?}", io_error, core::any::type_name::<T>(), de_error),
|
||||||
(Err(consensus_error), Some(de_error)) => panic!("{} should've returned `Other` IO error because of deserialization error {:?} but it returned consensus error {:?} instead", core::any::type_name::<T>(), de_error, consensus_error),
|
(Err(consensus_error), Some(de_error)) => panic!("{} should've returned `Other` IO error because of deserialization error {:?} but it returned consensus error {:?} instead", core::any::type_name::<T>(), de_error, consensus_error),
|
||||||
|
@ -494,8 +490,6 @@ impl<E> With<E> {
|
||||||
if serializer.is_human_readable() {
|
if serializer.is_human_readable() {
|
||||||
serializer.collect_str(&DisplayWrapper::<'_, _, E>(value, Default::default()))
|
serializer.collect_str(&DisplayWrapper::<'_, _, E>(value, Default::default()))
|
||||||
} else {
|
} else {
|
||||||
use crate::StdError;
|
|
||||||
|
|
||||||
let serializer = serializer.serialize_seq(None)?;
|
let serializer = serializer.serialize_seq(None)?;
|
||||||
let mut writer = BinWriter { serializer, error: None };
|
let mut writer = BinWriter { serializer, error: None };
|
||||||
|
|
||||||
|
@ -505,7 +499,7 @@ impl<E> With<E> {
|
||||||
(Ok(_), Some(error)) =>
|
(Ok(_), Some(error)) =>
|
||||||
panic!("{} silently ate an IO error: {:?}", core::any::type_name::<T>(), error),
|
panic!("{} silently ate an IO error: {:?}", core::any::type_name::<T>(), error),
|
||||||
(Err(io_error), Some(ser_error))
|
(Err(io_error), Some(ser_error))
|
||||||
if io_error.kind() == io::ErrorKind::Other && io_error.source().is_none() =>
|
if io_error.kind() == io::ErrorKind::Other && io_error.get_ref().is_none() =>
|
||||||
Err(ser_error),
|
Err(ser_error),
|
||||||
(Err(io_error), ser_error) => panic!(
|
(Err(io_error), ser_error) => panic!(
|
||||||
"{} returned an unexpected IO error: {:?} serialization error: {:?}",
|
"{} returned an unexpected IO error: {:?} serialization error: {:?}",
|
||||||
|
|
|
@ -71,7 +71,7 @@ impl PublicKey {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Write the public key into a writer
|
/// Write the public key into a writer
|
||||||
pub fn write_into<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
|
pub fn write_into<W: io::Write + ?Sized>(&self, writer: &mut W) -> Result<(), io::Error> {
|
||||||
self.with_serialized(|bytes| writer.write_all(bytes))
|
self.with_serialized(|bytes| writer.write_all(bytes))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,7 +79,7 @@ impl PublicKey {
|
||||||
///
|
///
|
||||||
/// This internally reads the first byte before reading the rest, so
|
/// This internally reads the first byte before reading the rest, so
|
||||||
/// use of a `BufReader` is recommended.
|
/// use of a `BufReader` is recommended.
|
||||||
pub fn read_from<R: io::Read>(mut reader: R) -> Result<Self, io::Error> {
|
pub fn read_from<R: io::Read + ?Sized>(reader: &mut R) -> Result<Self, io::Error> {
|
||||||
let mut bytes = [0; 65];
|
let mut bytes = [0; 65];
|
||||||
|
|
||||||
reader.read_exact(&mut bytes[0..1])?;
|
reader.read_exact(&mut bytes[0..1])?;
|
||||||
|
@ -87,7 +87,7 @@ impl PublicKey {
|
||||||
|
|
||||||
reader.read_exact(&mut bytes[1..])?;
|
reader.read_exact(&mut bytes[1..])?;
|
||||||
Self::from_slice(bytes).map_err(|e| {
|
Self::from_slice(bytes).map_err(|e| {
|
||||||
// Need a static string for core2
|
// Need a static string for no-std io
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
let reason = e;
|
let reason = e;
|
||||||
#[cfg(not(feature = "std"))]
|
#[cfg(not(feature = "std"))]
|
||||||
|
@ -755,7 +755,6 @@ mod tests {
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::address::Address;
|
use crate::address::Address;
|
||||||
use crate::io;
|
|
||||||
use crate::network::Network::{Bitcoin, Testnet};
|
use crate::network::Network::{Bitcoin, Testnet};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -917,11 +916,11 @@ mod tests {
|
||||||
|
|
||||||
// sanity checks
|
// sanity checks
|
||||||
assert!(PublicKey::read_from(&mut cursor).is_err());
|
assert!(PublicKey::read_from(&mut cursor).is_err());
|
||||||
assert!(PublicKey::read_from(io::Cursor::new(&[])).is_err());
|
assert!(PublicKey::read_from(&mut io::Cursor::new(&[])).is_err());
|
||||||
assert!(PublicKey::read_from(io::Cursor::new(&[0; 33][..])).is_err());
|
assert!(PublicKey::read_from(&mut io::Cursor::new(&[0; 33][..])).is_err());
|
||||||
assert!(PublicKey::read_from(io::Cursor::new(&[2; 32][..])).is_err());
|
assert!(PublicKey::read_from(&mut io::Cursor::new(&[2; 32][..])).is_err());
|
||||||
assert!(PublicKey::read_from(io::Cursor::new(&[0; 65][..])).is_err());
|
assert!(PublicKey::read_from(&mut io::Cursor::new(&[0; 65][..])).is_err());
|
||||||
assert!(PublicKey::read_from(io::Cursor::new(&[4; 64][..])).is_err());
|
assert!(PublicKey::read_from(&mut io::Cursor::new(&[4; 64][..])).is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -673,9 +673,9 @@ impl<R: Borrow<Transaction>> SighashCache<R> {
|
||||||
|
|
||||||
/// Encodes the BIP341 signing data for any flag type into a given object implementing a
|
/// Encodes the BIP341 signing data for any flag type into a given object implementing a
|
||||||
/// [`io::Write`] trait.
|
/// [`io::Write`] trait.
|
||||||
pub fn taproot_encode_signing_data_to<Write: io::Write, T: Borrow<TxOut>>(
|
pub fn taproot_encode_signing_data_to<Write: io::Write + ?Sized, T: Borrow<TxOut>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
mut writer: Write,
|
writer: &mut Write,
|
||||||
input_index: usize,
|
input_index: usize,
|
||||||
prevouts: &Prevouts<T>,
|
prevouts: &Prevouts<T>,
|
||||||
annex: Option<Annex>,
|
annex: Option<Annex>,
|
||||||
|
@ -687,18 +687,18 @@ impl<R: Borrow<Transaction>> SighashCache<R> {
|
||||||
let (sighash, anyone_can_pay) = sighash_type.split_anyonecanpay_flag();
|
let (sighash, anyone_can_pay) = sighash_type.split_anyonecanpay_flag();
|
||||||
|
|
||||||
// epoch
|
// epoch
|
||||||
0u8.consensus_encode(&mut writer)?;
|
0u8.consensus_encode(writer)?;
|
||||||
|
|
||||||
// * Control:
|
// * Control:
|
||||||
// hash_type (1).
|
// hash_type (1).
|
||||||
(sighash_type as u8).consensus_encode(&mut writer)?;
|
(sighash_type as u8).consensus_encode(writer)?;
|
||||||
|
|
||||||
// * Transaction Data:
|
// * Transaction Data:
|
||||||
// nVersion (4): the nVersion of the transaction.
|
// nVersion (4): the nVersion of the transaction.
|
||||||
self.tx.borrow().version.consensus_encode(&mut writer)?;
|
self.tx.borrow().version.consensus_encode(writer)?;
|
||||||
|
|
||||||
// nLockTime (4): the nLockTime of the transaction.
|
// nLockTime (4): the nLockTime of the transaction.
|
||||||
self.tx.borrow().lock_time.consensus_encode(&mut writer)?;
|
self.tx.borrow().lock_time.consensus_encode(writer)?;
|
||||||
|
|
||||||
// If the hash_type & 0x80 does not equal SIGHASH_ANYONECANPAY:
|
// If the hash_type & 0x80 does not equal SIGHASH_ANYONECANPAY:
|
||||||
// sha_prevouts (32): the SHA256 of the serialization of all input outpoints.
|
// sha_prevouts (32): the SHA256 of the serialization of all input outpoints.
|
||||||
|
@ -706,16 +706,16 @@ impl<R: Borrow<Transaction>> SighashCache<R> {
|
||||||
// sha_scriptpubkeys (32): the SHA256 of the serialization of all spent output scriptPubKeys.
|
// sha_scriptpubkeys (32): the SHA256 of the serialization of all spent output scriptPubKeys.
|
||||||
// sha_sequences (32): the SHA256 of the serialization of all input nSequence.
|
// sha_sequences (32): the SHA256 of the serialization of all input nSequence.
|
||||||
if !anyone_can_pay {
|
if !anyone_can_pay {
|
||||||
self.common_cache().prevouts.consensus_encode(&mut writer)?;
|
self.common_cache().prevouts.consensus_encode(writer)?;
|
||||||
self.taproot_cache(prevouts.get_all()?).amounts.consensus_encode(&mut writer)?;
|
self.taproot_cache(prevouts.get_all()?).amounts.consensus_encode(writer)?;
|
||||||
self.taproot_cache(prevouts.get_all()?).script_pubkeys.consensus_encode(&mut writer)?;
|
self.taproot_cache(prevouts.get_all()?).script_pubkeys.consensus_encode(writer)?;
|
||||||
self.common_cache().sequences.consensus_encode(&mut writer)?;
|
self.common_cache().sequences.consensus_encode(writer)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If hash_type & 3 does not equal SIGHASH_NONE or SIGHASH_SINGLE:
|
// If hash_type & 3 does not equal SIGHASH_NONE or SIGHASH_SINGLE:
|
||||||
// sha_outputs (32): the SHA256 of the serialization of all outputs in CTxOut format.
|
// sha_outputs (32): the SHA256 of the serialization of all outputs in CTxOut format.
|
||||||
if sighash != TapSighashType::None && sighash != TapSighashType::Single {
|
if sighash != TapSighashType::None && sighash != TapSighashType::Single {
|
||||||
self.common_cache().outputs.consensus_encode(&mut writer)?;
|
self.common_cache().outputs.consensus_encode(writer)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// * Data about this input:
|
// * Data about this input:
|
||||||
|
@ -728,7 +728,7 @@ impl<R: Borrow<Transaction>> SighashCache<R> {
|
||||||
if leaf_hash_code_separator.is_some() {
|
if leaf_hash_code_separator.is_some() {
|
||||||
spend_type |= 2u8;
|
spend_type |= 2u8;
|
||||||
}
|
}
|
||||||
spend_type.consensus_encode(&mut writer)?;
|
spend_type.consensus_encode(writer)?;
|
||||||
|
|
||||||
// If hash_type & 0x80 equals SIGHASH_ANYONECANPAY:
|
// If hash_type & 0x80 equals SIGHASH_ANYONECANPAY:
|
||||||
// outpoint (36): the COutPoint of this input (32-byte hash + 4-byte little-endian).
|
// outpoint (36): the COutPoint of this input (32-byte hash + 4-byte little-endian).
|
||||||
|
@ -742,12 +742,12 @@ impl<R: Borrow<Transaction>> SighashCache<R> {
|
||||||
inputs_size: self.tx.borrow().input.len(),
|
inputs_size: self.tx.borrow().input.len(),
|
||||||
})?;
|
})?;
|
||||||
let previous_output = prevouts.get(input_index)?;
|
let previous_output = prevouts.get(input_index)?;
|
||||||
txin.previous_output.consensus_encode(&mut writer)?;
|
txin.previous_output.consensus_encode(writer)?;
|
||||||
previous_output.value.consensus_encode(&mut writer)?;
|
previous_output.value.consensus_encode(writer)?;
|
||||||
previous_output.script_pubkey.consensus_encode(&mut writer)?;
|
previous_output.script_pubkey.consensus_encode(writer)?;
|
||||||
txin.sequence.consensus_encode(&mut writer)?;
|
txin.sequence.consensus_encode(writer)?;
|
||||||
} else {
|
} else {
|
||||||
(input_index as u32).consensus_encode(&mut writer)?;
|
(input_index as u32).consensus_encode(writer)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If an annex is present (the lowest bit of spend_type is set):
|
// If an annex is present (the lowest bit of spend_type is set):
|
||||||
|
@ -757,7 +757,7 @@ impl<R: Borrow<Transaction>> SighashCache<R> {
|
||||||
let mut enc = sha256::Hash::engine();
|
let mut enc = sha256::Hash::engine();
|
||||||
annex.consensus_encode(&mut enc)?;
|
annex.consensus_encode(&mut enc)?;
|
||||||
let hash = sha256::Hash::from_engine(enc);
|
let hash = sha256::Hash::from_engine(enc);
|
||||||
hash.consensus_encode(&mut writer)?;
|
hash.consensus_encode(writer)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// * Data about this output:
|
// * Data about this output:
|
||||||
|
@ -775,7 +775,7 @@ impl<R: Borrow<Transaction>> SighashCache<R> {
|
||||||
})?
|
})?
|
||||||
.consensus_encode(&mut enc)?;
|
.consensus_encode(&mut enc)?;
|
||||||
let hash = sha256::Hash::from_engine(enc);
|
let hash = sha256::Hash::from_engine(enc);
|
||||||
hash.consensus_encode(&mut writer)?;
|
hash.consensus_encode(writer)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if (scriptpath):
|
// if (scriptpath):
|
||||||
|
@ -783,9 +783,9 @@ impl<R: Borrow<Transaction>> SighashCache<R> {
|
||||||
// ss += bytes([0])
|
// ss += bytes([0])
|
||||||
// ss += struct.pack("<i", codeseparator_pos)
|
// ss += struct.pack("<i", codeseparator_pos)
|
||||||
if let Some((hash, code_separator_pos)) = leaf_hash_code_separator {
|
if let Some((hash, code_separator_pos)) = leaf_hash_code_separator {
|
||||||
hash.as_byte_array().consensus_encode(&mut writer)?;
|
hash.as_byte_array().consensus_encode(writer)?;
|
||||||
KEY_VERSION_0.consensus_encode(&mut writer)?;
|
KEY_VERSION_0.consensus_encode(writer)?;
|
||||||
code_separator_pos.consensus_encode(&mut writer)?;
|
code_separator_pos.consensus_encode(writer)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -860,9 +860,9 @@ impl<R: Borrow<Transaction>> SighashCache<R> {
|
||||||
/// `script_code` is dependent on the type of the spend transaction. For p2wpkh use
|
/// `script_code` is dependent on the type of the spend transaction. For p2wpkh use
|
||||||
/// [`Script::p2wpkh_script_code`], for p2wsh just pass in the witness script. (Also see
|
/// [`Script::p2wpkh_script_code`], for p2wsh just pass in the witness script. (Also see
|
||||||
/// [`Self::p2wpkh_signature_hash`] and [`SighashCache::p2wsh_signature_hash`].)
|
/// [`Self::p2wpkh_signature_hash`] and [`SighashCache::p2wsh_signature_hash`].)
|
||||||
pub fn segwit_v0_encode_signing_data_to<Write: io::Write>(
|
pub fn segwit_v0_encode_signing_data_to<Write: io::Write + ?Sized>(
|
||||||
&mut self,
|
&mut self,
|
||||||
mut writer: Write,
|
writer: &mut Write,
|
||||||
input_index: usize,
|
input_index: usize,
|
||||||
script_code: &Script,
|
script_code: &Script,
|
||||||
value: Amount,
|
value: Amount,
|
||||||
|
@ -872,21 +872,21 @@ impl<R: Borrow<Transaction>> SighashCache<R> {
|
||||||
|
|
||||||
let (sighash, anyone_can_pay) = sighash_type.split_anyonecanpay_flag();
|
let (sighash, anyone_can_pay) = sighash_type.split_anyonecanpay_flag();
|
||||||
|
|
||||||
self.tx.borrow().version.consensus_encode(&mut writer)?;
|
self.tx.borrow().version.consensus_encode(writer)?;
|
||||||
|
|
||||||
if !anyone_can_pay {
|
if !anyone_can_pay {
|
||||||
self.segwit_cache().prevouts.consensus_encode(&mut writer)?;
|
self.segwit_cache().prevouts.consensus_encode(writer)?;
|
||||||
} else {
|
} else {
|
||||||
zero_hash.consensus_encode(&mut writer)?;
|
zero_hash.consensus_encode(writer)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if !anyone_can_pay
|
if !anyone_can_pay
|
||||||
&& sighash != EcdsaSighashType::Single
|
&& sighash != EcdsaSighashType::Single
|
||||||
&& sighash != EcdsaSighashType::None
|
&& sighash != EcdsaSighashType::None
|
||||||
{
|
{
|
||||||
self.segwit_cache().sequences.consensus_encode(&mut writer)?;
|
self.segwit_cache().sequences.consensus_encode(writer)?;
|
||||||
} else {
|
} else {
|
||||||
zero_hash.consensus_encode(&mut writer)?;
|
zero_hash.consensus_encode(writer)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -896,14 +896,14 @@ impl<R: Borrow<Transaction>> SighashCache<R> {
|
||||||
inputs_size: self.tx.borrow().input.len(),
|
inputs_size: self.tx.borrow().input.len(),
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
txin.previous_output.consensus_encode(&mut writer)?;
|
txin.previous_output.consensus_encode(writer)?;
|
||||||
script_code.consensus_encode(&mut writer)?;
|
script_code.consensus_encode(writer)?;
|
||||||
value.consensus_encode(&mut writer)?;
|
value.consensus_encode(writer)?;
|
||||||
txin.sequence.consensus_encode(&mut writer)?;
|
txin.sequence.consensus_encode(writer)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if sighash != EcdsaSighashType::Single && sighash != EcdsaSighashType::None {
|
if sighash != EcdsaSighashType::Single && sighash != EcdsaSighashType::None {
|
||||||
self.segwit_cache().outputs.consensus_encode(&mut writer)?;
|
self.segwit_cache().outputs.consensus_encode(writer)?;
|
||||||
} else if sighash == EcdsaSighashType::Single && input_index < self.tx.borrow().output.len()
|
} else if sighash == EcdsaSighashType::Single && input_index < self.tx.borrow().output.len()
|
||||||
{
|
{
|
||||||
let mut single_enc = LegacySighash::engine();
|
let mut single_enc = LegacySighash::engine();
|
||||||
|
@ -914,8 +914,8 @@ impl<R: Borrow<Transaction>> SighashCache<R> {
|
||||||
writer.write_all(&zero_hash[..])?;
|
writer.write_all(&zero_hash[..])?;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.tx.borrow().lock_time.consensus_encode(&mut writer)?;
|
self.tx.borrow().lock_time.consensus_encode(writer)?;
|
||||||
sighash_type.to_u32().consensus_encode(&mut writer)?;
|
sighash_type.to_u32().consensus_encode(writer)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -984,9 +984,9 @@ impl<R: Borrow<Transaction>> SighashCache<R> {
|
||||||
///
|
///
|
||||||
/// This function can't handle the SIGHASH_SINGLE bug internally, so it returns [`EncodeSigningDataResult`]
|
/// This function can't handle the SIGHASH_SINGLE bug internally, so it returns [`EncodeSigningDataResult`]
|
||||||
/// that must be handled by the caller (see [`EncodeSigningDataResult::is_sighash_single_bug`]).
|
/// that must be handled by the caller (see [`EncodeSigningDataResult::is_sighash_single_bug`]).
|
||||||
pub fn legacy_encode_signing_data_to<Write: io::Write, U: Into<u32>>(
|
pub fn legacy_encode_signing_data_to<Write: io::Write + ?Sized, U: Into<u32>>(
|
||||||
&self,
|
&self,
|
||||||
writer: Write,
|
writer: &mut Write,
|
||||||
input_index: usize,
|
input_index: usize,
|
||||||
script_pubkey: &Script,
|
script_pubkey: &Script,
|
||||||
sighash_type: U,
|
sighash_type: U,
|
||||||
|
@ -1011,9 +1011,9 @@ impl<R: Borrow<Transaction>> SighashCache<R> {
|
||||||
return EncodeSigningDataResult::SighashSingleBug;
|
return EncodeSigningDataResult::SighashSingleBug;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn encode_signing_data_to_inner<Write: io::Write>(
|
fn encode_signing_data_to_inner<Write: io::Write + ?Sized>(
|
||||||
self_: &Transaction,
|
self_: &Transaction,
|
||||||
mut writer: Write,
|
writer: &mut Write,
|
||||||
input_index: usize,
|
input_index: usize,
|
||||||
script_pubkey: &Script,
|
script_pubkey: &Script,
|
||||||
sighash_type: u32,
|
sighash_type: u32,
|
||||||
|
@ -1074,8 +1074,8 @@ impl<R: Borrow<Transaction>> SighashCache<R> {
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
// hash the result
|
// hash the result
|
||||||
tx.consensus_encode(&mut writer)?;
|
tx.consensus_encode(writer)?;
|
||||||
sighash_type.to_le_bytes().consensus_encode(&mut writer)?;
|
sighash_type.to_le_bytes().consensus_encode(writer)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,10 +34,9 @@ macro_rules! impl_consensus_encoding {
|
||||||
fn consensus_decode<R: $crate::io::Read + ?Sized>(
|
fn consensus_decode<R: $crate::io::Read + ?Sized>(
|
||||||
r: &mut R,
|
r: &mut R,
|
||||||
) -> Result<$thing, $crate::consensus::encode::Error> {
|
) -> Result<$thing, $crate::consensus::encode::Error> {
|
||||||
use crate::io::Read as _;
|
|
||||||
let mut r = r.take($crate::consensus::encode::MAX_VEC_SIZE as u64);
|
let mut r = r.take($crate::consensus::encode::MAX_VEC_SIZE as u64);
|
||||||
Ok($thing {
|
Ok($thing {
|
||||||
$($field: $crate::consensus::Decodable::consensus_decode(r.by_ref())?),+
|
$($field: $crate::consensus::Decodable::consensus_decode(&mut r)?),+
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
@ -116,18 +113,7 @@ pub mod sign_message;
|
||||||
pub mod string;
|
pub mod string;
|
||||||
pub mod taproot;
|
pub mod taproot;
|
||||||
|
|
||||||
// May depend on crate features and we don't want to bother with it
|
use bitcoin_io::io;
|
||||||
#[allow(unused)]
|
|
||||||
#[cfg(feature = "std")]
|
|
||||||
use std::error::Error as StdError;
|
|
||||||
#[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;
|
|
||||||
|
|
||||||
#[rustfmt::skip] // Keep public re-exports separate.
|
#[rustfmt::skip] // Keep public re-exports separate.
|
||||||
#[doc(inline)]
|
#[doc(inline)]
|
||||||
|
@ -161,6 +147,8 @@ pub use crate::{
|
||||||
|
|
||||||
#[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: (),
|
||||||
|
@ -169,12 +157,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(()) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -196,34 +184,10 @@ mod prelude {
|
||||||
pub use std::collections::{BTreeMap, BTreeSet, btree_map, BinaryHeap};
|
pub use std::collections::{BTreeMap, BTreeSet, btree_map, BinaryHeap};
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
pub use std::io::sink;
|
pub use crate::io::sink;
|
||||||
|
|
||||||
#[cfg(not(feature = "std"))]
|
#[cfg(not(feature = "std"))]
|
||||||
pub use crate::io_extras::sink;
|
pub use crate::io_extras::sink;
|
||||||
|
|
||||||
pub use hex::DisplayHex;
|
pub use hex::DisplayHex;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(bench)]
|
|
||||||
use bench::EmptyWrite;
|
|
||||||
|
|
||||||
#[cfg(bench)]
|
|
||||||
mod bench {
|
|
||||||
use core::fmt::Arguments;
|
|
||||||
|
|
||||||
use crate::io::{IoSlice, Result, Write};
|
|
||||||
|
|
||||||
#[derive(Default, Clone, Debug, PartialEq, Eq)]
|
|
||||||
pub struct EmptyWrite;
|
|
||||||
|
|
||||||
impl Write for EmptyWrite {
|
|
||||||
fn write(&mut self, buf: &[u8]) -> Result<usize> { Ok(buf.len()) }
|
|
||||||
fn write_vectored(&mut self, bufs: &[IoSlice]) -> Result<usize> {
|
|
||||||
Ok(bufs.iter().map(|s| s.len()).sum())
|
|
||||||
}
|
|
||||||
fn flush(&mut self) -> Result<()> { Ok(()) }
|
|
||||||
|
|
||||||
fn write_all(&mut self, _: &[u8]) -> Result<()> { Ok(()) }
|
|
||||||
fn write_fmt(&mut self, _: Arguments) -> Result<()> { Ok(()) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -116,7 +116,7 @@ impl fmt::Debug for Address {
|
||||||
|
|
||||||
impl ToSocketAddrs for Address {
|
impl ToSocketAddrs for Address {
|
||||||
type Iter = iter::Once<SocketAddr>;
|
type Iter = iter::Once<SocketAddr>;
|
||||||
fn to_socket_addrs(&self) -> Result<Self::Iter, io::Error> {
|
fn to_socket_addrs(&self) -> Result<Self::Iter, std::io::Error> {
|
||||||
Ok(iter::once(self.socket_addr()?))
|
Ok(iter::once(self.socket_addr()?))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -296,7 +296,7 @@ impl Decodable for AddrV2Message {
|
||||||
|
|
||||||
impl ToSocketAddrs for AddrV2Message {
|
impl ToSocketAddrs for AddrV2Message {
|
||||||
type Iter = iter::Once<SocketAddr>;
|
type Iter = iter::Once<SocketAddr>;
|
||||||
fn to_socket_addrs(&self) -> Result<Self::Iter, io::Error> {
|
fn to_socket_addrs(&self) -> Result<Self::Iter, std::io::Error> {
|
||||||
Ok(iter::once(self.socket_addr()?))
|
Ok(iter::once(self.socket_addr()?))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,6 @@ use core::convert::TryFrom;
|
||||||
use core::{fmt, iter};
|
use core::{fmt, iter};
|
||||||
|
|
||||||
use hashes::{sha256d, Hash};
|
use hashes::{sha256d, Hash};
|
||||||
use io::Read as _;
|
|
||||||
|
|
||||||
use crate::blockdata::{block, transaction};
|
use crate::blockdata::{block, transaction};
|
||||||
use crate::consensus::encode::{self, CheckedData, Decodable, Encodable, VarInt};
|
use crate::consensus::encode::{self, CheckedData, Decodable, Encodable, VarInt};
|
||||||
|
@ -429,7 +428,7 @@ impl Decodable for HeaderDeserializationWrapper {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn consensus_decode<R: io::Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
|
fn consensus_decode<R: io::Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
|
||||||
Self::consensus_decode_from_finite_reader(r.take(MAX_MSG_SIZE as u64).by_ref())
|
Self::consensus_decode_from_finite_reader(&mut r.take(MAX_MSG_SIZE as u64))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -534,7 +533,7 @@ impl Decodable for RawNetworkMessage {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn consensus_decode<R: io::Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
|
fn consensus_decode<R: io::Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
|
||||||
Self::consensus_decode_from_finite_reader(r.take(MAX_MSG_SIZE as u64).by_ref())
|
Self::consensus_decode_from_finite_reader(&mut r.take(MAX_MSG_SIZE as u64))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,10 +5,9 @@
|
||||||
//! This module describes BIP37 Connection Bloom filtering network messages.
|
//! This module describes BIP37 Connection Bloom filtering network messages.
|
||||||
//!
|
//!
|
||||||
|
|
||||||
use std::io;
|
|
||||||
|
|
||||||
use crate::consensus::{encode, Decodable, Encodable, ReadExt};
|
use crate::consensus::{encode, Decodable, Encodable, ReadExt};
|
||||||
use crate::internal_macros::impl_consensus_encoding;
|
use crate::internal_macros::impl_consensus_encoding;
|
||||||
|
use crate::io;
|
||||||
|
|
||||||
/// `filterload` message sets the current bloom filter
|
/// `filterload` message sets the current bloom filter
|
||||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||||
|
|
|
@ -196,7 +196,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
// core2 doesn't have read_to_end
|
// core2 doesn't have read_to_end
|
||||||
pub(crate) fn read_to_end<D: io::Read>(mut d: D) -> Result<Vec<u8>, io::Error> {
|
pub(crate) fn read_to_end<D: io::Read + ?Sized>(d: &mut D) -> Result<Vec<u8>, io::Error> {
|
||||||
let mut result = vec![];
|
let mut result = vec![];
|
||||||
let mut buf = [0u8; 64];
|
let mut buf = [0u8; 64];
|
||||||
loop {
|
loop {
|
||||||
|
|
|
@ -1112,7 +1112,7 @@ impl TaprootMerkleBranch {
|
||||||
/// # Returns
|
/// # Returns
|
||||||
///
|
///
|
||||||
/// The number of bytes written to the writer.
|
/// The number of bytes written to the writer.
|
||||||
pub fn encode<Write: io::Write>(&self, mut writer: Write) -> io::Result<usize> {
|
pub fn encode<Write: io::Write + ?Sized>(&self, writer: &mut Write) -> io::Result<usize> {
|
||||||
for hash in self.0.iter() {
|
for hash in self.0.iter() {
|
||||||
writer.write_all(hash.as_ref())?;
|
writer.write_all(hash.as_ref())?;
|
||||||
}
|
}
|
||||||
|
@ -1240,12 +1240,12 @@ impl ControlBlock {
|
||||||
/// # Returns
|
/// # Returns
|
||||||
///
|
///
|
||||||
/// The number of bytes written to the writer.
|
/// The number of bytes written to the writer.
|
||||||
pub fn encode<Write: io::Write>(&self, mut writer: Write) -> io::Result<usize> {
|
pub fn encode<Write: io::Write + ?Sized>(&self, writer: &mut Write) -> io::Result<usize> {
|
||||||
let first_byte: u8 =
|
let first_byte: u8 =
|
||||||
i32::from(self.output_key_parity) as u8 | self.leaf_version.to_consensus();
|
i32::from(self.output_key_parity) as u8 | self.leaf_version.to_consensus();
|
||||||
writer.write_all(&[first_byte])?;
|
writer.write_all(&[first_byte])?;
|
||||||
writer.write_all(&self.internal_key.serialize())?;
|
writer.write_all(&self.internal_key.serialize())?;
|
||||||
self.merkle_branch.encode(&mut writer)?;
|
self.merkle_branch.encode(writer)?;
|
||||||
Ok(self.size())
|
Ok(self.size())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,8 +17,6 @@ if cargo --version | grep ${MSRV}; then
|
||||||
cargo update -p schemars --precise 0.8.12
|
cargo update -p schemars --precise 0.8.12
|
||||||
# schemars_derive 0.8.13 uses edition 2021
|
# schemars_derive 0.8.13 uses edition 2021
|
||||||
cargo update -p schemars_derive --precise 0.8.12
|
cargo update -p schemars_derive --precise 0.8.12
|
||||||
# memchr 2.6.0 uses edition 2021
|
|
||||||
cargo update -p memchr --precise 2.5.0
|
|
||||||
# byteorder 1.5.0 uses edition 2021
|
# byteorder 1.5.0 uses edition 2021
|
||||||
cargo update -p byteorder --precise 1.4.3
|
cargo update -p byteorder --precise 1.4.3
|
||||||
|
|
||||||
|
|
|
@ -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 "io".
|
||||||
core2 = ["actual-core2", "hex/core2"]
|
io = ["bitcoin-io"]
|
||||||
# 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"
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
set -ex
|
set -ex
|
||||||
|
|
||||||
FEATURES="serde serde-std std core2 alloc"
|
FEATURES="serde serde-std std io alloc"
|
||||||
|
|
||||||
cargo --version
|
cargo --version
|
||||||
rustc --version
|
rustc --version
|
||||||
|
|
|
@ -18,8 +18,8 @@ cortex-m-rt = "0.6.10"
|
||||||
cortex-m-semihosting = "0.3.3"
|
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 = ["io"] }
|
||||||
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"
|
||||||
|
|
|
@ -1,69 +1,73 @@
|
||||||
// SPDX-License-Identifier: CC0-1.0
|
// SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
//! `std` / `core2` Impls.
|
//! `std` / `io` Impls.
|
||||||
//!
|
//!
|
||||||
//! Implementations of traits defined in `std` / `core2` and not in `core`.
|
//! Implementations of traits defined in `std` / `io` and not in `core`.
|
||||||
//!
|
//!
|
||||||
|
|
||||||
use crate::{hmac, io, ripemd160, sha1, sha256, sha512, siphash24, HashEngine};
|
use bitcoin_io::impl_write;
|
||||||
|
|
||||||
impl io::Write for sha1::HashEngine {
|
use crate::{hmac, ripemd160, sha1, sha256, sha512, siphash24, HashEngine};
|
||||||
fn flush(&mut self) -> io::Result<()> { Ok(()) }
|
|
||||||
|
|
||||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
impl_write!(
|
||||||
self.input(buf);
|
sha1::HashEngine,
|
||||||
|
|us: &mut sha1::HashEngine, buf| {
|
||||||
|
us.input(buf);
|
||||||
Ok(buf.len())
|
Ok(buf.len())
|
||||||
}
|
},
|
||||||
}
|
|_us| { Ok(()) }
|
||||||
|
);
|
||||||
|
|
||||||
impl io::Write for sha256::HashEngine {
|
impl_write!(
|
||||||
fn flush(&mut self) -> io::Result<()> { Ok(()) }
|
sha256::HashEngine,
|
||||||
|
|us: &mut sha256::HashEngine, buf| {
|
||||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
us.input(buf);
|
||||||
self.input(buf);
|
|
||||||
Ok(buf.len())
|
Ok(buf.len())
|
||||||
}
|
},
|
||||||
}
|
|_us| { Ok(()) }
|
||||||
|
);
|
||||||
|
|
||||||
impl io::Write for sha512::HashEngine {
|
impl_write!(
|
||||||
fn flush(&mut self) -> io::Result<()> { Ok(()) }
|
sha512::HashEngine,
|
||||||
|
|us: &mut sha512::HashEngine, buf| {
|
||||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
us.input(buf);
|
||||||
self.input(buf);
|
|
||||||
Ok(buf.len())
|
Ok(buf.len())
|
||||||
}
|
},
|
||||||
}
|
|_us| { Ok(()) }
|
||||||
|
);
|
||||||
|
|
||||||
impl io::Write for ripemd160::HashEngine {
|
impl_write!(
|
||||||
fn flush(&mut self) -> io::Result<()> { Ok(()) }
|
ripemd160::HashEngine,
|
||||||
|
|us: &mut ripemd160::HashEngine, buf| {
|
||||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
us.input(buf);
|
||||||
self.input(buf);
|
|
||||||
Ok(buf.len())
|
Ok(buf.len())
|
||||||
}
|
},
|
||||||
}
|
|_us| { Ok(()) }
|
||||||
|
);
|
||||||
|
|
||||||
impl io::Write for siphash24::HashEngine {
|
impl_write!(
|
||||||
fn flush(&mut self) -> io::Result<()> { Ok(()) }
|
siphash24::HashEngine,
|
||||||
|
|us: &mut siphash24::HashEngine, buf| {
|
||||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
us.input(buf);
|
||||||
self.input(buf);
|
|
||||||
Ok(buf.len())
|
Ok(buf.len())
|
||||||
}
|
},
|
||||||
}
|
|_us| { Ok(()) }
|
||||||
|
);
|
||||||
|
|
||||||
impl<T: crate::Hash> io::Write for hmac::HmacEngine<T> {
|
impl_write!(
|
||||||
fn flush(&mut self) -> io::Result<()> { Ok(()) }
|
hmac::HmacEngine<T>,
|
||||||
|
|us: &mut hmac::HmacEngine<T>, buf| {
|
||||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
us.input(buf);
|
||||||
self.input(buf);
|
|
||||||
Ok(buf.len())
|
Ok(buf.len())
|
||||||
}
|
},
|
||||||
}
|
|_us| { Ok(()) },
|
||||||
|
T: crate::Hash
|
||||||
|
);
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::io::Write;
|
use bitcoin_io::io::Write;
|
||||||
|
|
||||||
use crate::{hash160, hmac, ripemd160, sha1, sha256, sha256d, sha512, siphash24, Hash};
|
use crate::{hash160, hmac, ripemd160, sha1, sha256, sha256d, sha512, siphash24, Hash};
|
||||||
|
|
||||||
macro_rules! write_test {
|
macro_rules! write_test {
|
||||||
|
|
|
@ -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,7 @@ 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"))]
|
|
||||||
use core2::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,22 @@
|
||||||
|
[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 = []
|
||||||
|
|
||||||
|
[package.metadata.docs.rs]
|
||||||
|
all-features = true
|
||||||
|
rustdoc-args = ["--cfg", "docsrs"]
|
|
@ -0,0 +1,425 @@
|
||||||
|
//! 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(any(feature = "alloc", feature = "std"))]
|
||||||
|
extern crate alloc;
|
||||||
|
|
||||||
|
/// Standard I/O stream definitions which are API-equivalent to `std`'s `io` module. See
|
||||||
|
/// [`std::io`] for more info.
|
||||||
|
pub mod io {
|
||||||
|
use core::convert::TryInto;
|
||||||
|
use core::fmt::{Debug, Display, Formatter};
|
||||||
|
#[cfg(any(feature = "alloc", feature = "std"))]
|
||||||
|
use alloc::boxed::Box;
|
||||||
|
|
||||||
|
#[cfg(all(feature = "alloc", not(feature = "std")))]
|
||||||
|
mod sealed {
|
||||||
|
use alloc::boxed::Box;
|
||||||
|
use alloc::string::String;
|
||||||
|
use core::fmt::Debug;
|
||||||
|
pub trait IntoBoxDynDebug {
|
||||||
|
fn into(self) -> Box<dyn Debug + Send + Sync + 'static>;
|
||||||
|
}
|
||||||
|
impl IntoBoxDynDebug for &str {
|
||||||
|
fn into(self) -> Box<dyn Debug + Send + Sync + 'static> {
|
||||||
|
Box::new(String::from(self))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl IntoBoxDynDebug for String {
|
||||||
|
fn into(self) -> Box<dyn Debug + Send + Sync + 'static> {
|
||||||
|
Box::new(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Error {
|
||||||
|
kind: ErrorKind,
|
||||||
|
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
error: Option<Box<dyn std::error::Error + Send + Sync + 'static>>,
|
||||||
|
#[cfg(all(feature = "alloc", not(feature = "std")))]
|
||||||
|
error: Option<Box<dyn Debug + Send + Sync + 'static>>,
|
||||||
|
}
|
||||||
|
impl Error {
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
pub fn new<E>(kind: ErrorKind, error: E) -> Error
|
||||||
|
where
|
||||||
|
E: Into<Box<dyn std::error::Error + Send + Sync + 'static>>,
|
||||||
|
{
|
||||||
|
Self { kind, error: Some(error.into()) }
|
||||||
|
}
|
||||||
|
#[cfg(all(feature = "alloc", not(feature = "std")))]
|
||||||
|
pub fn new<E: sealed::IntoBoxDynDebug>(kind: ErrorKind, error: E) -> Error {
|
||||||
|
Self { kind, error: Some(error.into()) }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn kind(&self) -> ErrorKind {
|
||||||
|
self.kind
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ErrorKind> for Error {
|
||||||
|
fn from(kind: ErrorKind) -> Error {
|
||||||
|
Self {
|
||||||
|
kind,
|
||||||
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
|
error: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for Error {
|
||||||
|
fn fmt(&self, fmt: &mut Formatter) -> core::result::Result<(), core::fmt::Error> {
|
||||||
|
fmt.write_fmt(format_args!("I/O Error: {}", self.kind.description()))?;
|
||||||
|
#[cfg(any(feature = "alloc", feature = "std"))]
|
||||||
|
if let Some(e) = &self.error {
|
||||||
|
fmt.write_fmt(format_args!(". {:?}", e))?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
impl std::error::Error for Error {
|
||||||
|
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
||||||
|
self.error.as_ref().and_then(|e| e.as_ref().source())
|
||||||
|
}
|
||||||
|
#[allow(deprecated)]
|
||||||
|
fn description(&self) -> &str {
|
||||||
|
match self.error.as_ref() {
|
||||||
|
Some(e) => e.description(),
|
||||||
|
None => self.kind.description(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[allow(deprecated)]
|
||||||
|
fn cause(&self) -> Option<&dyn std::error::Error> {
|
||||||
|
self.error.as_ref().and_then(|e| e.as_ref().cause())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Error {
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
pub fn get_ref(&self) -> Option<&(dyn std::error::Error + Send + Sync + 'static)> {
|
||||||
|
self.error.as_deref()
|
||||||
|
}
|
||||||
|
#[cfg(all(feature = "alloc", not(feature = "std")))]
|
||||||
|
pub fn get_ref(&self) -> Option<&(dyn Debug + Send + Sync + 'static)> {
|
||||||
|
self.error.as_deref()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
impl From<std::io::Error> for Error {
|
||||||
|
fn from(o: std::io::Error) -> Error {
|
||||||
|
Self { kind: ErrorKind::from_std(o.kind()), error: o.into_inner() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
impl From<Error> for std::io::Error {
|
||||||
|
fn from(o: Error) -> std::io::Error {
|
||||||
|
if let Some(err) = o.error {
|
||||||
|
std::io::Error::new(o.kind.to_std(), err)
|
||||||
|
} else {
|
||||||
|
o.kind.to_std().into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! define_errorkind {
|
||||||
|
($($kind: ident),*) => {
|
||||||
|
#[non_exhaustive]
|
||||||
|
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
|
||||||
|
/// A minimal subset of [`std::io::ErrorKind`] which is used for [`Error`]. Note that, as with
|
||||||
|
/// [`std::io`], only [`Self::Interrupted`] has defined semantics in this crate, all other
|
||||||
|
/// variants are provided here only to provide higher-fidelity conversions to and from
|
||||||
|
/// [`std::io::Error`].
|
||||||
|
pub enum ErrorKind {
|
||||||
|
$($kind),*
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ErrorKind {
|
||||||
|
fn description(&self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
$(Self::$kind => stringify!($kind)),*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
fn to_std(self) -> std::io::ErrorKind {
|
||||||
|
match self {
|
||||||
|
$(Self::$kind => std::io::ErrorKind::$kind),*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
fn from_std(o: std::io::ErrorKind) -> ErrorKind {
|
||||||
|
match o {
|
||||||
|
$(std::io::ErrorKind::$kind => ErrorKind::$kind),*,
|
||||||
|
_ => ErrorKind::Other
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
define_errorkind!(
|
||||||
|
NotFound,
|
||||||
|
PermissionDenied,
|
||||||
|
ConnectionRefused,
|
||||||
|
ConnectionReset,
|
||||||
|
ConnectionAborted,
|
||||||
|
NotConnected,
|
||||||
|
AddrInUse,
|
||||||
|
AddrNotAvailable,
|
||||||
|
BrokenPipe,
|
||||||
|
AlreadyExists,
|
||||||
|
WouldBlock,
|
||||||
|
InvalidInput,
|
||||||
|
InvalidData,
|
||||||
|
TimedOut,
|
||||||
|
WriteZero,
|
||||||
|
Interrupted,
|
||||||
|
UnexpectedEof,
|
||||||
|
// Note: Any time we bump the MSRV any new error kinds should be added here!
|
||||||
|
Other
|
||||||
|
);
|
||||||
|
|
||||||
|
pub type Result<T> = core::result::Result<T, Error>;
|
||||||
|
|
||||||
|
/// A generic trait describing an input stream. See [`std::io::Read`] for more info.
|
||||||
|
pub trait Read {
|
||||||
|
fn read(&mut self, buf: &mut [u8]) -> Result<usize>;
|
||||||
|
#[inline]
|
||||||
|
fn read_exact(&mut self, mut buf: &mut [u8]) -> Result<()> {
|
||||||
|
while !buf.is_empty() {
|
||||||
|
match self.read(buf) {
|
||||||
|
Ok(0) => return Err(ErrorKind::UnexpectedEof.into()),
|
||||||
|
Ok(len) => buf = &mut buf[len..],
|
||||||
|
Err(e) if e.kind() == ErrorKind::Interrupted => {}
|
||||||
|
Err(e) => return Err(e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
fn take(&mut self, limit: u64) -> Take<Self> {
|
||||||
|
Take { reader: self, remaining: limit }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Take<'a, R: Read + ?Sized> {
|
||||||
|
reader: &'a mut R,
|
||||||
|
remaining: u64,
|
||||||
|
}
|
||||||
|
impl<'a, R: Read + ?Sized> Read for Take<'a, R> {
|
||||||
|
#[inline]
|
||||||
|
fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
|
||||||
|
let len = core::cmp::min(buf.len(), self.remaining.try_into().unwrap_or(buf.len()));
|
||||||
|
let read = self.reader.read(&mut buf[..len])?;
|
||||||
|
self.remaining -= read.try_into().unwrap_or(self.remaining);
|
||||||
|
Ok(read)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
impl<R: std::io::Read> Read for R {
|
||||||
|
#[inline]
|
||||||
|
fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
|
||||||
|
Ok(<R as std::io::Read>::read(self, buf)?)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "std"))]
|
||||||
|
impl Read for &[u8] {
|
||||||
|
#[inline]
|
||||||
|
fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
|
||||||
|
let cnt = core::cmp::min(self.len(), buf.len());
|
||||||
|
buf[..cnt].copy_from_slice(&self[..cnt]);
|
||||||
|
*self = &self[cnt..];
|
||||||
|
Ok(cnt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Cursor<T> {
|
||||||
|
inner: T,
|
||||||
|
pos: u64,
|
||||||
|
}
|
||||||
|
impl<T: AsRef<[u8]>> Cursor<T> {
|
||||||
|
#[inline]
|
||||||
|
pub fn new(inner: T) -> Self {
|
||||||
|
Cursor { inner, pos: 0 }
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
pub fn position(&self) -> u64 {
|
||||||
|
self.pos
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
pub fn into_inner(self) -> T {
|
||||||
|
self.inner
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<T: AsRef<[u8]>> Read for Cursor<T> {
|
||||||
|
#[inline]
|
||||||
|
fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
|
||||||
|
let inner: &[u8] = self.inner.as_ref();
|
||||||
|
let start_pos = self.pos.try_into().unwrap_or(inner.len());
|
||||||
|
let read = core::cmp::min(inner.len().saturating_sub(start_pos), buf.len());
|
||||||
|
buf[..read].copy_from_slice(&inner[start_pos..start_pos + read]);
|
||||||
|
self.pos = self.pos.saturating_add(read.try_into().unwrap_or(u64::max_value() /* unreachable */));
|
||||||
|
Ok(read)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A generic trait describing an output stream. See [`std::io::Write`] for more info.
|
||||||
|
pub trait Write {
|
||||||
|
fn write(&mut self, buf: &[u8]) -> Result<usize>;
|
||||||
|
fn flush(&mut self) -> Result<()>;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn write_all(&mut self, mut buf: &[u8]) -> Result<()> {
|
||||||
|
while !buf.is_empty() {
|
||||||
|
match self.write(buf) {
|
||||||
|
Ok(0) => return Err(ErrorKind::UnexpectedEof.into()),
|
||||||
|
Ok(len) => buf = &buf[len..],
|
||||||
|
Err(e) if e.kind() == ErrorKind::Interrupted => {}
|
||||||
|
Err(e) => return Err(e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
impl<W: std::io::Write> Write for W {
|
||||||
|
#[inline]
|
||||||
|
fn write(&mut self, buf: &[u8]) -> Result<usize> {
|
||||||
|
Ok(<W as std::io::Write>::write(self, buf)?)
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
fn flush(&mut self) -> Result<()> {
|
||||||
|
Ok(<W as std::io::Write>::flush(self)?)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(all(feature = "alloc", not(feature = "std")))]
|
||||||
|
impl Write for alloc::vec::Vec<u8> {
|
||||||
|
#[inline]
|
||||||
|
fn write(&mut self, buf: &[u8]) -> Result<usize> {
|
||||||
|
self.extend_from_slice(buf);
|
||||||
|
Ok(buf.len())
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
fn flush(&mut self) -> Result<()> { Ok(()) }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "std"))]
|
||||||
|
impl<'a> Write for &'a mut [u8] {
|
||||||
|
#[inline]
|
||||||
|
fn write(&mut self, buf: &[u8]) -> Result<usize> {
|
||||||
|
let cnt = core::cmp::min(self.len(), buf.len());
|
||||||
|
self[..cnt].copy_from_slice(&buf[..cnt]);
|
||||||
|
*self = &mut core::mem::take(self)[cnt..];
|
||||||
|
Ok(cnt)
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
fn flush(&mut self) -> Result<()> { Ok(()) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A sink to which all writes succeed. See [`std::io::Sink`] for more info.
|
||||||
|
pub struct Sink;
|
||||||
|
#[cfg(not(feature = "std"))]
|
||||||
|
impl Write for Sink {
|
||||||
|
#[inline]
|
||||||
|
fn write(&mut self, buf: &[u8]) -> Result<usize> {
|
||||||
|
Ok(buf.len())
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
fn write_all(&mut self, _: &[u8]) -> Result<()> { Ok(()) }
|
||||||
|
#[inline]
|
||||||
|
fn flush(&mut self) -> Result<()> { Ok(()) }
|
||||||
|
}
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
impl std::io::Write for Sink {
|
||||||
|
#[inline]
|
||||||
|
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
|
||||||
|
Ok(buf.len())
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
fn write_all(&mut self, _: &[u8]) -> std::io::Result<()> { Ok(()) }
|
||||||
|
#[inline]
|
||||||
|
fn flush(&mut self) -> std::io::Result<()> { Ok(()) }
|
||||||
|
}
|
||||||
|
/// Returns a sink to which all writes succeed. See [`std::io::sink`] for more info.
|
||||||
|
pub fn sink() -> Sink { Sink }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
/// Re-export std for the below macro
|
||||||
|
pub use std as _std;
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
/// Because we cannot provide a blanket implementation of [`std::io::Write`] for all implementers
|
||||||
|
/// of this crate's `io::Write` trait, we provide this macro instead.
|
||||||
|
///
|
||||||
|
/// This macro will implement `Write` given a `write` and `flush` fn, either by implementing the
|
||||||
|
/// crate's native `io::Write` trait directly, or a more generic trait from `std` for users using
|
||||||
|
/// that feature. In any case, this crate's `io::Write` feature will be implemented for the given
|
||||||
|
/// type, even if indirectly.
|
||||||
|
#[cfg(not(feature = "std"))]
|
||||||
|
macro_rules! impl_write {
|
||||||
|
($ty: ty, $write_fn: expr, $flush_fn: expr $(, $bounded_ty: ident : $bounds: path),*) => {
|
||||||
|
impl<$($bounded_ty: $bounds),*> $crate::io::Write for $ty {
|
||||||
|
#[inline]
|
||||||
|
fn write(&mut self, buf: &[u8]) -> $crate::io::Result<usize> {
|
||||||
|
$write_fn(self, buf)
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
fn flush(&mut self) -> $crate::io::Result<()> {
|
||||||
|
$flush_fn(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
/// Because we cannot provide a blanket implementation of [`std::io::Write`] for all implementers
|
||||||
|
/// of this crate's `io::Write` trait, we provide this macro instead.
|
||||||
|
///
|
||||||
|
/// This macro will implement `Write` given a `write` and `flush` fn, either by implementing the
|
||||||
|
/// crate's native `io::Write` trait directly, or a more generic trait from `std` for users using
|
||||||
|
/// that feature. In any case, this crate's `io::Write` feature will be implemented for the given
|
||||||
|
/// type, even if indirectly.
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
macro_rules! impl_write {
|
||||||
|
($ty: ty, $write_fn: expr, $flush_fn: expr $(, $bounded_ty: ident : $bounds: path),*) => {
|
||||||
|
impl<$($bounded_ty: $bounds),*> $crate::_std::io::Write for $ty {
|
||||||
|
#[inline]
|
||||||
|
fn write(&mut self, buf: &[u8]) -> $crate::_std::io::Result<usize> {
|
||||||
|
$write_fn(self, buf)
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
fn flush(&mut self) -> $crate::_std::io::Result<()> {
|
||||||
|
$flush_fn(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue