liquid_core/partials/
eager.rs1use std::collections::HashMap;
2use std::fmt;
3use std::sync;
4
5use crate::error::Error;
6use crate::error::Result;
7use crate::parser;
8use crate::parser::Language;
9use crate::runtime;
10use crate::runtime::PartialStore;
11use crate::runtime::Renderable;
12
13use super::PartialCompiler;
14use super::PartialSource;
15
16#[derive(Debug)]
25pub struct EagerCompiler<S: PartialSource> {
26 source: S,
27}
28
29impl<S> EagerCompiler<S>
30where
31 S: PartialSource,
32{
33 pub fn new(source: S) -> Self {
35 EagerCompiler { source }
36 }
37}
38
39impl<S> EagerCompiler<S>
40where
41 S: PartialSource + Default,
42{
43 pub fn empty() -> Self {
45 Default::default()
46 }
47}
48
49impl<S> Default for EagerCompiler<S>
50where
51 S: PartialSource + Default,
52{
53 fn default() -> Self {
54 Self {
55 source: Default::default(),
56 }
57 }
58}
59
60impl<S> ::std::ops::Deref for EagerCompiler<S>
61where
62 S: PartialSource,
63{
64 type Target = S;
65
66 fn deref(&self) -> &S {
67 &self.source
68 }
69}
70
71impl<S> ::std::ops::DerefMut for EagerCompiler<S>
72where
73 S: PartialSource,
74{
75 fn deref_mut(&mut self) -> &mut S {
76 &mut self.source
77 }
78}
79
80impl<S> PartialCompiler for EagerCompiler<S>
81where
82 S: PartialSource + Send + Sync + 'static,
83{
84 fn compile(self, language: sync::Arc<Language>) -> Result<Box<dyn PartialStore + Send + Sync>> {
85 let store: HashMap<_, _> = self
86 .source
87 .names()
88 .into_iter()
89 .map(|name| {
90 let source = self.source.get(name).and_then(|s| {
91 parser::parse(s.as_ref(), &language)
92 .map(runtime::Template::new)
93 .map(|t| {
94 let t: sync::Arc<dyn runtime::Renderable> = sync::Arc::new(t);
95 t
96 })
97 });
98 (name.to_owned(), source)
99 })
100 .collect();
101 let store = EagerStore { store };
102 Ok(Box::new(store))
103 }
104
105 fn source(&self) -> &dyn PartialSource {
106 &self.source
107 }
108}
109
110struct EagerStore {
111 store: HashMap<String, Result<sync::Arc<dyn runtime::Renderable>>>,
112}
113
114impl PartialStore for EagerStore {
115 fn contains(&self, name: &str) -> bool {
116 self.store.contains_key(name)
117 }
118
119 fn names(&self) -> Vec<&str> {
120 self.store.keys().map(|s| s.as_str()).collect()
121 }
122
123 fn try_get(&self, name: &str) -> Option<sync::Arc<dyn Renderable>> {
124 self.store.get(name).and_then(|r| r.clone().ok())
125 }
126
127 fn get(&self, name: &str) -> Result<sync::Arc<dyn Renderable>> {
128 let result = self.store.get(name).ok_or_else(|| {
129 let mut available: Vec<_> = self.names();
130 available.sort_unstable();
131 let available = itertools::join(available, ", ");
132 Error::with_msg("Unknown partial-template")
133 .context("requested partial", name.to_owned())
134 .context("available partials", available)
135 })?;
136 result.clone()
137 }
138}
139
140impl fmt::Debug for EagerStore {
141 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
142 self.names().fmt(f)
143 }
144}