use {
alloc::{vec, vec::Vec},
core::{
convert::TryFrom,
fmt::{self, Display, Formatter},
iter::{self, Chain, FromIterator, Once, Repeat},
slice::Iter,
},
once_cell::sync::Lazy,
};
pub(crate) type Name = &'static str;
#[derive(Clone, Debug, Eq, PartialEq)]
#[non_exhaustive]
pub enum Scent {
Char(char),
Range(char, char),
Union(MultipleOdors),
Repetition(Odor),
Marked(Odor),
}
impl Scent {
fn is_marked(&self, name: Name) -> bool {
match *self {
Self::Char(..) | Self::Range(..) => false,
Self::Union(ref odors) => {
for odor in odors {
if odor.is_marked(name) {
return true;
}
}
false
}
Self::Repetition(ref odor) | Self::Marked(ref odor) => odor.is_marked(name),
}
}
}
impl Display for Scent {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match *self {
Self::Char(c) => write!(f, "'{}'", c),
Self::Range(begin, end) => write!(f, "'{}'..='{}'", begin, end),
Self::Union(ref odors) => write!(f, "{}", odors.display('(', " | ", ')')),
Self::Repetition(ref odor) => write!(f, "{}*", odor),
Self::Marked(ref odor) => write!(f, "({})", odor),
}
}
}
pub(crate) type Scents<'o> = Iter<'o, Scent>;
#[derive(Copy, Clone, Debug)]
pub enum MarkOdorError {
NameAlreadyExists,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Odor {
scents: Vec<Scent>,
name: Option<Name>,
}
impl Odor {
#[must_use]
pub fn into_branches(self) -> Vec<Self> {
if let (Some(&Scent::Union(ref branches)), None) = (self.scents.get(0), self.scents.get(1))
{
branches.clone().into_vec()
} else {
vec![self]
}
}
pub fn mark(mut self, name: Name) -> Result<Self, MarkOdorError> {
if self.scent_is_marked(name) {
return Err(MarkOdorError::NameAlreadyExists);
}
self.name = Some(name);
Ok(self)
}
#[must_use]
pub(crate) const fn name(&self) -> Option<Name> {
self.name
}
#[must_use]
pub(crate) fn scents(&self) -> Scents<'_> {
self.scents.iter()
}
fn scent_is_marked(&self, name: Name) -> bool {
for scent in &self.scents {
if scent.is_marked(name) {
return true;
}
}
false
}
fn is_marked(&self, name: Name) -> bool {
(self.name == Some(name)) || self.scent_is_marked(name)
}
}
impl Default for Odor {
fn default() -> Self {
Self::from_iter([])
}
}
impl Display for Odor {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
for scent in &self.scents {
write!(f, "{}", scent)?;
}
if let Some(name) = self.name {
write!(f, " as \"{}\"", name)?;
}
Ok(())
}
}
impl Extend<Scent> for Odor {
fn extend<I>(&mut self, iter: I)
where
I: IntoIterator<Item = Scent>,
{
self.scents.extend(iter);
}
}
impl From<char> for Odor {
fn from(c: char) -> Self {
iter::once(Scent::Char(c)).collect()
}
}
impl From<&str> for Odor {
fn from(s: &str) -> Self {
s.chars().map(Scent::Char).collect()
}
}
impl From<Vec<Self>> for Odor {
fn from(odors: Vec<Self>) -> Self {
let mut scents = Vec::new();
for mut odor in odors {
if odor.name().is_some() {
scents.push(Scent::Marked(odor));
} else {
scents.append(&mut odor.scents);
}
}
Self::from_iter(scents)
}
}
impl FromIterator<Scent> for Odor {
fn from_iter<I>(iter: I) -> Self
where
I: IntoIterator<Item = Scent>,
{
Self {
scents: Vec::from_iter(iter),
name: None,
}
}
}
#[derive(Clone, Copy, Debug)]
pub enum CreateMultipleOdorsError {
TooFewOdors,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct MultipleOdors {
first_two: [Odor; 2],
rest: Vec<Odor>,
}
impl MultipleOdors {
#[must_use]
pub fn new(first: Odor, second: Odor, rest: Vec<Odor>) -> Self {
Self {
first_two: [first, second],
rest,
}
}
fn into_vec(mut self) -> Vec<Odor> {
let mut odors = self.first_two.to_vec();
odors.append(&mut self.rest);
odors
}
fn display<'a>(&'a self, start: char, delimiter: &'static str, end: char) -> impl Display + 'a {
struct MultipleOdorsDisplay<'a> {
multiple_odors: &'a MultipleOdors,
start: char,
delimiter: &'static str,
end: char,
}
impl<'a> Display for MultipleOdorsDisplay<'a> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(
f,
"{}{}{}{}",
self.start,
self.multiple_odors.first_two[0],
self.delimiter,
self.multiple_odors.first_two[1]
)?;
for odor in &self.multiple_odors.rest {
write!(f, "{}{}", self.delimiter, odor)?;
}
write!(f, "{}", self.end)
}
}
MultipleOdorsDisplay {
multiple_odors: self,
start,
delimiter,
end,
}
}
}
impl Display for MultipleOdors {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.display('[', ", ", ']'))
}
}
impl Extend<Odor> for MultipleOdors {
fn extend<I>(&mut self, iter: I)
where
I: IntoIterator<Item = Odor>,
{
self.rest.extend(iter);
}
}
impl<'a> IntoIterator for &'a MultipleOdors {
type Item = &'a Odor;
type IntoIter = Chain<Iter<'a, Odor>, Iter<'a, Odor>>;
fn into_iter(self) -> Self::IntoIter {
self.first_two.iter().chain(self.rest.iter())
}
}
impl TryFrom<Vec<Odor>> for MultipleOdors {
type Error = CreateMultipleOdorsError;
fn try_from(odors: Vec<Odor>) -> Result<Self, Self::Error> {
odors
.get(0)
.and_then(|first| {
odors.get(1).and_then(|second| {
odors
.get(2..)
.map(|rest| Self::new(first.clone(), second.clone(), rest.to_vec()))
})
})
.ok_or(CreateMultipleOdorsError::TooFewOdors)
}
}
static EMPTY_ODOR: Lazy<Odor> = Lazy::new(Odor::default);
#[derive(Debug)]
pub(crate) enum Odors<'o> {
Single(Option<&'o Odor>),
RepeatAfterEmpty(Chain<Once<&'o Odor>, Repeat<&'o Odor>>),
List(Chain<Iter<'o, Odor>, Iter<'o, Odor>>),
}
impl<'o> Odors<'o> {
pub(crate) const fn single(odor: &'o Odor) -> Self {
Self::Single(Some(odor))
}
pub(crate) fn repeat_after_empty(odor: &'o Odor) -> Self {
let start: Once<&'o Odor> = iter::once(&EMPTY_ODOR);
Self::RepeatAfterEmpty(start.chain(iter::repeat(odor)))
}
pub(crate) const fn list(odors: Chain<Iter<'o, Odor>, Iter<'o, Odor>>) -> Self {
Self::List(odors)
}
}
impl<'o> Iterator for Odors<'o> {
type Item = &'o Odor;
fn next(&mut self) -> Option<Self::Item> {
match *self {
Self::Single(ref mut odor) => odor.take(),
Self::RepeatAfterEmpty(ref mut odors) => odors.next(),
Self::List(ref mut odors) => odors.next(),
}
}
}