sea_core/policy/
three_valued.rs1#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
4pub enum ThreeValuedBool {
5 True,
6 False,
7 Null,
8}
9
10impl ThreeValuedBool {
11 pub fn and(self, other: Self) -> Self {
12 use ThreeValuedBool::*;
13 match (self, other) {
14 (False, _) | (_, False) => False,
15 (True, True) => True,
16 (True, Null) | (Null, True) | (Null, Null) => Null,
17 }
18 }
19
20 pub fn or(self, other: Self) -> Self {
21 use ThreeValuedBool::*;
22 match (self, other) {
23 (True, _) | (_, True) => True,
24 (False, False) => False,
25 _ => Null,
26 }
27 }
28
29 #[allow(clippy::should_implement_trait)]
30 pub fn not(self) -> Self {
31 !self
32 }
33
34 pub fn implies(self, other: Self) -> Self {
35 (!self).or(other)
37 }
38
39 pub fn from_option_bool(v: Option<bool>) -> Self {
40 match v {
41 Some(true) => ThreeValuedBool::True,
42 Some(false) => ThreeValuedBool::False,
43 None => ThreeValuedBool::Null,
44 }
45 }
46
47 pub fn into_option(self) -> Option<bool> {
48 match self {
49 ThreeValuedBool::True => Some(true),
50 ThreeValuedBool::False => Some(false),
51 ThreeValuedBool::Null => None,
52 }
53 }
54
55 pub fn fold_and<I: IntoIterator<Item = Self>>(iter: I) -> Self {
56 let mut seen_null = false;
57 for v in iter {
58 match v {
59 ThreeValuedBool::False => return ThreeValuedBool::False,
60 ThreeValuedBool::Null => seen_null = true,
61 ThreeValuedBool::True => {}
62 }
63 }
64 if seen_null {
65 ThreeValuedBool::Null
66 } else {
67 ThreeValuedBool::True
68 }
69 }
70
71 pub fn fold_or<I: IntoIterator<Item = Self>>(iter: I) -> Self {
72 let mut seen_null = false;
73 for v in iter {
74 match v {
75 ThreeValuedBool::True => return ThreeValuedBool::True,
76 ThreeValuedBool::Null => seen_null = true,
77 ThreeValuedBool::False => {}
78 }
79 }
80 if seen_null {
81 ThreeValuedBool::Null
82 } else {
83 ThreeValuedBool::False
84 }
85 }
86}
87
88impl std::ops::Not for ThreeValuedBool {
89 type Output = Self;
90
91 fn not(self) -> Self::Output {
92 use ThreeValuedBool::*;
93 match self {
94 True => False,
95 False => True,
96 Null => Null,
97 }
98 }
99}
100
101pub mod aggregators {
102 #![allow(dead_code)]
103 use rust_decimal::Decimal;
104
105 pub fn sum_nullable(items: &[Option<Decimal>]) -> Option<Decimal> {
107 let mut total = Decimal::ZERO;
108 let mut any_null = false;
109 for item in items {
110 match item {
111 Some(v) => total += *v,
112 None => any_null = true,
113 }
114 }
115 if any_null {
116 None
117 } else {
118 Some(total)
119 }
120 }
121
122 pub fn sum_nonnull(items: &[Option<Decimal>]) -> Decimal {
124 let mut total = Decimal::ZERO;
125 for v in items.iter().flatten() {
126 total += *v;
127 }
128 total
129 }
130
131 pub fn count_all<T>(items: &[Option<T>]) -> usize {
133 items.len()
134 }
135
136 pub fn count_nonnull<T>(items: &[Option<T>]) -> usize {
138 items.iter().filter(|x| x.is_some()).count()
139 }
140}