Skip to main content

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        unsafe {
566            debug_assert_eq!(format, Format::Percent);
567            Percent::try_from_glib(value).ok()
568        }
569    }
570}
571
572impl From<Option<Percent>> for GenericFormattedValue {
573    #[inline]
574    fn from(v: Option<Percent>) -> Self {
575        skip_assert_initialized!();
576        GenericFormattedValue::Percent(v)
577    }
578}
579
580impl From<Percent> for GenericFormattedValue {
581    #[inline]
582    fn from(v: Percent) -> Self {
583        skip_assert_initialized!();
584        GenericFormattedValue::Percent(Some(v))
585    }
586}
587
588impl FormattedValue for Percent {
589    type FullRange = Option<Percent>;
590
591    #[inline]
592    fn default_format() -> Format {
593        Format::Percent
594    }
595
596    #[inline]
597    fn format(&self) -> Format {
598        Format::Percent
599    }
600
601    #[inline]
602    fn is_some(&self) -> bool {
603        true
604    }
605
606    #[inline]
607    unsafe fn into_raw_value(self) -> i64 {
608        self.0 as i64
609    }
610}
611
612impl TryFrom<u64> for Percent {
613    type Error = GlibNoneError;
614
615    #[inline]
616    fn try_from(v: u64) -> Result<Percent, GlibNoneError> {
617        skip_assert_initialized!();
618        unsafe { Self::try_from_glib(v as i64) }
619    }
620}
621
622impl TryFromGlib<i64> for Percent {
623    type Error = GlibNoneError;
624    #[inline]
625    unsafe fn try_from_glib(value: i64) -> Result<Self, Self::Error> {
626        skip_assert_initialized!();
627        if value < 0 || value > ffi::GST_FORMAT_PERCENT_MAX {
628            Err(GlibNoneError)
629        } else {
630            Ok(Percent(value as u32))
631        }
632    }
633}
634
635impl TryFrom<u32> for Percent {
636    type Error = FormattedValueError;
637
638    #[inline]
639    fn try_from(value: u32) -> Result<Self, Self::Error> {
640        skip_assert_initialized!();
641        if value > ffi::GST_FORMAT_PERCENT_MAX as u32 {
642            Err(FormattedValueError(Format::Percent))
643        } else {
644            Ok(Percent(value))
645        }
646    }
647}
648
649impl TryFrom<GenericFormattedValue> for Option<Percent> {
650    type Error = FormattedValueError;
651
652    #[inline]
653    fn try_from(v: GenericFormattedValue) -> Result<Option<Percent>, Self::Error> {
654        skip_assert_initialized!();
655        if let GenericFormattedValue::Percent(v) = v {
656            Ok(v)
657        } else {
658            Err(FormattedValueError(v.format()))
659        }
660    }
661}
662
663impl FormattedValueIntrinsic for Percent {}
664impl SpecificFormattedValue for Option<Percent> {}
665impl SpecificFormattedValueFullRange for Option<Percent> {}
666impl SpecificFormattedValueIntrinsic for Percent {}
667impl FormattedValueNoneBuilder for Option<Percent> {
668    #[inline]
669    fn none() -> Option<Percent> {
670        None
671    }
672}
673
674#[derive(Clone, Copy, Debug, PartialEq, Eq, thiserror::Error)]
675#[error("value out of range")]
676pub struct TryPercentFromFloatError(());
677
678impl TryFrom<f64> for Percent {
679    type Error = TryPercentFromFloatError;
680
681    #[inline]
682    fn try_from(v: f64) -> Result<Self, Self::Error> {
683        skip_assert_initialized!();
684        if v < 0.0 || v > 1.0 {
685            Err(TryPercentFromFloatError(()))
686        } else {
687            Ok(Percent(
688                (v * ffi::GST_FORMAT_PERCENT_MAX as f64).round() as u32
689            ))
690        }
691    }
692}
693
694impl TryFrom<f32> for Percent {
695    type Error = TryPercentFromFloatError;
696
697    #[inline]
698    fn try_from(v: f32) -> Result<Self, Self::Error> {
699        skip_assert_initialized!();
700        if v < 0.0 || v > 1.0 {
701            Err(TryPercentFromFloatError(()))
702        } else {
703            Ok(Percent(
704                (v * ffi::GST_FORMAT_PERCENT_MAX as f32).round() as u32
705            ))
706        }
707    }
708}
709
710// FIXME `functions in traits cannot be const` (rustc 1.64.0)
711// rustdoc-stripper-ignore-next
712/// `Percent` formatted value from integer constructor trait.
713pub trait PercentFormatIntegerConstructor {
714    // rustdoc-stripper-ignore-next
715    /// Builds a `Percent` formatted value from `self` interpreted as a percent.
716    fn percent(self) -> Percent;
717
718    // rustdoc-stripper-ignore-next
719    /// Builds a `Percent` formatted value from `self` interpreted as parts per million.
720    fn ppm(self) -> Percent;
721}
722
723impl PercentFormatIntegerConstructor for u32 {
724    #[track_caller]
725    #[inline]
726    fn percent(self) -> Percent {
727        Percent::from_percent(self)
728    }
729
730    #[track_caller]
731    #[inline]
732    fn ppm(self) -> Percent {
733        Percent::from_ppm(self)
734    }
735}
736
737// FIXME `functions in traits cannot be const` (rustc 1.64.0)
738// rustdoc-stripper-ignore-next
739/// `Percent` formatted value from float constructor trait.
740pub trait PercentFormatFloatConstructor {
741    // rustdoc-stripper-ignore-next
742    /// Builds a `Percent` formatted value from `self` interpreted as a ratio.
743    fn percent_ratio(self) -> Percent;
744}
745
746impl PercentFormatFloatConstructor for f32 {
747    #[track_caller]
748    #[inline]
749    fn percent_ratio(self) -> Percent {
750        Percent::try_from(self).unwrap()
751    }
752}
753
754impl std::fmt::Display for Percent {
755    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
756        std::fmt::Display::fmt(&(self.0 as f32 / (*Percent::SCALE) as f32), f)?;
757        f.write_str(" %")
758    }
759}
760
761impl crate::utils::Displayable for Percent {
762    type DisplayImpl = Self;
763    fn display(self) -> Self {
764        self
765    }
766}
767pub struct DisplayableOptionPercent(Option<Percent>);
768
769impl std::fmt::Display for DisplayableOptionPercent {
770    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
771        if let Some(val) = self.0.as_ref() {
772            std::fmt::Display::fmt(val, f)
773        } else {
774            f.write_str("undef. %")
775        }
776    }
777}
778
779impl crate::utils::Displayable for Option<Percent> {
780    type DisplayImpl = DisplayableOptionPercent;
781    fn display(self) -> Self::DisplayImpl {
782        DisplayableOptionPercent(self)
783    }
784}