tour_parser/
file.rs

1//! The [`File`] struct.
2use std::rc::Rc;
3use syn::{Ident, LitStr, Result};
4
5use crate::{
6    ast::StmtTempl,
7    data::Template,
8    metadata::Metadata,
9    syntax::{BlockTempl, LayoutTempl},
10};
11
12mod visitor;
13mod validate;
14
15use visitor::SynVisitor;
16use validate::ValidateVisitor;
17
18/// Content of a template source.
19pub struct File {
20    layout: Option<LayoutTempl>,
21    imports: Vec<Import>,
22    blocks: Vec<BlockContent>,
23    statics: Vec<Rc<str>>,
24    stmts: Vec<StmtTempl>,
25}
26
27pub struct BlockContent {
28    pub templ: BlockTempl,
29    pub stmts: Vec<StmtTempl>,
30}
31
32impl File {
33    /// Create [`File`] from [`Metadata`].
34    pub fn from_meta(meta: &Metadata) -> Result<File> {
35        let file = SynVisitor::generate(meta)?;
36        ValidateVisitor::validate(&file)?;
37        Ok(file)
38    }
39
40    /// Get block by id.
41    pub fn get_block(&self, block: &Ident) -> Option<&BlockContent> {
42        self.blocks.iter().find(|e| &e.templ.name == block)
43    }
44
45    pub(crate) fn block(&self, block: &Ident) -> &BlockContent {
46        self.get_block(block).expect("[BUG] validation block rendering missed")
47    }
48
49    /// Get imported template by id.
50    pub fn get_import_by_id(&self, name: &Ident) -> Option<&Import> {
51        self.imports.iter().find(|&e| e == name)
52    }
53
54    fn import_by_id(&self, name: &Ident) -> &Import {
55        self.get_import_by_id(name)
56            .unwrap_or_else(|| panic!("[BUG] validation import id missed, cannot find `{name}`: {:#?}",self.imports()))
57    }
58
59    /// Get imported template by path.
60    pub fn get_import_by_path(&self, path: &LitStr) -> Option<&Import> {
61        let path = path.value();
62        self.imports.iter().find(|&e| e == &*path)
63    }
64
65    pub(crate) fn import_by_path(&self, path: &LitStr) -> &Import {
66        self.get_import_by_path(path).unwrap_or_else(|| {
67            panic!(
68                "[BUG] validation import path missed, cannot find `{}`",
69                path.value()
70            )
71        })
72    }
73
74    pub(crate) fn get_resolved_id(&self, id: &Ident) -> Option<AliasKind<'_>> {
75        match self.get_block(id) {
76            Some(block) => Some(AliasKind::Block(block)),
77            None => Some(AliasKind::Import(self.get_import_by_id(id)?)),
78        }
79    }
80
81    pub(crate) fn resolve_id(&self, id: &Ident) -> AliasKind<'_> {
82        match self.get_block(id) {
83            Some(block) => AliasKind::Block(block),
84            None => AliasKind::Import(self.import_by_id(id)),
85        }
86    }
87
88    /// Returns all statements.
89    pub fn stmts(&self) -> &[StmtTempl] {
90        &self.stmts
91    }
92
93    /// Returns all mutable statements.
94    pub fn stmts_mut(&mut self) -> &mut Vec<StmtTempl> {
95        &mut self.stmts
96    }
97
98    pub fn imports(&self) -> &[Import] {
99        &self.imports
100    }
101
102    pub fn blocks(&self) -> &[BlockContent] {
103        &self.blocks
104    }
105
106    pub fn blocks_mut(&mut self) -> &mut Vec<BlockContent> {
107        &mut self.blocks
108    }
109
110    pub fn statics(&self) -> &[Rc<str>] {
111        &self.statics
112    }
113
114    pub fn layout(&self) -> Option<&LayoutTempl> {
115        self.layout.as_ref()
116    }
117}
118
119// ===== Import =====
120
121#[derive(Debug)]
122pub struct Import {
123    path: Rc<str>,
124    alias: Ident,
125    templ: Template,
126}
127
128impl Import {
129    pub fn path(&self) -> &str {
130        &self.path
131    }
132
133    pub fn alias(&self) -> &Ident {
134        &self.alias
135    }
136
137    pub fn templ(&self) -> &Template {
138        &self.templ
139    }
140}
141
142impl PartialEq<str> for Import {
143    fn eq(&self, other: &str) -> bool {
144        self.path.as_ref() == other
145    }
146}
147
148impl PartialEq<Ident> for Import {
149    fn eq(&self, other: &Ident) -> bool {
150        &self.alias == other
151    }
152}
153
154// ===== AliasKind =====
155
156pub enum AliasKind<'a> {
157    Block(&'a BlockContent),
158    Import(&'a Import),
159}
160
161// ===== Debug =====
162
163impl std::fmt::Debug for File {
164    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
165        f.debug_struct("File")
166            .field("layout", &self.layout.as_ref().map(|e|e.path.value()))
167            .field("imports", &self.imports)
168            .field("blocks", &self.blocks)
169            .field("statics", &self.statics)
170            .field("stmts", &"<statements>")
171            .finish()
172    }
173}
174
175impl std::fmt::Debug for BlockContent {
176    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
177        f.debug_struct("BlockContent")
178            .field("templ", &self.templ.name)
179            .field("stmts", &"<statements>")
180            .finish()
181    }
182}
183