extern crate xml;
mod trace;
pub use trace::Trace;
pub type ParseResult<'a, T> = Result<T, ParseError<'a>>;
#[derive(Debug)]
pub enum ParseError<'a> {
EndOfFile,
UnexpectedValue(&'a str),
}
pub fn wsp(c: char) -> bool {
['\x20', '\x09', '\x0D', '\x0A'].contains(&c)
}
fn digit(c: char) -> bool {
c.is_ascii_digit()
}
fn hex(mut input: &str) -> ParseResult<(&str, &str)> {
let mut end = 0;
let i = input;
if !input.starts_with('#') {
return Err(ParseError::UnexpectedValue(input));
}
input = &input[1..];
end += 1;
if !input.starts_with(|c: char| c.is_ascii_hexdigit()) {
return Err(ParseError::UnexpectedValue(input));
}
input = &input[1..];
end += 1;
while input.starts_with(|c: char| c.is_ascii_hexdigit()) {
input = &input[1..];
end += 1;
}
Ok((input, &i[..end]))
}
#[derive(Debug, PartialEq)]
pub struct Point(Vec<Value>);
impl Point {
fn parse(mut input: &str) -> ParseResult<(&str, Self)> {
let mut values = Vec::new();
input = input.trim_left_matches(wsp);
let (mut input, value) = Value::parse(input)?;
values.push(value);
input = input.trim_left_matches(wsp);
loop {
match Value::parse(input) {
Ok((i, value)) => {
input = i;
values.push(value);
}
Err(_) => break
}
input = input.trim_left_matches(wsp);
}
Ok((input, Point(values)))
}
}
#[cfg(test)]
mod point {
use super::{Point, Value};
#[test]
#[should_panic]
fn empty_string() {
Point::parse("").unwrap();
}
#[test]
fn single() {
let expect = ("", Point(vec![Value::Inferred]));
assert_eq!(expect, Point::parse("*").unwrap());
assert_eq!(expect, Point::parse(" *").unwrap());
assert_eq!(expect, Point::parse(" \t*\r\n").unwrap());
}
#[test]
fn many() {
let expect = ("", Point(vec![Value::Inferred, Value::Inferred]));
assert_eq!(expect, Point::parse("**").unwrap());
assert_eq!(expect, Point::parse("* *").unwrap());
assert_eq!(expect, Point::parse(" * *").unwrap());
assert_eq!(expect, Point::parse(" * * ").unwrap());
}
}
#[derive(Debug, PartialEq)]
pub enum Value {
Inferred,
NotGiven,
Bool(bool),
}
impl Value {
fn parse(input: &str) -> ParseResult<(&str, Self)> {
if input.is_empty() {
return Err(ParseError::EndOfFile)
}
let value = match &input[..1] {
"*" => Value::Inferred,
"?" => Value::NotGiven,
"T" => Value::Bool(true),
"F" => Value::Bool(false),
_ => return Err(ParseError::UnexpectedValue(input))
};
Ok((&input[1..], value))
}
}
#[cfg(test)]
mod value {
use super::Value;
#[test]
fn inferred() {
assert_eq!(("", Value::Inferred), Value::parse("*").unwrap());
}
#[test]
fn not_given() {
assert_eq!(("", Value::NotGiven), Value::parse("?").unwrap());
}
#[test]
fn boolean() {
assert_eq!(("", Value::Bool(true)), Value::parse("T").unwrap());
assert_eq!(("", Value::Bool(false)), Value::parse("F").unwrap());
}
}
static TEST_INKML: &str = include_str!("test.inkml");
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn open_simple_inkml() {
use xml::reader::XmlEvent;
use xml::name::OwnedName;
let stream = xml::EventReader::from_str(TEST_INKML);
let mut current_path = Vec::new();
let mut trace = None;
for event in stream {
match event.unwrap() {
XmlEvent::StartElement { name: OwnedName { local_name, .. }, .. } => {
current_path.push(local_name.clone());
}
XmlEvent::EndElement { name: OwnedName { local_name, .. }, .. } => {
assert!(*current_path.last().unwrap() == local_name);
current_path.pop();
}
XmlEvent::Characters(data) => {
if current_path.last().unwrap() == "trace" {
trace = Some(Trace::parse(&data).unwrap().1);
}
}
_ => {}
}
}
assert_eq!(trace.unwrap(), Trace::new(vec![
Point(vec![Value::Inferred, Value::Inferred]),
Point(vec![Value::NotGiven]),
Point(vec![Value::Bool(false), Value::Bool(true)]),
]));
}
}