Skip to content

Commit d609b2f

Browse files
authored
Merge pull request #144 from togglebyte/feature/expr_id
Dedupe expressions
2 parents 4c3bac9 + 0d52403 commit d609b2f

File tree

26 files changed

+769
-523
lines changed

26 files changed

+769
-523
lines changed

Cargo.toml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,12 @@ anathema-testutils = { path = "anathema-testutils" }
3131

3232
[features]
3333
default = []
34-
profile = ["anathema-runtime/profile", "anathema-widgets/profile", "anathema-backend/profile", "anathema-value-resolver/profile"]
34+
profile = [
35+
"anathema-runtime/profile",
36+
"anathema-widgets/profile",
37+
"anathema-backend/profile",
38+
"anathema-value-resolver/profile",
39+
]
3540
serde = ["anathema-state/serde", "anathema-store/serde"]
3641
# filelog = ["anathema-debug/filelog", "anathema-widgets/filelog", "anathema-runtime/filelog"]
3742

anathema-default-widgets/src/border.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -428,7 +428,7 @@ impl Widget for Border {
428428
id: WidgetId,
429429
ctx: &mut LayoutCtx<'_, 'bp>,
430430
) -> Result<Size> {
431-
let attributes = ctx.attribute_storage.get_mut(id);
431+
let attributes = ctx.attribute_storage.get(id);
432432

433433
self.sides = attributes.get_as::<Sides>("sides").unwrap_or_default();
434434

anathema-default-widgets/src/testing.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ pub struct TestRunner {
134134
variables: Variables,
135135
components: Components,
136136
function_table: FunctionTable,
137+
doc: Document,
137138
}
138139

139140
impl TestRunner {
@@ -171,6 +172,7 @@ impl TestRunner {
171172
variables,
172173
components: Components::new(),
173174
function_table: FunctionTable::new(),
175+
doc,
174176
}
175177
}
176178

@@ -184,6 +186,7 @@ impl TestRunner {
184186
&mut self.component_registry,
185187
&mut self.components,
186188
&self.function_table,
189+
&self.doc,
187190
)
188191
}
189192
}
@@ -202,6 +205,7 @@ pub struct TestInstance<'bp> {
202205
changes: Changes,
203206
glyph_map: GlyphMap,
204207
function_table: &'bp FunctionTable,
208+
doc: &'bp Document,
205209
}
206210

