Skip to main content

yarte_codegen/
fmt.rs

1use proc_macro2::{Ident, TokenStream};
2use quote::{format_ident, quote};
3
4use yarte_hir::{Struct, HIR};
5
6use crate::CodeGen;
7
8pub struct FmtCodeGen<'a, T: CodeGen> {
9    codegen: T,
10    s: &'a Struct<'a>,
11    parent: Ident,
12}
13
14impl<'a, T: CodeGen> FmtCodeGen<'a, T> {
15    pub fn new<'n>(codegen: T, s: &'n Struct, parent: &'static str) -> FmtCodeGen<'n, T> {
16        FmtCodeGen {
17            codegen,
18            s,
19            parent: format_ident!("{}", parent),
20        }
21    }
22
23    #[inline]
24    fn template(&self, size_hint: usize, tokens: &mut TokenStream) {
25        tokens.extend(self.s.implement_head(
26            quote!(yarte::TemplateTrait),
27            &quote!(
28            fn size_hint() -> usize {
29                #size_hint
30            }),
31        ));
32    }
33
34    fn display(&mut self, nodes: Vec<HIR>, tokens: &mut TokenStream) -> usize {
35        let nodes = self.codegen.gen(nodes);
36        // heuristic based on https://github.com/lfairy/maud
37        let size_hint = nodes.to_string().len();
38        let parent = &self.parent;
39        let func = quote!(
40            fn fmt(&self, _fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
41                #[allow(unused_imports)]
42                use std::fmt::Display;
43                #[allow(unused_imports)]
44                use #parent::*;
45                #nodes
46                Ok(())
47            }
48        );
49
50        tokens.extend(self.s.implement_head(quote!(std::fmt::Display), &func));
51
52        size_hint
53    }
54}
55
56// TODO: Create new trait for decouple concepts
57impl<'a, T: CodeGen> CodeGen for FmtCodeGen<'a, T> {
58    fn gen(&mut self, v: Vec<HIR>) -> TokenStream {
59        let mut tokens = TokenStream::new();
60
61        let size_hint = self.display(v, &mut tokens);
62        self.template(size_hint, &mut tokens);
63
64        tokens
65    }
66}