use super::{TemplatePolicy, TemplateRegion};
use crate::artifact::{ArtifactError, ComponentBody, ComponentFactory};
use crate::expr::JsExpr;
use crate::file::template::TemplateWalk;
use crate::file::{FileIssueKind, TemplateIssue};
use crate::op::{Attribute, Namespace};
use crate::provenance::ProvenanceRecord;
use core::ops::{Deref, DerefMut};
use vize_l0::{Span, id::NodeId};
pub struct TemplateWalkRegion<'g, 'f, 'a, P: TemplatePolicy> {
region: &'g mut TemplateRegion<'f, 'a, P>,
previous: TemplateWalk,
armed: bool,
}
impl<'f, 'a, P: TemplatePolicy> TemplateRegion<'f, 'a, P> {
pub fn walk(&mut self, span: Span) -> Result<TemplateWalkRegion<'_, 'f, 'a, P>, ArtifactError> {
if matches!(self.inner.facts.template_walk, TemplateWalk::Pending(_)) {
return Err(self.inner.reject(span, FileIssueKind::ActiveTemplateWalk));
}
if self
.source()
.get(span.start as usize..span.end as usize)
.is_none()
{
return Err(self.inner.reject(span, FileIssueKind::InvalidSpan));
}
let previous = self.inner.facts.template_walk.enter(span);
Ok(TemplateWalkRegion {
region: self,
previous,
armed: true,
})
}
}
impl<P: TemplatePolicy> TemplateWalkRegion<'_, '_, '_, P> {
pub fn complete(mut self) -> Result<(), TemplateIssue> {
self.region
.inner
.facts
.template_walk
.complete(self.previous);
self.armed = false;
match self.region.inner.facts.template_walk.interruption() {
Some(issue) => Err(issue),
None => Ok(()),
}
}
}
impl<P: TemplatePolicy> Drop for TemplateWalkRegion<'_, '_, '_, P> {
fn drop(&mut self) {
if self.armed {
self.region.inner.facts.template_walk.interrupt();
}
}
}
impl<'f, 'a, P: TemplatePolicy> Deref for TemplateWalkRegion<'_, 'f, 'a, P> {
type Target = TemplateRegion<'f, 'a, P>;
fn deref(&self) -> &Self::Target {
self.region
}
}
impl<P: TemplatePolicy> DerefMut for TemplateWalkRegion<'_, '_, '_, P> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.region
}
}
impl<'a, P: TemplatePolicy> ComponentFactory<'a> for TemplateWalkRegion<'_, '_, 'a, P> {
fn source(&self) -> &'a str {
self.region.source()
}
fn text(&mut self, text: &'a str, span: Span) -> Result<NodeId, ArtifactError> {
self.region.text(text, span)
}
fn comment(&mut self, text: &'a str, span: Span) -> Result<NodeId, ArtifactError> {
self.region.comment(text, span)
}
fn interpolation(
&mut self,
expression: &'a JsExpr<'a>,
span: Span,
) -> Result<NodeId, ArtifactError> {
self.region.interpolation(expression, span)
}
fn bind(
&mut self,
name: &'a str,
name_span: Span,
expression: &'a JsExpr<'a>,
span: Span,
) -> Result<NodeId, ArtifactError> {
self.region.bind(name, name_span, expression, span)
}
fn element<B: ComponentBody<'a>>(
&mut self,
tag: &'a str,
namespace: Namespace,
attributes: vize_l0::Vec<'a, Attribute<'a>>,
span: Span,
body: B,
) -> Result<NodeId, ArtifactError> {
self.region.element(tag, namespace, attributes, span, body)
}
fn component<B: ComponentBody<'a>>(
&mut self,
name: &'a str,
attributes: vize_l0::Vec<'a, Attribute<'a>>,
span: Span,
body: B,
) -> Result<NodeId, ArtifactError> {
self.region.component(name, attributes, span, body)
}
fn record(&mut self, record: ProvenanceRecord) -> Result<(), ArtifactError> {
self.region.record(record)
}
}