logic_circus/
implemented.rs

1use std::{
2    convert::Infallible,
3    ops::{BitAnd, BitOr, BitXor, Not},
4};
5
6use crate::{util::ContainerSizeGames, Bit, GateLike};
7
8#[cfg(test)]
9mod tests;
10
11#[derive(Clone, Debug, Copy)]
12pub(super) enum RustImpls<Rust = Infallible> {
13    Dup(usize),
14    Mem(Bit),
15    Not,
16    Nand,
17    And,
18    Or,
19    Nor,
20    Xor,
21    User(Rust),
22}
23
24impl<Rust> GateLike for RustImpls<Rust>
25where
26    Rust: GateLike,
27{
28    /// # Safety
29    /// `input.len()` must match the number of inputs the gate has
30    ///
31    /// in debug this is checked and will cause a panic, in release this will
32    /// create UB due to buffer overflow
33    unsafe fn compute(&mut self, mut input: Vec<Bit>) -> Vec<Bit> {
34        debug_assert_eq!(input.len(), self.num_of_inputs());
35
36        match self {
37            RustImpls::Dup(ref amount) => {
38                let value = *input.get_unchecked(0);
39                input.change_len(*amount, value)
40            }
41            RustImpls::Mem(current) => {
42                std::mem::swap(current, input.get_unchecked_mut(0));
43                input
44            }
45            RustImpls::Not => {
46                input.get_unchecked_mut(0).action_assign(Bit::not);
47                input
48            }
49            RustImpls::Nand => compute_binary_operation(input, |x, y| !(x && y)),
50            RustImpls::And => compute_binary_operation(input, Bit::bitand),
51            RustImpls::Or => compute_binary_operation(input, Bit::bitor),
52            RustImpls::Nor => compute_binary_operation(input, |x, y| !(x || y)),
53            RustImpls::Xor => compute_binary_operation(input, Bit::bitxor),
54            RustImpls::User(logic) => logic.compute(input),
55        }
56    }
57
58    fn num_of_inputs(&self) -> usize {
59        match self {
60            RustImpls::Dup(_) => 1,
61            RustImpls::Mem(_) => 1,
62            RustImpls::Not => 1,
63            RustImpls::Nand => 2,
64            RustImpls::And => 2,
65            RustImpls::Or => 2,
66            RustImpls::Nor => 2,
67            RustImpls::Xor => 2,
68            RustImpls::User(gate) => gate.num_of_inputs(),
69        }
70    }
71
72    fn reset(&mut self, full: bool) {
73        match self {
74            RustImpls::Mem(mem) if full => *mem = bool::default(),
75            RustImpls::User(gate) => gate.reset(full),
76            _ => {} // the rest don't need to be reset
77        }
78    }
79}
80
81/// # Safety
82/// `input` must be of length 2
83unsafe fn compute_binary_operation<O>(input: Vec<Bit>, operation: O) -> Vec<Bit>
84where
85    O: FnOnce(Bit, Bit) -> Bit,
86{
87    let value = operation(*input.get_unchecked(0), *input.get_unchecked(1));
88    input.shorten(1, value)
89}
90
91trait ActionAssign: Sized + Copy {
92    fn action_assign<F>(&mut self, action: F) -> &mut Self
93    where
94        F: FnOnce(Self) -> Self,
95    {
96        *self = action(*self);
97        self
98    }
99}
100impl<T> ActionAssign for T where T: Sized + Copy {}