Skip to content

Commit 34dc950

Browse files
committed
fix: Isolate cycle state
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()`.
1 parent 0659664 commit 34dc950

File tree

2 files changed

+44
-25
lines changed

2 files changed

+44
-25
lines changed

src/interpreter/context.rs

Lines changed: 42 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -52,15 +52,48 @@ impl InterruptState {
5252
}
5353
}
5454

55+
#[derive(Debug, Clone, PartialEq, Eq, Default)]
56+
struct CycleStateInner {
57+
// The indices of all the cycles encountered during rendering.
58+
cycles: HashMap<String, usize>,
59+
}
60+
61+
impl CycleStateInner {
62+
fn cycle_index(&mut self, name: &str, max: usize) -> usize {
63+
let i = self.cycles.entry(name.to_owned()).or_insert(0);
64+
let j = *i;
65+
*i = (*i + 1) % max;
66+
j
67+
}
68+
}
69+
70+
/// See `cycle` tag.
71+
pub struct CycleState<'a> {
72+
context: &'a mut Context,
73+
}
74+
75+
impl<'a> CycleState<'a> {
76+
pub fn cycle_element(&mut self, name: &str, values: &[Argument]) -> Result<Value> {
77+
let index = self.context.cycles.cycle_index(name, values.len());
78+
if index >= values.len() {
79+
return Err(Error::with_msg(
80+
"cycle index out of bounds, most likely from mismatched cycles",
81+
).context("index", &index)
82+
.context("count", &values.len()));
83+
}
84+
85+
let val = values[index].evaluate(self.context)?;
86+
Ok(val)
87+
}
88+
}
89+
5590
#[derive(Default)]
5691
pub struct Context {
5792
stack: Vec<Object>,
5893
globals: Object,
5994

6095
interrupt: InterruptState,
61-
62-
/// The indices of all the cycles encountered during rendering.
63-
cycles: HashMap<String, usize>,
96+
cycles: CycleStateInner,
6497

6598
filters: sync::Arc<HashMap<&'static str, BoxedValueFilter>>,
6699
}
@@ -81,24 +114,6 @@ impl Context {
81114
self
82115
}
83116

84-
pub fn cycle_element(&mut self, name: &str, values: &[Argument]) -> Result<Option<Value>> {
85-
let index = {
86-
let i = self.cycles.entry(name.to_owned()).or_insert(0);
87-
let j = *i;
88-
*i = (*i + 1) % values.len();
89-
j
90-
};
91-
92-
if index >= values.len() {
93-
return Err(Error::with_msg("cycle index out of bounds")
94-
.context("index", &index)
95-
.context("count", &values.len()));
96-
}
97-
98-
let val = values[index].evaluate(self)?;
99-
Ok(Some(val))
100-
}
101-
102117
pub fn get_filter<'b>(&'b self, name: &str) -> Option<&'b FilterValue> {
103118
self.filters.get(name).map(|f| {
104119
let f: &FilterValue = f;
@@ -114,6 +129,12 @@ impl Context {
114129
&mut self.interrupt
115130
}
116131

132+
pub fn cycles<'a>(&'a mut self) -> CycleState<'a> {
133+
CycleState {
134+
context: self,
135+
}
136+
}
137+
117138
/// Creates a new variable scope chained to a parent scope.
118139
fn push_scope(&mut self) {
119140
self.stack.push(Object::new());

src/tags/cycle_tag.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,9 @@ impl Cycle {
2828
impl Renderable for Cycle {
2929
fn render_to(&self, writer: &mut Write, context: &mut Context) -> Result<()> {
3030
let value = context
31-
.cycle_element(&self.name, &self.values)
31+
.cycles().cycle_element(&self.name, &self.values)
3232
.trace_with(|| self.trace().into())?;
33-
if let Some(ref value) = value {
34-
write!(writer, "{}", value).chain("Failed to render")?;
35-
}
33+
write!(writer, "{}", value).chain("Failed to render")?;
3634
Ok(())
3735
}
3836
}

0 commit comments

Comments
 (0)