ssip_client/
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, Request, Response, 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    #[derive(Debug)]
25    pub struct Poll {}
26
27    /// Source identifier.
28    ///
29    /// See [`mio::Token`](https://docs.rs/mio/latest/mio/struct.Token.html#).
30    #[derive(Debug)]
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.
42#[derive(Debug)]
43pub struct QueuedClient<S: Read + Write + Source> {
44    client: Client<S>,
45    requests: VecDeque<Request>,
46}
47
48impl<S: Read + Write + Source> QueuedClient<S> {
49    /// New asynchronous client build on top of a synchronous client.
50    pub fn new(client: Client<S>) -> Self {
51        Self {
52            client,
53            requests: VecDeque::with_capacity(INITIAL_REQUEST_QUEUE_CAPACITY),
54        }
55    }
56
57    #[cfg(all(not(feature = "async-mio"), unix))]
58    /// Input source.
59    pub fn input_source(&self) -> &S {
60        self.client.input_source()
61    }
62
63    #[cfg(all(not(feature = "async-mio"), unix))]
64    /// Output source.
65    pub fn output_source(&self) -> &S {
66        self.client.output_source()
67    }
68
69    #[cfg(any(feature = "async-mio", doc))]
70    /// Register client
71    pub fn register(
72        &mut self,
73        poll: &mio::Poll,
74        input_token: mio::Token,
75        output_token: mio::Token,
76    ) -> std::io::Result<()> {
77        self.client.register(poll, input_token, output_token)
78    }
79
80    /// Push a new request in the queue.
81    pub fn push(&mut self, request: Request) {
82        self.requests.push_back(request);
83    }
84
85    /// Pop the last request in the queue.
86    pub fn pop(&mut self) -> Option<Request> {
87        self.requests.pop_back()
88    }
89
90    /// Return true if there is a pending request.
91    pub fn has_next(&self) -> bool {
92        !self.requests.is_empty()
93    }
94
95    /// Return true if there is a pending request to send data.
96    ///
97    /// After a `Speak` has been sent, when the client receives `OK_RECEIVING_DATA`, the
98    /// next command must be `Request::SendLine` or `Request::SendLines`.
99    pub fn has_data_next(&self) -> bool {
100        match self.next() {
101            Some(request) => request.is_data(),
102            None => false,
103        }
104    }
105
106    /// Next request in the queue.
107    pub fn next(&self) -> Option<&Request> {
108        self.requests.front()
109    }
110
111    /// Last request in the queue.
112    pub fn last(&self) -> Option<&Request> {
113        self.requests.back()
114    }
115
116    /// Write one pending request if any.
117    ///
118    /// Instance of `mio::Poll` generates a writable event only once until the socket returns `WouldBlock`.
119    /// This error is mapped to `ClientError::NotReady`.
120    pub fn send_next(&mut self) -> ClientResult<bool> {
121        if let Some(request) = self.requests.pop_front() {
122            self.client.send(request)?;
123            Ok(true)
124        } else {
125            Ok(false)
126        }
127    }
128
129    /// Receive one response.
130    ///
131    /// Must be called each time a readable event is returned by `mio::Poll`.
132    pub fn receive_next(&mut self) -> ClientResult<Response> {
133        self.client.receive()
134    }
135}