chore: make the fields of Planning struct public

This commit is contained in:
PoiScript 2019-04-11 23:53:43 +08:00
parent c2c554a3d5
commit 9c82b268d6
5 changed files with 231 additions and 190 deletions

View file

@ -76,152 +76,158 @@ pub enum Timestamp<'a> {
Diary(&'a str),
}
pub fn parse_active(text: &str) -> Option<(Timestamp<'_>, usize)> {
debug_assert!(text.starts_with('<'));
impl<'a> Timestamp<'a> {
pub(crate) fn parse_active(text: &str) -> Option<(Timestamp<'_>, usize)> {
debug_assert!(text.starts_with('<'));
let bytes = text.as_bytes();
let mut off = memchr(b'>', bytes)?;
let (start, mut end) = parse_datetime(&bytes[1..off])?;
if end.is_none()
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("--<")
{
if let Some(new_off) = memchr(b'>', &bytes[off + 1..]) {
if let Some((start, _)) = parse_datetime(&bytes[off + 4..off + 1 + new_off]) {
end = Some(start);
off += new_off + 1;
{
if let Some(new_off) = memchr(b'>', &bytes[off + 1..]) {
if let Some((start, _)) = Self::parse_datetime(&bytes[off + 4..off + 1 + new_off]) {
end = Some(start);
off += new_off + 1;
}
}
}
Some((
if let Some(end) = end {
Timestamp::ActiveRange {
start,
end,
repeater: None,
delay: None,
}
} else {
Timestamp::Active {
start,
repeater: None,
delay: None,
}
},
off + 1,
))
}
Some((
if let Some(end) = end {
Timestamp::ActiveRange {
start,
end,
repeater: None,
delay: None,
}
} else {
Timestamp::Active {
start,
repeater: None,
delay: None,
}
},
off + 1,
))
}
pub(crate) fn parse_inactive(text: &str) -> Option<(Timestamp<'_>, usize)> {
debug_assert!(text.starts_with('['));
pub fn parse_inactive(text: &str) -> Option<(Timestamp<'_>, usize)> {
debug_assert!(text.starts_with('['));
let bytes = text.as_bytes();
let mut off = memchr(b']', bytes)?;
let (start, mut end) = parse_datetime(&bytes[1..off])?;
if end.is_none()
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("--[")
{
if let Some(new_off) = memchr(b']', &bytes[off + 1..]) {
if let Some((start, _)) = parse_datetime(&bytes[off + 4..off + 1 + new_off]) {
end = Some(start);
off += new_off + 1;
{
if let Some(new_off) = memchr(b']', &bytes[off + 1..]) {
if let Some((start, _)) = Self::parse_datetime(&bytes[off + 4..off + 1 + new_off]) {
end = Some(start);
off += new_off + 1;
}
}
}
Some((
if let Some(end) = end {
Timestamp::InactiveRange {
start,
end,
repeater: None,
delay: None,
}
} else {
Timestamp::Inactive {
start,
repeater: None,
delay: None,
}
},
off + 1,
))
}
Some((
if let Some(end) = end {
Timestamp::InactiveRange {
start,
end,
repeater: None,
delay: None,
}
} else {
Timestamp::Inactive {
start,
repeater: None,
delay: None,
}
},
off + 1,
))
}
fn parse_datetime(bytes: &[u8]) -> Option<(Datetime, Option<Datetime>)> {
if bytes.is_empty()
|| !bytes[0].is_ascii_digit()
|| !bytes[bytes.len() - 1].is_ascii_alphanumeric()
{
return None;
}
fn parse_datetime(bytes: &[u8]) -> Option<(Datetime, Option<Datetime>)> {
if bytes.is_empty()
|| !bytes[0].is_ascii_digit()
|| !bytes[bytes.len() - 1].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());
// similar to str::split_ascii_whitespace, but for &[u8]
let mut words = bytes
.split(u8::is_ascii_whitespace)
.filter(|s| !s.is_empty());
let date = words
.next()
.filter(|word| {
word.len() == 10 /* YYYY-MM-DD */
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)
})
.map(|word| {
(
(u16::from(word[0]) - u16::from(b'0')) * 1000
+ (u16::from(word[1]) - u16::from(b'0')) * 100
+ (u16::from(word[2]) - u16::from(b'0')) * 10
+ (u16::from(word[3]) - u16::from(b'0')),
(word[5] - b'0') * 10 + (word[6] - b'0'),
(word[8] - b'0') * 10 + (word[9] - b'0'),
)
})
.map(|word| {
(
(u16::from(word[0]) - u16::from(b'0')) * 1000
+ (u16::from(word[1]) - u16::from(b'0')) * 100
+ (u16::from(word[2]) - u16::from(b'0')) * 10
+ (u16::from(word[3]) - u16::from(b'0')),
(word[5] - b'0') * 10 + (word[6] - b'0'),
(word[8] - b'0') * 10 + (word[9] - b'0'),
)
})?;
let _dayname = words.next().filter(|word| {
word.iter().all(|&c| {
!(c == b'+'
|| c == b'-'
|| c == b']'
|| c == b'>'
|| c.is_ascii_digit()
|| c == b'\n')
})
})?;
let _dayname = words.next().filter(|word| {
word.iter().all(|&c| {
!(c == b'+' || c == b'-' || c == b']' || c == b'>' || c.is_ascii_digit() || c == b'\n')
})
})?;
let (start, end) = if let Some(word) = words.next() {
macro_rules! datetime {
($a:expr, $b:expr, $c:expr) => {
Datetime {
date,
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,
time: Some((
(word[$a] - b'0') * 10 + (word[$b] - b'0'),
(word[$c] - b'0') * 10 + (word[$d] - b'0'),
)),
}
};
}
let (start, end) = if let Some(word) = words.next() {
macro_rules! datetime {
($a:expr, $b:expr, $c:expr) => {
Datetime {
date,
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,
time: Some((
(word[$a] - b'0') * 10 + (word[$b] - b'0'),
(word[$c] - b'0') * 10 + (word[$d] - b'0'),
)),
}
};
}
if word.len() == 4 // H:MM
if word.len() == 4 // H:MM
&& word[0].is_ascii_digit()
&& word[1] == b':'
&& word[2..4].iter().all(u8::is_ascii_digit)
{
(datetime!(0, 2, 3), None)
} else if word.len() == 5 // HH: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)
{
(datetime!(0, 1, 3, 4), None)
} else if word.len() == 9 // H:MM-H: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)
@ -229,9 +235,9 @@ fn parse_datetime(bytes: &[u8]) -> Option<(Datetime, Option<Datetime>)> {
&& word[5].is_ascii_digit()
&& word[6] == b':'
&& word[7..9].iter().all(u8::is_ascii_digit)
{
(datetime!(0, 2, 3), Some(datetime!(5, 7, 8)))
} else if word.len() == 10 // H:MM-HH: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)
@ -239,9 +245,9 @@ fn parse_datetime(bytes: &[u8]) -> Option<(Datetime, Option<Datetime>)> {
&& word[5..7].iter().all(u8::is_ascii_digit)
&& word[7] == b':'
&& word[8..10].iter().all(u8::is_ascii_digit)
{
(datetime!(0, 2, 3), Some(datetime!(5, 6, 8, 9)))
} else if word.len() == 10 // HH:MM-H: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)
@ -249,9 +255,9 @@ fn parse_datetime(bytes: &[u8]) -> Option<(Datetime, Option<Datetime>)> {
&& word[6].is_ascii_digit()
&& word[7] == b':'
&& word[8..10].iter().all(u8::is_ascii_digit)
{
(datetime!(0, 1, 3, 4), Some(datetime!(6, 8, 9)))
} else if word.len() == 11 // HH:MM-HH: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)
@ -259,37 +265,38 @@ fn parse_datetime(bytes: &[u8]) -> Option<(Datetime, Option<Datetime>)> {
&& word[6..8].iter().all(u8::is_ascii_digit)
&& word[8] == b':'
&& word[9..11].iter().all(u8::is_ascii_digit)
{
(datetime!(0, 1, 3, 4), Some(datetime!(6, 7, 9, 10)))
{
(datetime!(0, 1, 3, 4), Some(datetime!(6, 7, 9, 10)))
} else {
return None;
}
} else {
(Datetime { date, time: None }, None)
};
// TODO: repeater and delay
if words.next().is_some() {
None
} else {
Some((start, end))
}
}
pub(crate) fn parse_diary(text: &str) -> Option<(Timestamp<'_>, usize)> {
debug_assert!(text.starts_with('<'));
if text.len() <= 6 /* <%%()> */ || &text[1..4] != "%%(" {
return None;
}
} else {
(Datetime { date, time: None }, None)
};
// TODO: repeater and delay
if words.next().is_some() {
None
} else {
Some((start, end))
let bytes = text.as_bytes();
memchr(b'>', bytes)
.filter(|i| bytes[i - 1] == b')' && bytes[4..i - 1].iter().all(|&c| c != b'\n'))
.map(|i| (Timestamp::Diary(&text[4..i - 1]), i))
}
}
pub fn parse_diary(text: &str) -> Option<(Timestamp<'_>, usize)> {
debug_assert!(text.starts_with('<'));
if text.len() <= 6 /* <%%()> */ || &text[1..4] != "%%(" {
return None;
}
let bytes = text.as_bytes();
memchr(b'>', bytes)
.filter(|i| bytes[i - 1] == b')' && bytes[4..i - 1].iter().all(|&c| c != b'\n'))
.map(|i| (Timestamp::Diary(&text[4..i - 1]), i))
}
#[cfg(test)]
mod tests {
#[test]
@ -297,7 +304,7 @@ mod tests {
use super::*;
assert_eq!(
parse_inactive("[2003-09-16 Tue]"),
Timestamp::parse_inactive("[2003-09-16 Tue]"),
Some((
Timestamp::Inactive {
start: Datetime {
@ -311,7 +318,7 @@ mod tests {
))
);
assert_eq!(
parse_inactive("[2003-09-16 Tue 09:39]--[2003-09-16 Tue 10:39]"),
Timestamp::parse_inactive("[2003-09-16 Tue 09:39]--[2003-09-16 Tue 10:39]"),
Some((
Timestamp::InactiveRange {
start: Datetime {
@ -329,7 +336,7 @@ mod tests {
))
);
assert_eq!(
parse_active("<2003-09-16 Tue 09:39-10:39>"),
Timestamp::parse_active("<2003-09-16 Tue 09:39-10:39>"),
Some((
Timestamp::ActiveRange {
start: Datetime {
@ -353,7 +360,7 @@ mod tests {
use super::*;
assert_eq!(
parse_datetime(b"2003-09-16 Tue"),
Timestamp::parse_datetime(b"2003-09-16 Tue"),
Some((
Datetime {
date: (2003, 9, 16),
@ -363,7 +370,7 @@ mod tests {
))
);
assert_eq!(
parse_datetime(b"2003-09-16 Tue 9:39"),
Timestamp::parse_datetime(b"2003-09-16 Tue 9:39"),
Some((
Datetime {
date: (2003, 9, 16),
@ -373,7 +380,7 @@ mod tests {
))
);
assert_eq!(
parse_datetime(b"2003-09-16 Tue 09:39"),
Timestamp::parse_datetime(b"2003-09-16 Tue 09:39"),
Some((
Datetime {
date: (2003, 9, 16),
@ -383,7 +390,7 @@ mod tests {
))
);
assert_eq!(
parse_datetime(b"2003-09-16 Tue 9:39-10:39"),
Timestamp::parse_datetime(b"2003-09-16 Tue 9:39-10:39"),
Some((
Datetime {
date: (2003, 9, 16),
@ -396,9 +403,9 @@ mod tests {
))
);
assert_eq!(parse_datetime(b"2003-9-16 Tue"), None);
assert_eq!(parse_datetime(b"2003-09-16"), None);
assert_eq!(parse_datetime(b"2003-09-16 09:39"), None);
assert_eq!(parse_datetime(b"2003-09-16 Tue 0939"), None);
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);
}
}