use std::convert::identity;
use std::mem;
use super::{Component, OwnedFormatItem, OwnedFormatItemInner};
impl OwnedFormatItem {
pub(crate) fn optimize(&mut self) {
self.inner.optimize();
}
}
impl OwnedFormatItemInner {
pub(crate) fn optimize(&mut self) {
let passes = [
Self::merge_consecutive_literals,
Self::unnest_trivial_compounds,
Self::unnest_nested_compounds,
Self::unnest_first_only_one,
Self::unnest_nested_first,
Self::only_formatting_uplift_optional,
Self::only_formatting_uplift_first,
Self::only_formatting_eliminate_end,
Self::compound_containing_empty_string,
];
match self {
Self::Literal(_) | Self::StringLiteral(_) | Self::Component(_) => {}
Self::Compound(items) | Self::First(items) => {
for item in items {
item.optimize();
}
}
Self::Optional { format: _, item } => item.optimize(),
}
while passes.map(|pass| pass(self)).into_iter().any(identity) {}
}
const fn no_op() -> Self {
Self::StringLiteral(String::new())
}
fn merge_consecutive_literals(&mut self) -> bool {
let Self::Compound(items) = self else {
return false;
};
let mut something_was_changed = false;
let mut idx = 1;
while idx < items.len() {
let pair = unsafe { items.get_disjoint_unchecked_mut([idx - 1, idx]) };
match pair {
[Self::Literal(a), Self::Literal(b)] => {
a.append(b);
items.remove(idx);
something_was_changed = true;
}
[Self::Literal(a), Self::StringLiteral(b)] => {
a.extend(b.as_bytes());
items.remove(idx);
something_was_changed = true;
}
[item @ Self::StringLiteral(_), Self::Literal(b)] => {
let Self::StringLiteral(a) = item else {
unreachable!()
};
let mut bytes = a.as_bytes().to_vec();
bytes.append(b);
*item = Self::Literal(bytes);
items.remove(idx);
something_was_changed = true;
}
[Self::StringLiteral(a), Self::StringLiteral(b)] => {
a.push_str(b);
items.remove(idx);
something_was_changed = true;
}
_ => idx += 1,
}
}
something_was_changed
}
fn unnest_trivial_compounds(&mut self) -> bool {
if let Self::Compound(items) = self
&& items.len() == 1
&& let Some(item) = items.pop()
{
*self = item;
true
} else {
false
}
}
fn unnest_nested_compounds(&mut self) -> bool {
let Self::Compound(items) = self else {
return false;
};
let mut idx = 0;
let mut something_was_changed = false;
while idx < items.len() {
if let Self::Compound(inner_items) = &mut items[idx] {
let inner_items = mem::take(inner_items);
items.splice(idx..=idx, inner_items).for_each(drop);
something_was_changed = true;
} else {
idx += 1;
}
}
something_was_changed
}
fn unnest_first_only_one(&mut self) -> bool {
if let Self::First(items) = self
&& items.len() == 1
&& let Some(item) = items.pop()
{
*self = item;
true
} else {
false
}
}
fn unnest_nested_first(&mut self) -> bool {
let Self::First(items) = self else {
return false;
};
let mut idx = 0;
let mut something_was_changed = false;
while idx < items.len() {
if let Self::First(inner_items) = &mut items[idx] {
let inner_items = mem::take(inner_items);
items.splice(idx..=idx, inner_items).for_each(drop);
something_was_changed = true;
} else {
idx += 1;
}
}
something_was_changed
}
fn only_formatting_uplift_optional(&mut self) -> bool {
if !cfg!(feature = "formatting") || cfg!(feature = "parsing") {
return false;
}
let Self::Optional { format, item } = self else {
return false;
};
let item = if *format {
mem::replace(item.as_mut(), Self::no_op())
} else {
Self::no_op()
};
*self = item;
true
}
fn only_formatting_uplift_first(&mut self) -> bool {
if !cfg!(feature = "formatting") || cfg!(feature = "parsing") {
return false;
}
let Self::First(items) = self else {
return false;
};
*self = items.remove(0);
true
}
fn only_formatting_eliminate_end(&mut self) -> bool {
if !cfg!(feature = "formatting") || cfg!(feature = "parsing") {
return false;
}
if let Self::Component(Component::End(_)) = self {
*self = Self::no_op();
true
} else {
false
}
}
fn compound_containing_empty_string(&mut self) -> bool {
let Self::Compound(items) = self else {
return false;
};
let mut idx = 0;
let mut something_was_changed = false;
while idx < items.len() {
if let Self::StringLiteral(s) = &items[idx]
&& s.is_empty()
{
items.remove(idx);
something_was_changed = true;
} else {
idx += 1;
}
}
something_was_changed
}
}