207211
impl<'bp> TestInstance<'bp> {
@@ -214,6 +218,7 @@ impl<'bp> TestInstance<'bp> {
214218
component_registry: &'bp mut ComponentRegistry,
215219
components: &'bp mut Components,
216220
function_table: &'bp FunctionTable,
221+
doc: &'bp Document,
217222
) -> Self {
218223
let mut tree = WidgetTree::empty();
219224
let mut attribute_storage = AttributeStorage::empty();
@@ -233,6 +238,7 @@ impl<'bp> TestInstance<'bp> {
233238
&mut glyph_map,
234239
&mut viewport,
235240
function_table,
241+
&doc.expressions,
236242
);
237243

238244
let mut ctx = ctx.eval_ctx(None, None);
@@ -254,6 +260,7 @@ impl<'bp> TestInstance<'bp> {
254260
changes: Changes::empty(),
255261
glyph_map,
256262
function_table,
263+
doc,
257264
}
258265
}
259266

@@ -285,6 +292,7 @@ impl<'bp> TestInstance<'bp> {
285292
&mut self.glyph_map,
286293
&mut self.viewport,
287294
self.function_table,
295+
&self.doc.expressions,
288296
);
289297

290298
self.changes.iter().for_each(|(sub, change)| {
@@ -331,6 +339,7 @@ impl<'bp> TestInstance<'bp> {
331339
&mut self.glyph_map,
332340
&mut self.viewport,
333341
self.function_table,
342+
&self.doc.expressions,
334343
);
335344

336345
let mut cycle = WidgetCycle::new(self.backend, self.tree.view(), constraints);

anathema-runtime/src/builder.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,8 @@ impl<G: GlobalEventHandler> Builder<G> {
171171
}
172172

173173
pub fn register_global(&mut self, key: impl Into<String>, value: impl Into<Expression>) -> Result<()> {
174-
self.variables.define_global(key, value).map_err(|e| e.to_error(None))?;
174+
let id = self.document.expressions.insert_at_root(value.into());
175+
self.variables.define_global(key, id).map_err(|e| e.to_error(None))?;
175176
Ok(())
176177
}
177178

anathema-runtime/src/runtime/mod.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,8 @@ impl Runtime<()> {
6666
}
6767

6868
pub fn register_global(&mut self, key: impl Into<String>, value: impl Into<Expression>) -> Result<()> {
69-
self.variables.define_global(key, value).map_err(|e| e.to_error(None))?;
69+
let id = self.document.expressions.insert_at_root(value.into());
70+
self.variables.define_global(key, id).map_err(|e| e.to_error(None))?;
7071
Ok(())
7172
}
7273

@@ -239,6 +240,7 @@ impl<G: GlobalEventHandler> Runtime<G> {
239240
&mut self.glyph_map,
240241
&mut self.viewport,
241242
&self.function_table,
243+
&self.document.expressions,
242244
);
243245

244246
let inst = Frame {

anathema-store/src/slab/generational.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -460,6 +460,20 @@ where
460460
}
461461
}
462462

463+
// -----------------------------------------------------------------------------
464+
// - Index -
465+
// -----------------------------------------------------------------------------
466+
impl<T> std::ops::Index<Key> for GenSlab<T> {
467+
type Output = T;
468+
469+
fn index(&self, index: Key) -> &Self::Output {
470+
match self.get(index) {
471+
Some(val) => val,
472+
None => panic!("invalid index or generation"),
473+
}
474+
}
475+
}
476+
463477
#[cfg(test)]
464478
mod test {
465479
use super::*;

anathema-templates/src/blueprints.rs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,29 @@
11
use anathema_store::smallmap::SmallMap;
22
use anathema_store::storage::strings::StringId;
33

4+
use crate::ComponentBlueprintId;
45
use crate::components::AssocEventMapping;
5-
use crate::{ComponentBlueprintId, Expression};
6+
use crate::expressions::ExpressionId;
67

78
#[derive(Debug, Clone, PartialEq)]
89
pub struct Single {
910
pub ident: String,
1011
pub children: Vec<Blueprint>,
11-
pub attributes: SmallMap<String, Expression>,
12-
pub value: Option<Expression>,
12+
pub attributes: SmallMap<String, ExpressionId>,
13+
pub value: Option<ExpressionId>,
1314
}
1415

1516
#[derive(Debug, Clone, PartialEq)]
1617
pub struct For {
1718
pub binding: String,
18-
pub data: Expression,
19+
pub data: ExpressionId,
1920
pub body: Vec<Blueprint>,
2021
}
2122

2223
#[derive(Debug, Clone, PartialEq)]
2324
pub struct With {
2425
pub binding: String,
25-
pub data: Expression,
26+
pub data: ExpressionId,
2627
pub body: Vec<Blueprint>,
2728
}
2829

@@ -34,7 +35,7 @@ pub struct ControlFlow {
3435

3536
#[derive(Debug, Clone, PartialEq)]
3637
pub struct Else {
37-
pub cond: Option<Expression>,
38+
pub cond: Option<ExpressionId>,
3839
pub body: Vec<Blueprint>,
3940
}
4041

@@ -44,7 +45,7 @@ pub struct Component {
4445
pub name_id: StringId,
4546
pub id: ComponentBlueprintId,
4647
pub body: Vec<Blueprint>,
47-
pub attributes: SmallMap<String, Expression>,
48+
pub attributes: SmallMap<String, ExpressionId>,
4849
pub assoc_functions: Vec<AssocEventMapping>,
4950
/// The parent component in the blueprint
5051
pub parent: Option<ComponentBlueprintId>,

anathema-templates/src/components.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use anathema_store::storage::Storage;
1010
use crate::Lexer;
1111
use crate::blueprints::Blueprint;
1212
use crate::error::{Error, ErrorKind, Result};
13+
use crate::expressions::Expressions;
1314
use crate::statements::eval::Scope;
1415
use crate::statements::parser::Parser;
1516
use crate::statements::{Context, Statements};
@@ -223,6 +224,7 @@ impl ComponentTemplates {
223224
variables: &mut Variables,
224225
slots: SmallMap<StringId, Vec<Blueprint>>,
225226
strings: &mut Strings,
227+
expressions: &mut Expressions,
226228
) -> Result<Vec<Blueprint>> {
227229
let ticket = self.components.checkout(component_id);
228230
let (_, component_src) = &*ticket;
@@ -238,7 +240,7 @@ impl ComponentTemplates {
238240
// NOTE
239241
// The ticket has to be restored to the component store,
240242
// this is why the error is returned rather than using `?` on `self.compile`.
241-
let ret = self.compile(component_src, variables, slots, strings, component_id);
243+
let ret = self.compile(component_src, variables, slots, strings, expressions, component_id);
242244
self.components.restore(ticket);
243245
self.dependencies.pop();
244246
ret
@@ -250,6 +252,7 @@ impl ComponentTemplates {
250252
variables: &mut Variables,
251253
slots: SmallMap<StringId, Vec<Blueprint>>,
252254
strings: &mut Strings,
255+
expressions: &mut Expressions,
253256
parent: ComponentBlueprintId,
254257
) -> Result<Vec<Blueprint>> {
255258
let tokens = Lexer::new(template, strings).collect::<Result<Vec<_>>>()?;
@@ -258,7 +261,7 @@ impl ComponentTemplates {
258261

259262
let statements = parser.collect::<Result<Statements>>()?;
260263

261-
let mut context = Context::new(template, variables, self, strings, slots, Some(parent));
264+
let mut context = Context::new(template, variables, self, strings, expressions, slots, Some(parent));
262265

263266
Scope::new(statements).eval(&mut context)
264267
}

anathema-templates/src/document.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use anathema_store::smallmap::SmallMap;
66
use crate::blueprints::Blueprint;
77
use crate::components::{ComponentTemplates, SourceKind, TemplateSource};
88
use crate::error::{Error, ErrorKind, Result};
9+
use crate::expressions::Expressions;
910
use crate::statements::eval::Scope;
1011
use crate::statements::parser::Parser;
1112
use crate::statements::{Context, Statements};
@@ -21,6 +22,7 @@ use crate::{ComponentBlueprintId, Lexer, Variables};
2122
pub struct Document {
2223
template: TemplateSource,
2324
pub strings: Strings,
25+
pub expressions: Expressions,
2426
components: ComponentTemplates,
2527
pub hot_reload: bool,
2628
}
@@ -31,6 +33,7 @@ impl Document {
3133
Self {
3234
template,
3335
strings: Strings::new(),
36+
expressions: Expressions::empty(),
3437
components: ComponentTemplates::new(),
3538
hot_reload: true,
3639
}
@@ -58,6 +61,8 @@ impl Document {
5861

5962
pub fn compile(&mut self, globals: &mut Variables) -> Result<Blueprint> {
6063
globals.reset_globals();
64+
self.expressions.clear();
65+
6166
let tokens = Lexer::new(&self.template, &mut self.strings).collect::<Result<Vec<_>>>()?;
6267
let tokens = Tokens::new(tokens, self.template.len());
6368
let parser = Parser::new(tokens, &mut self.strings, &self.template, &mut self.components);
@@ -68,6 +73,7 @@ impl Document {
6873
template: &self.template,
6974
variables: globals,
7075
strings: &mut self.strings,
76+
expressions: &mut self.expressions,
7177
components: &mut self.components,
7278
slots: SmallMap::empty(),
7379
current_component_parent: None,

anathema-templates/src/expressions/mod.rs

Lines changed: 68 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,80 @@ use std::collections::HashMap;
22
use std::fmt::Display;
33

44
use anathema_state::Hex;
5+
use anathema_store::slab::Index;
56

67
use crate::primitives::Primitive;
7-
use crate::variables::VarId;
8+
use crate::variables::{ScopeId, VarId};
89

910
pub(crate) mod eval;
1011
pub(crate) mod parser;
1112

13+
#[derive(Debug, Copy, Clone, PartialEq)]
14+
pub struct ExpressionId(u32);
15+
16+
impl From<ExpressionId> for Index {
17+
fn from(value: ExpressionId) -> Self {
18+
value.0.into()
19+
}
20+
}
21+
22+
#[derive(Debug)]
23+
pub struct Expressions {
24+
inner: Vec<(Expression, ScopeId)>,
25+
}
26+
27+
impl Expressions {
28+
pub fn empty() -> Self {
29+
Self { inner: vec![] }
30+
}
31+
32+
/// Get a reference to an expression
33+
///
34+
/// # Panics
35+
///
36+
/// Panics if the expression id is greater than the length of expressions.
37+
/// This should never happen as the ids are assigned to blueprints using them.
38+
///
39+
/// Only time this could happen is if the expression id is created outside of the tempalte
40+
/// generation.
41+
pub fn get(&self, id: ExpressionId) -> &Expression {
42+
&self.inner[id.0 as usize].0
43+
}
44+
45+
/// Insert an expression in the root scope
46+
pub fn insert_at_root(&mut self, expression: impl Into<Expression>) -> ExpressionId {
47+
self.insert(expression.into(), ScopeId::root().clone())
48+
}
49+
50+
/// Insert an expression and return the id to the newly inserted expression
51+
pub fn insert(&mut self, expression: Expression, boundary: ScopeId) -> ExpressionId {
52+
let id = ExpressionId(self.inner.len() as u32);
53+
match self
54+
.inner
55+
.iter()
56+
.position(|(e, scope)| expression.eq(e) && boundary.eq(scope))
57+
{
58+
Some(id) => ExpressionId(id as u32),
59+
None => {
60+
self.inner.push((expression, boundary));
61+
id
62+
}
63+
}
64+
}
65+
66+
pub(crate) fn clear(&mut self) {
67+
self.inner.clear()
68+
}
69+
}
70+
71+
impl std::ops::Index<ExpressionId> for Expressions {
72+
type Output = Expression;
73+
74+
fn index(&self, index: ExpressionId) -> &Self::Output {
75+
&self.inner[index.0 as usize].0
76+
}
77+
}
78+
1279
#[derive(Debug, Copy, Clone, PartialEq)]
1380
pub enum Op {
1481
Add,

0 commit comments

Comments
 (0)