summaryrefslogtreecommitdiff
path: root/drivers/gpu/nova-core/num.rs
blob: c952a834e6627cd1f4d84bdc313bc963ece4c0b0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
// SPDX-License-Identifier: GPL-2.0

//! Numerical helpers functions and traits.
//!
//! This is essentially a staging module for code to mature until it can be moved to the `kernel`
//! crate.

use kernel::{
    macros::paste,
    prelude::*, //
};

/// Implements safe `as` conversion functions from a given type into a series of target types.
///
/// These functions can be used in place of `as`, with the guarantee that they will be lossless.
macro_rules! impl_safe_as {
    ($from:ty as { $($into:ty),* }) => {
        $(
        paste! {
            #[doc = ::core::concat!(
                "Losslessly converts a [`",
                ::core::stringify!($from),
                "`] into a [`",
                ::core::stringify!($into),
                "`].")]
            ///
            /// This conversion is allowed as it is always lossless. Prefer this over the `as`
            /// keyword to ensure no lossy casts are performed.
            ///
            /// This is for use from a `const` context. For non `const` use, prefer the
            /// [`FromSafeCast`] and [`IntoSafeCast`] traits.
            ///
            /// # Examples
            ///
            /// ```
            /// use crate::num;
            ///
            #[doc = ::core::concat!(
                "assert_eq!(num::",
                ::core::stringify!($from),
                "_as_",
                ::core::stringify!($into),
                "(1",
                ::core::stringify!($from),
                "), 1",
                ::core::stringify!($into),
                ");")]
            /// ```
            #[allow(unused)]
            #[inline(always)]
            pub(crate) const fn [<$from _as_ $into>](value: $from) -> $into {
                kernel::static_assert!(size_of::<$into>() >= size_of::<$from>());

                value as $into
            }
        }
        )*
    };
}

impl_safe_as!(u8 as { u16, u32, u64, usize });
impl_safe_as!(u16 as { u32, u64, usize });
impl_safe_as!(u32 as { u64, usize } );
// `u64` and `usize` have the same size on 64-bit platforms.
#[cfg(CONFIG_64BIT)]
impl_safe_as!(u64 as { usize } );

// A `usize` fits into a `u64` on 32 and 64-bit platforms.
#[cfg(any(CONFIG_32BIT, CONFIG_64BIT))]
impl_safe_as!(usize as { u64 });

// A `usize` fits into a `u32` on 32-bit platforms.
#[cfg(CONFIG_32BIT)]
impl_safe_as!(usize as { u32 });

/// Extension trait providing guaranteed lossless cast to `Self` from `T`.
///
/// The standard library's `From` implementations do not cover conversions that are not portable or
/// future-proof. For instance, even though it is safe today, `From<usize>` is not implemented for
/// [`u64`] because of the possibility to support larger-than-64bit architectures in the future.
///
/// The workaround is to either deal with the error handling of [`TryFrom`] for an operation that
/// technically cannot fail, or to use the `as` keyword, which can silently strip data if the
/// destination type is smaller than the source.
///
/// Both options are hardly acceptable for the kernel. It is also a much more architecture
/// dependent environment, supporting only 32 and 64 bit architectures, with some modules
/// explicitly depending on a specific bus width that could greatly benefit from infallible
/// conversion operations.
///
/// Thus this extension trait that provides, for the architecture the kernel is built for, safe
/// conversion between types for which such cast is lossless.
///
/// In other words, this trait is implemented if, for the current build target and with `t: T`, the
/// `t as Self` operation is completely lossless.
///
/// Prefer this over the `as` keyword to ensure no lossy casts are performed.
///
/// If you need to perform a conversion in `const` context, use [`u64_as_usize`], [`u32_as_usize`],
/// [`usize_as_u64`], etc.
///
/// # Examples
///
/// ```
/// use crate::num::FromSafeCast;
///
/// assert_eq!(usize::from_safe_cast(0xf00u32), 0xf00u32 as usize);
/// ```
pub(crate) trait FromSafeCast<T> {
    /// Create a `Self` from `value`. This operation is guaranteed to be lossless.
    fn from_safe_cast(value: T) -> Self;
}

impl FromSafeCast<usize> for u64 {
    fn from_safe_cast(value: usize) -> Self {
        usize_as_u64(value)
    }
}

#[cfg(CONFIG_32BIT)]
impl FromSafeCast<usize> for u32 {
    fn from_safe_cast(value: usize) -> Self {
        usize_as_u32(value)
    }
}

impl FromSafeCast<u32> for usize {
    fn from_safe_cast(value: u32) -> Self {
        u32_as_usize(value)
    }
}

#[cfg(CONFIG_64BIT)]
impl FromSafeCast<u64> for usize {
    fn from_safe_cast(value: u64) -> Self {
        u64_as_usize(value)
    }
}

/// Counterpart to the [`FromSafeCast`] trait, i.e. this trait is to [`FromSafeCast`] what [`Into`]
/// is to [`From`].
///
/// See the documentation of [`FromSafeCast`] for the motivation.
///
/// # Examples
///
/// ```
/// use crate::num::IntoSafeCast;
///
/// assert_eq!(0xf00u32.into_safe_cast(), 0xf00u32 as usize);
/// ```
pub(crate) trait IntoSafeCast<T> {
    /// Convert `self` into a `T`. This operation is guaranteed to be lossless.
    fn into_safe_cast(self) -> T;
}

/// Reverse operation for types implementing [`FromSafeCast`].
impl<S, T> IntoSafeCast<T> for S
where
    T: FromSafeCast<S>,
{
    fn into_safe_cast(self) -> T {
        T::from_safe_cast(self)
    }
}

/// Implements lossless conversion of a constant from a larger type into a smaller one.
macro_rules! impl_const_into {
    ($from:ty => { $($into:ty),* }) => {
        $(
        paste! {
            #[doc = ::core::concat!(
                "Performs a build-time safe conversion of a [`",
                ::core::stringify!($from),
                "`] constant value into a [`",
                ::core::stringify!($into),
                "`].")]
            ///
            /// This checks at compile-time that the conversion is lossless, and triggers a build
            /// error if it isn't.
            ///
            /// # Examples
            ///
            /// ```
            /// use crate::num;
            ///
            /// // Succeeds because the value of the source fits into the destination's type.
            #[doc = ::core::concat!(
                "assert_eq!(num::",
                ::core::stringify!($from),
                "_into_",
                ::core::stringify!($into),
                "::<1",
                ::core::stringify!($from),
                ">(), 1",
                ::core::stringify!($into),
                ");")]
            /// ```
            #[allow(unused)]
            pub(crate) const fn [<$from _into_ $into>]<const N: $from>() -> $into {
                // Make sure that the target type is smaller than the source one.
                static_assert!($from::BITS >= $into::BITS);
                // CAST: we statically enforced above that `$from` is larger than `$into`, so the
                // `as` conversion will be lossless.
                build_assert!(N >= $into::MIN as $from && N <= $into::MAX as $from);

                N as $into
            }
        }
        )*
    };
}

impl_const_into!(usize => { u8, u16, u32 });
impl_const_into!(u64 => { u8, u16, u32 });
impl_const_into!(u32 => { u8, u16 });
impl_const_into!(u16 => { u8 });