tytanic_filter/eval/
set.rs1use std::fmt::Debug;
2use std::sync::Arc;
3
4use ecow::eco_vec;
5
6use super::{Context, Error, Test, TryFromValue, Type, Value};
7use crate::ast::Pat;
8
9type SetImpl<T> = Arc<dyn Fn(&Context<T>, &T) -> Result<bool, Error> + Send + Sync + 'static>;
11
12#[derive(Clone)]
17pub struct Set<T>(SetImpl<T>);
18
19impl<T> Set<T> {
20 pub fn new<F>(f: F) -> Self
22 where
23 F: Fn(&Context<T>, &T) -> Result<bool, Error> + Send + Sync + 'static,
24 {
25 Self(Arc::new(f) as _)
26 }
27
28 pub fn contains(&self, ctx: &Context<T>, test: &T) -> Result<bool, Error> {
30 (self.0)(ctx, test)
31 }
32}
33
34impl<T> Debug for Set<T> {
35 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
36 f.debug_tuple("Set").field(&..).finish()
37 }
38}
39
40impl<T: Test> Set<T> {
41 pub fn coerce_pat(pat: Pat) -> Set<T> {
45 Set::new(move |_, test: &T| Ok(pat.is_match(test.id())))
46 }
47}
48
49impl<T: 'static> Set<T> {
50 pub fn expr_comp(set: Set<T>) -> Self {
55 Self::new(move |ctx, test| Ok(!set.contains(ctx, test)?))
56 }
57
58 pub fn expr_union<I>(a: Set<T>, b: Set<T>, rest: I) -> Self
63 where
64 I: IntoIterator<Item = Set<T>>,
65 {
66 let sets: Vec<_> = [a, b].into_iter().chain(rest).collect();
67
68 Self::new(move |ctx, test| {
69 for set in &sets {
70 if set.contains(ctx, test)? {
71 return Ok(true);
72 }
73 }
74
75 Ok(false)
76 })
77 }
78
79 pub fn expr_inter<I>(a: Set<T>, b: Set<T>, rest: I) -> Self
84 where
85 I: IntoIterator<Item = Set<T>>,
86 {
87 let sets: Vec<_> = [a, b].into_iter().chain(rest).collect();
88
89 Self::new(move |ctx, test| {
90 for set in &sets {
91 if !set.contains(ctx, test)? {
92 return Ok(false);
93 }
94 }
95
96 Ok(true)
97 })
98 }
99
100 pub fn expr_diff(a: Set<T>, b: Set<T>) -> Self {
105 Self::new(move |ctx, test| Ok(a.contains(ctx, test)? && !b.contains(ctx, test)?))
106 }
107
108 pub fn expr_sym_diff(a: Set<T>, b: Set<T>) -> Self {
113 Self::new(move |ctx, test| Ok(a.contains(ctx, test)? ^ b.contains(ctx, test)?))
114 }
115}
116
117impl<T> TryFromValue<T> for Set<T> {
118 fn try_from_value(value: Value<T>) -> Result<Self, Error> {
119 Ok(match value {
120 Value::Set(set) => set,
121 _ => {
122 return Err(Error::TypeMismatch {
123 expected: eco_vec![Type::Set],
124 found: value.as_type(),
125 })
126 }
127 })
128 }
129}
130
131#[allow(dead_code)]
133fn assert_traits() {
134 tytanic_utils::assert::send::<Set<()>>();
135 tytanic_utils::assert::sync::<Set<()>>();
136}