base58: Re-order code
Code is arguably easier to read if the most important stuff comes first. In the old days, when writing C, we had to put definitions before they were used but in Rust this is not the case Re-order the `base58` file so that the public API functions are up the top then other helper functions are defined _after_ they are called. Refactor only, no logic changes.
This commit is contained in:
parent
d362e6286a
commit
a94af5c052
|
@ -14,92 +14,6 @@ use core::convert::TryInto;
|
||||||
|
|
||||||
use crate::hashes::{sha256d, Hash};
|
use crate::hashes::{sha256d, Hash};
|
||||||
|
|
||||||
/// An error that might occur during base58 decoding.
|
|
||||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone)]
|
|
||||||
#[non_exhaustive]
|
|
||||||
pub enum Error {
|
|
||||||
/// Invalid character encountered.
|
|
||||||
BadByte(u8),
|
|
||||||
/// Checksum was not correct (expected, actual).
|
|
||||||
BadChecksum(u32, u32),
|
|
||||||
/// The length (in bytes) of the object was not correct, note that if the length is excessively
|
|
||||||
/// long the provided length may be an estimate (and the checksum step may be skipped).
|
|
||||||
InvalidLength(usize),
|
|
||||||
/// Extended Key version byte(s) were not recognized.
|
|
||||||
InvalidExtendedKeyVersion([u8; 4]),
|
|
||||||
/// Address version byte were not recognized.
|
|
||||||
InvalidAddressVersion(u8),
|
|
||||||
/// Checked data was less than 4 bytes.
|
|
||||||
TooShort(usize),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for Error {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
match *self {
|
|
||||||
Error::BadByte(b) => write!(f, "invalid base58 character {:#x}", b),
|
|
||||||
Error::BadChecksum(exp, actual) => write!(f, "base58ck checksum {:#x} does not match expected {:#x}", actual, exp),
|
|
||||||
Error::InvalidLength(ell) => write!(f, "length {} invalid for this base58 type", ell),
|
|
||||||
Error::InvalidExtendedKeyVersion(ref v) => write!(f, "extended key version {:#04x?} is invalid for this base58 type", v),
|
|
||||||
Error::InvalidAddressVersion(ref v) => write!(f, "address version {} is invalid for this base58 type", v),
|
|
||||||
Error::TooShort(_) => write!(f, "base58ck data not even long enough for a checksum"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
|
|
||||||
impl std::error::Error for Error {
|
|
||||||
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
|
||||||
use self::Error::*;
|
|
||||||
|
|
||||||
match self {
|
|
||||||
BadByte(_)
|
|
||||||
| BadChecksum(_, _)
|
|
||||||
| InvalidLength(_)
|
|
||||||
| InvalidExtendedKeyVersion(_)
|
|
||||||
| InvalidAddressVersion(_)
|
|
||||||
| TooShort(_) => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Vector-like object that holds the first 100 elements on the stack. If more space is needed it
|
|
||||||
/// will be allocated on the heap.
|
|
||||||
struct SmallVec<T> {
|
|
||||||
len: usize,
|
|
||||||
stack: [T; 100],
|
|
||||||
heap: Vec<T>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Default + Copy> SmallVec<T> {
|
|
||||||
fn new() -> SmallVec<T> {
|
|
||||||
SmallVec {
|
|
||||||
len: 0,
|
|
||||||
stack: [T::default(); 100],
|
|
||||||
heap: Vec::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn push(&mut self, val: T) {
|
|
||||||
if self.len < 100 {
|
|
||||||
self.stack[self.len] = val;
|
|
||||||
self.len += 1;
|
|
||||||
} else {
|
|
||||||
self.heap.push(val);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn iter(&self) -> iter::Chain<slice::Iter<T>, slice::Iter<T>> {
|
|
||||||
// If len<100 then we just append an empty vec
|
|
||||||
self.stack[0..self.len].iter().chain(self.heap.iter())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn iter_mut(&mut self) -> iter::Chain<slice::IterMut<T>, slice::IterMut<T>> {
|
|
||||||
// If len<100 then we just append an empty vec
|
|
||||||
self.stack[0..self.len].iter_mut().chain(self.heap.iter_mut())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static BASE58_CHARS: &[u8] = b"123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
|
static BASE58_CHARS: &[u8] = b"123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
|
||||||
|
|
||||||
static BASE58_DIGITS: [Option<u8>; 128] = [
|
static BASE58_DIGITS: [Option<u8>; 128] = [
|
||||||
|
@ -174,6 +88,43 @@ pub fn from_check(data: &str) -> Result<Vec<u8>, Error> {
|
||||||
Ok(ret)
|
Ok(ret)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Encodes `data` as a base58 string.
|
||||||
|
pub fn encode_slice(data: &[u8]) -> String {
|
||||||
|
encode_iter(data.iter().cloned())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Encodes `data` as a base58 string including the checksum.
|
||||||
|
///
|
||||||
|
/// The checksum is the first 4 256-digits of the object's Bitcoin hash, concatenated onto the end.
|
||||||
|
pub fn check_encode_slice(data: &[u8]) -> String {
|
||||||
|
let checksum = sha256d::Hash::hash(data);
|
||||||
|
encode_iter(
|
||||||
|
data.iter()
|
||||||
|
.cloned()
|
||||||
|
.chain(checksum[0..4].iter().cloned())
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Encodes `data` as base58, including the checksum, into a formatter.
|
||||||
|
///
|
||||||
|
/// The checksum is the first 4 256-digits of the object's Bitcoin hash, concatenated onto the end.
|
||||||
|
pub fn check_encode_slice_to_fmt(fmt: &mut fmt::Formatter, data: &[u8]) -> fmt::Result {
|
||||||
|
let checksum = sha256d::Hash::hash(data);
|
||||||
|
let iter = data.iter()
|
||||||
|
.cloned()
|
||||||
|
.chain(checksum[0..4].iter().cloned());
|
||||||
|
format_iter(fmt, iter)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn encode_iter<I>(data: I) -> String
|
||||||
|
where
|
||||||
|
I: Iterator<Item=u8> + Clone,
|
||||||
|
{
|
||||||
|
let mut ret = String::new();
|
||||||
|
format_iter(&mut ret, data).expect("writing into string shouldn't fail");
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
|
||||||
fn format_iter<I, W>(writer: &mut W, data: I) -> Result<(), fmt::Error>
|
fn format_iter<I, W>(writer: &mut W, data: I) -> Result<(), fmt::Error>
|
||||||
where
|
where
|
||||||
I: Iterator<Item=u8> + Clone,
|
I: Iterator<Item=u8> + Clone,
|
||||||
|
@ -215,42 +166,90 @@ where
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn encode_iter<I>(data: I) -> String
|
/// Vector-like object that holds the first 100 elements on the stack. If more space is needed it
|
||||||
where
|
/// will be allocated on the heap.
|
||||||
I: Iterator<Item=u8> + Clone,
|
struct SmallVec<T> {
|
||||||
{
|
len: usize,
|
||||||
let mut ret = String::new();
|
stack: [T; 100],
|
||||||
format_iter(&mut ret, data).expect("writing into string shouldn't fail");
|
heap: Vec<T>,
|
||||||
ret
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T: Default + Copy> SmallVec<T> {
|
||||||
|
fn new() -> SmallVec<T> {
|
||||||
|
SmallVec {
|
||||||
|
len: 0,
|
||||||
|
stack: [T::default(); 100],
|
||||||
|
heap: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Encodes `data` as a base58 string.
|
fn push(&mut self, val: T) {
|
||||||
pub fn encode_slice(data: &[u8]) -> String {
|
if self.len < 100 {
|
||||||
encode_iter(data.iter().cloned())
|
self.stack[self.len] = val;
|
||||||
|
self.len += 1;
|
||||||
|
} else {
|
||||||
|
self.heap.push(val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn iter(&self) -> iter::Chain<slice::Iter<T>, slice::Iter<T>> {
|
||||||
|
// If len<100 then we just append an empty vec
|
||||||
|
self.stack[0..self.len].iter().chain(self.heap.iter())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn iter_mut(&mut self) -> iter::Chain<slice::IterMut<T>, slice::IterMut<T>> {
|
||||||
|
// If len<100 then we just append an empty vec
|
||||||
|
self.stack[0..self.len].iter_mut().chain(self.heap.iter_mut())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Encodes `data` as a base58 string including the checksum.
|
/// An error that might occur during base58 decoding.
|
||||||
///
|
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone)]
|
||||||
/// The checksum is the first 4 256-digits of the object's Bitcoin hash, concatenated onto the end.
|
#[non_exhaustive]
|
||||||
pub fn check_encode_slice(data: &[u8]) -> String {
|
pub enum Error {
|
||||||
let checksum = sha256d::Hash::hash(data);
|
/// Invalid character encountered.
|
||||||
encode_iter(
|
BadByte(u8),
|
||||||
data.iter()
|
/// Checksum was not correct (expected, actual).
|
||||||
.cloned()
|
BadChecksum(u32, u32),
|
||||||
.chain(checksum[0..4].iter().cloned())
|
/// The length (in bytes) of the object was not correct, note that if the length is excessively
|
||||||
)
|
/// long the provided length may be an estimate (and the checksum step may be skipped).
|
||||||
|
InvalidLength(usize),
|
||||||
|
/// Extended Key version byte(s) were not recognized.
|
||||||
|
InvalidExtendedKeyVersion([u8; 4]),
|
||||||
|
/// Address version byte were not recognized.
|
||||||
|
InvalidAddressVersion(u8),
|
||||||
|
/// Checked data was less than 4 bytes.
|
||||||
|
TooShort(usize),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Encodes `data` as base58, including the checksum, into a formatter.
|
impl fmt::Display for Error {
|
||||||
///
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
/// The checksum is the first 4 256-digits of the object's Bitcoin hash, concatenated onto the end.
|
match *self {
|
||||||
pub fn check_encode_slice_to_fmt(fmt: &mut fmt::Formatter, data: &[u8]) -> fmt::Result {
|
Error::BadByte(b) => write!(f, "invalid base58 character {:#x}", b),
|
||||||
let checksum = sha256d::Hash::hash(data);
|
Error::BadChecksum(exp, actual) => write!(f, "base58ck checksum {:#x} does not match expected {:#x}", actual, exp),
|
||||||
let iter = data.iter()
|
Error::InvalidLength(ell) => write!(f, "length {} invalid for this base58 type", ell),
|
||||||
.cloned()
|
Error::InvalidExtendedKeyVersion(ref v) => write!(f, "extended key version {:#04x?} is invalid for this base58 type", v),
|
||||||
.chain(checksum[0..4].iter().cloned());
|
Error::InvalidAddressVersion(ref v) => write!(f, "address version {} is invalid for this base58 type", v),
|
||||||
format_iter(fmt, iter)
|
Error::TooShort(_) => write!(f, "base58ck data not even long enough for a checksum"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
|
||||||
|
impl std::error::Error for Error {
|
||||||
|
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
||||||
|
use self::Error::*;
|
||||||
|
|
||||||
|
match self {
|
||||||
|
BadByte(_)
|
||||||
|
| BadChecksum(_, _)
|
||||||
|
| InvalidLength(_)
|
||||||
|
| InvalidExtendedKeyVersion(_)
|
||||||
|
| InvalidAddressVersion(_)
|
||||||
|
| TooShort(_) => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
Loading…
Reference in New Issue