Hide base58::Error internals
As is convention here in `rust-bitcoin`, hide the `base58::Error` internals by adding struct error types.
This commit is contained in:
parent
4f68e79da0
commit
af49841433
|
@ -6,16 +6,16 @@ use core::fmt;
|
|||
|
||||
use internals::write_err;
|
||||
|
||||
/// An error that might occur during base58 decoding.
|
||||
/// An error occurred during base58 decoding (with checksum).
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
#[non_exhaustive]
|
||||
pub enum Error {
|
||||
/// Invalid character while decoding.
|
||||
Decode(InvalidCharacterError),
|
||||
/// Checksum was not correct (expected, actual).
|
||||
BadChecksum(u32, u32),
|
||||
/// Checked data was less than 4 bytes.
|
||||
TooShort(usize),
|
||||
/// Checksum was not correct.
|
||||
IncorrectChecksum(IncorrectChecksumError),
|
||||
/// Checked data was too short.
|
||||
TooShort(TooShortError),
|
||||
}
|
||||
|
||||
internals::impl_from_infallible!(Error);
|
||||
|
@ -26,9 +26,8 @@ impl fmt::Display for Error {
|
|||
|
||||
match *self {
|
||||
Decode(ref e) => write_err!(f, "decode"; e),
|
||||
BadChecksum(exp, actual) =>
|
||||
write!(f, "base58ck checksum {:#x} does not match expected {:#x}", actual, exp),
|
||||
TooShort(_) => write!(f, "base58ck data not even long enough for a checksum"),
|
||||
IncorrectChecksum(ref e) => write_err!(f, "incorrect checksum"; e),
|
||||
TooShort(ref e) => write_err!(f, "too short"; e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -38,10 +37,10 @@ impl std::error::Error for Error {
|
|||
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
||||
use Error::*;
|
||||
|
||||
match self {
|
||||
match *self {
|
||||
Decode(ref e) => Some(e),
|
||||
BadChecksum(_, _)
|
||||
| TooShort(_) => None,
|
||||
IncorrectChecksum(ref e) => Some(e),
|
||||
TooShort(ref e) => Some(e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -51,6 +50,64 @@ impl From<InvalidCharacterError> for Error {
|
|||
fn from(e: InvalidCharacterError) -> Self { Self::Decode(e) }
|
||||
}
|
||||
|
||||
impl From<IncorrectChecksumError> for Error {
|
||||
#[inline]
|
||||
fn from(e: IncorrectChecksumError) -> Self { Self::IncorrectChecksum(e) }
|
||||
}
|
||||
|
||||
impl From<TooShortError> for Error {
|
||||
#[inline]
|
||||
fn from(e: TooShortError) -> Self { Self::TooShort(e) }
|
||||
}
|
||||
|
||||
/// Checksum was not correct.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct IncorrectChecksumError {
|
||||
/// The incorrect checksum.
|
||||
pub(super) incorrect: u32,
|
||||
/// The expected checksum.
|
||||
pub(super) expected: u32,
|
||||
}
|
||||
|
||||
impl IncorrectChecksumError {
|
||||
/// Returns the incorrect checksum along with the expected checksum.
|
||||
pub fn incorrect_checksum(&self) -> (u32, u32) { (self.incorrect, self.expected) }
|
||||
}
|
||||
|
||||
impl fmt::Display for IncorrectChecksumError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"base58 checksum {:#x} does not match expected {:#x}",
|
||||
self.incorrect, self.expected
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl std::error::Error for IncorrectChecksumError {}
|
||||
|
||||
/// The decode base58 data was too short (require at least 4 bytes for checksum).
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct TooShortError {
|
||||
/// The length of the decoded data.
|
||||
pub(super) length: usize,
|
||||
}
|
||||
|
||||
impl TooShortError {
|
||||
/// Returns the invalid base58 string length (require at least 4 bytes for checksum).
|
||||
pub fn invalid_base58_length(&self) -> usize { self.length }
|
||||
}
|
||||
|
||||
impl fmt::Display for TooShortError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "base58 decoded data was not long enough, must be at least 4 byte: {}", self.length)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl std::error::Error for TooShortError {}
|
||||
|
||||
/// Found a invalid ASCII byte while decoding base58 string.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct InvalidCharacterError {
|
||||
|
|
|
@ -34,6 +34,8 @@ pub use std::{string::String, vec::Vec};
|
|||
|
||||
use hashes::{sha256d, Hash};
|
||||
|
||||
use crate::error::{IncorrectChecksumError, TooShortError};
|
||||
|
||||
#[rustfmt::skip] // Keep public re-exports separate.
|
||||
#[doc(inline)]
|
||||
pub use self::error::{Error, InvalidCharacterError};
|
||||
|
@ -93,7 +95,7 @@ pub fn decode(data: &str) -> Result<Vec<u8>, InvalidCharacterError> {
|
|||
pub fn decode_check(data: &str) -> Result<Vec<u8>, Error> {
|
||||
let mut ret: Vec<u8> = decode(data)?;
|
||||
if ret.len() < 4 {
|
||||
return Err(Error::TooShort(ret.len()));
|
||||
return Err(TooShortError { length: ret.len() }.into());
|
||||
}
|
||||
let check_start = ret.len() - 4;
|
||||
|
||||
|
@ -104,8 +106,8 @@ pub fn decode_check(data: &str) -> Result<Vec<u8>, Error> {
|
|||
let expected = u32::from_le_bytes(hash_check);
|
||||
let actual = u32::from_le_bytes(data_check);
|
||||
|
||||
if expected != actual {
|
||||
return Err(Error::BadChecksum(expected, actual));
|
||||
if actual != expected {
|
||||
return Err(IncorrectChecksumError { incorrect: actual, expected }.into());
|
||||
}
|
||||
|
||||
ret.truncate(check_start);
|
||||
|
@ -282,6 +284,6 @@ mod tests {
|
|||
// Check that empty slice passes roundtrip.
|
||||
assert_eq!(decode_check(&encode_check(&[])), Ok(vec![]));
|
||||
// Check that `len > 4` is enforced.
|
||||
assert_eq!(decode_check(&encode(&[1, 2, 3])), Err(Error::TooShort(3)));
|
||||
assert_eq!(decode_check(&encode(&[1, 2, 3])), Err(TooShortError { length: 3 }.into()));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue