use crate::encode::{EncodeDecorated, EncodeState, NO_DECOR};
use crate::structure::{Attribute, AttributeMut, Block, Structure, StructureMut};
use crate::{parser, Decor};
use std::fmt;
use std::ops::Range;
use std::str::FromStr;
pub type IntoIter = Box<dyn Iterator<Item = Structure>>;
pub type Iter<'a> = Box<dyn Iterator<Item = &'a Structure> + 'a>;
pub type IterMut<'a> = Box<dyn Iterator<Item = StructureMut<'a>> + 'a>;
pub type IntoAttributes = Box<dyn Iterator<Item = Attribute>>;
pub type Attributes<'a> = Box<dyn Iterator<Item = &'a Attribute> + 'a>;
pub type AttributesMut<'a> = Box<dyn Iterator<Item = AttributeMut<'a>> + 'a>;
pub type IntoBlocks = Box<dyn Iterator<Item = Block>>;
pub type Blocks<'a> = Box<dyn Iterator<Item = &'a Block> + 'a>;
pub type BlocksMut<'a> = Box<dyn Iterator<Item = &'a mut Block> + 'a>;
#[derive(Debug, Clone, Default, Eq)]
pub struct Body {
structures: Vec<Structure>,
prefer_oneline: bool,
prefer_omit_trailing_newline: bool,
decor: Decor,
span: Option<Range<usize>>,
}
impl Body {
#[inline]
pub fn new() -> Self {
Body::default()
}
#[inline]
pub fn with_capacity(capacity: usize) -> Self {
Body {
structures: Vec::with_capacity(capacity),
..Default::default()
}
}
#[inline]
pub fn builder() -> BodyBuilder {
BodyBuilder::default()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.structures.is_empty()
}
#[inline]
pub fn len(&self) -> usize {
self.structures.len()
}
#[inline]
pub fn clear(&mut self) {
self.structures.clear();
}
#[inline]
pub fn get(&self, index: usize) -> Option<&Structure> {
self.structures.get(index)
}
#[inline]
pub fn get_mut(&mut self, index: usize) -> Option<&mut Structure> {
self.structures.get_mut(index)
}
#[inline]
pub fn has_attribute(&self, key: &str) -> bool {
self.get_attribute(key).is_some()
}
#[inline]
pub fn has_blocks(&self, ident: &str) -> bool {
self.get_blocks(ident).next().is_some()
}
pub fn get_attribute(&self, key: &str) -> Option<&Attribute> {
self.structures
.iter()
.filter_map(Structure::as_attribute)
.find(|attr| attr.has_key(key))
}
pub fn get_attribute_mut(&mut self, key: &str) -> Option<AttributeMut<'_>> {
self.structures
.iter_mut()
.filter_map(Structure::as_attribute_mut)
.find(|attr| attr.has_key(key))
.map(AttributeMut::new)
}
pub fn get_blocks<'a>(&'a self, ident: &'a str) -> Blocks<'a> {
Box::new(
self.structures
.iter()
.filter_map(Structure::as_block)
.filter(|block| block.has_ident(ident)),
)
}
pub fn get_blocks_mut<'a>(&'a mut self, ident: &'a str) -> BlocksMut<'a> {
Box::new(
self.structures
.iter_mut()
.filter_map(Structure::as_block_mut)
.filter(|block| block.has_ident(ident)),
)
}
#[inline]
pub fn insert(&mut self, index: usize, structure: impl Into<Structure>) {
_ = self.try_insert(index, structure);
}
#[inline]
pub fn try_insert(
&mut self,
index: usize,
structure: impl Into<Structure>,
) -> Result<(), Attribute> {
match structure.into() {
Structure::Attribute(attr) if self.has_attribute(&attr.key) => Err(attr),
structure => {
self.structures.insert(index, structure);
Ok(())
}
}
}
#[inline]
pub fn push(&mut self, structure: impl Into<Structure>) {
_ = self.try_push(structure);
}
#[inline]
pub fn try_push(&mut self, structure: impl Into<Structure>) -> Result<(), Attribute> {
match structure.into() {
Structure::Attribute(attr) if self.has_attribute(&attr.key) => Err(attr),
structure => {
self.structures.push(structure);
Ok(())
}
}
}
#[inline]
pub fn pop(&mut self) -> Option<Structure> {
self.structures.pop()
}
#[inline]
pub fn remove(&mut self, index: usize) -> Structure {
self.structures.remove(index)
}
pub fn remove_attribute(&mut self, key: &str) -> Option<Attribute> {
self.structures
.iter()
.position(|structure| {
structure
.as_attribute()
.is_some_and(|attr| attr.has_key(key))
})
.and_then(|index| self.remove(index).into_attribute().ok())
}
pub fn remove_blocks(&mut self, ident: &str) -> Vec<Block> {
let mut removed = Vec::new();
while let Some(block) = self.remove_block(ident) {
removed.push(block);
}
removed
}
fn remove_block(&mut self, ident: &str) -> Option<Block> {
self.structures
.iter()
.position(|structure| {
structure
.as_block()
.is_some_and(|block| block.has_ident(ident))
})
.and_then(|index| self.remove(index).into_block().ok())
}
#[inline]
pub fn iter(&self) -> Iter<'_> {
Box::new(self.structures.iter())
}
#[inline]
pub fn iter_mut(&mut self) -> IterMut<'_> {
Box::new(self.structures.iter_mut().map(StructureMut::new))
}
#[inline]
pub fn into_attributes(self) -> IntoAttributes {
Box::new(
self.structures
.into_iter()
.filter_map(|s| s.into_attribute().ok()),
)
}
#[inline]
pub fn attributes(&self) -> Attributes<'_> {
Box::new(self.structures.iter().filter_map(Structure::as_attribute))
}
#[inline]
pub fn attributes_mut(&mut self) -> AttributesMut<'_> {
Box::new(
self.structures
.iter_mut()
.filter_map(Structure::as_attribute_mut)
.map(AttributeMut::new),
)
}
#[inline]
pub fn into_blocks(self) -> IntoBlocks {
Box::new(
self.structures
.into_iter()
.filter_map(|s| s.into_block().ok()),
)
}
#[inline]
pub fn blocks(&self) -> Blocks<'_> {
Box::new(self.structures.iter().filter_map(Structure::as_block))
}
#[inline]
pub fn blocks_mut(&mut self) -> BlocksMut<'_> {
Box::new(
self.structures
.iter_mut()
.filter_map(Structure::as_block_mut),
)
}
#[inline]
pub fn set_prefer_oneline(&mut self, yes: bool) {
self.prefer_oneline = yes;
}
#[inline]
pub fn prefer_oneline(&self) -> bool {
self.prefer_oneline
}
#[inline]
pub fn set_prefer_omit_trailing_newline(&mut self, yes: bool) {
self.prefer_omit_trailing_newline = yes;
}
#[inline]
pub fn prefer_omit_trailing_newline(&self) -> bool {
self.prefer_omit_trailing_newline
}
#[inline]
pub(crate) fn has_single_attribute(&self) -> bool {
self.len() == 1 && self.get(0).is_some_and(Structure::is_attribute)
}
pub(crate) fn from_vec_unchecked(structures: Vec<Structure>) -> Self {
Body {
structures,
..Default::default()
}
}
pub(crate) fn despan(&mut self, input: &str) {
self.decor.despan(input);
for structure in &mut self.structures {
structure.despan(input);
}
}
}
impl PartialEq for Body {
fn eq(&self, other: &Self) -> bool {
self.structures == other.structures
}
}
impl fmt::Display for Body {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut state = EncodeState::new(f);
self.encode_decorated(&mut state, NO_DECOR)
}
}
impl FromStr for Body {
type Err = parser::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
parser::parse_body(s)
}
}
impl From<Vec<Structure>> for Body {
fn from(structures: Vec<Structure>) -> Self {
Body::from_iter(structures)
}
}
impl<T> Extend<T> for Body
where
T: Into<Structure>,
{
fn extend<I>(&mut self, iterable: I)
where
I: IntoIterator<Item = T>,
{
let iter = iterable.into_iter();
let reserve = if self.is_empty() {
iter.size_hint().0
} else {
(iter.size_hint().0 + 1) / 2
};
self.structures.reserve(reserve);
iter.for_each(|v| self.push(v));
}
}
impl<T> FromIterator<T> for Body
where
T: Into<Structure>,
{
fn from_iter<I>(iterable: I) -> Self
where
I: IntoIterator<Item = T>,
{
let iter = iterable.into_iter();
let lower = iter.size_hint().0;
let mut body = Body::with_capacity(lower);
body.extend(iter);
body
}
}
impl IntoIterator for Body {
type Item = Structure;
type IntoIter = IntoIter;
fn into_iter(self) -> Self::IntoIter {
Box::new(self.structures.into_iter())
}
}
impl<'a> IntoIterator for &'a Body {
type Item = &'a Structure;
type IntoIter = Iter<'a>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl<'a> IntoIterator for &'a mut Body {
type Item = StructureMut<'a>;
type IntoIter = IterMut<'a>;
fn into_iter(self) -> Self::IntoIter {
self.iter_mut()
}
}
decorate_impl!(Body);
span_impl!(Body);
#[derive(Debug, Default)]
pub struct BodyBuilder {
body: Body,
}
impl BodyBuilder {
#[inline]
pub fn attribute(self, attr: impl Into<Attribute>) -> BodyBuilder {
self.structure(attr.into())
}
#[inline]
pub fn attributes<I>(self, iter: I) -> BodyBuilder
where
I: IntoIterator,
I::Item: Into<Attribute>,
{
self.structures(iter.into_iter().map(Into::into))
}
#[inline]
pub fn block(self, block: impl Into<Block>) -> BodyBuilder {
self.structure(block.into())
}
#[inline]
pub fn blocks<I>(self, iter: I) -> BodyBuilder
where
I: IntoIterator,
I::Item: Into<Block>,
{
self.structures(iter.into_iter().map(Into::into))
}
#[inline]
pub fn structure(mut self, structure: impl Into<Structure>) -> BodyBuilder {
self.body.push(structure.into());
self
}
#[inline]
pub fn structures<I>(mut self, iter: I) -> BodyBuilder
where
I: IntoIterator,
I::Item: Into<Structure>,
{
self.body.extend(iter);
self
}
#[inline]
pub fn build(self) -> Body {
self.body
}
}
impl From<BodyBuilder> for Body {
#[inline]
fn from(builder: BodyBuilder) -> Self {
builder.build()
}
}