| 1 | |
| 2 |
|
| 3 | |
| 4 | |
| 5 | |
| 6 | |
| 7 |
|
| 8 | use kernel::{
|
| 9 | macros::paste,
|
| 10 | prelude::*, |
| 11 | };
|
| 12 |
|
| 13 | |
| 14 | |
| 15 | |
| 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 | |
| 28 | |
| 29 | |
| 30 | |
| 31 | |
| 32 | |
| 33 | |
| 34 | |
| 35 | |
| 36 | |
| 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::build_assert::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 | |
| 65 | #[cfg(CONFIG_64BIT)]
|
| 66 | impl_safe_as!(u64 as { usize } );
|
| 67 |
|
| 68 | |
| 69 | #[cfg(any(CONFIG_32BIT, CONFIG_64BIT))]
|
| 70 | impl_safe_as!(usize as { u64 });
|
| 71 |
|
| 72 | |
| 73 | #[cfg(CONFIG_32BIT)]
|
| 74 | impl_safe_as!(usize as { u32 });
|
| 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 | pub(crate) trait FromSafeCast<T> {
|
| 110 | |
| 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 | |
| 141 | |
| 142 | |
| 143 | |
| 144 | |
| 145 | |
| 146 | |
| 147 | |
| 148 | |
| 149 | |
| 150 | |
| 151 | |
| 152 | pub(crate) trait IntoSafeCast<T> {
|
| 153 | |
| 154 | fn into_safe_cast(self) -> T;
|
| 155 | }
|
| 156 |
|
| 157 | |
| 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 | |
| 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 | |
| 180 | |
| 181 | |
| 182 | |
| 183 | |
| 184 | |
| 185 | |
| 186 | |
| 187 | |
| 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 | |
| 202 | static_assert!($from::BITS >= $into::BITS);
|
| 203 | |
| 204 | |
| 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 | |
| 220 | |
| 221 | |
| 222 | |
| 223 | |
| 224 | #[macro_export]
|
| 225 | macro_rules! bounded_enum {
|
| 226 | (
|
| 227 | $(#[$enum_meta:meta])*
|
| 228 | $vis:vis enum $enum_type:ident with $from_impl:ident<Bounded<$width:ty, $length:literal>> {
|
| 229 | $( $(#[doc = $variant_doc:expr])* $variant:ident = $value:expr),* $(,)*
|
| 230 | }
|
| 231 | ) => {
|
| 232 | $(#[$enum_meta])*
|
| 233 | $vis enum $enum_type {
|
| 234 | $(
|
| 235 | $(#[doc = $variant_doc])*
|
| 236 | $variant = $value
|
| 237 | ),*
|
| 238 | }
|
| 239 |
|
| 240 | impl core::convert::From<$enum_type> for kernel::num::Bounded<$width, $length> {
|
| 241 | fn from(value: $enum_type) -> Self {
|
| 242 | match value {
|
| 243 | $($enum_type::$variant =>
|
| 244 | kernel::num::Bounded::<$width, _>::new::<{ $value }>()),*
|
| 245 | }
|
| 246 | }
|
| 247 | }
|
| 248 |
|
| 249 | bounded_enum!(@impl_from $enum_type with $from_impl<Bounded<$width, $length>> {
|
| 250 | $($variant = $value),*
|
| 251 | });
|
| 252 | };
|
| 253 |
|
| 254 | |
| 255 | (@impl_from $enum_type:ident with TryFrom<Bounded<$width:ty, $length:literal>> {
|
| 256 | $($variant:ident = $value:expr),* $(,)*
|
| 257 | }) => {
|
| 258 | impl core::convert::TryFrom<kernel::num::Bounded<$width, $length>> for $enum_type {
|
| 259 | type Error = kernel::error::Error;
|
| 260 |
|
| 261 | fn try_from(
|
| 262 | value: kernel::num::Bounded<$width, $length>
|
| 263 | ) -> kernel::error::Result<Self> {
|
| 264 | match value.get() {
|
| 265 | $(
|
| 266 | $value => Ok($enum_type::$variant),
|
| 267 | )*
|
| 268 | _ => Err(kernel::error::code::EINVAL),
|
| 269 | }
|
| 270 | }
|
| 271 | }
|
| 272 | };
|
| 273 |
|
| 274 | |
| 275 | |
| 276 | (@impl_from $enum_type:ident with From<Bounded<$width:ty, $length:literal>> {
|
| 277 | $($variant:ident = $value:expr),* $(,)*
|
| 278 | }) => {
|
| 279 | impl core::convert::From<kernel::num::Bounded<$width, $length>> for $enum_type {
|
| 280 | fn from(value: kernel::num::Bounded<$width, $length>) -> Self {
|
| 281 | const MAX: $width = 1 << $length;
|
| 282 |
|
| 283 | |
| 284 | let value = value.get() & ((1 << $length) - 1);
|
| 285 | match value {
|
| 286 | $(
|
| 287 | $value => $enum_type::$variant,
|
| 288 | )*
|
| 289 | |
| 290 | |
| 291 | |
| 292 | MAX.. => unreachable!(),
|
| 293 | }
|
| 294 | }
|
| 295 | }
|
| 296 | }
|
| 297 | }
|