diff options
Diffstat (limited to 'src/parse.rs')
-rw-r--r-- | src/parse.rs | 237 |
1 files changed, 237 insertions, 0 deletions
diff --git a/src/parse.rs b/src/parse.rs new file mode 100644 index 0000000..832cdb6 --- /dev/null +++ b/src/parse.rs @@ -0,0 +1,237 @@ +#![allow(missing_docs, dead_code, unused_variables, unused_imports)] + +use std::str::from_utf8; +use std::convert::Into; + +use nom; +use nom::IResult::*; +use nom::{alpha, alphanumeric, multispace, space, newline, line_ending}; + +use crate::properties; + +////////// Parameters + +/// Zero-copy version of `properties::Parameter` +#[derive(PartialEq, Debug, Clone)] +struct Parameter<'a> { + key: &'a str, + val: &'a str +} + +impl<'a> Into<properties::Parameter> for Parameter<'a> { + fn into(self) -> properties::Parameter { + properties::Parameter::new(self.key, self.val) + } +} + + +#[test] +fn parse_parameter() { + assert_eq!( + parameter(b";KEY=VALUE"), + Done(&[][..], Parameter{key: "KEY", val: "VALUE"}) + ); + assert_eq!( + parameter(b"; KEY=VALUE"), + Done(&[][..], Parameter{key: "KEY", val: "VALUE"}) + ); + assert!( parameter(b";KEY").is_incomplete()); + assert!( parameter(b";KEY=").is_incomplete()); +} + +named!(parameter(&[u8]) -> Parameter, + do_parse!( + tag!(";") >> + opt!(space) >> + key: map_res!(alpha, from_utf8) >> + tag!("=") >> + val: map_res!(alphanumeric, from_utf8) >> + (Parameter{key: key, val: val}) + ) + ); + +// parameter list + +#[test] +fn parse_parameter_list() { + assert_eq!( + parameter_list(b";KEY=VALUE"), + Done(&[][..], vec![Parameter{key: "KEY", val: "VALUE"}]) + ); + + assert_eq!( + parameter_list(b";KEY=VALUE;DATE=TODAY"), + Done(&[][..], vec![ + Parameter{key: "KEY", val: "VALUE"}, + Parameter{key: "DATE", val:"TODAY"} + ]) + ); + + assert_eq!( + parameter_list(b";KEY=VALUE;DATE=20170218"), + Done(&[][..], vec![ + Parameter{key: "KEY", val: "VALUE"}, + Parameter{key: "DATE", val:"20170218"} + ]) + ); +} + +named!(parameter_list(&[u8]) -> Vec<Parameter>, + many0!(parameter) +); + + + +////////// Properies + +/// Zero-copy version of `properties::Property` +#[derive(PartialEq, Debug, Clone)] +struct Property<'a> { + key: &'a str, + val: &'a str, + params: Vec<Parameter<'a>> +} + +#[test] +fn parse_propery() { + assert_eq!( property(b"KEY:VALUE\n"), Done(&[][..], Property{key: "KEY", val: "VALUE", params: vec![]} )); + + assert_eq!( + property(b"KEY;foo=bar:VALUE\n"), + Done(&[][..], Property{key: "KEY", val: "VALUE", params: vec![ + Parameter{key:"foo", val: "bar"} + ]}) + ); +} + +named!(property(&[u8]) -> Property, + do_parse!( + opt!(multispace) >> + key: map_res!(alpha, from_utf8) >> + params: parameter_list >> + tag!(":") >> + val: map_res!(alphanumeric, from_utf8) >> + line_ending >> + (Property{key: key, val: val, params: params}) + ) +); + +#[test] +fn parse_propery_list() { + + assert_eq!( + property_list(b"KEY;foo=bar:VALUE\n KEY;foo=bar; DATE=20170218:VALUE\n"), + Done(&[][..], vec![ + Property{key: "KEY", val: "VALUE", params: vec![ Parameter{key:"foo", val: "bar"} ]}, + Property{key: "KEY", val: "VALUE", params: vec![ + Parameter{key:"foo", val: "bar"}, + Parameter{key:"DATE", val: "20170218"}, + ]} + ]) + ); + assert_eq!( + property_list(b"KEY;foo=bar:VALUE\nKEY;foo=bar;DATE=20170218:VALUE\n"), + Done(&[][..], vec![ + Property{key: "KEY", val: "VALUE", params: vec![ Parameter{key:"foo", val: "bar"} ]}, + Property{key: "KEY", val: "VALUE", params: vec![ + Parameter{key:"foo", val: "bar"}, + Parameter{key:"DATE", val: "20170218"}, + ]} + ]) + ); + assert_eq!( + property_list(b""), + Done(&[][..], vec![ ])); +} + +named!(property_list(&[u8]) -> Vec<Property>, + many0!(property) +); + +////////// Components + +#[derive(PartialEq, Debug, Clone)] +pub struct Component<'a> { + name: &'a str, + properties: Vec<Property<'a>> +} + +#[test] +#[ignore] +fn parse_empty_component() { + assert_eq!(component(b"BEGIN:VEVENT\nEND:VEVENT\n"), Done(&[][..], Component{name: "VEVENT", properties: vec![]})); + + assert_eq!( + component(b"BEGIN:VEVENT\n\nEND:VEVENT\n"), + Done(&[][..], + Component{name: "VEVENT", properties: vec![]} + )); + assert_eq!( + component(b"BEGIN:VEVENT\nEND:VEVENT\n"), + Done(&[][..], + Component{name: "VEVENT", properties: vec![]} + )); +} + +#[test] +fn parse_component() { + let sample_0 = b"BEGIN:VEVENT\nKEY;foo=bar:VALUE\nKEY;foo=bar;DATE=20170218:VALUE\nEND:VEVENT\n"; + let sample_1 = b"BEGIN:VEVENT +KEY;foo=bar:VALUE + KEY;foo=bar;DATE=20170218:VALUE +END:VEVENT +"; + + //assert_eq!(from_utf8(sample_0), from_utf8(sample_1)); + + let expectation = Component{name: "VEVENT", properties: vec![ + Property{key: "KEY", val: "VALUE", params: vec![ + Parameter{key:"foo", val: "bar"}, + ]}, + Property{key: "KEY", val: "VALUE", params: vec![ + Parameter{key:"foo", val: "bar"}, + Parameter{key:"DATE", val: "20170218"}, + ]}, + ]}; + + println!("expectation: {:#?}", expectation); + println!("vs reality : {:#?}", component(sample_1)); + + //assert_eq!( + // component(sample_1), + // Done(&[][..], expectation.clone())); + + assert_eq!( + component(sample_1).unwrap().1, + expectation.clone()); +} + +named!{components(&[u8]) -> Vec<Component>, + many0!(component) +} + +pub fn calendar(raw: &str) -> Vec<Component> { + let parsed = components(raw.as_bytes()); + println!("{:?}", parsed); + if let Done(_, components) = parsed { + components + } else { vec![] } +} + +named!(component(&[u8]) -> Component, + dbg!( + do_parse!( + tag!("BEGIN:") >> name: map_res!(alpha, from_utf8) >> + properties: many_till!( + + do_parse!(p:property >> (p)), + tag!("END:") + + ) >> + tag!(name) >> + + (Component{name: name, properties: properties.0}) + ) + ) + ); + |