• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

TyRoXx / NonlocalityOS / 14810760569

03 May 2025 12:15PM UTC coverage: 72.938% (-0.08%) from 73.014%
14810760569

push

github

TyRoXx
Rename remaining instances of Value and VALUE

1 of 7 new or added lines in 3 files covered. (14.29%)

107 existing lines in 5 files now uncovered.

3051 of 4183 relevant lines covered (72.94%)

2265.98 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

94.2
/lambda/src/expressions.rs
1
use crate::name::Name;
2
use astraea::tree::{BlobDigest, HashedTree, ReferenceIndex, Tree, TreeDeserializationError};
3
use astraea::{
4
    storage::{LoadTree, StoreError, StoreTree},
5
    tree::TreeBlob,
6
};
7
use serde::{Deserialize, Serialize};
8
use std::fmt::Display;
9
use std::future::Future;
10
use std::hash::Hash;
11
use std::{
12
    collections::{BTreeMap, BTreeSet},
13
    pin::Pin,
14
    sync::Arc,
15
};
16

17
pub trait PrintExpression {
18
    fn print(&self, writer: &mut dyn std::fmt::Write, level: usize) -> std::fmt::Result;
19
}
20

21
#[derive(Debug, PartialEq, Eq, Ord, PartialOrd, Hash, Clone, Serialize, Deserialize)]
22
pub enum Expression<E, TreeLike>
23
where
24
    E: Clone + Display + PrintExpression,
25
    TreeLike: Clone + Display,
26
{
27
    Literal(TreeLike),
28
    Apply { callee: E, argument: E },
29
    ReadVariable(Name),
30
    Lambda { parameter_name: Name, body: E },
31
    Construct(Vec<E>),
32
}
33

34
impl<E, V> PrintExpression for Expression<E, V>
35
where
36
    E: Clone + Display + PrintExpression,
37
    V: Clone + Display,
38
{
39
    fn print(&self, writer: &mut dyn std::fmt::Write, level: usize) -> std::fmt::Result {
32✔
40
        match self {
32✔
41
            Expression::Literal(literal_value) => {
4✔
42
                write!(writer, "literal({})", literal_value)
4✔
43
            }
44
            Expression::Apply { callee, argument } => {
3✔
45
                callee.print(writer, level)?;
3✔
46
                write!(writer, "(")?;
3✔
47
                argument.print(writer, level)?;
3✔
48
                write!(writer, ")")
3✔
49
            }
50
            Expression::ReadVariable(name) => {
10✔
51
                write!(writer, "{}", &name.key)
10✔
52
            }
53
            Expression::Lambda {
×
54
                parameter_name,
12✔
55
                body,
12✔
56
            } => {
12✔
57
                write!(writer, "({}) =>\n", parameter_name)?;
12✔
58
                let indented = level + 1;
12✔
59
                for _ in 0..(indented * 2) {
12✔
60
                    write!(writer, " ")?;
30✔
61
                }
62
                body.print(writer, indented)
12✔
63
            }
64
            Expression::Construct(arguments) => {
3✔
65
                write!(writer, "construct(")?;
3✔
66
                for argument in arguments {
11✔
67
                    argument.print(writer, level)?;
4✔
68
                    write!(writer, ", ")?;
4✔
69
                }
70
                write!(writer, ")")
3✔
71
            }
72
        }
73
    }
74
}
75

76
impl<E, TreeLike> Expression<E, TreeLike>
77
where
78
    E: Clone + Display + PrintExpression,
79
    TreeLike: Clone + Display,
