ssip_client_async/
poll.rs

1// ssip-client -- Speech Dispatcher client in Rust
2// Copyright (c) 2022 Laurent Pelecq
3//
4// Licensed under the Apache License, Version 2.0
5// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT
6// license <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
7// option. All files in the project carrying such notice may not be copied,
8// modified, or distributed except according to those terms.
9
10use std::collections::VecDeque;
11use std::io::{Read, Write};
12
13#[cfg(feature = "async-mio")]
14use crate::client::{MioClient, MioSource};
15use crate::{
16    client::{Client, Source},
17    types::*,
18};
19
20// Hack to generate the doc. There must be a better way.
21#[cfg(all(not(feature = "async-mio"), doc))]
22mod mio {
23    /// Polls for readiness events on all registered values.
24    ///
25    /// See [`mio::Poll`](https://docs.rs/mio/latest/mio/struct.Poll.html#)
26    pub struct Poll {}
27
28    /// Source identifier.
29    ///
30    /// See [`mio::Token`](https://docs.rs/mio/latest/mio/struct.Token.html#).
31    pub struct Token(pub usize);
32}
33
34const INITIAL_REQUEST_QUEUE_CAPACITY: usize = 4;
35
36/// Client with a queue of requests.
37///
38/// The client can be used with crates like [popol](https://crates.io/crates/popol) or
39/// with [mio](https://crates.io/crates/mio) if feature `async-mio` is enabled.
40///
41/// When the output is ready, a next event can be sent.
42pub struct QueuedClient<S: Read + Write + Source> {
43    client: Client<S>,
44    requests: VecDeque<Request>,
45}
46
47/// Client with a queue of requests.
48///
49/// The client can be used with crates like [popol](https://crates.io/crates/popol) or
50/// with [mio](https://crates.io/crates/mio) if feature `async-mio` is enabled.
51///
52/// When the output is ready, a next event can be sent.
53#[cfg(feature = "async-mio")]
54pub struct MioQueuedClient<S: Read + Write + MioSource + Source> {
55    client: MioClient<S>,
56    requests: VecDeque<Request>,
57}
58
59impl<S: Read + Write + Source> QueuedClient<S> {
60    /// New asynchronous client build on top of a synchronous client.
61    pub fn new(client: Client<S>) -> Self {
62        Self {
63            client,
64            requests: VecDeque::with_capacity(INITIAL_REQUEST_QUEUE_CAPACITY),
65        }
66    }
67
68    /// Push a new request in the queue.
69    pub fn push(&mut self, request: Request) {
70        self.requests.push_back(request);
71    }
72
73    /// Pop the last request in the queue.
74    pub fn pop(&mut self) -> Option<Request> {
75        self.requests.pop_back()
76    }
77
78    /// Last request in the queue.
79    pub fn last(&self) -> Option<&Request> {
80        self.requests.back()
81    }
82
83    /// Return true if there is a pending request.
84    pub fn has_next(&self) -> bool {
85        !self.requests.is_empty()
86    }
87
88    /// Write one pending request if any.
89    ///
90    /// Instance of `mio::Poll` generates a writable event only once until the socket returns `WouldBlock`.
91    /// This error is mapped to `ClientError::NotReady`.
92    pub fn send_next(&mut self) -> ClientResult<bool> {
93        if let Some(request) = self.requests.pop_front() {
94            self.client.send(request)?;
95            Ok(true)
96        } else {
97            Ok(false)
98        }
99    }
100
101    /// Receive one response.
102    ///
103    /// Must be called each time a readable event is returned by `mio::Poll`.
104    pub fn receive_next(&mut self) -> ClientResult<Response> {
105        self.client.receive()
106    }
107}
108#[cfg(feature = "async-mio")]
109impl<S: Read + Write + MioSource + Source> MioQueuedClient<S> {
110    /// New asynchronous client build on top of a synchronous client.
111    pub fn new(client: MioClient<S>) -> Self {
112        Self {
113            client,
114            requests: VecDeque::with_capacity(INITIAL_REQUEST_QUEUE_CAPACITY),
115        }
116    }
117
118    #[cfg(all(not(feature = "async-mio"), unix))]
119    /// Input source.
120    pub fn input_source(&self) -> &S {
121        self.client.input_source()
122    }
123
124    #[cfg(all(not(feature = "async-mio"), unix))]
125    /// Output source.
126    pub fn output_source(&self) -> &S {
127        self.client.output_source()
128    }
129
130    #[cfg(feature = "async-mio")]
131    /// Register client
132    pub fn register(
133        &mut self,
134        poll: &mio::Poll,
135        input_token: mio::Token,
136        output_token: mio::Token,
137    ) -> std::io::Result<()> {
138        self.client.register(poll, input_token, output_token)
139    }
140
141    /// Push a new request in the queue.
142    pub fn push(&mut self, request: Request) {
143        self.requests.push_back(request);
144    }
145
146    /// Pop the last request in the queue.
147    pub fn pop(&mut self) -> Option<Request> {
148        self.requests.pop_back()
149    }
150
151    /// Last request in the queue.
152    pub fn last(&self) -> Option<&Request> {
153        self.requests.back()
154    }
155
156    /// Return true if there is a pending request.
157    pub fn has_next(&self) -> bool {
158        !self.requests.is_empty()
159    }
160
161    /// Write one pending request if any.
162    ///
163    /// Instance of `mio::Poll` generates a writable event only once until the socket returns `WouldBlock`.
164    /// This error is mapped to `ClientError::NotReady`.
165    pub fn send_next(&mut self) -> ClientResult<bool> {
166        if let Some(request) = self.requests.pop_front() {
167            self.client.send(request)?;
168            Ok(true)
169        } else {
170            Ok(false)
171        }
172    }
173
174    /// Receive one response.
175    ///
176    /// Must be called each time a readable event is returned by `mio::Poll`.
177    pub fn receive_next(&mut self) -> ClientResult<Response> {
178        self.client.receive()
179    }
180}