| 1 | |
| 2 |
|
| 3 | |
| 4 |
|
| 5 | use core::{
|
| 6 | mem::MaybeUninit,
|
| 7 | ops::Deref, |
| 8 | };
|
| 9 |
|
| 10 | use crate::prelude::*;
|
| 11 |
|
| 12 | |
| 13 | pub struct OutOfBound;
|
| 14 |
|
| 15 | impl From<OutOfBound> for Error {
|
| 16 | #[inline(always)]
|
| 17 | fn from(_: OutOfBound) -> Self {
|
| 18 | ERANGE
|
| 19 | }
|
| 20 | }
|
| 21 |
|
| 22 | |
| 23 | |
| 24 | |
| 25 | |
| 26 | |
| 27 | |
| 28 | |
| 29 | |
| 30 | |
| 31 | |
| 32 | |
| 33 | |
| 34 | |
| 35 | |
| 36 | |
| 37 | #[diagnostic::on_unimplemented(message = "`{Self}` cannot be used to index `{T}`")]
|
| 38 | #[doc(hidden)]
|
| 39 | pub unsafe trait ProjectIndex<T: ?Sized>: Sized {
|
| 40 | type Output: ?Sized;
|
| 41 |
|
| 42 | |
| 43 | fn get(self, slice: *mut T) -> Option<*mut Self::Output>;
|
| 44 |
|
| 45 | |
| 46 | fn index(self, slice: *mut T) -> *mut Self::Output;
|
| 47 |
|
| 48 | |
| 49 | #[inline(always)]
|
| 50 | fn build_index(self, slice: *mut T) -> *mut Self::Output {
|
| 51 | match Self::get(self, slice) {
|
| 52 | Some(v) => v,
|
| 53 | None => build_error!(),
|
| 54 | }
|
| 55 | }
|
| 56 | }
|
| 57 |
|
| 58 | |
| 59 | |
| 60 | |
| 61 | unsafe impl<T, I, const N: usize> ProjectIndex<[T; N]> for I
|
| 62 | where
|
| 63 | I: ProjectIndex<[T]>,
|
| 64 | {
|
| 65 | type Output = <I as ProjectIndex<[T]>>::Output;
|
| 66 |
|
| 67 | #[inline(always)]
|
| 68 | fn get(self, slice: *mut [T; N]) -> Option<*mut Self::Output> {
|
| 69 | <I as ProjectIndex<[T]>>::get(self, slice)
|
| 70 | }
|
| 71 |
|
| 72 | #[inline(always)]
|
| 73 | fn index(self, slice: *mut [T; N]) -> *mut Self::Output {
|
| 74 | <I as ProjectIndex<[T]>>::index(self, slice)
|
| 75 | }
|
| 76 |
|
| 77 | #[inline(always)]
|
| 78 | fn build_index(self, slice: *mut [T; N]) -> *mut Self::Output {
|
| 79 | <I as ProjectIndex<[T]>>::build_index(self, slice)
|
| 80 | }
|
| 81 | }
|
| 82 |
|
| 83 | |
| 84 | |
| 85 | unsafe impl<T> ProjectIndex<[T]> for usize {
|
| 86 | type Output = T;
|
| 87 |
|
| 88 | #[inline(always)]
|
| 89 | fn get(self, slice: *mut [T]) -> Option<*mut T> {
|
| 90 | if self >= slice.len() {
|
| 91 | None
|
| 92 | } else {
|
| 93 | Some(slice.cast::<T>().wrapping_add(self))
|
| 94 | }
|
| 95 | }
|
| 96 |
|
| 97 | #[inline(always)]
|
| 98 | fn index(self, slice: *mut [T]) -> *mut T {
|
| 99 | |
| 100 | |
| 101 | let zst_slice =
|
| 102 | unsafe { core::slice::from_raw_parts::<()>(core::ptr::dangling(), slice.len()) };
|
| 103 | let () = zst_slice[self];
|
| 104 | slice.cast::<T>().wrapping_add(self)
|
| 105 | }
|
| 106 | }
|
| 107 |
|
| 108 | |
| 109 | |
| 110 | unsafe impl<T> ProjectIndex<[T]> for core::ops::Range<usize> {
|
| 111 | type Output = [T];
|
| 112 |
|
| 113 | #[inline(always)]
|
| 114 | fn get(self, slice: *mut [T]) -> Option<*mut [T]> {
|
| 115 | let new_len = self.end.checked_sub(self.start)?;
|
| 116 | if self.end > slice.len() {
|
| 117 | return None;
|
| 118 | }
|
| 119 | Some(core::ptr::slice_from_raw_parts_mut(
|
| 120 | slice.cast::<T>().wrapping_add(self.start),
|
| 121 | new_len,
|
| 122 | ))
|
| 123 | }
|
| 124 |
|
| 125 | #[inline(always)]
|
| 126 | fn index(self, slice: *mut [T]) -> *mut [T] {
|
| 127 | |
| 128 | |
| 129 | let zst_slice =
|
| 130 | unsafe { core::slice::from_raw_parts::<()>(core::ptr::dangling(), slice.len()) };
|
| 131 | _ = zst_slice[self.clone()];
|
| 132 |
|
| 133 | |
| 134 | unsafe { self.get(slice).unwrap_unchecked() }
|
| 135 | }
|
| 136 | }
|
| 137 |
|
| 138 | |
| 139 | unsafe impl<T> ProjectIndex<[T]> for core::ops::RangeTo<usize> {
|
| 140 | type Output = [T];
|
| 141 |
|
| 142 | #[inline(always)]
|
| 143 | fn get(self, slice: *mut [T]) -> Option<*mut [T]> {
|
| 144 | (0..self.end).get(slice)
|
| 145 | }
|
| 146 |
|
| 147 | #[inline(always)]
|
| 148 | fn index(self, slice: *mut [T]) -> *mut [T] {
|
| 149 | (0..self.end).index(slice)
|
| 150 | }
|
| 151 | }
|
| 152 |
|
| 153 | |
| 154 | unsafe impl<T> ProjectIndex<[T]> for core::ops::RangeFrom<usize> {
|
| 155 | type Output = [T];
|
| 156 |
|
| 157 | #[inline(always)]
|
| 158 | fn get(self, slice: *mut [T]) -> Option<*mut [T]> {
|
| 159 | (self.start..slice.len()).get(slice)
|
| 160 | }
|
| 161 |
|
| 162 | #[inline(always)]
|
| 163 | fn index(self, slice: *mut [T]) -> *mut [T] {
|
| 164 | (self.start..slice.len()).index(slice)
|
| 165 | }
|
| 166 | }
|
| 167 |
|
| 168 | |
| 169 | unsafe impl<T> ProjectIndex<[T]> for core::ops::RangeFull {
|
| 170 | type Output = [T];
|
| 171 |
|
| 172 | #[inline(always)]
|
| 173 | fn get(self, slice: *mut [T]) -> Option<*mut [T]> {
|
| 174 | Some(slice)
|
| 175 | }
|
| 176 |
|
| 177 | #[inline(always)]
|
| 178 | fn index(self, slice: *mut [T]) -> *mut [T] {
|
| 179 | slice
|
| 180 | }
|
| 181 | }
|
| 182 |
|
| 183 | |
| 184 | |
| 185 | |
| 186 | |
| 187 | |
| 188 | |
| 189 | |
| 190 | |
| 191 | |
| 192 | |
| 193 | |
| 194 | #[doc(hidden)]
|
| 195 | pub unsafe trait ProjectField<const DEREF: bool> {
|
| 196 | |
| 197 | |
| 198 | |
| 199 | |
| 200 | |
| 201 | |
| 202 | |
| 203 | |
| 204 | |
| 205 | |
| 206 | |
| 207 | unsafe fn proj<F>(base: *mut Self, f: impl FnOnce(*mut Self) -> *mut F) -> *mut F;
|
| 208 | }
|
| 209 |
|
| 210 | |
| 211 | |
| 212 | |
| 213 | |
| 214 | unsafe impl<T> ProjectField<false> for T {
|
| 215 | #[inline(always)]
|
| 216 | unsafe fn proj<F>(base: *mut Self, f: impl FnOnce(*mut Self) -> *mut F) -> *mut F {
|
| 217 | |
| 218 | |
| 219 | |
| 220 | |
| 221 | let mut place = MaybeUninit::uninit();
|
| 222 | let place_base = place.as_mut_ptr();
|
| 223 | let field = f(place_base);
|
| 224 | |
| 225 | let offset = unsafe { field.byte_offset_from(place_base) };
|
| 226 | |
| 227 | base.wrapping_byte_offset(offset).cast()
|
| 228 | }
|
| 229 | }
|
| 230 |
|
| 231 | |
| 232 | unsafe impl<T: Deref> ProjectField<true> for T {
|
| 233 | #[inline(always)]
|
| 234 | unsafe fn proj<F>(_: *mut Self, _: impl FnOnce(*mut Self) -> *mut F) -> *mut F {
|
| 235 | build_error!("this function is a guard against `Deref` impl and is never invoked");
|
| 236 | }
|
| 237 | }
|
| 238 |
|
| 239 | |
| 240 | |
| 241 | |
| 242 | |
| 243 | |
| 244 | |
| 245 | |
| 246 | |
| 247 | |
| 248 | |
| 249 | |
| 250 | |
| 251 | |
| 252 | |
| 253 | |
| 254 | |
| 255 | |
| 256 | |
| 257 | |
| 258 | |
| 259 | |
| 260 | |
| 261 | |
| 262 | |
| 263 | |
| 264 | |
| 265 | |
| 266 | |
| 267 | |
| 268 | |
| 269 | |
| 270 | |
| 271 | |
| 272 | |
| 273 | |
| 274 | |
| 275 | |
| 276 | |
| 277 | |
| 278 | |
| 279 | |
| 280 | |
| 281 | |
| 282 | |
| 283 | |
| 284 | |
| 285 | |
| 286 | |
| 287 | |
| 288 | |
| 289 | |
| 290 | |
| 291 | |
| 292 | |
| 293 | |
| 294 | |
| 295 | |
| 296 | |
| 297 | |
| 298 | |
| 299 | |
| 300 | |
| 301 | |
| 302 | |
| 303 | |
| 304 | |
| 305 | |
| 306 | |
| 307 | |
| 308 | |
| 309 | |
| 310 | |
| 311 | |
| 312 | |
| 313 | |
| 314 | |
| 315 | |
| 316 | |
| 317 | #[macro_export]
|
| 318 | macro_rules! project_pointer {
|
| 319 | (@gen $ptr:ident, ) => {};
|
| 320 | |
| 321 | (@gen $ptr:ident, .$field:tt $($rest:tt)*) => {
|
| 322 | |
| 323 | let $ptr = unsafe {
|
| 324 | $crate::ptr::projection::ProjectField::proj($ptr, #[inline(always)] |ptr| {
|
| 325 | |
| 326 | |
| 327 | if false {
|
| 328 | let _ = &(*ptr).$field;
|
| 329 | }
|
| 330 | |
| 331 | |
| 332 | &raw mut (*ptr).$field
|
| 333 | })
|
| 334 | };
|
| 335 | $crate::ptr::project!(@gen $ptr, $($rest)*)
|
| 336 | };
|
| 337 | |
| 338 | (@gen $ptr:ident, [try: $index:expr] $($rest:tt)*) => {
|
| 339 | let $ptr = $crate::ptr::projection::ProjectIndex::get($index, $ptr)
|
| 340 | .ok_or($crate::ptr::projection::OutOfBound)?;
|
| 341 | $crate::ptr::project!(@gen $ptr, $($rest)*)
|
| 342 | };
|
| 343 | |
| 344 | (@gen $ptr:ident, [panic: $index:expr] $($rest:tt)*) => {
|
| 345 | let $ptr = $crate::ptr::projection::ProjectIndex::index($index, $ptr);
|
| 346 | $crate::ptr::project!(@gen $ptr, $($rest)*)
|
| 347 | };
|
| 348 | |
| 349 | (@gen $ptr:ident, [build: $index:expr] $($rest:tt)*) => {
|
| 350 | let $ptr = $crate::ptr::projection::ProjectIndex::build_index($index, $ptr);
|
| 351 | $crate::ptr::project!(@gen $ptr, $($rest)*)
|
| 352 | };
|
| 353 |
|
| 354 | (mut $ptr:expr, $($proj:tt)*) => {{
|
| 355 | let ptr: *mut _ = $ptr;
|
| 356 | $crate::ptr::project!(@gen ptr, $($proj)*);
|
| 357 | ptr
|
| 358 | }};
|
| 359 | ($ptr:expr, $($proj:tt)*) => {{
|
| 360 | let ptr = <*const _>::cast_mut($ptr);
|
| 361 | |
| 362 | |
| 363 | $crate::ptr::project!(@gen ptr, $($proj)*);
|
| 364 | ptr.cast_const()
|
| 365 | }};
|
| 366 | }
|