1use super::protocol::{self, Server};
12use std::io::{BufRead, Read, Write};
13
14pub enum Incoming {
17 Message(String),
18 Unreadable(&'static str),
19}
20
21pub trait Transport {
23 fn receive(&mut self) -> Result<Option<Incoming>, String>;
25 fn send(&mut self, message: &str) -> Result<(), String>;
27}
28
29pub fn serve(server: &mut Server, transport: &mut dyn Transport) -> Result<(), String> {
32 while let Some(incoming) = transport.receive()? {
33 let answer = match incoming {
34 Incoming::Message(message) if message.trim().is_empty() => continue,
35 Incoming::Message(message) => server.handle(&message),
36 Incoming::Unreadable(why) => Some(protocol::unreadable(why)),
37 };
38 if let Some(answer) = answer {
39 transport.send(&answer)?;
40 }
41 }
42 Ok(())
43}
44
45const LONGEST_LINE: usize = 8 << 20;
48
49pub struct Stdio {
51 input: std::io::StdinLock<'static>,
52 output: std::io::Stdout,
53}
54
55impl Stdio {
56 pub fn new() -> Stdio {
57 Stdio { input: std::io::stdin().lock(), output: std::io::stdout() }
58 }
59}
60
61impl Transport for Stdio {
62 fn receive(&mut self) -> Result<Option<Incoming>, String> {
63 read_message(&mut self.input, LONGEST_LINE)
64 }
65
66 fn send(&mut self, message: &str) -> Result<(), String> {
67 let mut out = self.output.lock();
69 writeln!(out, "{message}").and_then(|()| out.flush()).map_err(|e| format!("standard output: {e}"))
70 }
71}
72
73fn read_message(input: &mut impl BufRead, longest: usize) -> Result<Option<Incoming>, String> {
75 let fail = |e: std::io::Error| format!("standard input: {e}");
76 let mut line = Vec::new();
77 let read = (&mut *input).take(longest as u64 + 1).read_until(b'\n', &mut line).map_err(fail)?;
78 if read == 0 {
79 return Ok(None);
80 }
81 if line.len() > longest && line.last() != Some(&b'\n') {
82 loop {
84 let buffer = input.fill_buf().map_err(fail)?;
85 if buffer.is_empty() {
86 break;
87 }
88 match buffer.iter().position(|&b| b == b'\n') {
89 Some(at) => {
90 input.consume(at + 1);
91 break;
92 }
93 None => {
94 let length = buffer.len();
95 input.consume(length);
96 }
97 }
98 }
99 return Ok(Some(Incoming::Unreadable("A message is one line of at most 8 MiB.")));
100 }
101 while matches!(line.last(), Some(b'\n' | b'\r')) {
102 line.pop();
103 }
104 Ok(Some(match String::from_utf8(line) {
105 Ok(text) => Incoming::Message(text),
106 Err(_) => Incoming::Unreadable("A message is UTF-8 text."),
107 }))
108}
109
110#[cfg(test)]
112pub struct Script {
113 pub incoming: std::collections::VecDeque<String>,
114 pub outgoing: Vec<String>,
115}
116
117#[cfg(test)]
118impl Transport for Script {
119 fn receive(&mut self) -> Result<Option<Incoming>, String> {
120 Ok(self.incoming.pop_front().map(Incoming::Message))
121 }
122
123 fn send(&mut self, message: &str) -> Result<(), String> {
124 self.outgoing.push(message.to_string());
125 Ok(())
126 }
127}
128
129#[cfg(test)]
131pub struct Bytes<'a> {
132 pub input: &'a [u8],
133 pub longest: usize,
134 pub outgoing: Vec<String>,
135}
136
137#[cfg(test)]
138impl Transport for Bytes<'_> {
139 fn receive(&mut self) -> Result<Option<Incoming>, String> {
140 read_message(&mut self.input, self.longest)
141 }
142
143 fn send(&mut self, message: &str) -> Result<(), String> {
144 self.outgoing.push(message.to_string());
145 Ok(())
146 }
147}