1use alloc::borrow::ToOwned;
2use alloc::string::String;
3use alloc::vec::Vec;
4use core::convert::Infallible;
5use core::marker::PhantomData;
6
7use derive_more::From;
8
9#[derive(From, Debug)]
11pub enum GeneratorError<E> {
12 IOError(E),
14}
15
16impl<E: 'static> GeneratorError<E> {
17 pub fn from_infalliable(error: GeneratorError<Infallible>) -> Self {
19 match error {
20 GeneratorError::IOError(e) => match e {},
21 }
22 }
23}
24
25pub struct ExprGenerator<'a, W, E> {
27 out: &'a mut W,
28 string_pool: Vec<String>,
29 error: PhantomData<E>,
30}
31
32impl<'a, W, E> ExprGenerator<'a, W, E> {
33 pub fn new(out: &'a mut W) -> Self {
35 ExprGenerator {
36 out,
37 string_pool: Vec::new(),
38 error: PhantomData,
39 }
40 }
41
42 pub fn new_with_string_pool(out: &'a mut W, string_pool: Vec<String>) -> Self {
44 ExprGenerator {
45 out,
46 string_pool,
47 error: PhantomData,
48 }
49 }
50}
51
52macro_rules! writer_mod {
53 ($syncness: ident) => {
54 use alloc::borrow::Borrow;
55 use core::convert::Infallible;
56
57 use esexpr::{ESExpr, ESExprConstructor};
58 use half::f16;
59 use num_bigint::{BigUint, Sign};
60
61 use super::*;
62 use crate::async_macros::{do_await, maybe_async};
63 use crate::format::*;
64
65 #[allow(async_fn_in_trait, reason = "No additional traits to add")]
67 pub trait ExprGeneratorWrite<E> {
68 maybe_async!(
69 $syncness,
70 fn generate(&mut self, expr: &ESExpr<'_>) -> Result<(), GeneratorError<E>>;
75 );
76 }
77
78 pub(super) trait ExprGeneratorWriteExt<W, E>: ExprGeneratorWrite<E> {
79 maybe_async!(
80 $syncness,
81 fn generate_expr(&mut self, expr: &ESExpr) -> Result<(), GeneratorError<E>>;
82 );
83 maybe_async!(
84 $syncness,
85 fn get_string_pool_index<S: Borrow<str>>(&mut self, s: S) -> Result<usize, GeneratorError<E>>;
86 );
87 maybe_async!(
88 $syncness,
89 fn write_int_tag(&mut self, tag: u8, i: &BigUint) -> Result<(), GeneratorError<E>>;
90 );
91 maybe_async!(
92 $syncness,
93 fn write_int_tag_out(out: &mut W, tag: u8, i: &BigUint) -> Result<(), GeneratorError<E>>;
94 );
95 maybe_async!(
96 $syncness,
97 fn write_int_full(out: &mut W, i: &BigUint) -> Result<(), GeneratorError<E>>;
98 );
99 maybe_async!(
100 $syncness,
101 fn write_int_rest(
102 out: &mut W,
103 buff: &[u8],
104 current: u8,
105 bit_index: i32,
106 ) -> Result<(), GeneratorError<E>>;
107 );
108 maybe_async!(
109 $syncness,
110 fn write_string_expr(out: &mut W, s: &str) -> Result<(), GeneratorError<E>>;
111 );
112 maybe_async!(
113 $syncness,
114 fn write(&mut self, b: u8) -> Result<(), GeneratorError<E>>;
115 );
116 maybe_async!(
117 $syncness,
118 fn write_out(out: &mut W, b: u8) -> Result<(), GeneratorError<E>>;
119 );
120 }
121
122 impl<'a, E: 'static, W: Write<E>> ExprGeneratorWrite<E> for ExprGenerator<'a, W, E> {
123 maybe_async!(
124 $syncness,
125 fn generate(&mut self, expr: &ESExpr<'_>) -> Result<(), GeneratorError<E>> {
126 let old_string_pool_end = self.string_pool.len();
127
128 let mut generator: ExprGenerator<_, Infallible> = ExprGenerator {
129 out: &mut crate::io::sink(),
130 string_pool: Vec::new(),
131 error: PhantomData,
132 };
133
134 core::mem::swap(&mut self.string_pool, &mut generator.string_pool);
135 <ExprGenerator<_, Infallible> as super::writer_sync::ExprGeneratorWriteExt<_, Infallible>>::generate_expr(
137 &mut generator,
138 expr,
139 ).map_err(GeneratorError::from_infalliable)?;
140
141 core::mem::swap(&mut self.string_pool, &mut generator.string_pool);
142
143 match &self.string_pool[old_string_pool_end..] {
144 [] => {},
145 [s] => {
146 do_await!($syncness, Self::write_out(self.out, TAG_APPEND_STRING_TABLE))?;
147 do_await!($syncness, Self::write_string_expr(self.out, s.as_str()))?;
148 },
149 new_strings => {
150 do_await!($syncness, Self::write_out(self.out, TAG_APPEND_STRING_TABLE))?;
151 do_await!(
152 $syncness,
153 Self::write_out(self.out, TAG_CONSTRUCTOR_START_STRING_TABLE)
154 )?;
155 for s in new_strings {
156 do_await!($syncness, Self::write_string_expr(self.out, s))?;
157 }
158 do_await!($syncness, Self::write_out(self.out, TAG_CONSTRUCTOR_END))?;
159 },
160 }
161
162 do_await!($syncness, self.generate_expr(expr))?;
163 Ok(())
164 }
165 );
166 }
167
168 impl<'a, E: 'static, W: Write<E>> ExprGeneratorWriteExt<W, E> for ExprGenerator<'a, W, E> {
169 maybe_async!(
170 $syncness,
171 fn generate_expr(&mut self, expr: &ESExpr<'_>) -> Result<(), GeneratorError<E>> {
172 match expr {
173 ESExpr::Constructor(ESExprConstructor { name, args, kwargs }) => {
174 match &**name {
175 "string-table" => do_await!($syncness, self.write(TAG_CONSTRUCTOR_START_STRING_TABLE))?,
176 "list" => do_await!($syncness, self.write(TAG_CONSTRUCTOR_START_LIST))?,
177 _ => {
178 let index = do_await!($syncness, self.get_string_pool_index(name))?;
179 do_await!(
180 $syncness,
181 self.write_int_tag(TAG_VARINT_CONSTRUCTOR_START, &BigUint::from(index))
182 )?;
183 },
184 }
185
186 for arg in args.iter() {
187 do_await!($syncness, self.generate_expr(&arg))?;
188 }
189
190 for (kw, value) in kwargs.iter() {
191 let index = do_await!($syncness, self.get_string_pool_index(kw))?;
192 do_await!(
193 $syncness,
194 self.write_int_tag(TAG_VARINT_KEYWORD, &BigUint::from(index))
195 )?;
196 do_await!($syncness, self.generate_expr(&value))?;
197 }
198
199 do_await!($syncness, self.write(TAG_CONSTRUCTOR_END))?;
200 },
201 ESExpr::Bool(true) => {
202 do_await!($syncness, self.write(TAG_TRUE))?;
203 },
204 ESExpr::Bool(false) => {
205 do_await!($syncness, self.write(TAG_FALSE))?;
206 },
207 ESExpr::Int(i) => {
208 let (sign, mut magnitude) = i.as_ref().clone().into_parts();
209
210 match sign {
211 Sign::NoSign | Sign::Plus => {
212 do_await!($syncness, self.write_int_tag(TAG_VARINT_NON_NEG_INT, &magnitude))?;
213 },
214
215 Sign::Minus => {
216 magnitude -= 1usize;
217 do_await!($syncness, self.write_int_tag(TAG_VARINT_NEG_INT, &magnitude))?;
218 },
219 }
220 },
221 ESExpr::Float16(f) => {
222 do_await!($syncness, self.write(TAG_FLOAT16))?;
223 do_await!($syncness, self.out.write(&f16::to_le_bytes(*f)))?;
224 },
225 ESExpr::Float32(f) => {
226 do_await!($syncness, self.write(TAG_FLOAT32))?;
227 do_await!($syncness, self.out.write(&f32::to_le_bytes(*f)))?;
228 },
229 ESExpr::Float64(d) => {
230 do_await!($syncness, self.write(TAG_FLOAT64))?;
231 do_await!($syncness, self.out.write(&f64::to_le_bytes(*d)))?;
232 },
233 ESExpr::Str(s) => {
234 do_await!(
235 $syncness,
236 self.write_int_tag(TAG_VARINT_STRING_LENGTH, &BigUint::from(s.len()))
237 )?;
238 do_await!($syncness, self.out.write(s.as_bytes()))?;
239 },
240
241 ESExpr::Array8(b) => {
242 do_await!(
243 $syncness,
244 self.write_int_tag(TAG_VARINT_ARRAY8_LENGTH, &BigUint::from(b.len()))
245 )?;
246 do_await!($syncness, self.out.write(b.as_ref()))?;
247 },
248 ESExpr::Array16(b) => {
249 do_await!($syncness, self.write(TAG_ARRAY16))?;
250 do_await!($syncness, Self::write_int_full(self.out, &BigUint::from(b.len())))?;
251
252 #[cfg(target_endian = "little")]
253 {
254 do_await!(
255 $syncness,
256 self.out.write(bytemuck::cast_slice::<u16, u8>(b.as_ref()))
257 )?;
258 }
259
260 #[cfg(target_endian = "big")]
261 {
262 for value in b.iter().copied() {
263 do_await!(
264 $syncness,
265 self.out.write(&value.to_le_bytes())
266 )?;
267 }
268 }
269 },
270 ESExpr::Array32(b) => {
271 do_await!($syncness, self.write(TAG_ARRAY32))?;
272 do_await!($syncness, Self::write_int_full(self.out, &BigUint::from(b.len())))?;
273
274 #[cfg(target_endian = "little")]
275 {
276 do_await!(
277 $syncness,
278 self.out.write(bytemuck::cast_slice::<u32, u8>(b.as_ref()))
279 )?;
280 }
281
282 #[cfg(target_endian = "big")]
283 {
284 for value in b.iter().copied() {
285 do_await!(
286 $syncness,
287 self.out.write(&value.to_le_bytes())
288 )?;
289 }
290 }
291 },
292 ESExpr::Array64(b) => {
293 do_await!($syncness, self.write(TAG_ARRAY64))?;
294 do_await!($syncness, Self::write_int_full(self.out, &BigUint::from(b.len())))?;
295
296 #[cfg(target_endian = "little")]
297 {
298 do_await!(
299 $syncness,
300 self.out.write(bytemuck::cast_slice::<u64, u8>(b.as_ref()))
301 )?;
302 }
303
304 #[cfg(target_endian = "big")]
305 {
306 for value in b.iter().copied() {
307 do_await!(
308 $syncness,
309 self.out.write(&value.to_le_bytes())
310 )?;
311 }
312 }
313 },
314 ESExpr::Array128(b) => {
315 do_await!($syncness, self.write(TAG_ARRAY128))?;
316 do_await!($syncness, Self::write_int_full(self.out, &BigUint::from(b.len())))?;
317
318 #[cfg(target_endian = "little")]
319 {
320 do_await!(
321 $syncness,
322 self.out.write(bytemuck::cast_slice::<u128, u8>(b.as_ref()))
323 )?;
324 }
325
326 #[cfg(target_endian = "big")]
327 {
328 for value in b.iter().copied() {
329 do_await!(
330 $syncness,
331 self.out.write(&value.to_le_bytes())
332 )?;
333 }
334 }
335 },
336
337 ESExpr::Null(level) => {
338 let level: &BigUint = level.as_ref();
339
340 if *level == BigUint::ZERO {
341 do_await!($syncness, self.write(TAG_NULL0))?;
342 }
343 else if *level == BigUint::from(1u32) {
344 do_await!($syncness, self.write(TAG_NULL1))?;
345 }
346 else if *level == BigUint::from(2u32) {
347 do_await!($syncness, self.write(TAG_NULL2))?;
348 }
349 else {
350 do_await!($syncness, self.write(TAG_NULLN))?;
351 do_await!($syncness, Self::write_int_full(self.out, &(level - 3u32)))?;
352 }
353 },
354 }
355
356 Ok(())
357 }
358 );
359
360 maybe_async!(
361 $syncness,
362 fn get_string_pool_index<S: Borrow<str>>(&mut self, s: S) -> Result<usize, GeneratorError<E>> {
363 let s = s.borrow();
364 if let Some(index) = self.string_pool.iter().position(|s2| s2 == s) {
365 return Ok(index);
366 }
367
368 let index = self.string_pool.len();
369 self.string_pool.push(s.to_owned());
370
371 do_await!($syncness, self.write(TAG_APPEND_STRING_TABLE))?;
372 do_await!($syncness, Self::write_string_expr(self.out, s))?;
373
374 Ok(index)
375 }
376 );
377
378 maybe_async!(
379 $syncness,
380 fn write_int_tag(&mut self, tag: u8, i: &BigUint) -> Result<(), GeneratorError<E>> {
381 do_await!($syncness, Self::write_int_tag_out(self.out, tag, i))
382 }
383 );
384
385 maybe_async!(
386 $syncness,
387 fn write_int_tag_out(out: &mut W, tag: u8, i: &BigUint) -> Result<(), GeneratorError<E>> {
388 let buff = i.to_bytes_le();
389
390 let b0 = buff.first().copied().unwrap_or_default();
391 let mut current = tag | (b0 & 0x0F);
392 if buff.len() < 2 && (b0 & 0xF0) == 0 {
393 do_await!($syncness, Self::write_out(out, current))?;
394 return Ok(());
395 }
396
397 current |= 0x10;
398 do_await!($syncness, Self::write_out(out, current))?;
399
400 current = b0 >> 4;
401 let bit_index = 4;
402
403 do_await!(
404 $syncness,
405 Self::write_int_rest(out, &buff[1..], current, bit_index)
406 )
407 }
408 );
409
410 maybe_async!(
411 $syncness,
412 fn write_int_full(out: &mut W, i: &BigUint) -> Result<(), GeneratorError<E>> {
413 if *i == BigUint::ZERO {
414 do_await!($syncness, Self::write_out(out, 0))?;
415 return Ok(());
416 }
417
418 let buff = i.to_bytes_le();
419 let current = 0;
420 let bit_index = 0;
421
422 do_await!($syncness, Self::write_int_rest(out, &buff, current, bit_index))
423 }
424 );
425
426 maybe_async!(
427 $syncness,
428 fn write_int_rest(
429 out: &mut W,
430 buff: &[u8],
431 mut current: u8,
432 mut bit_index: i32,
433 ) -> Result<(), GeneratorError<E>> {
434 for (i, b) in buff.iter().copied().enumerate() {
435 let mut bit_index2 = 0;
436 while bit_index2 < 8 {
437 let written_bits = core::cmp::min(7 - bit_index, 8 - bit_index2);
438 current |= ((b >> bit_index2) & 0x7F) << bit_index;
439
440 bit_index += written_bits;
441 bit_index2 += written_bits;
442 if bit_index >= 7 {
443 if i < buff.len() - 1 || (bit_index2 < 8 && (b >> bit_index2) != 0) {
444 current |= 0x80;
445 }
446
447 do_await!($syncness, Self::write_out(out, current))?;
448 bit_index = 0;
449 current = 0;
450 }
451 }
452 }
453
454 if current != 0 {
455 do_await!($syncness, Self::write_out(out, current))?;
456 }
457
458 Ok(())
459 }
460 );
461
462 maybe_async!(
463 $syncness,
464 fn write_string_expr(out: &mut W, s: &str) -> Result<(), GeneratorError<E>> {
465 do_await!(
466 $syncness,
467 Self::write_int_tag_out(out, TAG_VARINT_STRING_LENGTH, &BigUint::from(s.len()))
468 )?;
469 do_await!($syncness, out.write(s.as_bytes()))?;
470 Ok(())
471 }
472 );
473
474 maybe_async!(
475 $syncness,
476 fn write(&mut self, b: u8) -> Result<(), GeneratorError<E>> {
477 do_await!($syncness, Self::write_out(self.out, b))
478 }
479 );
480
481 maybe_async!(
482 $syncness,
483 fn write_out(out: &mut W, b: u8) -> Result<(), GeneratorError<E>> {
484 Ok(do_await!($syncness, out.write(core::slice::from_ref(&b)))?)
485 }
486 );
487 }
488 };
489}
490
491mod writer_sync {
492 use crate::io::Write;
493 writer_mod!(sync);
494}
495
496mod writer_async {
497 use crate::io::AsyncWrite as Write;
498 writer_mod!(async);
499}
500
501pub use writer_async::ExprGeneratorWrite as ExprGeneratorAsync;
502pub use writer_sync::ExprGeneratorWrite as ExprGeneratorSync;