Skip to content

Commit

Permalink
feat(interpeter): Runtime partials
Browse files Browse the repository at this point in the history
Partials are `Arc` so that
- It doesn't matter if the partial is a reference to an existing one or
  created on the spot
- Lifetime issues disappear instead of dealing with a `&'context Renderable` and `&mut 'context Context`.
  • Loading branch information
epage committed Dec 24, 2018
1 parent 42538f4 commit 0ef46a1
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 1 deletion.
48 changes: 47 additions & 1 deletion liquid-interpreter/src/context.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
use std::sync;

use anymap;
use liquid_error::Error;
use liquid_error::Result;

use super::PartialStore;
use super::Renderable;
use super::Stack;
use super::ValueStore;

Expand Down Expand Up @@ -41,15 +47,40 @@ impl InterruptState {
}
}

#[derive(Copy, Clone, Debug)]
struct NullPartials;

impl PartialStore for NullPartials {
fn contains(&self, _name: &str) -> bool {
false
}

fn names(&self) -> Vec<&str> {
Vec::new()
}

fn try_get(&self, _name: &str) -> Option<sync::Arc<Renderable>> {
None
}

fn get(&self, name: &str) -> Result<sync::Arc<Renderable>> {
Err(Error::with_msg("Partial does not exist").context("name", name.to_owned()))
}
}

/// Create processing context for a template.
pub struct ContextBuilder<'g> {
globals: Option<&'g ValueStore>,
partials: Option<&'g PartialStore>,
}

impl<'g> ContextBuilder<'g> {
/// Creates a new, empty rendering context.
pub fn new() -> Self {
Self { globals: None }
Self {
globals: None,
partials: None,
}
}

/// Initialize the stack with the given globals.
Expand All @@ -58,14 +89,22 @@ impl<'g> ContextBuilder<'g> {
self
}

/// Initialize partial-templates availible for including.
pub fn set_partials(mut self, values: &'g PartialStore) -> Self {
self.partials = Some(values);
self
}

/// Create the `Context`.
pub fn build(self) -> Context<'g> {
let stack = match self.globals {
Some(globals) => Stack::with_globals(globals),
None => Stack::empty(),
};
let partials = self.partials.unwrap_or(&NullPartials);
Context {
stack,
partials,
registers: anymap::AnyMap::new(),
interrupt: InterruptState::default(),
}
Expand All @@ -81,6 +120,7 @@ impl<'g> Default for ContextBuilder<'g> {
/// Processing context for a template.
pub struct Context<'g> {
stack: Stack<'g>,
partials: &'g PartialStore,

registers: anymap::AnyMap,
interrupt: InterruptState,
Expand All @@ -104,6 +144,11 @@ impl<'g> Context<'g> {
&mut self.interrupt
}

/// Partial templates for inclusion.
pub fn partials(&self) -> &PartialStore {
self.partials
}

/// Data store for stateful tags/blocks.
///
/// If a plugin needs state, it creates a `struct State : Default` and accesses it via
Expand Down Expand Up @@ -160,6 +205,7 @@ impl<'g> Default for Context<'g> {
fn default() -> Self {
Self {
stack: Stack::empty(),
partials: &NullPartials,
registers: anymap::AnyMap::new(),
interrupt: InterruptState::default(),
}
Expand Down
2 changes: 2 additions & 0 deletions liquid-interpreter/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ extern crate serde_yaml;

mod context;
mod expression;
mod partials;
mod renderable;
mod stack;
mod store;
Expand All @@ -21,6 +22,7 @@ mod variable;

pub use self::context::*;
pub use self::expression::*;
pub use self::partials::*;
pub use self::renderable::*;
pub use self::stack::*;
pub use self::store::*;
Expand Down
21 changes: 21 additions & 0 deletions liquid-interpreter/src/partials.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
use std::fmt;
use std::sync;

use liquid_error::Result;

use super::Renderable;

/// Available partial-templates for including.
pub trait PartialStore: fmt::Debug {
/// Check if partial-template exists.
fn contains(&self, name: &str) -> bool;

/// Enumerate all partial-templates.
fn names(&self) -> Vec<&str>;

/// Access a partial-template.
fn try_get(&self, name: &str) -> Option<sync::Arc<Renderable>>;

/// Access a .partial-template
fn get(&self, name: &str) -> Result<sync::Arc<Renderable>>;
}

0 comments on commit 0ef46a1

Please sign in to comment.