Skip to main content

msrt_std/
frontend.rs

1//! Active std frontend adapter.
2
3use std::io::{Read, Write};
4
5use msrt::endpoint::{ClientEndpoint, EngineConfig, PeerState};
6
7use crate::error::Result;
8use crate::event::AdapterEvent;
9use crate::io::IoState;
10
11/// Active std frontend adapter.
12#[derive(Debug)]
13pub struct StdFrontend<T> {
14    io: T,
15    endpoint: ClientEndpoint,
16    state: IoState,
17}
18
19impl<T> StdFrontend<T>
20where
21    T: Read + Write,
22{
23    /// Creates a frontend adapter using default MSRT config.
24    pub fn new(io: T) -> Self {
25        Self::with_config(io, EngineConfig::default())
26    }
27
28    /// Creates a frontend adapter using `config`.
29    pub fn with_config(io: T, config: EngineConfig) -> Self {
30        Self {
31            io,
32            endpoint: ClientEndpoint::new(config),
33            state: IoState::new(),
34        }
35    }
36
37    /// Returns the endpoint peer state.
38    pub fn peer_state(&self) -> PeerState {
39        self.endpoint.peer().state()
40    }
41
42    /// Returns a shared reference to the owned IO object.
43    pub const fn io(&self) -> &T {
44        &self.io
45    }
46
47    /// Returns a mutable reference to the owned IO object.
48    pub fn io_mut(&mut self) -> &mut T {
49        &mut self.io
50    }
51
52    /// Consumes the adapter and returns the owned IO object.
53    pub fn into_inner(self) -> T {
54        self.io
55    }
56
57    /// Starts a fresh frontend session.
58    pub fn connect(&mut self) -> Result<()> {
59        self.endpoint.connect(self.state.now_ms())?;
60        Ok(())
61    }
62
63    /// Drops the active frontend session.
64    pub fn disconnect(&mut self) {
65        self.endpoint.disconnect();
66    }
67
68    /// Queues an application message.
69    pub fn send(&mut self, message: &[u8]) -> Result<bool> {
70        Ok(self.endpoint.send(message)?.is_some())
71    }
72
73    /// Reads currently available stream bytes and feeds them into MSRT.
74    ///
75    /// This method is best used with nonblocking IO. `WouldBlock` is treated as
76    /// no input.
77    pub fn receive_available(&mut self) -> Result<usize> {
78        self.state.receive_available(&mut self.io, |now_ms, bytes| {
79            self.endpoint.receive(now_ms, bytes)
80        })
81    }
82
83    /// Polls one adapter event and writes any pending transmit bytes.
84    pub fn poll(&mut self) -> Result<AdapterEvent> {
85        self.state.poll(&mut self.io, |now_ms, tx_buf| {
86            self.endpoint.poll(now_ms, tx_buf)
87        })
88    }
89
90    /// Runs `receive_available` followed by `poll`.
91    pub fn tick(&mut self) -> Result<AdapterEvent> {
92        let _ = self.receive_available()?;
93        self.poll()
94    }
95}