80
{
81
    pub fn make_literal(value: TreeLike) -> Self {
9✔
82
        Expression::Literal(value)
9✔
83
    }
84

85
    pub fn make_apply(callee: E, argument: E) -> Self {
10✔
86
        Expression::Apply { callee, argument }
87
    }
88

89
    pub fn make_lambda(parameter_name: Name, body: E) -> Self {
20✔
90
        Expression::Lambda {
91
            parameter_name,
92
            body,
93
        }
94
    }
95

96
    pub fn make_construct(arguments: Vec<E>) -> Self {
2✔
97
        Expression::Construct(arguments)
2✔
98
    }
99

100
    pub fn make_read_variable(name: Name) -> Self {
1✔
101
        Expression::ReadVariable(name)
1✔
102
    }
103

104
    pub async fn map_child_expressions<
29✔
105
        't,
106
        Expr: Clone + Display + PrintExpression,
107
        TreeLike2: Clone + Display,
108
        Error,
109
        F,
110
        G,
111
    >(
112
        &self,
113
        transform_expression: &'t F,
114
        transform_tree: &'t G,
115
    ) -> Result<Expression<Expr, TreeLike2>, Error>
116
    where
117
        F: Fn(&E) -> Pin<Box<dyn Future<Output = Result<Expr, Error>> + 't>>,
118
        G: Fn(&TreeLike) -> Pin<Box<dyn Future<Output = Result<TreeLike2, Error>> + 't>>,
119
    {
120
        match self {
29✔
121
            Expression::Literal(value) => Ok(Expression::Literal(transform_tree(value).await?)),
12✔
122
            Expression::Apply { callee, argument } => Ok(Expression::Apply {
3✔
123
                callee: transform_expression(callee).await?,
3✔
124
                argument: transform_expression(argument).await?,
3✔
125
            }),
126
            Expression::ReadVariable(name) => Ok(Expression::ReadVariable(name.clone())),
4✔
127
            Expression::Lambda {
×
128
                parameter_name,
3✔
129
                body,
3✔
130
            } => Ok(Expression::Lambda {
3✔
131
                parameter_name: parameter_name.clone(),
3✔
132
                body: transform_expression(body).await?,
3✔
133
            }),
134
            Expression::Construct(items) => {
7✔
135
                let mut transformed_items = Vec::new();
7✔
136
                for item in items.iter() {
17✔
137
                    transformed_items.push(transform_expression(item).await?);
30✔
138
                }
139
                Ok(Expression::Construct(transformed_items))
7✔
140
            }
141
        }
142
    }
143
}
144

145
impl<E, V> Display for Expression<E, V>
146
where
147
    E: Clone + Display + PrintExpression,
148
    V: Clone + Display,
149
{
150
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
6✔
151
        self.print(f, 0)
6✔
152
    }
153
}
154

155
#[derive(Debug, PartialEq, Eq, Ord, PartialOrd, Hash, Clone)]
156
pub struct DeepExpression(pub Expression<Arc<DeepExpression>, BlobDigest>);
157

158
impl PrintExpression for DeepExpression {
159
    fn print(&self, writer: &mut dyn std::fmt::Write, level: usize) -> std::fmt::Result {
1✔
160
        self.0.print(writer, level)
1✔
161
    }
162
}
163

164
impl PrintExpression for Arc<DeepExpression> {
165
    fn print(&self, writer: &mut dyn std::fmt::Write, level: usize) -> std::fmt::Result {
22✔
166
        self.0.print(writer, level)
22✔
167
    }
168
}
169

170
impl Display for DeepExpression {
171
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
6✔
172
        write!(f, "{}", self.0)
6✔
173
    }
174
}
175

176
pub type ShallowExpression = Expression<BlobDigest, BlobDigest>;
177

178
impl PrintExpression for BlobDigest {
179
    fn print(&self, writer: &mut dyn std::fmt::Write, _level: usize) -> std::fmt::Result {
1✔
180
        write!(writer, "{}", self)
1✔
181
    }
182
}
183

184
pub type ReferenceExpression = Expression<ReferenceIndex, ReferenceIndex>;
185

186
impl PrintExpression for ReferenceIndex {
187
    fn print(&self, writer: &mut dyn std::fmt::Write, _level: usize) -> std::fmt::Result {
1✔
188
        write!(writer, "{}", self)
1✔
189
    }
190
}
191

192
pub fn to_reference_expression(
12✔
193
    expression: &ShallowExpression,
194
) -> (ReferenceExpression, Vec<BlobDigest>) {
195
    match expression {
12✔
196
        Expression::Literal(value) => (
4✔
197
            ReferenceExpression::Literal(ReferenceIndex(0)),
4✔
198
            vec![*value],
4✔
199
        ),
200
        Expression::Apply { callee, argument } => (
1✔
201
            ReferenceExpression::Apply {
1✔
202
                callee: ReferenceIndex(0),
1✔
203
                argument: ReferenceIndex(1),
1✔
204
            },
205
            // TODO: deduplicate?
206
            vec![*callee, *argument],
1✔
207
        ),
208
        Expression::ReadVariable(name) => (ReferenceExpression::ReadVariable(name.clone()), vec![]),
3✔
209
        Expression::Lambda {
210
            parameter_name,
1✔
211
            body,
1✔
212
        } => (
1✔
213
            ReferenceExpression::Lambda {
1✔
214
                parameter_name: parameter_name.clone(),
1✔
215
                body: ReferenceIndex(0),
1✔
216
            },
217
            vec![*body],
1✔
218
        ),
219
        Expression::Construct(items) => (
3✔
220
            ReferenceExpression::Construct(
3✔
221
                (0..items.len())
3✔
222
                    .map(|index| ReferenceIndex(index as u64))
7✔
223
                    .collect(),
3✔
224
            ),
225
            // TODO: deduplicate?
226
            items.clone(),
3✔
227
        ),
228
    }
229
}
230

