sim_shape/primitives/combinators/
one_of.rs1use std::sync::Arc;
4
5use sim_kernel::{Cx, Expr, Result, Value, shape_is_subshape_of};
6
7use crate::base::{Bindings, MatchScore, Shape, ShapeDoc, ShapeMatch};
8
9pub struct OneOfShape {
15 choices: Vec<Arc<dyn Shape>>,
16}
17
18impl OneOfShape {
19 pub fn new(choices: Vec<Arc<dyn Shape>>) -> Self {
21 Self { choices }
22 }
23
24 pub fn choices(&self) -> &[Arc<dyn Shape>] {
26 &self.choices
27 }
28}
29
30impl Shape for OneOfShape {
31 fn is_effectful(&self) -> bool {
32 self.choices.iter().any(|choice| choice.is_effectful())
33 }
34
35 fn is_total(&self) -> bool {
36 self.choices.iter().any(|choice| choice.is_total())
37 }
38
39 fn is_subshape_of(&self, cx: &mut Cx, parent: &dyn Shape) -> Result<Option<bool>> {
40 for choice in &self.choices {
41 if !shape_is_subshape_of(cx, choice.as_ref(), parent)? {
42 return Ok(Some(false));
43 }
44 }
45 Ok(Some(true))
46 }
47
48 fn check_value(&self, cx: &mut Cx, value: Value) -> Result<ShapeMatch> {
49 let mut diagnostics = Vec::new();
50 for choice in &self.choices {
51 let matched = choice.check_value(cx, value.clone())?;
52 if matched.accepted {
53 return Ok(matched);
54 }
55 diagnostics.extend(matched.diagnostics);
56 }
57 Ok(ShapeMatch {
58 accepted: false,
59 captures: Bindings::new(),
60 score: MatchScore::reject(),
61 diagnostics,
62 })
63 }
64
65 fn check_expr(&self, cx: &mut Cx, expr: &Expr) -> Result<ShapeMatch> {
66 let mut diagnostics = Vec::new();
67 for choice in &self.choices {
68 let matched = choice.check_expr(cx, expr)?;
69 if matched.accepted {
70 return Ok(matched);
71 }
72 diagnostics.extend(matched.diagnostics);
73 }
74 Ok(ShapeMatch {
75 accepted: false,
76 captures: Bindings::new(),
77 score: MatchScore::reject(),
78 diagnostics,
79 })
80 }
81
82 fn describe(&self, cx: &mut Cx) -> Result<ShapeDoc> {
83 let mut doc = ShapeDoc::new("one-of shape");
84 for choice in &self.choices {
85 doc = doc.with_detail(choice.describe(cx)?.name);
86 }
87 Ok(doc)
88 }
89}