Skip to content

Commit

Permalink
feat: add FromStr implementations
Browse files Browse the repository at this point in the history
  • Loading branch information
hoodie committed Nov 23, 2021
1 parent b71826d commit c0ffee2
Show file tree
Hide file tree
Showing 11 changed files with 144 additions and 32 deletions.
4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,7 @@ required-features = ["parser"]
name = "reserialize"
path= "examples/reserialize.rs"
required-features = ["parser"]
[[example]]
name = "parsed_property"
path= "examples/parsed_property.rs"
required-features = ["parser"]
3 changes: 1 addition & 2 deletions examples/birthday.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,7 @@ Hendrik"#,

#[cfg(feature = "parser")]
{
use std::str::FromStr;
let parsed_calendar = dbg!(Calendar::from_str(&calendar.to_string())?);
let parsed_calendar = dbg!(calendar.to_string().parse::<Calendar>()?);
parsed_calendar.print()?;
}
Ok(())
Expand Down
20 changes: 20 additions & 0 deletions examples/custom_property.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
use icalendar::*;

fn main() -> Result<(), Box<dyn std::error::Error>> {
let event = Event::new()
.summary("test event")
.append_property(
Property::new("TEST", "FOOBAR")
.add_parameter("IMPORTANCE", "very")
.add_parameter("DUE", "tomorrow")
.done(),
)
.uid("my.own.id")
.done();

let calendar = Calendar::from([event]);

calendar.print()?;

Ok(())
}
15 changes: 2 additions & 13 deletions examples/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,28 +8,17 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
.starts(Utc::now())
.class(Class::Confidential)
.ends(Utc::now() + Duration::days(1))
.append_property(
Property::new("TEST", "FOOBAR")
.add_parameter("IMPORTANCE", "very")
.add_parameter("DUE", "tomorrow")
.done(),
)
.uid("my.own.id")
.done();

let event2 = Event::new().all_day(Utc.ymd(2016, 3, 15)).done();

let todo = Todo::new().summary("Buy some milk").done();

let mut calendar = Calendar::from([event, event2]);
calendar.push(todo);
let calendar = Calendar::from([event, event2]);

calendar.print()?;

#[cfg(feature = "parser")]
{
use std::str::FromStr;
let parsed_calendar = dbg!(Calendar::from_str(&calendar.to_string())?);
let parsed_calendar = dbg!(calendar.to_string().parse::<Calendar>()?);
parsed_calendar.print()?;
}
Ok(())
Expand Down
30 changes: 30 additions & 0 deletions examples/parsed_property.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#![cfg(feature = "parser")]
use icalendar::*;

fn main() -> Result<(), Box<dyn std::error::Error>> {
let event = Event::new()
.summary("test event")
.append_property(
"TEST;IMPORTANCE=very;DUE=tomorrow:FOOBAR\n"
.parse()
.unwrap(),
)
// .uid("my.own.id")
.done();

let parsed_event = r#"BEGIN:VEVENT
DTSTAMP:20211123T192118Z
SUMMARY:parsed event
TEST;IMPORTANCE=very;DUE=tomorrow:FOOBAR
END:VEVENT
"#;

let calendar = Calendar::from(event)
.push(parsed_event.parse::<CalendarComponent>().unwrap())
.done();
calendar.print()?;

let parsed_calendar = calendar.to_string().parse::<Calendar>()?;
parsed_calendar.print()?;
Ok(())
}
7 changes: 3 additions & 4 deletions examples/todos.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use chrono::*;
use icalendar::*;

fn main() -> Result<(), Box<dyn std::error::Error>> {
let groceryies = Todo::new()
let groceries = Todo::new()
.summary("buy groceries")
.description("* soy-milk\n* oak-meal\n* vegan chocolate\n* kale\n* bacon\nabcdefghijklmnopqrstuvwxyz")
.starts(Local::now().naive_local())
Expand All @@ -14,13 +14,12 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
.due(Local::now().with_timezone(&Utc))
.done();

let calendar = dbg!(Calendar::from([groceryies]));
let calendar = dbg!(Calendar::from([groceries]));
println!("{}", calendar);

#[cfg(feature = "parser")]
{
use std::str::FromStr;
let parsed_calendar = dbg!(Calendar::from_str(&calendar.to_string())?);
let parsed_calendar = dbg!(calendar.to_string().parse::<Calendar>()?);
parsed_calendar.print()?;
}
Ok(())
Expand Down
3 changes: 3 additions & 0 deletions src/components/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use super::*;
pub struct Event {
pub(super) inner: InnerComponent,
}

impl Event {
/// Creates a new Event.
pub fn new() -> Self {
Expand All @@ -28,3 +29,5 @@ impl Event {
// unimplemented!()
//}
}

// impl std::Str
6 changes: 4 additions & 2 deletions src/parser/calendar.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
use crate::calendar::CalendarComponent;

use super::{read_calendar, unfold, Component};
use core::fmt::{self, Write};
use std::str::FromStr;
use core::{
fmt::{self, Write},
str::FromStr,
};

/// Helpertype for reserialization
#[derive(Clone, Debug)]
Expand Down
34 changes: 31 additions & 3 deletions src/parser/components.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
use std::fmt;
use std::{fmt, str::FromStr};

use chrono::Utc;
use nom::{
branch::alt,
bytes::complete::tag,
combinator::{all_consuming, complete, cut, map},
error::{context, ContextError, ParseError},
error::{context, convert_error, ContextError, ParseError, VerboseError},
multi::{many0, many_till},
IResult,
Finish, IResult,
};

#[cfg(test)]
Expand All @@ -18,6 +18,7 @@ use uuid::Uuid;
use super::parameters::Parameter;
use super::{
properties::property,
unfold,
utils::{line, line_separated, valid_key_sequence},
Property,
};
Expand Down Expand Up @@ -71,6 +72,17 @@ impl Component<'_> {
}
}

impl<'a> TryFrom<&'a str> for Component<'a> {
type Error = String;

fn try_from(input: &'a str) -> Result<Self, Self::Error> {
component(input)
.finish()
.map(|(_, x)| x)
.map_err(|e: VerboseError<&str>| format!("error: {}", convert_error(input, e.clone())))
}
}

