diff --git a/Cargo.lock b/Cargo.lock index d8d89502edf..1eb7a7205b0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3564,7 +3564,7 @@ checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" [[package]] name = "tzif" -version = "0.1.0" +version = "0.2.0" dependencies = [ "combine", "walkdir", diff --git a/utils/tzif/Cargo.toml b/utils/tzif/Cargo.toml index a43ef95eb5f..6dc51c8206f 100644 --- a/utils/tzif/Cargo.toml +++ b/utils/tzif/Cargo.toml @@ -5,12 +5,14 @@ [package] name = "tzif" authors = ["The ICU4X Project Developers"] -version = "0.1.0" +description = "A parser for TZif files" +version = "0.2.0" edition = "2021" readme = "README.md" license-file = "LICENSE" repository = "https://github.com/unicode-org/icu4x" keywords = ["time-zone", "posix", "iana", "parse", "data"] +categories = ["date-and-time", "parser-implementations"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/utils/tzif/README.md b/utils/tzif/README.md index ffd74ab15f9..2b8385972f2 100644 --- a/utils/tzif/README.md +++ b/utils/tzif/README.md @@ -12,26 +12,12 @@ Resources to generate `TZif` files are provided by the [IANA database](https://w #### Parse TZif Files ```rust -use combine::{Parser, stream}; -use std::fs::File; -use tzif::tzif; - -let file = File::open("path_to_file").unwrap(); -let stream = stream::buffered::Stream::new( - stream::position::Stream::new(stream::read::Stream::new(file)), - 0, /* lookahead */ -); -let data = tzif().parse(stream).unwrap(); +let data = tzif::parse_tzif_file("path_to_file").unwrap(); ``` #### Parse POSIX time-zone strings ```rust -use combine::Parser; -use tzif::posix_tz_string; - -let data = posix_tz_string() - .parse(b"WGT3WGST,M3.5.0/-2,M10.5.0/-1".as_slice()) - .unwrap(); +let data = tzif::parse_posix_tz_string(b"WGT3WGST,M3.5.0/-2,M10.5.0/-1").unwrap(); ``` ## More Information diff --git a/utils/tzif/src/error.rs b/utils/tzif/src/error.rs new file mode 100644 index 00000000000..a1fc0ec0249 --- /dev/null +++ b/utils/tzif/src/error.rs @@ -0,0 +1,46 @@ +// This file is part of ICU4X. For terms of use, please see the file +// called LICENSE at the top level of the ICU4X source tree +// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). + +use std::fmt; + +/// An error enum for all error types. +#[derive(Debug)] +pub enum Error { + /// A [`std::io::Error`]. + Io(std::io::Error), + /// A [`combine::stream::read::Error`]. + Read(combine::stream::read::Error), + /// A [`combine::error::UnexpectedParse`]. + Parse(combine::error::UnexpectedParse), +} + +impl From for Error { + fn from(err: std::io::Error) -> Self { + Error::Io(err) + } +} + +impl From for Error { + fn from(err: combine::stream::read::Error) -> Self { + Error::Read(err) + } +} + +impl From for Error { + fn from(err: combine::error::UnexpectedParse) -> Self { + Error::Parse(err) + } +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Error::Io(err) => write!(f, "{}", err), + Error::Read(err) => write!(f, "{}", err), + Error::Parse(err) => write!(f, "{}", err), + } + } +} + +impl std::error::Error for Error {} diff --git a/utils/tzif/src/lib.rs b/utils/tzif/src/lib.rs index 2510ce0f567..8422daf2ddf 100644 --- a/utils/tzif/src/lib.rs +++ b/utils/tzif/src/lib.rs @@ -14,35 +14,42 @@ //! //! ### Parse TZif Files //! ```no_run -//! use combine::{Parser, stream}; -//! use std::fs::File; -//! use tzif::tzif; -//! -//! let file = File::open("path_to_file").unwrap(); -//! let stream = stream::buffered::Stream::new( -//! stream::position::Stream::new(stream::read::Stream::new(file)), -//! 0, /* lookahead */ -//! ); -//! let data = tzif().parse(stream).unwrap(); +//! let data = tzif::parse_tzif_file("path_to_file").unwrap(); //! ``` //! //! ### Parse POSIX time-zone strings //! ```rust -//! use combine::Parser; -//! use tzif::posix_tz_string; -//! -//! let data = posix_tz_string() -//! .parse(b"WGT3WGST,M3.5.0/-2,M10.5.0/-1".as_slice()) -//! .unwrap(); +//! let data = tzif::parse_posix_tz_string(b"WGT3WGST,M3.5.0/-2,M10.5.0/-1").unwrap(); //! ``` #![warn(missing_docs)] +use combine::{stream, Parser}; +use data::{posix::PosixTzString, tzif::TzifData}; +use error::Error; +use std::fs::File; +use std::path::Path; + /// The parsed data representations. pub mod data; /// The parser implementations. pub mod parse; -pub use parse::posix::posix_tz_string; -pub use parse::tzif::tzif; +/// Error types an implementations. +pub mod error; + +/// Parses a `TZif` file at the provided `path`. +pub fn parse_tzif_file>(path: P) -> Result { + let file = File::open(path)?; + let stream = stream::buffered::Stream::new( + stream::position::Stream::new(stream::read::Stream::new(file)), + 0, /* lookahead */ + ); + Ok(parse::tzif::tzif().parse(stream)?.0) +} + +/// Parses a POSIX time-zone string from the given bytes. +pub fn parse_posix_tz_string(bytes: &[u8]) -> Result { + Ok(parse::posix::posix_tz_string().parse(bytes)?.0) +} diff --git a/utils/tzif/tests/mod.rs b/utils/tzif/tests/mod.rs index e69767786c0..349c601eef1 100644 --- a/utils/tzif/tests/mod.rs +++ b/utils/tzif/tests/mod.rs @@ -2,37 +2,28 @@ // called LICENSE at the top level of the ICU4X source tree // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). -use combine::{stream, Parser}; -use std::{fs::File, path::Path}; -use tzif::parse::posix::posix_tz_string; -use tzif::parse::tzif::tzif; +use std::path::Path; use walkdir::WalkDir; -fn parse_tzif_file>(path: P) { +fn parse_tzif_file>(path: P) -> Result<(), tzif::error::Error> { println!("parsing {:?}", path.as_ref().to_str()); - let file = File::open(path).unwrap(); - let stream = stream::buffered::Stream::new( - stream::position::Stream::new(stream::read::Stream::new(file)), - 0, /* lookahead */ - ); - let parsed = tzif().parse(stream); - assert!(parsed.is_ok()); - println!("{:#?}", parsed.unwrap().0); + let parsed = tzif::parse_tzif_file(path)?; + println!("{:#?}", parsed); + Ok(()) } #[test] -fn parse_tzif_testdata() { +fn parse_tzif_testdata() -> Result<(), tzif::error::Error> { for entry in WalkDir::new("testdata").follow_links(true) { let entry = entry.unwrap(); if entry.file_type().is_file() { - parse_tzif_file(entry.path()) + parse_tzif_file(entry.path())? } } + Ok(()) } #[test] fn parse_posix_tz_string() { - assert!(posix_tz_string() - .parse(b"WGT3WGST,M3.5.0/-2,M10.5.0/-1".as_slice()) - .is_ok()); + assert!(tzif::parse_posix_tz_string(b"WGT3WGST,M3.5.0/-2,M10.5.0/-1").is_ok()); }