ical/tree/codec/mode.rs
1//! # Escaping mode
2//!
3//! The one place the codec consults the calendar version.
4//!
5//! Value escaping differs between vCalendar 1.0 (versit) and iCalendar 2.0
6//! (RFC 5545 3.3.11), and parameter encoding (RFC 6868) exists only from 2.0.
7//!
8//! A value node and a parameter node therefore each carry an [`Escaper`]
9//! telling the sibling [`escape`](crate::tree::codec::escape) and
10//! [`unescape`](crate::tree::codec::unescape) codecs which rules to apply.
11
12use crate::version::IcalVersion;
13
14/// The escaping rules to apply, selected by the calendar version.
15#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
16pub enum Escaper {
17 /// vCalendar 1.0 (versit): `\;` is resolved on read and a backslash before
18 /// anything else is literal; writing also escapes a newline, which versit
19 /// has none of its own for and which raw would end the line.
20 V1_0,
21 /// iCalendar 2.0 (RFC 5545 3.3.11): the value escapes `\\`, `\,`, `\;` and
22 /// `\n`, plus the RFC 6868 parameter value encoding.
23 #[default]
24 Modern,
25}
26
27impl Escaper {
28 /// The escaping rules a calendar of `version` uses.
29 pub fn for_version(version: IcalVersion) -> Self {
30 match version {
31 IcalVersion::V1_0 => Self::V1_0,
32 IcalVersion::V2_0 => Self::Modern,
33 }
34 }
35
36 /// The escaping rules for a raw `VERSION` wire string (e.g. `"1.0"`).
37 pub fn for_version_str(version: &str) -> Self {
38 match version.parse() {
39 Ok(IcalVersion::V1_0) => Self::V1_0,
40 _ => Self::Modern,
41 }
42 }
43
44 /// Whether this version carries the RFC 6868 parameter value encoding,
45 /// which updates RFC 5545 and so reaches iCalendar 2.0 alone: vCalendar 1.0
46 /// predates it, and a caret in one of its parameters is a literal caret.
47 pub fn has_param_encoding(self) -> bool {
48 matches!(self, Self::Modern)
49 }
50
51 /// Whether this version wraps a parameter value carrying a delimiter in
52 /// double quotes: RFC 5545 section 3.1 keeps `,`, `;` and `:` out of a
53 /// bare `paramtext` and gives `quoted-string` for a value that needs one,
54 /// while vCalendar 1.0 has no such production and reads its double quote
55 /// as content.
56 ///
57 /// A different question from [`has_param_encoding`], which is RFC 6868's
58 /// caret encoding, though the two versions this crate knows happen to
59 /// answer both the same way.
60 ///
61 /// [`has_param_encoding`]: Self::has_param_encoding
62 pub fn has_param_quoting(self) -> bool {
63 matches!(self, Self::Modern)
64 }
65}