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}