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

TyRoXx / NonlocalityOS / 14776020836

01 May 2025 01:16PM UTC coverage: 76.808% (-0.8%) from 77.611%
14776020836

Pull #227

github

web-flow
Merge cc8a1814a into 3008f5ee2
Pull Request #227: Remove obsolete code

287 of 357 new or added lines in 9 files covered. (80.39%)

9 existing lines in 3 files now uncovered.

3951 of 5144 relevant lines covered (76.81%)

1832.82 hits per line

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

81.09
/lambda/src/expressions.rs
1
use crate::name::Name;
2
use astraea::tree::{BlobDigest, HashedValue, ReferenceIndex, Value, ValueDeserializationError};
3
use astraea::{
4
    storage::{LoadValue, StoreError, StoreValue},
5
    tree::ValueBlob,
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, V>
23
where
24
    E: Clone + Display + PrintExpression,
25
    V: Clone + Display,
26
{
27
    Literal(V),
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 {
30✔
40
        match self {
30✔
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) => {
9✔
51
                write!(writer, "{}", &name.key)
9✔
52
            }
NEW
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) => {
2✔
65
                write!(writer, "construct(")?;
2✔
66
                for argument in arguments {
8✔
67
                    argument.print(writer, level)?;
3✔
68
                    write!(writer, ", ")?;
3✔
69
                }
70
                write!(writer, ")")
2✔
71
            }
72
        }
73
    }
74
}
75

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

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

89
    pub fn make_lambda(parameter_name: Name, body: E) -> Self {
18✔
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 async fn map_child_expressions<
16✔
101
        't,
102
        Expr: Clone + Display + PrintExpression,
103
        V2: Clone + Display,
104
        Error,
105
        F,
106
        G,
107
    >(
108
        &self,
109
        transform_expression: &'t F,
110
        transform_value: &'t G,
111
    ) -> Result<Expression<Expr, V2>, Error>
112
    where
113
        F: Fn(&E) -> Pin<Box<dyn Future<Output = Result<Expr, Error>> + 't>>,
114
        G: Fn(&V) -> Pin<Box<dyn Future<Output = Result<V2, Error>> + 't>>,
115
    {
116
        match self {
16✔
117
            Expression::Literal(value) => Ok(Expression::Literal(transform_value(value).await?)),
10✔
NEW
118
            Expression::Apply { callee, argument } => Ok(Expression::Apply {
×
NEW
119
                callee: transform_expression(callee).await?,
×
NEW
120
                argument: transform_expression(argument).await?,
×
121
            }),
NEW
122
            Expression::ReadVariable(name) => Ok(Expression::ReadVariable(name.clone())),
×
NEW
123
            Expression::Lambda {
×
124
                parameter_name,
3✔
125
                body,
3✔
126
            } => Ok(Expression::Lambda {
3✔
127
                parameter_name: parameter_name.clone(),
3✔
128
                body: transform_expression(body).await?,
3✔
129
            }),
130
            Expression::Construct(items) => {
3✔
131
                let mut transformed_items = Vec::new();
3✔
132
                for item in items.iter() {
9✔
133
                    transformed_items.push(transform_expression(item).await?);
6✔
134
                }
135
                Ok(Expression::Construct(transformed_items))
3✔
136
            }
137
        }
138
    }
139
}
140

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

151
#[derive(Debug, PartialEq, Eq, Ord, PartialOrd, Hash, Clone)]
152
pub struct DeepExpression(pub Expression<Arc<DeepExpression>, BlobDigest>);
153

154
impl PrintExpression for DeepExpression {
155
    fn print(&self, writer: &mut dyn std::fmt::Write, level: usize) -> std::fmt::Result {
1✔
156
        self.0.print(writer, level)
1✔
157
    }
158
}
159

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

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

172
pub type ShallowExpression = Expression<BlobDigest, BlobDigest>;
173

174
impl PrintExpression for BlobDigest {
NEW
175
    fn print(&self, writer: &mut dyn std::fmt::Write, _level: usize) -> std::fmt::Result {
×
NEW
176
        write!(writer, "{}", self)
×
177
    }
178
}
179

180
pub type ReferenceExpression = Expression<ReferenceIndex, ReferenceIndex>;
181