231
pub async fn deserialize_shallow(tree: &Tree) -> Result<ShallowExpression, ()> {
18✔
232
    let reference_expression: ReferenceExpression = postcard::from_bytes(tree.blob().as_slice())
9✔
233
        .unwrap(/*TODO*/);
234
    reference_expression
9✔
235
        .map_child_expressions(
236
            &|child: &ReferenceIndex| -> Pin<Box<dyn Future<Output = Result<BlobDigest, ()>>>> {
6✔
237
                let child = tree.references()[child.0 as usize].clone();
6✔
238
                Box::pin(async move { Ok(child) })
12✔
239
            },
240
            &|child: &ReferenceIndex| -> Pin<Box<dyn Future<Output = Result<BlobDigest, ()>>>> {
4✔
241
                let child = tree.references()[child.0 as usize].clone();
4✔
242
                Box::pin(async move { Ok(child) })
8✔
243
            },
244
        )
245
        .await
9✔
246
}
247

248
pub async fn deserialize_recursively(
9✔
249
    root: &BlobDigest,
250
    load_tree: &(dyn LoadTree + Sync),
251
) -> Result<DeepExpression, ()> {
252
    let root_loaded = load_tree.load_tree(root).await.unwrap(/*TODO*/).hash().unwrap(/*TODO*/);
27✔
253
    let shallow = deserialize_shallow(&root_loaded.tree()).await?;
18✔
254
    let deep = shallow
9✔
255
        .map_child_expressions(
256
            &|child: &BlobDigest| -> Pin<Box<dyn Future<Output = Result<Arc<DeepExpression>, ()>>>> {
6✔
257
                let child = child.clone();
6✔
258
                Box::pin(async move { deserialize_recursively(&child, load_tree)
12✔
259
                    .await
6✔
260
                    .map(|success| Arc::new(success)) })
12✔
261
            },
262
            &|child: &BlobDigest| -> Pin<Box<dyn Future<Output = Result<BlobDigest, ()>>>> {
4✔
263
                let child = child.clone();
4✔
264
                Box::pin(async move { Ok(child) })
8✔
265
            },
266
        )
267
        .await?;
×
268
    Ok(DeepExpression(deep))
269
}
270

271
pub fn expression_to_tree(expression: &ShallowExpression) -> Tree {
11✔
272
    let (reference_expression, references) = to_reference_expression(expression);
11✔
273
    let blob = postcard::to_allocvec(&reference_expression).unwrap(/*TODO*/);
11✔
274
    Tree::new(
275
        TreeBlob::try_from(bytes::Bytes::from_owner(blob)).unwrap(/*TODO*/),
11✔
276
        references,
11✔
277
    )
278
}
279

280
pub async fn serialize_shallow(
11✔
281
    expression: &ShallowExpression,
282
    storage: &(dyn StoreTree + Sync),
283
) -> std::result::Result<BlobDigest, StoreError> {
284
    let tree = expression_to_tree(expression);
11✔
285
    storage.store_tree(&HashedTree::from(Arc::new(tree))).await
11✔
286
}
287

288
pub async fn serialize_recursively(
11✔
289
    expression: &DeepExpression,
290
    storage: &(dyn StoreTree + Sync),
291
) -> std::result::Result<BlobDigest, StoreError> {
292
    let shallow_expression: ShallowExpression = expression
22✔
293
        .0
11✔
294
        .map_child_expressions(&|child: &Arc<DeepExpression>| -> Pin<
11✔
295
            Box<dyn Future<Output = Result<BlobDigest, StoreError>>>,
296
        > {
7✔
297
            let child = child.clone();
7✔
298
            Box::pin(async move {
14✔
299
                serialize_recursively(&child, storage)
7✔
300
                    .await
7✔
301
            })
302
        },&|child: &BlobDigest| -> Pin<
7✔
303
        Box<dyn Future<Output = Result<BlobDigest, StoreError>>>,
304
        > {
4✔
305
            let child = child.clone();
4✔
306
            Box::pin(async move {
8✔
307
                Ok(child)
4✔
308
            })
309
        })
310
        .await?;
11✔
311
    serialize_shallow(&shallow_expression, storage).await
312
}
313

