From 0101612029eae39dd4785e3c0c8d0c0ec097e1a0 Mon Sep 17 00:00:00 2001 From: PoiScript Date: Fri, 12 Apr 2019 22:19:07 +0800 Subject: [PATCH] docs: some doc comments --- src/elements/clock.rs | 24 +++-- src/elements/mod.rs | 3 + src/elements/planning.rs | 22 ++-- src/lib.rs | 1 + src/objects/mod.rs | 3 + src/objects/target.rs | 6 +- src/objects/timestamp.rs | 224 +++++++++++++++++++++++---------------- src/parser.rs | 15 +++ src/tools.rs | 4 +- 9 files changed, 182 insertions(+), 120 deletions(-) diff --git a/src/elements/clock.rs b/src/elements/clock.rs index 4465d9f..ca55234 100644 --- a/src/elements/clock.rs +++ b/src/elements/clock.rs @@ -1,18 +1,23 @@ use crate::objects::timestamp::{Datetime, Delay, Repeater, Timestamp}; use memchr::memchr; +/// clock elements +/// +/// there are two types of clock: *closed* clock and *running* clock. #[cfg_attr(test, derive(PartialEq))] #[derive(Debug)] pub enum Clock<'a> { + /// closed Clock Closed { - start: Datetime, - end: Datetime, + start: Datetime<'a>, + end: Datetime<'a>, repeater: Option, delay: Option, duration: &'a str, }, + /// running Clock Running { - start: Datetime, + start: Datetime<'a>, repeater: Option, delay: Option, }, @@ -88,6 +93,7 @@ impl<'a> Clock<'a> { None } + /// returns `true` if the clock is running pub fn is_running(&self) -> bool { match self { Clock::Closed { .. } => false, @@ -95,6 +101,7 @@ impl<'a> Clock<'a> { } } + /// returns `true` if the clock is closed pub fn is_closed(&self) -> bool { match self { Clock::Closed { .. } => true, @@ -102,6 +109,7 @@ impl<'a> Clock<'a> { } } + /// returns `Some` if the clock is closed, `None` if running pub fn duration(&self) -> Option<&'a str> { match self { Clock::Closed { duration, .. } => Some(duration), @@ -109,6 +117,7 @@ impl<'a> Clock<'a> { } } + /// constructs a new timestamp object from the clock pub fn value(&self) -> Timestamp<'_> { match *self { Clock::Closed { @@ -150,7 +159,8 @@ mod tests { Clock::Running { start: Datetime { date: (2003, 9, 16), - time: Some((9, 39)) + time: Some((9, 39)), + dayname: "Tue" }, repeater: None, delay: None, @@ -164,11 +174,13 @@ mod tests { Clock::Closed { start: Datetime { date: (2003, 9, 16), - time: Some((9, 39)) + time: Some((9, 39)), + dayname: "Tue" }, end: Datetime { date: (2003, 9, 16), - time: Some((10, 39)) + time: Some((10, 39)), + dayname: "Tue" }, repeater: None, delay: None, diff --git a/src/elements/mod.rs b/src/elements/mod.rs index 953d0d7..61261eb 100644 --- a/src/elements/mod.rs +++ b/src/elements/mod.rs @@ -1,3 +1,6 @@ +/// elements +/// +/// elements means some syntactical parts that have the same level with paragraph. pub(crate) mod block; pub(crate) mod clock; pub(crate) mod drawer; diff --git a/src/elements/planning.rs b/src/elements/planning.rs index 8cb6015..5b42485 100644 --- a/src/elements/planning.rs +++ b/src/elements/planning.rs @@ -1,11 +1,15 @@ use crate::objects::timestamp::Timestamp; use memchr::memchr; +/// palnning elements #[cfg_attr(test, derive(PartialEq))] #[derive(Debug)] pub struct Planning<'a> { + /// the date when the task should be done pub deadline: Option>, + /// the date when you should start working on the task pub scheduled: Option>, + /// the date when the task is closed pub closed: Option>, } @@ -22,18 +26,9 @@ impl<'a> Planning<'a> { macro_rules! set_timestamp { ($timestamp:expr) => { if $timestamp.is_none() { - if next.starts_with('<') { - let (timestamp, off) = Timestamp::parse_active(next) - .or_else(|| Timestamp::parse_diary(next))?; - $timestamp = Some(timestamp); - tail = &next[off..].trim_start(); - } else if next.starts_with('<') { - let (timestamp, off) = Timestamp::parse_active(next)?; - $timestamp = Some(timestamp); - tail = &next[off..].trim_start(); - } else { - return None; - } + let (timestamp, off) = Timestamp::parse(next)?; + $timestamp = Some(timestamp); + tail = &next[off..].trim_start(); } else { return None; } @@ -77,7 +72,8 @@ mod tests { scheduled: Some(Timestamp::Active { start: Datetime { date: (2019, 4, 8), - time: None + time: None, + dayname: "Mon" }, repeater: None, delay: None diff --git a/src/lib.rs b/src/lib.rs index ae6c32d..efb0b59 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -90,6 +90,7 @@ //! let result = String::from_utf8(cursor.into_inner()).expect("invalid utf-8"); //! ``` +#[warn(missing_docs)] pub mod elements; pub mod export; pub mod headline; diff --git a/src/objects/mod.rs b/src/objects/mod.rs index 81b0465..81be4a8 100644 --- a/src/objects/mod.rs +++ b/src/objects/mod.rs @@ -1,3 +1,6 @@ +/// objects +/// +/// objects is something that included in an element. pub(crate) mod cookie; pub(crate) mod emphasis; pub(crate) mod fn_ref; diff --git a/src/objects/target.rs b/src/objects/target.rs index 4bb8203..d1d8286 100644 --- a/src/objects/target.rs +++ b/src/objects/target.rs @@ -6,7 +6,7 @@ pub fn parse(text: &str) -> Option<(&str, usize)> { let bytes = text.as_bytes(); - let (target, off) = Substring::new(">>") + Substring::new(">>") .find(text) .filter(|&i| { bytes[2] != b' ' @@ -15,9 +15,7 @@ pub fn parse(text: &str) -> Option<(&str, usize)> { .iter() .all(|&c| c != b'<' && c != b'\n' && c != b'>') }) - .map(|i| (&text[2..i], i + 2 /* >> */))?; - - Some((target, off)) + .map(|i| (&text[2..i], i + 2 /* >> */)) } #[cfg(test)] diff --git a/src/objects/timestamp.rs b/src/objects/timestamp.rs index 45e54d3..22e6813 100644 --- a/src/objects/timestamp.rs +++ b/src/objects/timestamp.rs @@ -2,9 +2,10 @@ use memchr::memchr; #[cfg_attr(test, derive(PartialEq))] #[derive(Debug, Clone, Copy)] -pub struct Datetime { +pub struct Datetime<'a> { pub date: (u16, u8, u8), pub time: Option<(u8, u8)>, + pub dayname: &'a str, } #[cfg_attr(test, derive(PartialEq))] @@ -48,28 +49,29 @@ pub struct Delay { pub unit: TimeUnit, } +/// timestamp obejcts #[cfg_attr(test, derive(PartialEq))] #[derive(Debug)] pub enum Timestamp<'a> { Active { - start: Datetime, + start: Datetime<'a>, repeater: Option, delay: Option, }, Inactive { - start: Datetime, + start: Datetime<'a>, repeater: Option, delay: Option, }, ActiveRange { - start: Datetime, - end: Datetime, + start: Datetime<'a>, + end: Datetime<'a>, repeater: Option, delay: Option, }, InactiveRange { - start: Datetime, - end: Datetime, + start: Datetime<'a>, + end: Datetime<'a>, repeater: Option, delay: Option, }, @@ -77,18 +79,27 @@ pub enum Timestamp<'a> { } impl<'a> Timestamp<'a> { - pub(crate) fn parse_active(text: &str) -> Option<(Timestamp<'_>, usize)> { + pub(crate) fn parse(text: &'a str) -> Option<(Timestamp<'a>, usize)> { + if text.starts_with('<') { + Timestamp::parse_active(text).or_else(|| Timestamp::parse_diary(text)) + } else if text.starts_with('[') { + Timestamp::parse_inactive(text) + } else { + None + } + } + + pub(crate) fn parse_active(text: &'a str) -> Option<(Timestamp<'a>, usize)> { debug_assert!(text.starts_with('<')); let bytes = text.as_bytes(); let mut off = memchr(b'>', bytes)?; - let (start, mut end) = Self::parse_datetime(&bytes[1..off])?; - if end.is_none() - && off <= text.len() - 14 /* -- */ - && text[off + 1..].starts_with("--<") + let (start, mut end) = Self::parse_datetime(&text[1..off])?; + + if end.is_none() && off <= text.len() - 14 /* -- */ && text[off + 1..].starts_with("--<") { if let Some(new_off) = memchr(b'>', &bytes[off + 1..]) { - if let Some((start, _)) = Self::parse_datetime(&bytes[off + 4..off + 1 + new_off]) { + if let Some((start, _)) = Self::parse_datetime(&text[off + 4..off + 1 + new_off]) { end = Some(start); off += new_off + 1; } @@ -114,18 +125,16 @@ impl<'a> Timestamp<'a> { )) } - pub(crate) fn parse_inactive(text: &str) -> Option<(Timestamp<'_>, usize)> { + pub(crate) fn parse_inactive(text: &'a str) -> Option<(Timestamp<'a>, usize)> { debug_assert!(text.starts_with('[')); let bytes = text.as_bytes(); let mut off = memchr(b']', bytes)?; - let (start, mut end) = Self::parse_datetime(&bytes[1..off])?; - if end.is_none() - && off <= text.len() - 14 /* --[YYYY-MM-DD] */ - && text[off + 1..].starts_with("--[") + let (start, mut end) = Self::parse_datetime(&text[1..off])?; + if end.is_none() && off <= text.len() - 14 /* --[YYYY-MM-DD] */ && text[off + 1..].starts_with("--[") { if let Some(new_off) = memchr(b']', &bytes[off + 1..]) { - if let Some((start, _)) = Self::parse_datetime(&bytes[off + 4..off + 1 + new_off]) { + if let Some((start, _)) = Self::parse_datetime(&text[off + 4..off + 1 + new_off]) { end = Some(start); off += new_off + 1; } @@ -151,30 +160,30 @@ impl<'a> Timestamp<'a> { )) } - fn parse_datetime(bytes: &[u8]) -> Option<(Datetime, Option)> { - if bytes.is_empty() - || !bytes[0].is_ascii_digit() - || !bytes[bytes.len() - 1].is_ascii_alphanumeric() + fn parse_datetime(text: &'a str) -> Option<(Datetime<'a>, Option>)> { + if text.is_empty() + || !text.starts_with(|c: char| c.is_ascii_digit()) + || !text.ends_with(|c: char| c.is_ascii_alphanumeric()) { return None; } - // similar to str::split_ascii_whitespace, but for &[u8] - let mut words = bytes - .split(u8::is_ascii_whitespace) - .filter(|s| !s.is_empty()); + let mut words = text.split_ascii_whitespace(); let date = words .next() .filter(|word| { - word.len() == 10 /* YYYY-MM-DD */ - && word[0..4].iter().all(u8::is_ascii_digit) - && word[4] == b'-' - && word[5..7].iter().all(u8::is_ascii_digit) - && word[7] == b'-' - && word[8..10].iter().all(u8::is_ascii_digit) + let word = word.as_bytes(); + // YYYY-MM-DD + word.len() == 10 + && word[0..4].iter().all(u8::is_ascii_digit) + && word[4] == b'-' + && word[5..7].iter().all(u8::is_ascii_digit) + && word[7] == b'-' + && word[8..10].iter().all(u8::is_ascii_digit) }) .map(|word| { + let word = word.as_bytes(); ( (u16::from(word[0]) - u16::from(b'0')) * 1000 + (u16::from(word[1]) - u16::from(b'0')) * 100 @@ -185,8 +194,8 @@ impl<'a> Timestamp<'a> { ) })?; - let _dayname = words.next().filter(|word| { - word.iter().all(|&c| { + let dayname = words.next().filter(|word| { + word.as_bytes().iter().all(|&c| { !(c == b'+' || c == b'-' || c == b']' @@ -197,16 +206,20 @@ impl<'a> Timestamp<'a> { })?; let (start, end) = if let Some(word) = words.next() { + let word = word.as_bytes(); + macro_rules! datetime { ($a:expr, $b:expr, $c:expr) => { Datetime { date, + dayname, time: Some((word[$a] - b'0', (word[$b] - b'0') * 10 + (word[$c] - b'0'))), } }; ($a:expr, $b:expr, $c:expr, $d:expr) => { Datetime { date, + dayname, time: Some(( (word[$a] - b'0') * 10 + (word[$b] - b'0'), (word[$c] - b'0') * 10 + (word[$d] - b'0'), @@ -215,63 +228,76 @@ impl<'a> Timestamp<'a> { }; } - if word.len() == 4 // H:MM - && word[0].is_ascii_digit() - && word[1] == b':' - && word[2..4].iter().all(u8::is_ascii_digit) + if word.len() == 4 + && word[0].is_ascii_digit() + && word[1] == b':' + && word[2..4].iter().all(u8::is_ascii_digit) { + // H:MM (datetime!(0, 2, 3), None) - } else if word.len() == 5 // HH:MM - && word[0..2].iter().all(u8::is_ascii_digit) - && word[2] == b':' - && word[3..5].iter().all(u8::is_ascii_digit) + } else if word.len() == 5 + && word[0..2].iter().all(u8::is_ascii_digit) + && word[2] == b':' + && word[3..5].iter().all(u8::is_ascii_digit) { + // HH:MM (datetime!(0, 1, 3, 4), None) - } else if word.len() == 9 // H:MM-H:MM - && word[0].is_ascii_digit() - && word[1] == b':' - && word[2..4].iter().all(u8::is_ascii_digit) - && word[4] == b'-' - && word[5].is_ascii_digit() - && word[6] == b':' - && word[7..9].iter().all(u8::is_ascii_digit) + } else if word.len() == 9 + && word[0].is_ascii_digit() + && word[1] == b':' + && word[2..4].iter().all(u8::is_ascii_digit) + && word[4] == b'-' + && word[5].is_ascii_digit() + && word[6] == b':' + && word[7..9].iter().all(u8::is_ascii_digit) { + // H:MM-H:MM (datetime!(0, 2, 3), Some(datetime!(5, 7, 8))) - } else if word.len() == 10 // H:MM-HH:MM - && word[0].is_ascii_digit() - && word[1] == b':' - && word[2..4].iter().all(u8::is_ascii_digit) - && word[4] == b'-' - && word[5..7].iter().all(u8::is_ascii_digit) - && word[7] == b':' - && word[8..10].iter().all(u8::is_ascii_digit) + } else if word.len() == 10 + && word[0].is_ascii_digit() + && word[1] == b':' + && word[2..4].iter().all(u8::is_ascii_digit) + && word[4] == b'-' + && word[5..7].iter().all(u8::is_ascii_digit) + && word[7] == b':' + && word[8..10].iter().all(u8::is_ascii_digit) { + // H:MM-HH:MM (datetime!(0, 2, 3), Some(datetime!(5, 6, 8, 9))) - } else if word.len() == 10 // HH:MM-H:MM - && word[0..2].iter().all(u8::is_ascii_digit) - && word[2] == b':' - && word[3..5].iter().all(u8::is_ascii_digit) - && word[5] == b'-' - && word[6].is_ascii_digit() - && word[7] == b':' - && word[8..10].iter().all(u8::is_ascii_digit) + } else if word.len() == 10 + && word[0..2].iter().all(u8::is_ascii_digit) + && word[2] == b':' + && word[3..5].iter().all(u8::is_ascii_digit) + && word[5] == b'-' + && word[6].is_ascii_digit() + && word[7] == b':' + && word[8..10].iter().all(u8::is_ascii_digit) { + // HH:MM-H:MM (datetime!(0, 1, 3, 4), Some(datetime!(6, 8, 9))) - } else if word.len() == 11 // HH:MM-HH:MM - && word[0..2].iter().all(u8::is_ascii_digit) - && word[2] == b':' - && word[3..5].iter().all(u8::is_ascii_digit) - && word[5] == b'-' - && word[6..8].iter().all(u8::is_ascii_digit) - && word[8] == b':' - && word[9..11].iter().all(u8::is_ascii_digit) + } else if word.len() == 11 + && word[0..2].iter().all(u8::is_ascii_digit) + && word[2] == b':' + && word[3..5].iter().all(u8::is_ascii_digit) + && word[5] == b'-' + && word[6..8].iter().all(u8::is_ascii_digit) + && word[8] == b':' + && word[9..11].iter().all(u8::is_ascii_digit) { + // HH:MM-HH:MM (datetime!(0, 1, 3, 4), Some(datetime!(6, 7, 9, 10))) } else { return None; } } else { - (Datetime { date, time: None }, None) + ( + Datetime { + date, + dayname, + time: None, + }, + None, + ) }; // TODO: repeater and delay @@ -309,7 +335,8 @@ mod tests { Timestamp::Inactive { start: Datetime { date: (2003, 9, 16), - time: None + time: None, + dayname: "Tue" }, repeater: None, delay: None, @@ -323,11 +350,13 @@ mod tests { Timestamp::InactiveRange { start: Datetime { date: (2003, 9, 16), - time: Some((9, 39)) + time: Some((9, 39)), + dayname: "Tue" }, end: Datetime { date: (2003, 9, 16), - time: Some((10, 39)) + time: Some((10, 39)), + dayname: "Tue" }, repeater: None, delay: None @@ -341,11 +370,13 @@ mod tests { Timestamp::ActiveRange { start: Datetime { date: (2003, 9, 16), - time: Some((9, 39)) + time: Some((9, 39)), + dayname: "Tue" }, end: Datetime { date: (2003, 9, 16), - time: Some((10, 39)) + time: Some((10, 39)), + dayname: "Tue" }, repeater: None, delay: None @@ -360,52 +391,57 @@ mod tests { use super::*; assert_eq!( - Timestamp::parse_datetime(b"2003-09-16 Tue"), + Timestamp::parse_datetime("2003-09-16 Tue"), Some(( Datetime { date: (2003, 9, 16), - time: None + time: None, + dayname: "Tue" }, None )) ); assert_eq!( - Timestamp::parse_datetime(b"2003-09-16 Tue 9:39"), + Timestamp::parse_datetime("2003-09-16 Tue 9:39"), Some(( Datetime { date: (2003, 9, 16), - time: Some((9, 39)) + time: Some((9, 39)), + dayname: "Tue" }, None )) ); assert_eq!( - Timestamp::parse_datetime(b"2003-09-16 Tue 09:39"), + Timestamp::parse_datetime("2003-09-16 Tue 09:39"), Some(( Datetime { date: (2003, 9, 16), - time: Some((9, 39)) + time: Some((9, 39)), + dayname: "Tue" }, None )) ); assert_eq!( - Timestamp::parse_datetime(b"2003-09-16 Tue 9:39-10:39"), + Timestamp::parse_datetime("2003-09-16 Tue 9:39-10:39"), Some(( Datetime { date: (2003, 9, 16), - time: Some((9, 39)) + time: Some((9, 39)), + dayname: "Tue" }, Some(Datetime { date: (2003, 9, 16), - time: Some((10, 39)) + time: Some((10, 39)), + dayname: "Tue" }), )) ); - assert_eq!(Timestamp::parse_datetime(b"2003-9-16 Tue"), None); - assert_eq!(Timestamp::parse_datetime(b"2003-09-16"), None); - assert_eq!(Timestamp::parse_datetime(b"2003-09-16 09:39"), None); - assert_eq!(Timestamp::parse_datetime(b"2003-09-16 Tue 0939"), None); + assert_eq!(Timestamp::parse_datetime("2003-9-16 Tue"), None); + assert_eq!(Timestamp::parse_datetime("2003-09-16"), None); + assert_eq!(Timestamp::parse_datetime("2003-09-16 09:39"), None); + assert_eq!(Timestamp::parse_datetime("2003-09-16 Tue 0939"), None); } } diff --git a/src/parser.rs b/src/parser.rs index 48ba347..6059024 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -185,6 +185,19 @@ impl<'a> Parser<'a> { } } + /// creates a new parser from string, with the specified keywords + pub fn with_keywrods(text: &'a str, keywords: &'a [&'a str]) -> Parser<'a> { + Parser { + text, + stack: Vec::new(), + next_item: Vec::new(), + off: 0, + ele_buf: None, + obj_buf: None, + keywords, + } + } + /// returns current offset pub fn offset(&self) -> usize { self.off @@ -195,10 +208,12 @@ impl<'a> Parser<'a> { self.stack.len() } + /// set keywords pub fn set_keywords(&mut self, keywords: &'a [&'a str]) { self.keywords = keywords; } + /// set text pub fn set_text(&mut self, text: &'a str) { self.off = 0; self.stack.clear(); diff --git a/src/tools.rs b/src/tools.rs index d9f1282..fcd8254 100644 --- a/src/tools.rs +++ b/src/tools.rs @@ -7,9 +7,7 @@ type Keywords<'a> = Vec<(Key<'a>, &'a str)>; type Footnotes<'a> = Vec<&'a str>; pub fn metadata(src: &str) -> (Headlines<'_>, Keywords<'_>, Footnotes<'_>) { - let mut headlines = Vec::new(); - let mut keywords = Vec::new(); - let mut footnotes = Vec::new(); + let (mut headlines, mut keywords, mut footnotes) = (Vec::new(), Vec::new(), Vec::new()); for line in src.lines().filter(|l| !l.is_empty()) { if line.starts_with('*') {