gstreamer/format/
specific.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use glib::translate::{FromGlib, GlibNoneError, IntoGlib, OptionIntoGlib, TryFromGlib};
4
5use super::{
6    Format, FormattedValue, FormattedValueError, FormattedValueFullRange, FormattedValueIntrinsic,
7    FormattedValueNoneBuilder, GenericFormattedValue,
8};
9use crate::ffi;
10
11pub trait SpecificFormattedValue: FormattedValue {}
12
13pub trait SpecificFormattedValueFullRange: FormattedValueFullRange {}
14
15// rustdoc-stripper-ignore-next
16/// A trait implemented on the intrinsic type of a `SpecificFormattedValue`.
17///
18/// # Examples
19///
20/// - `Undefined` is the intrinsic type for `Undefined`.
21/// - `Bytes` is the intrinsic type for `Option<Bytes>`.
22pub trait SpecificFormattedValueIntrinsic: TryFromGlib<i64> + FormattedValueIntrinsic {}
23
24// rustdoc-stripper-ignore-next
25/// A Buffer quantity
26///
27/// Some functions enforce format specific quantities. This type can be used when
28/// Buffer counts are expected. It comes with functions to perform computations without the
29/// need to retrieve the inner integer.
30///
31/// # Examples
32///
33/// ```rust
34/// # use gstreamer::{prelude::*, format::Buffers};
35/// // Regular constructors (can be used in `const` contexts)
36/// const FORTY_TWO_BUFFERS: Buffers = Buffers::from_u64(42);
37/// let two_buffers = Buffers::from_u64(2);
38///
39/// // All four arithmetic operations
40/// let limit = (FORTY_TWO_BUFFERS + two_buffers) * 2 / 3;
41///
42/// // Comparisons
43/// if limit > Buffers::ZERO {
44///     println!("Greater");
45/// }
46/// ```
47///
48/// See [the documentation of the `format` module] for more examples.
49///
50/// [the documentation of the `format` module]: ./index.html
51#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Debug, Default)]
52pub struct Buffers(u64);
53impl Buffers {
54    #[doc(alias = "GST_BUFFER_OFFSET_NONE")]
55    pub const OFFSET_NONE: u64 = ffi::GST_BUFFER_OFFSET_NONE;
56    pub const MAX: Self = Self(Self::OFFSET_NONE - 1);
57}
58
59impl Buffers {
60    // rustdoc-stripper-ignore-next
61    /// Builds a new `Buffers` formatted value with the provided buffers count.
62    ///
63    /// # Panics
64    ///
65    /// Panics if the provided count equals `u64::MAX`,
66    /// which is reserved for `None` in C.
67    #[track_caller]
68    #[inline]
69    pub const fn from_u64(buffers: u64) -> Self {
70        if buffers == ffi::GST_BUFFER_OFFSET_NONE {
71            panic!("`Buffers` value out of range");
72        }
73
74        Buffers(buffers)
75    }
76
77    // rustdoc-stripper-ignore-next
78    /// Builds a new `Buffers` formatted value with the provided buffers count.
79    ///
80    /// # Panics
81    ///
82    /// Panics if the provided count equals `u64::MAX`,
83    /// which is reserved for `None` in C.
84    #[track_caller]
85    #[inline]
86    pub fn from_usize(buffers: usize) -> Self {
87        Buffers::from_u64(buffers.try_into().unwrap())
88    }
89}
90
91impl_common_ops_for_newtype_uint!(Buffers, u64);
92impl_signed_div_mul!(Buffers, u64);
93impl_signed_int_into_signed!(Buffers, u64);
94impl_format_value_traits!(Buffers, Buffers, Buffers, u64);
95option_glib_newtype_from_to!(Buffers, Buffers::OFFSET_NONE);
96glib_newtype_display!(Buffers, DisplayableOptionBuffers, Format::Buffers);
97
98impl TryFrom<Buffers> for usize {
99    type Error = std::num::TryFromIntError;
100
101    fn try_from(value: Buffers) -> Result<Self, Self::Error> {
102        value.0.try_into()
103    }
104}
105
106// FIXME `functions in traits cannot be const` (rustc 1.64.0)
107// rustdoc-stripper-ignore-next
108/// `Buffers` formatted value constructor trait.
109pub trait BuffersFormatConstructor {
110    // rustdoc-stripper-ignore-next
111    /// Builds a `Buffers` formatted value from `self`.
112    fn buffers(self) -> Buffers;
113}
114
115impl BuffersFormatConstructor for u64 {
116    #[track_caller]
117    #[inline]
118    fn buffers(self) -> Buffers {
119        Buffers::from_u64(self)
120    }
121}
122
123// rustdoc-stripper-ignore-next
124/// A Byte quantity
125///
126/// Some functions enforce format specific quantities. This type can be used when
127/// Bytes are expected. It comes with functions to perform computations without the
128/// need to retrieve the inner integer.
129///
130/// # Examples
131///
132/// ```rust
133/// # use gstreamer::{prelude::*, format::Bytes};
134/// // Regular constructors (can be used in `const` contexts)
135/// const FORTY_TWO_BYTES: Bytes = Bytes::from_bytes(42);
136/// const TWO_K: Bytes = Bytes::from_kibibytes(2);
137/// let three_m = Bytes::from_mebibytes(3);
138/// let four_g = Bytes::from_gibibytes(4);
139///
140/// // Convenience constructors (not `const`)
141/// let forty_two_bytes = 42.bytes();
142/// let two_k = 2.kibibytes();
143/// let three_m = 3.mebibytes();
144/// let four_g = 4.gibibytes();
145///
146/// // All four arithmetic operations
147/// let limit = (2.kibibytes() + 512.bytes()) * 2 / 3;
148///
149/// // Comparisons
150/// if limit > Bytes::KiB {
151///     println!("Greater");
152/// }
153/// ```
154///
155/// See [the documentation of the `format` module] for more examples.
156///
157/// [the documentation of the `format` module]: ./index.html
158#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Debug, Default)]
159pub struct Bytes(u64);
160impl Bytes {
161    #[allow(non_upper_case_globals)]
162    // rustdoc-stripper-ignore-next
163    /// 1 kibibyte (1024).
164    #[allow(non_upper_case_globals)]
165    pub const KiB: Self = Self(1024);
166    // rustdoc-stripper-ignore-next
167    /// 1 mebibyte (1024 * 1024).
168    #[allow(non_upper_case_globals)]
169    pub const MiB: Self = Self(1024 * 1024);
170    // rustdoc-stripper-ignore-next
171    /// 1 gibibyte (1024 * 1024 * 1024).
172    #[allow(non_upper_case_globals)]
173    pub const GiB: Self = Self(1024 * 1024 * 1024);
174    pub const MAX: Self = Self(u64::MAX - 1);
175}
176
177impl Bytes {
178    // rustdoc-stripper-ignore-next
179    /// Builds a new `Bytes` formatted value with the provided bytes count.
180    ///
181    /// # Panics
182    ///
183    /// Panics if the provided count equals `u64::MAX`,
184    /// which is reserved for `None` in C.
185    #[track_caller]
186    #[inline]
187    pub const fn from_bytes(bytes: u64) -> Self {
188        Bytes::from_u64(bytes)
189    }
190
191    // rustdoc-stripper-ignore-next
192    /// Builds a new `Bytes` formatted value with the provided kibibytes (1024) count.
193    ///
194    /// # Panics
195    ///
196    /// Panics if the resulting count equals `u64::MAX`,
197    /// which is reserved for `None` in C.
198    #[track_caller]
199    #[inline]
200    pub const fn from_kibibytes(kibibytes: u64) -> Self {
201        Bytes::from_u64(kibibytes * 1024)
202    }
203
204    // rustdoc-stripper-ignore-next
205    /// Builds a new `Bytes` formatted value with the provided mebibytes (1024 * 1024) count.
206    ///
207    /// # Panics
208    ///
209    /// Panics if the resulting count equals `u64::MAX`,
210    /// which is reserved for `None` in C.
211    #[track_caller]
212    #[inline]
213    pub const fn from_mebibytes(mebibytes: u64) -> Self {
214        Bytes::from_u64(mebibytes * 1024 * 1024)
215    }
216
217    // rustdoc-stripper-ignore-next
218    /// Builds a new `Bytes` formatted value with the provided gibibytes (1024 * 1024 * 1024) count.
219    ///
220    /// # Panics
221    ///
222    /// Panics if the resulting count equals `u64::MAX`,
223    /// which is reserved for `None` in C.
224    #[track_caller]
225    #[inline]
226    pub const fn from_gibibytes(gibibytes: u64) -> Self {
227        Bytes::from_u64(gibibytes * 1024 * 1024 * 1024)
228    }
229
230    // rustdoc-stripper-ignore-next
231    /// Builds a new `Bytes` formatted value with the provided bytes count.
232    ///
233    /// # Panics
234    ///
235    /// Panics if the provided count equals `u64::MAX`,
236    /// which is reserved for `None` in C.
237    #[track_caller]
238    #[inline]
239    pub const fn from_u64(bytes: u64) -> Self {
240        if bytes == u64::MAX {
241            panic!("`Bytes` value out of range");
242        }
243
244        Bytes(bytes)
245    }
246
247    // rustdoc-stripper-ignore-next
248    /// Builds a new `Bytes` formatted value with the provided bytes count.
249    ///
250    /// # Panics
251    ///
252    /// Panics if the provided count equals `u64::MAX`,
253    /// which is reserved for `None` in C.
254    #[track_caller]
255    #[inline]
256    pub fn from_usize(bytes: usize) -> Self {
257        // FIXME can't use `try_into` in `const` (rustc 1.64.0)
258        Bytes::from_u64(bytes.try_into().unwrap())
259    }
260}
261
262impl_common_ops_for_newtype_uint!(Bytes, u64);
263impl_signed_div_mul!(Bytes, u64);
264impl_signed_int_into_signed!(Bytes, u64);
265impl_format_value_traits!(Bytes, Bytes, Bytes, u64);
266option_glib_newtype_from_to!(Bytes, u64::MAX);
267glib_newtype_display!(Bytes, DisplayableOptionBytes, Format::Bytes);
268
269impl TryFrom<Bytes> for usize {
270    type Error = std::num::TryFromIntError;
271
272    fn try_from(value: Bytes) -> Result<Self, Self::Error> {
273        value.0.try_into()
274    }
275}
276
277// FIXME `functions in traits cannot be const` (rustc 1.64.0)
278// rustdoc-stripper-ignore-next
279/// `Bytes` formatted value constructor trait.
280///
281/// These constructors use the [unambiguous conventions] for byte units.
282///
283/// [unambiguous conventions]: https://en.wikipedia.org/wiki/Byte#Multiple-byte_units
284pub trait BytesFormatConstructor {
285    // rustdoc-stripper-ignore-next
286    /// Builds a `Bytes` formatted value from `self`.
287    fn bytes(self) -> Bytes;
288
289    // rustdoc-stripper-ignore-next
290    /// Builds a `Bytes` formatted value from `self` interpreted as kibibytes (1024).
291    fn kibibytes(self) -> Bytes;
292
293    // rustdoc-stripper-ignore-next
294    /// Builds a `Bytes` formatted value from `self` interpreted as mebibytes (1024²).
295    fn mebibytes(self) -> Bytes;
296
297    // rustdoc-stripper-ignore-next
298    /// Builds a `Bytes` formatted value from `self` interpreted as gibibytes (1024³).
299    fn gibibytes(self) -> Bytes;
300}
301
302impl BytesFormatConstructor for u64 {
303    #[track_caller]
304    #[inline]
305    fn bytes(self) -> Bytes {
306        Bytes::from_u64(self)
307    }
308
309    #[track_caller]
310    #[inline]
311    fn kibibytes(self) -> Bytes {
312        Bytes::from_u64(self * 1024)
313    }
314
315    #[track_caller]
316    #[inline]
317    fn mebibytes(self) -> Bytes {
318        Bytes::from_u64(self * 1024 * 1024)
319    }
320
321    #[track_caller]
322    #[inline]
323    fn gibibytes(self) -> Bytes {
324        Bytes::from_u64(self * 1024 * 1024 * 1024)
325    }
326}
327
328// rustdoc-stripper-ignore-next
329/// A unit-less quantity
330///
331/// Some functions enforce format specific quantities. This type can be used when
332/// a `Default` format is expected. It comes with functions to perform computations without the
333/// need to retrieve the inner integer.
334///
335/// # Examples
336///
337/// ```rust
338/// # use gstreamer::{prelude::*, format::Default};
339/// // Regular constructors (can be used in `const` contexts)
340/// const FORTY_TWO: Default = Default::from_u64(42);
341/// let two = Default::from_u64(2);
342///
343/// // All four arithmetic operations
344/// let limit = (FORTY_TWO + two) * 2 / 3;
345///
346/// // Comparisons
347/// if limit > Default::ZERO {
348///     println!("Greater");
349/// }
350/// ```
351///
352/// See [the documentation of the `format` module] for more examples.
353///
354/// [the documentation of the `format` module]: ./index.html
355#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Debug, Default)]
356pub struct Default(u64);
357impl Default {
358    pub const MAX: Self = Self(u64::MAX - 1);
359}
360
361impl Default {
362    // rustdoc-stripper-ignore-next
363    /// Builds a new `Default` formatted value with the provided quantity.
364    ///
365    /// # Panics
366    ///
367    /// Panics if the provided quantity equals `u64::MAX`,
368    /// which is reserved for `None` in C.
369    #[track_caller]
370    #[inline]
371    pub const fn from_u64(quantity: u64) -> Self {
372        if quantity == u64::MAX {
373            panic!("`Default` value out of range");
374        }
375
376        Default(quantity)
377    }
378
379    // rustdoc-stripper-ignore-next
380    /// Builds a new `Default` formatted value with the provided quantity.
381    ///
382    /// # Panics
383    ///
384    /// Panics if the provided quantity equals `u64::MAX`,
385    /// which is reserved for `None` in C.
386    #[track_caller]
387    #[inline]
388    pub fn from_usize(quantity: usize) -> Self {
389        // FIXME can't use `try_into` in `const` (rustc 1.64.0)
390        Default::from_u64(quantity.try_into().unwrap())
391    }
392}
393
394impl_common_ops_for_newtype_uint!(Default, u64);
395impl_signed_div_mul!(Default, u64);
396impl_signed_int_into_signed!(Default, u64);
397impl_format_value_traits!(Default, Default, Default, u64);
398option_glib_newtype_from_to!(Default, u64::MAX);
399glib_newtype_display!(Default, DisplayableOptionDefault, Format::Default);
400
401impl TryFrom<Default> for usize {
402    type Error = std::num::TryFromIntError;
403
404    fn try_from(value: Default) -> Result<Self, Self::Error> {
405        value.0.try_into()
406    }
407}
408
409// FIXME `functions in traits cannot be const` (rustc 1.64.0)
410// rustdoc-stripper-ignore-next
411/// `Default` formatted value constructor trait.
412pub trait DefaultFormatConstructor {
413    // rustdoc-stripper-ignore-next
414    /// Builds a `Default` formatted value from `self`.
415    fn default_format(self) -> Default;
416}
417
418impl DefaultFormatConstructor for u64 {
419    #[track_caller]
420    #[inline]
421    fn default_format(self) -> Default {
422        Default::from_u64(self)
423    }
424}
425
426pub type Time = super::ClockTime;
427
428// rustdoc-stripper-ignore-next
429/// A Percent quantity
430///
431/// Some functions enforce format specific quantities. This type can be used when
432/// a Percent is expected. It comes with functions to perform computations without the
433/// need to retrieve the inner integer.
434///
435/// # Examples
436///
437/// ```rust
438/// # use gstreamer::{prelude::*, format::Percent};
439/// // Regular constructors (can be used in `const` contexts)
440/// const FORTY_TWO_PERCENT: Percent = Percent::from_percent(42);
441/// const TWO_PPM: Percent = Percent::from_ppm(2);
442/// let half = Percent::from_ratio(0.5);
443///
444/// // All four arithmetic operations
445/// let limit = (FORTY_TWO_PERCENT + TWO_PPM) * 2 / 3;
446///
447/// // Comparisons
448/// if limit > half {
449///     println!("Greater");
450/// }
451/// ```
452///
453/// See [the documentation of the `format` module] for more examples.
454///
455/// [the documentation of the `format` module]: ./index.html
456#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Debug, Default)]
457pub struct Percent(u32);
458impl Percent {
459    #[doc(alias = "GST_FORMAT_PERCENT_MAX")]
460    pub const MAX: Self = Self(ffi::GST_FORMAT_PERCENT_MAX as u32);
461    #[doc(alias = "GST_FORMAT_PERCENT_SCALE")]
462    pub const SCALE: Self = Self(ffi::GST_FORMAT_PERCENT_SCALE as u32);
463
464    // rustdoc-stripper-ignore-next
465    /// Builds a new `Percent` with the provided percent value.
466    ///
467    /// # Panics
468    ///
469    /// Panics if the provided value is larger than 100.
470    #[track_caller]
471    #[inline]
472    pub const fn from_percent(percent: u32) -> Self {
473        if percent > 100 {
474            panic!("`Percent` value out of range");
475        }
476
477        Percent(ffi::GST_FORMAT_PERCENT_SCALE as u32 * percent)
478    }
479
480    // rustdoc-stripper-ignore-next
481    /// Builds a new `Percent` with the provided parts per million value.
482    ///
483    /// # Panics
484    ///
485    /// Panics if the provided value is larger than [`Self::MAX`].
486    #[track_caller]
487    #[inline]
488    pub const fn from_ppm(ppm: u32) -> Self {
489        if ppm > ffi::GST_FORMAT_PERCENT_MAX as u32 {
490            panic!("`Percent` ppm value out of range");
491        }
492
493        Percent(ppm)
494    }
495
496    // rustdoc-stripper-ignore-next
497    /// Builds a new `Percent` with the provided ratio.
498    ///
499    /// # Panics
500    ///
501    /// Panics if the provided radio is out of the range [0.0, 1.0].
502    #[track_caller]
503    #[inline]
504    pub fn from_ratio(ratio: f32) -> Self {
505        // FIXME floating point arithmetic is not allowed in constant functions (rustc 1.64.0)
506        Percent::try_from(ratio).expect("`Percent` ratio out of range")
507    }
508
509    // rustdoc-stripper-ignore-next
510    /// The percent value in the range [0, 100].
511    #[track_caller]
512    #[inline]
513    pub fn percent(&self) -> u32 {
514        self.0 / ffi::GST_FORMAT_PERCENT_SCALE as u32
515    }
516
517    // rustdoc-stripper-ignore-next
518    /// The per million value in the range [0, 1_000_000].
519    #[track_caller]
520    #[inline]
521    pub fn ppm(&self) -> u32 {
522        self.0
523    }
524
525    // rustdoc-stripper-ignore-next
526    /// The ratio value in the range [0.0, 1.0].
527    #[track_caller]
528    #[inline]
529    pub fn ratio(&self) -> f32 {
530        self.0 as f32 / ffi::GST_FORMAT_PERCENT_MAX as f32
531    }
532}
533
534impl_common_ops_for_newtype_uint!(Percent, u32, one: ffi::GST_FORMAT_PERCENT_SCALE as u32);
535impl_signed_div_mul!(Percent, u32);
536impl_signed_int_into_signed!(Percent, u32);
537
538impl FormattedValue for Option<Percent> {
539    type FullRange = Option<Percent>;
540
541    #[inline]
542    fn default_format() -> Format {
543        Format::Percent
544    }
545
546    #[inline]
547    fn format(&self) -> Format {
548        Format::Percent
549    }
550
551    #[inline]
552    fn is_some(&self) -> bool {
553        Option::is_some(self)
554    }
555
556    #[inline]
557    unsafe fn into_raw_value(self) -> i64 {
558        self.map_or(-1, |v| v.0 as i64)
559    }
560}
561
562impl FormattedValueFullRange for Option<Percent> {
563    #[inline]
564    unsafe fn from_raw(format: Format, value: i64) -> Self {
565        debug_assert_eq!(format, Format::Percent);
566        Percent::try_from_glib(value).ok()
567    }
568}
569
570impl From<Option<Percent>> for GenericFormattedValue {
571    #[inline]
572    fn from(v: Option<Percent>) -> Self {
573        skip_assert_initialized!();
574        GenericFormattedValue::Percent(v)
575    }
576}
577
578impl From<Percent> for GenericFormattedValue {
579    #[inline]
580    fn from(v: Percent) -> Self {
581        skip_assert_initialized!();
582        GenericFormattedValue::Percent(Some(v))
583    }
584}
585
586impl FormattedValue for Percent {
587    type FullRange = Option<Percent>;
588
589    #[inline]
590    fn default_format() -> Format {
591        Format::Percent
592    }
593
594    #[inline]
595    fn format(&self) -> Format {
596        Format::Percent
597    }
598
599    #[inline]
600    fn is_some(&self) -> bool {
601        true
602    }
603
604    #[inline]
605    unsafe fn into_raw_value(self) -> i64 {
606        self.0 as i64
607    }
608}
609
610impl TryFrom<u64> for Percent {
611    type Error = GlibNoneError;
612
613    #[inline]
614    fn try_from(v: u64) -> Result<Percent, GlibNoneError> {
615        skip_assert_initialized!();
616        unsafe { Self::try_from_glib(v as i64) }
617    }
618}
619
620impl TryFromGlib<i64> for Percent {
621    type Error = GlibNoneError;
622    #[inline]
623    unsafe fn try_from_glib(value: i64) -> Result<Self, Self::Error> {
624        skip_assert_initialized!();
625        if value < 0 || value > ffi::GST_FORMAT_PERCENT_MAX {
626            Err(GlibNoneError)
627        } else {
628            Ok(Percent(value as u32))
629        }
630    }
631}
632
633impl TryFrom<u32> for Percent {
634    type Error = FormattedValueError;
635
636    #[inline]
637    fn try_from(value: u32) -> Result<Self, Self::Error> {
638        skip_assert_initialized!();
639        if value > ffi::GST_FORMAT_PERCENT_MAX as u32 {
640            Err(FormattedValueError(Format::Percent))
641        } else {
642            Ok(Percent(value))
643        }
644    }
645}
646
647impl TryFrom<GenericFormattedValue> for Option<Percent> {
648    type Error = FormattedValueError;
649
650    #[inline]
651    fn try_from(v: GenericFormattedValue) -> Result<Option<Percent>, Self::Error> {
652        skip_assert_initialized!();
653        if let GenericFormattedValue::Percent(v) = v {
654            Ok(v)
655        } else {
656            Err(FormattedValueError(v.format()))
657        }
658    }
659}
660
661impl FormattedValueIntrinsic for Percent {}
662impl SpecificFormattedValue for Option<Percent> {}
663impl SpecificFormattedValueFullRange for Option<Percent> {}
664impl SpecificFormattedValueIntrinsic for Percent {}
665impl FormattedValueNoneBuilder for Option<Percent> {
666    #[inline]
667    fn none() -> Option<Percent> {
668        None
669    }
670}
671
672#[derive(Clone, Copy, Debug, PartialEq, Eq, thiserror::Error)]
673#[error("value out of range")]
674pub struct TryPercentFromFloatError(());
675
676impl TryFrom<f64> for Percent {
677    type Error = TryPercentFromFloatError;
678
679    #[inline]
680    fn try_from(v: f64) -> Result<Self, Self::Error> {
681        skip_assert_initialized!();
682        if v < 0.0 || v > 1.0 {
683            Err(TryPercentFromFloatError(()))
684        } else {
685            Ok(Percent(
686                (v * ffi::GST_FORMAT_PERCENT_MAX as f64).round() as u32
687            ))
688        }
689    }
690}
691
692impl TryFrom<f32> for Percent {
693    type Error = TryPercentFromFloatError;
694
695    #[inline]
696    fn try_from(v: f32) -> Result<Self, Self::Error> {
697        skip_assert_initialized!();
698        if v < 0.0 || v > 1.0 {
699            Err(TryPercentFromFloatError(()))
700        } else {
701            Ok(Percent(
702                (v * ffi::GST_FORMAT_PERCENT_MAX as f32).round() as u32
703            ))
704        }
705    }
706}
707
708// FIXME `functions in traits cannot be const` (rustc 1.64.0)
709// rustdoc-stripper-ignore-next
710/// `Percent` formatted value from integer constructor trait.
711pub trait PercentFormatIntegerConstructor {
712    // rustdoc-stripper-ignore-next
713    /// Builds a `Percent` formatted value from `self` interpreted as a percent.
714    fn percent(self) -> Percent;
715
716    // rustdoc-stripper-ignore-next
717    /// Builds a `Percent` formatted value from `self` interpreted as parts per million.
718    fn ppm(self) -> Percent;
719}
720
721impl PercentFormatIntegerConstructor for u32 {
722    #[track_caller]
723    #[inline]
724    fn percent(self) -> Percent {
725        Percent::from_percent(self)
726    }
727
728    #[track_caller]
729    #[inline]
730    fn ppm(self) -> Percent {
731        Percent::from_ppm(self)
732    }
733}
734
735// FIXME `functions in traits cannot be const` (rustc 1.64.0)
736// rustdoc-stripper-ignore-next
737/// `Percent` formatted value from float constructor trait.
738pub trait PercentFormatFloatConstructor {
739    // rustdoc-stripper-ignore-next
740    /// Builds a `Percent` formatted value from `self` interpreted as a ratio.
741    fn percent_ratio(self) -> Percent;
742}
743
744impl PercentFormatFloatConstructor for f32 {
745    #[track_caller]
746    #[inline]
747    fn percent_ratio(self) -> Percent {
748        Percent::try_from(self).unwrap()
749    }
750}
751
752impl std::fmt::Display for Percent {
753    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
754        std::fmt::Display::fmt(&(self.0 as f32 / (*Percent::SCALE) as f32), f)?;
755        f.write_str(" %")
756    }
757}
758
759impl crate::utils::Displayable for Percent {
760    type DisplayImpl = Self;
761    fn display(self) -> Self {
762        self
763    }
764}
765pub struct DisplayableOptionPercent(Option<Percent>);
766
767impl std::fmt::Display for DisplayableOptionPercent {
768    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
769        if let Some(val) = self.0.as_ref() {
770            std::fmt::Display::fmt(val, f)
771        } else {
772            f.write_str("undef. %")
773        }
774    }
775}
776
777impl crate::utils::Displayable for Option<Percent> {
778    type DisplayImpl = DisplayableOptionPercent;
779    fn display(self) -> Self::DisplayImpl {
780        DisplayableOptionPercent(self)
781    }
782}