gstreamer/format/
signed.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use std::fmt;
4
5use super::{Format, FormattedValueNoneBuilder};
6use crate::utils::Displayable;
7
8// rustdoc-stripper-ignore-next
9/// A signed wrapper.
10///
11/// This wrapper allows representing a signed value from a type
12/// which is originally unsigned. In C APIs, this is represented
13/// by a tuple with a signed integer positive or negative and
14/// the absolute value.
15#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
16#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
17pub enum Signed<T> {
18    Negative(T),
19    Positive(T),
20}
21
22impl<T> Signed<T> {
23    #[inline]
24    pub fn is_positive(self) -> bool {
25        matches!(self, Signed::Positive(_))
26    }
27
28    // rustdoc-stripper-ignore-next
29    /// Returns `Some(value)`, where `value` is the inner value,
30    /// if `self` is positive.
31    #[inline]
32    pub fn positive(self) -> Option<T> {
33        match self {
34            Signed::Positive(val) => Some(val),
35            Signed::Negative(_) => None,
36        }
37    }
38
39    // rustdoc-stripper-ignore-next
40    /// Transforms the `Signed<T>` into a `Result<T, E>`,
41    /// mapping `Positive(v)` to `Ok(v)` and `Negative(_)` to `Err(err)`.
42    #[inline]
43    pub fn positive_or<E>(self, err: E) -> Result<T, E> {
44        match self {
45            Signed::Positive(val) => Ok(val),
46            Signed::Negative(_) => Err(err),
47        }
48    }
49
50    // rustdoc-stripper-ignore-next
51    /// Transforms the `Signed<T>` into a `Result<T, E>`,
52    /// mapping `Positive(v)` to `Ok(v)` and `Negative(v)` to `Err(err(v))`.
53    #[inline]
54    pub fn positive_or_else<E, F: FnOnce(T) -> E>(self, err: F) -> Result<T, E> {
55        match self {
56            Signed::Positive(val) => Ok(val),
57            Signed::Negative(val) => Err(err(val)),
58        }
59    }
60
61    #[inline]
62    pub fn is_negative(self) -> bool {
63        matches!(self, Signed::Negative(_))
64    }
65
66    // rustdoc-stripper-ignore-next
67    /// Returns `Some(value)`, where `value` is the inner value,
68    /// if `self` is negative.
69    #[inline]
70    pub fn negative(self) -> Option<T> {
71        match self {
72            Signed::Negative(val) => Some(val),
73            Signed::Positive(_) => None,
74        }
75    }
76
77    // rustdoc-stripper-ignore-next
78    /// Transforms the `Signed<T>` into a `Result<T, E>`,
79    /// mapping `Negative(v)` to `Ok(v)` and `Positive(_)` to `Err(err)`.
80    #[inline]
81    pub fn negative_or<E>(self, err: E) -> Result<T, E> {
82        match self {
83            Signed::Negative(val) => Ok(val),
84            Signed::Positive(_) => Err(err),
85        }
86    }
87
88    // rustdoc-stripper-ignore-next
89    /// Transforms the `Signed<T>` into a `Result<T, E>`,
90    /// mapping `Negative(v)` to `Ok(v)` and `Positive(_)` to `Err(err(v))`.
91    #[inline]
92    pub fn negative_or_else<E, F: FnOnce(T) -> E>(self, err: F) -> Result<T, E> {
93        match self {
94            Signed::Negative(val) => Ok(val),
95            Signed::Positive(val) => Err(err(val)),
96        }
97    }
98
99    // rustdoc-stripper-ignore-next
100    /// Returns the absolute value of `self`.
101    #[inline]
102    pub fn abs(self) -> T {
103        match self {
104            Signed::Positive(val) | Signed::Negative(val) => val,
105        }
106    }
107}
108
109impl<T> std::ops::Neg for Signed<T> {
110    type Output = Signed<T>;
111
112    #[inline]
113    fn neg(self) -> Self {
114        match self {
115            Signed::Positive(val) => Signed::Negative(val),
116            Signed::Negative(val) => Signed::Positive(val),
117        }
118    }
119}
120
121pub trait SignedIntrinsic {}
122
123impl<T> fmt::Display for Signed<T>
124where
125    T: fmt::Display + SignedIntrinsic,
126{
127    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
128        use std::fmt::Write;
129
130        let (sign, val) = match self {
131            Signed::Positive(val) => ('+', val),
132            Signed::Negative(val) => ('-', val),
133        };
134
135        f.write_char(sign)?;
136        fmt::Display::fmt(&val, f)
137    }
138}
139
140impl<T> Displayable for Signed<T>
141where
142    T: fmt::Display + SignedIntrinsic,
143{
144    type DisplayImpl = Signed<T>;
145
146    fn display(self) -> Self::DisplayImpl {
147        self
148    }
149}
150
151impl<T> Signed<Option<T>> {
152    // rustdoc-stripper-ignore-next
153    /// Transposes a `Signed` `Option` into an `Option` of a `Signed`.
154    ///
155    /// Note that if the inner value was `None`, the sign is lost.
156    #[inline]
157    pub fn transpose(self) -> Option<Signed<T>> {
158        use Signed::*;
159
160        match self {
161            Positive(Some(val)) => Some(Positive(val)),
162            Negative(Some(val)) => Some(Negative(val)),
163            _ => None,
164        }
165    }
166}
167
168pub struct DisplayableOptionSigned<T>(Option<Signed<T>>);
169
170impl<T> fmt::Display for DisplayableOptionSigned<T>
171where
172    T: fmt::Display + SignedIntrinsic,
173    Option<T>: Displayable,
174{
175    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
176        match self.0 {
177            Some(ref signed) => fmt::Display::fmt(signed, f),
178            None => fmt::Display::fmt(&Option::<T>::None.display(), f),
179        }
180    }
181}
182
183impl<T> Displayable for Option<Signed<T>>
184where
185    T: fmt::Display + SignedIntrinsic,
186    Option<T>: Displayable,
187{
188    type DisplayImpl = DisplayableOptionSigned<T>;
189
190    fn display(self) -> Self::DisplayImpl {
191        DisplayableOptionSigned(self)
192    }
193}
194
195impl<T> Displayable for Signed<Option<T>>
196where
197    T: fmt::Display + SignedIntrinsic,
198    Option<T>: Displayable,
199{
200    type DisplayImpl = DisplayableOptionSigned<T>;
201
202    fn display(self) -> Self::DisplayImpl {
203        DisplayableOptionSigned(self.transpose())
204    }
205}
206
207// rustdoc-stripper-ignore-next
208/// A trait implemented on unsigned types which can be converted into [`crate::Signed`]s.
209pub trait UnsignedIntoSigned: Copy + Sized {
210    type Signed;
211
212    // rustdoc-stripper-ignore-next
213    /// Converts `self` into a `Signed` matching the given `sign`.
214    fn into_signed(self, sign: i32) -> Self::Signed {
215        if sign.is_positive() {
216            self.into_positive()
217        } else {
218            self.into_negative()
219        }
220    }
221
222    // rustdoc-stripper-ignore-next
223    /// Converts `self` into a `Signed::Positive`.
224    fn into_positive(self) -> Self::Signed;
225
226    // rustdoc-stripper-ignore-next
227    /// Converts `self` into a `Signed::Negative`.
228    fn into_negative(self) -> Self::Signed;
229}
230
231impl_unsigned_int_into_signed!(u64);
232impl_signed_ops!(u64);
233impl_signed_div_mul!(u64);
234impl_signed_int_into_signed!(u64);
235
236impl_unsigned_int_into_signed!(u32);
237impl_signed_ops!(u32);
238impl_signed_div_mul!(u32);
239impl_signed_int_into_signed!(u32);
240
241impl_unsigned_int_into_signed!(usize);
242impl_signed_ops!(usize);
243impl_signed_div_mul!(usize);
244impl_signed_int_into_signed!(usize);
245
246pub trait NoneSignedBuilder: FormattedValueNoneBuilder {
247    type Signed;
248
249    // rustdoc-stripper-ignore-next
250    /// Returns the `None` value for `Self` as a `Signed<FullRange>` if such a value can be represented.
251    ///
252    /// See details in [`FormattedValueNoneBuilder::none`].
253    ///
254    /// # Panics
255    ///
256    /// Panics if `Self` is `GenericFormattedValue` in which case, the `Format` must be known.
257    fn none_signed() -> Self::Signed;
258
259    // rustdoc-stripper-ignore-next
260    /// Returns the `None` value for `Self` as a `Signed<FullRange>`, if such a value can be represented.
261    ///
262    /// See details in [`FormattedValueNoneBuilder::none_for_format`].
263    ///
264    /// # Panics
265    ///
266    /// Panics if `None` can't be represented by `Self` for `format` or by the requested
267    /// `GenericFormattedValue` variant.
268    fn none_signed_for_format(format: Format) -> Self::Signed;
269}
270
271impl<T> NoneSignedBuilder for T
272where
273    T: UnsignedIntoSigned + FormattedValueNoneBuilder,
274{
275    type Signed = <T as UnsignedIntoSigned>::Signed;
276
277    #[inline]
278    fn none_signed() -> Self::Signed {
279        Self::none().into_positive()
280    }
281
282    #[inline]
283    fn none_signed_for_format(format: Format) -> Self::Signed {
284        skip_assert_initialized!();
285        Self::none_for_format(format).into_positive()
286    }
287}