use std::{borrow::Cow, fmt, iter::Peekable};
use serde_derive::Serialize;
#[derive(Clone)]
pub enum Span<'a> {
Content { text: Cow<'a, str>, token: FmtToken },
Child(&'a dyn TokenFmt<'a>),
}
impl<'a> Span<'a> {
pub fn new(text: impl Into<Cow<'a, str>>, token: FmtToken) -> Span<'a> {
Span::Content {
text: text.into(),
token,
}
}
pub fn plain(text: impl Into<Cow<'a, str>>) -> Span<'a> {
Span::new(text, FmtToken::Plain)
}
pub fn error(text: impl Into<Cow<'a, str>>) -> Span<'a> {
Span::new(text, FmtToken::Error)
}
pub fn unit(text: impl Into<Cow<'a, str>>) -> Span<'a> {
Span::new(text, FmtToken::Unit)
}
pub fn quantity(text: impl Into<Cow<'a, str>>) -> Span<'a> {
Span::new(text, FmtToken::Quantity)
}
pub fn number(text: impl Into<Cow<'a, str>>) -> Span<'a> {
Span::new(text, FmtToken::Number)
}
pub fn prop_name(text: impl Into<Cow<'a, str>>) -> Span<'a> {
Span::new(text, FmtToken::PropName)
}
pub fn user_input(text: impl Into<Cow<'a, str>>) -> Span<'a> {
Span::new(text, FmtToken::UserInput)
}
pub fn list_begin(text: impl Into<Cow<'a, str>>) -> Span<'a> {
Span::new(text, FmtToken::ListBegin)
}
pub fn list_sep(text: impl Into<Cow<'a, str>>) -> Span<'a> {
Span::new(text, FmtToken::ListSep)
}
pub fn doc_string(text: impl Into<Cow<'a, str>>) -> Span<'a> {
Span::new(text, FmtToken::DocString)
}
pub fn pow(text: impl Into<Cow<'a, str>>) -> Span<'a> {
Span::new(text, FmtToken::Pow)
}
pub fn date_time(text: impl Into<Cow<'a, str>>) -> Span<'a> {
Span::new(text, FmtToken::DateTime)
}
pub fn child(obj: &'a dyn TokenFmt<'a>) -> Span<'a> {
Span::Child(obj)
}
pub fn link(text: impl Into<Cow<'a, str>>) -> Span<'a> {
Span::new(text, FmtToken::Link)
}
pub fn keyword(text: impl Into<Cow<'a, str>>) -> Span<'a> {
Span::new(text, FmtToken::Keyword)
}
pub fn timezone(text: impl Into<Cow<'a, str>>) -> Span<'a> {
Span::new(text, FmtToken::TimeZone)
}
pub fn is_ws(&self) -> bool {
if let Span::Content { text, .. } = self {
text.ends_with(" ")
} else {
false
}
}
}
impl<'a> fmt::Debug for Span<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Span::Content { text, token } => write!(f, "({:?}, {:?})", text, token),
Span::Child(obj) => {
let spans = obj.to_spans();
spans.fmt(f)
}
}
}
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash, Serialize)]
#[serde(rename_all = "snake_case")]
#[non_exhaustive]
pub enum FmtToken {
Plain,
Error,
Unit,
Quantity,
Number,
UserInput,
ListBegin,
ListSep,
DocString,
Pow,
PropName,
DateTime,
Link,
Keyword,
TimeZone,
}
impl FmtToken {
pub fn as_str(self) -> &'static str {
match self {
FmtToken::Plain => "plain",
FmtToken::Error => "error",
FmtToken::Unit => "unit",
FmtToken::Quantity => "quantity",
FmtToken::Number => "number",
FmtToken::UserInput => "user_input",
FmtToken::ListBegin => "list_begin",
FmtToken::ListSep => "list_sep",
FmtToken::DocString => "doc_string",
FmtToken::Pow => "pow",
FmtToken::PropName => "prop_name",
FmtToken::DateTime => "date_time",
FmtToken::Link => "link",
FmtToken::Keyword => "keyword",
FmtToken::TimeZone => "time_zone",
}
}
}
pub(crate) fn write_spans_string(out: &mut String, spans: &[Span]) {
for span in spans {
match span {
Span::Content { text, .. } => out.push_str(text),
Span::Child(child) => write_spans_string(out, &child.to_spans()),
}
}
}
pub trait TokenFmt<'a> {
fn to_spans(&'a self) -> Vec<Span<'a>>;
fn spans_to_string(&'a self) -> String {
let mut string = String::new();
write_spans_string(&mut string, &self.to_spans());
string
}
fn display(&'a self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
for span in self.to_spans() {
match span {
Span::Content { text, .. } => write!(fmt, "{}", text)?,
Span::Child(child) => child.display(fmt)?,
}
}
Ok(())
}
}
pub(crate) struct JoinIter<'a, I>
where
I: Iterator,
{
iter: Peekable<I>,
sep: Span<'a>,
last_was_sep: bool,
}
pub(crate) fn join<'a, I>(iter: I, sep: Span<'a>) -> impl Iterator<Item = Span<'a>>
where
I: Iterator<Item = Span<'a>>,
{
JoinIter {
iter: iter.peekable(),
sep,
last_was_sep: true,
}
}
impl<'a, I> Iterator for JoinIter<'a, I>
where
I: Iterator<Item = Span<'a>>,
{
type Item = Span<'a>;
fn next(&mut self) -> Option<Self::Item> {
if self.iter.peek().is_some() {
if self.last_was_sep {
self.last_was_sep = false;
self.iter.next()
} else {
self.last_was_sep = true;
Some(self.sep.clone())
}
} else {
None
}
}
}
pub(crate) struct FlatJoinIter<'a, I, I2>
where
I: Iterator<Item = I2>,
I2: IntoIterator<Item = Span<'a>>,
{
iter: Peekable<I>,
sep: Span<'a>,
last_was_sep: bool,
current: Option<I2::IntoIter>,
}
pub(crate) fn flat_join<'a, I, I2>(iter: I, sep: Span<'a>) -> impl Iterator<Item = Span<'a>>
where
I: Iterator<Item = I2>,
I2: IntoIterator<Item = Span<'a>>,
{
FlatJoinIter {
iter: iter.peekable(),
sep,
last_was_sep: true,
current: None,
}
}
impl<'a, I, I2> Iterator for FlatJoinIter<'a, I, I2>
where
I: Iterator<Item = I2>,
I2: IntoIterator<Item = Span<'a>>,
{
type Item = Span<'a>;
fn next(&mut self) -> Option<Self::Item> {
if let Some(ref mut current) = self.current {
if let Some(next) = current.next() {
return Some(next);
}
}
if self.iter.peek().is_some() {
if self.last_was_sep {
self.last_was_sep = false;
let mut new_current = self.iter.next().unwrap().into_iter();
let next = new_current.next();
self.current = Some(new_current);
next
} else {
self.last_was_sep = true;
Some(self.sep.clone())
}
} else {
None
}
}
}