1use std::sync::Arc;
2
3use sim_kernel::{Cx, Error, Result, ShapeId, ShapeRef, Symbol, Value};
4use sim_shape::{Shape, ShapeDoc, ShapeMatch};
5
6pub const CORE_SHAPE_CLASS: &str = "Shape";
8
9pub use sim_shape::{shape_value, shape_value_with_encoding};
10
11pub struct DocumentedShape {
14 name: String,
15 details: Vec<String>,
16 inner: Arc<dyn Shape>,
17}
18
19impl DocumentedShape {
20 pub fn new(
22 name: impl Into<String>,
23 details: impl IntoIterator<Item = impl Into<String>>,
24 inner: Arc<dyn Shape>,
25 ) -> Self {
26 Self {
27 name: name.into(),
28 details: details.into_iter().map(Into::into).collect(),
29 inner,
30 }
31 }
32}
33
34impl Shape for DocumentedShape {
35 fn is_total(&self) -> bool {
36 self.inner.is_total()
37 }
38
39 fn parents(&self, cx: &mut Cx) -> Result<Vec<ShapeRef>> {
40 self.inner.parents(cx)
41 }
42
43 fn is_subshape_of(&self, cx: &mut Cx, parent: &dyn Shape) -> Result<Option<bool>> {
44 self.inner.is_subshape_of(cx, parent)
45 }
46
47 fn check_value(&self, cx: &mut Cx, value: Value) -> Result<sim_shape::ShapeMatch> {
48 self.inner.check_value(cx, value)
49 }
50
51 fn check_expr(&self, cx: &mut Cx, expr: &sim_kernel::Expr) -> Result<sim_shape::ShapeMatch> {
52 self.inner.check_expr(cx, expr)
53 }
54
55 fn describe(&self, _cx: &mut Cx) -> Result<ShapeDoc> {
56 let mut doc = ShapeDoc::new(self.name.clone());
57 for detail in &self.details {
58 doc = doc.with_detail(detail.clone());
59 }
60 Ok(doc)
61 }
62}
63
64pub fn shape_id(cx: &mut Cx, symbol: Symbol, shape: Arc<dyn Shape>) -> sim_kernel::ShapeId {
66 cx.registry_mut()
67 .register_shape_value(symbol.clone(), shape_value(symbol, shape))
68 .expect("shape registration should not duplicate symbols")
69}
70
71pub fn value_as_shape(value: &Value) -> Result<&dyn Shape> {
73 value.object().as_shape().ok_or(Error::TypeMismatch {
74 expected: "shape",
75 found: "non-shape",
76 })
77}
78
79pub fn shape_ref_as_shape(shape: &ShapeRef) -> Result<&dyn Shape> {
81 value_as_shape(shape)
82}
83
84#[derive(Clone)]
85struct ValueBackedShape {
86 value: ShapeRef,
87}
88
89impl Shape for ValueBackedShape {
90 fn id(&self) -> Option<ShapeId> {
91 self.value.object().as_shape().and_then(|shape| shape.id())
92 }
93
94 fn symbol(&self) -> Option<Symbol> {
95 self.value
96 .object()
97 .as_shape()
98 .and_then(|shape| shape.symbol())
99 }
100
101 fn parents(&self, cx: &mut Cx) -> Result<Vec<ShapeRef>> {
102 shape_ref_as_shape(&self.value)?.parents(cx)
103 }
104
105 fn is_effectful(&self) -> bool {
106 self.value
107 .object()
108 .as_shape()
109 .map(Shape::is_effectful)
110 .unwrap_or(false)
111 }
112
113 fn is_total(&self) -> bool {
114 self.value
115 .object()
116 .as_shape()
117 .map(Shape::is_total)
118 .unwrap_or(false)
119 }
120
121 fn is_subshape_of(&self, cx: &mut Cx, parent: &dyn Shape) -> Result<Option<bool>> {
122 shape_ref_as_shape(&self.value)?.is_subshape_of(cx, parent)
123 }
124
125 fn check_value(&self, cx: &mut Cx, value: Value) -> Result<ShapeMatch> {
126 shape_ref_as_shape(&self.value)?.check_value(cx, value)
127 }
128
129 fn check_expr(&self, cx: &mut Cx, expr: &sim_kernel::Expr) -> Result<ShapeMatch> {
130 shape_ref_as_shape(&self.value)?.check_expr(cx, expr)
131 }
132
133 fn describe(&self, cx: &mut Cx) -> Result<ShapeDoc> {
134 shape_ref_as_shape(&self.value)?.describe(cx)
135 }
136}
137
138pub fn shape_ref_arc(shape: &ShapeRef) -> Result<Arc<dyn Shape>> {
140 let _ = shape_ref_as_shape(shape)?;
141 Ok(Arc::new(ValueBackedShape {
142 value: shape.clone(),
143 }))
144}
145
146pub fn shape_ref_id(shape: &ShapeRef) -> ShapeId {
148 shape_ref_as_shape(shape)
149 .ok()
150 .and_then(|shape| shape.id())
151 .unwrap_or(ShapeId(0))
152}
153
154pub fn check_shape_value(cx: &mut Cx, shape: &ShapeRef, value: Value) -> Result<ShapeMatch> {
156 shape_ref_as_shape(shape)?.check_value(cx, value)
157}
158
159pub fn check_shape_expr(
161 cx: &mut Cx,
162 shape: &ShapeRef,
163 expr: &sim_kernel::Expr,
164) -> Result<ShapeMatch> {
165 shape_ref_as_shape(shape)?.check_expr(cx, expr)
166}