Skip to main content

sim_lib_interference_runtime/
shapes.rs

1//! Runtime Shapes for interference call arguments and results.
2
3use std::{marker::PhantomData, sync::Arc};
4
5use sim_kernel::{Cx, Expr, MatchScore, Result, Shape, ShapeDoc, ShapeMatch, Symbol, Value};
6use sim_shape::shape_value;
7
8use crate::{
9    PlaneDescriptor, ProblemDescriptor, ProjectionRequestDescriptor, ScalarProjectionDescriptor,
10    StudyDescriptor, citizen::RecordCitizenSpec,
11};
12
13/// Shape symbol for coherent problem records.
14pub fn problem_shape_symbol() -> Symbol {
15    Symbol::qualified("interference", "Problem")
16}
17
18/// Shape symbol for physical sampling-plane records.
19pub fn plane_shape_symbol() -> Symbol {
20    Symbol::qualified("interference", "Plane")
21}
22
23/// Shape symbol for complete Tensor-backed studies.
24pub fn study_shape_symbol() -> Symbol {
25    Symbol::qualified("interference", "Study")
26}
27
28/// Shape symbol for scalar projection requests.
29pub fn projection_request_shape_symbol() -> Symbol {
30    Symbol::qualified("interference", "ProjectionRequest")
31}
32
33/// Shape symbol for scalar projection results.
34pub fn projection_shape_symbol() -> Symbol {
35    Symbol::qualified("interference", "Projection")
36}
37
38/// Returns the five public Shape symbols registered by the record library.
39pub fn interference_shape_symbols() -> Vec<Symbol> {
40    vec![
41        problem_shape_symbol(),
42        plane_shape_symbol(),
43        study_shape_symbol(),
44        projection_request_shape_symbol(),
45        projection_shape_symbol(),
46    ]
47}
48
49pub(crate) fn register_interference_shapes(linker: &mut sim_kernel::Linker<'_>) -> Result<()> {
50    for (symbol, shape) in shape_specs() {
51        linker.shape_value(symbol.clone(), shape_value(symbol, shape))?;
52    }
53    Ok(())
54}
55
56fn shape_specs() -> Vec<(Symbol, Arc<dyn Shape>)> {
57    vec![
58        (problem_shape_symbol(), problem_shape()),
59        (plane_shape_symbol(), plane_shape()),
60        (study_shape_symbol(), study_shape()),
61        (
62            projection_request_shape_symbol(),
63            projection_request_shape(),
64        ),
65        (projection_shape_symbol(), projection_shape()),
66    ]
67}
68
69pub(crate) fn problem_shape() -> Arc<dyn Shape> {
70    record_shape::<ProblemDescriptor>(
71        problem_shape_symbol(),
72        "Problem",
73        "checked coherent single-frequency problem",
74    )
75}
76
77pub(crate) fn plane_shape() -> Arc<dyn Shape> {
78    record_shape::<PlaneDescriptor>(
79        plane_shape_symbol(),
80        "Plane",
81        "checked orthonormal finite physical sampling plane",
82    )
83}
84
85pub(crate) fn study_shape() -> Arc<dyn Shape> {
86    record_shape::<StudyDescriptor>(
87        study_shape_symbol(),
88        "Study",
89        "Tensor field with matching problem, plane, sampling, work, and provider evidence",
90    )
91}
92
93pub(crate) fn projection_request_shape() -> Arc<dyn Shape> {
94    record_shape::<ProjectionRequestDescriptor>(
95        projection_request_shape_symbol(),
96        "ProjectionRequest",
97        "checked observable, phase floor, target dimensions, and detector rule",
98    )
99}
100
101pub(crate) fn projection_shape() -> Arc<dyn Shape> {
102    record_shape::<ScalarProjectionDescriptor>(
103        projection_shape_symbol(),
104        "Projection",
105        "one-Tensor scalar projection with exact mask and certificate",
106    )
107}
108
109fn record_shape<T>(symbol: Symbol, name: &'static str, detail: &'static str) -> Arc<dyn Shape>
110where
111    T: RecordCitizenSpec,
112{
113    Arc::new(RecordShape::<T> {
114        symbol,
115        name,
116        detail,
117        marker: PhantomData,
118    })
119}
120
121struct RecordShape<T> {
122    symbol: Symbol,
123    name: &'static str,
124    detail: &'static str,
125    marker: PhantomData<T>,
126}
127
128impl<T> Shape for RecordShape<T>
129where
130    T: RecordCitizenSpec,
131{
132    fn symbol(&self) -> Option<Symbol> {
133        Some(self.symbol.clone())
134    }
135
136    fn check_value(&self, _cx: &mut Cx, value: Value) -> Result<ShapeMatch> {
137        let Some(record) = value.object().downcast_ref::<T>() else {
138            return Ok(ShapeMatch::reject(format!("{} record expected", self.name)));
139        };
140        Ok(match record.validate() {
141            Ok(()) => ShapeMatch::accept(MatchScore::exact(100)),
142            Err(error) => ShapeMatch::reject(format!("malformed {}: {error}", self.name)),
143        })
144    }
145
146    fn check_expr(&self, cx: &mut Cx, expr: &Expr) -> Result<ShapeMatch> {
147        let value = cx.eval_expr(expr.clone())?;
148        self.check_value(cx, value)
149    }
150
151    fn describe(&self, _cx: &mut Cx) -> Result<ShapeDoc> {
152        Ok(ShapeDoc::new(self.name).with_detail(self.detail))
153    }
154}