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/// 
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}