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
mod component;
use std::fmt::Write;
use crate::{
model::{
template::component::Component,
value::Values,
},
process::{
expand::{
Expand,
ExpandError,
},
parse::{
ParseError,
TryParse,
},
},
};
// =============================================================================
// Template
// =============================================================================
// Types
/// The `Template` type is the basis for most simple tasks. Parsing and
/// expansion are both template functions.
#[derive(Debug, Eq, PartialEq)]
pub struct Template<'t> {
components: Vec<Component<'t>>,
}
impl<'t> Template<'t> {
/// Expands the template using the given `Values`, returning a string if
/// expansion was successful.
///
/// ```
/// # use uri_template_system_core::{ Template, Values, Value };
/// #
/// let template = Template::parse("hello/{name}!").unwrap();
/// let values = Values::default().add("name", Value::item("world"));
///
/// assert_eq!("hello/world!", template.expand(&values).unwrap());
pub fn expand(&self, values: &Values) -> Result<String, ExpandError> {
let mut expanded = String::default();
Expand::expand(self, values, &mut expanded)?;
Ok(expanded)
}
/// Parses a string representing a potential template, and returns a new
/// `Template` instance if valid. See <https://datatracker.ietf.org/doc/html/rfc6570>
/// for the grammar of a valid URI Template. `uri-template-system` supports
/// all operators and modifiers up-to and including Level 4.
///
/// ```
/// # use uri_template_system_core::Template;
/// #
/// let template = Template::parse("my/valid/{template}");
///
/// assert!(template.is_ok());
/// ```
pub fn parse(raw: &'t str) -> Result<Self, ParseError> {
Self::try_parse(raw, 0).map(|(_, template)| template)
}
const fn new(components: Vec<Component<'t>>) -> Self {
Self { components }
}
}
// -----------------------------------------------------------------------------
// Parse
impl<'t> TryParse<'t> for Template<'t> {
fn try_parse(raw: &'t str, global: usize) -> Result<(usize, Self), ParseError> {
Vec::<Component<'t>>::try_parse(raw, global)
.map(|(position, components)| (position, Self::new(components)))
}
}
// -----------------------------------------------------------------------------
// Expand
impl<'t> Expand for Template<'t> {
fn expand(&self, values: &Values, write: &mut impl Write) -> Result<(), ExpandError> {
self.components
.iter()
.try_for_each(|component| component.expand(values, write))
}
}