iCalendar_parser 0.1.10

iCalendar (.ical) file parsing and putting into handy structure
Documentation
/// The root rule that matches the entire iCalendar file.
///
/// This rule matches the "BEGIN:VCALENDAR" and "END:VCALENDAR" markers, optionally matches the
/// "METHOD" field, and includes the version, prodid, and a sequence of events.
vc_calendar = { 
    comment* ~  "BEGIN:VCALENDAR" ~ method? ~ ((version  ~ prodid) | (prodid ~ version)) ~ event* ~ "END:VCALENDAR" ~ comment*
}

/// Matches the "VERSION" field in the iCalendar format.
///
/// The version must be followed by a floating-point number (e.g., `2.0`).
version = { "VERSION:" ~ float }

/// Matches the "PRODID" field in the iCalendar format.
///
/// The PRODID field contains the identifier of the software that generated the calendar.
prodid = { "PRODID:" ~ line }

/// Matches an individual "VEVENT" event in the iCalendar format.
///
/// An event is wrapped with "BEGIN:VEVENT" and "END:VEVENT" markers and includes a UID, organizer,
/// start and end datetime, summary, geographical location, and optionally a description.
event = { 
    comment* ~ "BEGIN:VEVENT" ~ uid ~ organizer ~ dtstart ~ dtend ~ summary ~ geo ~ dsc? ~ "END:VEVENT" ~ comment*
}

/// Matches the "UID" field in an event.
///
/// The UID is a unique identifier for the event, usually in the form of an email address.
uid = { "UID:" ~ email_address }

/// Matches the "ORGANIZER" field in an event.
///
/// The organizer is specified with a CN (common name) and an email address.
organizer = { 
    "ORGANIZER;" ~ "CN=" ~ identifier ~ ":" ~ "MAILTO:" ~ email_address 
}

/// Matches the "DTSTART" field in an event.
///
/// The "DTSTART" field specifies the start date and time of the event.
dtstart = { "DTSTART:" ~ datetime }

/// Matches the "DTEND" field in an event.
///
/// The "DTEND" field specifies the end date and time of the event.
dtend = { "DTEND:" ~ datetime }

/// Optionally matches the "DESCRIPTION" field in an event.
///
/// The "DESCRIPTION" field contains a detailed description of the event.
dsc = { "DESCRIPTION:" ~ line }

/// Matches the "SUMMARY" field in an event.
///
/// The "SUMMARY" field contains a brief title or summary of the event.
summary = { "SUMMARY:" ~ line }

/// Matches the "GEO" field in an event.
///
/// The "GEO" field contains the geographical coordinates of the event location in the form of
/// latitude and longitude.
geo = { "GEO:" ~ float ~ "," ~ float }

/// Optionally matches the "METHOD" field in the iCalendar file.
///
/// The "METHOD" field specifies the method of the calendar, such as "PUBLISH" or "REQUEST".
method = @{ "METHOD:" ~ ("PUBLISH" | "REQUEST") }

/// Matches an email address in the format `localpart@domain`.
///
/// The email address is constructed of letters, digits, and special characters like `.`, `_`.
email_address = @{ 
    (letter_or_digit | "." | "_")+ ~ "@" ~ letter_or_digit+ ~ "." ~ letter_or_digit+ 
}

/// Matches a datetime string in the format `YYYYMMDDTHHMMSSZ` (UTC time).
///
/// The datetime is represented with 8 digits for the date and 6 digits for the time, followed by a "Z" for UTC.
datetime = @{ digit{8} ~ "T" ~ digit{6} ~ "Z" }

/// Matches an identifier, which consists of one or more letters or digits.
///
/// An identifier can contain spaces between alphanumeric words.
identifier = @{ letter_or_digit+ ~ (" " ~ letter_or_digit+)* }

/// Matches a floating-point number.
///
/// A float consists of one or more digits, followed by a dot and more digits (e.g., `12.34`).
float = @{ digit+ ~ "." ~ digit+ }

/// Matches a quoted string in the format `"text"`.
///
/// The string may contain any printable character.
quoted_string = @{ "\"" ~ (printable_char ~ ANY)* ~ "\"" }

/// Matches any alphanumeric character (letters or digits).
///
/// This is used for simple alphanumeric matching in identifiers and other fields.
ascii_alphanumeric = @{ ASCII_ALPHANUMERIC }

/// Matches any printable character except control characters.
///
/// This includes characters with Unicode values between U+0020 (space) and U+007A (tilde ~).
printable_char = @{ 
    '\u{20}'..'\u{21}' | '\u{23}'..'\u{5B}' | '\u{5D}'..'\u{7A}' 
}

/// Matches a digit (0-9).
digit = @{ '0'..'9' }

/// Matches any letter (a-z, A-Z) or digit (0-9).
letter_or_digit = @{ 'a'..'z' | 'A'..'Z' | '0'..'9' }

/// Matches a comment, which starts with a semicolon and continues until the end of the line.
///
/// This rule allows for inline comments in the calendar file.
comment =  { ";" ~ line }

/// Matches any whitespace character, including spaces, tabs, newlines, and comments.
///
/// This rule is used to ignore irrelevant whitespace between fields.
WHITESPACE = _{ comment | " " | "\t" | "\n" }

/// Matches a line of text, which can contain letters, digits, spaces, and certain punctuation characters.
///
/// This rule is used to match free-form text like descriptions, summaries, and lines in the calendar file.
line = @{ 
    (letter_or_digit | " " | "-" | "/" | "." | "," | ":")* 
}