onepass_seed/expr/
context.rs1use core::{error, fmt};
2use std::{collections::HashMap, iter::once, sync::Arc};
3
4use onepass_base::dict::Dict;
5
6use crate::{dict::EFF_WORDLIST, expr::GeneratorFunc};
7
8#[derive(Clone, Debug)]
16pub struct Context<'a> {
17 generator: Arc<HashMap<&'static str, Arc<dyn GeneratorFunc>>>,
18
19 dict: Arc<HashMap<[u8; 32], Arc<dyn Dict + 'a>>>,
22
23 pub default_dict: Arc<dyn Dict + 'a>,
24}
25
26#[derive(Clone, Copy, Debug)]
28pub struct NotFound;
29
30impl<'a> Context<'a> {
31 pub fn new(
32 generator: impl IntoIterator<Item = Arc<dyn GeneratorFunc>>,
33 dict: impl IntoIterator<Item = Arc<dyn Dict + 'a>>,
34 default_dict: Arc<dyn Dict + 'a>,
35 ) -> Self {
36 let generator = Arc::new(generator.into_iter().map(|g| (g.name(), g)).collect());
37 let dict = Arc::new(
38 once(default_dict.clone())
39 .chain(dict)
40 .map(|d| (*d.hash(), d))
41 .collect(),
42 );
43 Context {
44 generator,
45 dict,
46 default_dict,
47 }
48 }
49
50 pub fn empty() -> Self {
52 Context {
53 generator: Arc::default(),
54 dict: Arc::default(),
55 default_dict: Arc::new(EFF_WORDLIST),
56 }
57 }
58
59 pub fn with_default_dict(&mut self, default_dict: Arc<dyn Dict + 'a>) -> Self {
65 Arc::make_mut(&mut self.dict).extend([(*default_dict.hash(), default_dict.clone())]);
66 Context {
67 generator: self.generator.clone(),
68 dict: self.dict.clone(),
69 default_dict,
70 }
71 }
72
73 pub fn dict_hash(args: &[&str]) -> Option<[u8; 32]> {
74 let mut out = [0u8; 32];
75 for &arg in args {
76 if hex::decode_to_slice(arg, &mut out).is_ok() {
77 return Some(out);
78 }
79 }
80 None
81 }
82
83 pub fn get_generator(&self, name: &str) -> Result<Arc<dyn GeneratorFunc>, NotFound> {
84 self.generator.get(name).map(Arc::clone).ok_or(NotFound)
85 }
86
87 pub fn get_dict(&self, hash: &Option<[u8; 32]>) -> Result<Arc<dyn Dict + 'a>, NotFound> {
88 let Some(hash) = hash else {
89 return Ok(self.default_dict.clone());
90 };
91 self.dict.get(hash).map(Arc::clone).ok_or(NotFound)
92 }
93}
94
95impl<'a> Extend<Arc<dyn Dict + 'a>> for Context<'a> {
96 fn extend<T: IntoIterator<Item = Arc<dyn Dict + 'a>>>(&mut self, iter: T) {
97 let dict = Arc::make_mut(&mut self.dict);
98 dict.extend(iter.into_iter().map(|d| (*d.hash(), d)));
99 }
100}
101
102impl fmt::Display for NotFound {
103 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
104 f.write_str("item not found")
105 }
106}
107
108impl error::Error for NotFound {}