balanced_ternary/
digit.rs

1//! ## Module: Balanced Ternary `Digit`
2//!
3//! This module defines the `Digit` type for the balanced ternary numeral system,
4//! along with its associated operations and functionality.
5//!
6//! ### Key Features
7//!
8//! - **`Digit` Type**: Represents a digit in the balanced ternary numeral system.
9//!     - Possible values: `Neg` (-1), `Zero` (0), `Pos` (+1).
10//!     - Provides utility functions for converting between characters, integers, and other formats.
11//! - **Arithmetic Operators**: Implements arithmetic operations for digits, including:
12//!     - Negation (`Neg`) and Bitwise Not (`Not`).
13//!     - Addition (`Add`) and Subtraction (`Sub`).
14//!     - Multiplication (`Mul`) and Division (`Div`), with safe handling of divisors (division by zero panics).
15//! - **Logical Operators**: Supports bitwise logical operations (AND, OR, XOR) based on ternary logic rules.
16//! - **Custom Methods**: Additional utility methods implementing balanced ternary logic principles.
17//!
18//! ### Supported Use Cases
19//!
20//! - Arithmetic in balanced ternary numeral systems.
21//! - Logic operations in custom numeral systems.
22//! - Conversion between balanced ternary representation and more common formats like integers and characters.
23//!
24//! ## `Digit` type arithmetical and logical operations
25//!
26//! - `Neg` and `Not` for `Digit`: Negates the digit value, adhering to balanced ternary rules.
27//! - `Add<Digit>` for `Digit`: Adds two `Digit` values and returns a `Ternary`.
28//! - `Sub<Digit>` for `Digit`: Subtracts one `Digit` from another and returns a `Ternary`.
29//! - `Mul<Digit>` for `Digit`: Multiplies two `Digit` values and returns a `Digit`.
30//! - `Div<Digit>` for `Digit`: Divides one `Digit` by another and returns a `Digit`. Division by zero panics.
31//!
32//! ### Logical Operations for `Digit`
33//!
34//! The `Digit` type supports bitwise logical operations, which are implemented according to logical rules applicable to balanced ternary digits.
35//!
36//! ### Digits operations
37//!
38//! #### Unary operations
39//!
40//! These operations (except inc & dec) can be applied for `Ternary` with `Ternary::each(operator)`:
41//!
42//! | Unary operations      | - | 0 | + |
43//! |-----------------------|---|---|---|
44//! | possibly              | - | + | + |
45//! | necessary             | - | - | + |
46//! | contingently          | - | + | - |
47//! | ht_not                | + | - | - |
48//! | post                  | 0 | + | - |
49//! | pre                   | + | - | 0 |
50//! | `!` (not) / `-` (neg) | + | 0 | - |
51//! | absolute_positive     | + | 0 | + |
52//! | positive              | 0 | 0 | + |
53//! | not_negative          | 0 | + | + |
54//! | not_positive          | - | - | 0 |
55//! | negative              | - | 0 | 0 |
56//! | absolute_negative     | - | 0 | - |
57//! | inc                   | 0 | + | `+-` |
58//! | dec                   | `-+` | - | 0 |
59//!
60//! `inc` and `dec` can respectively be replaced by `post` and `pre` which are the same operations without the carry digit.
61//!
62//! #### Binary operations
63//!
64//! These operations (except add & sub) can be applied for `Ternary` with:
65//!
66//! - `Ternary::each_with(operator, with)`, or,
67//! - `Ternary::each_zip(operator, other)`:
68//!
69//! | Binary operations | -<br>- | -<br>0 | -<br>+ | 0<br>- | 0<br>0 | 0<br>+ | +<br>- | +<br>0 | +<br>+ |
70//! |------------------|--------|--------|--------|--------|--------|--------|--------|--------|--------|
71//! | `+` (add)        | -+     | -      | 0      | -      | 0      | +      | 0      | +      | +-     |
72//! | `-` (sub)        | 0      | -      | -+     | +      | 0      | -      | +-     | +      | 0      |
73//! | `/` (div)        | +      |        | -      | 0      |        | 0      | -      |        | +      |
74//! | `*` (mul)        | +      | 0      | -      | 0      | 0      | 0      | -      | 0      | +      |
75//! | `&` (bitand)     | -      | -      | -      | -      | 0      | 0      | -      | 0      | +      |
76//! | bi3_and          | -      | 0      | -      | 0      | 0      | 0      | -      | 0      | +      |
77//! | `\|` (bitor)     | -      | 0      | +      | 0      | 0      | +      | +      | +      | +      |
78//! | bi3_or           | -      | 0      | +      | 0      | 0      | 0      | +      | 0      | +      |
79//! | `^` (bitxor)     | -      | 0      | +      | 0      | 0      | 0      | +      | 0      | -      |
80//! | k3_equiv         | +      | 0      | -      | 0      | 0      | 0      | -      | 0      | +      |
81//! | k3_imply         | +      | +      | +      | 0      | 0      | +      | -      | 0      | +      |
82//! | bi3_imply        | +      | 0      | +      | 0      | 0      | 0      | -      | 0      | +      |
83//! | l3_imply         | +      | +      | +      | 0      | +      | +      | -      | 0      | +      |
84//! | rm3_imply        | +      | +      | +      | -      | 0      | +      | -      | -      | +      |
85//! | para_imply       | +      | +      | +      | -      | 0      | +      | -      | 0      | +      |
86//! | ht_imply         | +      | +      | +      | -      | +      | +      | -      | 0      | +      |
87//!
88//! `/`, `*`, `&`, `|` and `^` should not be used with `Ternary::each_{with,zip}()`.  
89//! Instead, use these operators from `Ternary` directly.
90//!
91//! Do so to `add` and `sub` ternaries, too.
92//!
93
94use crate::Ternary;
95use alloc::vec;
96use core::ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Neg, Not, Sub};
97
98/// Represents a digit in the balanced ternary numeral system.
99///
100/// A digit can have one of three values:
101/// - `Neg` (-1): Represents the value -1 in the balanced ternary system.
102/// - `Zero` (0): Represents the value 0 in the balanced ternary system.
103/// - `Pos` (+1): Represents the value +1 in the balanced ternary system.
104///
105/// Provides utility functions for converting to/from characters, integers, and negation.
106#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
107pub enum Digit {
108    /// Represents -1
109    Neg,
110    /// Represents 0
111    Zero,
112    /// Represents +1
113    Pos,
114}
115
116impl Digit {
117
118    /// Converts the `Digit` into a character representation.
119    ///
120    /// - Returns:
121    ///     - `Θ` for `Digit::Neg`
122    ///     - `0` for `Digit::Zero`
123    ///     - `1` for `Digit::Pos`
124    pub const fn to_char_theta(&self) -> char {
125        match self {
126            Digit::Neg => 'Θ',
127            Digit::Zero => '0',
128            Digit::Pos => '1',
129        }
130    }
131
132
133    /// Converts the `Digit` into a character representation.
134    ///
135    /// - Returns:
136    ///     - `Z` for `Digit::Neg`
137    ///     - `0` for `Digit::Zero`
138    ///     - `1` for `Digit::Pos`
139    pub const fn to_char_z(&self) -> char {
140        match self {
141            Digit::Neg => 'Z',
142            Digit::Zero => '0',
143            Digit::Pos => '1',
144        }
145    }
146
147    /// Converts the `Digit` into a character representation.
148    ///
149    /// - Returns:
150    ///     - `T` for `Digit::Neg`
151    ///     - `0` for `Digit::Zero`
152    ///     - `1` for `Digit::Pos`
153    pub const fn to_char_t(&self) -> char {
154        match self {
155            Digit::Neg => 'T',
156            Digit::Zero => '0',
157            Digit::Pos => '1',
158        }
159    }
160
161    /// Creates a `Digit` from a character representation.
162    ///
163    /// - Accepts:
164    ///     - `Θ` for `Digit::Neg`
165    ///     - `0` for `Digit::Zero`
166    ///     - `1` for `Digit::Pos`
167    /// - Panics if the input character is invalid.
168    pub const fn from_char_theta(c: char) -> Digit {
169        match c { 
170            'Θ' => Digit::Neg,
171            '0' => Digit::Zero,
172            '1' => Digit::Pos,
173            _ => panic!("Invalid value. Expected 'Θ', '0', or '1'."),
174        }
175    }
176
177    /// Creates a `Digit` from a character representation.
178    ///
179    /// - Accepts:
180    ///     - `Z` for `Digit::Neg`
181    ///     - `0` for `Digit::Zero`
182    ///     - `1` for `Digit::Pos`
183    /// - Panics if the input character is invalid.
184    pub const fn from_char_z(c: char) -> Digit {
185        match c {
186            'Z' => Digit::Neg,
187            '0' => Digit::Zero,
188            '1' => Digit::Pos,
189            _ => panic!("Invalid value. Expected 'Z', '0', or '1'."),
190        }
191    }
192
193    /// Creates a `Digit` from a character representation.
194    ///
195    /// - Accepts:
196    ///     - `T` for `Digit::Neg`
197    ///     - `0` for `Digit::Zero`
198    ///     - `1` for `Digit::Pos`
199    /// - Panics if the input character is invalid.
200    pub const fn from_char_t(c: char) -> Digit {
201        match c {
202            'T' => Digit::Neg,
203            '0' => Digit::Zero,
204            '1' => Digit::Pos,
205            _ => panic!("Invalid value. Expected 'T', '0', or '1'."),
206        }
207    }
208    
209    /// Converts the `Digit` into its character representation.
210    ///
211    /// - Returns:
212    ///     - `-` for `Digit::Neg`
213    ///     - `0` for `Digit::Zero`
214    ///     - `+` for `Digit::Pos`
215    pub const fn to_char(&self) -> char {
216        match self {
217            Digit::Neg => '-',
218            Digit::Zero => '0',
219            Digit::Pos => '+',
220        }
221    }
222
223    /// Creates a `Digit` from its character representation.
224    ///
225    /// - Accepts:
226    ///     - `-` for `Digit::Neg`
227    ///     - `0` for `Digit::Zero`
228    ///     - `+` for `Digit::Pos`
229    /// - Panics if the input character is invalid.
230    pub const fn from_char(c: char) -> Digit {
231        match c {
232            '-' => Digit::Neg,
233            '0' => Digit::Zero,
234            '+' => Digit::Pos,
235            _ => panic!("Invalid value. A Ternary must be either -, 0 or +."),
236        }
237    }
238
239    /// Converts the `Digit` into its integer representation.
240    ///
241    /// - Returns:
242    ///     - -1 for `Digit::Neg`
243    ///     - 0 for `Digit::Zero`
244    ///     - 1 for `Digit::Pos`
245    pub const fn to_i8(&self) -> i8 {
246        match self {
247            Digit::Neg => -1,
248            Digit::Zero => 0,
249            Digit::Pos => 1,
250        }
251    }
252
253    /// Creates a `Digit` from its integer representation.
254    ///
255    /// - Accepts:
256    ///     - -1 for `Digit::Neg`
257    ///     - 0 for `Digit::Zero`
258    ///     - 1 for `Digit::Pos`
259    /// - Panics if the input integer is invalid.
260    pub const fn from_i8(i: i8) -> Digit {
261        match i {
262            -1 => Digit::Neg,
263            0 => Digit::Zero,
264            1 => Digit::Pos,
265            _ => panic!("Invalid value. A Ternary must be either -1, 0 or +1."),
266        }
267    }
268
269    /// Returns the corresponding possible value of the current `Digit`.
270    ///
271    /// - Returns:
272    ///     - `Digit::Neg` for `Digit::Neg`
273    ///     - `Digit::Pos` for `Digit::Zero`
274    ///     - `Digit::Pos` for `Digit::Pos`
275    pub const fn possibly(self) -> Self {
276        match self {
277            Digit::Neg => Digit::Neg,
278            Digit::Zero => Digit::Pos,
279            Digit::Pos => Digit::Pos,
280        }
281    }
282
283    /// Determines the condition of necessity for the current `Digit`.
284    ///
285    /// - Returns:
286    ///     - `Digit::Neg` for `Digit::Neg`
287    ///     - `Digit::Neg` for `Digit::Zero`
288    ///     - `Digit::Pos` for `Digit::Pos`
289    ///
290    /// This method is used to calculate necessity as part
291    /// of balanced ternary logic systems.
292    pub const fn necessary(self) -> Self {
293        match self {
294            Digit::Neg => Digit::Neg,
295            Digit::Zero => Digit::Neg,
296            Digit::Pos => Digit::Pos,
297        }
298    }
299
300    /// Determines the condition of contingency for the current `Digit`.
301    ///
302    /// - Returns:
303    ///     - `Digit::Neg` for `Digit::Neg`
304    ///     - `Digit::Pos` for `Digit::Zero`
305    ///     - `Digit::Neg` for `Digit::Pos`
306    ///
307    /// This method represents contingency in balanced ternary logic,
308    /// which defines the specific alternation of `Digit` values.
309    pub const fn contingently(self) -> Self {
310        match self {
311            Digit::Neg => Digit::Neg,
312            Digit::Zero => Digit::Pos,
313            Digit::Pos => Digit::Neg,
314        }
315    }
316
317    /// Returns the absolute positive value of the current `Digit`.
318    ///
319    /// - Returns:
320    ///     - `Digit::Pos` for `Digit::Neg`
321    ///     - `Digit::Zero` for `Digit::Zero`
322    ///     - `Digit::Pos` for `Digit::Pos`
323    pub const fn absolute_positive(self) -> Self {
324        match self {
325            Digit::Neg => Digit::Pos,
326            Digit::Zero => Digit::Zero,
327            Digit::Pos => Digit::Pos,
328        }
329    }
330
331    /// Determines the strictly positive condition for the current `Digit`.
332    ///
333    /// - Returns:
334    ///     - `Digit::Zero` for `Digit::Neg`
335    ///     - `Digit::Zero` for `Digit::Zero`
336    ///     - `Digit::Pos` for `Digit::Pos`
337    ///
338    /// This method is used to calculate strictly positive states
339    /// in association with ternary logic.
340    pub const fn positive(self) -> Self {
341        match self {
342            Digit::Neg => Digit::Zero,
343            Digit::Zero => Digit::Zero,
344            Digit::Pos => Digit::Pos,
345        }
346    }
347
348    /// Determines the condition of non-negativity for the current `Digit`.
349    ///
350    /// - Returns:
351    ///     - `Digit::Zero` for `Digit::Neg`
352    ///     - `Digit::Pos` for `Digit::Zero`
353    ///     - `Digit::Pos` for `Digit::Pos`
354    ///
355    /// This method is used to filter out negative conditions
356    /// in computations with balanced ternary representations.
357    pub const fn not_negative(self) -> Self {
358        match self {
359            Digit::Neg => Digit::Zero,
360            Digit::Zero => Digit::Pos,
361            Digit::Pos => Digit::Pos,
362        }
363    }
364
365    /// Determines the condition of non-positivity for the current `Digit`.
366    ///
367    /// - Returns:
368    ///     - `Digit::Neg` for `Digit::Neg`
369    ///     - `Digit::Neg` for `Digit::Zero`
370    ///     - `Digit::Zero` for `Digit::Pos`
371    ///
372    /// This method complements the `positive` condition and captures
373    /// states that are not strictly positive.
374    pub const fn not_positive(self) -> Self {
375        match self {
376            Digit::Neg => Digit::Neg,
377            Digit::Zero => Digit::Neg,
378            Digit::Pos => Digit::Zero,
379        }
380    }
381
382    /// Determines the strictly negative condition for the current `Digit`.
383    ///
384    /// - Returns:
385    ///     - `Digit::Neg` for `Digit::Neg`
386    ///     - `Digit::Zero` for `Digit::Zero`
387    ///     - `Digit::Zero` for `Digit::Pos`
388    ///
389    /// This method calculates strictly negative states
390    /// in association with ternary logic.
391    pub const fn negative(self) -> Self {
392        match self {
393            Digit::Neg => Digit::Neg,
394            Digit::Zero => Digit::Zero,
395            Digit::Pos => Digit::Zero,
396        }
397    }
398
399    /// Returns the absolute negative value of the current `Digit`.
400    ///
401    /// - Returns:
402    ///     - `Digit::Neg` for `Digit::Neg`
403    ///     - `Digit::Zero` for `Digit::Zero`
404    ///     - `Digit::Neg` for `Digit::Pos`
405    pub const fn absolute_negative(self) -> Self {
406        match self {
407            Digit::Neg => Digit::Neg,
408            Digit::Zero => Digit::Zero,
409            Digit::Pos => Digit::Neg,
410        }
411    }
412
413    /// Performs Kleene implication with the current `Digit` as `self` and another `Digit`.
414    ///
415    /// - `self`: The antecedent of the implication.
416    /// - `other`: The consequent of the implication.
417    ///
418    /// - Returns:
419    ///     - `Digit::Pos` when `self` is `Digit::Neg`.
420    ///     - The positive condition of `other` when `self` is `Digit::Zero`.
421    ///     - `other` when `self` is `Digit::Pos`.
422    ///
423    /// Implements Kleene ternary implication logic, which includes
424    /// determining the logical result based on antecedent and consequent.
425    pub const fn k3_imply(self, other: Self) -> Self {
426        match self {
427            Digit::Neg => Digit::Pos,
428            Digit::Zero => other.positive(),
429            Digit::Pos => other,
430        }
431    }
432
433    /// Apply a ternary equivalence operation for the current `Digit` and another `Digit`.
434    ///
435    /// - `self`: The first operand of the equivalence operation.
436    /// - `other`: The second operand of the equivalence operation.
437    ///
438    /// - Returns:
439    ///     - The negation of `other` when `self` is `Digit::Neg`.
440    ///     - `Digit::Zero` when `self` is `Digit::Zero`.
441    ///     - `other` when `self` is `Digit::Pos`.
442    ///
443    /// This method implements a ternary logic equivalence, which captures the relationship between
444    /// two balanced ternary `Digit`s based on their logical equivalence.
445    pub const fn k3_equiv(self, other: Self) -> Self {
446        match self {
447            Digit::Neg => match other {
448                Digit::Neg => Digit::Pos,
449                Digit::Zero => Digit::Zero,
450                Digit::Pos => Digit::Neg,
451            },
452            Digit::Zero => Digit::Zero,
453            Digit::Pos => other,
454        }
455    }
456
457    /// Performs a ternary AND operation for the current `Digit` and another `Digit`.
458    ///
459    /// - `self`: The first operand of the AND operation.
460    /// - `other`: The second operand of the AND operation.
461    ///
462    /// - Returns:
463    ///     - `Digit::Neg` if `self` is `Digit::Neg` and `other` is not `Digit::Zero`.
464    ///     - `Digit::Zero` if either `self` or `other` is `Digit::Zero`.
465    ///     - `other` if `self` is `Digit::Pos`.
466    ///
467    /// This method implements Bochvar's internal three-valued logic in balanced ternary AND operation,
468    /// which evaluates the logical conjunction of two `Digit`s in the ternary logic system.
469    pub const fn bi3_and(self, other: Self) -> Self {
470        match self {
471            Digit::Neg => other.absolute_negative(),
472            Digit::Zero => Digit::Zero,
473            Digit::Pos => other,
474        }
475    }
476
477    /// Performs a ternary OR operation for the current `Digit` and another `Digit`.
478    ///
479    /// - `self`: The first operand of the OR operation.
480    /// - `other`: The second operand of the OR operation.
481    ///
482    /// - Returns:
483    ///     - `other` if `self` is `Digit::Neg`.
484    ///     - `Digit::Zero` if `self` is `Digit::Zero`.
485    ///     - `Digit::Pos` if `self` is `Digit::Pos` and `other` is not `Digit::Zero`.
486    ///
487    /// This method implements Bochvar's three-valued internal ternary logic for the OR operation,
488    /// determining the logical disjunction of two balanced ternary `Digit`s.
489    pub const fn bi3_or(self, other: Self) -> Self {
490        match self {
491            Digit::Neg => other,
492            Digit::Zero => Digit::Zero,
493            Digit::Pos => other.absolute_positive(),
494        }
495    }
496
497    /// Performs Bochvar's internal three-valued implication with the current `Digit` as `self`
498    /// and another `Digit` as the consequent.
499    ///
500    /// - `self`: The antecedent of the implication.
501    /// - `other`: The consequent of the implication.
502    ///
503    /// - Returns:
504    ///     - `Digit::Zero` if `self` is `Digit::Neg` and `other` is `Digit::Zero`.
505    ///     - `Digit::Pos` if `self` is `Digit::Neg` and `other` is not `Digit::Zero`.
506    ///     - `Digit::Zero` if `self` is `Digit::Zero`.
507    ///     - `other` if `self` is `Digit::Pos`.
508    ///
509    /// This method implements Bochvar's internal implication logic, which evaluates
510    /// the logical consequence, between two balanced ternary `Digit`s in a manner
511    /// consistent with three-valued logic principles.
512    pub const fn bi3_imply(self, other: Self) -> Self {
513        match self {
514            Digit::Neg => other.absolute_positive(),
515            Digit::Zero => Digit::Zero,
516            Digit::Pos => other,
517        }
518    }
519
520    /// Performs Łukasiewicz implication with the current `Digit` as `self` and another `Digit`.
521    ///
522    /// - `self`: The antecedent of the implication.
523    /// - `other`: The consequent of the implication.
524    ///
525    /// - Returns:
526    ///     - `Digit::Pos` when `self` is `Digit::Neg`.
527    ///     - The non-negative condition of `other` when `self` is `Digit::Zero`.
528    ///     - `other` when `self` is `Digit::Pos`.
529    ///
530    /// Implements Łukasiewicz ternary implication logic, which
531    /// evaluates an alternative approach for implication compared to Kleene logic.
532    pub const fn l3_imply(self, other: Self) -> Self {
533        match self {
534            Digit::Neg => Digit::Pos,
535            Digit::Zero => other.not_negative(),
536            Digit::Pos => other,
537        }
538    }
539
540    /// Performs RM3 implication with the current `Digit` as `self` and another `Digit`.
541    ///
542    /// - `self`: The antecedent of the implication.
543    /// - `other`: The consequent of the implication.
544    ///
545    /// - Returns:
546    ///     - `Digit::Pos` when `self` is `Digit::Neg`.
547    ///     - `other` when `self` is `Digit::Zero`.
548    ///     - The necessary condition of `other` when `self` is `Digit::Pos`.
549    ///
550    /// Implements RM3 ternary implication logic, which defines a unique
551    /// perspective for implication operations in balanced ternary systems.
552    pub const fn rm3_imply(self, other: Self) -> Self {
553        match self {
554            Digit::Neg => Digit::Pos,
555            Digit::Zero => other,
556            Digit::Pos => other.necessary(),
557        }
558    }
559
560    /// Performs the paraconsistent-logic implication with the current `Digit` as `self` and another `Digit`.
561    ///
562    /// - `self`: The antecedent of the implication.
563    /// - `other`: The consequent of the implication.
564    ///
565    /// - Returns:
566    ///     - `Digit::Pos` when `self` is `Digit::Neg`.
567    ///     - `other` otherwise.
568    pub const fn para_imply(self, other: Self) -> Self {
569        match self {
570            Digit::Neg => Digit::Pos,
571            _ => other,
572        }
573    }
574
575    /// Performs HT implication with the current `Digit` as `self` and another `Digit`.
576    ///
577    /// - `self`: The antecedent of the implication.
578    /// - `other`: The consequent of the implication.
579    ///
580    /// - Returns:
581    ///     - `Digit::Pos` when `self` is `Digit::Neg`.
582    ///     - The possibility condition of `other` when `self` is `Digit::Zero`.
583    ///     - `other` when `self` is `Digit::Pos`.
584    ///
585    /// This method computes HT ternary implication based on heuristic logic.
586    pub const fn ht_imply(self, other: Self) -> Self {
587        match self {
588            Digit::Neg => Digit::Pos,
589            Digit::Zero => other.possibly(),
590            Digit::Pos => other,
591        }
592    }
593
594    /// Performs HT logical negation of the current `Digit`.
595    ///
596    /// - Returns:
597    ///     - `Digit::Pos` when `self` is `Digit::Neg`.
598    ///     - `Digit::Neg` when `self` is `Digit::Zero` or `Digit::Pos`.
599    ///
600    /// This method evaluates the HT negation result using heuristic ternary logic.
601    pub const fn ht_not(self) -> Self {
602        match self {
603            Digit::Neg => Digit::Pos,
604            Digit::Zero => Digit::Neg,
605            Digit::Pos => Digit::Neg,
606        }
607    }
608
609    /// Converts the `Digit` to a `bool` in HT logic.
610    ///
611    /// - Returns:
612    ///     - `true` when `self` is `Digit::Pos`.
613    ///     - `false` when `self` is `Digit::Neg`.
614    ///
615    /// - Panics:
616    ///     - Panics if `self` is `Digit::Zero`, as `Digit::Zero` cannot be directly
617    ///       converted to a boolean value.
618    ///       > To ensure `Pos` or `Neg` value, use one of :
619    ///       > * [Digit::possibly]
620    ///       > * [Digit::necessary]
621    ///       > * [Digit::contingently]
622    ///       > * [Digit::ht_not]
623    ///
624    pub const fn ht_bool(self) -> bool {
625        match self {
626            Digit::Neg => false,
627            Digit::Zero => panic!(
628                "Cannot convert a Digit::Zero to a bool. \
629                 Use Digit::possibly()->to_bool() or Digit::necessary()->to_bool() instead."
630            ),
631            Digit::Pos => true,
632        }
633    }
634
635    /// Performs Post's negation of the current `Digit`.
636    ///
637    /// - Returns:
638    ///     - `Digit::Zero` when `self` is `Digit::Neg`.
639    ///     - `Digit::Pos` when `self` is `Digit::Zero`.
640    ///     - `Digit::Neg` when `self` is `Digit::Pos`.
641    ///
642    /// This method evaluates the negation based on Post's logic in ternary systems,
643    /// which differs from standard negation logic.
644    pub const fn post(self) -> Self {
645        match self {
646            Digit::Neg => Digit::Zero,
647            Digit::Zero => Digit::Pos,
648            Digit::Pos => Digit::Neg,
649        }
650    }
651
652    /// Performs the inverse operation from the Post's negation of the current `Digit`.
653    ///
654    /// - Returns:
655    ///     - `Digit::Pos` when `self` is `Digit::Neg`.
656    ///     - `Digit::Neg` when `self` is `Digit::Zero`.
657    ///     - `Digit::Zero` when `self` is `Digit::Pos`.
658    pub const fn pre(self) -> Self {
659        match self {
660            Digit::Neg => Digit::Pos,
661            Digit::Zero => Digit::Neg,
662            Digit::Pos => Digit::Zero,
663        }
664    }
665
666    /// This method maps this `Digit` value to its corresponding unbalanced ternary
667    /// integer representation.
668    ///
669    /// - Returns:
670    ///     - `0` for `Digit::Neg`.
671    ///     - `1` for `Digit::Zero`.
672    ///     - `2` for `Digit::Pos`.
673    ///
674    pub const fn to_unbalanced(self) -> u8 {
675        match self {
676            Digit::Neg => 0,
677            Digit::Zero => 1,
678            Digit::Pos => 2,
679        }
680    }
681
682    /// Creates a `Digit` from an unbalanced ternary integer representation.
683    ///
684    /// # Arguments:
685    /// - `u`: An unsigned 8-bit integer representing an unbalanced ternary value.
686    ///
687    /// # Returns:
688    /// - `Digit::Neg` for `0`.
689    /// - `Digit::Zero` for `1`.
690    /// - `Digit::Pos` for `2`.
691    ///
692    /// # Panics:
693    /// - Panics if the provided value is not `0`, `1`, or `2`, as these are the
694    ///   only valid representations of unbalanced ternary values.
695    pub const fn from_unbalanced(u: u8) -> Digit {
696        match u {
697            0 => Digit::Neg,
698            1 => Digit::Zero,
699            2 => Digit::Pos,
700            _ => panic!("Invalid value. A unbalanced ternary value must be either 0, 1 or 2."),
701        }
702    }
703
704    /// Increments the `Digit` value and returns a `Ternary` result.
705    ///
706    /// - The rules for incrementing are based on ternary arithmetic:
707    ///   - For `Digit::Neg`:
708    ///     - Incrementing results in `Digit::Zero` (`Ternary::parse("0")`).
709    ///   - For `Digit::Zero`:
710    ///     - Incrementing results in `Digit::Pos` (`Ternary::parse("+")`).
711    ///   - For `Digit::Pos`:
712    ///     - Incrementing results in "overflow" (`Ternary::parse("+-")`).
713    ///
714    /// - Returns:
715    ///   - A `Ternary` instance representing the result of the increment operation.
716    pub fn inc(self) -> Ternary {
717        match self {
718            Digit::Neg => Ternary::parse("0"),
719            Digit::Zero => Ternary::parse("+"),
720            Digit::Pos => Ternary::parse("+-"),
721        }
722    }
723
724    /// Decrements the `Digit` value and returns a `Ternary` result.
725    ///
726    /// - The rules for decrementing are based on ternary arithmetic:
727    ///   - For `Digit::Neg`:
728    ///     - Decrementing results in "underflow" (`Ternary::parse("-+")`).
729    ///   - For `Digit::Zero`:
730    ///     - Decrementing results in `Digit::Neg` (`Ternary::parse("-")`).
731    ///   - For `Digit::Pos`:
732    ///     - Decrementing results in `Digit::Zero` (`Ternary::parse("0")`).
733    ///
734    /// - Returns:
735    ///   - A `Ternary` instance representing the result of the decrement operation.
736    pub fn dec(self) -> Ternary {
737        match self {
738            Digit::Neg => Ternary::parse("-+"),
739            Digit::Zero => Ternary::parse("-"),
740            Digit::Pos => Ternary::parse("0"),
741        }
742    }
743}
744
745impl Neg for Digit {
746    type Output = Self;
747
748    /// Returns the negation of the `Digit`.
749    ///
750    /// - `Digit::Neg` becomes `Digit::Pos`
751    /// - `Digit::Pos` becomes `Digit::Neg`
752    /// - `Digit::Zero` remains `Digit::Zero`
753    fn neg(self) -> Self::Output {
754        match self {
755            Digit::Neg => Digit::Pos,
756            Digit::Zero => Digit::Zero,
757            Digit::Pos => Digit::Neg,
758        }
759    }
760}
761
762impl Not for Digit {
763    type Output = Self;
764    fn not(self) -> Self::Output {
765        -self
766    }
767}
768
769impl Add<Digit> for Digit {
770    type Output = Ternary;
771
772    /// Adds two `Digit` values together and returns a `Ternary` result.
773    ///
774    /// - The rules for addition are based on ternary arithmetic:
775    ///   - For `Digit::Neg`:
776    ///     - Adding `Digit::Neg` results in "underflow" (`Ternary::parse("-+")`).
777    ///     - Adding `Digit::Zero` keeps the result as `Digit::Neg` (`Ternary::parse("-")`).
778    ///     - Adding `Digit::Pos` results in a balance (`Ternary::parse("0")`).
779    ///   - For `Digit::Zero`:
780    ///     - Simply returns the other operand wrapped in a `Ternary` object.
781    ///   - For `Digit::Pos`:
782    ///     - Adding `Digit::Neg` results in balance (`Ternary::parse("0")`).
783    ///     - Adding `Digit::Zero` keeps the result as `Digit::Pos` (`Ternary::parse("+")`).
784    ///     - Adding `Digit::Pos` results in "overflow" (`Ternary::parse("+-")`).
785    ///
786    /// - Returns:
787    ///   - A `Ternary` instance that holds the result of the addition.
788    ///
789    /// - Panics:
790    ///   - This method does not panic under any circumstances.
791    fn add(self, other: Digit) -> Self::Output {
792        match self {
793            Digit::Neg => other.dec(),
794            Digit::Zero => Ternary::new(vec![other]),
795            Digit::Pos => other.inc(),
796        }
797    }
798}
799
800impl Sub<Digit> for Digit {
801    type Output = Ternary;
802
803    /// Subtracts two `Digit` values and returns a `Ternary` result.
804    ///
805    /// - The rules for subtraction are based on ternary arithmetic:
806    ///   - For `Digit::Neg`:
807    ///     - Subtracting `Digit::Neg` results in balance (`Ternary::parse("0")`).
808    ///     - Subtracting `Digit::Zero` keeps the result as `Digit::Neg` (`Ternary::parse("-")`).
809    ///     - Subtracting `Digit::Pos` results in "underflow" (`Ternary::parse("-+")`).
810    ///   - For `Digit::Zero`:
811    ///     - Simply negates the other operand and returns it wrapped in a `Ternary` object.
812    ///   - For `Digit::Pos`:
813    ///     - Subtracting `Digit::Neg` results in "overflow" (`Ternary::parse("+-")`).
814    ///     - Subtracting `Digit::Zero` keeps the result as `Digit::Pos` (`Ternary::parse("+")`).
815    ///     - Subtracting `Digit::Pos` results in balance (`Ternary::parse("0")`).
816    ///
817    /// - Returns:
818    ///   - A `Ternary` instance that holds the result of the subtraction.
819    ///
820    /// - Panics:
821    ///   - This method does not panic under any circumstances.
822    fn sub(self, other: Digit) -> Self::Output {
823        match self {
824            Digit::Neg => other.inc(),
825            Digit::Zero => Ternary::new(vec![-other]),
826            Digit::Pos => other.dec(),
827        }
828    }
829}
830
831impl Mul<Digit> for Digit {
832    type Output = Digit;
833
834    /// Multiplies two `Digit` values together and returns the product as a `Digit`.
835    ///
836    /// - The rules for multiplication in this implementation are straightforward:
837    ///   - `Digit::Neg` multiplied by:
838    ///     - `Digit::Neg` results in `Digit::Pos`.
839    ///     - `Digit::Zero` results in `Digit::Zero`.
840    ///     - `Digit::Pos` results in `Digit::Neg`.
841    ///   - `Digit::Zero` multiplied by any `Digit` always results in `Digit::Zero`.
842    ///   - `Digit::Pos` multiplied by:
843    ///     - `Digit::Neg` results in `Digit::Neg`.
844    ///     - `Digit::Zero` results in `Digit::Zero`.
845    ///     - `Digit::Pos` results in `Digit::Pos`.
846    ///
847    /// - Returns:
848    ///   - A `Digit` instance representing the result of the multiplication.
849    fn mul(self, other: Digit) -> Self::Output {
850        match self {
851            Digit::Neg => -other,
852            Digit::Zero => Digit::Zero,
853            Digit::Pos => other,
854        }
855    }
856}
857
858impl Div<Digit> for Digit {
859    type Output = Digit;
860
861    /// Divides one `Digit` value by another and returns the result as a `Digit`.
862    ///
863    /// # Rules for division:
864    /// - For `Digit::Neg`:
865    ///   - Dividing `Digit::Neg` by `Digit::Neg` results in `Digit::Pos`.
866    ///   - Dividing `Digit::Neg` by `Digit::Zero` will panic with "Cannot divide by zero."
867    ///   - Dividing `Digit::Neg` by `Digit::Pos` results in `Digit::Neg`.
868    /// - For `Digit::Zero`:
869    ///   - Dividing `Digit::Zero` by `Digit::Neg` results in `Digit::Zero`.
870    ///   - Dividing `Digit::Zero` by `Digit::Zero` will panic with "Cannot divide by zero."
871    ///   - Dividing `Digit::Zero` by `Digit::Pos` results in `Digit::Zero`.
872    /// - For `Digit::Pos`:
873    ///   - Dividing `Digit::Pos` by `Digit::Neg` results in `Digit::Neg`.
874    ///   - Dividing `Digit::Pos` by `Digit::Zero` will panic with "Cannot divide by zero."
875    ///   - Dividing `Digit::Pos` by `Digit::Pos` results in `Digit::Pos`.
876    ///
877    /// # Returns:
878    /// - A `Digit` value representing the result of the division.
879    ///
880    /// # Panics:
881    /// - Panics with "Cannot divide by zero." if the `other` operand is `Digit::Zero`.
882    fn div(self, other: Digit) -> Self::Output {
883        if other == Digit::Zero {
884            panic!("Cannot divide by zero.");
885        }
886        self * other
887    }
888}
889
890impl BitAnd for Digit {
891    type Output = Self;
892
893    /// Performs a bitwise AND operation between two `Digit` values and returns the result.
894    ///
895    /// - The rules for the bitwise AND (`&`) operation are:
896    ///   - If `self` is `Digit::Neg`, the result is always `Digit::Neg`.
897    ///   - If `self` is `Digit::Zero`, the result depends on the value of `other`:
898    ///     - `Digit::Neg` results in `Digit::Neg`.
899    ///     - Otherwise, the result is `Digit::Zero`.
900    ///   - If `self` is `Digit::Pos`, the result is simply `other`.
901    ///
902    /// # Returns:
903    /// - A `Digit` value that is the result of the bitwise AND operation.
904    ///
905    /// # Examples:
906    /// ```
907    /// use balanced_ternary::Digit;
908    /// use Digit::{Neg, Pos, Zero};
909    ///
910    /// assert_eq!(Neg & Pos, Neg);
911    /// assert_eq!(Zero & Neg, Neg);
912    /// assert_eq!(Zero & Pos, Zero);
913    /// assert_eq!(Pos & Zero, Zero);
914    /// ```
915    fn bitand(self, other: Self) -> Self::Output {
916        match self {
917            Digit::Neg => Digit::Neg,
918            Digit::Zero => other.negative(),
919            Digit::Pos => other,
920        }
921    }
922}
923
924impl BitOr for Digit {
925    type Output = Self;
926
927    /// Performs a bitwise OR operation between two `Digit` values and returns the result.
928    ///
929    /// - The rules for the bitwise OR (`|`) operation are as follows:
930    ///   - If `self` is `Digit::Neg`, the result is always the value of `other`.
931    ///   - If `self` is `Digit::Zero`, the result depends on the value of `other`:
932    ///     - `Digit::Pos` results in `Digit::Pos`.
933    ///     - Otherwise, the result is `Digit::Zero`.
934    ///   - If `self` is `Digit::Pos`, the result is always `Digit::Pos`.
935    ///
936    /// # Returns:
937    /// - A `Digit` value that is the result of the bitwise OR operation.
938    ///
939    /// # Examples:
940    /// ```
941    /// use balanced_ternary::Digit;
942    /// use Digit::{Neg, Pos, Zero};
943    ///
944    /// assert_eq!(Neg | Pos, Pos);
945    /// assert_eq!(Zero | Neg, Zero);
946    /// assert_eq!(Zero | Pos, Pos);
947    /// assert_eq!(Pos | Zero, Pos);
948    /// ```
949    fn bitor(self, other: Self) -> Self::Output {
950        match self {
951            Digit::Neg => other,
952            Digit::Zero => other.positive(),
953            Digit::Pos => Digit::Pos,
954        }
955    }
956}
957
958impl BitXor for Digit {
959    type Output = Self;
960
961    /// Performs a bitwise XOR (exclusive OR) operation between two `Digit` values.
962    ///
963    /// - The rules for the bitwise XOR (`^`) operation are as follows:
964    ///   - If `self` is `Digit::Neg`, the result is always the value of `rhs`.
965    ///   - If `self` is `Digit::Zero`, the result is always `Digit::Zero`.
966    ///   - If `self` is `Digit::Pos`, the result is the negation of `rhs`:
967    ///     - `Digit::Neg` becomes `Digit::Pos`.
968    ///     - `Digit::Zero` becomes `Digit::Zero`.
969    ///     - `Digit::Pos` becomes `Digit::Neg`.
970    ///
971    /// # Returns:
972    /// - A `Digit` value that is the result of the bitwise XOR operation.
973    ///
974    /// # Examples:
975    /// ```
976    /// use balanced_ternary::Digit;
977    /// use Digit::{Neg, Pos, Zero};
978    ///
979    /// assert_eq!(Neg ^ Pos, Pos);
980    /// assert_eq!(Zero ^ Neg, Zero);
981    /// assert_eq!(Pos ^ Pos, Neg);
982    /// ```
983    fn bitxor(self, rhs: Self) -> Self::Output {
984        match self {
985            Digit::Neg => rhs,
986            Digit::Zero => Digit::Zero,
987            Digit::Pos => -rhs,
988        }
989    }
990}