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