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 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
// 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::collections::HashMap;
/// A trait which has to be implemented on any type that will be used to
/// provide replacement values for the placeholder pattern during interpolation.
///
/// # Examples
///
/// Since the trait comes with implementations for [`Vec<E>`] and [`HashMap<String, E>`][`HashMap`],
/// most common cases are already covered and manual implementation of the trait
/// is not needed.
///
/// The consumer may want to implement it in less conventional cases where the replacements
/// are stored in a different data collection.
/// To illustrate such example, we'll use a `HashMap<usize, E>`, a map where keys value and position may
/// be disassociate.
///
/// ```
/// use icu_pattern::{
/// Parser, ParserOptions,
/// Pattern,
/// Interpolator, InterpolatedKind, ReplacementProvider
/// };
/// use std::{
/// collections::HashMap,
/// convert::TryInto,
/// borrow::Cow,
/// };
///
/// #[derive(Debug, PartialEq)]
/// enum Element {
/// TokenZero,
/// TokenFive,
/// }
///
/// impl<'r> ReplacementProvider<'r, Element> for HashMap<usize, Vec<Element>> {
/// type Key = usize;
/// type Iter = std::slice::Iter<'r, Element>;
///
/// fn take_replacement(&'r self, key: &usize) -> Option<Self::Iter> {
/// let replacement = self.get(key)?;
/// Some(replacement.iter())
/// }
/// }
///
/// let mut replacements = HashMap::new();
/// replacements.insert(0, vec![
/// Element::TokenZero
/// ]);
/// replacements.insert(5, vec![
/// Element::TokenFive
/// ]);
///
/// let pattern: Pattern<_> = Parser::new("{5}, {0}", ParserOptions {
/// allow_raw_letters: false
/// }).try_into().unwrap();
/// let mut interpolator = Interpolator::new(&pattern, &replacements);
///
///
/// assert_eq!(Ok(Some(InterpolatedKind::Element(&Element::TokenFive))), interpolator.try_next());
/// assert_eq!(Ok(Some(InterpolatedKind::Literal(&", ".into()))), interpolator.try_next());
/// assert_eq!(Ok(Some(InterpolatedKind::Element(&Element::TokenZero))), interpolator.try_next());
/// assert_eq!(Ok(None), interpolator.try_next());
/// ```
pub trait ReplacementProvider<'r, E: 'r> {
type Key;
type Iter: Iterator<Item = &'r E>;
/// Retrieves a replacement iterator to be used by the [`Interpolator`] in
/// place of a placeholder.
///
/// # Examples
/// ```
/// use icu_pattern::ReplacementProvider;
/// use std::{
/// collections::HashMap,
/// convert::TryInto
/// };
///
/// #[derive(Debug, PartialEq)]
/// enum Element {
/// TokenFive,
/// }
///
/// impl<'r> ReplacementProvider<'r, Element> for HashMap<usize, Vec<Element>> {
/// type Key = usize;
/// type Iter = std::slice::Iter<'r, Element>;
///
/// fn take_replacement(&'r self, key: &usize) -> Option<Self::Iter> {
/// let replacement = self.get(key)?;
/// Some(replacement.iter())
/// }
/// }
///
/// let mut replacements = HashMap::new();
/// replacements.insert(5, vec![
/// Element::TokenFive
/// ]);
///
/// assert_eq!(
/// replacements.take_replacement(&5).map(|r| r.collect()),
/// Some(vec![&Element::TokenFive])
/// );
///
/// assert_eq!(
/// replacements.take_replacement(&1).map(|r| r.collect::<Vec<_>>()),
/// None
/// );
/// ```
///
/// [`Interpolator`]: crate::interpolator::Interpolator
fn take_replacement(&'r self, key: &Self::Key) -> Option<Self::Iter>;
}
impl<'r, E: 'r> ReplacementProvider<'r, E> for Vec<Vec<E>> {
type Key = usize;
type Iter = std::slice::Iter<'r, E>;
fn take_replacement(&'r self, input: &usize) -> Option<Self::Iter> {
let replacement = self.get(*input)?;
Some(replacement.iter())
}
}
impl<'r, E: 'r> ReplacementProvider<'r, E> for Vec<E> {
type Key = usize;
type Iter = std::iter::Once<&'r E>;
fn take_replacement(&'r self, input: &usize) -> Option<Self::Iter> {
let replacement = self.get(*input)?;
Some(std::iter::once(replacement))
}
}
impl<'r, E: 'r> ReplacementProvider<'r, E> for HashMap<String, Vec<E>> {
type Key = String;
type Iter = std::slice::Iter<'r, E>;
fn take_replacement(&'r self, input: &String) -> Option<Self::Iter> {
let replacement = self.get(input)?;
Some(replacement.iter())
}
}
impl<'r, E: 'r> ReplacementProvider<'r, E> for HashMap<String, E> {
type Key = String;
type Iter = std::iter::Once<&'r E>;
fn take_replacement(&'r self, input: &String) -> Option<Self::Iter> {
let replacement = self.get(input)?;
Some(std::iter::once(replacement))
}
}