jaq_syn/
string.rs

1//! Interpolated strings.
2use alloc::{boxed::Box, string::String, vec::Vec};
3#[cfg(feature = "serde")]
4use serde::{Deserialize, Serialize};
5
6/// A part of an interpolated string.
7#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
8#[derive(Clone, Debug)]
9pub enum Part<T> {
10    /// constant string
11    Str(String),
12    /// interpolated filter
13    Fun(T),
14}
15
16impl<T> Part<T> {
17    /// Apply a function to the contained filters.
18    pub fn map<U>(self, mut f: impl FnMut(T) -> U) -> Part<U> {
19        match self {
20            Self::Str(s) => Part::Str(s),
21            Self::Fun(x) => Part::Fun(f(x)),
22        }
23    }
24
25    /// Returns true if the part is an empty constant string.
26    pub fn is_empty(&self) -> bool {
27        match self {
28            Self::Str(s) => s.is_empty(),
29            Self::Fun(_) => false,
30        }
31    }
32}
33
34/// A possibly interpolated string.
35#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
36#[derive(Clone, Debug)]
37pub struct Str<T> {
38    /// optional filter that is applied to the output of interpolated filters
39    /// (`tostring` if not given)
40    pub fmt: Option<Box<T>>,
41    /// sequence of strings and interpolated filters
42    pub parts: Vec<Part<T>>,
43}
44
45impl<T> Str<T> {
46    /// Apply a function to the contained filters.
47    pub fn map<U>(self, mut f: impl FnMut(T) -> U) -> Str<U> {
48        Str {
49            fmt: self.fmt.map(|fmt| Box::new(f(*fmt))),
50            parts: self.parts.into_iter().map(|p| p.map(&mut f)).collect(),
51        }
52    }
53}
54
55impl<T> From<String> for Str<T> {
56    fn from(s: String) -> Self {
57        Self {
58            fmt: None,
59            parts: Vec::from([Part::Str(s)]),
60        }
61    }
62}