balanced_ternary/
digit.rs

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