use crate::data_structures::SlabIndex;
use indexmap::IndexSet;
use smallvec::SmallVec;
use std::fmt::{self, Display, Formatter};
#[repr(transparent)]
#[derive(Clone, Copy, Eq, PartialEq, Hash, Debug, Ord, PartialOrd)]
pub struct GateIndex {
pub(super) idx: usize,
}
macro_rules! gi {
( $x:expr ) => {{
GateIndex::new($x)
}};
}
pub const OFF: GateIndex = gi!(0);
pub const ON: GateIndex = gi!(1);
impl GateIndex {
pub(super) const fn new(idx: usize) -> GateIndex {
GateIndex { idx }
}
pub fn is_off(&self) -> bool {
*self == OFF
}
pub fn is_on(&self) -> bool {
*self == ON
}
#[inline(always)]
pub fn is_const(&self) -> bool {
*self == OFF || *self == ON
}
pub fn opposite_if_const(&self) -> Option<GateIndex> {
if self.is_on() {
Some(OFF)
} else if self.is_off() {
Some(ON)
} else {
None
}
}
}
impl From<SlabIndex> for GateIndex {
fn from(i: SlabIndex) -> Self {
Self {
idx: i.i_actually_really_know_what_i_am_doing_and_i_want_the_inner_usize(),
}
}
}
impl Into<SlabIndex> for GateIndex {
fn into(self) -> SlabIndex {
SlabIndex::i_actually_really_know_what_i_am_doing_and_i_want_to_construct_from_usize(
self.idx,
)
}
}
impl Into<SlabIndex> for &GateIndex {
fn into(self) -> SlabIndex {
SlabIndex::i_actually_really_know_what_i_am_doing_and_i_want_to_construct_from_usize(
self.idx,
)
}
}
impl Display for GateIndex {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.idx)
}
}
#[repr(u8)]
#[derive(Clone, Debug, Copy, Eq, PartialEq, Hash)]
pub(super) enum GateType {
Off = 0,
On,
Lever,
Xor,
Xnor,
Not,
Or,
And,
Nand,
Nor,
}
use GateType::*;
impl GateType {
#[inline(always)]
pub fn accumulate(&self, acc: bool, b: bool) -> bool {
match self {
Or | Nor => acc | b,
And | Nand => acc & b,
Xor | Xnor => acc ^ b,
On | Off | Lever | Not => {
unreachable!("Accumulate only works on gates with multiple dependencies")
}
}
}
#[inline(always)]
pub fn init(&self) -> bool {
match self {
Or | Nor | Xor | Xnor => false,
And | Nand => true,
Not => false,
On | Off | Lever => unreachable!("Init doesn't work on gates without dependencies"),
}
}
#[inline(always)]
pub fn short_circuits(&self) -> bool {
match self {
Xor | Xnor => false,
Or | Nor | And | Nand => true,
Not | On | Off | Lever => {
unreachable!("Short_circuits only works on gates with multiple dependencies")
}
}
}
#[inline(always)]
pub fn negated_version(&self) -> GateType {
match self {
Or => Nor,
Nor => Or,
And => Nand,
Nand => And,
Xor => Xnor,
Xnor => Xor,
On | Off | Not | Lever => unreachable!(),
}
}
#[inline(always)]
pub fn has_negated_version(&self) -> bool {
!matches!(self, On | Off | Not | Lever)
}
pub fn is_lever(&self) -> bool {
matches!(self, Lever)
}
pub fn is_not(&self) -> bool {
matches!(self, Not)
}
pub fn is_negated(&self) -> bool {
matches!(self, Nor | Nand | Not | Xnor)
}
}
impl Display for GateType {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Lever => write!(f, stringify!(Lever)),
On => write!(f, stringify!(On)),
Off => write!(f, stringify!(Off)),
Not => write!(f, stringify!(Not)),
Or => write!(f, stringify!(Or)),
Nor => write!(f, stringify!(Nor)),
And => write!(f, stringify!(And)),
Nand => write!(f, stringify!(Nand)),
Xor => write!(f, stringify!(Xor)),
Xnor => write!(f, stringify!(Xnor)),
}
}
}
pub(super) const GATE_DEPENDENCIES_TINYVEC_SIZE: usize = 2;
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub(super) struct Gate<T> {
pub ty: GateType,
pub dependencies: SmallVec<[GateIndex; GATE_DEPENDENCIES_TINYVEC_SIZE]>,
pub dependents: T,
}
impl<T: Default> Gate<T> {
pub fn new(
ty: GateType,
dependencies: SmallVec<[GateIndex; GATE_DEPENDENCIES_TINYVEC_SIZE]>,
) -> Self {
Gate {
ty,
dependencies,
dependents: Default::default(),
}
}
}
pub(super) type BuildGate = Gate<IndexSet<GateIndex>>;
pub(super) type InitializedGate = Gate<SmallVec<[GateIndex; 2]>>;
impl From<BuildGate> for InitializedGate {
fn from(g: BuildGate) -> Self {
let BuildGate {
ty,
dependents,
dependencies,
} = g;
Self {
ty,
dependencies,
dependents: dependents.into_iter().collect(),
}
}
}
impl BuildGate {
pub(super) fn swap_dependency(&mut self, old_dep: GateIndex, new_dep: GateIndex) {
for d in &mut self.dependencies {
if old_dep == *d {
*d = new_dep
}
}
}
}
#[cfg(test)]
mod test {
use super::*;
use smallvec::smallvec;
#[test]
fn test_swap_dependency() {
let mut g = Gate::new(Or, smallvec![gi!(3), gi!(2), gi!(3)]);
g.swap_dependency(gi!(3), gi!(1));
assert_eq!(g.dependencies[0], gi!(1));
assert_eq!(g.dependencies[1], gi!(2));
assert_eq!(g.dependencies[2], gi!(1));
}
}