314
#[derive(Debug)]
315
pub struct Closure {
316
    parameter_name: Name,
317
    body: Arc<DeepExpression>,
318
    captured_variables: BTreeMap<Name, BlobDigest>,
319
}
320

321
#[derive(Debug, Serialize, Deserialize)]
322
pub struct ClosureBlob {
323
    parameter_name: Name,
324
    captured_variables: BTreeMap<Name, ReferenceIndex>,
325
}
326

327
impl ClosureBlob {
328
    pub fn new(parameter_name: Name, captured_variables: BTreeMap<Name, ReferenceIndex>) -> Self {
3✔
329
        Self {
330
            parameter_name,
331
            captured_variables,
332
        }
333
    }
334
}
335

336
impl Closure {
337
    pub fn new(
5✔
338
        parameter_name: Name,
339
        body: Arc<DeepExpression>,
340
        captured_variables: BTreeMap<Name, BlobDigest>,
341
    ) -> Self {
342
        Self {
343
            parameter_name,
344
            body,
345
            captured_variables,
346
        }
347
    }
348

349
    pub async fn serialize(
3✔
350
        &self,
351
        store_tree: &(dyn StoreTree + Sync),
352
    ) -> Result<BlobDigest, StoreError> {
353
        let mut references = vec![serialize_recursively(&self.body, store_tree).await?];
6✔
354
        let mut captured_variables = BTreeMap::new();
355
        for (name, reference) in self.captured_variables.iter() {
2✔
356
            let index = ReferenceIndex(references.len() as u64);
357
            captured_variables.insert(name.clone(), index);
358
            references.push(reference.clone());
359
        }
360
        let closure_blob = ClosureBlob::new(self.parameter_name.clone(), captured_variables);
361
        let closure_blob_bytes = postcard::to_allocvec(&closure_blob).unwrap(/*TODO*/);
362
        store_tree
363
            .store_tree(&HashedTree::from(Arc::new(Tree::new(
364
                TreeBlob::try_from(bytes::Bytes::from_owner(closure_blob_bytes)).unwrap(/*TODO*/),
365
                references,
366
            ))))
367
            .await
368
    }
369

370
    pub async fn deserialize(
2✔
371
        root: &BlobDigest,
372
        load_tree: &(dyn LoadTree + Sync),
373
    ) -> Result<Closure, TreeDeserializationError> {
374
        let loaded_root = match load_tree.load_tree(root).await {
4✔
375
            Some(success) => success,
2✔
UNCOV
376
            None => return Err(TreeDeserializationError::BlobUnavailable(root.clone())),
×
377
        };
378
        let root_tree = loaded_root.hash().unwrap(/*TODO*/).tree().clone();
2✔
379
        let closure_blob: ClosureBlob = match postcard::from_bytes(&root_tree.blob().as_slice()) {
4✔
380
            Ok(success) => success,
UNCOV
381
            Err(error) => return Err(TreeDeserializationError::Postcard(error)),
×
382
        };
383
        let body_reference = &root_tree.references()[0];
384
        let body = deserialize_recursively(body_reference, load_tree).await.unwrap(/*TODO*/);
4✔
385
        let mut captured_variables = BTreeMap::new();
2✔
386
        for (name, index) in closure_blob.captured_variables {
4✔
387
            let reference = &root_tree.references()[index.0 as usize];
388
            captured_variables.insert(name, reference.clone());
389
        }
390
        Ok(Closure::new(
2✔
391
            closure_blob.parameter_name,
2✔
392
            Arc::new(body),
2✔
393
            captured_variables,
2✔
394
        ))
395
    }
396
}
397

398
async fn call_method(
2✔
399
    parameter_name: &Name,
400
    captured_variables: &BTreeMap<Name, BlobDigest>,
401
    body: &DeepExpression,
402
    argument: &BlobDigest,
403
    load_tree: &(dyn LoadTree + Sync),
404
    store_tree: &(dyn StoreTree + Sync),
405
    read_variable: &Arc<ReadVariable>,
406
) -> std::result::Result<BlobDigest, StoreError> {
407
    let read_variable_in_body: Arc<ReadVariable> = Arc::new({
2✔
408
        let parameter_name = parameter_name.clone();
2✔
409
        let argument = argument.clone();
2✔
410
        let captured_variables = captured_variables.clone();
2✔
411
        let read_variable = read_variable.clone();
2✔
412
        move |name: &Name| -> Pin<Box<dyn core::future::Future<Output = BlobDigest> + Send>> {
1✔
413
            if name == &parameter_name {
1✔
414
                let argument = argument.clone();
1✔
415
                Box::pin(core::future::ready(argument))
1✔
UNCOV
416
            } else if let Some(found) = captured_variables.get(name) {
×
417
                Box::pin(core::future::ready(found.clone()))
418
            } else {
UNCOV
419
                read_variable(name)
×
420
            }
421
        }
422
    });
423
    Box::pin(evaluate(
2✔
424
        &body,
2✔
425
        load_tree,
2✔
426
        store_tree,
2✔
427
        &read_variable_in_body,
2✔
428
    ))
429
    .await
2✔
430
}
431

