tinytemplate_async/
instruction.rs

1use std::ops::Deref;
2
3/// TinyTemplate implements a simple bytecode interpreter for its template engine. Instructions
4/// for this interpreter are represented by the Instruction enum and typically contain various
5/// parameters such as the path to context values or name strings.
6///
7/// In TinyTemplate, the template string itself is assumed to be statically available (or at least
8/// longer-lived than the TinyTemplate instance) so paths and instructions simply borrow string
9/// slices from the template text. These string slices can then be appended directly to the output
10/// string.
11
12/// Enum for a step in a path which optionally contains a parsed index.
13#[derive(Eq, PartialEq, Debug, Clone)]
14pub(crate) enum PathStep {
15    Name(String),
16    Index(String, usize),
17}
18impl Deref for PathStep {
19    type Target = str;
20
21    fn deref(&self) -> &Self::Target {
22        match self {
23            PathStep::Name(s) => s,
24            PathStep::Index(s, _) => s,
25        }
26    }
27}
28
29/// Sequence of named steps used for looking up values in the context
30pub(crate) type Path = Vec<PathStep>;
31
32/// Path, but as a slice.
33pub(crate) type PathSlice<'a> = &'a [PathStep];
34
35/// Enum representing the bytecode instructions.
36#[derive(Eq, PartialEq, Debug, Clone)]
37pub(crate) enum Instruction {
38    /// Emit a literal string into the output buffer
39    Literal(String),
40
41    /// Look up the value for the given path and render it into the output buffer using the default
42    /// formatter
43    Value(Path),
44
45    /// Look up the value for the given path and pass it to the formatter with the given name
46    FormattedValue(Path, String),
47
48    /// Look up the value at the given path and jump to the given instruction index if that value
49    /// is truthy (if the boolean is true) or falsy (if the boolean is false)
50    Branch(Path, bool, usize),
51
52    /// Push a named context on the stack, shadowing only that name.
53    PushNamedContext(Path, String),
54
55    /// Push an iteration context on the stack, shadowing the given name with the current value from
56    /// the vec pointed to by the path. The current value will be updated by the Iterate instruction.
57    /// This is always generated before an Iterate instruction which actually starts the iterator.
58    PushIterationContext(Path, String),
59
60    /// Pop a context off the stack
61    PopContext,
62
63    /// Advance the topmost iterator on the context stack by one and update that context. If the
64    /// iterator is empty, jump to the given instruction.
65    Iterate(usize),
66
67    /// Unconditionally jump to the given instruction. Used to skip else blocks and repeat loops.
68    Goto(usize),
69
70    /// Look up the named template and render it into the output buffer with the value pointed to
71    /// by the path as its context.
72    Call(String, Path),
73}
74
75/// Convert a path back into a dotted string.
76pub(crate) fn path_to_str(path: PathSlice) -> String {
77    let mut path_str = "".to_string();
78    for (i, step) in path.iter().enumerate() {
79        if i > 0 {
80            path_str.push('.');
81        }
82        path_str.push_str(step);
83    }
84    path_str
85}