use crate::structure::{Attribute, Body, Structure};
use crate::{Decor, Decorate, Decorated, Ident};
use std::ops::{self, Range};
#[derive(Debug, Clone, Eq)]
pub struct Block {
pub ident: Decorated<Ident>,
pub labels: Vec<BlockLabel>,
pub body: Body,
decor: Decor,
span: Option<Range<usize>>,
}
impl Block {
pub fn new(ident: impl Into<Decorated<Ident>>) -> Block {
Block {
ident: ident.into(),
labels: Vec::new(),
body: Body::new(),
decor: Decor::default(),
span: None,
}
}
#[inline]
pub fn builder(ident: impl Into<Decorated<Ident>>) -> BlockBuilder {
BlockBuilder::new(ident.into())
}
#[inline]
pub fn is_labeled(&self) -> bool {
!self.labels.is_empty()
}
#[inline]
pub fn has_ident(&self, ident: &str) -> bool {
self.ident.as_str() == ident
}
pub fn has_labels<T>(&self, labels: &[T]) -> bool
where
T: AsRef<str>,
{
if self.labels.len() < labels.len() {
false
} else {
self.labels
.iter()
.zip(labels.iter())
.all(|(a, b)| a.as_str() == b.as_ref())
}
}
pub fn has_exact_labels<T>(&self, labels: &[T]) -> bool
where
T: AsRef<str>,
{
self.labels.len() == labels.len() && self.has_labels(labels)
}
pub(crate) fn despan(&mut self, input: &str) {
self.decor.despan(input);
self.ident.decor_mut().despan(input);
for label in &mut self.labels {
label.despan(input);
}
self.body.despan(input);
}
}
impl PartialEq for Block {
fn eq(&self, other: &Self) -> bool {
self.ident == other.ident && self.labels == other.labels && self.body == other.body
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum BlockLabel {
Ident(Decorated<Ident>),
String(Decorated<String>),
}
impl BlockLabel {
pub fn is_ident(&self) -> bool {
matches!(self, BlockLabel::Ident(_))
}
pub fn is_string(&self) -> bool {
matches!(self, BlockLabel::String(_))
}
pub fn as_str(&self) -> &str {
match self {
BlockLabel::Ident(ident) => ident.as_str(),
BlockLabel::String(string) => string.as_str(),
}
}
pub(crate) fn despan(&mut self, input: &str) {
match self {
BlockLabel::Ident(ident) => ident.decor_mut().despan(input),
BlockLabel::String(string) => string.decor_mut().despan(input),
}
}
}
impl From<Ident> for BlockLabel {
fn from(value: Ident) -> Self {
BlockLabel::from(Decorated::new(value))
}
}
impl From<Decorated<Ident>> for BlockLabel {
fn from(value: Decorated<Ident>) -> Self {
BlockLabel::Ident(value)
}
}
impl From<&str> for BlockLabel {
fn from(value: &str) -> Self {
BlockLabel::from(value.to_string())
}
}
impl From<String> for BlockLabel {
fn from(value: String) -> Self {
BlockLabel::from(Decorated::new(value))
}
}
impl From<Decorated<String>> for BlockLabel {
fn from(value: Decorated<String>) -> Self {
BlockLabel::String(value)
}
}
impl AsRef<str> for BlockLabel {
fn as_ref(&self) -> &str {
self.as_str()
}
}
impl ops::Deref for BlockLabel {
type Target = str;
fn deref(&self) -> &Self::Target {
self.as_str()
}
}
decorate_impl!(Block);
span_impl!(Block);
forward_decorate_impl!(BlockLabel => { Ident, String });
forward_span_impl!(BlockLabel => { Ident, String });
#[derive(Debug)]
pub struct BlockBuilder {
ident: Decorated<Ident>,
labels: Vec<BlockLabel>,
body: Body,
}
impl BlockBuilder {
fn new(ident: Decorated<Ident>) -> BlockBuilder {
BlockBuilder {
ident,
labels: Vec::new(),
body: Body::new(),
}
}
#[inline]
pub fn label(mut self, label: impl Into<BlockLabel>) -> Self {
self.labels.push(label.into());
self
}
#[inline]
pub fn labels<I>(mut self, iter: I) -> BlockBuilder
where
I: IntoIterator,
I::Item: Into<BlockLabel>,
{
self.labels.extend(iter.into_iter().map(Into::into));
self
}
#[inline]
pub fn attribute(self, attr: impl Into<Attribute>) -> BlockBuilder {
self.structure(attr.into())
}
#[inline]
pub fn attributes<I>(self, iter: I) -> BlockBuilder
where
I: IntoIterator,
I::Item: Into<Attribute>,
{
self.structures(iter.into_iter().map(Into::into))
}
#[inline]
pub fn block(self, block: impl Into<Block>) -> BlockBuilder {
self.structure(block.into())
}
#[inline]
pub fn blocks<I>(self, iter: I) -> BlockBuilder
where
I: IntoIterator,
I::Item: Into<Block>,
{
self.structures(iter.into_iter().map(Into::into))
}
#[inline]
pub fn structure(mut self, structures: impl Into<Structure>) -> BlockBuilder {
self.body.push(structures.into());
self
}
#[inline]
pub fn structures<I>(mut self, iter: I) -> BlockBuilder
where
I: IntoIterator,
I::Item: Into<Structure>,
{
self.body.extend(iter);
self
}
#[inline]
pub fn build(self) -> Block {
Block {
ident: self.ident,
labels: self.labels,
body: self.body,
decor: Decor::default(),
span: None,
}
}
}
impl From<BlockBuilder> for Block {
#[inline]
fn from(builder: BlockBuilder) -> Self {
builder.build()
}
}