1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use std::fmt;
4
5use glib::translate::{FromGlib, GlibNoneError, IntoGlib, OptionIntoGlib, TryFromGlib};
6
7use super::{
8 Buffers, Bytes, ClockTime, CompatibleFormattedValue, Default, Format, FormattedValue,
9 FormattedValueError, FormattedValueFullRange, FormattedValueIntrinsic,
10 FormattedValueNoneBuilder, Percent, Signed, SignedIntrinsic, Undefined, UnsignedIntoSigned,
11};
12use crate::utils::Displayable;
13
14#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Debug, Default)]
15pub struct Other(u64);
16impl Other {
17 pub const MAX: Self = Self(u64::MAX - 1);
18}
19
20impl Other {
21 // rustdoc-stripper-ignore-next
22 /// Builds a new `Other` value with the provided quantity.
23 ///
24 /// # Panics
25 ///
26 /// Panics if the provided quantity equals `u64::MAX`,
27 /// which is reserved for `None` in C.
28 #[track_caller]
29 #[inline]
30 pub const fn from_u64(quantity: u64) -> Self {
31 if quantity == u64::MAX {
32 panic!("`Other` value out of range");
33 }
34
35 Other(quantity)
36 }
37
38 // rustdoc-stripper-ignore-next
39 /// Builds a new `Other` value with the provided quantity.
40 ///
41 /// # Panics
42 ///
43 /// Panics if the provided quantity equals `u64::MAX`,
44 /// which is reserved for `None` in C.
45 #[track_caller]
46 #[inline]
47 pub fn from_usize(quantity: usize) -> Self {
48 // FIXME can't use `try_into` in `const` (rustc 1.64.0)
49 Other::from_u64(quantity.try_into().unwrap())
50 }
51}
52
53impl_common_ops_for_newtype_uint!(Other, u64);
54impl_signed_div_mul!(Other, u64);
55impl_signed_int_into_signed!(Other, u64);
56option_glib_newtype_from_to!(Other, u64::MAX);
57glib_newtype_display!(Other, DisplayableOptionOther);
58
59impl TryFrom<u64> for Other {
60 type Error = GlibNoneError;
61 #[inline]
62 fn try_from(val: u64) -> Result<Self, GlibNoneError> {
63 skip_assert_initialized!();
64 unsafe { Self::try_from_glib(val) }
65 }
66}
67
68impl TryFromGlib<i64> for Other {
69 type Error = GlibNoneError;
70 #[inline]
71 unsafe fn try_from_glib(val: i64) -> Result<Self, GlibNoneError> {
72 skip_assert_initialized!();
73 Self::try_from_glib(val as u64)
74 }
75}
76
77impl TryFrom<Other> for usize {
78 type Error = std::num::TryFromIntError;
79
80 fn try_from(value: Other) -> Result<Self, Self::Error> {
81 value.0.try_into()
82 }
83}
84
85// FIXME `functions in traits cannot be const` (rustc 1.64.0)
86// rustdoc-stripper-ignore-next
87/// `Other` formatted value constructor trait.
88pub trait OtherFormatConstructor {
89 // rustdoc-stripper-ignore-next
90 /// Builds an `Other` formatted value from `self`.
91 fn other_format(self) -> Other;
92}
93
94impl OtherFormatConstructor for u64 {
95 #[track_caller]
96 #[inline]
97 fn other_format(self) -> Other {
98 Other::from_u64(self)
99 }
100}
101
102#[derive(PartialEq, Eq, Hash, Clone, Copy, Debug)]
103#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
104pub enum GenericFormattedValue {
105 Undefined(Undefined),
106 Default(Option<Default>),
107 Bytes(Option<Bytes>),
108 Time(Option<ClockTime>),
109 Buffers(Option<Buffers>),
110 Percent(Option<Percent>),
111 Other(Format, Option<Other>),
112}
113
114impl fmt::Display for GenericFormattedValue {
115 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
116 match self {
117 Self::Undefined(val: &Undefined) => val.fmt(f),
118 Self::Default(val: &Option) => val.display().fmt(f),
119 Self::Bytes(val: &Option) => val.display().fmt(f),
120 Self::Time(val: &Option) => val.display().fmt(f),
121 Self::Buffers(val: &Option) => val.display().fmt(f),
122 Self::Percent(val: &Option) => val.display().fmt(f),
123 Self::Other(format: &Format, val: &Option) => {
124 val.display().fmt(f)?;
125 fmt::Write::write_char(self:f, c:' ')?;
126 fmt::Display::fmt(&format, f)
127 }
128 }
129 }
130}
131
132impl Displayable for GenericFormattedValue {
133 type DisplayImpl = Self;
134 fn display(self) -> Self {
135 self
136 }
137}
138
139impl GenericFormattedValue {
140 #[inline]
141 pub fn new(format: Format, value: i64) -> Self {
142 skip_assert_initialized!();
143 match format {
144 Format::Undefined => Self::Undefined(value.into()),
145 Format::Default => Self::Default(unsafe { FromGlib::from_glib(value) }),
146 Format::Bytes => Self::Bytes(unsafe { FromGlib::from_glib(value) }),
147 Format::Time => Self::Time(unsafe { FromGlib::from_glib(value) }),
148 Format::Buffers => Self::Buffers(unsafe { FromGlib::from_glib(value) }),
149 Format::Percent => Self::Percent(unsafe { FromGlib::from_glib(value) }),
150 Format::__Unknown(_) => Self::Other(format, unsafe { FromGlib::from_glib(value) }),
151 }
152 }
153
154 #[doc(alias = "get_format")]
155 #[inline]
156 pub fn format(&self) -> Format {
157 match *self {
158 Self::Undefined(_) => Format::Undefined,
159 Self::Default(_) => Format::Default,
160 Self::Bytes(_) => Format::Bytes,
161 Self::Time(_) => Format::Time,
162 Self::Buffers(_) => Format::Buffers,
163 Self::Percent(_) => Format::Percent,
164 Self::Other(f, _) => f,
165 }
166 }
167
168 #[doc(alias = "get_value")]
169 #[inline]
170 pub fn value(&self) -> i64 {
171 unsafe {
172 match *self {
173 Self::Undefined(v) => *v,
174 Self::Default(v) => v.into_raw_value(),
175 Self::Bytes(v) => v.into_raw_value(),
176 Self::Time(v) => v.into_raw_value(),
177 Self::Buffers(v) => v.into_raw_value(),
178 Self::Percent(v) => v.into_raw_value(),
179 Self::Other(_, v) => v.into_glib() as i64,
180 }
181 }
182 }
183}
184
185impl FormattedValue for GenericFormattedValue {
186 // The intrinsic value for `GenericFormattedValue` is also
187 // `GenericFormattedValue`. We can't dissociate the `Option`
188 // from the variants' inner type since they are not all `Option`s.
189 type FullRange = GenericFormattedValue;
190
191 #[inline]
192 fn default_format() -> Format {
193 Format::Undefined
194 }
195
196 #[inline]
197 fn format(&self) -> Format {
198 self.format()
199 }
200
201 #[inline]
202 fn is_some(&self) -> bool {
203 match self {
204 Self::Undefined(_) => true,
205 Self::Default(v) => v.is_some(),
206 Self::Bytes(v) => v.is_some(),
207 Self::Time(v) => v.is_some(),
208 Self::Buffers(v) => v.is_some(),
209 Self::Percent(v) => v.is_some(),
210 Self::Other(_, v) => v.is_some(),
211 }
212 }
213
214 #[inline]
215 unsafe fn into_raw_value(self) -> i64 {
216 self.value()
217 }
218}
219
220impl FormattedValueFullRange for GenericFormattedValue {
221 #[inline]
222 unsafe fn from_raw(format: Format, value: i64) -> Self {
223 GenericFormattedValue::new(format, value)
224 }
225}
226
227impl FormattedValueIntrinsic for GenericFormattedValue {}
228impl SignedIntrinsic for GenericFormattedValue {}
229
230impl FormattedValueNoneBuilder for GenericFormattedValue {
231 #[track_caller]
232 fn none() -> Self {
233 panic!(concat!(
234 "`GenericFormattedValue` can't build `None` without knowing",
235 "the target format. Use `GenericFormattedValue::none_for_format`",
236 ));
237 }
238
239 #[track_caller]
240 #[inline]
241 fn none_for_format(format: Format) -> Self {
242 skip_assert_initialized!();
243 match format {
244 Format::Undefined => panic!("`None` can't be represented by `Undefined`"),
245 Format::Default => Self::Default(None),
246 Format::Bytes => Self::Bytes(None),
247 Format::Time => Self::Time(None),
248 Format::Buffers => Self::Buffers(None),
249 Format::Percent => Self::Percent(None),
250 unknown: Format => Self::Other(unknown, Other::NONE),
251 }
252 }
253}
254
255impl UnsignedIntoSigned for GenericFormattedValue {
256 type Signed = GenericSignedFormattedValue;
257
258 #[track_caller]
259 #[inline]
260 fn into_positive(self) -> Self::Signed {
261 use Signed::Positive;
262 match self {
263 Self::Undefined(_) => {
264 unimplemented!("`GenericFormattedValue::Undefined` is already signed")
265 }
266 Self::Default(val) => Self::Signed::Default(val.map(Positive)),
267 Self::Bytes(val) => Self::Signed::Bytes(val.map(Positive)),
268 Self::Time(val) => Self::Signed::Time(val.map(Positive)),
269 Self::Buffers(val) => Self::Signed::Buffers(val.map(Positive)),
270 Self::Percent(val) => Self::Signed::Percent(val.map(Positive)),
271 Self::Other(format, val) => Self::Signed::Other(format, val.map(Positive)),
272 }
273 }
274
275 #[track_caller]
276 #[inline]
277 fn into_negative(self) -> Self::Signed {
278 use Signed::Negative;
279 match self {
280 Self::Undefined(_) => {
281 unimplemented!("`GenericFormattedValue::Undefined` is already signed")
282 }
283 Self::Default(val) => Self::Signed::Default(val.map(Negative)),
284 Self::Bytes(val) => Self::Signed::Bytes(val.map(Negative)),
285 Self::Time(val) => Self::Signed::Time(val.map(Negative)),
286 Self::Buffers(val) => Self::Signed::Buffers(val.map(Negative)),
287 Self::Percent(val) => Self::Signed::Percent(val.map(Negative)),
288 Self::Other(format, val) => Self::Signed::Other(format, val.map(Negative)),
289 }
290 }
291}
292
293impl CompatibleFormattedValue<GenericFormattedValue> for GenericFormattedValue {
294 type Original = Self;
295 #[inline]
296 fn try_into_checked(self, other: GenericFormattedValue) -> Result<Self, FormattedValueError> {
297 skip_assert_initialized!();
298 if self.format() == other.format() {
299 Ok(self)
300 } else {
301 Err(FormattedValueError(self.format()))
302 }
303 }
304
305 #[inline]
306 fn try_into_checked_explicit(
307 self,
308 format: Format,
309 ) -> Result<Self::Original, FormattedValueError> {
310 skip_assert_initialized!();
311 if self.format() == format {
312 Ok(self)
313 } else {
314 Err(FormattedValueError(self.format()))
315 }
316 }
317}
318
319#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
320#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
321pub enum GenericSignedFormattedValue {
322 Default(Option<Signed<Default>>),
323 Bytes(Option<Signed<Bytes>>),
324 Time(Option<Signed<ClockTime>>),
325 Buffers(Option<Signed<Buffers>>),
326 Percent(Option<Signed<Percent>>),
327 Other(Format, Option<Signed<Other>>),
328}
329
330impl GenericSignedFormattedValue {
331 #[doc(alias = "get_format")]
332 #[inline]
333 pub fn format(&self) -> Format {
334 match *self {
335 Self::Default(_) => Format::Default,
336 Self::Bytes(_) => Format::Bytes,
337 Self::Time(_) => Format::Time,
338 Self::Buffers(_) => Format::Buffers,
339 Self::Percent(_) => Format::Percent,
340 Self::Other(format, _) => format,
341 }
342 }
343
344 #[inline]
345 pub fn abs(self) -> GenericFormattedValue {
346 use GenericFormattedValue as Unsigned;
347 match self {
348 Self::Default(opt_signed) => Unsigned::Default(opt_signed.map(Signed::abs)),
349 Self::Bytes(opt_signed) => Unsigned::Bytes(opt_signed.map(Signed::abs)),
350 Self::Time(opt_signed) => Unsigned::Time(opt_signed.map(Signed::abs)),
351 Self::Buffers(opt_signed) => Unsigned::Buffers(opt_signed.map(Signed::abs)),
352 Self::Percent(opt_signed) => Unsigned::Percent(opt_signed.map(Signed::abs)),
353 Self::Other(format, opt_signed) => Unsigned::Other(format, opt_signed.map(Signed::abs)),
354 }
355 }
356
357 #[inline]
358 pub fn is_some(&self) -> bool {
359 match self {
360 Self::Default(v) => v.is_some(),
361 Self::Bytes(v) => v.is_some(),
362 Self::Time(v) => v.is_some(),
363 Self::Buffers(v) => v.is_some(),
364 Self::Percent(v) => v.is_some(),
365 Self::Other(_, v) => v.is_some(),
366 }
367 }
368
369 #[inline]
370 pub fn is_none(&self) -> bool {
371 !self.is_some()
372 }
373
374 #[track_caller]
375 #[inline]
376 pub fn none_for_format(format: Format) -> Self {
377 skip_assert_initialized!();
378 match format {
379 Format::Default => Self::Default(None),
380 Format::Bytes => Self::Bytes(None),
381 Format::Time => Self::Time(None),
382 Format::Buffers => Self::Buffers(None),
383 Format::Percent => Self::Percent(None),
384 Format::Undefined => {
385 panic!("`Undefined` is already signed, use `GenericFormattedValue`")
386 }
387 other => Self::Other(other, None),
388 }
389 }
390}
391
392macro_rules! impl_gsfv_fn_opt_ret(
393 ($fn:ident(self) -> Option<$ret_ty:ty>) => {
394 #[inline]
395 pub fn $fn(self) -> Option<$ret_ty> {
396 match self {
397 Self::Default(opt_signed) => opt_signed.map(|signed| signed.$fn()),
398 Self::Bytes(opt_signed) => opt_signed.map(|signed| signed.$fn()),
399 Self::Time(opt_signed) => opt_signed.map(|signed| signed.$fn()),
400 Self::Buffers(opt_signed) => opt_signed.map(|signed| signed.$fn()),
401 Self::Percent(opt_signed) => opt_signed.map(|signed| signed.$fn()),
402 Self::Other(_, opt_signed) => opt_signed.map(|signed| signed.$fn()),
403 }
404 }
405 };
406);
407
408impl GenericSignedFormattedValue {
409 impl_gsfv_fn_opt_ret!(is_positive(self) -> Option<bool>);
410 impl_gsfv_fn_opt_ret!(is_negative(self) -> Option<bool>);
411 impl_gsfv_fn_opt_ret!(signum(self) -> Option<i32>);
412}
413
414impl std::ops::Neg for GenericSignedFormattedValue {
415 type Output = Self;
416
417 #[inline]
418 fn neg(self) -> Self {
419 use std::ops::Neg;
420 match self {
421 Self::Default(opt_signed: Option>) => Self::Default(opt_signed.map(Neg::neg)),
422 Self::Bytes(opt_signed: Option>) => Self::Bytes(opt_signed.map(Neg::neg)),
423 Self::Time(opt_signed: Option>) => Self::Time(opt_signed.map(Neg::neg)),
424 Self::Buffers(opt_signed: Option>) => Self::Buffers(opt_signed.map(Neg::neg)),
425 Self::Percent(opt_signed: Option>) => Self::Percent(opt_signed.map(Neg::neg)),
426 Self::Other(format: Format, opt_signed: Option>) => Self::Other(format, opt_signed.map(Neg::neg)),
427 }
428 }
429}
430
431impl fmt::Display for GenericSignedFormattedValue {
432 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
433 match self {
434 Self::Default(opt_signed: &Option>) => opt_signed.display().fmt(f),
435 Self::Bytes(opt_signed: &Option>) => opt_signed.display().fmt(f),
436 Self::Time(opt_signed: &Option>) => opt_signed.display().fmt(f),
437 Self::Buffers(opt_signed: &Option>) => opt_signed.display().fmt(f),
438 Self::Percent(opt_signed: &Option>) => opt_signed.display().fmt(f),
439 Self::Other(format: &Format, opt_signed: &Option>) => {
440 opt_signed.display().fmt(f)?;
441 fmt::Write::write_char(self:f, c:' ')?;
442 fmt::Display::fmt(&format, f)
443 }
444 }
445 }
446}
447
448impl Displayable for GenericSignedFormattedValue {
449 type DisplayImpl = Self;
450
451 fn display(self) -> Self::DisplayImpl {
452 self
453 }
454}
455
456#[cfg(test)]
457mod tests {
458 use super::*;
459
460 #[test]
461 #[allow(clippy::eq_op, clippy::op_ref)]
462 fn other() {
463 // Check a few ops on `Other`, better coverage for
464 // the macro ops impl ensured as part of the `clock_time` module.
465
466 use opt_ops::prelude::*;
467
468 let other_none: Option<Other> = Other::try_from(u64::MAX).ok();
469 assert!(other_none.is_none());
470
471 let other_10 = Other::from_u64(10);
472 let other_20 = Other::from_usize(20);
473 let other_30 = 30.other_format();
474
475 assert_eq!(other_10 + other_20, other_30);
476 assert_eq!(other_30 - other_20, other_10);
477
478 assert!(other_10 < Other::MAX);
479
480 assert_eq!(Some(other_10).opt_add(other_20), Some(other_30));
481 }
482
483 #[test]
484 #[allow(clippy::eq_op, clippy::op_ref)]
485 fn generic_other() {
486 let gen_other_42: GenericFormattedValue =
487 GenericFormattedValue::new(Format::__Unknown(128), 42);
488 assert_eq!(
489 gen_other_42,
490 GenericFormattedValue::Other(Format::__Unknown(128), Other::try_from(42).ok())
491 );
492 assert_eq!(gen_other_42.format(), Format::__Unknown(128));
493 assert_eq!(gen_other_42.value(), 42);
494 assert!(gen_other_42.is_some());
495
496 let other_none: Option<Other> = Other::NONE;
497 assert!(other_none.is_none());
498
499 let gen_other_none: GenericFormattedValue =
500 GenericFormattedValue::none_for_format(Format::__Unknown(128));
501 assert!(gen_other_none.is_none());
502 assert_eq!(
503 gen_other_none,
504 GenericFormattedValue::Other(Format::__Unknown(128), None)
505 );
506 }
507
508 #[test]
509 #[allow(clippy::eq_op, clippy::op_ref)]
510 fn generic_signed_other() {
511 let gen_other_42: GenericFormattedValue =
512 GenericFormattedValue::new(Format::__Unknown(128), 42);
513
514 let p_gen_other_42 = gen_other_42.into_positive();
515 assert_eq!(
516 p_gen_other_42,
517 GenericSignedFormattedValue::Other(
518 Format::__Unknown(128),
519 Some(Signed::Positive(42.other_format())),
520 ),
521 );
522
523 let n_gen_other_42 = gen_other_42.into_negative();
524 assert_eq!(
525 n_gen_other_42,
526 GenericSignedFormattedValue::Other(
527 Format::__Unknown(128),
528 Some(Signed::Negative(42.other_format())),
529 ),
530 );
531 }
532}
533