ternlog 0.1.0

Ternary logic operations on integer types
Documentation
#![no_std]
#![doc = include_str!("../README.md")]

/// Extension trait to compute ternary logic on integer types.
///
/// To use, import it:
/// ```
/// use ternlog::TernLog;
/// ```
pub trait TernLog {
    /// Compute "ternary logic" using an 8-entry lookup table.
    ///
    /// For each bit, the expression will be computed as:
    /// | `a` | `b` | `c` | `lut`                 |
    /// | --- | --- | --- | --------------------- |
    /// | `0` | `0` | `0` | `lut & (1 << 0) != 0` |
    /// | `0` | `0` | `1` | `lut & (1 << 1) != 0` |
    /// | `0` | `1` | `0` | `lut & (1 << 2) != 0` |
    /// | `0` | `1` | `1` | `lut & (1 << 3) != 0` |
    /// | `1` | `0` | `0` | `lut & (1 << 4) != 0` |
    /// | `1` | `0` | `1` | `lut & (1 << 5) != 0` |
    /// | `1` | `1` | `0` | `lut & (1 << 6) != 0` |
    /// | `1` | `1` | `1` | `lut & (1 << 7) != 0` |
    ///
    /// If `lut` is constant, prefer using [`Self::const_ternlog`] instead.
    ///
    /// # Example
    ///
    /// ```
    /// // if sprite_mask { background } else { sprite }
    /// background.ternlog(sprite, sprite_mask, 0xe4)
    /// ```
    fn ternlog(self, b: Self, c: Self, lut: u8) -> Self;
    /// Same as [`Self::ternlog`], but with a guaranteed compile-time constant table.
    ///
    /// # Example
    ///
    /// ```
    /// // if sprite_mask { background } else { sprite }
    /// background.ternlog::<0xe4>(sprite, sprite_mask)
    /// ```
    fn const_ternlog<const LUT: u8>(self, b: Self, c: Self) -> Self;
}

macro_rules! impl_ternlog {
    ($($ty:ident)*) => {
        $(impl TernLog for $ty {
            fn ternlog(self, b: Self, c: Self, lut: u8) -> Self {
                ternlog(self as _, b as _, c as _, lut) as _
            }
            fn const_ternlog<const LUT: u8>(self, b: Self, c: Self) -> Self {
                ternlog(self as _, b as _, c as _, LUT) as _
            }
        })*
    };
}

impl_ternlog![u8 i8 u16 i16 u32 i32 u64 i64 u128 i128 usize isize];

impl TernLog for bool {
    fn ternlog(self, b: Self, c: Self, lut: u8) -> Self {
        ternlog(self as _, b as _, c as _, lut) & 1 != 0
    }
    fn const_ternlog<const LUT: u8>(self, b: Self, c: Self) -> Self {
        ternlog(self as _, b as _, c as _, LUT) & 1 != 0
    }
}

