base58: Close all errors
Currently we have a bunch of public errors in the `base58` crate. Only two are returned by public functions `decode()` and `decode_check()` (`Error` and `InvalidCharacterError` respectively). - Close the two public errors by adding private inner errors. - Add getters on the public errors to get the error data. - Make all other errors private. - Call `impl_from_infallible` for _all_ error types. Done as part of #3261
This commit is contained in:
parent
0f887707ea
commit
c92290278e
|
@ -8,8 +8,10 @@ use internals::write_err;
|
||||||
|
|
||||||
/// An error occurred during base58 decoding (with checksum).
|
/// An error occurred during base58 decoding (with checksum).
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
#[non_exhaustive]
|
pub struct Error(pub(super) ErrorInner);
|
||||||
pub enum Error {
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub(super) enum ErrorInner {
|
||||||
/// Invalid character while decoding.
|
/// Invalid character while decoding.
|
||||||
Decode(InvalidCharacterError),
|
Decode(InvalidCharacterError),
|
||||||
/// Checksum was not correct.
|
/// Checksum was not correct.
|
||||||
|
@ -19,12 +21,39 @@ pub enum Error {
|
||||||
}
|
}
|
||||||
|
|
||||||
internals::impl_from_infallible!(Error);
|
internals::impl_from_infallible!(Error);
|
||||||
|
internals::impl_from_infallible!(ErrorInner);
|
||||||
|
|
||||||
|
impl Error {
|
||||||
|
/// Returns the invalid base58 ssscharacter, if encountered.
|
||||||
|
pub fn invalid_character(&self) -> Option<u8> {
|
||||||
|
match self.0 {
|
||||||
|
ErrorInner::Decode(ref e) => Some(e.invalid_character()),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the incorrect checksum along with the expected checksum, if encountered.
|
||||||
|
pub fn incorrect_checksum(&self) -> Option<(u32, u32)> {
|
||||||
|
match self.0 {
|
||||||
|
ErrorInner::IncorrectChecksum(ref e) => Some((e.incorrect, e.expected)),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the invalid base58 string length (require at least 4 bytes for checksum), if encountered.
|
||||||
|
pub fn invalid_length(&self) -> Option<usize> {
|
||||||
|
match self.0 {
|
||||||
|
ErrorInner::TooShort(ref e) => Some(e.length),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl fmt::Display for Error {
|
impl fmt::Display for Error {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
use Error::*;
|
use ErrorInner::*;
|
||||||
|
|
||||||
match *self {
|
match self.0 {
|
||||||
Decode(ref e) => write_err!(f, "decode"; e),
|
Decode(ref e) => write_err!(f, "decode"; e),
|
||||||
IncorrectChecksum(ref e) => write_err!(f, "incorrect checksum"; e),
|
IncorrectChecksum(ref e) => write_err!(f, "incorrect checksum"; e),
|
||||||
TooShort(ref e) => write_err!(f, "too short"; e),
|
TooShort(ref e) => write_err!(f, "too short"; e),
|
||||||
|
@ -35,9 +64,9 @@ impl fmt::Display for Error {
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
impl std::error::Error for Error {
|
impl std::error::Error for Error {
|
||||||
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
||||||
use Error::*;
|
use ErrorInner::*;
|
||||||
|
|
||||||
match *self {
|
match self.0 {
|
||||||
Decode(ref e) => Some(e),
|
Decode(ref e) => Some(e),
|
||||||
IncorrectChecksum(ref e) => Some(e),
|
IncorrectChecksum(ref e) => Some(e),
|
||||||
TooShort(ref e) => Some(e),
|
TooShort(ref e) => Some(e),
|
||||||
|
@ -46,33 +75,27 @@ impl std::error::Error for Error {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<InvalidCharacterError> for Error {
|
impl From<InvalidCharacterError> for Error {
|
||||||
#[inline]
|
fn from(e: InvalidCharacterError) -> Self { Self(ErrorInner::Decode(e)) }
|
||||||
fn from(e: InvalidCharacterError) -> Self { Self::Decode(e) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<IncorrectChecksumError> for Error {
|
impl From<IncorrectChecksumError> for Error {
|
||||||
#[inline]
|
fn from(e: IncorrectChecksumError) -> Self { Self(ErrorInner::IncorrectChecksum(e)) }
|
||||||
fn from(e: IncorrectChecksumError) -> Self { Self::IncorrectChecksum(e) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<TooShortError> for Error {
|
impl From<TooShortError> for Error {
|
||||||
#[inline]
|
fn from(e: TooShortError) -> Self { Self(ErrorInner::TooShort(e)) }
|
||||||
fn from(e: TooShortError) -> Self { Self::TooShort(e) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checksum was not correct.
|
/// Checksum was not correct.
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct IncorrectChecksumError {
|
pub(super) struct IncorrectChecksumError {
|
||||||
/// The incorrect checksum.
|
/// The incorrect checksum.
|
||||||
pub(super) incorrect: u32,
|
pub(super) incorrect: u32,
|
||||||
/// The expected checksum.
|
/// The expected checksum.
|
||||||
pub(super) expected: u32,
|
pub(super) expected: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IncorrectChecksumError {
|
internals::impl_from_infallible!(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 {
|
impl fmt::Display for IncorrectChecksumError {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
@ -89,15 +112,12 @@ impl std::error::Error for IncorrectChecksumError {}
|
||||||
|
|
||||||
/// The decode base58 data was too short (require at least 4 bytes for checksum).
|
/// The decode base58 data was too short (require at least 4 bytes for checksum).
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct TooShortError {
|
pub(super) struct TooShortError {
|
||||||
/// The length of the decoded data.
|
/// The length of the decoded data.
|
||||||
pub(super) length: usize,
|
pub(super) length: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TooShortError {
|
internals::impl_from_infallible!(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 {
|
impl fmt::Display for TooShortError {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
@ -114,18 +134,26 @@ impl std::error::Error for TooShortError {}
|
||||||
|
|
||||||
/// Found a invalid ASCII byte while decoding base58 string.
|
/// Found a invalid ASCII byte while decoding base58 string.
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct InvalidCharacterError {
|
pub struct InvalidCharacterError(pub(super) InvalidCharacterErrorInner);
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub(super) struct InvalidCharacterErrorInner {
|
||||||
pub(super) invalid: u8,
|
pub(super) invalid: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internals::impl_from_infallible!(InvalidCharacterError);
|
||||||
|
internals::impl_from_infallible!(InvalidCharacterErrorInner);
|
||||||
|
|
||||||
impl InvalidCharacterError {
|
impl InvalidCharacterError {
|
||||||
/// Returns the ASCII byte that is not a valid base58 character.
|
pub(super) fn new(invalid: u8) -> Self { Self(InvalidCharacterErrorInner{ invalid }) }
|
||||||
pub fn invalid_base58_character(&self) -> u8 { self.invalid }
|
|
||||||
|
/// Returns the invalid base58 character.
|
||||||
|
pub fn invalid_character(&self) -> u8 { self.0.invalid }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for InvalidCharacterError {
|
impl fmt::Display for InvalidCharacterError {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(f, "invalid base58 character {:#x}", self.invalid)
|
write!(f, "invalid base58 character {:#x}", self.0.invalid)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -75,12 +75,12 @@ pub fn decode(data: &str) -> Result<Vec<u8>, InvalidCharacterError> {
|
||||||
for d58 in data.bytes() {
|
for d58 in data.bytes() {
|
||||||
// Compute "X = X * 58 + next_digit" in base 256
|
// Compute "X = X * 58 + next_digit" in base 256
|
||||||
if usize::from(d58) >= BASE58_DIGITS.len() {
|
if usize::from(d58) >= BASE58_DIGITS.len() {
|
||||||
return Err(InvalidCharacterError { invalid: d58 });
|
return Err(InvalidCharacterError::new(d58));
|
||||||
}
|
}
|
||||||
let mut carry = match BASE58_DIGITS[usize::from(d58)] {
|
let mut carry = match BASE58_DIGITS[usize::from(d58)] {
|
||||||
Some(d58) => u32::from(d58),
|
Some(d58) => u32::from(d58),
|
||||||
None => {
|
None => {
|
||||||
return Err(InvalidCharacterError { invalid: d58 });
|
return Err(InvalidCharacterError::new(d58));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if scratch.is_empty() {
|
if scratch.is_empty() {
|
||||||
|
@ -302,7 +302,7 @@ mod tests {
|
||||||
Some(hex!("00f8917303bfa8ef24f292e8fa1419b20460ba064d"))
|
Some(hex!("00f8917303bfa8ef24f292e8fa1419b20460ba064d"))
|
||||||
);
|
);
|
||||||
// Non Base58 char.
|
// Non Base58 char.
|
||||||
assert_eq!(decode("¢").unwrap_err(), InvalidCharacterError { invalid: 194 });
|
assert_eq!(decode("¢").unwrap_err(), InvalidCharacterError::new(194));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
Loading…
Reference in New Issue