From a298a1bec4f4458486286d63282e70ae000715e9 Mon Sep 17 00:00:00 2001 From: Ariel Dabalsa Date: Wed, 19 Apr 2017 01:00:33 -0400 Subject: Add CRLF endings and line folding RFC 5545 (section 3.1) --- src/calendar.rs | 14 ++++++------- src/components.rs | 12 +++++------ src/lib.rs | 18 +++++++++++++++++ src/properties.rs | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++----- 4 files changed, 85 insertions(+), 19 deletions(-) diff --git a/src/calendar.rs b/src/calendar.rs index b904999..a6c3660 100644 --- a/src/calendar.rs +++ b/src/calendar.rs @@ -73,17 +73,15 @@ impl Calendar { /// Writes `Calendar` into a `Writer` using `std::fmt`. fn fmt_write(&self, out: &mut W) -> Result<(), fmt::Error> { - writeln!(out, "BEGIN:VCALENDAR")?; - writeln!(out, "VERSION:2.0")?; - writeln!(out, "PRODID:ICALENDAR-RS")?; - writeln!(out, "CALSCALE:GREGORIAN")?; - writeln!(out, "\n")?; + write_crlf!(out, "BEGIN:VCALENDAR")?; + write_crlf!(out, "VERSION:2.0")?; + write_crlf!(out, "PRODID:ICALENDAR-RS")?; + write_crlf!(out, "CALSCALE:GREGORIAN")?; for component in &self.components { component.fmt_write(out)?; - write!(out, "\n")?; } - writeln!(out, "END:VCALENDAR")?; + write_crlf!(out, "END:VCALENDAR")?; Ok(()) } @@ -92,7 +90,7 @@ impl Calendar { pub fn print(&self) -> Result<(), fmt::Error> { let mut out = String::new(); try!(self.fmt_write(&mut out)); - println!("{}", out); + print_crlf!("{}", out); Ok(()) } } diff --git a/src/components.rs b/src/components.rs index 8e9b3fa..0b3ac15 100644 --- a/src/components.rs +++ b/src/components.rs @@ -126,10 +126,10 @@ pub trait Component { /// Writes `Component` into a `Writer` using `std::fmt`. fn fmt_write(&self, out: &mut W) -> Result<(), fmt::Error> { - writeln!(out, "BEGIN:{}", Self::component_kind())?; + write_crlf!(out, "BEGIN:{}", Self::component_kind())?; let now = UTC::now().format("%Y%m%dT%H%M%S"); - writeln!(out, "DTSTAMP:{}", now)?; - writeln!(out, "UID:{}", Uuid::new_v4())?; + write_crlf!(out, "DTSTAMP:{}", now)?; + write_crlf!(out, "UID:{}", Uuid::new_v4())?; for property in self.properties().values() { property.fmt_write(out)?; @@ -139,7 +139,7 @@ pub trait Component { property.fmt_write(out)?; } - writeln!(out, "END:{}", Self::component_kind())?; + write_crlf!(out, "END:{}", Self::component_kind())?; Ok(()) } @@ -222,7 +222,7 @@ pub trait Component { self } - /// Defindes the relative priority. + /// Defines the relative priority. /// /// Ranges from 0 to 10, larger values will be truncated fn priority(&mut self, priority:u32) -> &mut Self { @@ -235,7 +235,7 @@ pub trait Component { fn print(&self) -> Result<(), fmt::Error> { let mut out = String::new(); try!(self.fmt_write(&mut out)); - println!("{}", out); + print_crlf!("{}", out); Ok(()) } diff --git a/src/lib.rs b/src/lib.rs index ffcdb98..d911f06 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -60,6 +60,24 @@ extern crate chrono; extern crate uuid; //extern crate vobject; +macro_rules! print_crlf { + () => (print!("\r\n")); + ($fmt:expr) => (print!(concat!($fmt, "\r\n"))); + ($fmt:expr, $($arg:tt)*) => (print!(concat!($fmt, "\r\n"), $($arg)*)); +} + +macro_rules! write_crlf { + ($dst:expr) => ( + write!($dst, "\r\n") + ); + ($dst:expr, $fmt:expr) => ( + write!($dst, concat!($fmt, "\r\n")) + ); + ($dst:expr, $fmt:expr, $($arg:tt)*) => ( + write!($dst, concat!($fmt, "\r\n"), $($arg)*) + ); +} + //pub mod period; mod components; mod properties; diff --git a/src/properties.rs b/src/properties.rs index 8348cb5..3ab8a6a 100644 --- a/src/properties.rs +++ b/src/properties.rs @@ -1,4 +1,4 @@ -use std::fmt; +use std::fmt::{self, Write}; use std::mem; use std::collections::HashMap; use std::convert::Into; @@ -71,12 +71,16 @@ impl Property { } /// Writes this Property to `out` - pub fn fmt_write(&self, out: &mut W) -> Result<(), fmt::Error> { - try!(write!(out, "{}", self.key)); + pub fn fmt_write(&self, out: &mut W) -> Result<(), fmt::Error> { + // A nice starting capacity for the majority of content lines + let mut line = String::with_capacity(150); + + try!(write!(line, "{}", self.key)); for &Parameter { ref key, ref value } in self.parameters.values() { - try!(write!(out, ";{}={}", key, value)); + try!(write!(line, ";{}={}", key, value)); } - try!(writeln!(out, ":{}", self.value)); + try!(write!(line, ":{}", self.value)); + try!(write_crlf!(out, "{}", fold_line(line))); Ok(()) } } @@ -255,3 +259,49 @@ impl Into for TodoStatus { //impl Into for Attendee { //} + +// Fold a content line as described in RFC 5545, Section 3.1 +fn fold_line(line: String) -> String { + let limit = 75; + let len = line.len(); + let mut ret = String::with_capacity(len + (len / limit * 3)); + let mut bytes_remaining = len; + + let mut pos = 0; + let mut next_pos = limit; + while bytes_remaining > limit { + while line.is_char_boundary(next_pos) == false { + next_pos -= 1; + } + ret.push_str(&line[pos..next_pos]); + ret.push_str("\r\n "); + + bytes_remaining -= next_pos - pos; + pos = next_pos; + next_pos += limit; + } + + ret.push_str(&line[len - bytes_remaining..]); + ret +} + +#[cfg(test)] +mod tests { + use std::string::String; + use super::*; + + #[test] + fn fold_line_short() { + let line = String::from("This is a short line"); + assert_eq!(line.clone(), fold_line(line)); + } + + #[test] + fn fold_line_folds_on_char_boundary() { + let line = String::from("Content lines shouldn't be folded in the middle \ + of a UTF-8 character. 老虎."); + let expected = String::from("Content lines shouldn't be folded in the middle \ + of a UTF-8 character. 老\r\n 虎."); + assert_eq!(expected, fold_line(line)); + } +} -- cgit v1.2.3 From b25578868f47b5d83a7b5d6dd76526daf8bf83fc Mon Sep 17 00:00:00 2001 From: Ariel Dabalsa Date: Thu, 20 Apr 2017 21:39:43 -0400 Subject: Fix failing doctest --- src/lib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index d911f06..f124dda 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -15,6 +15,7 @@ //! # extern crate icalendar; //! # use chrono::*; //! # use icalendar::*; +//! # fn main() { //! let event = Event::new() //! .summary("test event") //! .description("here I have something really important to do") @@ -44,7 +45,7 @@ //! calendar.add(event); //! calendar.add(todo); //! calendar.add(bday); -//! +//! # } //! ``` #![warn(missing_docs, -- cgit v1.2.3