Skip to content
This repository has been archived by the owner on Aug 17, 2024. It is now read-only.

Commit

Permalink
V0.3.0
Browse files Browse the repository at this point in the history
- Fix #17 
- Fix #16 
- Fix value detection bug
- Format code
- Add tests on IcalParser / VcardParser
- Correct old tests
  • Loading branch information
Peltoche authored Mar 4, 2017
2 parents 9080095 + 0d070ad commit 09b68f7
Show file tree
Hide file tree
Showing 14 changed files with 242 additions and 143 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "ical"
version = "0.2.1"
version = "0.3.0"
authors = ["Peltoche <[email protected]>"]

description = "Ical/Vcard parser for Rust"
Expand Down
21 changes: 11 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@

# ical-rs 0.2.1
# ical-rs 0.3.0
===============

[![Build Status](https://travis-ci.org/Peltoche/ical-rs.svg?branch=master)](https://travis-ci.org/Peltoche/ical-rs)
Expand All @@ -22,7 +22,7 @@ Put this in your `Cargo.toml`:

```toml
[dependencies]
ical = "0.2.0"
ical = "0.3.0"
```


Expand Down Expand Up @@ -50,7 +50,7 @@ Each component can contains properties (ie: LineParsed) or sub-components.
Cargo.toml:
```toml
[dependencies.ical]
version = "0.2.*"
version = "0.3.*"
default-features = false
features = ["ical-parser", "vcard-parser"]
```
Expand All @@ -66,7 +66,7 @@ fn main() {
let buf = BufReader::new(File::open("/tmp/component.ics")
.unwrap());

let reader = ical::IcalReader::new(buf);
let reader = ical::IcalParser::new(buf);

for line in reader {
println!("{:?}", line);
Expand Down Expand Up @@ -111,7 +111,7 @@ It work for both the Vcard and Ical format.
Cargo.toml:
```toml
[dependencies.ical]
version = "0.2.*"
version = "0.3.*"
default-features = false
features = ["line-parser"]
```
Expand All @@ -132,14 +132,15 @@ fn main() {
for line in reader {
println!("{:?}", line);
}

}
```

Input -> Output:
```
begin:VCALENDAR Ok(LineParsed { name: "BEGIN", params: None, value: "VCALENDAR" })
ATTENDEE;cn=FooBar:mailto:foo3@bar -> Ok(LineParsed { name: "ATTENDEE", params: Some([("CN", "FooBar")]), value: "mailto:foo3@bar" })
END:VCALENDAR Ok(LineParsed { name: "END", params: None, value: "VCALENDAR" })
begin:VCALENDAR Ok(LineParsed { name: "BEGIN", params: None, value: Some("VCALENDAR") })
ATTENDEE;cn=FooBar:mailto:foo3@bar -> Ok(LineParsed { name: "ATTENDEE", params: Some([("CN", "FooBar")]), value: Some("mailto:foo3@bar") })
DESCRIPTION: Ok(LineParsed { name: "DESCRIPTION": params: None, value: None })
END:VCALENDAR Ok(LineParsed { name: "END", params: None, value: Some("VCALENDAR") })
```

### LineReader
Expand All @@ -153,7 +154,7 @@ It work for both the Vcard and Ical format.
Cargo.toml:
```toml
[dependencies.ical]
version = "0.2.*"
version = "0.3.*"
default-features = false
features = ["line-reader"]
```
Expand Down
82 changes: 49 additions & 33 deletions src/line/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,23 +17,23 @@ use line::reader::{LineReader, Line};
pub struct LineParsed {
pub name: String,
pub params: Option<Vec<(String, Vec<String>)>>,
pub value: String,
pub value: Option<String>,
}

impl LineParsed {
pub fn new() -> LineParsed {
LineParsed {
name: String::new(),
params: None,
value: String::new(),
value: None,
}
}
}

impl fmt::Display for LineParsed {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f,
"name: {}\nparams: {:?}\nvalue: {}",
"name: {}\nparams: {:?}\nvalue: {:?}",
self.name,
self.params,
self.value)
Expand Down Expand Up @@ -61,25 +61,35 @@ impl<B: BufRead> LineParser<B> {
fn parse(&self, line: Line) -> Result<LineParsed, ParseError> {
let mut property = LineParsed::new();

let mut content = line.as_str();

// Parse name.
property.name = self.parse_name(line.as_str())
property.name = self.parse_name(content)
.and_then(|name| Some(name.to_string()))
.ok_or(ParseError::MissingName)?;

// Parse value
property.value = self.parse_value(line.as_str())
.and_then(|value| Some(value.to_string()))
.ok_or(ParseError::MissingValue)?;
content = content.split_at(property.name.len()).1;

// Parse parameters.
property.params = self.parse_parameters(line.as_str())?;
let res = self.parse_parameters(content)?;
property.params = res.0;
content = res.1;

// Parse value
property.value = self.parse_value(content)
.and_then(|value| {
match value.len() {
0 => None,
_ => Some(value.to_string()),
}
});

Ok(property)

}

/// Return the name from the given `Line`.
fn parse_name<'a>(&self, line: &'a str) -> Option<&'a str> {
fn parse_name<'a>(&self, line: &'a str) -> Option<(&'a str)> {
let end_name_index;

let param_index = line.find(::PARAM_DELIMITER).unwrap_or(usize::max_value());
Expand All @@ -96,34 +106,22 @@ impl<B: BufRead> LineParser<B> {
Some(line.split_at(end_name_index).0)
}


/// Return the value from the given `Line`.
fn parse_value<'a>(&self, line: &'a str) -> Option<&'a str> {
let value_index = match line.find(::VALUE_DELIMITER) {
Some(val) => val + 1, // Jump the VALUE_DELIMITER
None => return None,
};

if value_index < line.len() {
Some(line.split_at(value_index).1)
} else {
None
}
}

/// Return the parameters from the given `Line`.
fn parse_parameters(&self, line: &str) -> Result<Option<Vec<(String, Vec<String>)>>, ParseError> {
fn parse_parameters<'a>
(&self,
line: &'a str)
-> Result<(Option<Vec<(String, Vec<String>)>>, &'a str), ParseError> {
let mut param_list = Vec::new();
let mut params_str;

let start_value_index = line.find(::VALUE_DELIMITER).unwrap_or(usize::max_value());
let start_param_index = match line.find(::PARAM_DELIMITER) {
Some(val) => val,
None => return Ok(None), // there is no params.
None => return Ok((None, line)), // there is no params.
};

if start_value_index < start_param_index {
return Ok(None);
return Ok((None, line));
}

// Remove the attribue name.
Expand All @@ -145,21 +143,38 @@ impl<B: BufRead> LineParser<B> {

param_list.push((name.to_uppercase(), values));

}

Ok((Some(param_list), params_str))
}


/// Return the value from the given `Line`.
fn parse_value<'a>(&self, line: &'a str) -> Option<&'a str> {
let value_index = match line.find(::VALUE_DELIMITER) {
Some(val) => val + 1, // Jump the VALUE_DELIMITER
None => return None,
};

Ok(Some((param_list)))
if value_index < line.len() {
Some(line.split_at(value_index).1)
} else {
None
}
}
}

fn parse_param_value<'a>(mut values: Vec<String>, params_str: &'a str) -> Result<(Vec<String>, &'a str), ParseError> {
fn parse_param_value<'a>(mut values: Vec<String>,
params_str: &'a str)
-> Result<(Vec<String>, &'a str), ParseError> {
let new_params_str;

if params_str.starts_with('"') {
// This is a dquoted value. (NAME:Foo="Bar":value)
let mut elements = params_str.splitn(3, '"').skip(1);
values.push(elements.next()
.and_then(|value| Some(value.to_string()))
.ok_or(ParseError::InvalidParamFormat)?);
.and_then(|value| Some(value.to_string()))
.ok_or(ParseError::InvalidParamFormat)?);
new_params_str = elements.next()
.ok_or(ParseError::InvalidParamFormat)?;
} else {
Expand All @@ -184,7 +199,8 @@ fn parse_param_value<'a>(mut values: Vec<String>, params_str: &'a str) -> Result
}

if new_params_str.starts_with(::PARAM_VALUE_DELIMITER) {
parse_param_value(values, new_params_str.trim_left_matches(::PARAM_VALUE_DELIMITER))
parse_param_value(values,
new_params_str.trim_left_matches(::PARAM_VALUE_DELIMITER))
} else {
Ok((values, new_params_str))
}
Expand Down
4 changes: 2 additions & 2 deletions src/parser/ical/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ impl<B: BufRead> IcalParser<B> {
None => return Ok(None),
};

if line.name != "BEGIN" || line.value != "VCALENDAR" || line.params != None {
if line.name != "BEGIN" || line.value.is_none() || line.value.unwrap() != "VCALENDAR" ||
line.params != None {
return Err(ParseError::MissingHeader);
}

Expand Down Expand Up @@ -59,4 +60,3 @@ impl<B: BufRead> Iterator for IcalParser<B> {
Some(result)
}
}

8 changes: 7 additions & 1 deletion src/parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,13 @@ pub trait Component {

match line.name.as_str() {
"END" => break,
"BEGIN" => self.add_sub_component(line.value.as_str(), line_parser)?,
"BEGIN" => {
match line.value {
Some(v) => self.add_sub_component(v.as_str(), line_parser)?,
None => return Err(ParseError::NotComplete),
}
}

_ => self.add_property(line),
};
}
Expand Down
5 changes: 2 additions & 3 deletions src/parser/vcard/component.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,14 @@ use std::cell::RefCell;
use parser::{Component, ParseError};
use line::parser::{LineParsed, LineParser};

#[derive(Debug, Clone)]
pub struct VcardContact {
pub properties: Vec<LineParsed>,
}

impl VcardContact {
pub fn new() -> VcardContact {
VcardContact {
properties: Vec::new(),
}
VcardContact { properties: Vec::new() }
}
}

Expand Down
3 changes: 2 additions & 1 deletion src/parser/vcard/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ impl<B: BufRead> VcardParser<B> {
None => return Ok(None),
};

if line.name != "BEGIN" || line.value != "VCARD" || line.params != None {
if line.name != "BEGIN" || line.value.is_none() || line.value.unwrap() != "VCARD" ||
line.params != None {
return Err(ParseError::MissingHeader);
}

Expand Down
Loading

0 comments on commit 09b68f7

Please sign in to comment.