use obzenflow_core::{
Contract, ContractContext, ContractReadContext, ContractResult, ContractWriteContext,
};
pub struct ContractChain {
contracts: Vec<Box<dyn Contract>>,
write_contexts: Vec<ContractWriteContext>,
read_contexts: Vec<ContractReadContext>,
}
impl Default for ContractChain {
fn default() -> Self {
Self::new()
}
}
impl ContractChain {
pub fn new() -> Self {
Self {
contracts: Vec::new(),
write_contexts: Vec::new(),
read_contexts: Vec::new(),
}
}
pub fn with_contract<C>(mut self, contract: C) -> Self
where
C: Contract + 'static,
{
let placeholder_stage = obzenflow_core::StageId::new();
self.write_contexts
.push(ContractWriteContext::new(placeholder_stage));
self.read_contexts.push(ContractReadContext::new(
placeholder_stage,
placeholder_stage,
));
self.contracts.push(Box::new(contract));
self
}
pub fn is_empty(&self) -> bool {
self.contracts.is_empty()
}
pub fn on_write(
&mut self,
event: &obzenflow_core::ChainEvent,
writer_stage: obzenflow_core::StageId,
writer_seq: obzenflow_core::event::types::SeqNo,
) {
for ctx in &mut self.write_contexts {
ctx.writer_stage = writer_stage;
ctx.writer_seq = writer_seq;
}
for (contract, ctx) in self.contracts.iter().zip(self.write_contexts.iter_mut()) {
contract.on_write(event, ctx);
}
}
pub fn on_read(
&mut self,
event: &obzenflow_core::ChainEvent,
reader_stage: obzenflow_core::StageId,
reader_seq: obzenflow_core::event::types::SeqNo,
upstream_stage: obzenflow_core::StageId,
) {
for ctx in &mut self.read_contexts {
ctx.reader_stage = reader_stage;
ctx.reader_seq = reader_seq;
ctx.upstream_stage = upstream_stage;
}
for (contract, ctx) in self.contracts.iter().zip(self.read_contexts.iter_mut()) {
contract.on_read(event, ctx);
}
}
pub fn verify_all(
&self,
upstream_stage: obzenflow_core::StageId,
downstream_stage: obzenflow_core::StageId,
) -> Vec<(String, ContractResult)> {
self.contracts
.iter()
.zip(self.write_contexts.iter())
.zip(self.read_contexts.iter())
.map(|((contract, write_ctx), read_ctx)| {
let ctx = ContractContext {
upstream_stage,
downstream_stage,
write_state: &write_ctx.state,
read_state: &read_ctx.state,
};
(contract.name().to_string(), contract.verify(&ctx))
})
.collect()
}
pub fn check_progress_all(
&self,
upstream_stage: obzenflow_core::StageId,
downstream_stage: obzenflow_core::StageId,
) -> Vec<(String, ContractResult)> {
self.contracts
.iter()
.zip(self.write_contexts.iter())
.zip(self.read_contexts.iter())
.map(|((contract, write_ctx), read_ctx)| {
let ctx = ContractContext {
upstream_stage,
downstream_stage,
write_state: &write_ctx.state,
read_state: &read_ctx.state,
};
let result = match contract.check_progress(&ctx) {
Some(v) => ContractResult::Failed(v),
None => ContractResult::Pending,
};
(contract.name().to_string(), result)
})
.collect()
}
}