1use std::{borrow::Cow, fs::read_to_string, rc::Rc};
3use syn::*;
4
5use crate::{
6 common::{error, path},
7 config::Config,
8 syntax::LayoutTempl,
9};
10
11mod attribute;
12
13use attribute::AttrVisitor;
14
15#[derive(Debug)]
19pub struct Metadata {
20 path: Rc<str>,
21 source: Option<Rc<str>>,
22 reload: Reload,
23 block: Option<Ident>,
24 kind: TemplKind,
25}
26
27#[derive(Debug)]
28pub enum TemplKind {
29 Main,
30 MainWrapper,
31 Layout,
32 Import,
33}
34
35impl std::fmt::Display for TemplKind {
36 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
37 match self {
38 Self::Main => write!(f, "Main"),
39 Self::MainWrapper => write!(f, "MainWrapper"),
40 Self::Layout => write!(f, "Layout"),
41 Self::Import => write!(f, "Import"),
42 }
43 }
44}
45
46impl Metadata {
47 pub fn from_attrs(attrs: &[Attribute], conf: &Config) -> Result<Metadata> {
49 AttrVisitor::parse(attrs, conf)
50 }
51
52 pub fn clone_as_import(&self, path: impl AsRef<std::path::Path>) -> Metadata {
56 Self {
57 path: path::resolve_at(path, self.dir_ref()),
58 source: None,
59 reload: self.reload.clone(),
60 block: None,
61 kind: TemplKind::Import,
62 }
63 }
64
65 pub fn clone_as_layout(&self, layout: &LayoutTempl) -> Metadata {
69 Self {
70 path: path::resolve_at(layout.path.value(), self.dir_ref()),
71 source: None, reload: self.reload.clone(), block: None, kind: TemplKind::Layout,
75 }
76 }
77
78 pub fn resolve_source(&self) -> Result<Cow<'_, str>> {
80 match self.source.as_deref() {
81 Some(src) => Ok(src.into()),
82 None => Ok(error!(
83 !read_to_string(&*self.path),
84 "cannot read `{}`: {}", self.path
85 )
86 .into()),
87 }
88 }
89
90 pub(crate) fn dir_ref(&self) -> &std::path::Path {
91 std::path::Path::new(&*self.path)
92 .parent()
93 .unwrap_or(std::path::Path::new("/"))
94 }
95
96 pub(crate) fn is_file(&self) -> bool {
100 std::path::Path::new(&*self.path).is_file()
101 }
102
103 pub fn block(&self) -> Option<&Ident> {
105 self.block.as_ref()
106 }
107
108 pub fn path(&self) -> &str {
110 &self.path
111 }
112
113 pub fn reload(&self) -> &Reload {
115 &self.reload
116 }
117
118 pub fn kind(&self) -> &TemplKind {
120 &self.kind
121 }
122
123 pub fn inline(&self) -> Option<&str> {
125 self.source.as_deref()
126 }
127}
128
129#[derive(Clone)]
133pub enum Reload {
134 Debug,
135 Always,
136 Never,
137 Expr(Rc<Expr>),
138}
139
140impl Default for Reload {
141 fn default() -> Self {
142 if cfg!(feature = "dev-reload") {
143 Reload::Debug
144 } else {
145 Reload::Never
146 }
147 }
148}
149
150impl Reload {
151 pub fn as_bool(&self) -> std::result::Result<bool, &Expr> {
154 match self {
155 Reload::Debug => Ok(cfg!(debug_assertions)),
156 Reload::Always => Ok(true),
157 Reload::Never => Ok(false),
158 Reload::Expr(expr) => Err(expr),
159 }
160 }
161}
162
163impl std::fmt::Debug for Reload {
164 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
165 match self {
166 Self::Debug => write!(f, "Reload::Debug"),
167 Self::Always => write!(f, "Reload::Always"),
168 Self::Never => write!(f, "Reload::Never"),
169 Self::Expr(_) => write!(f, "Reload::<Expr>"),
170 }
171 }
172}
173