use super::*;
use zirql::{DeclaredType as D, Location, ProgramHost, ProjectionHost};
#[derive(Debug)]
pub struct Computational<'a> {
pub(super) value: Rc<zirql::ComputationalValue<ReportValue<'a>, Kind>>,
pub(super) range: Range<usize>,
}
impl Computational<'_> {
pub fn len(&self) -> usize {
match self.value.as_ref() {
zirql::ComputationalValue::Queue(value) => value.len(),
zirql::ComputationalValue::IdentitySet(value) => value.len(),
}
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn range(&self) -> Range<usize> {
self.range.clone()
}
}
#[derive(Debug)]
pub struct NativeTuple<'a> {
pub(super) values: Rc<Vec<ReportValue<'a>>>,
pub(super) range: Range<usize>,
}
impl<'a> NativeTuple<'a> {
pub fn values(&self) -> &[ReportValue<'a>] {
&self.values
}
pub fn range(&self) -> Range<usize> {
self.range.clone()
}
}
#[derive(Debug)]
pub struct NativeSequence<'a> {
pub(super) values: Rc<Vec<ReportValue<'a>>>,
pub(super) element: Rc<D<Kind>>,
pub(super) range: Range<usize>,
}
impl<'a> NativeSequence<'a> {
pub fn values(&self) -> &[ReportValue<'a>] {
&self.values
}
pub fn range(&self) -> Range<usize> {
self.range.clone()
}
}
pub(super) fn copy<'a>(value: &ReportValue<'a>) -> Option<ReportValue<'a>> {
Some(match value {
ReportValue::Computational(value) => ReportValue::Computational(Computational {
value: Rc::clone(&value.value),
range: value.range.clone(),
}),
ReportValue::Tuple(value) => ReportValue::Tuple(NativeTuple {
values: Rc::clone(&value.values),
range: value.range.clone(),
}),
ReportValue::Sequence(value) => ReportValue::Sequence(NativeSequence {
values: Rc::clone(&value.values),
element: Rc::clone(&value.element),
range: value.range.clone(),
}),
_ => return None,
})
}
pub(super) fn owner<'v, 'a>(value: &'v ReportValue<'a>) -> Option<&'v Rc<ModelFacts<'a>>> {
match value {
ReportValue::Retained(value) => owner(value),
ReportValue::Item(value) | ReportValue::IncompleteSelection { value, .. } => owner(value),
ReportValue::EntitySequence { owner, .. } => owner.as_ref(),
_ => None,
}
}
pub(super) fn declaration(
value: &D<Kind>,
budget: &mut Budget,
range: &Range<usize>,
) -> Result<Rc<D<Kind>>, zirql::QueryError> {
let location = Location::Query(range.clone());
budget.charge_results(1, location.clone())?;
Ok(Rc::new(zirql::copy_declaration(value, budget, &location)?))
}
impl<'a> composition::CompositionHost<'_, '_> {
pub(super) fn sequence_values(
&self,
value: &ReportValue<'a>,
element: &D<Kind>,
context: &mut Context<'_, 'a>,
budget: &mut Budget,
range: &Range<usize>,
) -> Result<Vec<ReportValue<'a>>, zirql::EvaluationError<QueryError>> {
let location = Location::Query(range.clone());
if let ReportValue::Sequence(sequence) = functions::unretained(value) {
if !zirql::declarations_compatible(&sequence.element, element, budget, &location)? {
return Err(zirql::QueryError::query(
range.clone(),
"native sequence element contract mismatch",
)
.into());
}
for value in sequence.values.iter() {
zirql::admit_value(value, element, self, context, budget, location.clone())?;
}
budget.check_items(sequence.values.len(), location.clone())?;
budget.charge_results(sequence.values.len(), location)?;
return sequence
.values
.iter()
.map(|value| self.copy_value(value, context, budget, range))
.collect();
}
zirql::admit_value(
value,
&D::Sequence(Box::new(element.clone())),
self,
context,
budget,
location,
)?;
let copied = self.copy_value(value, context, budget, range)?;
self.subjects(copied, context, budget, range)
}
pub(super) fn identity(
&self,
value: &ReportValue<'a>,
expected: &Kind,
context: &mut Context<'_, 'a>,
budget: &mut Budget,
range: &Range<usize>,
) -> Result<zirql::NativeIdentity, zirql::EvaluationError<QueryError>> {
zirql::admit_value(
value,
&D::Native(expected.clone()),
self,
context,
budget,
Location::Query(range.clone()),
)?;
match (expected, functions::unretained(value)) {
(
Kind::Declaration | Kind::Declarations,
ReportValue::Query(SemanticStream::Entities(rows)),
) if rows.len() == 1 => {
let semantic::SemanticEntity::Declaration(id) = rows[0] else {
unreachable!("admitted declaration")
};
let owner = owner(value).expect("admitted declaration owner");
Ok(zirql::NativeIdentity([
owner.bindings() as *const _ as usize as u64,
0,
id.0 as u64,
0,
]))
}
(Kind::Node | Kind::Nodes, ReportValue::Query(SemanticStream::Inspection(result)))
if matches!(result.as_ref(), QueryResult::Nodes(selection) if selection.nodes.len() == 1)
|| matches!(result.as_ref(), QueryResult::Selection(selection) if selection.items.len() == 1) =>
{
let (input, node) = match result.as_ref() {
QueryResult::Nodes(selection) => (selection.input, selection.nodes[0].node),
QueryResult::Selection(selection) => (selection.input, selection.items[0].node),
_ => unreachable!("admitted node"),
};
Ok(zirql::NativeIdentity([
input as *const _ as usize as u64,
1,
node as *const _ as usize as u64,
0,
]))
}
_ => Err(zirql::QueryError::query(
range.clone(),
"identity requires one Declaration or Node",
)
.into()),
}
}
}