182
impl PrintExpression for ReferenceIndex {
NEW
183
    fn print(&self, writer: &mut dyn std::fmt::Write, _level: usize) -> std::fmt::Result {
×
NEW
184
        write!(writer, "{}", self)
×
185
    }
186
}
187

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

227
pub async fn deserialize_shallow(value: &Value) -> Result<ShallowExpression, ()> {
10✔
228
    let reference_expression: ReferenceExpression = postcard::from_bytes(value.blob().as_slice())
5✔
229
        .unwrap(/*TODO*/);
230
    reference_expression
5✔
231
        .map_child_expressions(
232
            &|child: &ReferenceIndex| -> Pin<Box<dyn Future<Output = Result<BlobDigest, ()>>>> {
8✔
233
                let child = value.references()[child.0 as usize].clone();
3✔
234
                Box::pin(async move { Ok(child) })
9✔
235
            },
236
            &|child: &ReferenceIndex| -> Pin<Box<dyn Future<Output = Result<BlobDigest, ()>>>> {
8✔
237
                let child = value.references()[child.0 as usize].clone();
3✔
238
                Box::pin(async move { Ok(child) })
9✔
239
            },
240
        )
241
        .await
5✔
242
}
243

244
pub async fn deserialize_recursively(
5✔
245
    root: &BlobDigest,
246
    load_value: &(dyn LoadValue + Sync),
247
) -> Result<DeepExpression, ()> {
248
    let root_loaded = load_value.load_value(root).await.unwrap(/*TODO*/).hash().unwrap(/*TODO*/);
15✔
249
    let shallow = deserialize_shallow(&root_loaded.value()).await?;
10✔
250
    let deep = shallow
5✔
251
        .map_child_expressions(
252
            &|child: &BlobDigest| -> Pin<Box<dyn Future<Output = Result<Arc<DeepExpression>, ()>>>> {
3✔
253
                let child = child.clone();
3✔
254
                Box::pin(async move { deserialize_recursively(&child, load_value)
6✔
255
                    .await
3✔
256
                    .map(|success| Arc::new(success)) })
9✔
257
            },
258
            &|child: &BlobDigest| -> Pin<Box<dyn Future<Output = Result<BlobDigest, ()>>>> {
3✔
259
                let child = child.clone();
3✔
260
                Box::pin(async move { Ok(child) })
9✔
261
            },
262
        )
NEW
263
        .await?;
×
264
    Ok(DeepExpression(deep))
265
}
266

267
pub fn expression_to_value(expression: &ShallowExpression) -> Value {
6✔
268
    let (reference_expression, references) = to_reference_expression(expression);
6✔
269
    let blob = postcard::to_allocvec(&reference_expression).unwrap(/*TODO*/);
6✔
270
    Value::new(
271
        ValueBlob::try_from(bytes::Bytes::from_owner(blob)).unwrap(/*TODO*/),
6✔
272
        references,
6✔
273
    )
274
}
275

276
pub async fn serialize_shallow(
6✔
277
    expression: &ShallowExpression,
278
    storage: &(dyn StoreValue + Sync),
279
) -> std::result::Result<BlobDigest, StoreError> {
280
    let value = expression_to_value(expression);
6✔
281
    storage
6✔
282
        .store_value(&HashedValue::from(Arc::new(value)))
6✔
283
        .await
6✔
284
}
285

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

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

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

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

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

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

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

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

430
#[derive(Debug, Clone)]
431
pub struct InMemoryValue {
432
    pub blob: ValueBlob,
433
    pub references: Vec<Pointer>,
434
}
435

436
impl InMemoryValue {
NEW
437
    pub fn new(blob: ValueBlob, references: Vec<Pointer>) -> Self {
×
438
        Self { blob, references }
439
    }
440
}
441

442
#[derive(Debug, Clone)]
443
pub enum Pointer {
444
    Value(HashedValue),
445
    Reference(BlobDigest),
446
    InMemoryValue(InMemoryValue),
447
}
448

