Skip to content

Commit

Permalink
Change the Object::attributes method to return an iterator (#138)
Browse files Browse the repository at this point in the history
  • Loading branch information
mitsuhiko committed Nov 8, 2022
1 parent d4a9d0e commit eddd7c6
Show file tree
Hide file tree
Showing 4 changed files with 27 additions and 26 deletions.
16 changes: 7 additions & 9 deletions minijinja/src/value/mod.rs
Expand Up @@ -552,7 +552,7 @@ impl Value {
ValueRepr::String(ref s, _) => Some(s.chars().count()),
ValueRepr::Map(ref items, _) => Some(items.len()),
ValueRepr::Seq(ref items) => Some(items.len()),
ValueRepr::Dynamic(ref dy) => Some(dy.attributes().len()),
ValueRepr::Dynamic(ref dy) => Some(dy.attributes().count()),
_ => None,
}
}
Expand Down Expand Up @@ -796,8 +796,7 @@ impl Value {
) as Box<dyn Iterator<Item = _>>,
ValueRepr::Dynamic(ref obj) => Box::new(
obj.attributes()
.iter()
.filter_map(move |attr| Some((*attr, some!(obj.get_attr(attr))))),
.filter_map(move |attr| Some((attr, some!(obj.get_attr(attr))))),
) as Box<dyn Iterator<Item = _>>,
_ => Box::new(None.into_iter()) as Box<dyn Iterator<Item = _>>,
}
Expand Down Expand Up @@ -869,11 +868,10 @@ impl Serialize for Value {
}
ValueRepr::Dynamic(ref n) => {
use serde::ser::SerializeMap;
let fields = n.attributes();
let mut s = ok!(serializer.serialize_map(Some(fields.len())));
for k in fields {
let mut s = ok!(serializer.serialize_map(None));
for k in n.attributes() {
let v = n.get_attr(k).unwrap_or(Value::UNDEFINED);
ok!(s.serialize_entry(k, &v));
ok!(s.serialize_entry(&k, &v));
}
s.end()
}
Expand Down Expand Up @@ -983,8 +981,8 @@ fn test_dynamic_object_roundtrip() {
}
}

fn attributes(&self) -> &'static [&'static str] {
&["value"]
fn attributes(&self) -> Box<dyn Iterator<Item = &str> + '_> {
Box::new(["value"].into_iter())
}
}

Expand Down
6 changes: 3 additions & 3 deletions minijinja/src/value/object.rs
Expand Up @@ -36,12 +36,12 @@ pub trait Object: fmt::Display + fmt::Debug + Any + Sync + Send {

/// An enumeration of attributes that are known to exist on this object.
///
/// The default implementation returns an empty slice. If it's not possible
/// The default implementation returns an empty iterator. If it's not possible
/// to implement this, it's fine for the implementation to be omitted. The
/// enumeration here is used by the `for` loop to iterate over the attributes
/// on the value.
fn attributes(&self) -> &[&str] {
&[][..]
fn attributes(&self) -> Box<dyn Iterator<Item = &str> + '_> {
Box::new(None.into_iter())
}

/// Called when the engine tries to call a method on the object.
Expand Down
27 changes: 15 additions & 12 deletions minijinja/src/vm/loop_object.rs
Expand Up @@ -24,18 +24,21 @@ impl fmt::Debug for Loop {
}

impl Object for Loop {
fn attributes(&self) -> &[&str] {
&[
"index0",
"index",
"length",
"revindex",
"revindex0",
"first",
"last",
"depth",
"depth0",
][..]
fn attributes(&self) -> Box<dyn Iterator<Item = &str> + '_> {
Box::new(
[
"index0",
"index",
"length",
"revindex",
"revindex0",
"first",
"last",
"depth",
"depth0",
]
.into_iter(),
)
}

fn get_attr(&self, name: &str) -> Option<Value> {
Expand Down
4 changes: 2 additions & 2 deletions minijinja/src/vm/macro_object.rs
Expand Up @@ -41,8 +41,8 @@ impl fmt::Display for Macro {
}

impl Object for Macro {
fn attributes(&self) -> &[&str] {
&["name", "arguments"][..]
fn attributes(&self) -> Box<dyn Iterator<Item = &str> + '_> {
Box::new(["name", "arguments"].into_iter())
}

fn get_attr(&self, name: &str) -> Option<Value> {
Expand Down

0 comments on commit eddd7c6

Please sign in to comment.