impl From<Component<'_>> for InnerComponent {
fn from(component: Component) -> Self {
Self {
Expand All @@ -96,6 +108,15 @@ impl<'a> From<Component<'a>> for CalendarComponent {
}
}

impl<'a> FromStr for CalendarComponent {
type Err = String;

fn from_str(s: &str) -> Result<Self, Self::Err> {
let from_parsed = crate::CalendarComponent::from(read_component(&unfold(s))?);
Ok(from_parsed)
}
}

#[test]
#[rustfmt::skip]
fn parse_empty_component1() {
Expand Down Expand Up @@ -156,6 +177,13 @@ enum ComponentChild<'a> {
Component(Component<'a>),
}

pub fn read_component(input: &str) -> Result<Component<'_>, String> {
component(input)
.finish()
.map(|(_, component)| component)
.map_err(|e: VerboseError<&str>| format!("error: {}", convert_error(input, e.clone())))
}

pub fn component<'a, E: ParseError<&'a str> + ContextError<&'a str>>(
input: &'a str,
) -> IResult<&'a str, Component, E> {
Expand Down
15 changes: 13 additions & 2 deletions src/parser/parameters.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ use nom::{
bytes::complete::{tag, take_till1},
character::complete::space0,
combinator::{eof, map, opt},
error::{ContextError, ParseError},
error::{convert_error, ContextError, ParseError, VerboseError},
multi::many0,
sequence::{preceded, tuple},
IResult,
Finish, IResult,
};

#[cfg(test)]
Expand All @@ -21,6 +21,17 @@ pub struct Parameter<'a> {
pub val: Option<&'a str>,
}

impl<'a> TryFrom<&'a str> for Parameter<'a> {
type Error = String;

fn try_from(input: &'a str) -> Result<Self, Self::Error> {
parameter(input)
.finish()
.map(|(_, x)| x)
.map_err(|e: VerboseError<&str>| format!("error: {}", convert_error(input, e.clone())))
}
}

impl<'a> From<Parameter<'a>> for crate::properties::Parameter {
fn from(parameter: Parameter<'_>) -> crate::properties::Parameter {
crate::properties::Parameter::new(parameter.key, parameter.val.unwrap_or(""))
Expand Down
39 changes: 33 additions & 6 deletions src/parser/properties.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use std::fmt::{self, Write};
use std::{
fmt::{self, Write},
str::FromStr,
};

use crate::properties::fold_line;

Expand All @@ -8,12 +11,12 @@ use super::{
};
use nom::{
branch::alt,
bytes::complete::{tag, take_until},
bytes::complete::{tag, take_until, take_while},
character::complete::{line_ending, multispace0},
combinator::{cut, map, opt},
error::{context, ContextError, ParseError},
error::{context, convert_error, ContextError, ParseError, VerboseError},
sequence::{preceded, separated_pair, tuple},
IResult,
Finish, IResult,
};

#[cfg(test)]
Expand Down Expand Up @@ -46,6 +49,17 @@ impl Property<'_> {
}
}

impl<'a> TryFrom<&'a str> for Property<'a> {
type Error = String;

fn try_from(input: &'a str) -> Result<Self, Self::Error> {
property(input)
.finish()
.map(|(_, x)| x)
.map_err(|e: VerboseError<&str>| format!("error: {}", convert_error(input, e.clone())))
}
}

impl From<Property<'_>> for crate::Property {
fn from(parsed: Property<'_>) -> Self {
Self {
Expand All @@ -54,12 +68,20 @@ impl From<Property<'_>> for crate::Property {
params: parsed
.params
.into_iter()
.map(|p| (p.key.to_owned(), p.into()))
.map(|p| (p.key.to_owned(), p.into()))
.collect(),
}
}
}

impl FromStr for crate::Property {
type Err = String;

fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(crate::parser::Property::try_from(s)?.into())
}
}

#[test]
fn test_property() {
assert_parser!(
Expand Down Expand Up @@ -220,7 +242,12 @@ pub fn property<'a, E: ParseError<&'a str> + ContextError<&'a str>>(
context("property sparator", tag(":")), // separator
context(
"property value",
alt((take_until("\r\n"), take_until("\n"))),
alt((
take_until("\r\n"),
take_until("\n"),
// this is for single line prop parsing, just so I can leave off the '\n'
take_while(|_| true),
)),
), // val TODO: replace this with something simpler!
),
context(
Expand Down

0 comments on commit c0ffee2

Please sign in to comment.