libreda-logic 0.0.3

Logic library for LibrEDA.
Documentation
// SPDX-FileCopyrightText: 2022 Thomas Kramer <code@tkramer.ch>
//
// SPDX-License-Identifier: AGPL-3.0-or-later

//! Adaptors for Boolean functions.

use crate::traits::*;

/// Wrap a multi-output Boolean function by selecting a single output.
/// # Example
/// ```
/// use libreda_logic::traits::*;
/// use libreda_logic::native_boolean_functions::*;
/// use libreda_logic::adaptors::*;
///
/// fn f([a]: [bool; 1]) -> [bool; 2] {
///     [a, !a]   
/// }
///
/// // Wrap the native Rust function such that it implements the traits of Boolean functions.
/// let f2 = NativeBooleanFunction::new(f);
///
/// // Select the first output.
/// let f_0 = OutputSelection::new(&f2, 0);
///
/// // Select the second output.
/// let f_1 = OutputSelection::new(&f2, 1);
///
/// assert_eq!(f_0.eval(&[false]), false);
/// assert_eq!(f_0.eval(&[true]), true);
///
/// assert_eq!(f_1.eval(&[false]), true);
/// assert_eq!(f_1.eval(&[true]), false);
/// ```
pub struct OutputSelection<'a, T, TermId> {
    s: &'a T,
    output: TermId,
}

impl<'a, T: BooleanSystem> OutputSelection<'a, T, T::TermId> {
    /// Create a boolean function by selecting a single output.
    pub fn new(boolean_system: &'a T, output: T::TermId) -> Self {
        Self {
            s: boolean_system,
            output,
        }
    }
}

impl<'a, T: NumInputs, TermId> NumInputs for OutputSelection<'a, T, TermId> {
    fn num_inputs(&self) -> usize {
        self.s.num_inputs()
    }
}

impl<'a, T: NumOutputs, TermId> NumOutputs for OutputSelection<'a, T, TermId> {
    fn num_outputs(&self) -> usize {
        self.s.num_outputs()
    }
}

impl<'a, T: PartialBooleanSystem> PartialBooleanSystem for OutputSelection<'a, T, T::TermId> {
    type LiteralId = T::LiteralId;

    type TermId = ();

    fn evaluate_term_partial(&self, _term: &Self::TermId, input_values: &[bool]) -> Option<bool> {
        self.s.evaluate_term_partial(&self.output, input_values)
    }
}

impl<'a, T: BooleanSystem> BooleanSystem for OutputSelection<'a, T, T::TermId> {
    fn evaluate_term(&self, _term: &Self::TermId, input_values: &[bool]) -> bool {
        self.s.evaluate_term(&self.output, input_values)
    }
}

impl<'a, T, TermId> StaticNumOutputs<1> for OutputSelection<'a, T, TermId> {}

impl<'a, T: PartialBooleanSystem> PartialBooleanFunction for OutputSelection<'a, T, T::TermId> {
    fn partial_eval(&self, input_values: &[bool]) -> Option<bool> {
        self.evaluate_term_partial(&(), input_values)
    }
}

impl<'a, T: BooleanSystem> BooleanFunction for OutputSelection<'a, T, T::TermId> {
    fn eval(&self, input_values: &[bool]) -> bool {
        self.evaluate_term(&(), input_values)
    }
}