Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/gpu/nova-core/num.rs
38184 views
1
// SPDX-License-Identifier: GPL-2.0
2
3
//! Numerical helpers functions and traits.
4
//!
5
//! This is essentially a staging module for code to mature until it can be moved to the `kernel`
6
//! crate.
7
8
use kernel::{
9
macros::paste,
10
prelude::*, //
11
};
12
13
/// Implements safe `as` conversion functions from a given type into a series of target types.
14
///
15
/// These functions can be used in place of `as`, with the guarantee that they will be lossless.
16
macro_rules! impl_safe_as {
17
($from:ty as { $($into:ty),* }) => {
18
$(
19
paste! {
20
#[doc = ::core::concat!(
21
"Losslessly converts a [`",
22
::core::stringify!($from),
23
"`] into a [`",
24
::core::stringify!($into),
25
"`].")]
26
///
27
/// This conversion is allowed as it is always lossless. Prefer this over the `as`
28
/// keyword to ensure no lossy casts are performed.
29
///
30
/// This is for use from a `const` context. For non `const` use, prefer the
31
/// [`FromSafeCast`] and [`IntoSafeCast`] traits.
32
///
33
/// # Examples
34
///
35
/// ```
36
/// use crate::num;
37
///
38
#[doc = ::core::concat!(
39
"assert_eq!(num::",
40
::core::stringify!($from),
41
"_as_",
42
::core::stringify!($into),
43
"(1",
44
::core::stringify!($from),
45
"), 1",
46
::core::stringify!($into),
47
");")]
48
/// ```
49
#[allow(unused)]
50
#[inline(always)]
51
pub(crate) const fn [<$from _as_ $into>](value: $from) -> $into {
52
kernel::static_assert!(size_of::<$into>() >= size_of::<$from>());
53
54
value as $into
55
}
56
}
57
)*
58
};
59
}
60
61
impl_safe_as!(u8 as { u16, u32, u64, usize });
62
impl_safe_as!(u16 as { u32, u64, usize });
63
impl_safe_as!(u32 as { u64, usize } );
64
// `u64` and `usize` have the same size on 64-bit platforms.
65
#[cfg(CONFIG_64BIT)]
66
impl_safe_as!(u64 as { usize } );
67
68
// A `usize` fits into a `u64` on 32 and 64-bit platforms.
69
#[cfg(any(CONFIG_32BIT, CONFIG_64BIT))]
70
impl_safe_as!(usize as { u64 });
71
72
// A `usize` fits into a `u32` on 32-bit platforms.
73
#[cfg(CONFIG_32BIT)]
74
impl_safe_as!(usize as { u32 });
75
76
/// Extension trait providing guaranteed lossless cast to `Self` from `T`.
77
///
78
/// The standard library's `From` implementations do not cover conversions that are not portable or
79
/// future-proof. For instance, even though it is safe today, `From<usize>` is not implemented for
80
/// [`u64`] because of the possibility to support larger-than-64bit architectures in the future.
81
///
82
/// The workaround is to either deal with the error handling of [`TryFrom`] for an operation that
83
/// technically cannot fail, or to use the `as` keyword, which can silently strip data if the
84
/// destination type is smaller than the source.
85
///
86
/// Both options are hardly acceptable for the kernel. It is also a much more architecture
87
/// dependent environment, supporting only 32 and 64 bit architectures, with some modules
88
/// explicitly depending on a specific bus width that could greatly benefit from infallible
89
/// conversion operations.
90
///
91
/// Thus this extension trait that provides, for the architecture the kernel is built for, safe
92
/// conversion between types for which such cast is lossless.
93
///
94
/// In other words, this trait is implemented if, for the current build target and with `t: T`, the
95
/// `t as Self` operation is completely lossless.
96
///
97
/// Prefer this over the `as` keyword to ensure no lossy casts are performed.
98
///
99
/// If you need to perform a conversion in `const` context, use [`u64_as_usize`], [`u32_as_usize`],
100
/// [`usize_as_u64`], etc.
101
///
102
/// # Examples
103
///
104
/// ```
105
/// use crate::num::FromSafeCast;
106
///
107
/// assert_eq!(usize::from_safe_cast(0xf00u32), 0xf00u32 as usize);
108
/// ```
109
pub(crate) trait FromSafeCast<T> {
110
/// Create a `Self` from `value`. This operation is guaranteed to be lossless.
111
fn from_safe_cast(value: T) -> Self;
112
}
113
114
impl FromSafeCast<usize> for u64 {
115
fn from_safe_cast(value: usize) -> Self {
116
usize_as_u64(value)
117
}
118
}
119
120
#[cfg(CONFIG_32BIT)]
121
impl FromSafeCast<usize> for u32 {
122
fn from_safe_cast(value: usize) -> Self {
123
usize_as_u32(value)
124
}
125
}
126
127
impl FromSafeCast<u32> for usize {
128
fn from_safe_cast(value: u32) -> Self {
129
u32_as_usize(value)
130
}
131
}
132
133
#[cfg(CONFIG_64BIT)]
134
impl FromSafeCast<u64> for usize {
135
fn from_safe_cast(value: u64) -> Self {
136
u64_as_usize(value)
137
}
138
}
139
140
/// Counterpart to the [`FromSafeCast`] trait, i.e. this trait is to [`FromSafeCast`] what [`Into`]
141
/// is to [`From`].
142
///
143
/// See the documentation of [`FromSafeCast`] for the motivation.
144
///
145
/// # Examples
146
///
147
/// ```
148
/// use crate::num::IntoSafeCast;
149
///
150
/// assert_eq!(0xf00u32.into_safe_cast(), 0xf00u32 as usize);
151
/// ```
152
pub(crate) trait IntoSafeCast<T> {
153
/// Convert `self` into a `T`. This operation is guaranteed to be lossless.
154
fn into_safe_cast(self) -> T;
155
}
156
157
/// Reverse operation for types implementing [`FromSafeCast`].
158
impl<S, T> IntoSafeCast<T> for S
159
where
160
T: FromSafeCast<S>,
161
{
162
fn into_safe_cast(self) -> T {
163
T::from_safe_cast(self)
164
}
165
}
166
167
/// Implements lossless conversion of a constant from a larger type into a smaller one.
168
macro_rules! impl_const_into {
169
($from:ty => { $($into:ty),* }) => {
170
$(
171
paste! {
172
#[doc = ::core::concat!(
173
"Performs a build-time safe conversion of a [`",
174
::core::stringify!($from),
175
"`] constant value into a [`",
176
::core::stringify!($into),
177
"`].")]
178
///
179
/// This checks at compile-time that the conversion is lossless, and triggers a build
180
/// error if it isn't.
181
///
182
/// # Examples
183
///
184
/// ```
185
/// use crate::num;
186
///
187
/// // Succeeds because the value of the source fits into the destination's type.
188
#[doc = ::core::concat!(
189
"assert_eq!(num::",
190
::core::stringify!($from),
191
"_into_",
192
::core::stringify!($into),
193
"::<1",
194
::core::stringify!($from),
195
">(), 1",
196
::core::stringify!($into),
197
");")]
198
/// ```
199
#[allow(unused)]
200
pub(crate) const fn [<$from _into_ $into>]<const N: $from>() -> $into {
201
// Make sure that the target type is smaller than the source one.
202
static_assert!($from::BITS >= $into::BITS);
203
// CAST: we statically enforced above that `$from` is larger than `$into`, so the
204
// `as` conversion will be lossless.
205
build_assert!(N >= $into::MIN as $from && N <= $into::MAX as $from);
206
207
N as $into
208
}
209
}
210
)*
211
};
212
}
213
214
impl_const_into!(usize => { u8, u16, u32 });
215
impl_const_into!(u64 => { u8, u16, u32 });
216
impl_const_into!(u32 => { u8, u16 });
217
impl_const_into!(u16 => { u8 });
218
219