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}