1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
//! Utilities for I/O shared by the client and server
use std::io::{Read, Write, BufReader, BufRead};
use serde::Serialize;
use serde::de::DeserializeOwned;
use serde_json::error::Category;
use serde_json;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
pub struct Disconnected;
/// Continuously read from something that implements Read
/// For each line of input, try to read that line and serialize
/// it from JSON. Pass the result into a function.
///
/// If that function returns `Disconnected`, break the loop. Otherwise continue to read until EOF.
pub fn read_forever<R: Read, T: DeserializeOwned, F: FnMut(T) -> Result<(), Disconnected>>(
reader: R,
unable_to_read_bytes: &'static str,
failed_to_read_result: &'static str,
mut handler: F,
) {
let mut reader = BufReader::new(reader);
loop {
let mut buffer = String::new();
let read_bytes = reader.read_line(&mut buffer)
.expect(unable_to_read_bytes);
if read_bytes == 0 {
// Reached EOF, renderer process must have quit
break;
}
let result = serde_json::from_str(&buffer).map_err(|err| match err.classify() {
// In addition to cases where the JSON formatting is incorrect for some reason, this
// panic will occur if you use `println!` from inside the renderer process. This is
// because anything sent to stdout from within the renderer process is parsed as JSON.
// To avoid that and still be able to debug, switch to using the `eprintln!` macro
// instead. That macro will write to stderr and you will be able to continue as normal.
Category::Io | Category::Syntax | Category::Data => panic!(failed_to_read_result),
Category::Eof => Disconnected,
}).and_then(|result| handler(result));
if result.is_err() {
break;
}
}
}
/// Writes a message to given Write stream.
pub fn send<W: Write, T: Serialize>(
mut writer: W,
message: &T,
unable_to_write_newline: &str,
) -> Result<(), Disconnected> {
serde_json::to_writer(&mut writer, message).map_err(|err| match err.classify() {
Category::Io | Category::Eof => Disconnected,
// The other cases for err all have to do with input, so those should never occur
Category::Syntax | Category::Data => {
unreachable!("bug: got an input error when writing output")
},
}).map(|_| writeln!(writer).expect(unable_to_write_newline))
}