use std::num::NonZeroUsize;
pub use self::hrx::*;
peg::parser!{grammar hrx(boundary_length: NonZeroUsize) for str {
use self::super::super::super::{HrxEntryData, HrxEntry, HrxPath};
pub rule archive() -> (Option<String>, Vec<(HrxPath, HrxEntry)>, NonZeroUsize)
= ee:entry()* c:comment()?
{ (c.map(str::to_string), ee, boundary_length) }
pub rule entry() -> (HrxPath, HrxEntry)
= c:comment()? d:file()
{
(
d.0,
HrxEntry {
comment: c.map(str::to_string),
data: HrxEntryData::File {
body: d.1.map(str::to_string),
},
}
)
}
/ c:comment()? d:directory()
{
(
d,
HrxEntry {
comment: c.map(str::to_string),
data: HrxEntryData::Directory,
}
)
}
pub rule comment() -> &'input str
= boundary() newline() b:body()
{ b }
pub rule file() -> (HrxPath, Option<&'input str>)
= boundary() " "+ p:path() newline() b:body()?
{ (p, b) }
pub rule directory() -> HrxPath
= boundary() " "+ p:path() "/" newline()+
{ p }
rule boundary()
= "<" "="*<{boundary_length.get()}> ">"
rule newline()
= "\n"
pub rule body() -> &'input str
= contents()
rule contents() -> &'input str
= !boundary() ctnt:$((!(newline() boundary()) [_])+) newline() &boundary() { ctnt }
/ !boundary() ctnt:$([_]+) { ctnt }
pub rule path() -> HrxPath
= p:$(path_component() ("/" path_component())*)
{ HrxPath(p.to_string()) }
rule path_component() -> &'input str
= pc:$(path_character()+)
{?
if pc == "." || pc == ".." {
Err("Invalid '.' or '..' path component")
} else {
Ok(pc)
}
}
rule path_character() -> char
= quiet!{c:$([^'\x00'..='\x1F' | '\x7F' | '/' | ':' | '\\']) { c.chars().next().unwrap() }}
/ expected!("Any character other than U+0000 through U+001F, U+007F DELETE, U+002F SOLIDUS, U+003A COLON, or U+005C REVERSE SOLIDUS")
}}