use super::{FileArtifact, RejectedFile};
use crate::lang::js::NativeTemplateIssueKind;
use crate::op::{Attribute, ElementOp};
use core::ptr::NonNull;
use vize_l0::id::NodeId;
use vize_l1::markup::{NativeAttributeValue, NativeAttributeValueFailure};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum NativeFileAttributeValueState {
Pending,
Attached { node: NodeId, slot: usize },
Refused(NativeTemplateIssueKind),
}
pub struct NativeFileAttributeValue<'a> {
pub(crate) observation: Result<NativeAttributeValue<'a>, NativeAttributeValueFailure<'a>>,
pub(crate) state: NativeFileAttributeValueState,
pub(crate) slot: usize,
pub(crate) name: &'a str,
pub(crate) element: Option<NonNull<ElementOp<'a>>>,
pub(crate) attribute: Option<NonNull<Attribute<'a>>>,
}
impl<'a> NativeFileAttributeValue<'a> {
#[must_use]
pub fn observation(&self) -> Option<&NativeAttributeValue<'a>> {
self.observation.as_ref().ok()
}
#[must_use]
pub fn failure(&self) -> Option<&NativeAttributeValueFailure<'a>> {
self.observation.as_ref().err()
}
#[must_use]
pub const fn state(&self) -> NativeFileAttributeValueState {
self.state
}
}
#[derive(Clone, Copy)]
pub struct FileAttributeValue<'f, 'a> {
file: &'f FileArtifact<'a>,
element: &'f ElementOp<'a>,
index: usize,
slot: usize,
}
impl<'a> FileArtifact<'a> {
#[must_use]
pub fn native_attribute_values(&self) -> &[NativeFileAttributeValue<'a>] {
&self.facts.native_attribute_values
}
#[must_use]
pub fn native_attribute_value_for<'f>(
&'f self,
index: usize,
element: &'f ElementOp<'a>,
slot: usize,
) -> Option<FileAttributeValue<'f, 'a>> {
let record = self.facts.native_attribute_values.get(index)?;
let attribute = element.attributes.get(slot)?;
let observation = record.observation()?;
if !matches!(record.state, NativeFileAttributeValueState::Attached { slot: actual, .. } if actual == slot)
|| record.element != Some(NonNull::from(element))
|| record.attribute != Some(NonNull::from(attribute))
|| !core::ptr::eq(record.name, attribute.name)
|| !attribute
.value
.is_some_and(|value| core::ptr::eq(value, observation.source().text()))
{
return None;
}
Some(FileAttributeValue {
file: self,
element,
index,
slot,
})
}
}
impl<'a> RejectedFile<'a> {
#[must_use]
pub fn native_attribute_values(&self) -> &[NativeFileAttributeValue<'a>] {
&self.facts.native_attribute_values
}
}
impl<'f, 'a> FileAttributeValue<'f, 'a> {
#[must_use]
pub const fn file(self) -> &'f FileArtifact<'a> {
self.file
}
#[must_use]
pub const fn element(self) -> &'f ElementOp<'a> {
self.element
}
#[must_use]
pub const fn index(self) -> usize {
self.index
}
#[must_use]
pub const fn slot(self) -> usize {
self.slot
}
#[must_use]
pub fn observation(self) -> Option<&'f NativeAttributeValue<'a>> {
self.file
.facts
.native_attribute_values
.get(self.index)?
.observation()
}
#[must_use]
pub fn attribute(self) -> Option<&'f Attribute<'a>> {
self.element.attributes.get(self.slot)
}
}