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};
9
10pub trait SpecificFormattedValue: FormattedValue {}
11
12pub trait SpecificFormattedValueFullRange: FormattedValueFullRange {}
13
14// rustdoc-stripper-ignore-next
15/// A trait implemented on the intrinsic type of a `SpecificFormattedValue`.
16///
17/// # Examples
18///
19/// - `Undefined` is the intrinsic type for `Undefined`.
20/// - `Bytes` is the intrinsic type for `Option<Bytes>`.
21pub trait SpecificFormattedValueIntrinsic: TryFromGlib<i64> + FormattedValueIntrinsic {}
22
23#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Debug, Default)]
24pub struct Buffers(u64);
25impl Buffers {
26 #[doc(alias = "GST_BUFFER_OFFSET_NONE")]
27 pub const OFFSET_NONE: u64 = ffi::GST_BUFFER_OFFSET_NONE;
28 pub const MAX: Self = Self(Self::OFFSET_NONE - 1);
29}
30
31impl Buffers {
32 // rustdoc-stripper-ignore-next
33 /// Builds a new `Buffers` formatted value with the provided buffers count.
34 ///
35 /// # Panics
36 ///
37 /// Panics if the provided count equals `u64::MAX`,
38 /// which is reserved for `None` in C.
39 #[track_caller]
40 #[inline]
41 pub const fn from_u64(buffers: u64) -> Self {
42 if buffers == ffi::GST_BUFFER_OFFSET_NONE {
43 panic!("`Buffers` value out of range");
44 }
45
46 Buffers(buffers)
47 }
48
49 // rustdoc-stripper-ignore-next
50 /// Builds a new `Buffers` formatted value with the provided buffers count.
51 ///
52 /// # Panics
53 ///
54 /// Panics if the provided count equals `u64::MAX`,
55 /// which is reserved for `None` in C.
56 #[track_caller]
57 #[inline]
58 pub fn from_usize(buffers: usize) -> Self {
59 Buffers::from_u64(buffers.try_into().unwrap())
60 }
61}
62
63impl_common_ops_for_newtype_uint!(Buffers, u64);
64impl_signed_div_mul!(Buffers, u64);
65impl_signed_int_into_signed!(Buffers, u64);
66impl_format_value_traits!(Buffers, Buffers, Buffers, u64);
67option_glib_newtype_from_to!(Buffers, Buffers::OFFSET_NONE);
68glib_newtype_display!(Buffers, DisplayableOptionBuffers, Format::Buffers);
69
70impl TryFrom<Buffers> for usize {
71 type Error = std::num::TryFromIntError;
72
73 fn try_from(value: Buffers) -> Result<Self, Self::Error> {
74 value.0.try_into()
75 }
76}
77
78// FIXME `functions in traits cannot be const` (rustc 1.64.0)
79// rustdoc-stripper-ignore-next
80/// `Buffers` formatted value constructor trait.
81pub trait BuffersFormatConstructor {
82 // rustdoc-stripper-ignore-next
83 /// Builds a `Buffers` formatted value from `self`.
84 fn buffers(self) -> Buffers;
85}
86
87impl BuffersFormatConstructor for u64 {
88 #[track_caller]
89 #[inline]
90 fn buffers(self) -> Buffers {
91 Buffers::from_u64(self)
92 }
93}
94
95#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Debug, Default)]
96pub struct Bytes(u64);
97impl Bytes {
98 #[allow(non_upper_case_globals)]
99 // rustdoc-stripper-ignore-next
100 /// 1 kibibyte (1024).
101 #[allow(non_upper_case_globals)]
102 pub const KiB: Self = Self(1024);
103 // rustdoc-stripper-ignore-next
104 /// 1 mebibyte (1024 * 1024).
105 #[allow(non_upper_case_globals)]
106 pub const MiB: Self = Self(1024 * 1024);
107 // rustdoc-stripper-ignore-next
108 /// 1 gibibyte (1024 * 1024 * 1024).
109 #[allow(non_upper_case_globals)]
110 pub const GiB: Self = Self(1024 * 1024 * 1024);
111 pub const MAX: Self = Self(u64::MAX - 1);
112}
113
114impl Bytes {
115 // rustdoc-stripper-ignore-next
116 /// Builds a new `Bytes` formatted value with the provided bytes count.
117 ///
118 /// # Panics
119 ///
120 /// Panics if the provided count equals `u64::MAX`,
121 /// which is reserved for `None` in C.
122 #[track_caller]
123 #[inline]
124 pub const fn from_u64(bytes: u64) -> Self {
125 if bytes == u64::MAX {
126 panic!("`Bytes` value out of range");
127 }
128
129 Bytes(bytes)
130 }
131
132 // rustdoc-stripper-ignore-next
133 /// Builds a new `Bytes` formatted value with the provided bytes count.
134 ///
135 /// # Panics
136 ///
137 /// Panics if the provided count equals `u64::MAX`,
138 /// which is reserved for `None` in C.
139 #[track_caller]
140 #[inline]
141 pub fn from_usize(bytes: usize) -> Self {
142 // FIXME can't use `try_into` in `const` (rustc 1.64.0)
143 Bytes::from_u64(bytes.try_into().unwrap())
144 }
145}
146
147impl_common_ops_for_newtype_uint!(Bytes, u64);
148impl_signed_div_mul!(Bytes, u64);
149impl_signed_int_into_signed!(Bytes, u64);
150impl_format_value_traits!(Bytes, Bytes, Bytes, u64);
151option_glib_newtype_from_to!(Bytes, u64::MAX);
152glib_newtype_display!(Bytes, DisplayableOptionBytes, Format::Bytes);
153
154impl TryFrom<Bytes> for usize {
155 type Error = std::num::TryFromIntError;
156
157 fn try_from(value: Bytes) -> Result<Self, Self::Error> {
158 value.0.try_into()
159 }
160}
161
162// FIXME `functions in traits cannot be const` (rustc 1.64.0)
163// rustdoc-stripper-ignore-next
164/// `Bytes` formatted value constructor trait.
165///
166/// These constructors use the [unambiguous conventions] for byte units.
167///
168/// [unambiguous conventions]: https://en.wikipedia.org/wiki/Byte#Multiple-byte_units
169pub trait BytesFormatConstructor {
170 // rustdoc-stripper-ignore-next
171 /// Builds a `Bytes` formatted value from `self`.
172 fn bytes(self) -> Bytes;
173
174 // rustdoc-stripper-ignore-next
175 /// Builds a `Bytes` formatted value from `self` interpreted as kibibytes (1024).
176 fn kibibytes(self) -> Bytes;
177
178 // rustdoc-stripper-ignore-next
179 /// Builds a `Bytes` formatted value from `self` interpreted as mebibytes (1024²).
180 fn mebibytes(self) -> Bytes;
181
182 // rustdoc-stripper-ignore-next
183 /// Builds a `Bytes` formatted value from `self` interpreted as gibibytes (1024³).
184 fn gibibytes(self) -> Bytes;
185}
186
187impl BytesFormatConstructor for u64 {
188 #[track_caller]
189 #[inline]
190 fn bytes(self) -> Bytes {
191 Bytes::from_u64(self)
192 }
193
194 #[track_caller]
195 #[inline]
196 fn kibibytes(self) -> Bytes {
197 Bytes::from_u64(self * 1024)
198 }
199
200 #[track_caller]
201 #[inline]
202 fn mebibytes(self) -> Bytes {
203 Bytes::from_u64(self * 1024 * 1024)
204 }
205
206 #[track_caller]
207 #[inline]
208 fn gibibytes(self) -> Bytes {
209 Bytes::from_u64(self * 1024 * 1024 * 1024)
210 }
211}
212
213#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Debug, Default)]
214pub struct Default(u64);
215impl Default {
216 pub const MAX: Self = Self(u64::MAX - 1);
217}
218
219impl Default {
220 // rustdoc-stripper-ignore-next
221 /// Builds a new `Default` formatted value with the provided quantity.
222 ///
223 /// # Panics
224 ///
225 /// Panics if the provided quantity equals `u64::MAX`,
226 /// which is reserved for `None` in C.
227 #[track_caller]
228 #[inline]
229 pub const fn from_u64(quantity: u64) -> Self {
230 if quantity == u64::MAX {
231 panic!("`Default` value out of range");
232 }
233
234 Default(quantity)
235 }
236
237 // rustdoc-stripper-ignore-next
238 /// Builds a new `Default` formatted value with the provided quantity.
239 ///
240 /// # Panics
241 ///
242 /// Panics if the provided quantity equals `u64::MAX`,
243 /// which is reserved for `None` in C.
244 #[track_caller]
245 #[inline]
246 pub fn from_usize(quantity: usize) -> Self {
247 // FIXME can't use `try_into` in `const` (rustc 1.64.0)
248 Default::from_u64(quantity.try_into().unwrap())
249 }
250}
251
252impl_common_ops_for_newtype_uint!(Default, u64);
253impl_signed_div_mul!(Default, u64);
254impl_signed_int_into_signed!(Default, u64);
255impl_format_value_traits!(Default, Default, Default, u64);
256option_glib_newtype_from_to!(Default, u64::MAX);
257glib_newtype_display!(Default, DisplayableOptionDefault, Format::Default);
258
259impl TryFrom<Default> for usize {
260 type Error = std::num::TryFromIntError;
261
262 fn try_from(value: Default) -> Result<Self, Self::Error> {
263 value.0.try_into()
264 }
265}
266
267// FIXME `functions in traits cannot be const` (rustc 1.64.0)
268// rustdoc-stripper-ignore-next
269/// `Default` formatted value constructor trait.
270pub trait DefaultFormatConstructor {
271 // rustdoc-stripper-ignore-next
272 /// Builds a `Default` formatted value from `self`.
273 fn default_format(self) -> Default;
274}
275
276impl DefaultFormatConstructor for u64 {
277 #[track_caller]
278 #[inline]
279 fn default_format(self) -> Default {
280 Default::from_u64(self)
281 }
282}
283
284pub type Time = super::ClockTime;
285
286#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Debug, Default)]
287pub struct Percent(u32);
288impl Percent {
289 #[doc(alias = "GST_FORMAT_PERCENT_MAX")]
290 pub const MAX: Self = Self(ffi::GST_FORMAT_PERCENT_MAX as u32);
291 #[doc(alias = "GST_FORMAT_PERCENT_SCALE")]
292 pub const SCALE: Self = Self(ffi::GST_FORMAT_PERCENT_SCALE as u32);
293
294 // rustdoc-stripper-ignore-next
295 /// Builds a new `Percent` with the provided percent value.
296 ///
297 /// # Panics
298 ///
299 /// Panics if the provided value is larger than 100.
300 #[track_caller]
301 #[inline]
302 pub const fn from_percent(percent: u32) -> Self {
303 if percent > 100 {
304 panic!("`Percent` value out of range");
305 }
306
307 Percent(ffi::GST_FORMAT_PERCENT_SCALE as u32 * percent)
308 }
309
310 // rustdoc-stripper-ignore-next
311 /// Builds a new `Percent` with the provided parts per million value.
312 ///
313 /// # Panics
314 ///
315 /// Panics if the provided value is larger than [`Self::MAX`].
316 #[track_caller]
317 #[inline]
318 pub const fn from_ppm(ppm: u32) -> Self {
319 if ppm > ffi::GST_FORMAT_PERCENT_MAX as u32 {
320 panic!("`Percent` ppm value out of range");
321 }
322
323 Percent(ppm)
324 }
325
326 // rustdoc-stripper-ignore-next
327 /// Builds a new `Percent` with the provided ratio.
328 ///
329 /// # Panics
330 ///
331 /// Panics if the provided radio is out of the range [0.0, 1.0].
332 #[track_caller]
333 #[inline]
334 pub fn from_ratio(ratio: f32) -> Self {
335 // FIXME floating point arithmetic is not allowed in constant functions (rustc 1.64.0)
336 Percent::try_from(ratio).expect("`Percent` ratio out of range")
337 }
338}
339
340impl_common_ops_for_newtype_uint!(Percent, u32, one: ffi::GST_FORMAT_PERCENT_SCALE as u32);
341impl_signed_div_mul!(Percent, u32);
342impl_signed_int_into_signed!(Percent, u32);
343
344impl FormattedValue for Option<Percent> {
345 type FullRange = Option<Percent>;
346
347 #[inline]
348 fn default_format() -> Format {
349 Format::Percent
350 }
351
352 #[inline]
353 fn format(&self) -> Format {
354 Format::Percent
355 }
356
357 #[inline]
358 fn is_some(&self) -> bool {
359 Option::is_some(self)
360 }
361
362 #[inline]
363 unsafe fn into_raw_value(self) -> i64 {
364 self.map_or(default:-1, |v: Percent| v.0 as i64)
365 }
366}
367
368impl FormattedValueFullRange for Option<Percent> {
369 #[inline]
370 unsafe fn from_raw(format: Format, value: i64) -> Self {
371 debug_assert_eq!(format, Format::Percent);
372 Percent::try_from_glib(val:value).ok()
373 }
374}
375
376impl From<Option<Percent>> for GenericFormattedValue {
377 #[inline]
378 fn from(v: Option<Percent>) -> Self {
379 skip_assert_initialized!();
380 GenericFormattedValue::Percent(v)
381 }
382}
383
384impl From<Percent> for GenericFormattedValue {
385 #[inline]
386 fn from(v: Percent) -> Self {
387 skip_assert_initialized!();
388 GenericFormattedValue::Percent(Some(v))
389 }
390}
391
392impl FormattedValue for Percent {
393 type FullRange = Option<Percent>;
394
395 #[inline]
396 fn default_format() -> Format {
397 Format::Percent
398 }
399
400 #[inline]
401 fn format(&self) -> Format {
402 Format::Percent
403 }
404
405 #[inline]
406 fn is_some(&self) -> bool {
407 true
408 }
409
410 #[inline]
411 unsafe fn into_raw_value(self) -> i64 {
412 self.0 as i64
413 }
414}
415
416impl TryFrom<u64> for Percent {
417 type Error = GlibNoneError;
418
419 #[inline]
420 fn try_from(v: u64) -> Result<Percent, GlibNoneError> {
421 skip_assert_initialized!();
422 unsafe { Self::try_from_glib(val:v as i64) }
423 }
424}
425
426impl TryFromGlib<i64> for Percent {
427 type Error = GlibNoneError;
428 #[inline]
429 unsafe fn try_from_glib(value: i64) -> Result<Self, Self::Error> {
430 skip_assert_initialized!();
431 if value < 0 || value > ffi::GST_FORMAT_PERCENT_MAX {
432 Err(GlibNoneError)
433 } else {
434 Ok(Percent(value as u32))
435 }
436 }
437}
438
439impl TryFrom<u32> for Percent {
440 type Error = FormattedValueError;
441
442 #[inline]
443 fn try_from(value: u32) -> Result<Self, Self::Error> {
444 skip_assert_initialized!();
445 if value > ffi::GST_FORMAT_PERCENT_MAX as u32 {
446 Err(FormattedValueError(Format::Percent))
447 } else {
448 Ok(Percent(value))
449 }
450 }
451}
452
453impl TryFrom<GenericFormattedValue> for Option<Percent> {
454 type Error = FormattedValueError;
455
456 #[inline]
457 fn try_from(v: GenericFormattedValue) -> Result<Option<Percent>, Self::Error> {
458 skip_assert_initialized!();
459 if let GenericFormattedValue::Percent(v: Option) = v {
460 Ok(v)
461 } else {
462 Err(FormattedValueError(v.format()))
463 }
464 }
465}
466
467impl FormattedValueIntrinsic for Percent {}
468impl SpecificFormattedValue for Option<Percent> {}
469impl SpecificFormattedValueFullRange for Option<Percent> {}
470impl SpecificFormattedValueIntrinsic for Percent {}
471impl FormattedValueNoneBuilder for Option<Percent> {
472 #[inline]
473 fn none() -> Option<Percent> {
474 None
475 }
476}
477
478#[derive(Clone, Copy, Debug, PartialEq, Eq, thiserror::Error)]
479#[error("value out of range")]
480pub struct TryPercentFromFloatError(());
481
482impl TryFrom<f64> for Percent {
483 type Error = TryPercentFromFloatError;
484
485 #[inline]
486 fn try_from(v: f64) -> Result<Self, Self::Error> {
487 skip_assert_initialized!();
488 if v < 0.0 || v > 1.0 {
489 Err(TryPercentFromFloatError(()))
490 } else {
491 Ok(Percent(
492 (v * ffi::GST_FORMAT_PERCENT_MAX as f64).round() as u32
493 ))
494 }
495 }
496}
497
498impl TryFrom<f32> for Percent {
499 type Error = TryPercentFromFloatError;
500
501 #[inline]
502 fn try_from(v: f32) -> Result<Self, Self::Error> {
503 skip_assert_initialized!();
504 if v < 0.0 || v > 1.0 {
505 Err(TryPercentFromFloatError(()))
506 } else {
507 Ok(Percent(
508 (v * ffi::GST_FORMAT_PERCENT_MAX as f32).round() as u32
509 ))
510 }
511 }
512}
513
514// FIXME `functions in traits cannot be const` (rustc 1.64.0)
515// rustdoc-stripper-ignore-next
516/// `Percent` formatted value from integer constructor trait.
517pub trait PercentFormatIntegerConstructor {
518 // rustdoc-stripper-ignore-next
519 /// Builds a `Percent` formatted value from `self` interpreted as a percent.
520 fn percent(self) -> Percent;
521
522 // rustdoc-stripper-ignore-next
523 /// Builds a `Percent` formatted value from `self` interpreted as parts per million.
524 fn ppm(self) -> Percent;
525}
526
527impl PercentFormatIntegerConstructor for u32 {
528 #[track_caller]
529 #[inline]
530 fn percent(self) -> Percent {
531 Percent::from_percent(self)
532 }
533
534 #[track_caller]
535 #[inline]
536 fn ppm(self) -> Percent {
537 Percent::from_ppm(self)
538 }
539}
540
541// FIXME `functions in traits cannot be const` (rustc 1.64.0)
542// rustdoc-stripper-ignore-next
543/// `Percent` formatted value from float constructor trait.
544pub trait PercentFormatFloatConstructor {
545 // rustdoc-stripper-ignore-next
546 /// Builds a `Percent` formatted value from `self` interpreted as a ratio.
547 fn percent_ratio(self) -> Percent;
548}
549
550impl PercentFormatFloatConstructor for f32 {
551 #[track_caller]
552 #[inline]
553 fn percent_ratio(self) -> Percent {
554 Percent::try_from(self).unwrap()
555 }
556}
557
558impl std::fmt::Display for Percent {
559 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
560 std::fmt::Display::fmt(&(self.0 as f32 / (*Percent::SCALE) as f32), f)?;
561 f.write_str(data:" %")
562 }
563}
564
565impl crate::utils::Displayable for Percent {
566 type DisplayImpl = Self;
567 fn display(self) -> Self {
568 self
569 }
570}
571pub struct DisplayableOptionPercent(Option<Percent>);
572
573impl std::fmt::Display for DisplayableOptionPercent {
574 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
575 if let Some(val: &Percent) = self.0.as_ref() {
576 std::fmt::Display::fmt(self:val, f)
577 } else {
578 f.write_str(data:"undef. %")
579 }
580 }
581}
582
583impl crate::utils::Displayable for Option<Percent> {
584 type DisplayImpl = DisplayableOptionPercent;
585 fn display(self) -> Self::DisplayImpl {
586 DisplayableOptionPercent(self)
587 }
588}
589