1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
use wagyu_model::wordlist::{Wordlist, WordlistError};

pub mod chinese_simplified;
pub use self::chinese_simplified::*;

pub mod dutch;
pub use self::dutch::*;

pub mod english;
pub use self::english::*;

pub mod english_old;
pub use self::english_old::*;

pub mod esperanto;
pub use self::esperanto::*;

pub mod french;
pub use self::french::*;

pub mod german;
pub use self::german::*;

pub mod italian;
pub use self::italian::*;

pub mod japanese;
pub use self::japanese::*;

pub mod lojban;
pub use self::lojban::*;

pub mod portuguese;
pub use self::portuguese::*;

pub mod russian;
pub use self::russian::*;

pub mod spanish;
pub use self::spanish::*;

/// The interface for a Monero wordlist.
pub trait MoneroWordlist: Wordlist {
    /// The wordlist in original form.
    const WORDLIST: &'static str;
    /// The prefix length for computing the checksum.
    const PREFIX_LENGTH: usize;

    /// Returns the word of a given index from the word list.
    fn get(index: usize) -> Result<String, WordlistError> {
        if index >= 1626 {
            return Err(WordlistError::InvalidIndex(index));
        }
        Ok(Self::get_all()[index].into())
    }

    /// Returns the index of a given word from the word list.
    fn get_index(word: &str) -> Result<usize, WordlistError> {
        match Self::get_all().iter().position(|e| e == &word) {
            Some(index) => Ok(index),
            None => Err(WordlistError::InvalidWord(word.into())),
        }
    }

    /// Returns the index of a given trimmed word from the word list.
    fn get_index_trimmed(trimmed_word: &str) -> Result<usize, WordlistError> {
        match Self::get_all_trimmed().iter().position(|e| e == &trimmed_word) {
            Some(index) => Ok(index),
            None => Err(WordlistError::InvalidWord(trimmed_word.into())),
        }
    }

    /// Returns the word list as a string.
    fn get_all() -> Vec<&'static str> {
        Self::WORDLIST.lines().collect::<Vec<&str>>()
    }

    /// Returns the word list as a string.
    fn get_all_trimmed() -> Vec<String> {
        Self::get_all().iter().map(|&word| Self::to_trimmed(word)).collect()
    }

    /// Returns the trimmed word for a given prefix length.
    fn to_trimmed(word: &str) -> String {
        match word.chars().count() > Self::PREFIX_LENGTH {
            true => word.chars().take(Self::PREFIX_LENGTH).collect(),
            false => word.into(),
        }
    }
}