Skip to content

Commit

Permalink
fix: Isolate cycle state
Browse files Browse the repository at this point in the history
This is a part of an effort to modularize context so it will be easier
to put in special logic for globals.

BREAKING CHANGE: For tags, you need to use
`context.cycles()`.
  • Loading branch information
epage committed Sep 10, 2018
1 parent 0659664 commit 34dc950
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 25 deletions.
63 changes: 42 additions & 21 deletions src/interpreter/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,15 +52,48 @@ impl InterruptState {
}
}

#[derive(Debug, Clone, PartialEq, Eq, Default)]
struct CycleStateInner {
// The indices of all the cycles encountered during rendering.
cycles: HashMap<String, usize>,
}

impl CycleStateInner {
fn cycle_index(&mut self, name: &str, max: usize) -> usize {
let i = self.cycles.entry(name.to_owned()).or_insert(0);
let j = *i;
*i = (*i + 1) % max;
j
}
}

/// See `cycle` tag.
pub struct CycleState<'a> {
context: &'a mut Context,
}

impl<'a> CycleState<'a> {
pub fn cycle_element(&mut self, name: &str, values: &[Argument]) -> Result<Value> {
let index = self.context.cycles.cycle_index(name, values.len());
if index >= values.len() {
return Err(Error::with_msg(
"cycle index out of bounds, most likely from mismatched cycles",
).context("index", &index)
.context("count", &values.len()));
}

let val = values[index].evaluate(self.context)?;
Ok(val)
}
}

#[derive(Default)]
pub struct Context {
stack: Vec<Object>,
globals: Object,

interrupt: InterruptState,

/// The indices of all the cycles encountered during rendering.
cycles: HashMap<String, usize>,
cycles: CycleStateInner,

filters: sync::Arc<HashMap<&'static str, BoxedValueFilter>>,
}
Expand All @@ -81,24 +114,6 @@ impl Context {
self
}

pub fn cycle_element(&mut self, name: &str, values: &[Argument]) -> Result<Option<Value>> {
let index = {
let i = self.cycles.entry(name.to_owned()).or_insert(0);
let j = *i;
*i = (*i + 1) % values.len();
j
};

if index >= values.len() {
return Err(Error::with_msg("cycle index out of bounds")
.context("index", &index)
.context("count", &values.len()));
}

let val = values[index].evaluate(self)?;
Ok(Some(val))
}

pub fn get_filter<'b>(&'b self, name: &str) -> Option<&'b FilterValue> {
self.filters.get(name).map(|f| {
let f: &FilterValue = f;
Expand All @@ -114,6 +129,12 @@ impl Context {
&mut self.interrupt
}

pub fn cycles<'a>(&'a mut self) -> CycleState<'a> {
CycleState {
context: self,
}
}

/// Creates a new variable scope chained to a parent scope.
fn push_scope(&mut self) {
self.stack.push(Object::new());
Expand Down
6 changes: 2 additions & 4 deletions src/tags/cycle_tag.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,9 @@ impl Cycle {
impl Renderable for Cycle {
fn render_to(&self, writer: &mut Write, context: &mut Context) -> Result<()> {
let value = context
.cycle_element(&self.name, &self.values)
.cycles().cycle_element(&self.name, &self.values)
.trace_with(|| self.trace().into())?;
if let Some(ref value) = value {
write!(writer, "{}", value).chain("Failed to render")?;
}
write!(writer, "{}", value).chain("Failed to render")?;
Ok(())
}
}
Expand Down

0 comments on commit 34dc950

Please sign in to comment.