Skip to main content

trellis_testing/
script.rs

1use trellis_core::{GraphResult, InputNode, Transaction};
2
3pub(crate) type StageOperation<C, O> =
4    dyn for<'tx> Fn(&mut Transaction<'tx, C, O>) -> GraphResult<()> + 'static;
5
6/// Deterministic transaction script that can be replayed against a fresh graph.
7pub struct TransactionScript<C = (), O = ()> {
8    pub(crate) steps: Vec<TransactionScriptStep<C, O>>,
9}
10
11impl<C, O> TransactionScript<C, O> {
12    /// Creates an empty transaction script.
13    pub fn new() -> Self {
14        Self { steps: Vec::new() }
15    }
16
17    /// Starts a named script step.
18    pub fn step(&mut self, name: impl Into<String>) -> TransactionScriptStepBuilder<'_, C, O> {
19        TransactionScriptStepBuilder {
20            script: self,
21            name: name.into(),
22            operations: Vec::new(),
23        }
24    }
25
26    /// Returns script steps in replay order.
27    pub fn steps(&self) -> &[TransactionScriptStep<C, O>] {
28        &self.steps
29    }
30}
31
32impl<C, O> Default for TransactionScript<C, O> {
33    fn default() -> Self {
34        Self::new()
35    }
36}
37
38/// Builder for one transaction script step.
39pub struct TransactionScriptStepBuilder<'script, C, O> {
40    script: &'script mut TransactionScript<C, O>,
41    name: String,
42    operations: Vec<Box<StageOperation<C, O>>>,
43}
44
45impl<C, O> TransactionScriptStepBuilder<'_, C, O>
46where
47    O: Clone + PartialEq,
48{
49    /// Stages a typed canonical input write for this step.
50    pub fn input<T>(mut self, input: InputNode<T>, value: T) -> Self
51    where
52        T: Clone + PartialEq + Send + Sync + 'static,
53    {
54        self.operations
55            .push(Box::new(move |tx| tx.set_input(input, value.clone())));
56        self
57    }
58
59    /// Stages a custom operation against the transaction.
60    pub fn operation(
61        mut self,
62        operation: impl for<'tx> Fn(&mut Transaction<'tx, C, O>) -> GraphResult<()> + 'static,
63    ) -> Self {
64        self.operations.push(Box::new(operation));
65        self
66    }
67
68    /// Adds this step to the script.
69    pub fn commit(self) {
70        self.script.steps.push(TransactionScriptStep {
71            name: self.name,
72            operations: self.operations,
73        });
74    }
75}
76
77/// One named transaction in a replayable script.
78pub struct TransactionScriptStep<C = (), O = ()> {
79    pub(crate) name: String,
80    pub(crate) operations: Vec<Box<StageOperation<C, O>>>,
81}
82
83impl<C, O> TransactionScriptStep<C, O> {
84    /// Returns the step name.
85    pub fn name(&self) -> &str {
86        &self.name
87    }
88}