ternlog/
lib.rs

1#![no_std]
2#![doc = include_str!("../README.md")]
3
4/// Extension trait to compute ternary logic on integer types.
5///
6/// To use, import it:
7/// ```
8/// use ternlog::TernLog;
9/// ```
10pub trait TernLog {
11    /// Compute "ternary logic" using an 8-entry lookup table.
12    ///
13    /// For each bit, the expression will be computed as:
14    /// | `a` | `b` | `c` | `lut`                 |
15    /// | --- | --- | --- | --------------------- |
16    /// | `0` | `0` | `0` | `lut & (1 << 0) != 0` |
17    /// | `0` | `0` | `1` | `lut & (1 << 1) != 0` |
18    /// | `0` | `1` | `0` | `lut & (1 << 2) != 0` |
19    /// | `0` | `1` | `1` | `lut & (1 << 3) != 0` |
20    /// | `1` | `0` | `0` | `lut & (1 << 4) != 0` |
21    /// | `1` | `0` | `1` | `lut & (1 << 5) != 0` |
22    /// | `1` | `1` | `0` | `lut & (1 << 6) != 0` |
23    /// | `1` | `1` | `1` | `lut & (1 << 7) != 0` |
24    ///
25    /// If `lut` is constant, prefer using [`Self::const_ternlog`] instead.
26    ///
27    /// # Example
28    ///
29    /// ```
30    /// // if sprite_mask { background } else { sprite }
31    /// background.ternlog(sprite, sprite_mask, 0xe4)
32    /// ```
33    fn ternlog(self, b: Self, c: Self, lut: u8) -> Self;
34    /// Same as [`Self::ternlog`], but with a guaranteed compile-time constant table.
35    ///
36    /// # Example
37    ///
38    /// ```
39    /// // if sprite_mask { background } else { sprite }
40    /// background.ternlog::<0xe4>(sprite, sprite_mask)
41    /// ```
42    fn const_ternlog<const LUT: u8>(self, b: Self, c: Self) -> Self;
43}
44
45macro_rules! impl_ternlog {
46    ($($ty:ident)*) => {
47        $(impl TernLog for $ty {
48            fn ternlog(self, b: Self, c: Self, lut: u8) -> Self {
49                ternlog(self as _, b as _, c as _, lut) as _
50            }
51            fn const_ternlog<const LUT: u8>(self, b: Self, c: Self) -> Self {
52                ternlog(self as _, b as _, c as _, LUT) as _
53            }
54        })*
55    };
56}
57
58impl_ternlog![u8 i8 u16 i16 u32 i32 u64 i64 u128 i128 usize isize];
59
60impl TernLog for bool {
61    fn ternlog(self, b: Self, c: Self, lut: u8) -> Self {
62        ternlog(self as _, b as _, c as _, lut) & 1 != 0
63    }
64    fn const_ternlog<const LUT: u8>(self, b: Self, c: Self) -> Self {
65        ternlog(self as _, b as _, c as _, LUT) & 1 != 0
66    }
67}
68
69#[inline(always)]
70fn ternlog(a: u128, b: u128, c: u128, lut: u8) -> u128 {
71    match lut {
72        0b00000000 => c ^ c,
73        0b00000001 => !c ^ (!c & (b | a)),
74        0b00000010 => c ^ (c & (b | a)),
75        0b00000011 => !b & !a,
76        0b00000100 => b ^ (b & (c | a)),
77        0b00000101 => !c & !a,
78        0b00000110 => !a & (c ^ b),
79        0b00000111 => !a & (!c | !b),
80        0b00001000 => !a & (c & b),
81        0b00001001 => !c ^ ((c & a) ^ (b | a)),
82        0b00001010 => c & !a,
83        0b00001011 => a ^ (!b | (c | a)),
84        0b00001100 => b & !a,
85        0b00001101 => a ^ (!c | (b | a)),
86        0b00001110 => !a & (c | b),
87        0b00001111 => !a,
88        0b00010000 => a ^ (a & (c | b)),
89        0b00010001 => !c & !b,
90        0b00010010 => !b & (c ^ a),
91        0b00010011 => !b & (!c | !a),
92        0b00010100 => !c & (b ^ a),
93        0b00010101 => !c ^ (!c & (b & a)),
94        0b00010110 => c ^ ((c & b) | (b ^ a)),
95        0b00010111 => !c ^ ((c ^ b) & (c ^ a)),
96        0b00011000 => (c ^ a) & (b ^ a),
97        0b00011001 => c ^ (!b | (c & a)),
98        0b00011010 => a ^ (c | (b & a)),
99        0b00011011 => !c ^ ((c | b) ^ (c & a)),
100        0b00011100 => a ^ (b | (c & a)),
101        0b00011101 => !c ^ (b & (c ^ a)),
102        0b00011110 => a ^ (c | b),
103        0b00011111 => a ^ (!a | (c | b)),
104        0b00100000 => !b & (c & a),
105        0b00100001 => !c ^ ((c & b) ^ (b | a)),
106        0b00100010 => c & !b,
107        0b00100011 => b ^ (!a | (c | b)),
108        0b00100100 => (c ^ b) & (b ^ a),
109        0b00100101 => c ^ (!a | (c & b)),
110        0b00100110 => b ^ (c | (b & a)),
111        0b00100111 => !c ^ ((c & b) ^ (c | a)),
112        0b00101000 => c & (b ^ a),
113        0b00101001 => (c | !b) & (!c ^ (b ^ a)),
114        0b00101010 => c ^ (c & (b & a)),
115        0b00101011 => !c ^ ((c ^ b) | (c ^ a)),
116        0b00101100 => (c | b) & (b ^ a),
117        0b00101101 => c ^ (!a ^ (c & b)),
118        0b00101110 => (c | b) ^ (b & a),
119        0b00101111 => !a | (c & !b),
120        0b00110000 => b ^ (b | a),
121        0b00110001 => b ^ (!c | (b | a)),
122        0b00110010 => !b & (c | a),
123        0b00110011 => !b,
124        0b00110100 => b ^ (a | (c & b)),
125        0b00110101 => !c ^ (a & (c ^ b)),
126        0b00110110 => b ^ (c | a),
127        0b00110111 => b ^ (!b | (c | a)),
128        0b00111000 => (c | a) & (b ^ a),
129        0b00111001 => c ^ (!b ^ (c & a)),
130        0b00111010 => (c | a) ^ (b & a),
131        0b00111011 => !b | (c & !a),
132        0b00111100 => b ^ a,
133        0b00111101 => !b ^ (!a & (c | b)),
134        0b00111110 => (c ^ b) ^ ((c ^ a) & (b | a)),
135        0b00111111 => !b | !a,
136        0b01000000 => !c & (b & a),
137        0b01000001 => !c & (b ^ !a),
138        0b01000010 => (c ^ b) & (c ^ a),
139        0b01000011 => b ^ (!a | (c & b)),
140        0b01000100 => c ^ (c | b),
141        0b01000101 => c ^ (!a | (c | b)),
142        0b01000110 => c ^ (b | (c & a)),
143        0b01000111 => !c ^ (!b & (c ^ a)),
144        0b01001000 => b & (c ^ a),
145        0b01001001 => (c | a) ^ (!b | (c & a)),
146        0b01001010 => (c | b) & (c ^ a),
147        0b01001011 => c ^ (!a ^ (c | b)),
148        0b01001100 => c ^ ((c ^ b) | (c & a)),
149        0b01001101 => !c ^ ((c ^ a) & (b ^ a)),
150        0b01001110 => (c | b) ^ (c & a),
151        0b01001111 => !a | (c ^ (c | b)),
152        0b01010000 => c ^ (c | a),
153        0b01010001 => c ^ (!b | (c | a)),
154        0b01010010 => c ^ (a | (c & b)),
155        0b01010011 => !c ^ (!a & (c ^ b)),
156        0b01010100 => !c & (b | a),
157        0b01010101 => !c,
158        0b01010110 => c ^ (b | a),
159        0b01010111 => c ^ (!c | (b | a)),
160        0b01011000 => (c ^ a) & (b | a),
161        0b01011001 => c ^ (a | !b),
162        0b01011010 => c ^ a,
163        0b01011011 => !c ^ (!a & (c | b)),
164        0b01011100 => (c & a) ^ (b | a),
165        0b01011101 => !c | (b & !a),
166        0b01011110 => (c ^ b) ^ ((c | a) & (b ^ a)),
167        0b01011111 => !c | !a,
168        0b01100000 => a & (c ^ b),
169        0b01100001 => (c | b) ^ (!a | (c & b)),
170        0b01100010 => (c ^ b) & (c | a),
171        0b01100011 => c ^ (!b ^ (c | a)),
172        0b01100100 => (c ^ b) & (b | a),
173        0b01100101 => c ^ (b | !a),
174        0b01100110 => c ^ b,
175        0b01100111 => !c ^ (!b & (c | a)),
176        0b01101000 => (c & b) ^ (a & (c | b)),
177        0b01101001 => !c ^ (b ^ a),
178        0b01101010 => c ^ (b & a),
179        0b01101011 => !b ^ ((c ^ a) & (b | a)),
180        0b01101100 => b ^ (c & a),
181        0b01101101 => !c ^ ((c | a) & (b ^ a)),
182        0b01101110 => (c & b) ^ ((c ^ b) | (c & a)),
183        0b01101111 => !a | (c ^ b),
184        0b01110000 => c ^ ((c & b) | (c ^ a)),
185        0b01110001 => !c ^ ((c ^ b) & (b ^ a)),
186        0b01110010 => (c & b) ^ (c | a),
187        0b01110011 => !b | (c ^ (c | a)),
188        0b01110100 => (c & b) ^ (b | a),
189        0b01110101 => !c | (b ^ (b | a)),
190        0b01110110 => (c & b) ^ (c | (b | a)),
191        0b01110111 => !c | !b,
192        0b01111000 => a ^ (c & b),
193        0b01111001 => !c ^ ((c | b) & (b ^ a)),
194        0b01111010 => (c & a) ^ ((c & b) | (c ^ a)),
195        0b01111011 => !b | (c ^ a),
196        0b01111100 => (c ^ (c | b)) | (b ^ a),
197        0b01111101 => !c | (b ^ a),
198        0b01111110 => (c ^ b) | (c ^ a),
199        0b01111111 => c ^ (!c | (b & a)),
200        0b10000000 => c & (b & a),
201        0b10000001 => (c | b) ^ (!a | (c ^ b)),
202        0b10000010 => c ^ (c & (b ^ a)),
203        0b10000011 => (c | !b) & (b ^ !a),
204        0b10000100 => c ^ ((c | b) ^ (b & a)),
205        0b10000101 => (c & !a) ^ (!a | (c & b)),
206        0b10000110 => c ^ ((c | b) & (b ^ a)),
207        0b10000111 => !a ^ (c & b),
208        0b10001000 => c & b,
209        0b10001001 => (c ^ b) ^ (!a | (c | b)),
210        0b10001010 => c & (b | !a),
211        0b10001011 => a ^ (!b | (c ^ a)),
212        0b10001100 => b & (c | !a),
213        0b10001101 => a ^ (!c | (b ^ a)),
214        0b10001110 => c ^ ((c ^ b) & (b ^ a)),
215        0b10001111 => !a | (c & b),
216        0b10010000 => c ^ ((c | a) ^ (b & a)),
217        0b10010001 => (c & !b) ^ (!b | (c & a)),
218        0b10010010 => c ^ ((c | a) & (b ^ a)),
219        0b10010011 => !b ^ (c & a),
220        0b10010100 => b ^ ((c ^ a) & (b | a)),
221        0b10010101 => !c ^ (b & a),
222        0b10010110 => c ^ (b ^ a),
223        0b10010111 => (c | !b) ^ ((c | b) & (b ^ a)),
224        0b10011000 => c ^ (!b & (c | a)),
225        0b10011001 => c ^ !b,
226        0b10011010 => (c ^ b) ^ (b | a),
227        0b10011011 => !b ^ (c & (b | a)),
228        0b10011100 => (c ^ b) ^ (c | a),
229        0b10011101 => !c ^ (b & (c | a)),
230        0b10011110 => (c & b) | (c ^ (b ^ a)),
231        0b10011111 => a ^ (!a | (c ^ b)),
232        0b10100000 => c & a,
233        0b10100001 => (c ^ a) ^ (!b | (c | a)),
234        0b10100010 => c & (a | !b),
235        0b10100011 => b ^ (!a | (c ^ b)),
236        0b10100100 => c ^ (!a & (c | b)),
237        0b10100101 => c ^ !a,
238        0b10100110 => (c ^ b) ^ (b & a),
239        0b10100111 => !a ^ (c & (b | a)),
240        0b10101000 => c & (b | a),
241        0b10101001 => !c ^ (b | a),
242        0b10101010 => c,
243        0b10101011 => c | (!c ^ (b | a)),
244        0b10101100 => c ^ (!a & (c ^ b)),
245        0b10101101 => !c ^ (a | (c & b)),
246        0b10101110 => c | (b & !a),
247        0b10101111 => c | !a,
248        0b10110000 => a & (c | !b),
249        0b10110001 => b ^ (!c | (b ^ a)),
250        0b10110010 => c ^ ((c ^ a) & (b ^ a)),
251        0b10110011 => !b | (c & a),
252        0b10110100 => (c & b) ^ (b ^ a),
253        0b10110101 => !c ^ (a & (c | b)),
254        0b10110110 => (c | b) ^ ((c ^ a) & (b | a)),
255        0b10110111 => b ^ (!b | (c ^ a)),
256        0b10111000 => c ^ (!b & (c ^ a)),
257        0b10111001 => !c ^ (b | (c & a)),
258        0b10111010 => c | (b ^ (b | a)),
259        0b10111011 => c | !b,
260        0b10111100 => (c & b) | (b ^ a),
261        0b10111101 => (c | !c) ^ ((c ^ b) & (c ^ a)),
262        0b10111110 => c | (b ^ a),
263        0b10111111 => c | (!c ^ (b & a)),
264        0b11000000 => b & a,
265        0b11000001 => (c ^ !b) ^ ((c ^ a) & (b | a)),
266        0b11000010 => b ^ (!a & (c | b)),
267        0b11000011 => b ^ !a,
268        0b11000100 => b & (a | !c),
269        0b11000101 => c ^ (!a | (c ^ b)),
270        0b11000110 => (c ^ b) ^ (c & a),
271        0b11000111 => !a ^ (b & (c | a)),
272        0b11001000 => b & (c | a),
273        0b11001001 => !b ^ (c | a),
274        0b11001010 => c ^ (a & (c ^ b)),
275        0b11001011 => !b ^ (a | (c & b)),
276        0b11001100 => b,
277        0b11001101 => b | (!c & !a),
278        0b11001110 => c ^ ((c ^ b) & (b | a)),
279        0b11001111 => b | !a,
280        0b11010000 => a & (b | !c),
281        0b11010001 => c ^ (!b | (c ^ a)),
282        0b11010010 => (c & b) ^ (c ^ a),
283        0b11010011 => !b ^ (a & (c | b)),
284        0b11010100 => c ^ ((c ^ b) | (c ^ a)),
285        0b11010101 => !c | (b & a),
286        0b11010110 => (c | b) ^ ((c | a) & (b ^ a)),
287        0b11010111 => c ^ (!c | (b ^ a)),
288        0b11011000 => c ^ ((c & b) ^ (c | a)),
289        0b11011001 => !b ^ (c | (b & a)),
290        0b11011010 => (c & b) | (c ^ a),
291        0b11011011 => (c & a) ^ (!b | (c ^ a)),
292        0b11011100 => b | (c ^ (c | a)),
293        0b11011101 => b | !c,
294        0b11011110 => b | (c ^ a),
295        0b11011111 => b | (!c | !a),
296        0b11100000 => a & (c | b),
297        0b11100001 => !a ^ (c | b),
298        0b11100010 => c ^ (b & (c ^ a)),
299        0b11100011 => !a ^ (b | (c & a)),
300        0b11100100 => c ^ ((c | b) ^ (c & a)),
301        0b11100101 => !a ^ (c | (b & a)),
302        0b11100110 => (c ^ b) | (c & a),
303        0b11100111 => (c & b) ^ (!a | (c ^ b)),
304        0b11101000 => c ^ ((c ^ b) & (c ^ a)),
305        0b11101001 => !c ^ ((c & b) | (b ^ a)),
306        0b11101010 => c | (b & a),
307        0b11101011 => c | (b ^ !a),
308        0b11101100 => b | (c & a),
309        0b11101101 => b | (c ^ !a),
310        0b11101110 => c | b,
311        0b11101111 => !a | (c | b),
312        0b11110000 => a,
313        0b11110001 => a | (!c & !b),
314        0b11110010 => c ^ ((c ^ a) & (b | a)),
315        0b11110011 => a | !b,
316        0b11110100 => b ^ ((c | a) & (b ^ a)),
317        0b11110101 => a | !c,
318        0b11110110 => a | (c ^ b),
319        0b11110111 => a | (!c | !b),
320        0b11111000 => a | (c & b),
321        0b11111001 => a | (c ^ !b),
322        0b11111010 => c | a,
323        0b11111011 => !b | (c | a),
324        0b11111100 => b | a,
325        0b11111101 => !c | (b | a),
326        0b11111110 => c | (b | a),
327        0b11111111 => c | !c,
328    }
329}
330
331#[cfg(test)]
332mod test {
333    use super::TernLog;
334
335    #[test]
336    fn all_boolean() {
337        for tbl in 0..=255 {
338            for i in 0..8 {
339                let a = i & 4 != 0;
340                let b = i & 2 != 0;
341                let c = i & 1 != 0;
342                let r = tbl & 1 << i != 0;
343                assert_eq!(r, a.ternlog(b, c, tbl), "{tbl:#010b}:{i} -> {a}{b}{c} {r}");
344            }
345        }
346    }
347}