1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
use memchr::memchr;
use crate::elements::Timestamp;
#[cfg_attr(test, derive(PartialEq))]
#[cfg_attr(feature = "ser", derive(serde::Serialize))]
#[derive(Debug)]
pub struct Planning<'a> {
#[cfg_attr(feature = "ser", serde(skip_serializing_if = "Option::is_none"))]
pub deadline: Option<Timestamp<'a>>,
#[cfg_attr(feature = "ser", serde(skip_serializing_if = "Option::is_none"))]
pub scheduled: Option<Timestamp<'a>>,
#[cfg_attr(feature = "ser", serde(skip_serializing_if = "Option::is_none"))]
pub closed: Option<Timestamp<'a>>,
}
impl Planning<'_> {
#[inline]
pub(crate) fn parse(text: &str) -> Option<(&str, Planning<'_>)> {
let (mut deadline, mut scheduled, mut closed) = (None, None, None);
let (mut tail, off) = memchr(b'\n', text.as_bytes())
.map(|i| (text[..i].trim(), i + 1))
.unwrap_or_else(|| (text.trim(), text.len()));
while let Some(i) = memchr(b' ', tail.as_bytes()) {
let next = &tail[i + 1..].trim_start();
macro_rules! set_timestamp {
($timestamp:expr) => {
if $timestamp.is_none() {
let (new_tail, timestamp) = Timestamp::parse_active(next)
.or_else(|_| Timestamp::parse_inactive(next))
.ok()?;
$timestamp = Some(timestamp);
tail = new_tail.trim_start();
} else {
return None;
}
};
}
match &tail[..i] {
"DEADLINE:" => set_timestamp!(deadline),
"SCHEDULED:" => set_timestamp!(scheduled),
"CLOSED:" => set_timestamp!(closed),
_ => return None,
}
}
if deadline.is_none() && scheduled.is_none() && closed.is_none() {
None
} else {
Some((
&text[off..],
Planning {
deadline,
scheduled,
closed,
},
))
}
}
pub fn into_owned(self) -> Planning<'static> {
Planning {
deadline: self.deadline.map(|x| x.into_owned()),
scheduled: self.scheduled.map(|x| x.into_owned()),
closed: self.closed.map(|x| x.into_owned()),
}
}
}
#[test]
fn prase() {
use crate::elements::Datetime;
assert_eq!(
Planning::parse("SCHEDULED: <2019-04-08 Mon>\n"),
Some((
"",
Planning {
scheduled: Some(Timestamp::Active {
start: Datetime {
year: 2019,
month: 4,
day: 8,
dayname: "Mon".into(),
hour: None,
minute: None
},
repeater: None,
delay: None
}),
deadline: None,
closed: None,
}
))
)
}