use std::iter::FromIterator; #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct InterpolatedText { head: String, tail: Vec<(SubExpr, String)>, } impl From<(String, Vec<(SubExpr, String)>)> for InterpolatedText { fn from(x: (String, Vec<(SubExpr, String)>)) -> Self { InterpolatedText { head: x.0, tail: x.1, } } } impl From for InterpolatedText { fn from(s: String) -> Self { InterpolatedText { head: s, tail: vec![], } } } #[derive(Debug, Clone, PartialEq, Eq)] pub enum InterpolatedTextContents { Text(String), Expr(SubExpr), } impl InterpolatedTextContents { pub fn is_empty(&self) -> bool { use InterpolatedTextContents::{Expr, Text}; match self { Expr(_) => false, Text(s) => s.is_empty(), } } pub fn traverse_ref<'a, SubExpr2, E, F>( &'a self, mut f: F, ) -> Result, E> where F: FnMut(&'a SubExpr) -> Result, { use InterpolatedTextContents::{Expr, Text}; Ok(match self { Expr(e) => Expr(f(e)?), Text(s) => Text(s.clone()), }) } pub fn map_ref<'a, SubExpr2, F>( &'a self, mut f: F, ) -> InterpolatedTextContents where F: FnMut(&'a SubExpr) -> SubExpr2, { use InterpolatedTextContents::{Expr, Text}; match self { Expr(e) => Expr(f(e)), Text(s) => Text(s.clone()), } } } impl InterpolatedText { pub fn len(&self) -> usize { 1 + 2 * self.tail.len() } pub fn head(&self) -> &str { &self.head } pub fn tail(&self) -> &Vec<(SubExpr, String)> { &self.tail } pub fn head_mut(&mut self) -> &mut String { &mut self.head } pub fn is_empty(&self) -> bool { self.head.is_empty() && self.tail.is_empty() } pub fn traverse_ref<'a, SubExpr2, E, F>( &'a self, mut f: F, ) -> Result, E> where F: FnMut(&'a SubExpr) -> Result, { Ok(InterpolatedText { head: self.head.clone(), tail: self .tail .iter() .map(|(e, s)| Ok((f(e)?, s.clone()))) .collect::>()?, }) } pub fn iter<'a>( &'a self, ) -> impl Iterator> + 'a { use std::iter::once; use InterpolatedTextContents::{Expr, Text}; let exprs = self.tail.iter().map(|(e, _)| Expr(e)); let texts = self.tail.iter().map(|(_, s)| Text(s.clone())); once(Text(self.head.clone())).chain(itertools::interleave(exprs, texts)) } pub fn into_iter( self, ) -> impl Iterator> { use std::iter::once; use InterpolatedTextContents::{Expr, Text}; once(Text(self.head)).chain( self.tail .into_iter() .flat_map(|(e, s)| once(Expr(e)).chain(once(Text(s)))), ) } } impl FromIterator> for InterpolatedText { fn from_iter(iter: T) -> Self where T: IntoIterator>, { let mut res = InterpolatedText { head: String::new(), tail: Vec::new(), }; let mut crnt_str = &mut res.head; for x in iter.into_iter() { match x { InterpolatedTextContents::Text(s) => crnt_str.push_str(&s), InterpolatedTextContents::Expr(e) => { res.tail.push((e, String::new())); crnt_str = &mut res.tail.last_mut().unwrap().1; } } } res } }