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