liquid_core/partials/
ondemand.rs

1use std::fmt;
2use std::sync;
3
4use crate::error::Result;
5use crate::parser;
6use crate::parser::Language;
7use crate::runtime;
8use crate::runtime::PartialStore;
9use crate::runtime::Renderable;
10
11use super::PartialCompiler;
12use super::PartialSource;
13
14/// An on-demand compiler for `PartialSource`.
15///
16/// This is unlikely the `PartialCompiler` you want.  This best serves as an example.
17///
18/// This would be useful in cases where:
19/// - Most partial-templates aren't used
20/// - Of the used partial-templates, they are generally used once.
21#[derive(Debug)]
22pub struct OnDemandCompiler<S: PartialSource> {
23    source: S,
24}
25
26impl<S> OnDemandCompiler<S>
27where
28    S: PartialSource,
29{
30    /// Create an on-demand compiler for `PartialSource`.
31    pub fn new(source: S) -> Self {
32        OnDemandCompiler { source }
33    }
34}
35
36impl<S> OnDemandCompiler<S>
37where
38    S: PartialSource + Default,
39{
40    /// Create an empty compiler for `PartialSource`.
41    pub fn empty() -> Self {
42        Default::default()
43    }
44}
45
46impl<S> Default for OnDemandCompiler<S>
47where
48    S: PartialSource + Default,
49{
50    fn default() -> Self {
51        Self {
52            source: Default::default(),
53        }
54    }
55}
56
57impl<S> ::std::ops::Deref for OnDemandCompiler<S>
58where
59    S: PartialSource,
60{
61    type Target = S;
62
63    fn deref(&self) -> &S {
64        &self.source
65    }
66}
67
68impl<S> ::std::ops::DerefMut for OnDemandCompiler<S>
69where
70    S: PartialSource,
71{
72    fn deref_mut(&mut self) -> &mut S {
73        &mut self.source
74    }
75}
76
77impl<S> PartialCompiler for OnDemandCompiler<S>
78where
79    S: PartialSource + Send + Sync + 'static,
80{
81    fn compile(self, language: sync::Arc<Language>) -> Result<Box<dyn PartialStore + Send + Sync>> {
82        let store = OnDemandStore {
83            language,
84            source: self.source,
85        };
86        Ok(Box::new(store))
87    }
88
89    fn source(&self) -> &dyn PartialSource {
90        &self.source
91    }
92}
93
94struct OnDemandStore<S: PartialSource> {
95    language: sync::Arc<Language>,
96    source: S,
97}
98
99impl<S> PartialStore for OnDemandStore<S>
100where
101    S: PartialSource,
102{
103    fn contains(&self, name: &str) -> bool {
104        self.source.contains(name)
105    }
106
107    fn names(&self) -> Vec<&str> {
108        self.source.names()
109    }
110
111    fn try_get(&self, name: &str) -> Option<sync::Arc<dyn Renderable>> {
112        let s = self.source.try_get(name)?;
113        let s = s.as_ref();
114        let template = parser::parse(s, &self.language)
115            .map(runtime::Template::new)
116            .map(sync::Arc::new)
117            .ok()?;
118        Some(template)
119    }
120
121    fn get(&self, name: &str) -> Result<sync::Arc<dyn Renderable>> {
122        let s = self.source.get(name)?;
123        let s = s.as_ref();
124        let template = parser::parse(s, &self.language)
125            .map(runtime::Template::new)
126            .map(sync::Arc::new)?;
127        Ok(template)
128    }
129}
130
131impl<S> fmt::Debug for OnDemandStore<S>
132where
133    S: PartialSource,
134{
135    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
136        self.source.fmt(f)
137    }
138}