Skip to main content

trellis_testing/
script.rs

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