sim_shape/compare/
venn.rs1use std::{collections::BTreeSet, sync::Arc};
5
6use sim_kernel::{ClassRef, Cx, Error, Expr, Object, ObjectEncode, ObjectEncoding, Result, Symbol};
7
8use crate::{AndShape, NotShape, OrShape, Shape};
9
10#[derive(Clone)]
15pub struct VennShapeSet {
16 members: Vec<(Symbol, Arc<dyn Shape>)>,
17}
18
19impl VennShapeSet {
20 pub fn new(members: Vec<(Symbol, Arc<dyn Shape>)>) -> Self {
22 Self { members }
23 }
24
25 pub fn members(&self) -> &[(Symbol, Arc<dyn Shape>)] {
27 &self.members
28 }
29
30 pub fn union(&self) -> Arc<dyn Shape> {
32 Arc::new(OrShape::new(self.member_shapes()))
33 }
34
35 pub fn intersection(&self) -> Arc<dyn Shape> {
37 Arc::new(AndShape::new(self.member_shapes()))
38 }
39
40 pub fn only(&self, name: &Symbol) -> Result<Arc<dyn Shape>> {
42 let target = self.member_shape(name)?.clone();
43 let others = self
44 .members
45 .iter()
46 .filter(|(candidate, _)| candidate != name)
47 .map(|(_, shape)| shape.clone())
48 .collect::<Vec<_>>();
49 if others.is_empty() {
50 return Ok(target);
51 }
52 Ok(Arc::new(AndShape::new(vec![
53 target,
54 Arc::new(NotShape::new(Arc::new(OrShape::new(others)))),
55 ])))
56 }
57
58 pub fn outside_all(&self) -> Arc<dyn Shape> {
60 Arc::new(NotShape::new(self.union()))
61 }
62
63 pub fn exactly(&self, names: &[Symbol]) -> Result<Arc<dyn Shape>> {
65 let selected = names.iter().cloned().collect::<BTreeSet<_>>();
66 for name in &selected {
67 self.member_shape(name)?;
68 }
69
70 let mut parts = Vec::new();
71 let mut others = Vec::new();
72 for (name, shape) in &self.members {
73 if selected.contains(name) {
74 parts.push(shape.clone());
75 } else {
76 others.push(shape.clone());
77 }
78 }
79 if !others.is_empty() {
80 parts.push(Arc::new(NotShape::new(Arc::new(OrShape::new(others)))));
81 }
82 Ok(Arc::new(AndShape::new(parts)))
83 }
84
85 fn member_shape(&self, name: &Symbol) -> Result<&Arc<dyn Shape>> {
86 self.members
87 .iter()
88 .find_map(|(candidate, shape)| (candidate == name).then_some(shape))
89 .ok_or_else(|| Error::Eval(format!("shape-venn: unknown member {name}")))
90 }
91
92 fn member_shapes(&self) -> Vec<Arc<dyn Shape>> {
93 self.members
94 .iter()
95 .map(|(_, shape)| shape.clone())
96 .collect()
97 }
98}
99
100impl Object for VennShapeSet {
101 fn display(&self, _cx: &mut Cx) -> Result<String> {
102 Ok(format!("#<shape-venn {} members>", self.members.len()))
103 }
104
105 fn as_any(&self) -> &dyn std::any::Any {
106 self
107 }
108}
109
110impl sim_kernel::ObjectCompat for VennShapeSet {
111 fn class(&self, cx: &mut Cx) -> Result<ClassRef> {
112 let symbol = crate::citizen::venn_shape_set_class_symbol();
113 if let Some(value) = cx.registry().class_by_symbol(&symbol) {
114 return Ok(value.clone());
115 }
116 cx.factory().nil()
117 }
118
119 fn as_expr(&self, cx: &mut Cx) -> Result<Expr> {
120 match self.object_encoding(cx)? {
121 ObjectEncoding::Constructor { class, args } => Ok(Expr::Call {
122 operator: Box::new(Expr::Symbol(class)),
123 args,
124 }),
125 _ => Err(Error::Eval(
126 "venn shape set produced a non-constructor object encoding; only \
127 constructor encodings can render as an expression"
128 .to_owned(),
129 )),
130 }
131 }
132
133 fn as_object_encoder(&self) -> Option<&dyn ObjectEncode> {
134 Some(self)
135 }
136}