432
pub type ReadVariable =
433
    dyn Fn(&Name) -> Pin<Box<dyn core::future::Future<Output = BlobDigest> + Send>> + Send + Sync;
434

435
fn find_captured_names(expression: &DeepExpression) -> BTreeSet<Name> {
8✔
436
    match &expression.0 {
8✔
437
        Expression::Literal(_blob_digest) => BTreeSet::new(),
2✔
UNCOV
438
        Expression::Apply { callee, argument } => {
×
UNCOV
439
            let mut result = find_captured_names(callee);
×
440
            result.append(&mut find_captured_names(argument));
×
441
            result
×
442
        }
443
        Expression::ReadVariable(name) => BTreeSet::from([name.clone()]),
2✔
444
        Expression::Lambda {
445
            parameter_name,
1✔
446
            body,
1✔
447
        } => {
1✔
448
            let mut result = find_captured_names(body);
1✔
449
            result.remove(&parameter_name);
1✔
450
            result
1✔
451
        }
452
        Expression::Construct(arguments) => {
3✔
453
            let mut result = BTreeSet::new();
3✔
454
            for argument in arguments {
11✔
455
                result.append(&mut find_captured_names(argument));
456
            }
457
            result
3✔
458
        }
459
    }
460
}
461

462
pub async fn evaluate(
12✔
463
    expression: &DeepExpression,
464
    load_tree: &(dyn LoadTree + Sync),
465
    store_tree: &(dyn StoreTree + Sync),
466
    read_variable: &Arc<ReadVariable>,
467
) -> std::result::Result<BlobDigest, StoreError> {
468
    match &expression.0 {
12✔
469
        Expression::Literal(literal_value) => Ok(literal_value.clone()),
6✔
470
        Expression::Apply { callee, argument } => {
2✔
471
            let evaluated_callee =
2✔
472
                Box::pin(evaluate(callee, load_tree, store_tree, read_variable)).await?;
2✔
473
            let evaluated_argument =
2✔
UNCOV
474
                Box::pin(evaluate(argument, load_tree, store_tree, read_variable)).await?;
×
475
            let closure = match Closure::deserialize(&evaluated_callee, load_tree).await {
2✔
476
                Ok(success) => success,
2✔
477
                Err(_) => todo!(),
478
            };
479
            call_method(
480
                &closure.parameter_name,
2✔
481
                &closure.captured_variables,
2✔
482
                &closure.body,
2✔
483
                &evaluated_argument,
2✔
484
                load_tree,
2✔
485
                store_tree,
2✔
486
                read_variable,
2✔
487
            )
488
            .await
2✔
489
        }
UNCOV
490
        Expression::ReadVariable(name) => Ok(read_variable(&name).await),
×
491
        Expression::Lambda {
492
            parameter_name,
3✔
493
            body,
3✔
494
        } => {
3✔
495
            let mut captured_variables = BTreeMap::new();
3✔
496
            for captured_name in find_captured_names(body).into_iter() {
5✔
497
                let captured_variable_value = read_variable(&captured_name).await;
4✔
498
                captured_variables.insert(captured_name, captured_variable_value);
499
            }
500
            let closure = Closure::new(parameter_name.clone(), body.clone(), captured_variables);
3✔
501
            let serialized = closure.serialize(store_tree).await?;
3✔
502
            Ok(serialized)
503
        }
504
        Expression::Construct(arguments) => {
1✔
505
            let mut evaluated_arguments = Vec::new();
1✔
506
            for argument in arguments {
5✔
507
                let evaluated_argument =
2✔
508
                    Box::pin(evaluate(argument, load_tree, store_tree, read_variable)).await?;
2✔
509
                evaluated_arguments.push(evaluated_argument);
510
            }
511
            Ok(
512
                HashedTree::from(Arc::new(Tree::new(TreeBlob::empty(), evaluated_arguments)))
1✔
513
                    .digest()
1✔
514
                    .clone(),
1✔
515
            )
516
        }
517
    }
518
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc