logic-circus 0.3.0

Open source logic circuit simualtor written in Rust.
Documentation
use std::{
    convert::Infallible,
    ops::{BitAnd, BitOr, BitXor, Not},
};

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

#[cfg(test)]
mod tests;

#[derive(Clone, Debug, Copy)]
pub(super) enum RustImpls<Rust = Infallible> {
    Dup(usize),
    Mem(Bit),
    Not,
    Nand,
    And,
    Or,
    Nor,
    Xor,
    User(Rust),
}

impl<Rust> GateLike for RustImpls<Rust>
where
    Rust: GateLike,
{
    /// # Safety
    /// `input.len()` must match the number of inputs the gate has
    ///
    /// in debug this is checked and will cause a panic, in release this will
    /// create UB due to buffer overflow
    unsafe fn compute(&mut self, mut input: Vec<Bit>) -> Vec<Bit> {
        debug_assert_eq!(input.len(), self.num_of_inputs());

        match self {
            RustImpls::Dup(ref amount) => {
                let value = *input.get_unchecked(0);
                input.change_len(*amount, value)
            }
            RustImpls::Mem(current) => {
                std::mem::swap(current, input.get_unchecked_mut(0));
                input
            }
            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(logic) => logic.compute(input),
        }
    }

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

    fn reset(&mut self, full: bool) {
        match self {
            RustImpls::Mem(mem) if full => *mem = bool::default(),
            RustImpls::User(gate) => gate.reset(full),
            _ => {} // the rest don't need to be reset
        }
    }
}

/// # Safety
/// `input` must be of length 2
unsafe fn compute_binary_operation<O>(input: Vec<Bit>, operation: O) -> Vec<Bit>
where
    O: FnOnce(Bit, Bit) -> Bit,
{
    let value = operation(*input.get_unchecked(0), *input.get_unchecked(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 {}