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.
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.
#[derive(Debug, Clone, PartialEq, Eq, Copy)]
pub enum Error {
@ -69,11 +94,10 @@ pub enum Error {
BadEntropyBitCount(usize),
/// The mnemonic has an invalid checksum.
InvalidChecksum,
/// The word list can be interpreted as multiple languages.
/// The booleans inside correspond to the occurrences in [Language::all()].
/// Use the method [Error::ambiguous_word_list] to get a vector of the
/// possible languages.
AmbiguousWordList([bool; language::MAX_NB_LANGUAGES]),
/// The mnemonic can be interpreted as multiple languages.
/// Use the helper methods of the inner struct to inspect
/// which languages are possible.
AmbiguousLanguages(AmbiguousLanguages),
}
#[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,
),
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")]
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.
///
/// 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
/// 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.
fn language_of<'a, W: Iterator<Item = &'a str>>(words: W) -> Result<Language, Error> {
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.
@ -479,7 +486,7 @@ mod tests {
#[cfg(feature = "std")]
#[test]
fn test_ambiguous_word_list() {
fn test_ambiguous_languages() {
let mut present = [false; language::MAX_NB_LANGUAGES];
let mut present_vec = Vec::new();
let mut alternate = true;
@ -490,8 +497,9 @@ mod tests {
}
alternate = !alternate;
}
let err = Error::AmbiguousWordList(present);
assert_eq!(err.ambiguous_word_list().unwrap(), present_vec);
let amb = AmbiguousLanguages(present);
assert_eq!(amb.to_vec(), present_vec);
assert_eq!(amb.iter().collect::<Vec<_>>(), present_vec);
}
#[test]