#[inline(always)]
fn ternlog(a: u128, b: u128, c: u128, lut: u8) -> u128 {
    match lut {
        0b00000000 => c ^ c,
        0b00000001 => !c ^ (!c & (b | a)),
        0b00000010 => c ^ (c & (b | a)),
        0b00000011 => !b & !a,
        0b00000100 => b ^ (b & (c | a)),
        0b00000101 => !c & !a,
        0b00000110 => !a & (c ^ b),
        0b00000111 => !a & (!c | !b),
        0b00001000 => !a & (c & b),
        0b00001001 => !c ^ ((c & a) ^ (b | a)),
        0b00001010 => c & !a,
        0b00001011 => a ^ (!b | (c | a)),
        0b00001100 => b & !a,
        0b00001101 => a ^ (!c | (b | a)),
        0b00001110 => !a & (c | b),
        0b00001111 => !a,
        0b00010000 => a ^ (a & (c | b)),
        0b00010001 => !c & !b,
        0b00010010 => !b & (c ^ a),
        0b00010011 => !b & (!c | !a),
        0b00010100 => !c & (b ^ a),
        0b00010101 => !c ^ (!c & (b & a)),
        0b00010110 => c ^ ((c & b) | (b ^ a)),
        0b00010111 => !c ^ ((c ^ b) & (c ^ a)),
        0b00011000 => (c ^ a) & (b ^ a),
        0b00011001 => c ^ (!b | (c & a)),
        0b00011010 => a ^ (c | (b & a)),
        0b00011011 => !c ^ ((c | b) ^ (c & a)),
        0b00011100 => a ^ (b | (c & a)),
        0b00011101 => !c ^ (b & (c ^ a)),
        0b00011110 => a ^ (c | b),
        0b00011111 => a ^ (!a | (c | b)),
        0b00100000 => !b & (c & a),
        0b00100001 => !c ^ ((c & b) ^ (b | a)),
        0b00100010 => c & !b,
        0b00100011 => b ^ (!a | (c | b)),
        0b00100100 => (c ^ b) & (b ^ a),
        0b00100101 => c ^ (!a | (c & b)),
        0b00100110 => b ^ (c | (b & a)),
        0b00100111 => !c ^ ((c & b) ^ (c | a)),
        0b00101000 => c & (b ^ a),
        0b00101001 => (c | !b) & (!c ^ (b ^ a)),
        0b00101010 => c ^ (c & (b & a)),
        0b00101011 => !c ^ ((c ^ b) | (c ^ a)),
        0b00101100 => (c | b) & (b ^ a),
        0b00101101 => c ^ (!a ^ (c & b)),
        0b00101110 => (c | b) ^ (b & a),
        0b00101111 => !a | (c & !b),
        0b00110000 => b ^ (b | a),
        0b00110001 => b ^ (!c | (b | a)),
        0b00110010 => !b & (c | a),
        0b00110011 => !b,
        0b00110100 => b ^ (a | (c & b)),
        0b00110101 => !c ^ (a & (c ^ b)),
        0b00110110 => b ^ (c | a),
        0b00110111 => b ^ (!b | (c | a)),
        0b00111000 => (c | a) & (b ^ a),
        0b00111001 => c ^ (!b ^ (c & a)),
        0b00111010 => (c | a) ^ (b & a),
        0b00111011 => !b | (c & !a),
        0b00111100 => b ^ a,
        0b00111101 => !b ^ (!a & (c | b)),
        0b00111110 => (c ^ b) ^ ((c ^ a) & (b | a)),
        0b00111111 => !b | !a,
        0b01000000 => !c & (b & a),
        0b01000001 => !c & (b ^ !a),
        0b01000010 => (c ^ b) & (c ^ a),
        0b01000011 => b ^ (!a | (c & b)),
        0b01000100 => c ^ (c | b),
        0b01000101 => c ^ (!a | (c | b)),
        0b01000110 => c ^ (b | (c & a)),
        0b01000111 => !c ^ (!b & (c ^ a)),
        0b01001000 => b & (c ^ a),
        0b01001001 => (c | a) ^ (!b | (c & a)),
        0b01001010 => (c | b) & (c ^ a),
        0b01001011 => c ^ (!a ^ (c | b)),
        0b01001100 => c ^ ((c ^ b) | (c & a)),
        0b01001101 => !c ^ ((c ^ a) & (b ^ a)),
        0b01001110 => (c | b) ^ (c & a),
        0b01001111 => !a | (c ^ (c | b)),
        0b01010000 => c ^ (c | a),
        0b01010001 => c ^ (!b | (c | a)),
        0b01010010 => c ^ (a | (c & b)),
        0b01010011 => !c ^ (!a & (c ^ b)),
        0b01010100 => !c & (b | a),
        0b01010101 => !c,
        0b01010110 => c ^ (b | a),
        0b01010111 => c ^ (!c | (b | a)),
        0b01011000 => (c ^ a) & (b | a),
        0b01011001 => c ^ (a | !b),
        0b01011010 => c ^ a,
        0b01011011 => !c ^ (!a & (c | b)),
        0b01011100 => (c & a) ^ (b | a),
        0b01011101 => !c | (b & !a),
        0b01011110 => (c ^ b) ^ ((c | a) & (b ^ a)),
        0b01011111 => !c | !a,
        0b01100000 => a & (c ^ b),
        0b01100001 => (c | b) ^ (!a | (c & b)),
        0b01100010 => (c ^ b) & (c | a),
        0b01100011 => c ^ (!b ^ (c | a)),
        0b01100100 => (c ^ b) & (b | a),
        0b01100101 => c ^ (b | !a),
        0b01100110 => c ^ b,
        0b01100111 => !c ^ (!b & (c | a)),
        0b01101000 => (c & b) ^ (a & (c | b)),
        0b01101001 => !c ^ (b ^ a),
        0b01101010 => c ^ (b & a),
        0b01101011 => !b ^ ((c ^ a) & (b | a)),
        0b01101100 => b ^ (c & a),
        0b01101101 => !c ^ ((c | a) & (b ^ a)),
        0b01101110 => (c & b) ^ ((c ^ b) | (c & a)),
        0b01101111 => !a | (c ^ b),
        0b01110000 => c ^ ((c & b) | (c ^ a)),
        0b01110001 => !c ^ ((c ^ b) & (b ^ a)),
        0b01110010 => (c & b) ^ (c | a),
        0b01110011 => !b | (c ^ (c | a)),
        0b01110100 => (c & b) ^ (b | a),
        0b01110101 => !c | (b ^ (b | a)),
        0b01110110 => (c & b) ^ (c | (b | a)),
        0b01110111 => !c | !b,
        0b01111000 => a ^ (c & b),
        0b01111001 => !c ^ ((c | b) & (b ^ a)),
        0b01111010 => (c & a) ^ ((c & b) | (c ^ a)),
        0b01111011 => !b | (c ^ a),
        0b01111100 => (c ^ (c | b)) | (b ^ a),
        0b01111101 => !c | (b ^ a),
        0b01111110 => (c ^ b) | (c ^ a),
        0b01111111 => c ^ (!c | (b & a)),
        0b10000000 => c & (b & a),
        0b10000001 => (c | b) ^ (!a | (c ^ b)),
        0b10000010 => c ^ (c & (b ^ a)),
        0b10000011 => (c | !b) & (b ^ !a),
        0b10000100 => c ^ ((c | b) ^ (b & a)),
        0b10000101 => (c & !a) ^ (!a | (c & b)),
        0b10000110 => c ^ ((c | b) & (b ^ a)),
        0b10000111 => !a ^ (c & b),
        0b10001000 => c & b,
        0b10001001 => (c ^ b) ^ (!a | (c | b)),
        0b10001010 => c & (b | !a),
        0b10001011 => a ^ (!b | (c ^ a)),
        0b10001100 => b & (c | !a),
        0b10001101 => a ^ (!c | (b ^ a)),
        0b10001110 => c ^ ((c ^ b) & (b ^ a)),
        0b10001111 => !a | (c & b),
        0b10010000 => c ^ ((c | a) ^ (b & a)),
        0b10010001 => (c & !b) ^ (!b | (c & a)),
        0b10010010 => c ^ ((c | a) & (b ^ a)),
        0b10010011 => !b ^ (c & a),
        0b10010100 => b ^ ((c ^ a) & (b | a)),
        0b10010101 => !c ^ (b & a),
        0b10010110 => c ^ (b ^ a),
        0b10010111 => (c | !b) ^ ((c | b) & (b ^ a)),
        0b10011000 => c ^ (!b & (c | a)),
        0b10011001 => c ^ !b,
        0b10011010 => (c ^ b) ^ (b | a),
        0b10011011 => !b ^ (c & (b | a)),
        0b10011100 => (c ^ b) ^ (c | a),
        0b10011101 => !c ^ (b & (c | a)),
        0b10011110 => (c & b) | (c ^ (b ^ a)),
        0b10011111 => a ^ (!a | (c ^ b)),
        0b10100000 => c & a,
        0b10100001 => (c ^ a) ^ (!b | (c | a)),
        0b10100010 => c & (a | !b),
        0b10100011 => b ^ (!a | (c ^ b)),
        0b10100100 => c ^ (!a & (c | b)),
        0b10100101 => c ^ !a,
        0b10100110 => (c ^ b) ^ (b & a),
        0b10100111 => !a ^ (c & (b | a)),
        0b10101000 => c & (b | a),
        0b10101001 => !c ^ (b | a),
        0b10101010 => c,
        0b10101011 => c | (!c ^ (b | a)),
        0b10101100 => c ^ (!a & (c ^ b)),
        0b10101101 => !c ^ (a | (c & b)),
        0b10101110 => c | (b & !a),
        0b10101111 => c | !a,
        0b10110000 => a & (c | !b),
        0b10110001 => b ^ (!c | (b ^ a)),
        0b10110010 => c ^ ((c ^ a) & (b ^ a)),
        0b10110011 => !b | (c & a),
        0b10110100 => (c & b) ^ (b ^ a),
        0b10110101 => !c ^ (a & (c | b)),
        0b10110110 => (c | b) ^ ((c ^ a) & (b | a)),
        0b10110111 => b ^ (!b | (c ^ a)),
        0b10111000 => c ^ (!b & (c ^ a)),
        0b10111001 => !c ^ (b | (c & a)),
        0b10111010 => c | (b ^ (b | a)),
        0b10111011 => c | !b,
        0b10111100 => (c & b) | (b ^ a),
        0b10111101 => (c | !c) ^ ((c ^ b) & (c ^ a)),
        0b10111110 => c | (b ^ a),
        0b10111111 => c | (!c ^ (b & a)),
        0b11000000 => b & a,
        0b11000001 => (c ^ !b) ^ ((c ^ a) & (b | a)),
        0b11000010 => b ^ (!a & (c | b)),
        0b11000011 => b ^ !a,
        0b11000100 => b & (a | !c),
        0b11000101 => c ^ (!a | (c ^ b)),
        0b11000110 => (c ^ b) ^ (c & a),
        0b11000111 => !a ^ (b & (c | a)),
        0b11001000 => b & (c | a),
        0b11001001 => !b ^ (c | a),
        0b11001010 => c ^ (a & (c ^ b)),
        0b11001011 => !b ^ (a | (c & b)),
        0b11001100 => b,
        0b11001101 => b | (!c & !a),
        0b11001110 => c ^ ((c ^ b) & (b | a)),
        0b11001111 => b | !a,
        0b11010000 => a & (b | !c),
        0b11010001 => c ^ (!b | (c ^ a)),
        0b11010010 => (c & b) ^ (c ^ a),
        0b11010011 => !b ^ (a & (c | b)),
        0b11010100 => c ^ ((c ^ b) | (c ^ a)),
        0b11010101 => !c | (b & a),
        0b11010110 => (c | b) ^ ((c | a) & (b ^ a)),
        0b11010111 => c ^ (!c | (b ^ a)),
        0b11011000 => c ^ ((c & b) ^ (c | a)),
        0b11011001 => !b ^ (c | (b & a)),
        0b11011010 => (c & b) | (c ^ a),
        0b11011011 => (c & a) ^ (!b | (c ^ a)),
        0b11011100 => b | (c ^ (c | a)),
        0b11011101 => b | !c,
        0b11011110 => b | (c ^ a),
        0b11011111 => b | (!c | !a),
        0b11100000 => a & (c | b),
        0b11100001 => !a ^ (c | b),
        0b11100010 => c ^ (b & (c ^ a)),
        0b11100011 => !a ^ (b | (c & a)),
        0b11100100 => c ^ ((c | b) ^ (c & a)),
        0b11100101 => !a ^ (c | (b & a)),
        0b11100110 => (c ^ b) | (c & a),
        0b11100111 => (c & b) ^ (!a | (c ^ b)),
        0b11101000 => c ^ ((c ^ b) & (c ^ a)),
        0b11101001 => !c ^ ((c & b) | (b ^ a)),
        0b11101010 => c | (b & a),
        0b11101011 => c | (b ^ !a),
        0b11101100 => b | (c & a),
        0b11101101 => b | (c ^ !a),
        0b11101110 => c | b,
        0b11101111 => !a | (c | b),
        0b11110000 => a,
        0b11110001 => a | (!c & !b),
        0b11110010 => c ^ ((c ^ a) & (b | a)),
        0b11110011 => a | !b,
        0b11110100 => b ^ ((c | a) & (b ^ a)),
        0b11110101 => a | !c,
        0b11110110 => a | (c ^ b),
        0b11110111 => a | (!c | !b),
        0b11111000 => a | (c & b),
        0b11111001 => a | (c ^ !b),
        0b11111010 => c | a,
        0b11111011 => !b | (c | a),
        0b11111100 => b | a,
        0b11111101 => !c | (b | a),
        0b11111110 => c | (b | a),
        0b11111111 => c | !c,
    }
}

#[cfg(test)]
mod test {
    use super::TernLog;

    #[test]
    fn all_boolean() {
        for tbl in 0..=255 {
            for i in 0..8 {
                let a = i & 4 != 0;
                let b = i & 2 != 0;
                let c = i & 1 != 0;
                let r = tbl & 1 << i != 0;
                assert_eq!(r, a.ternlog(b, c, tbl), "{tbl:#010b}:{i} -> {a}{b}{c} {r}");
            }
        }
    }
}