webext/lib.rs
1//! A library to make native messaging even easier than it already is.
2//!
3//! Typically you'd use this in a loop, reading a message in and writing a
4//! message out until there are none left to read. Perhaps something like this:
5//!
6//! ```rust,no_run
7//! # extern crate webext;
8//! # #[macro_use]
9//! # extern crate serde_derive;
10//! # fn main() {
11//! #
12//! #[derive(Deserialize)]
13//! struct Input { n: usize }
14//!
15//! #[derive(Serialize)]
16//! struct Output { n: usize }
17//!
18//! // An extension that just adds one to the input number `n`.
19//!
20//! while let Some(msg) = webext::read::<Input>() {
21//! let inp = msg.unwrap();
22//! let out = Output { n: inp.n + 1 };
23//! webext::write(&out).unwrap();
24//! }
25//! #
26//! # }
27//! ```
28//!
29//! # Serde
30//!
31//! I strongly recommend that you use this with `serde_derive` so that you can
32//! use your own structs for input and output. Alternatively, you can use the
33//! `Json` type, but that's a lot more annoying to deal with. My favorite enum
34//! attributes are `#[serde(tag = "type", rename_all = "snake_case")]`.
35
36extern crate byteorder;
37extern crate serde;
38extern crate serde_json as json;
39
40use byteorder::{NativeEndian, ReadBytesExt, WriteBytesExt};
41use serde::{Deserialize, Serialize};
42use std::io::{self, Read, Write};
43use io::ErrorKind::{BrokenPipe, UnexpectedEof};
44
45/// A type that can encode to and decode from any JSON string.
46pub type Json = json::Value;
47
48/// Read a message from standard input.
49pub fn read<D: for<'a> Deserialize<'a>>() -> Option<io::Result<D>> {
50 let stdin = io::stdin();
51 let mut stdin = stdin.lock();
52
53 let len = match stdin.read_u32::<NativeEndian>() {
54 Ok(len) => len,
55 Err(e) => return
56 if e.kind() == BrokenPipe || e.kind() == UnexpectedEof { None }
57 else { Some(Err(e.into())) },
58 };
59
60 Some(json::from_reader((&mut stdin).take(len as _)).map_err(Into::into))
61}
62
63/// Write a message to standard output.
64pub fn write<S: Serialize>(msg: &S) -> io::Result<()> {
65 let stdout = io::stdout();
66 let mut stdout = stdout.lock();
67 let msg = json::to_vec(msg)?;
68 stdout.write_u32::<NativeEndian>(msg.len() as _)?;
69 stdout.write_all(&msg)?;
70 Ok(())
71}