1 | // Take a look at the license at the top of the repository in the LICENSE file. |
2 | |
3 | use std::fmt; |
4 | |
5 | use super::{Format, FormattedValueNoneBuilder}; |
6 | use crate::utils::Displayable; |
7 | |
8 | // rustdoc-stripper-ignore-next |
9 | /// A signed wrapper. |
10 | /// |
11 | /// This wrapper allows representing a signed value from a type |
12 | /// which is originally unsigned. In C APIs, this is represented |
13 | /// by a tuple with a signed integer positive or negative and |
14 | /// the absolute value. |
15 | #[derive (Clone, Copy, Debug, Eq, PartialEq, Hash)] |
16 | #[cfg_attr (feature = "serde" , derive(serde::Serialize, serde::Deserialize))] |
17 | pub enum Signed<T> { |
18 | Negative(T), |
19 | Positive(T), |
20 | } |
21 | |
22 | impl<T> Signed<T> { |
23 | #[inline ] |
24 | pub fn is_positive(self) -> bool { |
25 | matches!(self, Signed::Positive(_)) |
26 | } |
27 | |
28 | // rustdoc-stripper-ignore-next |
29 | /// Returns `Some(value)`, where `value` is the inner value, |
30 | /// if `self` is positive. |
31 | #[inline ] |
32 | pub fn positive(self) -> Option<T> { |
33 | match self { |
34 | Signed::Positive(val) => Some(val), |
35 | Signed::Negative(_) => None, |
36 | } |
37 | } |
38 | |
39 | // rustdoc-stripper-ignore-next |
40 | /// Transforms the `Signed<T>` into a `Result<T, E>`, |
41 | /// mapping `Positive(v)` to `Ok(v)` and `Negative(_)` to `Err(err)`. |
42 | #[inline ] |
43 | pub fn positive_or<E>(self, err: E) -> Result<T, E> { |
44 | match self { |
45 | Signed::Positive(val) => Ok(val), |
46 | Signed::Negative(_) => Err(err), |
47 | } |
48 | } |
49 | |
50 | // rustdoc-stripper-ignore-next |
51 | /// Transforms the `Signed<T>` into a `Result<T, E>`, |
52 | /// mapping `Positive(v)` to `Ok(v)` and `Negative(v)` to `Err(err(v))`. |
53 | #[inline ] |
54 | pub fn positive_or_else<E, F: FnOnce(T) -> E>(self, err: F) -> Result<T, E> { |
55 | match self { |
56 | Signed::Positive(val) => Ok(val), |
57 | Signed::Negative(val) => Err(err(val)), |
58 | } |
59 | } |
60 | |
61 | #[inline ] |
62 | pub fn is_negative(self) -> bool { |
63 | matches!(self, Signed::Negative(_)) |
64 | } |
65 | |
66 | // rustdoc-stripper-ignore-next |
67 | /// Returns `Some(value)`, where `value` is the inner value, |
68 | /// if `self` is negative. |
69 | #[inline ] |
70 | pub fn negative(self) -> Option<T> { |
71 | match self { |
72 | Signed::Negative(val) => Some(val), |
73 | Signed::Positive(_) => None, |
74 | } |
75 | } |
76 | |
77 | // rustdoc-stripper-ignore-next |
78 | /// Transforms the `Signed<T>` into a `Result<T, E>`, |
79 | /// mapping `Negative(v)` to `Ok(v)` and `Positive(_)` to `Err(err)`. |
80 | #[inline ] |
81 | pub fn negative_or<E>(self, err: E) -> Result<T, E> { |
82 | match self { |
83 | Signed::Negative(val) => Ok(val), |
84 | Signed::Positive(_) => Err(err), |
85 | } |
86 | } |
87 | |
88 | // rustdoc-stripper-ignore-next |
89 | /// Transforms the `Signed<T>` into a `Result<T, E>`, |
90 | /// mapping `Negative(v)` to `Ok(v)` and `Positive(_)` to `Err(err(v))`. |
91 | #[inline ] |
92 | pub fn negative_or_else<E, F: FnOnce(T) -> E>(self, err: F) -> Result<T, E> { |
93 | match self { |
94 | Signed::Negative(val) => Ok(val), |
95 | Signed::Positive(val) => Err(err(val)), |
96 | } |
97 | } |
98 | |
99 | // rustdoc-stripper-ignore-next |
100 | /// Returns the absolute value of `self`. |
101 | #[inline ] |
102 | pub fn abs(self) -> T { |
103 | match self { |
104 | Signed::Positive(val) | Signed::Negative(val) => val, |
105 | } |
106 | } |
107 | } |
108 | |
109 | impl<T> std::ops::Neg for Signed<T> { |
110 | type Output = Signed<T>; |
111 | |
112 | #[inline ] |
113 | fn neg(self) -> Self { |
114 | match self { |
115 | Signed::Positive(val: T) => Signed::Negative(val), |
116 | Signed::Negative(val: T) => Signed::Positive(val), |
117 | } |
118 | } |
119 | } |
120 | |
121 | pub trait SignedIntrinsic {} |
122 | |
123 | impl<T> fmt::Display for Signed<T> |
124 | where |
125 | T: fmt::Display + SignedIntrinsic, |
126 | { |
127 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
128 | use std::fmt::Write; |
129 | |
130 | let (sign: char, val: &T) = match self { |
131 | Signed::Positive(val: &T) => ('+' , val), |
132 | Signed::Negative(val: &T) => ('-' , val), |
133 | }; |
134 | |
135 | f.write_char(sign)?; |
136 | fmt::Display::fmt(&val, f) |
137 | } |
138 | } |
139 | |
140 | impl<T> Displayable for Signed<T> |
141 | where |
142 | T: fmt::Display + SignedIntrinsic, |
143 | { |
144 | type DisplayImpl = Signed<T>; |
145 | |
146 | fn display(self) -> Self::DisplayImpl { |
147 | self |
148 | } |
149 | } |
150 | |
151 | impl<T> Signed<Option<T>> { |
152 | // rustdoc-stripper-ignore-next |
153 | /// Transposes a `Signed` `Option` into an `Option` of a `Signed`. |
154 | /// |
155 | /// Note that if the inner value was `None`, the sign is lost. |
156 | #[inline ] |
157 | pub fn transpose(self) -> Option<Signed<T>> { |
158 | use Signed::*; |
159 | |
160 | match self { |
161 | Positive(Some(val: T)) => Some(Positive(val)), |
162 | Negative(Some(val: T)) => Some(Negative(val)), |
163 | _ => None, |
164 | } |
165 | } |
166 | } |
167 | |
168 | pub struct DisplayableOptionSigned<T>(Option<Signed<T>>); |
169 | |
170 | impl<T> fmt::Display for DisplayableOptionSigned<T> |
171 | where |
172 | T: fmt::Display + SignedIntrinsic, |
173 | Option<T>: Displayable, |
174 | { |
175 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
176 | match self.0 { |
177 | Some(ref signed: &Signed) => fmt::Display::fmt(self:signed, f), |
178 | None => fmt::Display::fmt(&Option::<T>::None.display(), f), |
179 | } |
180 | } |
181 | } |
182 | |
183 | impl<T> Displayable for Option<Signed<T>> |
184 | where |
185 | T: fmt::Display + SignedIntrinsic, |
186 | Option<T>: Displayable, |
187 | { |
188 | type DisplayImpl = DisplayableOptionSigned<T>; |
189 | |
190 | fn display(self) -> Self::DisplayImpl { |
191 | DisplayableOptionSigned(self) |
192 | } |
193 | } |
194 | |
195 | impl<T> Displayable for Signed<Option<T>> |
196 | where |
197 | T: fmt::Display + SignedIntrinsic, |
198 | Option<T>: Displayable, |
199 | { |
200 | type DisplayImpl = DisplayableOptionSigned<T>; |
201 | |
202 | fn display(self) -> Self::DisplayImpl { |
203 | DisplayableOptionSigned(self.transpose()) |
204 | } |
205 | } |
206 | |
207 | // rustdoc-stripper-ignore-next |
208 | /// A trait implemented on unsigned types which can be converted into [`crate::Signed`]s. |
209 | pub trait UnsignedIntoSigned: Copy + Sized { |
210 | type Signed; |
211 | |
212 | // rustdoc-stripper-ignore-next |
213 | /// Converts `self` into a `Signed` matching the given `sign`. |
214 | fn into_signed(self, sign: i32) -> Self::Signed { |
215 | if sign.is_positive() { |
216 | self.into_positive() |
217 | } else { |
218 | self.into_negative() |
219 | } |
220 | } |
221 | |
222 | // rustdoc-stripper-ignore-next |
223 | /// Converts `self` into a `Signed::Positive`. |
224 | fn into_positive(self) -> Self::Signed; |
225 | |
226 | // rustdoc-stripper-ignore-next |
227 | /// Converts `self` into a `Signed::Negative`. |
228 | fn into_negative(self) -> Self::Signed; |
229 | } |
230 | |
231 | impl_unsigned_int_into_signed!(u64); |
232 | impl_signed_ops!(u64); |
233 | impl_signed_div_mul!(u64); |
234 | impl_signed_int_into_signed!(u64); |
235 | |
236 | impl_unsigned_int_into_signed!(u32); |
237 | impl_signed_ops!(u32); |
238 | impl_signed_div_mul!(u32); |
239 | impl_signed_int_into_signed!(u32); |
240 | |
241 | impl_unsigned_int_into_signed!(usize); |
242 | impl_signed_ops!(usize); |
243 | impl_signed_div_mul!(usize); |
244 | impl_signed_int_into_signed!(usize); |
245 | |
246 | pub trait NoneSignedBuilder: FormattedValueNoneBuilder { |
247 | type Signed; |
248 | |
249 | // rustdoc-stripper-ignore-next |
250 | /// Returns the `None` value for `Self` as a `Signed<FullRange>` if such a value can be represented. |
251 | /// |
252 | /// See details in [`FormattedValueNoneBuilder::none`]. |
253 | /// |
254 | /// # Panics |
255 | /// |
256 | /// Panics if `Self` is `GenericFormattedValue` in which case, the `Format` must be known. |
257 | fn none_signed() -> Self::Signed; |
258 | |
259 | // rustdoc-stripper-ignore-next |
260 | /// Returns the `None` value for `Self` as a `Signed<FullRange>`, if such a value can be represented. |
261 | /// |
262 | /// See details in [`FormattedValueNoneBuilder::none_for_format`]. |
263 | /// |
264 | /// # Panics |
265 | /// |
266 | /// Panics if `None` can't be represented by `Self` for `format` or by the requested |
267 | /// `GenericFormattedValue` variant. |
268 | fn none_signed_for_format(format: Format) -> Self::Signed; |
269 | } |
270 | |
271 | impl<T> NoneSignedBuilder for T |
272 | where |
273 | T: UnsignedIntoSigned + FormattedValueNoneBuilder, |
274 | { |
275 | type Signed = <T as UnsignedIntoSigned>::Signed; |
276 | |
277 | #[inline ] |
278 | fn none_signed() -> Self::Signed { |
279 | Self::none().into_positive() |
280 | } |
281 | |
282 | #[inline ] |
283 | fn none_signed_for_format(format: Format) -> Self::Signed { |
284 | skip_assert_initialized!(); |
285 | Self::none_for_format(format).into_positive() |
286 | } |
287 | } |
288 | |