Improve slightly on the Error::AmbiguousLanguages

This commit is contained in:
Steven Roose 2021-03-08 10:34:20 +00:00
parent 335025d573
commit da84fd8164
No known key found for this signature in database
GPG Key ID: 2F2A88D7F8D68E87
1 changed files with 36 additions and 28 deletions

View File

@ -58,6 +58,31 @@ pub use language::Language;
/// The maximum number of words in a mnemonic. /// The maximum number of words in a mnemonic.
const MAX_NB_WORDS: usize = 24; const MAX_NB_WORDS: usize = 24;
/// A structured used in the [Error::AmbiguousLanguages] variant that iterates
/// over the possible languages.
#[derive(Debug, Clone, PartialEq, Eq, Copy)]
pub struct AmbiguousLanguages([bool; language::MAX_NB_LANGUAGES]);
impl AmbiguousLanguages {
/// Presents the possible languages in the form of a slice of booleans
/// that correspond to the occurrences in [Language::all()].
pub fn as_bools(&self) -> &[bool; language::MAX_NB_LANGUAGES] {
&self.0
}
/// An iterator over the possible languages.
#[cfg(feature = "std")]
pub fn iter(&self) -> impl Iterator<Item = Language> + '_ {
Language::all().iter().enumerate().filter(move |(i, _)| self.0[*i]).map(|(_, l)| *l)
}
/// Returns a vector of the possible languages.
#[cfg(feature = "std")]
pub fn to_vec(&self) -> Vec<Language> {
self.iter().collect()
}
}
/// A BIP39 error. /// A BIP39 error.
#[derive(Debug, Clone, PartialEq, Eq, Copy)] #[derive(Debug, Clone, PartialEq, Eq, Copy)]
pub enum Error { pub enum Error {
@ -69,11 +94,10 @@ pub enum Error {
BadEntropyBitCount(usize), BadEntropyBitCount(usize),
/// The mnemonic has an invalid checksum. /// The mnemonic has an invalid checksum.
InvalidChecksum, InvalidChecksum,
/// The word list can be interpreted as multiple languages. /// The mnemonic can be interpreted as multiple languages.
/// The booleans inside correspond to the occurrences in [Language::all()]. /// Use the helper methods of the inner struct to inspect
/// Use the method [Error::ambiguous_word_list] to get a vector of the /// which languages are possible.
/// possible languages. AmbiguousLanguages(AmbiguousLanguages),
AmbiguousWordList([bool; language::MAX_NB_LANGUAGES]),
} }
#[cfg(feature = "std")] #[cfg(feature = "std")]
@ -90,7 +114,7 @@ impl fmt::Display for Error {
"entropy was not between 128-256 bits or not a multiple of 32 bits: {} bits", c, "entropy was not between 128-256 bits or not a multiple of 32 bits: {} bits", c,
), ),
Error::InvalidChecksum => write!(f, "the mnemonic has an invalid checksum"), Error::InvalidChecksum => write!(f, "the mnemonic has an invalid checksum"),
Error::AmbiguousWordList(_) => write!(f, "ambiguous word list: {:?}", self.ambiguous_word_list()), Error::AmbiguousLanguages(a) => write!(f, "ambiguous word list: {:?}", a.to_vec()),
} }
} }
} }
@ -98,23 +122,6 @@ impl fmt::Display for Error {
#[cfg(feature = "std")] #[cfg(feature = "std")]
impl error::Error for Error {} impl error::Error for Error {}
impl Error {
/// A helper method to get the set of languages present in an
/// [Error::AmbiguousWordList] error.
#[cfg(feature = "std")]
pub fn ambiguous_word_list(&self) -> Option<Vec<Language>> {
match self {
Error::AmbiguousWordList(bools) => Some(Language::all().iter()
.zip(bools.iter())
.filter(|(_lang, present)| **present)
.map(|(lang, _p)| *lang)
.collect()
),
_ => None,
}
}
}
/// A mnemonic code. /// A mnemonic code.
/// ///
/// The [std::str::FromStr] implementation will try to determine the language of the /// The [std::str::FromStr] implementation will try to determine the language of the
@ -224,7 +231,7 @@ impl Mnemonic {
/// ///
/// Some word lists don't guarantee that their words don't occur in other /// Some word lists don't guarantee that their words don't occur in other
/// word lists. In the extremely unlikely case that a word list can be /// word lists. In the extremely unlikely case that a word list can be
/// interpreted in multiple languages, an [Error::AmbiguousWordList] is /// interpreted in multiple languages, an [Error::AmbiguousLanguages] is
/// returned, containing the possible languages. /// returned, containing the possible languages.
fn language_of<'a, W: Iterator<Item = &'a str>>(words: W) -> Result<Language, Error> { fn language_of<'a, W: Iterator<Item = &'a str>>(words: W) -> Result<Language, Error> {
let mut words = words.peekable(); let mut words = words.peekable();
@ -283,7 +290,7 @@ impl Mnemonic {
} }
} }
return Err(Error::AmbiguousWordList(possible)); return Err(Error::AmbiguousLanguages(AmbiguousLanguages(possible)));
} }
/// Parse a mnemonic in normalized UTF8 in the given language. /// Parse a mnemonic in normalized UTF8 in the given language.
@ -479,7 +486,7 @@ mod tests {
#[cfg(feature = "std")] #[cfg(feature = "std")]
#[test] #[test]
fn test_ambiguous_word_list() { fn test_ambiguous_languages() {
let mut present = [false; language::MAX_NB_LANGUAGES]; let mut present = [false; language::MAX_NB_LANGUAGES];
let mut present_vec = Vec::new(); let mut present_vec = Vec::new();
let mut alternate = true; let mut alternate = true;
@ -490,8 +497,9 @@ mod tests {
} }
alternate = !alternate; alternate = !alternate;
} }
let err = Error::AmbiguousWordList(present); let amb = AmbiguousLanguages(present);
assert_eq!(err.ambiguous_word_list().unwrap(), present_vec); assert_eq!(amb.to_vec(), present_vec);
assert_eq!(amb.iter().collect::<Vec<_>>(), present_vec);
} }
#[test] #[test]