-
-
Notifications
You must be signed in to change notification settings - Fork 78
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Cow based interface for StructObject::fields #157
Comments
Looking through the code base a bit now the case for |
@SergioBenitez so since I changed the An alternative would be to let it return |
You can model my case as a The ideal would be to be able to return values that borrow from anything or values that can optimally borrow from nothing. I'm not sure what prohibits the former in minijinja's case. I would imagine that since the context is only held during the rendering call, this wouldn't be too difficult to pull off, but I haven't given it a closer look. In the latter case, I have imagined an API by which the engine tracks object path accesses at compile-time and then asks once (say via an Object trait) for a terminal value that isn't compound, so anything but a map or sequence. For example, for
The engine would again ask I'm in favor of any zero-overhead solution that allows me to make use of my HashMap wrapper as a template context. The less code I have to write to make that possible, the better, of course. |
For what it's worth MiniJinja today already has an optimization for this, but it's not exposed. When minijinja converts string keys it auto interns. In some ways a Exposing a compound lookup is definitely possible and I have considered this before, but for the case where someone needs to iterate over one of those objects probably the same issue applies. |
Sorry, I conflated a couple of things without properly distinguishing them. The optimization I was referring to was one where clones of compound values (maps, vectors) are avoided (in response to In terms of the iterator of strings returned by
I think if properly tracked, the final lookup should still be compound. So something like: {% for k in map %}
{{ other.map[k].foo }}
{% endfor %} Should still perform a single call per iteration to |
I will have a look at this, but in terms of this:
If I were to expose |
Today there is actually not a single code path that is likely to be encountered where I'm heavily leaning towards changing the interface to this: pub trait StructObject: Send + Sync {
fn get_field(&self, name: &str) -> Option<Value>;
fn static_fields(&self) -> Option<&'static [&'static str]> {
None
}
fn fields(&self) -> Vec<Arc<String>> {
self.static_fields()
.into_iter()
.flat_map(|fields| fields.iter().copied().map(intern))
.collect()
}
fn field_count(&self) -> usize {
if let Some(fields) = self.static_fields() {
fields.len()
} else {
self.fields().len()
}
}
} Exposing the Implementation is in #158 |
I'm still not entirely sure where In any case, I expect (but would like clarity) that
I also wonder what the benefit to string interning is here. If the strings are static, then you can just store the pointer. If the strings are dynamic, are they really used all that often to merit the cost of string interning? The alternative being, of course, that strings aren't interned and the method is allowed to return |
Iteration is the only place where it's used, but iteration there is not lazy for structs. This is because the length needs to be known anyways for the struct (
I thought so too but it turns out that having two representations ( |
One other bit of information I suppose is that even in Jinja2, iteration over dictionaries typically takes place in the form of |
I'm changing this on main for now and will play around with it before release to see if this works well. |
The current
fields
interface only allows borrowing astr
out of self. While attempting to make a safe interface for stack borrowing I realized that there are cases where you really need to create an owned string there (#156).There are two options here:
fn fields(&self) -> Box<dyn Iterator<Item = Cow<'_, str>> + '_>
— which has the advantage that you can borrow in a lot of cases, but it means that code which cannot hold on to the lifetime needs to allocate a string in all casesfn fields(&self) -> Box<dyn Iterator<Item = Cow<'static, str>> + '_>
— would require more dynamic allocations in case the field name is not fully known, but has the advantage that we could internally start having aValueRepr::StaticStr
which might avoid unnecessary allocations in a lot of cases.The text was updated successfully, but these errors were encountered: