use crate::Conjunction;
use core::{
cell::Cell,
fmt,
};
pub struct JoinFmt<'a, I: Iterator>
where <I as Iterator>::Item: fmt::Display {
iter: Cell<Option<I>>,
glue: &'a str,
}
impl<'a, I: Iterator> JoinFmt<'a, I>
where <I as Iterator>::Item: fmt::Display {
#[inline]
pub const fn new(iter: I, glue: &'a str) -> Self {
Self {
iter: Cell::new(Some(iter)),
glue,
}
}
}
impl<I: Iterator> fmt::Display for JoinFmt<'_, I>
where <I as Iterator>::Item: fmt::Display {
#[inline]
#[track_caller]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut iter = self.iter.take().ok_or(fmt::Error)?;
if self.glue.is_empty() {
for v in iter { <I::Item as fmt::Display>::fmt(&v, f)?; }
}
else if let Some(v) = iter.next() {
<I::Item as fmt::Display>::fmt(&v, f)?;
for v in iter {
f.write_str(self.glue)?;
<I::Item as fmt::Display>::fmt(&v, f)?;
}
}
Ok(())
}
}
pub struct OxfordJoinFmt<'a, T: fmt::Display> {
inner: &'a [T],
glue: Conjunction<'a>,
}
impl<T: fmt::Display> fmt::Display for OxfordJoinFmt<'_, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use core::cmp::Ordering;
if let Some((last, rest)) = self.inner.split_last() {
match rest.len().cmp(&1) {
Ordering::Less => write!(f, "{last}"),
Ordering::Equal => write!(f, "{} {} {last}", rest[0], self.glue),
Ordering::Greater => {
for v in rest { write!(f, "{v}, ")?; }
write!(f, "{} {last}", self.glue)
},
}
}
else { Ok(()) }
}
}
impl<'a, T: fmt::Display> OxfordJoinFmt<'a, T> {
#[inline]
pub const fn new(set: &'a [T], glue: Conjunction<'a>) -> Self {
Self { inner: set, glue }
}
#[inline]
pub const fn and(set: &'a [T]) -> Self { Self::new(set, Conjunction::And) }
#[inline]
pub const fn and_or(set: &'a [T]) -> Self { Self::new(set, Conjunction::AndOr) }
#[inline]
pub const fn nor(set: &'a [T]) -> Self { Self::new(set, Conjunction::Nor) }
#[inline]
pub const fn or(set: &'a [T]) -> Self { Self::new(set, Conjunction::Or) }
}
#[cfg(test)]
mod test {
use super::*;
use alloc::format;
#[test]
fn t_join() {
assert_eq!(
format!("{}", JoinFmt::new(core::iter::once("hi"), "-")),
"hi",
);
assert_eq!(
format!("{}", JoinFmt::new(["hi", "ho"].iter(), "-")),
"hi-ho",
);
assert_eq!(
format!("{}", JoinFmt::new(["hi", "ho"].iter(), "")),
"hiho",
);
}
#[test]
fn t_oxford_join() {
use crate::OxfordJoin;
let slice: &[&str] = &["hi"];
assert_eq!(
format!("{}", OxfordJoinFmt::and(slice)),
slice.oxford_and(),
);
let slice: &[&str] = &["hi", "ho"];
assert_eq!(
format!("{}", OxfordJoinFmt::and(slice)),
slice.oxford_and(),
);
let slice: &[&str] = &["hi", "ho", "hi", "ho"];
assert_eq!(
format!("{}", OxfordJoinFmt::and(slice)),
slice.oxford_and(),
);
}
}