1 | // Take a look at the license at the top of the repository in the LICENSE file. |
2 | |
3 | use glib::translate::{FromGlib, GlibNoneError, IntoGlib, OptionIntoGlib, TryFromGlib}; |
4 | |
5 | use super::{ |
6 | Format, FormattedValue, FormattedValueError, FormattedValueFullRange, FormattedValueIntrinsic, |
7 | FormattedValueNoneBuilder, GenericFormattedValue, |
8 | }; |
9 | |
10 | pub trait SpecificFormattedValue: FormattedValue {} |
11 | |
12 | pub 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>`. |
21 | pub trait SpecificFormattedValueIntrinsic: TryFromGlib<i64> + FormattedValueIntrinsic {} |
22 | |
23 | #[derive (PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Debug, Default)] |
24 | pub struct Buffers(u64); |
25 | impl 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 | |
31 | impl 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 | |
63 | impl_common_ops_for_newtype_uint!(Buffers, u64); |
64 | impl_signed_div_mul!(Buffers, u64); |
65 | impl_signed_int_into_signed!(Buffers, u64); |
66 | impl_format_value_traits!(Buffers, Buffers, Buffers, u64); |
67 | option_glib_newtype_from_to!(Buffers, Buffers::OFFSET_NONE); |
68 | glib_newtype_display!(Buffers, DisplayableOptionBuffers, Format::Buffers); |
69 | |
70 | impl 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. |
81 | pub trait BuffersFormatConstructor { |
82 | // rustdoc-stripper-ignore-next |
83 | /// Builds a `Buffers` formatted value from `self`. |
84 | fn buffers(self) -> Buffers; |
85 | } |
86 | |
87 | impl 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)] |
96 | pub struct Bytes(u64); |
97 | impl 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 | |
114 | impl 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 | |
147 | impl_common_ops_for_newtype_uint!(Bytes, u64); |
148 | impl_signed_div_mul!(Bytes, u64); |
149 | impl_signed_int_into_signed!(Bytes, u64); |
150 | impl_format_value_traits!(Bytes, Bytes, Bytes, u64); |
151 | option_glib_newtype_from_to!(Bytes, u64::MAX); |
152 | glib_newtype_display!(Bytes, DisplayableOptionBytes, Format::Bytes); |
153 | |
154 | impl 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 |
169 | pub 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 | |
187 | impl 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)] |
214 | pub struct Default(u64); |
215 | impl Default { |
216 | pub const MAX: Self = Self(u64::MAX - 1); |
217 | } |
218 | |
219 | impl 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 | |
252 | impl_common_ops_for_newtype_uint!(Default, u64); |
253 | impl_signed_div_mul!(Default, u64); |
254 | impl_signed_int_into_signed!(Default, u64); |
255 | impl_format_value_traits!(Default, Default, Default, u64); |
256 | option_glib_newtype_from_to!(Default, u64::MAX); |
257 | glib_newtype_display!(Default, DisplayableOptionDefault, Format::Default); |
258 | |
259 | impl 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. |
270 | pub trait DefaultFormatConstructor { |
271 | // rustdoc-stripper-ignore-next |
272 | /// Builds a `Default` formatted value from `self`. |
273 | fn default_format(self) -> Default; |
274 | } |
275 | |
276 | impl DefaultFormatConstructor for u64 { |
277 | #[track_caller ] |
278 | #[inline ] |
279 | fn default_format(self) -> Default { |
280 | Default::from_u64(self) |
281 | } |
282 | } |
283 | |
284 | pub type Time = super::ClockTime; |
285 | |
286 | #[derive (PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Debug, Default)] |
287 | pub struct Percent(u32); |
288 | impl 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 | |
340 | impl_common_ops_for_newtype_uint!(Percent, u32, one: ffi::GST_FORMAT_PERCENT_SCALE as u32); |
341 | impl_signed_div_mul!(Percent, u32); |
342 | impl_signed_int_into_signed!(Percent, u32); |
343 | |
344 | impl 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 | |
368 | impl 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 | |
376 | impl 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 | |
384 | impl From<Percent> for GenericFormattedValue { |
385 | #[inline ] |
386 | fn from(v: Percent) -> Self { |
387 | skip_assert_initialized!(); |
388 | GenericFormattedValue::Percent(Some(v)) |
389 | } |
390 | } |
391 | |
392 | impl 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 | |
416 | impl 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 | |
426 | impl 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 | |
439 | impl 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 | |
453 | impl 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 | |
467 | impl FormattedValueIntrinsic for Percent {} |
468 | impl SpecificFormattedValue for Option<Percent> {} |
469 | impl SpecificFormattedValueFullRange for Option<Percent> {} |
470 | impl SpecificFormattedValueIntrinsic for Percent {} |
471 | impl 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" )] |
480 | pub struct TryPercentFromFloatError(()); |
481 | |
482 | impl 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 | |
498 | impl 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. |
517 | pub 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 | |
527 | impl 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. |
544 | pub 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 | |
550 | impl PercentFormatFloatConstructor for f32 { |
551 | #[track_caller ] |
552 | #[inline ] |
553 | fn percent_ratio(self) -> Percent { |
554 | Percent::try_from(self).unwrap() |
555 | } |
556 | } |
557 | |
558 | impl 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 | |
565 | impl crate::utils::Displayable for Percent { |
566 | type DisplayImpl = Self; |
567 | fn display(self) -> Self { |
568 | self |
569 | } |
570 | } |
571 | pub struct DisplayableOptionPercent(Option<Percent>); |
572 | |
573 | impl 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 | |
583 | impl crate::utils::Displayable for Option<Percent> { |
584 | type DisplayImpl = DisplayableOptionPercent; |
585 | fn display(self) -> Self::DisplayImpl { |
586 | DisplayableOptionPercent(self) |
587 | } |
588 | } |
589 | |