tytanic_filter/eval/
set.rs1use std::fmt::Debug;
2use std::sync::Arc;
3
4use ecow::eco_vec;
5
6use super::Context;
7use super::Error;
8use super::Test;
9use super::TryFromValue;
10use super::Type;
11use super::Value;
12use crate::ast::Pat;
13
14type SetImpl<T> = Arc<dyn Fn(&Context<T>, &T) -> Result<bool, Error> + Send + Sync + 'static>;
16
17#[derive(Clone)]
22pub struct Set<T>(SetImpl<T>);
23
24impl<T> Set<T> {
25 pub fn new<F>(f: F) -> Self
27 where
28 F: Fn(&Context<T>, &T) -> Result<bool, Error> + Send + Sync + 'static,
29 {
30 Self(Arc::new(f) as _)
31 }
32
33 pub fn contains(&self, ctx: &Context<T>, test: &T) -> Result<bool, Error> {
35 (self.0)(ctx, test)
36 }
37}
38
39impl<T> Debug for Set<T> {
40 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
41 f.debug_tuple("Set").field(&..).finish()
42 }
43}
44
45impl<T: Test> Set<T> {
46 pub fn coerce_pat(pat: Pat) -> Set<T> {
50 Set::new(move |_, test: &T| Ok(pat.is_match(test.id())))
51 }
52}
53
54impl<T: 'static> Set<T> {
55 pub fn expr_comp(set: Set<T>) -> Self {
60 Self::new(move |ctx, test| Ok(!set.contains(ctx, test)?))
61 }
62
63 pub fn expr_union<I>(a: Set<T>, b: Set<T>, rest: I) -> Self
68 where
69 I: IntoIterator<Item = Set<T>>,
70 {
71 let sets: Vec<_> = [a, b].into_iter().chain(rest).collect();
72
73 Self::new(move |ctx, test| {
74 for set in &sets {
75 if set.contains(ctx, test)? {
76 return Ok(true);
77 }
78 }
79
80 Ok(false)
81 })
82 }
83
84 pub fn expr_inter<I>(a: Set<T>, b: Set<T>, rest: I) -> Self
89 where
90 I: IntoIterator<Item = Set<T>>,
91 {
92 let sets: Vec<_> = [a, b].into_iter().chain(rest).collect();
93
94 Self::new(move |ctx, test| {
95 for set in &sets {
96 if !set.contains(ctx, test)? {
97 return Ok(false);
98 }
99 }
100
101 Ok(true)
102 })
103 }
104
105 pub fn expr_diff(a: Set<T>, b: Set<T>) -> Self {
110 Self::new(move |ctx, test| Ok(a.contains(ctx, test)? && !b.contains(ctx, test)?))
111 }
112
113 pub fn expr_sym_diff(a: Set<T>, b: Set<T>) -> Self {
118 Self::new(move |ctx, test| Ok(a.contains(ctx, test)? ^ b.contains(ctx, test)?))
119 }
120}
121
122impl<T> TryFromValue<T> for Set<T> {
123 fn try_from_value(value: Value<T>) -> Result<Self, Error> {
124 Ok(match value {
125 Value::Set(set) => set,
126 _ => {
127 return Err(Error::TypeMismatch {
128 expected: eco_vec![Type::Set],
129 found: value.as_type(),
130 });
131 }
132 })
133 }
134}
135
136#[allow(dead_code)]
138fn assert_traits() {
139 tytanic_utils::assert::send::<Set<()>>();
140 tytanic_utils::assert::sync::<Set<()>>();
141}