1mod codec;
2mod payloads;
3pub mod primitives;
4
5use log::{debug, trace};
6use pallas_multiplexer::{Channel, Payload};
7use std::borrow::Borrow;
8use std::fmt::{Debug, Display};
9use std::sync::mpsc::Sender;
10
11pub use payloads::*;
12
13#[derive(Debug)]
14pub enum MachineError<State, Msg>
15where
16 State: Debug,
17 Msg: Debug,
18{
19 InvalidMsgForState(State, Msg),
20}
21
22impl<S, M> Display for MachineError<S, M>
23where
24 S: Debug,
25 M: Debug,
26{
27 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
28 match self {
29 MachineError::InvalidMsgForState(msg, state) => {
30 write!(
31 f,
32 "received invalid message ({:?}) for current state ({:?})",
33 msg, state
34 )
35 }
36 }
37 }
38}
39
40impl<S, M> std::error::Error for MachineError<S, M>
41where
42 S: Debug,
43 M: Debug,
44{
45}
46
47#[derive(Debug)]
48pub enum CodecError {
49 BadLabel(u16),
50 UnexpectedCbor(&'static str),
51}
52
53impl std::error::Error for CodecError {}
54
55impl Display for CodecError {
56 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
57 match self {
58 CodecError::BadLabel(label) => {
59 write!(f, "unknown message label: {}", label)
60 }
61 CodecError::UnexpectedCbor(msg) => {
62 write!(f, "unexpected cbor: {}", msg)
63 }
64 }
65 }
66}
67
68pub trait MachineOutput {
69 fn send_msg(&self, data: &impl EncodePayload) -> Result<(), Box<dyn std::error::Error>>;
70}
71
72impl MachineOutput for Sender<Payload> {
73 fn send_msg(&self, data: &impl EncodePayload) -> Result<(), Box<dyn std::error::Error>> {
74 let payload = to_payload(data.borrow())?;
75 self.send(payload)?;
76
77 Ok(())
78 }
79}
80
81pub type Transition<T> = Result<T, Box<dyn std::error::Error>>;
82
83pub trait Agent: Sized {
84 type Message: DecodePayload + Debug;
85
86 fn is_done(&self) -> bool;
87 fn has_agency(&self) -> bool;
88 fn send_next(self, tx: &impl MachineOutput) -> Transition<Self>;
89 fn receive_next(self, msg: Self::Message) -> Transition<Self>;
90}
91
92pub fn run_agent<T: Agent + Debug>(
93 agent: T,
94 channel: &mut Channel,
95) -> Result<T, Box<dyn std::error::Error>> {
96 let Channel(tx, rx) = channel;
97
98 let mut input = PayloadDeconstructor {
99 rx,
100 remaining: Vec::new(),
101 };
102
103 let mut agent = agent;
104
105 while !agent.is_done() {
106 debug!("evaluating agent {:?}", agent);
107
108 match agent.has_agency() {
109 true => {
110 agent = agent.send_next(tx)?;
111 }
112 false => {
113 let msg = input.consume_next_message::<T::Message>()?;
114 trace!("procesing inbound msg: {:?}", msg);
115 agent = agent.receive_next(msg)?;
116 }
117 }
118 }
119
120 Ok(agent)
121}