#![recursion_limit = "256"]
#![deny(dead_code, missing_docs, warnings)]
#[cfg(feature = "derive")]
pub extern crate strict_encoding_derive as derive;
#[cfg(feature = "derive")]
pub use derive::{NetworkDecode, NetworkEncode, StrictDecode, StrictEncode};
#[macro_use]
extern crate amplify;
#[cfg(test)]
#[macro_use]
extern crate strict_encoding_test;
#[cfg(feature = "serde")]
#[macro_use]
extern crate serde;
#[cfg(feature = "lnpbp_secp256k1zkp")]
extern crate lnpbp_secp256k1zkp as secp256k1zkp;
#[macro_use]
mod macros;
mod amplify_types;
#[cfg(feature = "bitcoin")]
mod bitcoin;
mod bitcoin_hashes;
mod collections;
#[cfg(feature = "crypto")]
mod crypto;
#[cfg(feature = "miniscript")]
mod miniscript;
#[cfg(feature = "monero")]
mod monero;
pub mod net;
mod pointers;
mod primitives;
mod slice32;
pub mod strategies;
use std::io::Seek;
use std::ops::Range;
use std::path::Path;
use std::string::FromUtf8Error;
use std::{fmt, fs, io};
#[cfg(feature = "bitcoin")]
pub use ::bitcoin::consensus::encode::{ReadExt, WriteExt};
use amplify::IoError;
pub use collections::{LargeVec, MediumVec};
pub use strategies::Strategy;
pub trait StrictEncode {
fn strict_encode<E: io::Write>(&self, e: E) -> Result<usize, Error>;
fn strict_serialize(&self) -> Result<Vec<u8>, Error> {
let mut e = vec![];
let _ = self.strict_encode(&mut e)?;
Ok(e)
}
fn strict_file_save(&self, path: impl AsRef<Path>) -> Result<usize, Error> {
let file = fs::File::create(path)?;
self.strict_encode(file)
}
}
pub trait StrictDecode: Sized {
fn strict_decode<D: io::Read>(d: D) -> Result<Self, Error>;
fn strict_deserialize(data: impl AsRef<[u8]>) -> Result<Self, Error> {
Self::strict_decode(data.as_ref())
}
fn strict_file_load(path: impl AsRef<Path>) -> Result<Self, Error> {
let mut file = fs::File::open(path)?;
let obj = Self::strict_decode(&mut file)?;
if file.stream_position()? != file.metadata()?.len() {
Err(Error::DataNotEntirelyConsumed)
} else {
Ok(obj)
}
}
}
pub fn strict_serialize<T>(data: &T) -> Result<Vec<u8>, Error>
where
T: StrictEncode,
{
let mut encoder = io::Cursor::new(vec![]);
data.strict_encode(&mut encoder)?;
Ok(encoder.into_inner())
}
pub fn strict_deserialize<T>(data: impl AsRef<[u8]>) -> Result<T, Error>
where
T: StrictDecode,
{
let mut decoder = io::Cursor::new(data.as_ref());
let rv = T::strict_decode(&mut decoder)?;
let consumed = decoder.position() as usize;
if consumed == data.as_ref().len() {
Ok(rv)
} else {
Err(Error::DataNotEntirelyConsumed)
}
}
#[derive(Clone, PartialEq, Eq, Debug, Display, From, Error)]
#[display(doc_comments)]
pub enum Error {
#[from(io::Error)]
#[from(io::ErrorKind)]
Io(IoError),
#[from]
Utf8Conversion(std::str::Utf8Error),
ExceedMaxItems(usize),
#[display(
"Invalid value {0} met as an optional type byte, which must be equal \
to either 0 (no value) or 1"
)]
WrongOptionalEncoding(u8),
EnumValueOverflow(&'static str),
EnumValueNotKnown(&'static str, usize),
UnsupportedDataStructure(&'static str),
ValueOutOfRange(&'static str, Range<u128>, u128),
RepeatedValue(String),
#[display(
"Data were not consumed entirely during strict decoding procedure"
)]
DataNotEntirelyConsumed,
DataIntegrityError(String),
}
impl From<Error> for fmt::Error {
#[inline]
fn from(_: Error) -> Self { fmt::Error }
}
impl From<FromUtf8Error> for Error {
fn from(err: FromUtf8Error) -> Self {
Error::Utf8Conversion(err.utf8_error())
}
}
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Display, Error)]
#[display(doc_comments)]
pub enum TlvError {
Order {
read: u64,
max: u64,
},
Len {
expected: u64,
actual: u64,
},
Repeated(u64),
UnknownEvenType(u64),
}
impl From<TlvError> for Error {
fn from(err: TlvError) -> Self {
match err {
TlvError::Repeated(size) => Error::RepeatedValue(size.to_string()),
err => Error::DataIntegrityError(err.to_string()),
}
}
}