1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
use std::ops::{BitAnd, BitOr, BitXor, Not};

use crate::{util::ContainerSizeGames, Bit, GateLike, RustImpls};

#[cfg(test)]
mod tests;

impl<Rust> GateLike for RustImpls<Rust>
where
    Rust: GateLike,
{
    fn compute(&mut self, mut input: Vec<Bit>) -> Vec<Bit> {
        debug_assert_eq!(input.len(), self.num_of_inputs());

        unsafe {
            match self {
                RustImpls::Dup(ref amount) => {
                    let value = input.get_copied(0);
                    input.change_len(*amount, value)
                }
                RustImpls::Not => {
                    input.get_unchecked_mut(0).action_assign(Bit::not);
                    input
                }
                RustImpls::Nand => compute_binary_operation(input, |x, y| !(x && y)),
                RustImpls::And => compute_binary_operation(input, Bit::bitand),
                RustImpls::Or => compute_binary_operation(input, Bit::bitor),
                RustImpls::Nor => compute_binary_operation(input, |x, y| !(x || y)),
                RustImpls::Xor => compute_binary_operation(input, Bit::bitxor),
                RustImpls::User(component) => component.compute(input),
            }
        }
    }

    fn num_of_inputs(&self) -> usize {
        match self {
            RustImpls::Dup(_) => 1,
            RustImpls::Not => 1,
            RustImpls::Nand => 2,
            RustImpls::And => 2,
            RustImpls::Or => 2,
            RustImpls::Nor => 2,
            RustImpls::Xor => 2,
            RustImpls::User(component) => component.num_of_inputs(),
        }
    }
}

unsafe fn compute_binary_operation<O>(input: Vec<Bit>, operation: O) -> Vec<Bit>
where
    O: FnOnce(Bit, Bit) -> Bit,
{
    let value = operation(input.get_copied(0), input.get_copied(1));
    input.shorten(1, value)
}

trait ActionAssign: Sized + Copy {
    fn action_assign<F>(&mut self, action: F) -> &mut Self
    where
        F: FnOnce(Self) -> Self,
    {
        *self = action(*self);
        self
    }
}
impl<T> ActionAssign for T where T: Sized + Copy {}