sim_lib_interference_runtime/
shapes.rs1use 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
13pub fn problem_shape_symbol() -> Symbol {
15 Symbol::qualified("interference", "Problem")
16}
17
18pub fn plane_shape_symbol() -> Symbol {
20 Symbol::qualified("interference", "Plane")
21}
22
23pub fn study_shape_symbol() -> Symbol {
25 Symbol::qualified("interference", "Study")
26}
27
28pub fn projection_request_shape_symbol() -> Symbol {
30 Symbol::qualified("interference", "ProjectionRequest")
31}
32
33pub fn projection_shape_symbol() -> Symbol {
35 Symbol::qualified("interference", "Projection")
36}
37
38pub 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}