style(rust): Format all Rust code with rustfmt
Change-Id: Iab7e00cc26a4f9727d3ab98691ef379921a33052 Reviewed-on: https://cl.tvl.fyi/c/depot/+/5240 Tested-by: BuildkiteCI Reviewed-by: kanepyork <rikingcoding@gmail.com> Reviewed-by: Profpatsch <mail@profpatsch.de> Reviewed-by: grfn <grfn@gws.fyi> Reviewed-by: tazjin <tazjin@tvl.su>
This commit is contained in:
parent
3318982f81
commit
3d8ee62087
42 changed files with 1253 additions and 876 deletions
|
|
@ -1,13 +1,16 @@
|
|||
use std::os::unix::process::CommandExt;
|
||||
use std::ffi::OsStr;
|
||||
use std::os::unix::ffi::{OsStringExt, OsStrExt};
|
||||
use std::os::unix::ffi::{OsStrExt, OsStringExt};
|
||||
use std::os::unix::process::CommandExt;
|
||||
|
||||
pub fn no_args(current_prog_name: &str) -> () {
|
||||
let mut args = std::env::args_os();
|
||||
// remove argv[0]
|
||||
let _ = args.nth(0);
|
||||
if args.len() > 0 {
|
||||
die_user_error(current_prog_name, format!("Expected no arguments, got {:?}", args.collect::<Vec<_>>()))
|
||||
die_user_error(
|
||||
current_prog_name,
|
||||
format!("Expected no arguments, got {:?}", args.collect::<Vec<_>>()),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -16,31 +19,46 @@ pub fn args(current_prog_name: &str, no_of_positional_args: usize) -> Vec<Vec<u8
|
|||
// remove argv[0]
|
||||
let _ = args.nth(0);
|
||||
if args.len() != no_of_positional_args {
|
||||
die_user_error(current_prog_name, format!("Expected {} arguments, got {}, namely {:?}", no_of_positional_args, args.len(), args.collect::<Vec<_>>()))
|
||||
die_user_error(
|
||||
current_prog_name,
|
||||
format!(
|
||||
"Expected {} arguments, got {}, namely {:?}",
|
||||
no_of_positional_args,
|
||||
args.len(),
|
||||
args.collect::<Vec<_>>()
|
||||
),
|
||||
)
|
||||
}
|
||||
args.map(|arg| arg.into_vec()).collect()
|
||||
}
|
||||
|
||||
pub fn args_for_exec(current_prog_name: &str, no_of_positional_args: usize) -> (Vec<Vec<u8>>, Vec<Vec<u8>>) {
|
||||
pub fn args_for_exec(
|
||||
current_prog_name: &str,
|
||||
no_of_positional_args: usize,
|
||||
) -> (Vec<Vec<u8>>, Vec<Vec<u8>>) {
|
||||
let mut args = std::env::args_os();
|
||||
// remove argv[0]
|
||||
let _ = args.nth(0);
|
||||
let mut args = args.map(|arg| arg.into_vec());
|
||||
let mut pos_args = vec![];
|
||||
// get positional args
|
||||
for i in 1..no_of_positional_args+1 {
|
||||
pos_args.push(
|
||||
args.nth(0).expect(
|
||||
&format!("{}: expects {} positional args, only got {}", current_prog_name, no_of_positional_args, i))
|
||||
);
|
||||
for i in 1..no_of_positional_args + 1 {
|
||||
pos_args.push(args.nth(0).expect(&format!(
|
||||
"{}: expects {} positional args, only got {}",
|
||||
current_prog_name, no_of_positional_args, i
|
||||
)));
|
||||
}
|
||||
// prog... is the rest of the iterator
|
||||
let prog : Vec<Vec<u8>> = args.collect();
|
||||
let prog: Vec<Vec<u8>> = args.collect();
|
||||
(pos_args, prog)
|
||||
}
|
||||
|
||||
pub fn exec_into_args<'a, 'b, Args, Arg, Env, Key, Val>(current_prog_name: &str, args: Args, env_additions: Env) -> !
|
||||
where
|
||||
pub fn exec_into_args<'a, 'b, Args, Arg, Env, Key, Val>(
|
||||
current_prog_name: &str,
|
||||
args: Args,
|
||||
env_additions: Env,
|
||||
) -> !
|
||||
where
|
||||
Args: IntoIterator<Item = Arg>,
|
||||
Arg: AsRef<[u8]>,
|
||||
Env: IntoIterator<Item = (Key, Val)>,
|
||||
|
|
@ -50,27 +68,40 @@ pub fn exec_into_args<'a, 'b, Args, Arg, Env, Key, Val>(current_prog_name: &str,
|
|||
// TODO: is this possible without collecting into a Vec first, just leaving it an IntoIterator?
|
||||
let args = args.into_iter().collect::<Vec<Arg>>();
|
||||
let mut args = args.iter().map(|v| OsStr::from_bytes(v.as_ref()));
|
||||
let prog = args.nth(0).expect(&format!("{}: first argument must be an executable", current_prog_name));
|
||||
let prog = args.nth(0).expect(&format!(
|
||||
"{}: first argument must be an executable",
|
||||
current_prog_name
|
||||
));
|
||||
// TODO: same here
|
||||
let env = env_additions.into_iter().collect::<Vec<(Key, Val)>>();
|
||||
let env = env.iter().map(|(k,v)| (OsStr::from_bytes(k.as_ref()), OsStr::from_bytes(v.as_ref())));
|
||||
let env = env
|
||||
.iter()
|
||||
.map(|(k, v)| (OsStr::from_bytes(k.as_ref()), OsStr::from_bytes(v.as_ref())));
|
||||
let err = std::process::Command::new(prog).args(args).envs(env).exec();
|
||||
die_missing_executable(current_prog_name, format!("exec failed: {}, while trying to execing into {:?}", err, prog));
|
||||
die_missing_executable(
|
||||
current_prog_name,
|
||||
format!(
|
||||
"exec failed: {}, while trying to execing into {:?}",
|
||||
err, prog
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// Exit 1 to signify a generic expected error
|
||||
/// (e.g. something that sometimes just goes wrong, like a nix build).
|
||||
pub fn die_expected_error<S>(current_prog_name: &str, msg: S) -> !
|
||||
where S: AsRef<str>
|
||||
where
|
||||
S: AsRef<str>,
|
||||
{
|
||||
die_with(1, current_prog_name, msg)
|
||||
die_with(1, current_prog_name, msg)
|
||||
}
|
||||
|
||||
/// Exit 100 to signify a user error (“the user is holding it wrong”).
|
||||
/// This is a permanent error, if the program is executed the same way
|
||||
/// it should crash with 100 again.
|
||||
pub fn die_user_error<S>(current_prog_name: &str, msg: S) -> !
|
||||
where S: AsRef<str>
|
||||
where
|
||||
S: AsRef<str>,
|
||||
{
|
||||
die_with(100, current_prog_name, msg)
|
||||
}
|
||||
|
|
@ -78,14 +109,16 @@ where S: AsRef<str>
|
|||
/// Exit 101 to signify an unexpected crash (failing assertion or panic).
|
||||
/// This is the same exit code that `panic!()` emits.
|
||||
pub fn die_panic<S>(current_prog_name: &str, msg: S) -> !
|
||||
where S: AsRef<str>
|
||||
where
|
||||
S: AsRef<str>,
|
||||
{
|
||||
die_with(101, current_prog_name, msg)
|
||||
}
|
||||
|
||||
/// Exit 111 to signify a temporary error (such as resource exhaustion)
|
||||
pub fn die_temporary<S>(current_prog_name: &str, msg: S) -> !
|
||||
where S: AsRef<str>
|
||||
where
|
||||
S: AsRef<str>,
|
||||
{
|
||||
die_with(111, current_prog_name, msg)
|
||||
}
|
||||
|
|
@ -93,20 +126,23 @@ where S: AsRef<str>
|
|||
/// Exit 126 to signify an environment problem
|
||||
/// (the user has set up stuff incorrectly so the program cannot work)
|
||||
pub fn die_environment_problem<S>(current_prog_name: &str, msg: S) -> !
|
||||
where S: AsRef<str>
|
||||
where
|
||||
S: AsRef<str>,
|
||||
{
|
||||
die_with(126, current_prog_name, msg)
|
||||
}
|
||||
|
||||
/// Exit 127 to signify a missing executable.
|
||||
pub fn die_missing_executable<S>(current_prog_name: &str, msg: S) -> !
|
||||
where S: AsRef<str>
|
||||
where
|
||||
S: AsRef<str>,
|
||||
{
|
||||
die_with(127, current_prog_name, msg)
|
||||
}
|
||||
|
||||
fn die_with<S>(status: i32, current_prog_name: &str, msg: S) -> !
|
||||
where S: AsRef<str>
|
||||
where
|
||||
S: AsRef<str>,
|
||||
{
|
||||
eprintln!("{}: {}", current_prog_name, msg.as_ref());
|
||||
std::process::exit(status)
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ extern crate git2;
|
|||
use std::os::unix::ffi::OsStrExt;
|
||||
use std::path::PathBuf;
|
||||
|
||||
const DEFAULT_BRANCH : &str = "refs/heads/main";
|
||||
const DEFAULT_BRANCH: &str = "refs/heads/main";
|
||||
|
||||
fn main() {
|
||||
let git_db_dir = std::env::var_os("GIT_DB_DIR").expect("set GIT_DB_DIR");
|
||||
|
|
@ -16,8 +16,12 @@ fn main() {
|
|||
.bare(true)
|
||||
.mkpath(true)
|
||||
.description("git-db database")
|
||||
.initial_head(DEFAULT_BRANCH)
|
||||
).expect(&format!("unable to create or open bare git repo at {}", &git_db.display()));
|
||||
.initial_head(DEFAULT_BRANCH),
|
||||
)
|
||||
.expect(&format!(
|
||||
"unable to create or open bare git repo at {}",
|
||||
&git_db.display()
|
||||
));
|
||||
|
||||
let mut index = repo.index().expect("cannot get the git index file");
|
||||
eprintln!("{:#?}", index.version());
|
||||
|
|
@ -34,8 +38,9 @@ fn main() {
|
|||
|
||||
let data = "hi, it’s me".as_bytes();
|
||||
|
||||
index.add_frombuffer(
|
||||
&git2::IndexEntry {
|
||||
index
|
||||
.add_frombuffer(
|
||||
&git2::IndexEntry {
|
||||
mtime: now_git_time,
|
||||
ctime: now_git_time,
|
||||
// don’t make sense
|
||||
|
|
@ -50,25 +55,26 @@ fn main() {
|
|||
flags_extended: 0,
|
||||
path: "hi.txt".as_bytes().to_owned(),
|
||||
},
|
||||
data
|
||||
).expect("could not add data to index");
|
||||
data,
|
||||
)
|
||||
.expect("could not add data to index");
|
||||
|
||||
let oid = index.write_tree().expect("could not write index tree");
|
||||
|
||||
let to_add_tree = repo.find_tree(oid)
|
||||
let to_add_tree = repo
|
||||
.find_tree(oid)
|
||||
.expect("we just created this tree, where did it go?");
|
||||
|
||||
let parent_commits = match repo.find_reference(DEFAULT_BRANCH) {
|
||||
Ok(ref_) => vec![
|
||||
ref_
|
||||
.peel_to_commit()
|
||||
.expect(&format!("reference {} does not point to a commit", DEFAULT_BRANCH))
|
||||
],
|
||||
Ok(ref_) => vec![ref_.peel_to_commit().expect(&format!(
|
||||
"reference {} does not point to a commit",
|
||||
DEFAULT_BRANCH
|
||||
))],
|
||||
Err(err) => match err.code() {
|
||||
// no commit exists yet
|
||||
git2::ErrorCode::NotFound => vec![],
|
||||
_ => panic!("could not read latest commit from {}", DEFAULT_BRANCH),
|
||||
}
|
||||
},
|
||||
};
|
||||
repo.commit(
|
||||
Some(DEFAULT_BRANCH),
|
||||
|
|
@ -79,7 +85,6 @@ fn main() {
|
|||
I wonder if it supports extended commit descriptions?\n",
|
||||
&to_add_tree,
|
||||
&parent_commits.iter().collect::<Vec<_>>()[..],
|
||||
).expect("could not commit the index we just wrote");
|
||||
|
||||
|
||||
)
|
||||
.expect("could not commit the index we just wrote");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,16 +1,16 @@
|
|||
extern crate exec_helpers;
|
||||
// extern crate arglib_netencode;
|
||||
// extern crate netencode;
|
||||
extern crate imap;
|
||||
extern crate epoll;
|
||||
extern crate imap;
|
||||
|
||||
// use netencode::dec;
|
||||
use std::convert::TryFrom;
|
||||
use std::io::{Read, Write};
|
||||
use std::fs::File;
|
||||
use std::os::unix::io::{FromRawFd, AsRawFd, RawFd};
|
||||
use std::time::Duration;
|
||||
use imap::extensions::idle::SetReadTimeout;
|
||||
use std::convert::TryFrom;
|
||||
use std::fs::File;
|
||||
use std::io::{Read, Write};
|
||||
use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
|
||||
use std::time::Duration;
|
||||
|
||||
/// Implements an UCSPI client that wraps fd 6 & 7
|
||||
/// and implements Write and Read with a timeout.
|
||||
|
|
@ -33,7 +33,7 @@ impl UcspiClient {
|
|||
read: File::from_raw_fd(6),
|
||||
read_epoll_fd,
|
||||
read_timeout: None,
|
||||
write: File::from_raw_fd(7)
|
||||
write: File::from_raw_fd(7),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -54,21 +54,23 @@ impl SetReadTimeout for UcspiClient {
|
|||
impl Read for UcspiClient {
|
||||
// TODO: test the epoll code with a short timeout
|
||||
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
|
||||
const NO_DATA : u64 = 0;
|
||||
const NO_DATA: u64 = 0;
|
||||
// in order to implement the read_timeout,
|
||||
// we use epoll to wait for either data or time out
|
||||
epoll::ctl(
|
||||
self.read_epoll_fd,
|
||||
epoll::ControlOptions::EPOLL_CTL_ADD,
|
||||
self.read.as_raw_fd(),
|
||||
epoll::Event::new(epoll::Events::EPOLLIN, NO_DATA)
|
||||
epoll::Event::new(epoll::Events::EPOLLIN, NO_DATA),
|
||||
)?;
|
||||
let UNUSED = epoll::Event::new(epoll::Events::EPOLLIN, NO_DATA);
|
||||
let wait = epoll::wait(
|
||||
self.read_epoll_fd,
|
||||
match self.read_timeout {
|
||||
Some(duration) => i32::try_from(duration.as_millis()).expect("duration too big for epoll"),
|
||||
None => -1 // infinite
|
||||
Some(duration) => {
|
||||
i32::try_from(duration.as_millis()).expect("duration too big for epoll")
|
||||
}
|
||||
None => -1, // infinite
|
||||
},
|
||||
// event that was generated; but we don’t care
|
||||
&mut vec![UNUSED; 1][..],
|
||||
|
|
@ -79,11 +81,14 @@ impl Read for UcspiClient {
|
|||
self.read_epoll_fd,
|
||||
epoll::ControlOptions::EPOLL_CTL_DEL,
|
||||
self.read.as_raw_fd(),
|
||||
UNUSED
|
||||
UNUSED,
|
||||
)?;
|
||||
match wait {
|
||||
// timeout happened (0 events)
|
||||
Ok(0) => Err(std::io::Error::new(std::io::ErrorKind::TimedOut, "ucspi read timeout")),
|
||||
Ok(0) => Err(std::io::Error::new(
|
||||
std::io::ErrorKind::TimedOut,
|
||||
"ucspi read timeout",
|
||||
)),
|
||||
// its ready for reading, we can read
|
||||
Ok(_) => self.read.read(buf),
|
||||
// error
|
||||
|
|
@ -110,18 +115,21 @@ fn main() {
|
|||
let username = std::env::var("IMAP_USERNAME").expect("username");
|
||||
let password = std::env::var("IMAP_PASSWORD").expect("password");
|
||||
|
||||
let net = unsafe {
|
||||
UcspiClient::new_from_6_and_7().expect("no ucspi client for you")
|
||||
};
|
||||
let net = unsafe { UcspiClient::new_from_6_and_7().expect("no ucspi client for you") };
|
||||
let client = imap::Client::new(net);
|
||||
let mut session = client.login(username, password).map_err(|(err, _)| err).expect("unable to login");
|
||||
let mut session = client
|
||||
.login(username, password)
|
||||
.map_err(|(err, _)| err)
|
||||
.expect("unable to login");
|
||||
eprintln!("{:#?}", session);
|
||||
let list = session.list(None, Some("*"));
|
||||
eprintln!("{:#?}", list);
|
||||
let mailbox = session.examine("INBOX");
|
||||
eprintln!("{:#?}", mailbox);
|
||||
fn now() -> String {
|
||||
String::from_utf8_lossy(&std::process::Command::new("date").output().unwrap().stdout).trim_right().to_string()
|
||||
String::from_utf8_lossy(&std::process::Command::new("date").output().unwrap().stdout)
|
||||
.trim_right()
|
||||
.to_string()
|
||||
}
|
||||
loop {
|
||||
eprintln!("{}: idling on INBOX", now());
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
extern crate netencode;
|
||||
extern crate mustache;
|
||||
extern crate arglib_netencode;
|
||||
extern crate mustache;
|
||||
extern crate netencode;
|
||||
|
||||
use mustache::{Data};
|
||||
use netencode::{T};
|
||||
use mustache::Data;
|
||||
use netencode::T;
|
||||
use std::collections::HashMap;
|
||||
use std::os::unix::ffi::{OsStrExt};
|
||||
use std::io::{Read};
|
||||
use std::io::Read;
|
||||
use std::os::unix::ffi::OsStrExt;
|
||||
|
||||
fn netencode_to_mustache_data_dwim(t: T) -> Data {
|
||||
match t {
|
||||
|
|
@ -25,27 +25,26 @@ fn netencode_to_mustache_data_dwim(t: T) -> Data {
|
|||
T::Record(xs) => Data::Map(
|
||||
xs.into_iter()
|
||||
.map(|(key, val)| (key, netencode_to_mustache_data_dwim(val)))
|
||||
.collect::<HashMap<_,_>>()
|
||||
.collect::<HashMap<_, _>>(),
|
||||
),
|
||||
T::List(xs) => Data::Vec(
|
||||
xs.into_iter()
|
||||
.map(|x| netencode_to_mustache_data_dwim(x))
|
||||
.collect::<Vec<_>>()
|
||||
.collect::<Vec<_>>(),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_stdin() -> () {
|
||||
let data = netencode_to_mustache_data_dwim(
|
||||
arglib_netencode::arglib_netencode("netencode-mustache", Some(std::ffi::OsStr::new("TEMPLATE_DATA")))
|
||||
);
|
||||
let data = netencode_to_mustache_data_dwim(arglib_netencode::arglib_netencode(
|
||||
"netencode-mustache",
|
||||
Some(std::ffi::OsStr::new("TEMPLATE_DATA")),
|
||||
));
|
||||
let mut stdin = String::new();
|
||||
std::io::stdin().read_to_string(&mut stdin).unwrap();
|
||||
mustache::compile_str(&stdin)
|
||||
.and_then(|templ| templ.render_data(
|
||||
&mut std::io::stdout(),
|
||||
&data
|
||||
)).unwrap()
|
||||
.and_then(|templ| templ.render_data(&mut std::io::stdout(), &data))
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
extern crate nom;
|
||||
extern crate exec_helpers;
|
||||
extern crate nom;
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::io::{Write, Read};
|
||||
use std::fmt::{Display, Debug};
|
||||
use std::fmt::{Debug, Display};
|
||||
use std::io::{Read, Write};
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||
pub enum T {
|
||||
|
|
@ -46,22 +46,19 @@ impl T {
|
|||
T::I7(i) => U::I7(*i),
|
||||
T::Text(t) => U::Text(t.as_str()),
|
||||
T::Binary(v) => U::Binary(v),
|
||||
T::Sum(Tag { tag, val }) => U::Sum(
|
||||
Tag { tag: tag.as_str(), val: Box::new(val.to_u()) }
|
||||
),
|
||||
T::Record(map) => U::Record(
|
||||
map.iter().map(|(k, v)| (k.as_str(), v.to_u())).collect()
|
||||
),
|
||||
T::List(l) => U::List(
|
||||
l.iter().map(|v| v.to_u()).collect::<Vec<U<'a>>>()
|
||||
),
|
||||
T::Sum(Tag { tag, val }) => U::Sum(Tag {
|
||||
tag: tag.as_str(),
|
||||
val: Box::new(val.to_u()),
|
||||
}),
|
||||
T::Record(map) => U::Record(map.iter().map(|(k, v)| (k.as_str(), v.to_u())).collect()),
|
||||
T::List(l) => U::List(l.iter().map(|v| v.to_u()).collect::<Vec<U<'a>>>()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn encode<'a>(&'a self) -> Vec<u8> {
|
||||
match self {
|
||||
// TODO: don’t go via U, inefficient
|
||||
o => o.to_u().encode()
|
||||
o => o.to_u().encode(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -110,15 +107,16 @@ impl<'a> U<'a> {
|
|||
U::I7(i) => T::I7(*i),
|
||||
U::Text(t) => T::Text((*t).to_owned()),
|
||||
U::Binary(v) => T::Binary((*v).to_owned()),
|
||||
U::Sum(Tag { tag, val }) => T::Sum(
|
||||
Tag { tag: (*tag).to_owned(), val: Box::new(val.to_t()) }
|
||||
),
|
||||
U::Sum(Tag { tag, val }) => T::Sum(Tag {
|
||||
tag: (*tag).to_owned(),
|
||||
val: Box::new(val.to_t()),
|
||||
}),
|
||||
U::Record(map) => T::Record(
|
||||
map.iter().map(|(k, v)| ((*k).to_owned(), v.to_t())).collect::<HashMap<String, T>>()
|
||||
),
|
||||
U::List(l) => T::List(
|
||||
l.iter().map(|v| v.to_t()).collect::<Vec<T>>()
|
||||
map.iter()
|
||||
.map(|(k, v)| ((*k).to_owned(), v.to_t()))
|
||||
.collect::<HashMap<String, T>>(),
|
||||
),
|
||||
U::List(l) => T::List(l.iter().map(|v| v.to_t()).collect::<Vec<T>>()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -127,16 +125,18 @@ impl<'a> U<'a> {
|
|||
pub struct Tag<S, A> {
|
||||
// TODO: make into &str
|
||||
pub tag: S,
|
||||
pub val: Box<A>
|
||||
pub val: Box<A>,
|
||||
}
|
||||
|
||||
impl<S, A> Tag<S, A> {
|
||||
fn map<F, B>(self, f: F) -> Tag<S, B>
|
||||
where F: Fn(A) -> B {
|
||||
Tag {
|
||||
tag: self.tag,
|
||||
val: Box::new(f(*self.val))
|
||||
}
|
||||
where
|
||||
F: Fn(A) -> B,
|
||||
{
|
||||
Tag {
|
||||
tag: self.tag,
|
||||
val: Box::new(f(*self.val)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -147,45 +147,51 @@ fn encode_tag<W: Write>(w: &mut W, tag: &str, val: &U) -> std::io::Result<()> {
|
|||
}
|
||||
|
||||
pub fn encode<W: Write>(w: &mut W, u: &U) -> std::io::Result<()> {
|
||||
match u {
|
||||
U::Unit => write!(w, "u,"),
|
||||
U::N1(b) => if *b { write!(w, "n1:1,") } else { write!(w, "n1:0,") },
|
||||
U::N3(n) => write!(w, "n3:{},", n),
|
||||
U::N6(n) => write!(w, "n6:{},", n),
|
||||
U::N7(n) => write!(w, "n7:{},", n),
|
||||
U::I3(i) => write!(w, "i3:{},", i),
|
||||
U::I6(i) => write!(w, "i6:{},", i),
|
||||
U::I7(i) => write!(w, "i7:{},", i),
|
||||
U::Text(s) => {
|
||||
write!(w, "t{}:", s.len());
|
||||
w.write_all(s.as_bytes());
|
||||
write!(w, ",")
|
||||
}
|
||||
U::Binary(s) => {
|
||||
write!(w, "b{}:", s.len());
|
||||
w.write_all(&s);
|
||||
write!(w, ",")
|
||||
},
|
||||
U::Sum(Tag{tag, val}) => encode_tag(w, tag, val),
|
||||
U::Record(m) => {
|
||||
let mut c = std::io::Cursor::new(vec![]);
|
||||
for (k, v) in m {
|
||||
encode_tag(&mut c, k, v)?;
|
||||
}
|
||||
write!(w, "{{{}:", c.get_ref().len())?;
|
||||
w.write_all(c.get_ref())?;
|
||||
write!(w, "}}")
|
||||
},
|
||||
U::List(l) => {
|
||||
let mut c = std::io::Cursor::new(vec![]);
|
||||
for u in l {
|
||||
encode(&mut c, u)?;
|
||||
}
|
||||
write!(w, "[{}:", c.get_ref().len())?;
|
||||
w.write_all(c.get_ref())?;
|
||||
write!(w, "]")
|
||||
}
|
||||
}
|
||||
match u {
|
||||
U::Unit => write!(w, "u,"),
|
||||
U::N1(b) => {
|
||||
if *b {
|
||||
write!(w, "n1:1,")
|
||||
} else {
|
||||
write!(w, "n1:0,")
|
||||
}
|
||||
}
|
||||
U::N3(n) => write!(w, "n3:{},", n),
|
||||
U::N6(n) => write!(w, "n6:{},", n),
|
||||
U::N7(n) => write!(w, "n7:{},", n),
|
||||
U::I3(i) => write!(w, "i3:{},", i),
|
||||
U::I6(i) => write!(w, "i6:{},", i),
|
||||
U::I7(i) => write!(w, "i7:{},", i),
|
||||
U::Text(s) => {
|
||||
write!(w, "t{}:", s.len());
|
||||
w.write_all(s.as_bytes());
|
||||
write!(w, ",")
|
||||
}
|
||||
U::Binary(s) => {
|
||||
write!(w, "b{}:", s.len());
|
||||
w.write_all(&s);
|
||||
write!(w, ",")
|
||||
}
|
||||
U::Sum(Tag { tag, val }) => encode_tag(w, tag, val),
|
||||
U::Record(m) => {
|
||||
let mut c = std::io::Cursor::new(vec![]);
|
||||
for (k, v) in m {
|
||||
encode_tag(&mut c, k, v)?;
|
||||
}
|
||||
write!(w, "{{{}:", c.get_ref().len())?;
|
||||
w.write_all(c.get_ref())?;
|
||||
write!(w, "}}")
|
||||
}
|
||||
U::List(l) => {
|
||||
let mut c = std::io::Cursor::new(vec![]);
|
||||
for u in l {
|
||||
encode(&mut c, u)?;
|
||||
}
|
||||
write!(w, "[{}:", c.get_ref().len())?;
|
||||
w.write_all(c.get_ref())?;
|
||||
write!(w, "]")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn text(s: String) -> T {
|
||||
|
|
@ -197,27 +203,36 @@ pub fn u_from_stdin_or_die_user_error<'a>(prog_name: &'_ str, stdin_buf: &'a mut
|
|||
let u = match parse::u_u(stdin_buf) {
|
||||
Ok((rest, u)) => match rest {
|
||||
b"" => u,
|
||||
_ => exec_helpers::die_user_error(prog_name, format!("stdin contained some soup after netencode value: {:?}", String::from_utf8_lossy(rest)))
|
||||
_ => exec_helpers::die_user_error(
|
||||
prog_name,
|
||||
format!(
|
||||
"stdin contained some soup after netencode value: {:?}",
|
||||
String::from_utf8_lossy(rest)
|
||||
),
|
||||
),
|
||||
},
|
||||
Err(err) => exec_helpers::die_user_error(prog_name, format!("unable to parse netencode from stdin: {:?}", err))
|
||||
Err(err) => exec_helpers::die_user_error(
|
||||
prog_name,
|
||||
format!("unable to parse netencode from stdin: {:?}", err),
|
||||
),
|
||||
};
|
||||
u
|
||||
}
|
||||
|
||||
pub mod parse {
|
||||
use super::{T, Tag, U};
|
||||
use super::{Tag, T, U};
|
||||
|
||||
use std::str::FromStr;
|
||||
use std::ops::Neg;
|
||||
use std::collections::HashMap;
|
||||
use std::ops::Neg;
|
||||
use std::str::FromStr;
|
||||
|
||||
use nom::{IResult};
|
||||
use nom::branch::{alt};
|
||||
use nom::branch::alt;
|
||||
use nom::bytes::streaming::{tag, take};
|
||||
use nom::character::streaming::{digit1, char};
|
||||
use nom::sequence::{tuple};
|
||||
use nom::combinator::{map, map_res, flat_map, map_parser, opt};
|
||||
use nom::character::streaming::{char, digit1};
|
||||
use nom::combinator::{flat_map, map, map_parser, map_res, opt};
|
||||
use nom::error::{context, ErrorKind, ParseError};
|
||||
use nom::sequence::tuple;
|
||||
use nom::IResult;
|
||||
|
||||
fn unit_t(s: &[u8]) -> IResult<&[u8], ()> {
|
||||
let (s, _) = context("unit", tag("u,"))(s)?;
|
||||
|
|
@ -227,9 +242,9 @@ pub mod parse {
|
|||
fn usize_t(s: &[u8]) -> IResult<&[u8], usize> {
|
||||
context(
|
||||
"usize",
|
||||
map_res(
|
||||
map_res(digit1, |n| std::str::from_utf8(n)),
|
||||
|s| s.parse::<usize>())
|
||||
map_res(map_res(digit1, |n| std::str::from_utf8(n)), |s| {
|
||||
s.parse::<usize>()
|
||||
}),
|
||||
)(s)
|
||||
}
|
||||
|
||||
|
|
@ -238,87 +253,77 @@ pub mod parse {
|
|||
// This is the point where we check the descriminator;
|
||||
// if the beginning char does not match, we can immediately return.
|
||||
let (s, _) = char(begin)(s)?;
|
||||
let (s, (len, _)) = tuple((
|
||||
usize_t,
|
||||
char(':')
|
||||
))(s)?;
|
||||
let (s, (res, _)) = tuple((
|
||||
take(len),
|
||||
char(end)
|
||||
))(s)?;
|
||||
let (s, (len, _)) = tuple((usize_t, char(':')))(s)?;
|
||||
let (s, (res, _)) = tuple((take(len), char(end)))(s)?;
|
||||
Ok((s, res))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn uint_t<'a, I: FromStr + 'a>(t: &'static str) -> impl Fn(&'a [u8]) -> IResult<&'a [u8], I> {
|
||||
move |s: &'a [u8]| {
|
||||
let (s, (_, _, int, _)) = tuple((
|
||||
tag(t.as_bytes()),
|
||||
char(':'),
|
||||
map_res(
|
||||
map_res(digit1, |n: &[u8]| std::str::from_utf8(n)),
|
||||
|s| s.parse::<I>()
|
||||
),
|
||||
char(',')
|
||||
map_res(map_res(digit1, |n: &[u8]| std::str::from_utf8(n)), |s| {
|
||||
s.parse::<I>()
|
||||
}),
|
||||
char(','),
|
||||
))(s)?;
|
||||
Ok((s, int))
|
||||
}
|
||||
}
|
||||
|
||||
fn bool_t<'a>() -> impl Fn(&'a [u8]) -> IResult<&'a [u8], bool> {
|
||||
context("bool", alt((
|
||||
map(tag("n1:0,"), |_| false),
|
||||
map(tag("n1:1,"), |_| true),
|
||||
)))
|
||||
context(
|
||||
"bool",
|
||||
alt((map(tag("n1:0,"), |_| false), map(tag("n1:1,"), |_| true))),
|
||||
)
|
||||
}
|
||||
|
||||
fn int_t<'a, I: FromStr + Neg<Output=I>>(t: &'static str) -> impl Fn(&'a [u8]) -> IResult<&[u8], I> {
|
||||
context(
|
||||
t,
|
||||
move |s: &'a [u8]| {
|
||||
let (s, (_, _, neg, int, _)) = tuple((
|
||||
tag(t.as_bytes()),
|
||||
char(':'),
|
||||
opt(char('-')),
|
||||
map_res(
|
||||
map_res(digit1, |n: &[u8]| std::str::from_utf8(n)),
|
||||
|s| s.parse::<I>()
|
||||
),
|
||||
char(',')
|
||||
))(s)?;
|
||||
let res = match neg {
|
||||
Some(_) => -int,
|
||||
None => int,
|
||||
};
|
||||
Ok((s, res))
|
||||
}
|
||||
)
|
||||
fn int_t<'a, I: FromStr + Neg<Output = I>>(
|
||||
t: &'static str,
|
||||
) -> impl Fn(&'a [u8]) -> IResult<&[u8], I> {
|
||||
context(t, move |s: &'a [u8]| {
|
||||
let (s, (_, _, neg, int, _)) = tuple((
|
||||
tag(t.as_bytes()),
|
||||
char(':'),
|
||||
opt(char('-')),
|
||||
map_res(map_res(digit1, |n: &[u8]| std::str::from_utf8(n)), |s| {
|
||||
s.parse::<I>()
|
||||
}),
|
||||
char(','),
|
||||
))(s)?;
|
||||
let res = match neg {
|
||||
Some(_) => -int,
|
||||
None => int,
|
||||
};
|
||||
Ok((s, res))
|
||||
})
|
||||
}
|
||||
|
||||
fn tag_t(s: &[u8]) -> IResult<&[u8], Tag<String, T>> {
|
||||
// recurses into the main parser
|
||||
map(tag_g(t_t),
|
||||
|Tag {tag, val}|
|
||||
Tag {
|
||||
tag: tag.to_string(),
|
||||
val
|
||||
})(s)
|
||||
map(tag_g(t_t), |Tag { tag, val }| Tag {
|
||||
tag: tag.to_string(),
|
||||
val,
|
||||
})(s)
|
||||
}
|
||||
|
||||
fn tag_g<'a, P, O>(inner: P) -> impl Fn(&'a [u8]) -> IResult<&'a [u8], Tag<&'a str, O>>
|
||||
where
|
||||
P: Fn(&'a [u8]) -> IResult<&'a [u8], O>
|
||||
P: Fn(&'a [u8]) -> IResult<&'a [u8], O>,
|
||||
{
|
||||
move |s: &[u8]| {
|
||||
let (s, tag) = sized('<', '|')(s)?;
|
||||
let (s, val) = inner(s)?;
|
||||
Ok((s, Tag {
|
||||
tag: std::str::from_utf8(tag)
|
||||
.map_err(|_| nom::Err::Failure((s, ErrorKind::Char)))?,
|
||||
val: Box::new(val)
|
||||
}))
|
||||
|
||||
Ok((
|
||||
s,
|
||||
Tag {
|
||||
tag: std::str::from_utf8(tag)
|
||||
.map_err(|_| nom::Err::Failure((s, ErrorKind::Char)))?,
|
||||
val: Box::new(val),
|
||||
},
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -330,9 +335,9 @@ pub mod parse {
|
|||
|
||||
fn text_g(s: &[u8]) -> IResult<&[u8], &str> {
|
||||
let (s, res) = sized('t', ',')(s)?;
|
||||
Ok((s,
|
||||
std::str::from_utf8(res)
|
||||
.map_err(|_| nom::Err::Failure((s, ErrorKind::Char)))?,
|
||||
Ok((
|
||||
s,
|
||||
std::str::from_utf8(res).map_err(|_| nom::Err::Failure((s, ErrorKind::Char)))?,
|
||||
))
|
||||
}
|
||||
|
||||
|
|
@ -374,22 +379,24 @@ pub mod parse {
|
|||
{
|
||||
map_parser(
|
||||
sized('[', ']'),
|
||||
nom::multi::many0(inner_no_empty_string(inner))
|
||||
nom::multi::many0(inner_no_empty_string(inner)),
|
||||
)
|
||||
}
|
||||
|
||||
fn record_t<'a>(s: &'a [u8]) -> IResult<&'a [u8], HashMap<String, T>> {
|
||||
let (s, r) = record_g(t_t)(s)?;
|
||||
Ok((s,
|
||||
Ok((
|
||||
s,
|
||||
r.into_iter()
|
||||
.map(|(k, v)| (k.to_string(), v))
|
||||
.collect::<HashMap<_,_>>()))
|
||||
.map(|(k, v)| (k.to_string(), v))
|
||||
.collect::<HashMap<_, _>>(),
|
||||
))
|
||||
}
|
||||
|
||||
fn record_g<'a, P, O>(inner: P) -> impl Fn(&'a [u8]) -> IResult<&'a [u8], HashMap<&'a str, O>>
|
||||
where
|
||||
O: Clone,
|
||||
P: Fn(&'a [u8]) -> IResult<&'a [u8], O>
|
||||
P: Fn(&'a [u8]) -> IResult<&'a [u8], O>,
|
||||
{
|
||||
move |s: &'a [u8]| {
|
||||
let (s, map) = map_parser(
|
||||
|
|
@ -397,19 +404,19 @@ pub mod parse {
|
|||
nom::multi::fold_many0(
|
||||
inner_no_empty_string(tag_g(&inner)),
|
||||
HashMap::new(),
|
||||
|mut acc: HashMap<_,_>, Tag { tag, mut val }| {
|
||||
|mut acc: HashMap<_, _>, Tag { tag, mut val }| {
|
||||
// ignore duplicated tag names that appear later
|
||||
// according to netencode spec
|
||||
if ! acc.contains_key(tag) {
|
||||
if !acc.contains_key(tag) {
|
||||
acc.insert(tag, *val);
|
||||
}
|
||||
acc
|
||||
}
|
||||
)
|
||||
},
|
||||
),
|
||||
)(s)?;
|
||||
if map.is_empty() {
|
||||
// records must not be empty, according to the spec
|
||||
Err(nom::Err::Failure((s,nom::error::ErrorKind::Many1)))
|
||||
Err(nom::Err::Failure((s, nom::error::ErrorKind::Many1)))
|
||||
} else {
|
||||
Ok((s, map))
|
||||
}
|
||||
|
|
@ -424,7 +431,6 @@ pub mod parse {
|
|||
map(tag_g(u_u), |t| U::Sum(t)),
|
||||
map(list_g(u_u), U::List),
|
||||
map(record_g(u_u), U::Record),
|
||||
|
||||
map(bool_t(), |u| U::N1(u)),
|
||||
map(uint_t("n3"), |u| U::N3(u)),
|
||||
map(uint_t("n6"), |u| U::N6(u)),
|
||||
|
|
@ -432,7 +438,6 @@ pub mod parse {
|
|||
map(int_t("i3"), |u| U::I3(u)),
|
||||
map(int_t("i6"), |u| U::I6(u)),
|
||||
map(int_t("i7"), |u| U::I7(u)),
|
||||
|
||||
// less common
|
||||
map(uint_t("n2"), |u| U::N3(u)),
|
||||
map(uint_t("n4"), |u| U::N6(u)),
|
||||
|
|
@ -445,7 +450,7 @@ pub mod parse {
|
|||
))(s)
|
||||
}
|
||||
|
||||
pub fn t_t(s: &[u8]) -> IResult<&[u8], T> {
|
||||
pub fn t_t(s: &[u8]) -> IResult<&[u8], T> {
|
||||
alt((
|
||||
text,
|
||||
binary(),
|
||||
|
|
@ -453,7 +458,6 @@ pub mod parse {
|
|||
map(tag_t, |t| T::Sum(t)),
|
||||
map(list_t, |l| T::List(l)),
|
||||
map(record_t, |p| T::Record(p)),
|
||||
|
||||
map(bool_t(), |u| T::N1(u)),
|
||||
// 8, 64 and 128 bit
|
||||
map(uint_t("n3"), |u| T::N3(u)),
|
||||
|
|
@ -462,7 +466,6 @@ pub mod parse {
|
|||
map(int_t("i3"), |u| T::I3(u)),
|
||||
map(int_t("i6"), |u| T::I6(u)),
|
||||
map(int_t("i7"), |u| T::I7(u)),
|
||||
|
||||
// less common
|
||||
map(uint_t("n2"), |u| T::N3(u)),
|
||||
map(uint_t("n4"), |u| T::N6(u)),
|
||||
|
|
@ -481,30 +484,18 @@ pub mod parse {
|
|||
|
||||
#[test]
|
||||
fn test_parse_unit_t() {
|
||||
assert_eq!(
|
||||
unit_t("u,".as_bytes()),
|
||||
Ok(("".as_bytes(), ()))
|
||||
);
|
||||
assert_eq!(unit_t("u,".as_bytes()), Ok(("".as_bytes(), ())));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_bool_t() {
|
||||
assert_eq!(
|
||||
bool_t()("n1:0,".as_bytes()),
|
||||
Ok(("".as_bytes(), false))
|
||||
);
|
||||
assert_eq!(
|
||||
bool_t()("n1:1,".as_bytes()),
|
||||
Ok(("".as_bytes(), true))
|
||||
);
|
||||
assert_eq!(bool_t()("n1:0,".as_bytes()), Ok(("".as_bytes(), false)));
|
||||
assert_eq!(bool_t()("n1:1,".as_bytes()), Ok(("".as_bytes(), true)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_usize_t() {
|
||||
assert_eq!(
|
||||
usize_t("32foo".as_bytes()),
|
||||
Ok(("foo".as_bytes(), 32))
|
||||
);
|
||||
assert_eq!(usize_t("32foo".as_bytes()), Ok(("foo".as_bytes(), 32)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -515,7 +506,10 @@ pub mod parse {
|
|||
);
|
||||
assert_eq!(
|
||||
uint_t::<u8>("n3")("n3:1024,abc".as_bytes()),
|
||||
Err(nom::Err::Error(("1024,abc".as_bytes(), nom::error::ErrorKind::MapRes)))
|
||||
Err(nom::Err::Error((
|
||||
"1024,abc".as_bytes(),
|
||||
nom::error::ErrorKind::MapRes
|
||||
)))
|
||||
);
|
||||
assert_eq!(
|
||||
int_t::<i64>("i6")("i6:-23,abc".as_bytes()),
|
||||
|
|
@ -544,18 +538,21 @@ pub mod parse {
|
|||
assert_eq!(
|
||||
text("t5:hello,".as_bytes()),
|
||||
Ok(("".as_bytes(), T::Text("hello".to_owned()))),
|
||||
"{}", r"t5:hello,"
|
||||
"{}",
|
||||
r"t5:hello,"
|
||||
);
|
||||
assert_eq!(
|
||||
text("t4:fo".as_bytes()),
|
||||
// The content of the text should be 4 long
|
||||
Err(nom::Err::Incomplete(nom::Needed::Size(4))),
|
||||
"{}", r"t4:fo,"
|
||||
"{}",
|
||||
r"t4:fo,"
|
||||
);
|
||||
assert_eq!(
|
||||
text("t9:今日は,".as_bytes()),
|
||||
Ok(("".as_bytes(), T::Text("今日は".to_owned()))),
|
||||
"{}", r"t9:今日は,"
|
||||
"{}",
|
||||
r"t9:今日は,"
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -564,24 +561,28 @@ pub mod parse {
|
|||
assert_eq!(
|
||||
binary()("b5:hello,".as_bytes()),
|
||||
Ok(("".as_bytes(), T::Binary(Vec::from("hello".to_owned())))),
|
||||
"{}", r"b5:hello,"
|
||||
"{}",
|
||||
r"b5:hello,"
|
||||
);
|
||||
assert_eq!(
|
||||
binary()("b4:fo".as_bytes()),
|
||||
// The content of the byte should be 4 long
|
||||
Err(nom::Err::Incomplete(nom::Needed::Size(4))),
|
||||
"{}", r"b4:fo,"
|
||||
"{}",
|
||||
r"b4:fo,"
|
||||
);
|
||||
assert_eq!(
|
||||
binary()("b4:foob".as_bytes()),
|
||||
// The content is 4 bytes now, but the finishing , is missing
|
||||
Err(nom::Err::Incomplete(nom::Needed::Size(1))),
|
||||
"{}", r"b4:fo,"
|
||||
);
|
||||
"{}",
|
||||
r"b4:fo,"
|
||||
);
|
||||
assert_eq!(
|
||||
binary()("b9:今日は,".as_bytes()),
|
||||
Ok(("".as_bytes(), T::Binary(Vec::from("今日は".as_bytes())))),
|
||||
"{}", r"b9:今日は,"
|
||||
"{}",
|
||||
r"b9:今日は,"
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -590,25 +591,23 @@ pub mod parse {
|
|||
assert_eq!(
|
||||
list_t("[0:]".as_bytes()),
|
||||
Ok(("".as_bytes(), vec![])),
|
||||
"{}", r"[0:]"
|
||||
"{}",
|
||||
r"[0:]"
|
||||
);
|
||||
assert_eq!(
|
||||
list_t("[6:u,u,u,]".as_bytes()),
|
||||
Ok(("".as_bytes(), vec![
|
||||
T::Unit,
|
||||
T::Unit,
|
||||
T::Unit,
|
||||
])),
|
||||
"{}", r"[6:u,u,u,]"
|
||||
Ok(("".as_bytes(), vec![T::Unit, T::Unit, T::Unit,])),
|
||||
"{}",
|
||||
r"[6:u,u,u,]"
|
||||
);
|
||||
assert_eq!(
|
||||
list_t("[15:u,[7:t3:foo,]u,]".as_bytes()),
|
||||
Ok(("".as_bytes(), vec![
|
||||
T::Unit,
|
||||
T::List(vec![T::Text("foo".to_owned())]),
|
||||
T::Unit,
|
||||
])),
|
||||
"{}", r"[15:u,[7:t3:foo,]u,]"
|
||||
Ok((
|
||||
"".as_bytes(),
|
||||
vec![T::Unit, T::List(vec![T::Text("foo".to_owned())]), T::Unit,]
|
||||
)),
|
||||
"{}",
|
||||
r"[15:u,[7:t3:foo,]u,]"
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -616,27 +615,40 @@ pub mod parse {
|
|||
fn test_record() {
|
||||
assert_eq!(
|
||||
record_t("{21:<1:a|u,<1:b|u,<1:c|u,}".as_bytes()),
|
||||
Ok(("".as_bytes(), vec![
|
||||
("a".to_owned(), T::Unit),
|
||||
("b".to_owned(), T::Unit),
|
||||
("c".to_owned(), T::Unit),
|
||||
].into_iter().collect::<HashMap<String, T>>())),
|
||||
"{}", r"{21:<1:a|u,<1:b|u,<1:c|u,}"
|
||||
Ok((
|
||||
"".as_bytes(),
|
||||
vec![
|
||||
("a".to_owned(), T::Unit),
|
||||
("b".to_owned(), T::Unit),
|
||||
("c".to_owned(), T::Unit),
|
||||
]
|
||||
.into_iter()
|
||||
.collect::<HashMap<String, T>>()
|
||||
)),
|
||||
"{}",
|
||||
r"{21:<1:a|u,<1:b|u,<1:c|u,}"
|
||||
);
|
||||
// duplicated keys are ignored (first is taken)
|
||||
assert_eq!(
|
||||
record_t("{25:<1:a|u,<1:b|u,<1:a|i1:-1,}".as_bytes()),
|
||||
Ok(("".as_bytes(), vec![
|
||||
("a".to_owned(), T::Unit),
|
||||
("b".to_owned(), T::Unit),
|
||||
].into_iter().collect::<HashMap<_,_>>())),
|
||||
"{}", r"{25:<1:a|u,<1:b|u,<1:a|i1:-1,}"
|
||||
Ok((
|
||||
"".as_bytes(),
|
||||
vec![("a".to_owned(), T::Unit), ("b".to_owned(), T::Unit),]
|
||||
.into_iter()
|
||||
.collect::<HashMap<_, _>>()
|
||||
)),
|
||||
"{}",
|
||||
r"{25:<1:a|u,<1:b|u,<1:a|i1:-1,}"
|
||||
);
|
||||
// empty records are not allowed
|
||||
assert_eq!(
|
||||
record_t("{0:}".as_bytes()),
|
||||
Err(nom::Err::Failure(("".as_bytes(), nom::error::ErrorKind::Many1))),
|
||||
"{}", r"{0:}"
|
||||
Err(nom::Err::Failure((
|
||||
"".as_bytes(),
|
||||
nom::error::ErrorKind::Many1
|
||||
))),
|
||||
"{}",
|
||||
r"{0:}"
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -645,37 +657,62 @@ pub mod parse {
|
|||
assert_eq!(
|
||||
t_t("n3:255,".as_bytes()),
|
||||
Ok(("".as_bytes(), T::N3(255))),
|
||||
"{}", r"n3:255,"
|
||||
"{}",
|
||||
r"n3:255,"
|
||||
);
|
||||
assert_eq!(
|
||||
t_t("t6:halloo,".as_bytes()),
|
||||
Ok(("".as_bytes(), T::Text("halloo".to_owned()))),
|
||||
"{}", r"t6:halloo,"
|
||||
"{}",
|
||||
r"t6:halloo,"
|
||||
);
|
||||
assert_eq!(
|
||||
t_t("<3:foo|t6:halloo,".as_bytes()),
|
||||
Ok(("".as_bytes(), T::Sum (Tag {
|
||||
tag: "foo".to_owned(),
|
||||
val: Box::new(T::Text("halloo".to_owned()))
|
||||
}))),
|
||||
"{}", r"<3:foo|t6:halloo,"
|
||||
Ok((
|
||||
"".as_bytes(),
|
||||
T::Sum(Tag {
|
||||
tag: "foo".to_owned(),
|
||||
val: Box::new(T::Text("halloo".to_owned()))
|
||||
})
|
||||
)),
|
||||
"{}",
|
||||
r"<3:foo|t6:halloo,"
|
||||
);
|
||||
// { a: Unit
|
||||
// , foo: List <A: Unit | B: List i3> }
|
||||
assert_eq!(
|
||||
t_t("{52:<1:a|u,<3:foo|[33:<1:A|u,<1:A|n1:1,<1:B|[7:i3:127,]]}".as_bytes()),
|
||||
Ok(("".as_bytes(), T::Record(vec![
|
||||
("a".to_owned(), T::Unit),
|
||||
("foo".to_owned(), T::List(vec![
|
||||
T::Sum(Tag { tag: "A".to_owned(), val: Box::new(T::Unit) }),
|
||||
T::Sum(Tag { tag: "A".to_owned(), val: Box::new(T::N1(true)) }),
|
||||
T::Sum(Tag { tag: "B".to_owned(), val: Box::new(T::List(vec![T::I3(127)])) }),
|
||||
]))
|
||||
].into_iter().collect::<HashMap<String, T>>()))),
|
||||
"{}", r"{52:<1:a|u,<3:foo|[33:<1:A|u,<1:A|n1:1,<1:B|[7:i3:127,]]}"
|
||||
Ok((
|
||||
"".as_bytes(),
|
||||
T::Record(
|
||||
vec![
|
||||
("a".to_owned(), T::Unit),
|
||||
(
|
||||
"foo".to_owned(),
|
||||
T::List(vec![
|
||||
T::Sum(Tag {
|
||||
tag: "A".to_owned(),
|
||||
val: Box::new(T::Unit)
|
||||
}),
|
||||
T::Sum(Tag {
|
||||
tag: "A".to_owned(),
|
||||
val: Box::new(T::N1(true))
|
||||
}),
|
||||
T::Sum(Tag {
|
||||
tag: "B".to_owned(),
|
||||
val: Box::new(T::List(vec![T::I3(127)]))
|
||||
}),
|
||||
])
|
||||
)
|
||||
]
|
||||
.into_iter()
|
||||
.collect::<HashMap<String, T>>()
|
||||
)
|
||||
)),
|
||||
"{}",
|
||||
r"{52:<1:a|u,<3:foo|[33:<1:A|u,<1:A|n1:1,<1:B|[7:i3:127,]]}"
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -735,7 +772,10 @@ pub mod dec {
|
|||
fn dec(&self, u: U<'a>) -> Result<Self::A, DecodeError> {
|
||||
match u {
|
||||
U::Binary(b) => Ok(b),
|
||||
other => Err(DecodeError(format!("Cannot decode {:?} into Binary", other))),
|
||||
other => Err(DecodeError(format!(
|
||||
"Cannot decode {:?} into Binary",
|
||||
other
|
||||
))),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -766,16 +806,17 @@ pub mod dec {
|
|||
pub struct Record<T>(pub T);
|
||||
|
||||
impl<'a, Inner> Decoder<'a> for Record<Inner>
|
||||
where Inner: Decoder<'a>
|
||||
where
|
||||
Inner: Decoder<'a>,
|
||||
{
|
||||
type A = HashMap<&'a str, Inner::A>;
|
||||
fn dec(&self, u: U<'a>) -> Result<Self::A, DecodeError> {
|
||||
match u {
|
||||
U::Record(map) =>
|
||||
map.into_iter()
|
||||
U::Record(map) => map
|
||||
.into_iter()
|
||||
.map(|(k, v)| self.0.dec(v).map(|v2| (k, v2)))
|
||||
.collect::<Result<Self::A, _>>(),
|
||||
o => Err(DecodeError(format!("Cannot decode {:?} into record", o)))
|
||||
o => Err(DecodeError(format!("Cannot decode {:?} into record", o))),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -784,18 +825,22 @@ pub mod dec {
|
|||
#[derive(Clone, Copy)]
|
||||
pub struct RecordDot<'a, T> {
|
||||
pub field: &'a str,
|
||||
pub inner: T
|
||||
pub inner: T,
|
||||
}
|
||||
|
||||
impl <'a, Inner> Decoder<'a> for RecordDot<'_, Inner>
|
||||
where Inner: Decoder<'a> + Clone
|
||||
impl<'a, Inner> Decoder<'a> for RecordDot<'_, Inner>
|
||||
where
|
||||
Inner: Decoder<'a> + Clone,
|
||||
{
|
||||
type A = Inner::A;
|
||||
fn dec(&self, u: U<'a>) -> Result<Self::A, DecodeError> {
|
||||
match Record(self.inner.clone()).dec(u) {
|
||||
Ok(mut map) => match map.remove(self.field) {
|
||||
Some(inner) => Ok(inner),
|
||||
None => Err(DecodeError(format!("Cannot find `{}` in record map", self.field))),
|
||||
None => Err(DecodeError(format!(
|
||||
"Cannot find `{}` in record map",
|
||||
self.field
|
||||
))),
|
||||
},
|
||||
Err(err) => Err(err),
|
||||
}
|
||||
|
|
@ -804,23 +849,27 @@ pub mod dec {
|
|||
|
||||
/// Equals one of the listed `A`s exactly, after decoding.
|
||||
#[derive(Clone)]
|
||||
pub struct OneOf<T, A>{
|
||||
pub struct OneOf<T, A> {
|
||||
pub inner: T,
|
||||
pub list: Vec<A>,
|
||||
}
|
||||
|
||||
impl <'a, Inner> Decoder<'a> for OneOf<Inner, Inner::A>
|
||||
where Inner: Decoder<'a>,
|
||||
Inner::A: Display + Debug + PartialEq
|
||||
impl<'a, Inner> Decoder<'a> for OneOf<Inner, Inner::A>
|
||||
where
|
||||
Inner: Decoder<'a>,
|
||||
Inner::A: Display + Debug + PartialEq,
|
||||
{
|
||||
type A = Inner::A;
|
||||
fn dec(&self, u: U<'a>) -> Result<Self::A, DecodeError> {
|
||||
match self.inner.dec(u) {
|
||||
Ok(inner) => match self.list.iter().any(|x| x.eq(&inner)) {
|
||||
true => Ok(inner),
|
||||
false => Err(DecodeError(format!("{} is not one of {:?}", inner, self.list)))
|
||||
false => Err(DecodeError(format!(
|
||||
"{} is not one of {:?}",
|
||||
inner, self.list
|
||||
))),
|
||||
},
|
||||
Err(err) => Err(err)
|
||||
Err(err) => Err(err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -829,16 +878,16 @@ pub mod dec {
|
|||
#[derive(Clone)]
|
||||
pub struct Try<T>(pub T);
|
||||
|
||||
impl <'a, Inner> Decoder<'a> for Try<Inner>
|
||||
where Inner: Decoder<'a>
|
||||
impl<'a, Inner> Decoder<'a> for Try<Inner>
|
||||
where
|
||||
Inner: Decoder<'a>,
|
||||
{
|
||||
type A = Option<Inner::A>;
|
||||
fn dec(&self, u: U<'a>) -> Result<Self::A, DecodeError> {
|
||||
match self.0.dec(u) {
|
||||
Ok(inner) => Ok(Some(inner)),
|
||||
Err(err) => Ok(None)
|
||||
Err(err) => Ok(None),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
extern crate netencode;
|
||||
|
||||
use netencode::{U, T, Tag};
|
||||
use netencode::{Tag, T, U};
|
||||
|
||||
pub enum Pretty {
|
||||
Single {
|
||||
|
|
@ -20,7 +20,7 @@ pub enum Pretty {
|
|||
r#type: char,
|
||||
length: String,
|
||||
vals: Vec<Pretty>,
|
||||
trailer: char
|
||||
trailer: char,
|
||||
},
|
||||
}
|
||||
|
||||
|
|
@ -39,7 +39,7 @@ impl Pretty {
|
|||
r#type: 't',
|
||||
length: format!("{}:", s.len()),
|
||||
val: s.to_string(),
|
||||
trailer: ','
|
||||
trailer: ',',
|
||||
},
|
||||
U::Binary(s) => Pretty::Single {
|
||||
r#type: 'b',
|
||||
|
|
@ -47,15 +47,18 @@ impl Pretty {
|
|||
// For pretty printing we want the string to be visible obviously.
|
||||
// Instead of not supporting binary, let’s use lossy conversion.
|
||||
val: String::from_utf8_lossy(s).into_owned(),
|
||||
trailer: ','
|
||||
trailer: ',',
|
||||
},
|
||||
U::Sum(Tag{tag, val}) => Self::pretty_tag(tag, Self::from_u(*val)),
|
||||
U::Sum(Tag { tag, val }) => Self::pretty_tag(tag, Self::from_u(*val)),
|
||||
U::Record(m) => Pretty::Multi {
|
||||
r#type: '{',
|
||||
// TODO: we are losing the size here, should we recompute it? Keep it?
|
||||
length: String::from(""),
|
||||
vals: m.into_iter().map(|(k, v)| Self::pretty_tag(k, Self::from_u(v))).collect(),
|
||||
trailer: '}'
|
||||
vals: m
|
||||
.into_iter()
|
||||
.map(|(k, v)| Self::pretty_tag(k, Self::from_u(v)))
|
||||
.collect(),
|
||||
trailer: '}',
|
||||
},
|
||||
U::List(l) => Pretty::Multi {
|
||||
r#type: '[',
|
||||
|
|
@ -68,13 +71,14 @@ impl Pretty {
|
|||
}
|
||||
|
||||
fn scalar<D>(r#type: char, length: &str, d: D) -> Pretty
|
||||
where D: std::fmt::Display
|
||||
where
|
||||
D: std::fmt::Display,
|
||||
{
|
||||
Pretty::Single {
|
||||
r#type,
|
||||
length: length.to_string(),
|
||||
val: format!("{}", d),
|
||||
trailer: ','
|
||||
trailer: ',',
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -89,43 +93,62 @@ impl Pretty {
|
|||
}
|
||||
|
||||
pub fn print_multiline<W>(&self, mut w: &mut W) -> std::io::Result<()>
|
||||
where W: std::io::Write
|
||||
where
|
||||
W: std::io::Write,
|
||||
{
|
||||
Self::go(&mut w, self, 0, true);
|
||||
write!(w, "\n")
|
||||
}
|
||||
|
||||
fn go<W>(mut w: &mut W, p: &Pretty, depth: usize, is_newline: bool) -> std::io::Result<()>
|
||||
where W: std::io::Write
|
||||
where
|
||||
W: std::io::Write,
|
||||
{
|
||||
const full : usize = 4;
|
||||
const half : usize = 2;
|
||||
let i = &vec![b' '; depth*full];
|
||||
let iandhalf = &vec![b' '; depth*full + half];
|
||||
let (i, iandhalf) = unsafe {(
|
||||
std::str::from_utf8_unchecked(i),
|
||||
std::str::from_utf8_unchecked(iandhalf),
|
||||
)};
|
||||
const full: usize = 4;
|
||||
const half: usize = 2;
|
||||
let i = &vec![b' '; depth * full];
|
||||
let iandhalf = &vec![b' '; depth * full + half];
|
||||
let (i, iandhalf) = unsafe {
|
||||
(
|
||||
std::str::from_utf8_unchecked(i),
|
||||
std::str::from_utf8_unchecked(iandhalf),
|
||||
)
|
||||
};
|
||||
if is_newline {
|
||||
write!(&mut w, "{}", i);
|
||||
}
|
||||
match p {
|
||||
Pretty::Single {r#type, length, val, trailer} =>
|
||||
write!(&mut w, "{} {}{}", r#type, val, trailer),
|
||||
Pretty::Tag { r#type, length, key, inner, val } => {
|
||||
Pretty::Single {
|
||||
r#type,
|
||||
length,
|
||||
val,
|
||||
trailer,
|
||||
} => write!(&mut w, "{} {}{}", r#type, val, trailer),
|
||||
Pretty::Tag {
|
||||
r#type,
|
||||
length,
|
||||
key,
|
||||
inner,
|
||||
val,
|
||||
} => {
|
||||
write!(&mut w, "{} {} {}", r#type, key, inner)?;
|
||||
Self::go::<W>(&mut w, val, depth, false)
|
||||
},
|
||||
}
|
||||
// if the length is 0 or 1, we print on one line,
|
||||
// only if there’s more than one element we split the resulting value.
|
||||
// we never break lines on arbitrary column sizes, since that is just silly.
|
||||
Pretty::Multi {r#type, length, vals, trailer} => match vals.len() {
|
||||
Pretty::Multi {
|
||||
r#type,
|
||||
length,
|
||||
vals,
|
||||
trailer,
|
||||
} => match vals.len() {
|
||||
0 => write!(&mut w, "{} {}", r#type, trailer),
|
||||
1 => {
|
||||
write!(&mut w, "{} ", r#type);
|
||||
Self::go::<W>(&mut w, &vals[0], depth, false)?;
|
||||
write!(&mut w, "{}", trailer)
|
||||
},
|
||||
}
|
||||
more => {
|
||||
write!(&mut w, "\n{}{} \n", iandhalf, r#type)?;
|
||||
for v in vals {
|
||||
|
|
|
|||
|
|
@ -1,37 +1,35 @@
|
|||
extern crate httparse;
|
||||
extern crate netencode;
|
||||
extern crate arglib_netencode;
|
||||
extern crate ascii;
|
||||
extern crate exec_helpers;
|
||||
extern crate httparse;
|
||||
extern crate netencode;
|
||||
|
||||
use std::os::unix::io::FromRawFd;
|
||||
use std::io::Read;
|
||||
use std::io::Write;
|
||||
use exec_helpers::{die_expected_error, die_temporary, die_user_error};
|
||||
use std::collections::HashMap;
|
||||
use exec_helpers::{die_user_error, die_expected_error, die_temporary};
|
||||
use std::io::{Read, Write};
|
||||
use std::os::unix::io::FromRawFd;
|
||||
|
||||
use netencode::{U, T, dec};
|
||||
use netencode::dec::Decoder;
|
||||
use netencode::{dec, T, U};
|
||||
|
||||
enum What {
|
||||
Request,
|
||||
Response
|
||||
Response,
|
||||
}
|
||||
|
||||
// reads a http request (stdin), and writes all headers to stdout, as netencoded record.
|
||||
// The keys are text, but can be lists of text iff headers appear multiple times, so beware.
|
||||
fn main() -> std::io::Result<()> {
|
||||
|
||||
exec_helpers::no_args("read-http");
|
||||
|
||||
let args = dec::RecordDot {
|
||||
field: "what",
|
||||
inner: dec::OneOf {
|
||||
list: vec!["request", "response"],
|
||||
inner: dec::Text
|
||||
}
|
||||
inner: dec::Text,
|
||||
},
|
||||
};
|
||||
let what : What = match args.dec(arglib_netencode::arglib_netencode("read-http", None).to_u()) {
|
||||
let what: What = match args.dec(arglib_netencode::arglib_netencode("read-http", None).to_u()) {
|
||||
Ok("request") => What::Request,
|
||||
Ok("response") => What::Response,
|
||||
Ok(v) => panic!("shouldn’t happen!, value was: {}", v),
|
||||
|
|
@ -39,7 +37,8 @@ fn main() -> std::io::Result<()> {
|
|||
};
|
||||
|
||||
fn read_stdin_to_complete<F>(mut parse: F) -> ()
|
||||
where F: FnMut(&[u8]) -> httparse::Result<usize>
|
||||
where
|
||||
F: FnMut(&[u8]) -> httparse::Result<usize>,
|
||||
{
|
||||
let mut res = httparse::Status::Partial;
|
||||
loop {
|
||||
|
|
@ -48,16 +47,22 @@ fn main() -> std::io::Result<()> {
|
|||
}
|
||||
let mut buf = [0; 2048];
|
||||
match std::io::stdin().read(&mut buf[..]) {
|
||||
Ok(size) => if size == 0 {
|
||||
break;
|
||||
},
|
||||
Err(err) => die_temporary("read-http", format!("could not read from stdin, {:?}", err))
|
||||
Ok(size) => {
|
||||
if size == 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
die_temporary("read-http", format!("could not read from stdin, {:?}", err))
|
||||
}
|
||||
}
|
||||
match parse(&buf) {
|
||||
Ok(status) => {
|
||||
res = status;
|
||||
}
|
||||
Err(err) => die_temporary("read-http", format!("httparse parsing failed: {:#?}", err))
|
||||
Err(err) => {
|
||||
die_temporary("read-http", format!("httparse parsing failed: {:#?}", err))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -66,7 +71,10 @@ fn main() -> std::io::Result<()> {
|
|||
let mut res = HashMap::new();
|
||||
for httparse::Header { name, value } in headers {
|
||||
let val = ascii::AsciiStr::from_ascii(*value)
|
||||
.expect(&format!("read-http: we require header values to be ASCII, but the header {} was {:?}", name, value))
|
||||
.expect(&format!(
|
||||
"read-http: we require header values to be ASCII, but the header {} was {:?}",
|
||||
name, value
|
||||
))
|
||||
.as_str();
|
||||
// lowercase the header names, since the standard doesn’t care
|
||||
// and we want unique strings to match against
|
||||
|
|
@ -77,13 +85,13 @@ fn main() -> std::io::Result<()> {
|
|||
let name_lower = name.to_lowercase();
|
||||
let _ = res.insert(name_lower, U::List(vec![U::Text(t), U::Text(val)]));
|
||||
()
|
||||
},
|
||||
}
|
||||
Some(U::List(mut l)) => {
|
||||
let name_lower = name.to_lowercase();
|
||||
l.push(U::Text(val));
|
||||
let _ = res.insert(name_lower, U::List(l));
|
||||
()
|
||||
},
|
||||
}
|
||||
Some(o) => panic!("read-http: header not text nor list: {:?}", o),
|
||||
}
|
||||
}
|
||||
|
|
@ -98,12 +106,14 @@ fn main() -> std::io::Result<()> {
|
|||
match chonker.next() {
|
||||
Some(Ok(chunk)) => {
|
||||
buf.extend_from_slice(&chunk);
|
||||
if chunk.windows(4).any(|c| c == b"\r\n\r\n" ) {
|
||||
if chunk.windows(4).any(|c| c == b"\r\n\r\n") {
|
||||
return Some(());
|
||||
}
|
||||
},
|
||||
Some(Err(err)) => die_temporary("read-http", format!("error reading from stdin: {:?}", err)),
|
||||
None => return None
|
||||
}
|
||||
Some(Err(err)) => {
|
||||
die_temporary("read-http", format!("error reading from stdin: {:?}", err))
|
||||
}
|
||||
None => return None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -118,66 +128,97 @@ fn main() -> std::io::Result<()> {
|
|||
let mut buf: Vec<u8> = vec![];
|
||||
match read_till_end_of_header(&mut buf, stdin.lock()) {
|
||||
Some(()) => match req.parse(&buf) {
|
||||
Ok(httparse::Status::Complete(_body_start)) => {},
|
||||
Ok(httparse::Status::Partial) => die_expected_error("read-http", "httparse should have gotten a full header"),
|
||||
Err(err) => die_expected_error("read-http", format!("httparse response parsing failed: {:#?}", err))
|
||||
Ok(httparse::Status::Complete(_body_start)) => {}
|
||||
Ok(httparse::Status::Partial) => {
|
||||
die_expected_error("read-http", "httparse should have gotten a full header")
|
||||
}
|
||||
Err(err) => die_expected_error(
|
||||
"read-http",
|
||||
format!("httparse response parsing failed: {:#?}", err),
|
||||
),
|
||||
},
|
||||
None => die_expected_error("read-http", format!("httparse end of stdin reached before able to parse request headers"))
|
||||
None => die_expected_error(
|
||||
"read-http",
|
||||
format!("httparse end of stdin reached before able to parse request headers"),
|
||||
),
|
||||
}
|
||||
let method = req.method.expect("method must be filled on complete parse");
|
||||
let path = req.path.expect("path must be filled on complete parse");
|
||||
write_dict_req(method, path, &normalize_headers(req.headers))
|
||||
},
|
||||
}
|
||||
Response => {
|
||||
let mut resp = httparse::Response::new(&mut headers);
|
||||
let mut buf: Vec<u8> = vec![];
|
||||
match read_till_end_of_header(&mut buf, stdin.lock()) {
|
||||
Some(()) => match resp.parse(&buf) {
|
||||
Ok(httparse::Status::Complete(_body_start)) => {},
|
||||
Ok(httparse::Status::Partial) => die_expected_error("read-http", "httparse should have gotten a full header"),
|
||||
Err(err) => die_expected_error("read-http", format!("httparse response parsing failed: {:#?}", err))
|
||||
Ok(httparse::Status::Complete(_body_start)) => {}
|
||||
Ok(httparse::Status::Partial) => {
|
||||
die_expected_error("read-http", "httparse should have gotten a full header")
|
||||
}
|
||||
Err(err) => die_expected_error(
|
||||
"read-http",
|
||||
format!("httparse response parsing failed: {:#?}", err),
|
||||
),
|
||||
},
|
||||
None => die_expected_error("read-http", format!("httparse end of stdin reached before able to parse response headers"))
|
||||
None => die_expected_error(
|
||||
"read-http",
|
||||
format!("httparse end of stdin reached before able to parse response headers"),
|
||||
),
|
||||
}
|
||||
let code = resp.code.expect("code must be filled on complete parse");
|
||||
let reason = resp.reason.expect("reason must be filled on complete parse");
|
||||
let reason = resp
|
||||
.reason
|
||||
.expect("reason must be filled on complete parse");
|
||||
write_dict_resp(code, reason, &normalize_headers(resp.headers))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn write_dict_req<'a, 'buf>(method: &'buf str, path: &'buf str, headers: &'a HashMap<String, U<'a>>) -> std::io::Result<()> {
|
||||
let mut http = vec![
|
||||
("method", U::Text(method)),
|
||||
("path", U::Text(path)),
|
||||
].into_iter().collect();
|
||||
fn write_dict_req<'a, 'buf>(
|
||||
method: &'buf str,
|
||||
path: &'buf str,
|
||||
headers: &'a HashMap<String, U<'a>>,
|
||||
) -> std::io::Result<()> {
|
||||
let mut http = vec![("method", U::Text(method)), ("path", U::Text(path))]
|
||||
.into_iter()
|
||||
.collect();
|
||||
write_dict(http, headers)
|
||||
}
|
||||
|
||||
fn write_dict_resp<'a, 'buf>(code: u16, reason: &'buf str, headers: &'a HashMap<String, U<'a>>) -> std::io::Result<()> {
|
||||
fn write_dict_resp<'a, 'buf>(
|
||||
code: u16,
|
||||
reason: &'buf str,
|
||||
headers: &'a HashMap<String, U<'a>>,
|
||||
) -> std::io::Result<()> {
|
||||
let mut http = vec![
|
||||
("status", U::N6(code as u64)),
|
||||
("status-text", U::Text(reason)),
|
||||
].into_iter().collect();
|
||||
]
|
||||
.into_iter()
|
||||
.collect();
|
||||
write_dict(http, headers)
|
||||
}
|
||||
|
||||
|
||||
fn write_dict<'buf, 'a>(mut http: HashMap<&str, U<'a>>, headers: &'a HashMap<String, U<'a>>) -> std::io::Result<()> {
|
||||
match http.insert("headers", U::Record(
|
||||
headers.iter().map(|(k,v)| (k.as_str(), v.clone())).collect()
|
||||
)) {
|
||||
fn write_dict<'buf, 'a>(
|
||||
mut http: HashMap<&str, U<'a>>,
|
||||
headers: &'a HashMap<String, U<'a>>,
|
||||
) -> std::io::Result<()> {
|
||||
match http.insert(
|
||||
"headers",
|
||||
U::Record(
|
||||
headers
|
||||
.iter()
|
||||
.map(|(k, v)| (k.as_str(), v.clone()))
|
||||
.collect(),
|
||||
),
|
||||
) {
|
||||
None => (),
|
||||
Some(_) => panic!("read-http: headers already in dict"),
|
||||
};
|
||||
netencode::encode(
|
||||
&mut std::io::stdout(),
|
||||
&U::Record(http)
|
||||
)?;
|
||||
netencode::encode(&mut std::io::stdout(), &U::Record(http))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
// iter helper
|
||||
|
||||
struct Chunkyboi<T> {
|
||||
|
|
@ -188,10 +229,7 @@ struct Chunkyboi<T> {
|
|||
impl<R: Read> Chunkyboi<R> {
|
||||
fn new(inner: R, chunksize: usize) -> Self {
|
||||
let buf = vec![0; chunksize];
|
||||
Chunkyboi {
|
||||
inner,
|
||||
buf
|
||||
}
|
||||
Chunkyboi { inner, buf }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -205,7 +243,7 @@ impl<R: Read> Iterator for Chunkyboi<R> {
|
|||
// clone a new buffer so we can reuse the internal one
|
||||
Some(Ok(self.buf[..read].to_owned()))
|
||||
}
|
||||
Err(err) => Some(Err(err))
|
||||
Err(err) => Some(Err(err)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,6 @@
|
|||
use clap::Clap;
|
||||
|
||||
use crate::codegen;
|
||||
use crate::interpreter;
|
||||
use crate::parser;
|
||||
use crate::tc;
|
||||
use crate::Result;
|
||||
use crate::{codegen, interpreter, parser, tc, Result};
|
||||
|
||||
/// Evaluate an expression and print its result
|
||||
#[derive(Clap)]
|
||||
|
|
|
|||
|
|
@ -1,9 +1,8 @@
|
|||
use std::borrow::Cow;
|
||||
|
||||
use nom::alt;
|
||||
use nom::character::complete::{digit1, multispace0, multispace1};
|
||||
use nom::{
|
||||
call, char, complete, delimited, do_parse, flat_map, many0, map, named, opt, parse_to,
|
||||
alt, call, char, complete, delimited, do_parse, flat_map, many0, map, named, opt, parse_to,
|
||||
preceded, separated_list0, separated_list1, tag, tuple,
|
||||
};
|
||||
use pratt::{Affix, Associativity, PrattParser, Precedence};
|
||||
|
|
|
|||
|
|
@ -13,11 +13,8 @@ use futures::Future;
|
|||
use metrics_exporter_prometheus::PrometheusBuilder;
|
||||
use nix::pty::Winsize;
|
||||
use pty::ChildHandle;
|
||||
use thrussh::ChannelId;
|
||||
use thrussh::{
|
||||
server::{self, Auth, Session},
|
||||
CryptoVec,
|
||||
};
|
||||
use thrussh::server::{self, Auth, Session};
|
||||
use thrussh::{ChannelId, CryptoVec};
|
||||
use thrussh_keys::decode_secret_key;
|
||||
use thrussh_keys::key::KeyPair;
|
||||
use tokio::fs::File;
|
||||
|
|
|
|||
|
|
@ -6,8 +6,7 @@ use std::task::{Context, Poll};
|
|||
|
||||
use eyre::{bail, Result};
|
||||
use futures::Future;
|
||||
use nix::pty::forkpty;
|
||||
use nix::pty::Winsize;
|
||||
use nix::pty::{forkpty, Winsize};
|
||||
use nix::sys::termios::Termios;
|
||||
use nix::sys::wait::{waitpid, WaitPidFlag, WaitStatus};
|
||||
use nix::unistd::{ForkResult, Pid};
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ use std::io::BufReader;
|
|||
const PART_2: bool = true;
|
||||
|
||||
fn day01(is_part2: bool, numbers: &Vec<i64>) -> Result<String, anyhow::Error> {
|
||||
//println!("{:?}", numbers);
|
||||
// println!("{:?}", numbers);
|
||||
|
||||
for n1 in numbers.iter() {
|
||||
for n2 in numbers.iter() {
|
||||
|
|
@ -50,7 +50,7 @@ fn parse(filename: &str) -> Result<Vec<i64>, anyhow::Error> {
|
|||
fn main() -> anyhow::Result<()> {
|
||||
let args: Vec<String> = std::env::args().collect();
|
||||
|
||||
//println!("{:?}", args);
|
||||
// println!("{:?}", args);
|
||||
if args.len() != 2 {
|
||||
return Err(anyhow!("usage: day01 input_file"));
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue