1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
// 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 ).

//! `icu_pattern` is a utility crate of the [`ICU4X`] project.
//!
//! It includes a [`Pattern`] struct which wraps a paid of [`Parser`] and [`Interpolator`] allowing for parsing and interpolation of ICU placeholder patterns, like "{0} days" or
//! "{0}, {1}" with custom elements and string literals.
//!
//! # Placeholders & Elements
//!
//! The [`Parser`] is generic over any `Placeholder` which implements [`FromStr`]
//! allowing the consumer to parse placeholder patterns such as "{0}, {1}",
//! "{date}, {time}" or any other.
//!
//! The [`Interpolator`] can interpolate the [`Pattern`] against any
//! iterator over `Element`.
//!
//! # Examples
//!
//! In the following example we're going to use a custom `Token` type,
//! and an `Element` type which will be either a `Token` or a string slice.
//!
//! For the purpose of the example, a higher level
//! [`interpolate_to_string`](Pattern::interpolate_to_string) method
//! is being used.
//!
//! ```
//! use icu_pattern::Pattern;
//! use std::{
//!     convert::TryInto,
//!     borrow::Cow,
//!     fmt::Display,
//! };
//!
//! #[derive(Debug, PartialEq)]
//! enum ExampleToken {
//!     Year,
//!     Month,
//!     Day,
//!     Hour,
//!     Minute
//! }
//!
//! impl Display for ExampleToken {
//!     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
//!         write!(f, "[{:?}]", self)
//!     }
//! }
//!
//! #[derive(Debug, PartialEq)]
//! enum ExampleElement<'s> {
//!     Token(ExampleToken),
//!     Literal(Cow<'s, str>),
//! }
//!
//! impl Display for ExampleElement<'_> {
//!     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
//!         match self {
//!             Self::Token(token) => token.fmt(f),
//!             Self::Literal(lit) => lit.fmt(f),
//!         }
//!     }
//! }
//!
//! let pattern: Pattern<usize> = "{0}, {1}".try_into()
//!     .expect("Failed to parse a pattern.");
//!
//! let replacements = vec![
//!     vec![
//!         ExampleElement::Token(ExampleToken::Year),
//!         ExampleElement::Literal("-".into()),
//!         ExampleElement::Token(ExampleToken::Month),
//!         ExampleElement::Literal("-".into()),
//!         ExampleElement::Token(ExampleToken::Day),
//!     ],
//!     vec![
//!         ExampleElement::Token(ExampleToken::Hour),
//!         ExampleElement::Literal(":".into()),
//!         ExampleElement::Token(ExampleToken::Minute),
//!     ],
//! ];
//!
//! assert_eq!(
//!     pattern.interpolate_to_string::<ExampleElement, _>(&replacements)
//!         .expect("Failed to interpolate a pattern."),
//!
//!     "[Year]-[Month]-[Day], [Hour]:[Minute]"
//! );
//! ```
//!
//! # Combinators
//!
//! In the example above, the replacements will be parsed at compile time and stored on a [`Vec`],
//! which is a collection type that has an implementation for [`ReplacementProvider`]
//! trait.
//!
//! In real use, the consumer may want to use different models of replacement provider,
//! and different element schemas.
//! Because the replacement is an iterator itself, it allows for other, more specialized parsers,
//! to be used to lazily parse particular patterns that are meant to replace the placeholders.
//! This allows for lazy parsing of those specialized patterns to be triggered
//! only if the placeholder pattern encounters a placeholder key that requires given
//! pattern to be used.
//!
//! [`ICU4X`]: ../icu/index.html
//! [`FromStr`]: std::str::FromStr

// https://github.com/unicode-org/icu4x/blob/main/docs/process/boilerplate.md#library-annotations
#![cfg_attr(
    not(test),
    deny(
        clippy::indexing_slicing,
        clippy::unwrap_used,
        clippy::expect_used,
        clippy::panic
    )
)]

mod interpolator;
mod parser;
mod pattern;
mod replacement;
mod token;

pub use interpolator::{InterpolatedKind, Interpolator, InterpolatorError};
pub use parser::{Parser, ParserError, ParserOptions};
pub use pattern::{InterpolatedPattern, Pattern, PatternError};
pub use replacement::ReplacementProvider;
pub use token::PatternToken;