chinese_format/
sign.rs

1use std::hash::Hash;
2
3use crate::{Chinese, ChineseFormat, Variant};
4
5/// Sign of a number.
6#[derive(Debug, Clone, Copy)]
7pub struct Sign(pub i128);
8
9/// [Sign] instances are equal if the sign (+, - or 0) of their
10/// underlying numeric values are equal:
11///
12/// ```
13/// use chinese_format::*;
14///
15/// assert_eq!(Sign(-9), Sign(-3));
16/// assert_eq!(Sign(0), Sign(0));
17/// assert_eq!(Sign(13), Sign(90));
18///
19/// assert_ne!(Sign(-9), Sign(0));
20/// assert_ne!(Sign(-9), Sign(7));
21/// assert_ne!(Sign(0), Sign(-9));
22/// assert_ne!(Sign(0), Sign(13));
23/// assert_ne!(Sign(13), Sign(-9));
24/// assert_ne!(Sign(13), Sign(0));
25/// ```
26impl PartialEq for Sign {
27    fn eq(&self, other: &Self) -> bool {
28        self.0.signum() == other.0.signum()
29    }
30}
31
32impl Eq for Sign {}
33
34/// [Sign] instances are sorted in this order:
35///
36/// 1. negative
37/// 1. zero
38/// 1. positive
39///
40/// The magnitude of the underlying integer values
41/// does not affect the comparison:
42///
43/// ```
44/// use chinese_format::*;
45///
46/// assert!(Sign(-90) == Sign(-4));
47/// assert!(Sign(0) > Sign(-4));
48/// assert!(Sign(0) < Sign(17));
49/// assert!(Sign(17) == Sign(92));
50/// ```
51impl PartialOrd for Sign {
52    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
53        Some(self.cmp(other))
54    }
55}
56
57impl Ord for Sign {
58    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
59        self.0.signum().cmp(&other.0.signum())
60    }
61}
62
63/// The hash depends uniquely on the sign of the underlying integer value.
64///
65/// ```
66/// use chinese_format::*;
67/// use std::collections::hash_map::DefaultHasher;
68/// use std::hash::{Hash, Hasher};
69///
70/// fn get_hash<T: Hash>(source: &T) -> u64 {
71///     let mut hasher = DefaultHasher::new();
72///     source.hash(&mut hasher);
73///     hasher.finish()
74/// }
75///
76/// fn main() {
77///     assert_eq!(get_hash(&Sign(-54)), get_hash(&Sign(-7)));
78///     assert_eq!(get_hash(&Sign(0)), get_hash(&Sign(0)));
79///     assert_eq!(get_hash(&Sign(3)), get_hash(&Sign(90)));
80///
81///     assert_ne!(get_hash(&Sign(-54)), get_hash(&Sign(0)));
82///     assert_ne!(get_hash(&Sign(0)), get_hash(&Sign(90)));
83/// }
84/// ```
85impl Hash for Sign {
86    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
87        self.0.signum().hash(state);
88    }
89}
90
91/// When converted to Chinese, a sign renders as follows:
92///
93/// * for *positive numbers* and *zero*: an **empty string** (thus [omissible](Chinese::omissible), too).
94///
95/// * for *negative numbers*:
96///
97///   * `负` in [Variant::Simplified] script.
98///
99///   * `負` in [Variant::Traditional] script.
100///
101/// ```
102/// use chinese_format::*;
103///
104/// //Positive numbers
105/// assert_eq!(Sign(90).to_chinese(Variant::Simplified), Chinese {
106///     logograms: "".to_string(),
107///     omissible: true
108/// });
109/// assert_eq!(Sign(90).to_chinese(Variant::Traditional), "");
110///
111/// //Zero
112/// assert_eq!(Sign(0).to_chinese(Variant::Simplified), Chinese {
113///     logograms: "".to_string(),
114///     omissible: true
115/// });
116/// assert_eq!(Sign(0).to_chinese(Variant::Traditional), "");
117///
118/// //Negative numbers
119/// assert_eq!(Sign(-7).to_chinese(Variant::Simplified), Chinese {
120///     logograms: "负".to_string(),
121///     omissible: false
122/// });
123/// assert_eq!(Sign(-7).to_chinese(Variant::Traditional), "負");
124/// ```
125impl ChineseFormat for Sign {
126    fn to_chinese(&self, variant: Variant) -> Chinese {
127        if self.0 >= 0 {
128            "".to_chinese(variant)
129        } else {
130            ("负", "負").to_chinese(variant)
131        }
132    }
133}