Skip to main content

iri_string/
template.rs

1//! Processor for [RFC 6570] URI Template.
2//!
3//! [RFC 6570]: https://www.rfc-editor.org/rfc/rfc6570.html
4//!
5//! # Usage
6//!
7//! 1. Prepare a template.
8//!     * You can create a template as [`UriTemplateStr`]
9#![cfg_attr(
10    feature = "alloc",
11    doc = "      type (borrowed) or [`UriTemplateString`] type (owned)."
12)]
13#![cfg_attr(not(feature = "alloc"), doc = "      type.")]
14//! 2. Prepare a context.
15//!     * Create a value of type that implements [`Context`] trait.
16#![cfg_attr(
17    feature = "alloc",
18    doc = "    * Or, if you use [`SimpleContext`], insert key-value pairs into it."
19)]
20//! 3. Expand.
21//!     * Pass the context to [`UriTemplateStr::expand`] method of the template.
22//! 4. Use the result.
23//!     * Returned [`Expanded`] object can be directly printed since it
24//!       implements [`Display`][`core::fmt::Display`] trait. Or, you can call
25//!       `.to_string()` method of the `alloc::string::ToString` trait to
26//!       convert it to a `String`.
27//!
28//! # Examples
29//!
30//! ## Custom context type
31//!
32//! For details, see [the documentation of `context` module][`context`].
33//!
34//! ```
35//! # use iri_string::template::Error;
36//! use core::fmt;
37//! use iri_string::spec::{IriSpec, Spec, UriSpec};
38//! use iri_string::template::UriTemplateStr;
39//! use iri_string::template::context::{Context, VarName, Visitor};
40//!
41//! struct UserInfo {
42//!     username: &'static str,
43//!     utf8_available: bool,
44//! }
45//!
46//! impl Context for UserInfo {
47//!     fn visit<V: Visitor>(
48//!         &self,
49//!         visitor: V,
50//!     ) -> V::Result {
51//!         match visitor.var_name().as_str() {
52//!             "username" => visitor.visit_string(self.username),
53//!             "utf8" => {
54//!                 if self.utf8_available {
55//!                     // U+2713 CHECK MARK
56//!                     visitor.visit_string("\u{2713}")
57//!                 } else {
58//!                     visitor.visit_undefined()
59//!                 }
60//!             }
61//!             _ => visitor.visit_undefined()
62//!         }
63//!     }
64//! }
65//!
66//! let context = UserInfo {
67//!     username: "foo",
68//!     utf8_available: true,
69//! };
70//!
71//! let template = UriTemplateStr::new("/users/{username}{?utf8}")?;
72//!
73//! # #[cfg(feature = "alloc")] {
74//! assert_eq!(
75//!     template.expand::<UriSpec, _>(&context)?.to_string(),
76//!     "/users/foo?utf8=%E2%9C%93"
77//! );
78//! assert_eq!(
79//!     template.expand::<IriSpec, _>(&context)?.to_string(),
80//!     "/users/foo?utf8=\u{2713}"
81//! );
82//! # }
83//! # Ok::<_, Error>(())
84//! ```
85//!
86//! ## `SimpleContext` type (enabled by `alloc` feature flag)
87//!
88//! ```
89//! # use iri_string::template::Error;
90//! # #[cfg(feature = "alloc")] {
91//! use iri_string::spec::{IriSpec, UriSpec};
92//! use iri_string::template::UriTemplateStr;
93//! use iri_string::template::simple_context::SimpleContext;
94//!
95//! let mut context = SimpleContext::new();
96//! context.insert("username", "foo");
97//! // U+2713 CHECK MARK
98//! context.insert("utf8", "\u{2713}");
99//!
100//! let template = UriTemplateStr::new("/users/{username}{?utf8}")?;
101//!
102//! assert_eq!(
103//!     template.expand::<UriSpec, _>(&context)?.to_string(),
104//!     "/users/foo?utf8=%E2%9C%93"
105//! );
106//! assert_eq!(
107//!     template.expand::<IriSpec, _>(&context)?.to_string(),
108//!     "/users/foo?utf8=\u{2713}"
109//! );
110//! # }
111//! # Ok::<_, Error>(())
112//! ```
113//!
114#![cfg_attr(
115    feature = "alloc",
116    doc = "[`SimpleContext`]: `simple_context::SimpleContext`"
117)]
118mod components;
119#[macro_use]
120pub mod context;
121mod error;
122mod expand;
123mod parser;
124#[cfg(feature = "alloc")]
125pub mod simple_context;
126mod string;
127mod value;
128
129pub use self::context::{Context, DynamicContext};
130#[cfg(feature = "alloc")]
131pub use self::error::CreationError;
132pub use self::error::Error;
133pub use self::expand::Expanded;
134#[cfg(feature = "alloc")]
135pub use self::string::UriTemplateString;
136pub use self::string::{UriTemplateStr, UriTemplateVariables};
137
138/// Deprecated old name of [`template::context::VarName`].
139///
140/// [`template::context::VarName`]: `components::VarName`
141#[deprecated(
142    since = "0.7.1",
143    note = "renamed (moved) to `template::context::VarName`"
144)]
145pub type VarName<'a> = self::components::VarName<'a>;
146
147/// Variable value type.
148#[derive(Debug, Clone, Copy)]
149enum ValueType {
150    /// Undefined (i.e. null).
151    Undefined,
152    /// String value.
153    String,
154    /// List.
155    List,
156    /// Associative array.
157    Assoc,
158}
159
160impl ValueType {
161    /// Returns the value type for an undefined variable.
162    #[inline]
163    #[must_use]
164    pub const fn undefined() -> Self {
165        ValueType::Undefined
166    }
167
168    /// Returns the value type for a string variable.
169    #[inline]
170    #[must_use]
171    pub const fn string() -> Self {
172        ValueType::String
173    }
174
175    /// Returns the value type for an empty list variable.
176    #[inline]
177    #[must_use]
178    pub const fn empty_list() -> Self {
179        ValueType::Undefined
180    }
181
182    /// Returns the value type for a nonempty list variable.
183    #[inline]
184    #[must_use]
185    pub const fn nonempty_list() -> Self {
186        ValueType::List
187    }
188
189    /// Returns the value type for an empty associative array variable.
190    #[inline]
191    #[must_use]
192    pub const fn empty_assoc() -> Self {
193        ValueType::Undefined
194    }
195
196    /// Returns the value type for a nonempty associative array variable.
197    #[inline]
198    #[must_use]
199    pub const fn nonempty_assoc() -> Self {
200        ValueType::Assoc
201    }
202}