WIP checkpoint schema8 analysis core before user reboot
This commit is contained in:
@@ -0,0 +1,146 @@
|
||||
use super::*;
|
||||
use crate::analysis_numeric::{NumericType, ResolvedKind, Unit};
|
||||
use crate::{Id, Project, SharedBody};
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
/// Bounded local nominal origin; no rooted graph is cloned during arithmetic.
|
||||
/// Full ResolvedKind equality additionally includes dimension/algebra/difference.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct KindHandle {
|
||||
model: Id,
|
||||
definition: Id,
|
||||
}
|
||||
impl KindHandle {
|
||||
pub fn definition(self) -> Id {
|
||||
self.definition
|
||||
}
|
||||
pub(crate) fn local(model: Id, definition: Id) -> Self {
|
||||
Self { model, definition }
|
||||
}
|
||||
}
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum ResolvedScalar {
|
||||
Boolean,
|
||||
Numeric(NumericType<KindHandle>),
|
||||
}
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum ResolvedType {
|
||||
Scalar(ResolvedScalar),
|
||||
List(ResolvedScalar),
|
||||
}
|
||||
impl ResolvedType {
|
||||
pub(crate) fn boolean() -> Self {
|
||||
Self::Scalar(ResolvedScalar::Boolean)
|
||||
}
|
||||
pub(crate) fn numeric(value: NumericType<KindHandle>) -> Self {
|
||||
Self::Scalar(ResolvedScalar::Numeric(value.normalized()))
|
||||
}
|
||||
}
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct EffectiveBinding<'a> {
|
||||
pub binding: &'a Binding,
|
||||
pub origin: BindingOrigin,
|
||||
}
|
||||
|
||||
/// Constructed only by admission; exact source/capture provenance stays with its owner.
|
||||
/// Values from different accepted environments must not be mixed by an evaluator.
|
||||
pub struct ResolvedAnalysis<'p> {
|
||||
pub(super) project: &'p Project,
|
||||
pub(super) kinds: BTreeMap<Id, ResolvedKind<KindHandle>>,
|
||||
pub(super) units: BTreeMap<Id, Unit<KindHandle>>,
|
||||
pub(super) limits: AdmissionLimits,
|
||||
pub(super) usage: AdmissionUsage,
|
||||
}
|
||||
impl<'p> ResolvedAnalysis<'p> {
|
||||
pub fn project(&self) -> &'p Project {
|
||||
self.project
|
||||
}
|
||||
pub fn admission_usage(&self) -> AdmissionUsage {
|
||||
self.usage
|
||||
}
|
||||
pub fn admission_limits(&self) -> AdmissionLimits {
|
||||
self.limits
|
||||
}
|
||||
pub fn definition(&self, reference: DefinitionRef) -> Option<&'p Definition> {
|
||||
self.project.definitions.get(&reference.local())
|
||||
}
|
||||
pub fn kind(&self, reference: DefinitionRef) -> Option<&ResolvedKind<KindHandle>> {
|
||||
self.kinds.get(&reference.local())
|
||||
}
|
||||
pub fn unit(&self, reference: DefinitionRef) -> Option<&Unit<KindHandle>> {
|
||||
self.units.get(&reference.local())
|
||||
}
|
||||
pub fn calculation(&self, reference: DefinitionRef) -> Option<&'p CalculationDefinition> {
|
||||
match &self.definition(reference)?.body {
|
||||
DefinitionBody::Calculation(value) => Some(value),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
pub fn declared_type(&self, value: &AnalysisType) -> Option<ResolvedType> {
|
||||
let (AnalysisType::Scalar(scalar) | AnalysisType::List(scalar)) = value;
|
||||
let scalar = match scalar {
|
||||
ScalarType::Boolean => ResolvedScalar::Boolean,
|
||||
ScalarType::Number => ResolvedScalar::Numeric(NumericType::Number),
|
||||
ScalarType::Quantity(reference) => {
|
||||
ResolvedScalar::Numeric(NumericType::Named(self.kind(*reference)?.clone()))
|
||||
}
|
||||
};
|
||||
Some(match value {
|
||||
AnalysisType::Scalar(_) => ResolvedType::Scalar(scalar),
|
||||
AnalysisType::List(_) => ResolvedType::List(scalar),
|
||||
})
|
||||
}
|
||||
pub fn effective_binding(
|
||||
&self,
|
||||
property: Id,
|
||||
context: EvaluationContext,
|
||||
) -> Result<EffectiveBinding<'p>, AnalysisError> {
|
||||
let element = self.project.elements.get(&property).ok_or_else(|| {
|
||||
AnalysisError::new(
|
||||
property,
|
||||
"context",
|
||||
"analysis_property",
|
||||
"Property does not exist.",
|
||||
)
|
||||
})?;
|
||||
let Some(SharedBody::EngineeringProperty { base, .. }) = element.shared() else {
|
||||
return Err(AnalysisError::new(
|
||||
property,
|
||||
"context",
|
||||
"analysis_property",
|
||||
"Target is not an engineering property.",
|
||||
));
|
||||
};
|
||||
if let EvaluationContext::Case(id) = context {
|
||||
let case = self.project.elements.get(&id).ok_or_else(|| {
|
||||
AnalysisError::new(id, "context", "analysis_case", "Case does not exist.")
|
||||
})?;
|
||||
let Some(SharedBody::AnalysisCase { overrides, .. }) = case.shared() else {
|
||||
return Err(AnalysisError::new(
|
||||
id,
|
||||
"context",
|
||||
"analysis_case",
|
||||
"Context is not an analysis case.",
|
||||
));
|
||||
};
|
||||
if case.layer() != element.layer() {
|
||||
return Err(AnalysisError::new(
|
||||
id,
|
||||
"context",
|
||||
"analysis_layer",
|
||||
"Case and property must share a layer.",
|
||||
));
|
||||
}
|
||||
if let Some(binding) = overrides.get(&property) {
|
||||
return Ok(EffectiveBinding {
|
||||
binding,
|
||||
origin: BindingOrigin::CaseOverride(id),
|
||||
});
|
||||
}
|
||||
}
|
||||
Ok(EffectiveBinding {
|
||||
binding: base,
|
||||
origin: BindingOrigin::ModelBaseline,
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user