libreda_logic/
logic_value.rs

1// SPDX-FileCopyrightText: 2023 Thomas Kramer <code@tkramer.ch>
2//
3// SPDX-License-Identifier: AGPL-3.0-or-later
4
5//! Trait for logic values and implementations thereof.
6
7use std::hash::Hash;
8
9use crate::traits::LogicValue;
10
11impl LogicValue for bool {
12    fn num_values() -> usize {
13        2
14    }
15
16    fn value(idx: usize) -> Self {
17        match idx {
18            0 => false,
19            1 => true,
20            _ => panic!("index out of bounds"),
21        }
22    }
23
24    fn zero() -> Self {
25        false
26    }
27
28    fn one() -> Self {
29        true
30    }
31}
32
33/// Custom implementation of a boolean value.
34#[derive(Copy, Clone, Eq, PartialEq, Hash)]
35pub enum Bool {
36    /// Low, zero or 'false'.
37    L,
38    /// High, one or 'true.
39    H,
40}
41
42impl LogicValue for Bool {
43    fn num_values() -> usize {
44        2
45    }
46
47    fn value(idx: usize) -> Self {
48        match idx {
49            0 => Self::L,
50            1 => Self::H,
51            _ => panic!("index out of bounds"),
52        }
53    }
54
55    fn zero() -> Self {
56        Self::L
57    }
58
59    fn one() -> Self {
60        Self::H
61    }
62}
63
64/// Three-valued logic.
65/// In contrast to bivalent logic values such as `bool`
66/// this logic type also encodes the unknown value `X`.
67#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Default)]
68pub enum Logic3 {
69    /// Low, zero or 'false'.
70    L,
71    /// High, one or 'true.
72    H,
73    /// Value for representing unknown/undecidable/both/irrelevant.
74    #[default]
75    X,
76}
77
78impl From<bool> for Logic3 {
79    fn from(value: bool) -> Self {
80        match value {
81            true => Self::H,
82            false => Self::L,
83        }
84    }
85}
86
87impl From<Option<bool>> for Logic3 {
88    fn from(value: Option<bool>) -> Self {
89        match value {
90            None => Self::X,
91            Some(true) => Self::H,
92            Some(false) => Self::L,
93        }
94    }
95}
96
97impl TryInto<bool> for Logic3 {
98    type Error = ();
99
100    fn try_into(self) -> Result<bool, Self::Error> {
101        match self {
102            Logic3::L => Ok(false),
103            Logic3::H => Ok(true),
104            Logic3::X => Err(()),
105        }
106    }
107}
108
109impl LogicValue for Logic3 {
110    fn value(idx: usize) -> Self {
111        match idx {
112            0 => Self::L,
113            1 => Self::H,
114            2 => Self::X,
115            _ => panic!("index out of bounds"),
116        }
117    }
118
119    fn zero() -> Self {
120        Self::L
121    }
122
123    fn one() -> Self {
124        Self::H
125    }
126
127    fn num_values() -> usize {
128        3
129    }
130}
131
132impl std::ops::Not for Logic3 {
133    type Output = Self;
134
135    fn not(self) -> Self::Output {
136        use Logic3::*;
137        match self {
138            L => H,
139            H => L,
140            X => X,
141        }
142    }
143}
144
145impl std::ops::BitAnd for Logic3 {
146    type Output = Self;
147
148    fn bitand(self, rhs: Self) -> Self::Output {
149        use Logic3::*;
150        match (self, rhs) {
151            (L, _) | (_, L) => L,
152            (H, H) => H,
153            _ => X,
154        }
155    }
156}
157
158impl std::ops::BitOr for Logic3 {
159    type Output = Self;
160
161    fn bitor(self, rhs: Self) -> Self::Output {
162        use Logic3::*;
163        match (self, rhs) {
164            (H, _) | (_, H) => H,
165            (L, L) => L,
166            _ => X,
167        }
168    }
169}
170
171impl std::ops::BitXor for Logic3 {
172    type Output = Self;
173
174    fn bitxor(self, rhs: Self) -> Self::Output {
175        use Logic3::*;
176        match (self, rhs) {
177            (H, H) | (L, L) => L,
178            (H, L) | (L, H) => H,
179            (X, _) | (_, X) => X,
180        }
181    }
182}
183
184#[test]
185fn test_logic3_ops() {
186    use Logic3::*;
187
188    assert_eq!(H & H, H);
189    assert_eq!(L & X, L);
190    assert_eq!(X & L, L);
191    assert_eq!(H & X, X);
192
193    assert_eq!(L | L, L);
194    assert_eq!(H | X, H);
195    assert_eq!(X | H, H);
196    assert_eq!(X | L, X);
197}