//! This crates provides support for parsing a subset of [RFC 2822].
//! In particular, it exports functions that parse a string according
//! to the [`name-addr`] production, and the [`addr-spec`] production.
//!
//! This crate does not yet parse [RFC 2822] [`dates and times`] or
//! [`message headers`]. Given the infrastructure, adding support for
//! these productions should be straightforward. However, the main
//! user of this crate is [Sequoia], an [OpenPGP implementation], and
//! it only uses this crate to parse [User IDs], which usually include
//! an [RFC 2822] mail [`name-addr`]. If you require this
//! functionality, please feel free to open an [issue].
//!
//! [RFC 2822]: https://tools.ietf.org/html/rfc2822
//! [`name-addr`]: https://tools.ietf.org/html/rfc2822#section-3.4
//! [`addr-spec`]: https://tools.ietf.org/html/rfc2822#section-3.4.1
//! [`dates and times`]: https://tools.ietf.org/html/rfc2822#section-3.3
//! [`message headers`]: https://tools.ietf.org/html/rfc2822#section-3.6
//! [Sequoia]: https://sequoia-pgp.org/
//! [OpenPGP implementation]: https://tools.ietf.org/html/rfc4880
//! [User IDs]: https://tools.ietf.org/html/rfc4880#section-5.11
//! [issue]: https://gitlab.com/sequoia-pgp/sequoia/issues
//!
//! # Examples
//!
//! Parsing a [`name-addr`]:
//!
//! ```
//! use sequoia_rfc2822::NameAddr;
//!
//! let nameaddr = NameAddr::parse(
//! "Professor Pippy P. Poopypants <pippy@jerome-horwitz.k12.oh.us>")
//! .expect("Valid name-addr");
//! assert_eq!(nameaddr.name(), Some("Professor Pippy P. Poopypants"));
//! assert_eq!(nameaddr.comment(), None);
//! assert_eq!(nameaddr.address(), Some("pippy@jerome-horwitz.k12.oh.us"));
//!
//! // Extra angle brackets.
//! assert!(NameAddr::parse("Invalid <<pippy@jerome-horwitz.k12.oh.us>>")
//! .is_err());
//!
//! // No angle brackets.
//! assert!(NameAddr::parse("pippy@jerome-horwitz.k12.oh.us")
//! .is_err());
//! ```
//!
//! Parsing an [`addr-spec`]:
//!
//! ```
//! use sequoia_rfc2822::AddrSpec;
//!
//! let addrspec = AddrSpec::parse(
//! "pippy@jerome-horwitz.k12.oh.us")
//! .expect("Valid addr-spec");
//! assert_eq!(addrspec.address(), "pippy@jerome-horwitz.k12.oh.us");
//!
//! // Angle brackets are not allowed.
//! assert!(AddrSpec::parse("<pippy@jerome-horwitz.k12.oh.us>")
//! .is_err());
//! ```
extern crate failure;
extern crate lalrpop_util;
#[cfg(test)] #[macro_use] extern crate lazy_static;
#[cfg(test)] #[macro_use] extern crate quickcheck;
#[cfg(test)] extern crate rand;
use lalrpop_util::ParseError;
#[macro_use] mod macros;
#[macro_use] mod trace;
mod strings;
#[macro_use] mod component;
use component::{
Component
};
mod lexer;
// We expose a number of productions for testing purposes.
// Unfortunately, lalrpop doesn't understand the #[cfg(test)]
// attribute. So, to avoid warnings, we allow unused imports and dead
// code when not testing.
#[cfg(test)]
mod grammar;
#[cfg(not(test))]
#[allow(unused_imports, dead_code)]
mod grammar;
#[cfg(test)]
mod roundtrip;
const TRACE : bool = false;
pub type Result<T> = ::std::result::Result<T, Error>;
pub type Error = failure::Error;
// A failure needs to have a 'static life time. lexer::Tokens don't.
// Convert tokens into strings.
//
// Unfortunately, we can't implement From, because we don't define the
// ParseError in this crate.
fn parse_error_downcast<'a>(e: ParseError<usize, lexer::Token<'a>, Error>)
-> ParseError<usize, String, Error>
{
match e {
ParseError::UnrecognizedToken {
token: Some((start, t, end)),
expected,
} => ParseError::UnrecognizedToken {
token: Some((start, t<