Skip to main content

lace_sans_io/core/
interlace.rs

1use crate::iltp::IltpItem;
2use crate::logic::InterlaceModule;
3
4use super::{
5    CarrierRole, ConnectedCarrier, ConnectedConfig, CoreError, DirectConfig, DirectPair,
6    FixedPointWakeBoundary, InterlaceSide, MachineError, MachinePoll, PeerInput,
7    PeerInputDisposition, ProtocolPhaseToken, StoreCall, StorePosition, StorePositionAdvance,
8};
9
10/// The sole semantic owner of either a same-runtime pair or one connected carrier.
11#[derive(Debug)]
12pub struct InterlaceMachine {
13    owner: InterlaceOwner,
14}
15
16#[derive(Debug)]
17enum InterlaceOwner {
18    Direct(Box<DirectPair>),
19    Connected(Box<ConnectedCarrier>),
20}
21
22impl InterlaceMachine {
23    pub fn new_direct(config: DirectConfig) -> Result<Self, CoreError> {
24        Ok(Self {
25            owner: InterlaceOwner::Direct(Box::new(DirectPair::new(config)?)),
26        })
27    }
28
29    pub fn new_connected(role: CarrierRole, config: ConnectedConfig) -> Result<Self, CoreError> {
30        Ok(Self {
31            owner: InterlaceOwner::Connected(Box::new(ConnectedCarrier::new(role, config)?)),
32        })
33    }
34
35    pub fn protocol_phase_token(&self, side: InterlaceSide) -> Option<ProtocolPhaseToken> {
36        match &self.owner {
37            InterlaceOwner::Direct(pair) => Some(pair.protocol_phase_token(side)),
38            InterlaceOwner::Connected(carrier) => {
39                (carrier.local_protocol_side() == side).then(|| carrier.protocol_phase_token())
40            }
41        }
42    }
43
44    pub fn active_store_call(&self, side: InterlaceSide) -> Option<&StoreCall> {
45        match &self.owner {
46            InterlaceOwner::Direct(pair) => pair.active_store_call(side),
47            InterlaceOwner::Connected(carrier) => carrier
48                .active_store_call()
49                .filter(|call| call.side() == side),
50        }
51    }
52
53    pub fn active_store_call_mut(&mut self, side: InterlaceSide) -> Option<&mut StoreCall> {
54        match &mut self.owner {
55            InterlaceOwner::Direct(pair) => pair.active_store_call_mut(side),
56            InterlaceOwner::Connected(carrier) => carrier
57                .active_store_call_mut()
58                .filter(|call| call.side() == side),
59        }
60    }
61
62    pub fn replace_direct_policy(
63        &mut self,
64        operands: [InterlaceModule; 2],
65    ) -> Result<(), CoreError> {
66        match &mut self.owner {
67            InterlaceOwner::Direct(pair) => pair.replace_policy(operands),
68            InterlaceOwner::Connected(_) => Err(CoreError::InvalidConfig(
69                "connected interlace requires one local replacement operand",
70            )),
71        }
72    }
73
74    pub fn replace_connected_policy(&mut self, operand: InterlaceModule) -> Result<(), CoreError> {
75        match &mut self.owner {
76            InterlaceOwner::Connected(carrier) => carrier.replace_policy(operand),
77            InterlaceOwner::Direct(_) => Err(CoreError::InvalidConfig(
78                "direct interlace requires both replacement operands",
79            )),
80        }
81    }
82
83    pub fn submit_store_call(&mut self, id: u64) -> Result<(), MachineError> {
84        match &mut self.owner {
85            InterlaceOwner::Direct(pair) => pair.submit_store_call(id),
86            InterlaceOwner::Connected(carrier) => carrier.submit_store_call(id),
87        }
88    }
89
90    pub fn try_store_position_advanced(
91        &mut self,
92        boundary: &FixedPointWakeBoundary,
93        position: StorePosition,
94    ) -> StorePositionAdvance {
95        match &mut self.owner {
96            InterlaceOwner::Direct(pair) => pair.try_store_position_advanced(boundary, position),
97            InterlaceOwner::Connected(carrier) => {
98                carrier.try_store_position_advanced(boundary, position)
99            }
100        }
101    }
102
103    pub fn timeout(&mut self, side: InterlaceSide) -> Result<(), CoreError> {
104        match &mut self.owner {
105            InterlaceOwner::Direct(pair) => pair.timeout(side),
106            InterlaceOwner::Connected(carrier) if carrier.local_protocol_side() == side => {
107                carrier.timeout()
108            }
109            InterlaceOwner::Connected(_) => {
110                return Err(CoreError::InvalidConfig(
111                    "connected interlace has no endpoint on that side",
112                ));
113            }
114        }
115        Ok(())
116    }
117
118    pub fn can_read_peer_input(&self) -> Result<bool, CoreError> {
119        match &self.owner {
120            InterlaceOwner::Connected(carrier) => Ok(carrier.can_read_peer_input()),
121            InterlaceOwner::Direct(_) => Err(CoreError::InvalidConfig(
122                "direct interlace has no peer stream",
123            )),
124        }
125    }
126
127    pub fn peer_record_ingress(&self) -> Result<super::RecordIngress, CoreError> {
128        match &self.owner {
129            InterlaceOwner::Connected(carrier) => Ok(carrier.peer_record_ingress()),
130            InterlaceOwner::Direct(_) => Err(CoreError::InvalidConfig(
131                "direct interlace has no peer stream",
132            )),
133        }
134    }
135
136    pub fn peer_input_disposition(
137        &self,
138        input: &PeerInput,
139    ) -> Result<PeerInputDisposition, CoreError> {
140        match &self.owner {
141            InterlaceOwner::Connected(carrier) => Ok(carrier.peer_input_disposition(input)),
142            InterlaceOwner::Direct(_) => Err(CoreError::InvalidConfig(
143                "direct interlace has no peer stream",
144            )),
145        }
146    }
147
148    pub fn push_peer_input(&mut self, input: impl Into<PeerInput>) -> Result<(), MachineError> {
149        match &mut self.owner {
150            InterlaceOwner::Connected(carrier) => carrier.push_input(input),
151            InterlaceOwner::Direct(_) => Err(super::machine::integration_machine_error(
152                "direct interlace does not accept peer input",
153            )),
154        }
155    }
156
157    /// Accept the retained connected output. A terminal transition this causes
158    /// returns the same error the next poll reports as `Failed`.
159    /// Accept the polled peer output, handing its items to the writer.
160    pub fn accept_peer_output(&mut self) -> Result<Vec<IltpItem>, MachineError> {
161        match &mut self.owner {
162            InterlaceOwner::Connected(carrier) => carrier.accept_peer_output(),
163            InterlaceOwner::Direct(_) => Err(super::machine::integration_machine_error(
164                "direct interlace has no peer output",
165            )),
166        }
167    }
168
169    /// Answer [`MachinePoll::SelectOperand`] on a port-selecting carrier:
170    /// this logical session's operand, or `None` to refuse the port.
171    /// Share `cache` with every logical session, while the first operand
172    /// selection is unanswered ([`ConnectedCarrier::adopt_operand_cache`]).
173    pub fn adopt_operand_cache(&mut self, cache: super::OperandCache) -> Result<(), MachineError> {
174        match &mut self.owner {
175            InterlaceOwner::Connected(carrier) => carrier.adopt_operand_cache(cache),
176            InterlaceOwner::Direct(_) => Err(super::machine::integration_machine_error(
177                "direct interlace has no port",
178            )),
179        }
180    }
181
182    pub fn select_operand(
183        &mut self,
184        selection: Option<super::SessionOperand>,
185    ) -> Result<(), MachineError> {
186        match &mut self.owner {
187            InterlaceOwner::Connected(carrier) => carrier.select_operand(selection),
188            InterlaceOwner::Direct(_) => Err(super::machine::integration_machine_error(
189                "direct interlace has no port",
190            )),
191        }
192    }
193
194    /// The port of the latest peer preface; a direct pair has none.
195    pub fn peer_port(&self) -> Option<&crate::iltp::PortText> {
196        match &self.owner {
197            InterlaceOwner::Connected(carrier) => carrier.peer_port(),
198            InterlaceOwner::Direct(_) => None,
199        }
200    }
201
202    /// The By the live peer proved in the latest logical session; a direct
203    /// pair has none.
204    pub fn peer_by(&self) -> Option<&crate::records::ByValue> {
205        match &self.owner {
206            InterlaceOwner::Connected(carrier) => carrier.peer_by(),
207            InterlaceOwner::Direct(_) => None,
208        }
209    }
210
211    /// The encoding of the local-to-peer direction the latest preface pair
212    /// selects; a direct pair has none.
213    pub fn outgoing_encoding(&self) -> Option<crate::iltp::StreamEncoding> {
214        match &self.owner {
215            InterlaceOwner::Connected(carrier) => carrier.outgoing_encoding(),
216            InterlaceOwner::Direct(_) => None,
217        }
218    }
219
220    /// The encoding of the peer-to-local direction the latest preface pair
221    /// selects; a direct pair has none.
222    pub fn incoming_encoding(&self) -> Option<crate::iltp::StreamEncoding> {
223        match &self.owner {
224            InterlaceOwner::Connected(carrier) => carrier.incoming_encoding(),
225            InterlaceOwner::Direct(_) => None,
226        }
227    }
228
229    /// The connected route's diagnostics for a bounded outcome.
230    pub fn peer_diagnostics(&self) -> crate::runtime_values::PeerDiagnostics {
231        crate::runtime_values::PeerDiagnostics {
232            peer_by: self.peer_by().copied(),
233            outgoing_encoding: self.outgoing_encoding(),
234            incoming_encoding: self.incoming_encoding(),
235        }
236    }
237
238    pub fn peer_eof(&mut self) -> Result<(), MachineError> {
239        match &mut self.owner {
240            InterlaceOwner::Connected(carrier) => carrier.peer_eof(),
241            InterlaceOwner::Direct(_) => Err(super::machine::integration_machine_error(
242                "direct interlace has no peer stream",
243            )),
244        }
245    }
246
247    pub fn cancel(&mut self) {
248        match &mut self.owner {
249            InterlaceOwner::Connected(carrier) => carrier.cancel(),
250            InterlaceOwner::Direct(pair) => pair.cancel(),
251        }
252    }
253
254    pub fn poll(&mut self) -> MachinePoll<'_> {
255        match &mut self.owner {
256            InterlaceOwner::Direct(pair) => pair.poll(),
257            InterlaceOwner::Connected(carrier) => carrier.poll(),
258        }
259    }
260}