1
#![doc = include_str!("../README.md")]
2

            
3
use crate::parser::Error;
4
use nom::branch::alt;
5
use nom::combinator::recognize;
6
use nom::error::ParseError;
7
use nom::{IResult, Input, Parser};
8
use std::num::NonZeroUsize;
9

            
10
/// Common types.
11
pub mod common;
12

            
13
/// Conversion from the parser model to the core representation.
14
pub mod convert;
15

            
16
/// The core representation that is used for everything except the parser.
17
pub mod model;
18

            
19
/// Common operations.
20
pub mod ops;
21

            
22
/// The iCalendar parser.
23
pub mod parser;
24

            
25
/// The serializer for the core representation back to the iCalendar text format.
26
pub mod serialize;
27

            
28
/// Validation of iCalendar rules against the core representation.
29
pub mod validate;
30

            
31
mod error;
32

            
33
#[cfg(test)]
34
mod test_utils;
35

            
36
/// Prelude which contains everything that's needed for most use-cases to consume this library.
37
pub mod prelude {
38
    pub use crate::common::PropertyKind;
39
    pub use crate::common::*;
40
    pub use crate::error::{AetoliaError, AetoliaResult};
41
    pub use crate::model::access::*;
42
    pub use crate::model::component::*;
43
    pub use crate::model::object::*;
44
    pub use crate::model::param::*;
45
    pub use crate::model::property::*;
46
    pub use crate::ops::{load_ical, read_ical};
47
    pub use crate::parser::{content_line_first_pass, ical_object, ical_stream};
48
    pub use crate::serialize::WriteModel;
49
    pub use crate::validate::{validate_model, ICalendarErrorSeverity};
50
}
51

            
52
/// Streaming, single character matching the predicate
53
84900
pub(crate) fn single<F, In, Output, Error: ParseError<In>>(
54
84900
    cond: F,
55
84900
) -> impl Fn(In) -> IResult<In, Output, Error>
56
84900
where
57
84900
    In: Input<Item = Output>,
58
84900
    F: Fn(<In as Input>::Item) -> bool,
59
84900
    Output: Copy,
60
84900
{
61
37872
    move |i: In| {
62
37872
        match i.iter_elements().next() {
63
37872
            Some(c) if cond(c) => {
64
15116
                let (input, v) = i.take_split(1);
65
15116
                Ok((input, v.iter_elements().next().unwrap()))
66
            }
67
            // Closest error I can get, can't add to the Nom enum!
68
22756
            Some(_) => Err(nom::Err::Error(Error::from_error_kind(
69
22756
                i,
70
22756
                nom::error::ErrorKind::OneOf,
71
22756
            ))),
72
            None => Err(nom::Err::Incomplete(nom::Needed::Size(
73
                NonZeroUsize::new(1).unwrap(),
74
            ))),
75
        }
76
37872
    }
77
84900
}
78

            
79
2478
fn utf8_seq<'a, E>(input: &'a [u8]) -> IResult<&'a [u8], &'a [u8], E>
80
2478
where
81
2478
    E: ParseError<&'a [u8]> + From<Error<'a>>,
82
2478
{
83
2478
    let (input, seq) = alt((
84
2478
        // Utf-8 2-byte sequence
85
2478
        recognize((
86
2478
            single(|b| matches!(b, b'\xC2'..=b'\xDF')),
87
2478
            single(|b| matches!(b, b'\x80'..=b'\xBF')),
88
2478
        )),
89
2478
        // Utf-8 3-byte sequence
90
2478
        alt((
91
2478
            recognize((
92
2478
                single(|b| b == b'\xE0'),
93
2478
                single(|b| matches!(b, b'\xA0'..=b'\xBF')),
94
2478
                single(|b| matches!(b, b'\x80'..=b'\xBF')),
95
2478
            )),
96
2478
            recognize((
97
2478
                single(|b| matches!(b, b'\xE1'..=b'\xEC')),
98
2478
                single(|b| matches!(b, b'\x80'..=b'\xBF')),
99
2478
                single(|b| matches!(b, b'\x80'..=b'\xBF')),
100
2478
            )),
101
2478
            recognize((
102
2478
                single(|b| b == b'\xED'),
103
2478
                single(|b| matches!(b, b'\x80'..=b'\x9F')),
104
2478
                single(|b| matches!(b, b'\x80'..=b'\xBF')),
105
2478
            )),
106
2478
            recognize((
107
2478
                single(|b| matches!(b, b'\xEE'..=b'\xEF')),
108
2478
                single(|b| matches!(b, b'\x80'..=b'\xBF')),
109
2478
                single(|b| matches!(b, b'\x80'..=b'\xBF')),
110
2478
            )),
111
2478
        )),
112
2478
        // Utf-8 4-byte sequence
113
2478
        alt((
114
2478
            recognize((
115
2478
                single(|b| b == b'\xF0'),
116
2478
                single(|b| matches!(b, b'\x90'..=b'\xBF')),
117
2478
                single(|b| matches!(b, b'\x80'..=b'\xBF')),
118
2478
                single(|b| matches!(b, b'\x80'..=b'\xBF')),
119
2478
            )),
120
2478
            recognize((
121
2478
                single(|b| matches!(b, b'\xF1'..=b'\xF3')),
122
2478
                single(|b| matches!(b, b'\x80'..=b'\xBF')),
123
2478
                single(|b| matches!(b, b'\x80'..=b'\xBF')),
124
2478
                single(|b| matches!(b, b'\x80'..=b'\xBF')),
125
2478
            )),
126
2478
            recognize((
127
2478
                single(|b| b == b'\xF4'),
128
2478
                single(|b| matches!(b, b'\x80'..=b'\x8F')),
129
2478
                single(|b| matches!(b, b'\x80'..=b'\xBF')),
130
2478
                single(|b| matches!(b, b'\x80'..=b'\xBF')),
131
2478
            )),
132
2478
        )),
133
2478
    ))
134
2478
    .parse(input)?;
135

            
136
8
    Ok((input, seq))
137
2478
}
138

            
139
#[cfg(test)]
140
mod tests {
141
    use super::*;
142
    use nom::multi::many1;
143

            
144
    #[test]
145
2
    fn valid_utf8() {
146
2
        let (rem, seq) = utf8_seq::<Error>("👍".as_bytes()).unwrap();
147
2
        test_utils::check_rem(rem, 0);
148
2
        assert_eq!(seq, "👍".as_bytes());
149
2
    }
150

            
151
    #[test]
152
2
    fn invalid_utf8() {
153
2
        let mut input = "👍👌".as_bytes().to_vec();
154
2
        input.extend_from_slice(&[1, 3, 4, 5, 2, 1]);
155
2
        let (rem, seq) = many1(utf8_seq::<Error>).parse(input.as_slice()).unwrap();
156
2
        test_utils::check_rem(rem, 6);
157
2
        assert_eq!(
158
2
            seq.into_iter().flatten().cloned().collect::<Vec<_>>(),
159
2
            "👍👌".as_bytes().to_vec()
160
2
        );
161
2
    }
162
}