bip39/
language.rs

1use hashbrown::HashMap;
2use error::ErrorKind;
3use failure::Error;
4use util::{Bits11, Bits};
5
6pub struct WordMap {
7    inner: HashMap<&'static str, Bits11>
8
9}
10
11pub struct WordList {
12    inner: Vec<&'static str>
13}
14
15impl WordMap {
16    pub fn get_bits(&self, word: &str) -> Result<Bits11, Error> {
17        match self.inner.get(word) {
18            Some(n) => Ok(*n),
19            None => Err(ErrorKind::InvalidWord)?
20        }
21    }
22}
23
24impl WordList {
25    pub fn get_word(&self, bits: Bits11) -> &'static str {
26        self.inner[bits.bits() as usize]
27    }
28}
29
30mod lazy {
31    use super::{Bits11, WordList, WordMap};
32    use once_cell::sync::Lazy;
33
34    /// lazy generation of the word list
35    fn gen_wordlist(lang_words: &'static str) -> WordList {
36        let inner: Vec<_> = lang_words.split_whitespace().collect();
37
38        debug_assert!(inner.len() == 2048, "Invalid wordlist length");
39
40        WordList {
41            inner
42        }
43    }
44
45    /// lazy generation of the word map
46    fn gen_wordmap(wordlist: &WordList) -> WordMap {
47        let inner = wordlist.inner
48                            .iter()
49                            .enumerate()
50                            .map(|(i, item)| (*item, Bits11::from(i as u16)))
51                            .collect();
52
53        WordMap {
54            inner
55        }
56    }
57
58    pub static WORDLIST_ENGLISH: Lazy<WordList> = sync_lazy!{ gen_wordlist(include_str!("langs/english.txt")) };
59    #[cfg(feature = "chinese-simplified")]
60    pub static WORDLIST_CHINESE_SIMPLIFIED: Lazy<WordList> = sync_lazy!{ gen_wordlist(include_str!("langs/chinese_simplified.txt")) };
61    #[cfg(feature = "chinese-traditional")]
62    pub static WORDLIST_CHINESE_TRADITIONAL: Lazy<WordList> = sync_lazy!{ gen_wordlist(include_str!("langs/chinese_traditional.txt")) };
63    #[cfg(feature = "french")]
64    pub static WORDLIST_FRENCH: Lazy<WordList> = sync_lazy!{ gen_wordlist(include_str!("langs/french.txt")) };
65    #[cfg(feature = "italian")]
66    pub static WORDLIST_ITALIAN: Lazy<WordList> = sync_lazy!{ gen_wordlist(include_str!("langs/italian.txt")) };
67    #[cfg(feature = "japanese")]
68    pub static WORDLIST_JAPANESE: Lazy<WordList> = sync_lazy!{ gen_wordlist(include_str!("langs/japanese.txt")) };
69    #[cfg(feature = "korean")]
70    pub static WORDLIST_KOREAN: Lazy<WordList> = sync_lazy!{ gen_wordlist(include_str!("langs/korean.txt")) };
71    #[cfg(feature = "spanish")]
72    pub static WORDLIST_SPANISH: Lazy<WordList> = sync_lazy!{ gen_wordlist(include_str!("langs/spanish.txt")) };
73
74    pub static WORDMAP_ENGLISH: Lazy<WordMap> = sync_lazy!{ gen_wordmap(&WORDLIST_ENGLISH) };
75    #[cfg(feature = "chinese-simplified")]
76    pub static WORDMAP_CHINESE_SIMPLIFIED: Lazy<WordMap> = sync_lazy!{  gen_wordmap(&WORDLIST_CHINESE_SIMPLIFIED) };
77    #[cfg(feature = "chinese-traditional")]
78    pub static WORDMAP_CHINESE_TRADITIONAL: Lazy<WordMap> = sync_lazy!{ gen_wordmap(&WORDLIST_CHINESE_TRADITIONAL) };
79    #[cfg(feature = "french")]
80    pub static WORDMAP_FRENCH: Lazy<WordMap> = sync_lazy!{ gen_wordmap(&WORDLIST_FRENCH) };
81    #[cfg(feature = "italian")]
82    pub static WORDMAP_ITALIAN: Lazy<WordMap> = sync_lazy!{ gen_wordmap(&WORDLIST_ITALIAN) };
83    #[cfg(feature = "japanese")]
84    pub static WORDMAP_JAPANESE: Lazy<WordMap> = sync_lazy!{ gen_wordmap(&WORDLIST_JAPANESE) };
85    #[cfg(feature = "korean")]
86    pub static WORDMAP_KOREAN: Lazy<WordMap> = sync_lazy!{ gen_wordmap(&WORDLIST_KOREAN) };
87    #[cfg(feature = "spanish")]
88    pub static WORDMAP_SPANISH: Lazy<WordMap> = sync_lazy!{ gen_wordmap(&WORDLIST_SPANISH) };
89
90}
91
92/// The language determines which words will be used in a mnemonic phrase, but also indirectly
93/// determines the binary value of each word when a [`Mnemonic`][Mnemonic] is turned into a [`Seed`][Seed].
94///
95/// These are not of much use right now, and may even be removed from the crate, as there is no
96/// official language specified by the standard except English.
97///
98/// [Mnemonic]: ./mnemonic/struct.Mnemonic.html
99/// [Seed]: ./seed/struct.Seed.html
100#[derive(Debug, Clone, Copy, Serialize, Deserialize, Eq, PartialEq)]
101pub enum Language {
102    English,
103    #[cfg(feature = "chinese-simplified")]
104    ChineseSimplified,
105    #[cfg(feature = "chinese-traditional")]
106    ChineseTraditional,
107    #[cfg(feature = "french")]
108    French,
109    #[cfg(feature = "italian")]
110    Italian,
111    #[cfg(feature = "japanese")]
112    Japanese,
113    #[cfg(feature = "korean")]
114    Korean,
115    #[cfg(feature = "spanish")]
116    Spanish,
117}
118
119impl Language {
120    /// Get the word list for this language
121    pub fn wordlist(&self) -> &'static WordList {
122        match *self {
123            Language::English => &lazy::WORDLIST_ENGLISH,
124            #[cfg(feature = "chinese-simplified")]
125            Language::ChineseSimplified => &lazy::WORDLIST_CHINESE_SIMPLIFIED,
126            #[cfg(feature = "chinese-traditional")]
127            Language::ChineseTraditional => &lazy::WORDLIST_CHINESE_TRADITIONAL,
128            #[cfg(feature = "french")]
129            Language::French => &lazy::WORDLIST_FRENCH,
130            #[cfg(feature = "italian")]
131            Language::Italian => &lazy::WORDLIST_ITALIAN,
132            #[cfg(feature = "japanese")]
133            Language::Japanese => &lazy::WORDLIST_JAPANESE,
134            #[cfg(feature = "korean")]
135            Language::Korean => &lazy::WORDLIST_KOREAN,
136            #[cfg(feature = "spanish")]
137            Language::Spanish => &lazy::WORDLIST_SPANISH,
138        }
139    }
140
141    /// Get a [`WordMap`][WordMap] that allows word -> index lookups in the word list
142    ///
143    /// The index of an individual word in the word list is used as the binary value of that word
144    /// when the phrase is turned into a [`Seed`][Seed].
145    pub fn wordmap(&self) -> &'static WordMap {
146        match *self {
147            Language::English => &lazy::WORDMAP_ENGLISH,
148            #[cfg(feature = "chinese-simplified")]
149            Language::ChineseSimplified => &lazy::WORDMAP_CHINESE_SIMPLIFIED,
150            #[cfg(feature = "chinese-traditional")]
151            Language::ChineseTraditional => &lazy::WORDMAP_CHINESE_TRADITIONAL,
152            #[cfg(feature = "french")]
153            Language::French => &lazy::WORDMAP_FRENCH,
154            #[cfg(feature = "italian")]
155            Language::Italian => &lazy::WORDMAP_ITALIAN,
156            #[cfg(feature = "japanese")]
157            Language::Japanese => &lazy::WORDMAP_JAPANESE,
158            #[cfg(feature = "korean")]
159            Language::Korean => &lazy::WORDMAP_KOREAN,
160            #[cfg(feature = "spanish")]
161            Language::Spanish => &lazy::WORDMAP_SPANISH,
162        }
163    }
164}
165
166impl Default for Language {
167    fn default() -> Language {
168        Language::English
169    }
170}