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
13use crate::{
14 client::{Client, Source},
15 types::*,
16};
17
18// Hack to generate the doc. There must be a better way.
19#[cfg(all(not(feature = "async-mio"), doc))]
20mod mio {
21 /// Polls for readiness events on all registered values.
22 ///
23 /// See [`mio::Poll`](https://docs.rs/mio/latest/mio/struct.Poll.html#)
24 pub struct Poll {}
25
26 /// Source identifier.
27 ///
28 /// See [`mio::Token`](https://docs.rs/mio/latest/mio/struct.Token.html#).
29 pub struct Token(pub usize);
30}
31
32const INITIAL_REQUEST_QUEUE_CAPACITY: usize = 4;
33
34/// Client with a queue of requests.
35///
36/// The client can be used with crates like [popol](https://crates.io/crates/popol) or
37/// with [mio](https://crates.io/crates/mio) if feature `async-mio` is enabled.
38///
39/// When the output is ready, a next event can be sent.
40pub struct QueuedClient<S: Read + Write + Source> {
41 client: Client<S>,
42 requests: VecDeque<Request>,
43}
44
45impl<S: Read + Write + Source> QueuedClient<S> {
46 /// New asynchronous client build on top of a synchronous client.
47 pub fn new(client: Client<S>) -> Self {
48 Self {
49 client,
50 requests: VecDeque::with_capacity(INITIAL_REQUEST_QUEUE_CAPACITY),
51 }
52 }
53
54 #[cfg(all(not(feature = "async-mio"), unix))]
55 /// Input source.
56 pub fn input_source(&self) -> &S {
57 self.client.input_source()
58 }
59
60 #[cfg(all(not(feature = "async-mio"), unix))]
61 /// Output source.
62 pub fn output_source(&self) -> &S {
63 self.client.output_source()
64 }
65
66 #[cfg(any(feature = "async-mio", doc))]
67 /// Register client
68 pub fn register(
69 &mut self,
70 poll: &mio::Poll,
71 input_token: mio::Token,
72 output_token: mio::Token,
73 ) -> std::io::Result<()> {
74 self.client.register(poll, input_token, output_token)
75 }
76
77 /// Push a new request in the queue.
78 pub fn push(&mut self, request: Request) {
79 self.requests.push_back(request);
80 }
81
82 /// Pop the last request in the queue.
83 pub fn pop(&mut self) -> Option<Request> {
84 self.requests.pop_back()
85 }
86
87 /// Last request in the queue.
88 pub fn last(&self) -> Option<&Request> {
89 self.requests.back()
90 }
91
92 /// Return true if there is a pending request.
93 pub fn has_next(&self) -> bool {
94 !self.requests.is_empty()
95 }
96
97 /// Write one pending request if any.
98 ///
99 /// Instance of `mio::Poll` generates a writable event only once until the socket returns `WouldBlock`.
100 /// This error is mapped to `ClientError::NotReady`.
101 pub fn send_next(&mut self) -> ClientResult<bool> {
102 if let Some(request) = self.requests.pop_front() {
103 self.client.send(request)?;
104 Ok(true)
105 } else {
106 Ok(false)
107 }
108 }
109
110 /// Receive one response.
111 ///
112 /// Must be called each time a readable event is returned by `mio::Poll`.
113 pub fn receive_next(&mut self) -> ClientResult<Response> {
114 self.client.receive()
115 }
116}