dusk_cdf/encoder/
context.rs1use std::collections::HashMap;
2use std::ops::Deref;
3use std::{fs, io};
4
5use msgpacker::Message;
6
7use crate::{Config, Preamble};
8
9pub trait EncoderContextProvider {
11 fn contents<P>(&mut self, path: P) -> io::Result<String>
13 where
14 P: AsRef<str>;
15}
16
17#[derive(Debug, Default, Clone, PartialEq, Eq)]
19pub struct EncoderContextFileProvider;
20
21impl EncoderContextProvider for EncoderContextFileProvider {
22 fn contents<P>(&mut self, path: P) -> io::Result<String>
23 where
24 P: AsRef<str>,
25 {
26 fs::read_to_string(path.as_ref())
27 }
28}
29
30impl<V> EncoderContextProvider for HashMap<String, V>
31where
32 V: AsRef<str>,
33{
34 fn contents<P>(&mut self, path: P) -> io::Result<String>
35 where
36 P: AsRef<str>,
37 {
38 self.get(path.as_ref())
39 .map(|p| p.as_ref().to_string())
40 .ok_or_else(|| {
41 io::Error::new(
42 io::ErrorKind::NotFound,
43 "the provided path was not found in the disk",
44 )
45 })
46 }
47}
48
49#[derive(Debug, Default, Clone, PartialEq, Eq)]
51pub struct EncoderContext {
52 preamble: Preamble,
53 path_cache: HashMap<String, usize>,
54}
55
56impl EncoderContext {
57 pub(crate) fn from_preamble(preamble: Preamble) -> Self {
62 Self {
63 preamble,
64 path_cache: HashMap::new(),
65 }
66 }
67
68 pub const fn config(&self) -> &Config {
70 &self.preamble.config
71 }
72
73 pub const fn preamble(&self) -> &Preamble {
75 &self.preamble
76 }
77
78 pub fn add_path<P>(&mut self, path: P) -> usize
80 where
81 P: Into<String>,
82 {
83 let path = path.into();
84 let len = self.path_cache.len();
85
86 *self.path_cache.entry(path).or_insert(len)
87 }
88}
89
90impl EncoderContext {
91 pub fn write_all<P, W>(&self, mut writer: W, mut provider: P) -> io::Result<usize>
92 where
93 P: EncoderContextProvider,
94 W: io::Write,
95 {
96 let mut contents = self.path_cache.iter().collect::<Vec<_>>();
97
98 contents.as_mut_slice().sort_by_key(|(_p, i)| *i);
99
100 let paths = contents
101 .iter()
102 .map(|(p, _i)| p.to_string())
103 .collect::<Vec<_>>();
104
105 let contents = paths
106 .iter()
107 .map(|p| provider.contents(p))
108 .map(|p| p.map(Message::String))
109 .collect::<io::Result<Vec<_>>>()?;
110
111 let paths = paths.into_iter().map(Message::String).collect();
112
113 let n = Message::Array(paths).pack(&mut writer)?;
114 let n = n + Message::Array(contents).pack(&mut writer)?;
115
116 Ok(n)
117 }
118}
119
120impl Deref for EncoderContext {
121 type Target = HashMap<String, usize>;
122
123 fn deref(&self) -> &Self::Target {
124 &self.path_cache
125 }
126}
127
128#[cfg(test)]
129use std::path::PathBuf;
130
131#[test]
132fn path_cache_is_not_duplicated() {
133 let main = PathBuf::from("home")
134 .join("zkp-debugger")
135 .join("main.rs")
136 .display()
137 .to_string();
138
139 let lib = PathBuf::from("home")
140 .join("zkp-debugger")
141 .join("lib.rs")
142 .display()
143 .to_string();
144
145 let mut context = EncoderContext::from_preamble(Default::default());
146
147 let idx_main = context.add_path(main.clone());
148
149 assert_eq!(idx_main, context.add_path(main.clone()));
151
152 let idx_lib = context.add_path(lib.clone());
153
154 assert_ne!(idx_main, idx_lib);
156}
157
158#[test]
159fn context_derives_expected_map() {
160 let main = PathBuf::from("home")
161 .join("zkp-debugger")
162 .join("main.rs")
163 .display()
164 .to_string();
165
166 let lib = PathBuf::from("home")
167 .join("zkp-debugger")
168 .join("lib.rs")
169 .display()
170 .to_string();
171
172 let mut context = EncoderContext::from_preamble(Default::default());
173
174 let idx_main = context.add_path(main.clone());
175 let idx_lib = context.add_path(lib.clone());
176
177 let expected_map: HashMap<String, usize> = vec![(main.clone(), idx_main), (lib, idx_lib)]
178 .into_iter()
179 .collect();
180
181 assert_eq!(expected_map[&main], context[&main]);
183
184 assert_eq!(*context, expected_map);
186}
187
188#[test]
189fn preamble_is_correctly_created() {
190 let preamble = Preamble::default();
192 let context = EncoderContext::from_preamble(preamble);
193
194 assert_eq!(&preamble, context.preamble());
196}