balanced_ternary/
digit.rs

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