1#![no_std]
16#![warn(missing_docs)]
18#![warn(deprecated_in_future)]
19#![doc(test(attr(warn(unused))))]
20#[cfg(feature = "alloc")]
23extern crate alloc;
24
25#[cfg(feature = "std")]
26extern crate std;
27
28#[cfg(feature = "serde")]
29#[macro_use]
30extern crate serde;
31
32#[cfg(feature = "hex")]
33pub extern crate hex_stable as hex;
34
35#[doc(hidden)]
36pub mod _export {
37 pub mod _core {
39 pub use core::*;
40 }
41}
42
43mod hash_types;
44#[cfg(feature = "alloc")]
45mod opcodes;
46
47pub mod block;
48pub mod merkle_tree;
49#[cfg(feature = "alloc")]
50pub mod script;
51pub mod transaction;
52#[cfg(feature = "alloc")]
53pub mod witness;
54
55#[doc(inline)]
56pub use units::{
57 amount::{self, Amount, SignedAmount},
58 block::{BlockHeight, BlockHeightInterval, BlockMtp, BlockMtpInterval},
59 fee_rate::{self, FeeRate},
60 locktime::{self, absolute, relative},
61 parse_int,
62 pow::{self, CompactTarget},
63 result::{self, NumOpResult},
64 sequence::{self, Sequence},
65 time::{self, BlockTime},
66 weight::{self, Weight},
67};
68
69#[deprecated(since = "1.0.0-rc.0", note = "use `BlockHeightInterval` instead")]
70#[doc(hidden)]
71pub type BlockInterval = BlockHeightInterval;
72
73#[doc(inline)]
74#[cfg(feature = "alloc")]
75pub use self::{
76 block::{
77 Block, Checked as BlockChecked, Unchecked as BlockUnchecked, Validation as BlockValidation,
78 },
79 script::{
80 RedeemScript, RedeemScriptBuf, ScriptPubKey, ScriptPubKeyBuf, ScriptSig, ScriptSigBuf,
81 TapScript, TapScriptBuf, WitnessScript, WitnessScriptBuf,
82 },
83 transaction::{Transaction, TxIn, TxOut},
84 witness::Witness,
85};
86#[doc(inline)]
87pub use self::{
88 block::{BlockHash, Header as BlockHeader, Version as BlockVersion, WitnessCommitment},
89 merkle_tree::{TxMerkleNode, WitnessMerkleNode},
90 transaction::{Ntxid, OutPoint, Txid, Version as TransactionVersion, Wtxid},
91};
92
93#[rustfmt::skip]
94#[allow(unused_imports)]
95mod prelude {
96 #[cfg(feature = "alloc")]
97 pub use alloc::collections::{BTreeMap, BTreeSet, btree_map, BinaryHeap};
98
99 #[cfg(feature = "alloc")]
100 pub use alloc::{string::{String, ToString}, vec::Vec, boxed::Box, borrow::{Borrow, BorrowMut, Cow, ToOwned}, slice, rc};
101
102 #[cfg(all(feature = "alloc", target_has_atomic = "ptr"))]
103 pub use alloc::sync;
104}
105
106#[cfg(feature = "alloc")]
107use encoding::Encoder;
108#[cfg(feature = "alloc")]
109use internals::array_vec::ArrayVec;
110
111#[cfg(feature = "alloc")]
113pub(crate) fn compact_size_encode(value: usize) -> ArrayVec<u8, 9> {
114 let encoder = encoding::CompactSizeEncoder::new(value);
115 ArrayVec::from_slice(encoder.current_chunk())
116}
117
118#[cfg(all(feature = "hex", feature = "alloc"))]
119use core::{convert, fmt};
120
121#[cfg(all(feature = "hex", feature = "alloc"))]
122use encoding::{Decodable, Decoder};
123#[cfg(all(feature = "hex", feature = "alloc"))]
124use internals::write_err;
125
126#[cfg(all(feature = "hex", feature = "alloc"))]
128enum ParsePrimitiveError<T: Decodable> {
129 OddLengthString(hex::error::OddLengthStringError),
131 InvalidChar(hex::error::InvalidCharError),
133 Decode(<T::Decoder as Decoder>::Error),
135}
136
137#[cfg(all(feature = "hex", feature = "alloc"))]
138impl<T: Decodable> fmt::Debug for ParsePrimitiveError<T> {
139 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
140 match self {
141 Self::OddLengthString(ref e) => write_err!(f, "odd length string"; e),
142 Self::InvalidChar(ref e) => write_err!(f, "invalid character"; e),
143 Self::Decode(_) =>
145 write!(f, "failure decoding hex string into {}", core::any::type_name::<T>()),
146 }
147 }
148}
149
150#[cfg(all(feature = "hex", feature = "alloc"))]
151impl<T: Decodable> fmt::Display for ParsePrimitiveError<T> {
152 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(&self, f) }
153}
154
155#[cfg(all(feature = "hex", feature = "alloc"))]
156impl<T: Decodable> From<hex::DecodeVariableLengthBytesError> for ParsePrimitiveError<T> {
157 fn from(dec_err: hex::DecodeVariableLengthBytesError) -> Self {
158 use hex::DecodeVariableLengthBytesError as D;
159
160 match dec_err {
161 D::InvalidChar(err) => Self::InvalidChar(err),
162 D::OddLengthString(err) => Self::OddLengthString(err),
163 }
164 }
165}
166
167#[cfg(all(feature = "hex", feature = "alloc"))]
168impl<T: Decodable> From<convert::Infallible> for ParsePrimitiveError<T> {
169 fn from(never: convert::Infallible) -> Self { match never {} }
170}
171
172#[cfg(all(feature = "hex", feature = "alloc", feature = "std"))]
173impl<T: Decodable> std::error::Error for ParsePrimitiveError<T> {
174 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
175 match self {
176 Self::OddLengthString(ref e) => Some(e),
177 Self::InvalidChar(ref e) => Some(e),
178 Self::Decode(_) => None,
179 }
180 }
181}
182
183#[cfg(all(feature = "hex", feature = "alloc"))]
184pub(crate) mod hex_codec {
185 use encoding::{Encodable, EncodableByteIter};
186 use hex_unstable::{BytesToHexIter, Case};
187
188 use super::{fmt, Decodable, ParsePrimitiveError};
189
190 #[inline]
192 fn hex_write_with_case<T: Encodable + Decodable>(
193 obj: &HexPrimitive<T>,
194 f: &mut fmt::Formatter,
195 case: Case,
196 ) -> fmt::Result {
197 let iter = BytesToHexIter::new(encoding::EncodableByteIter::new(obj.0), case);
198 let collection = iter.collect::<alloc::string::String>();
199 f.pad(&collection)
200 }
201
202 pub(crate) struct HexPrimitive<'a, T: Encodable + Decodable>(pub &'a T);
208
209 impl<'a, T: Encodable + Decodable> IntoIterator for &HexPrimitive<'a, T> {
210 type Item = u8;
211 type IntoIter = EncodableByteIter<'a, T>;
212
213 fn into_iter(self) -> Self::IntoIter { EncodableByteIter::new(self.0) }
214 }
215
216 impl<T: Encodable + Decodable> HexPrimitive<'_, T> {
217 pub(crate) fn from_str(s: &str) -> Result<T, ParsePrimitiveError<T>> {
229 let bytes = hex::decode_to_vec(s).map_err(ParsePrimitiveError::from)?;
230
231 encoding::decode_from_slice(&bytes).map_err(ParsePrimitiveError::Decode)
232 }
233 }
234
235 impl<T: Encodable + Decodable> fmt::Display for HexPrimitive<'_, T> {
236 #[inline]
237 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::LowerHex::fmt(self, f) }
238 }
239
240 impl<T: Encodable + Decodable> fmt::Debug for HexPrimitive<'_, T> {
241 #[inline]
242 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::LowerHex::fmt(self, f) }
243 }
244
245 impl<T: Encodable + Decodable> fmt::LowerHex for HexPrimitive<'_, T> {
246 #[inline]
247 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
248 hex_write_with_case(self, f, Case::Lower)
249 }
250 }
251
252 impl<T: Encodable + Decodable> fmt::UpperHex for HexPrimitive<'_, T> {
253 #[inline]
254 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
255 hex_write_with_case(self, f, Case::Upper)
256 }
257 }
258}
259
260#[cfg(test)]
261mod tests {
262 #[cfg(feature = "alloc")]
263 use alloc::{format, string::ToString};
264
265 #[cfg(feature = "alloc")]
266 use super::*;
267
268 #[test]
269 #[cfg(all(feature = "alloc", feature = "hex"))]
270 fn parse_primitive_error_display() {
271 let odd: ParsePrimitiveError<block::Header> =
272 hex_codec::HexPrimitive::from_str("0").unwrap_err();
273 let invalid: ParsePrimitiveError<block::Header> =
274 hex_codec::HexPrimitive::from_str("zz").unwrap_err();
275 let decode: ParsePrimitiveError<block::Header> =
276 hex_codec::HexPrimitive::from_str("00").unwrap_err();
277
278 assert!(!odd.to_string().is_empty());
279 assert!(!invalid.to_string().is_empty());
280 assert!(!decode.to_string().is_empty());
281 }
282
283 #[test]
284 #[cfg(all(feature = "hex", feature = "std"))]
285 fn parse_primitive_error_source() {
286 use std::error::Error as _;
287
288 let odd: ParsePrimitiveError<block::Header> =
289 hex_codec::HexPrimitive::from_str("0").unwrap_err();
290 let invalid: ParsePrimitiveError<block::Header> =
291 hex_codec::HexPrimitive::from_str("zz").unwrap_err();
292 let decode: ParsePrimitiveError<block::Header> =
293 hex_codec::HexPrimitive::from_str("00").unwrap_err();
294
295 assert!(odd.source().is_some());
296 assert!(invalid.source().is_some());
297 assert!(decode.source().is_none());
298 }
299
300 #[test]
301 #[cfg(all(feature = "alloc", feature = "hex"))]
302 fn hex_primitive_iter_and_debug() {
303 let header: block::Header =
304 encoding::decode_from_slice(&[0u8; block::Header::SIZE]).expect("valid header");
305 let hex = hex_codec::HexPrimitive(&header);
306
307 assert_eq!((&hex).into_iter().next(), Some(0u8));
308 assert!(!format!("{hex:?}").is_empty());
309 }
310}