##// END OF EJS Templates
rust-index: handle `MixedIndex` in `pyindex_to_graph`...
rust-index: handle `MixedIndex` in `pyindex_to_graph` On the long run we will want to implement the Graph trait directly in Rust, but for now we take the path with the least amount of change to focus on the coming persistent NodeMap code. We test this new code through with the lazy ancestors code. Differential Revision: https://phab.mercurial-scm.org/D7657

File last commit:

r44270:ce088b38 default
r44463:c627f1b2 default
Show More
message.rs
133 lines | 3.8 KiB | application/rls-services+xml | RustLexer
Yuya Nishihara
rust-chg: add parser for request messages sent to "S" channel...
r40007 // Copyright 2018 Yuya Nishihara <yuya@tcha.org>
//
// This software may be used and distributed according to the terms of the
// GNU General Public License version 2 or any later version.
//! Utility for parsing and building command-server messages.
use bytes::Bytes;
use std::error;
use std::ffi::{OsStr, OsString};
use std::io;
use std::os::unix::ffi::OsStrExt;
Gregory Szorc
rust: run rustfmt...
r44270 pub use tokio_hglib::message::*; // re-exports
Yuya Nishihara
rust-chg: add parser for request messages sent to "S" channel...
r40007
/// Shell command type requested by the server.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum CommandType {
/// Pager should be spawned.
Pager,
/// Shell command should be executed to send back the result code.
System,
}
/// Shell command requested by the server.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct CommandSpec {
pub command: OsString,
pub current_dir: OsString,
pub envs: Vec<(OsString, OsString)>,
}
/// Parses "S" channel request into command type and spec.
pub fn parse_command_spec(data: Bytes) -> io::Result<(CommandType, CommandSpec)> {
let mut split = data.split(|&c| c == b'\0');
let ctype = parse_command_type(split.next().ok_or(new_parse_error("missing type"))?)?;
let command = split.next().ok_or(new_parse_error("missing command"))?;
let current_dir = split.next().ok_or(new_parse_error("missing current dir"))?;
let mut envs = Vec::new();
for l in split {
let mut s = l.splitn(2, |&c| c == b'=');
let k = s.next().unwrap();
let v = s.next().ok_or(new_parse_error("malformed env"))?;
Gregory Szorc
rust: run rustfmt...
r44270 envs.push((
OsStr::from_bytes(k).to_owned(),
OsStr::from_bytes(v).to_owned(),
));
Yuya Nishihara
rust-chg: add parser for request messages sent to "S" channel...
r40007 }
let spec = CommandSpec {
command: OsStr::from_bytes(command).to_owned(),
current_dir: OsStr::from_bytes(current_dir).to_owned(),
envs: envs,
};
Ok((ctype, spec))
}
fn parse_command_type(value: &[u8]) -> io::Result<CommandType> {
match value {
b"pager" => Ok(CommandType::Pager),
b"system" => Ok(CommandType::System),
Gregory Szorc
rust: run rustfmt...
r44270 _ => Err(new_parse_error(format!(
"unknown command type: {}",
decode_latin1(value)
))),
Yuya Nishihara
rust-chg: add parser for request messages sent to "S" channel...
r40007 }
}
fn decode_latin1<S>(s: S) -> String
Gregory Szorc
rust: run rustfmt...
r44270 where
S: AsRef<[u8]>,
Yuya Nishihara
rust-chg: add parser for request messages sent to "S" channel...
r40007 {
s.as_ref().iter().map(|&c| c as char).collect()
}
fn new_parse_error<E>(error: E) -> io::Error
Gregory Szorc
rust: run rustfmt...
r44270 where
E: Into<Box<error::Error + Send + Sync>>,
Yuya Nishihara
rust-chg: add parser for request messages sent to "S" channel...
r40007 {
io::Error::new(io::ErrorKind::InvalidData, error)
}
#[cfg(test)]
mod tests {
Gregory Szorc
rust: run rustfmt...
r44270 use super::*;
Yuya Nishihara
rust-chg: add parser for request messages sent to "S" channel...
r40007 use std::os::unix::ffi::OsStringExt;
#[test]
fn parse_command_spec_good() {
Gregory Szorc
rust: run rustfmt...
r44270 let src = [
b"pager".as_ref(),
b"less -FRX".as_ref(),
b"/tmp".as_ref(),
b"LANG=C".as_ref(),
b"HGPLAIN=".as_ref(),
]
.join(&0);
Yuya Nishihara
rust-chg: add parser for request messages sent to "S" channel...
r40007 let spec = CommandSpec {
command: os_string_from(b"less -FRX"),
current_dir: os_string_from(b"/tmp"),
Gregory Szorc
rust: run rustfmt...
r44270 envs: vec![
(os_string_from(b"LANG"), os_string_from(b"C")),
(os_string_from(b"HGPLAIN"), os_string_from(b"")),
],
Yuya Nishihara
rust-chg: add parser for request messages sent to "S" channel...
r40007 };
Gregory Szorc
rust: run rustfmt...
r44270 assert_eq!(
parse_command_spec(Bytes::from(src)).unwrap(),
(CommandType::Pager, spec)
);
Yuya Nishihara
rust-chg: add parser for request messages sent to "S" channel...
r40007 }
#[test]
fn parse_command_spec_too_short() {
assert!(parse_command_spec(Bytes::from_static(b"")).is_err());
assert!(parse_command_spec(Bytes::from_static(b"pager")).is_err());
assert!(parse_command_spec(Bytes::from_static(b"pager\0less")).is_err());
}
#[test]
fn parse_command_spec_malformed_env() {
assert!(parse_command_spec(Bytes::from_static(b"pager\0less\0/tmp\0HOME")).is_err());
}
#[test]
fn parse_command_spec_unknown_type() {
assert!(parse_command_spec(Bytes::from_static(b"paper\0less")).is_err());
}
fn os_string_from(s: &[u8]) -> OsString {
OsString::from_vec(s.to_vec())
}
}