449
impl Pointer {
NEW
450
    pub fn serialize(self) -> HashedValue {
×
UNCOV
451
        match self {
×
NEW
452
            Pointer::Value(hashed_value) => hashed_value,
×
453
            Pointer::Reference(_blob_digest) => todo!(),
NEW
454
            Pointer::InMemoryValue(_in_memory_value) => {
×
455
                todo!()
456
            }
457
        }
458
    }
459

UNCOV
460
    pub async fn serialize_to_flat_value(&self) -> Option<Arc<Value>> {
×
UNCOV
461
        match self {
×
UNCOV
462
            Pointer::Value(hashed_value) => {
×
UNCOV
463
                if hashed_value.value().references().is_empty() {
×
UNCOV
464
                    Some(hashed_value.value().clone())
×
465
                } else {
466
                    None
×
467
                }
468
            }
469
            Pointer::Reference(_blob_digest) => todo!(),
NEW
470
            Pointer::InMemoryValue(_in_memory_value) => {
×
471
                todo!()
472
            }
473
        }
474
    }
475
}
476

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

480
fn find_captured_names(expression: &DeepExpression) -> BTreeSet<Name> {
6✔
481
    match &expression.0 {
6✔
482
        Expression::Literal(_blob_digest) => BTreeSet::new(),
4✔
NEW
483
        Expression::Apply { callee, argument } => {
×
NEW
484
            let mut result = find_captured_names(callee);
×
NEW
485
            result.append(&mut find_captured_names(argument));
×
NEW
486
            result
×
487
        }
NEW
488
        Expression::ReadVariable(name) => BTreeSet::from([name.clone()]),
×
489
        Expression::Lambda {
490
            parameter_name,
1✔
491
            body,
1✔
492
        } => {
1✔
493
            let mut result = find_captured_names(body);
1✔
494
            result.remove(&parameter_name);
1✔
495
            result
1✔
496
        }
497
        Expression::Construct(arguments) => {
1✔
498
            let mut result = BTreeSet::new();
1✔
499
            for argument in arguments {
5✔
500
                result.append(&mut find_captured_names(argument));
501
            }
502
            result
1✔
503
        }
504
    }
505
}
506

507
pub async fn evaluate(
12✔
508
    expression: &DeepExpression,
509
    load_value: &(dyn LoadValue + Sync),
510
    store_value: &(dyn StoreValue + Sync),
511
    read_variable: &Arc<ReadVariable>,
512
) -> std::result::Result<BlobDigest, StoreError> {
513
    match &expression.0 {
12✔
514
        Expression::Literal(literal_value) => Ok(literal_value.clone()),
6✔
515
        Expression::Apply { callee, argument } => {
2✔
516
            let evaluated_callee =
2✔
517
                Box::pin(evaluate(callee, load_value, store_value, read_variable)).await?;
2✔
518
            let evaluated_argument =
2✔
NEW
519
                Box::pin(evaluate(argument, load_value, store_value, read_variable)).await?;
×
520
            let closure = match Closure::deserialize(&evaluated_callee, load_value).await {
2✔
521
                Ok(success) => success,
2✔
522
                Err(_) => todo!(),
523
            };
524
            call_method(
525
                &closure.parameter_name,
2✔
526
                &closure.captured_variables,
2✔
527
                &closure.body,
2✔
528
                &evaluated_argument,
2✔
529
                load_value,
2✔
530
                store_value,
2✔
531
                read_variable,
2✔
532
            )
533
            .await
2✔
534
        }
NEW
535
        Expression::ReadVariable(name) => Ok(read_variable(&name).await),
×
536
        Expression::Lambda {
537
            parameter_name,
3✔
538
            body,
3✔
539
        } => {
3✔
540
            let mut captured_variables = BTreeMap::new();
3✔
541
            for captured_name in find_captured_names(body).into_iter() {
3✔
542
                let captured_value = read_variable(&captured_name).await;
×
543
                captured_variables.insert(captured_name, captured_value);
544
            }
545
            let closure = Closure::new(parameter_name.clone(), body.clone(), captured_variables);
3✔
546
            let serialized = closure.serialize(store_value).await?;
3✔
547
            Ok(serialized)
548
        }
549
        Expression::Construct(arguments) => {
1✔
550
            let mut evaluated_arguments = Vec::new();
1✔
551
            for argument in arguments {
5✔
552
                let evaluated_argument =
2✔
553
                    Box::pin(evaluate(argument, load_value, store_value, read_variable)).await?;
2✔
554
                evaluated_arguments.push(evaluated_argument);
555
            }
556
            Ok(HashedValue::from(Arc::new(Value::new(
1✔
557
                ValueBlob::empty(),
1✔
558
                evaluated_arguments,
1✔
559
            )))
560
            .digest()
1✔
561
            .clone())
1✔
562
        }
563
    }
564
}
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