1#![cfg(not(tarpaulin_include))]
10
11use core::{
12 cmp,
13 convert::TryFrom,
14 fmt::{
15 self,
16 Debug,
17 Display,
18 Formatter,
19 Pointer,
20 },
21 hash::{
22 Hash,
23 Hasher,
24 },
25 ops::Deref,
26 ptr::NonNull,
27 slice,
28};
29
30use tap::Pipe;
31
32#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
34pub struct Const;
35
36#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
38pub struct Mut;
39
40#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
42pub struct Frozen<Inner>
43where Inner: Mutability
44{
45 inner: Inner,
46}
47
48pub trait Mutability: 'static + Copy + Sized + self::seal::Sealed {
60 const CONTAINS_MUTABILITY: bool = false;
65
66 const PEANO_NUMBER: usize = 0;
68
69 const SELF: Self;
71
72 const RENDER: &'static str;
74
75 fn freeze(self) -> Frozen<Self> {
78 Frozen { inner: self }
79 }
80
81 fn thaw(Frozen { inner }: Frozen<Self>) -> Self {
84 inner
85 }
86}
87
88impl Mutability for Const {
89 const RENDER: &'static str = "*const";
90 const SELF: Self = Self;
91}
92
93impl self::seal::Sealed for Const {
94}
95
96impl<Inner> Mutability for Frozen<Inner>
97where Inner: Mutability + Sized
98{
99 const CONTAINS_MUTABILITY: bool = Inner::CONTAINS_MUTABILITY;
100 const PEANO_NUMBER: usize = 1 + Inner::PEANO_NUMBER;
101 const RENDER: &'static str = Inner::RENDER;
102 const SELF: Self = Self { inner: Inner::SELF };
103}
104
105impl<Inner> self::seal::Sealed for Frozen<Inner> where Inner: Mutability + Sized
106{
107}
108
109impl Mutability for Mut {
110 const CONTAINS_MUTABILITY: bool = true;
111 const RENDER: &'static str = "*mut";
112 const SELF: Self = Self;
113}
114
115impl self::seal::Sealed for Mut {
116}
117
118pub struct Address<M, T>
126where
127 M: Mutability,
128 T: ?Sized,
129{
130 inner: NonNull<T>,
132 comu: M,
134}
135
136impl<M, T> Address<M, T>
137where M: Mutability
138{
139 pub const DANGLING: Self = Self {
141 inner: NonNull::dangling(),
142 comu: M::SELF,
143 };
144}
145
146impl<M, T> Address<M, T>
147where
148 M: Mutability,
149 T: ?Sized,
150{
151 #[inline(always)]
155 pub fn new(addr: NonNull<T>) -> Self {
156 Self {
157 inner: addr,
158 comu: M::SELF,
159 }
160 }
161
162 #[inline(always)]
166 pub fn immut(self) -> Address<Const, T> {
167 Address {
168 inner: self.inner,
169 comu: Const,
170 }
171 }
172
173 #[inline(always)]
183 pub unsafe fn assert_mut(self) -> Address<Mut, T> {
184 Address {
185 inner: self.inner,
186 comu: Mut,
187 }
188 }
189
190 #[inline(always)]
192 pub fn freeze(self) -> Address<Frozen<M>, T> {
193 let Self { inner, comu } = self;
194 Address {
195 inner,
196 comu: comu.freeze(),
197 }
198 }
199
200 #[inline(always)]
202 pub fn into_inner(self) -> NonNull<T> {
203 self.inner
204 }
205
206 #[inline(always)]
208 pub fn to_const(self) -> *const T {
209 self.inner.as_ptr() as *const T
210 }
211}
212
213impl<T> Address<Mut, T> {
214 #[inline(always)]
216 #[allow(clippy::wrong_self_convention)]
217 pub fn to_mut(self) -> *mut T {
218 self.inner.as_ptr()
219 }
220}
221
222impl<M, T> Address<Frozen<M>, T>
223where
224 M: Mutability,
225 T: ?Sized,
226{
227 #[inline(always)]
229 pub fn thaw(self) -> Address<M, T> {
230 let Self { inner, comu } = self;
231 Address {
232 inner,
233 comu: Mutability::thaw(comu),
234 }
235 }
236}
237
238macro_rules! fwd {
240 ($(
241 $(@$unsafe:ident)?
242 $name:ident
243 $(<
244 $($lt:lifetime),*
245 $($typaram:ident$(: $($bound:ident),+ $(,)?)?),*
246 $(,)*
247 >)?
248 $(, $arg:ident: $ty:ty)*
249 $(=> $ret:ty)?
250 );+ $(;)?) => { $(
251 #[doc = concat!("Applies `<*T>::", stringify!($name), "`.")]
252 #[doc = concat!("[orig]: https://doc.rust-lang.org/std/primitive.pointer.html#method.", stringify!($name))]
256 pub $($unsafe)? fn $name$(<
257 $($lt,)* $($typaram$(: $($bound),+)?,)*
258 >)?(self$(, $arg: $ty)*) $(-> $ret)? {
259 self.with_ptr(|ptr| ptr.$name($($arg),*))
260 }
261 )+ };
262}
263
264macro_rules! map {
266 ($(
267 $(@$unsafe:ident)?
268 $name:ident
269 $(<
270 $($lt:lifetime),*
271 $($typaram:ident$(: $($bound:ident),+ $(,)?)?),*
272 $(,)?
273 >)?
274 $(, $arg:ident: $ty:ty $(as $map:expr)?)*
275 $(=> $ret:ty)?
276 );+ $(;)?) => { $(
277 #[doc = concat!("Applies `<*T>::", stringify!($name), "`.")]
278 #[doc = concat!("[orig]: https://doc.rust-lang.org/std/primitive.pointer.html#method.", stringify!($name))]
282 pub $($unsafe)? fn $name$(<
283 $($lt,)* $($typaram$(: $($bound),+)?,)*
284 >)?(self$(, $arg: $ty)*) $(-> $ret)? {
285 self.inner.as_ptr().$name($($arg$(.pipe($map))?),*)
286 }
287 )+ };
288}
289
290#[allow(clippy::missing_safety_doc)]
292impl<M, T> Address<M, T>
293where M: Mutability
294{
295 fwd! {
296 cast<U> => Address<M, U>;
297 @unsafe offset, count: isize => Self;
298 @unsafe add, count: usize => Self;
299 @unsafe sub, count: usize => Self;
300 wrapping_offset, count: isize => Self;
301 wrapping_add, count: usize => Self;
302 wrapping_sub, count: usize => Self;
303 }
304
305 map! {
306 @unsafe offset_from, origin: Self as |orig| orig.to_const() as *mut T => isize;
307 @unsafe read => T;
308 @unsafe read_volatile => T;
309 @unsafe read_unaligned => T;
310 @unsafe copy_to, dest: Address<Mut, T> as Address::to_mut, count: usize;
311 @unsafe copy_to_nonoverlapping, dest: Address<Mut, T> as Address::to_mut, count: usize;
312 align_offset, align: usize => usize;
313 }
314}
315
316impl<M, T> Address<M, T>
318where
319 M: Mutability,
320 T: ?Sized,
321{
322 map! {
323 @unsafe as_ref<'a> => Option<&'a T>;
324 }
325
326 #[track_caller]
328 fn with_ptr<U>(self, func: impl FnOnce(*mut T) -> *mut U) -> Address<M, U> {
329 self.inner
330 .as_ptr()
331 .pipe(func)
332 .pipe(NonNull::new)
333 .unwrap()
334 .pipe(Address::new)
335 }
336}
337
338impl<T> Address<Mut, T> {
340 map! {
341 @unsafe copy_from<M2: Mutability>, src: Address<M2, T> as Address::to_const, count: usize;
342 @unsafe copy_from_nonoverlapping<M2: Mutability>, src: Address<M2, T> as Address::to_const, count: usize;
343 @unsafe write, value: T;
344 @unsafe write_volatile, value: T;
345 @unsafe write_unaligned, value: T;
346 @unsafe replace, src: T => T;
347 @unsafe swap, with: Self as Self::to_mut;
348 }
349}
350
351impl<T> Address<Mut, T>
353where T: ?Sized
354{
355 map! {
356 @unsafe as_mut<'a> => Option<&'a mut T>;
357 @unsafe drop_in_place;
358 }
359}
360
361impl<M, T> Clone for Address<M, T>
362where
363 M: Mutability,
364 T: ?Sized,
365{
366 #[inline(always)]
367 fn clone(&self) -> Self {
368 *self
369 }
370}
371
372impl<T> TryFrom<*const T> for Address<Const, T>
373where T: ?Sized
374{
375 type Error = NullPtrError;
376
377 #[inline(always)]
378 fn try_from(elem: *const T) -> Result<Self, Self::Error> {
379 NonNull::new(elem as *mut T)
380 .ok_or(NullPtrError)
381 .map(Self::new)
382 }
383}
384
385impl<T> From<&T> for Address<Const, T>
386where T: ?Sized
387{
388 #[inline(always)]
389 fn from(elem: &T) -> Self {
390 Self::new(elem.into())
391 }
392}
393
394impl<T> TryFrom<*mut T> for Address<Mut, T>
395where T: ?Sized
396{
397 type Error = NullPtrError;
398
399 #[inline(always)]
400 fn try_from(elem: *mut T) -> Result<Self, Self::Error> {
401 NonNull::new(elem).ok_or(NullPtrError).map(Self::new)
402 }
403}
404
405impl<T> From<&mut T> for Address<Mut, T>
406where T: ?Sized
407{
408 #[inline(always)]
409 fn from(elem: &mut T) -> Self {
410 Self::new(elem.into())
411 }
412}
413
414impl<M, T> Eq for Address<M, T> where M: Mutability
415{
416}
417
418impl<M1, M2, T1, T2> PartialEq<Address<M2, T2>> for Address<M1, T1>
419where
420 M1: Mutability,
421 M2: Mutability,
422{
423 #[inline]
424 fn eq(&self, other: &Address<M2, T2>) -> bool {
425 self.inner.as_ptr() as usize == other.inner.as_ptr() as usize
426 }
427}
428
429impl<M, T> Ord for Address<M, T>
430where M: Mutability
431{
432 #[inline]
433 fn cmp(&self, other: &Self) -> cmp::Ordering {
434 self.partial_cmp(other)
435 .expect("Addresses have a total ordering")
436 }
437}
438
439impl<M1, M2, T1, T2> PartialOrd<Address<M2, T2>> for Address<M1, T1>
440where
441 M1: Mutability,
442 M2: Mutability,
443{
444 #[inline]
445 fn partial_cmp(&self, other: &Address<M2, T2>) -> Option<cmp::Ordering> {
446 (self.inner.as_ptr() as usize)
447 .partial_cmp(&(other.inner.as_ptr() as usize))
448 }
449}
450
451impl<M, T> Debug for Address<M, T>
452where
453 M: Mutability,
454 T: ?Sized,
455{
456 #[inline(always)]
457 fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
458 Debug::fmt(&self.to_const(), fmt)
459 }
460}
461
462impl<M, T> Pointer for Address<M, T>
463where
464 M: Mutability,
465 T: ?Sized,
466{
467 #[inline(always)]
468 fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
469 Pointer::fmt(&self.to_const(), fmt)
470 }
471}
472
473impl<M, T> Hash for Address<M, T>
474where
475 M: Mutability,
476 T: ?Sized,
477{
478 #[inline(always)]
479 fn hash<H>(&self, state: &mut H)
480 where H: Hasher {
481 self.inner.hash(state)
482 }
483}
484
485impl<M, T> Copy for Address<M, T>
486where
487 M: Mutability,
488 T: ?Sized,
489{
490}
491
492impl<M, T> self::seal::Sealed for Address<M, T>
493where
494 M: Mutability,
495 T: ?Sized,
496{
497}
498
499pub trait Referential<'a>: self::seal::Sealed {
501 type Ref: 'a + Deref;
503
504 unsafe fn to_ref(self) -> Self::Ref;
512
513 fn from_ref(this: Self::Ref) -> Self;
515}
516
517impl<'a, T> Referential<'a> for Address<Const, T>
518where T: 'a + ?Sized
519{
520 type Ref = &'a T;
521
522 unsafe fn to_ref(self) -> Self::Ref {
523 self.inner.as_ref()
524 }
525
526 fn from_ref(this: Self::Ref) -> Self {
527 this.into()
528 }
529}
530
531impl<'a, T> Referential<'a> for Address<Mut, T>
532where T: 'a + ?Sized
533{
534 type Ref = &'a mut T;
535
536 unsafe fn to_ref(mut self) -> Self::Ref {
537 self.inner.as_mut()
538 }
539
540 fn from_ref(this: Self::Ref) -> Self {
541 this.into()
542 }
543}
544
545impl<'a, M, T> Referential<'a> for Address<Frozen<M>, T>
546where
547 M: Mutability,
548 T: 'a + ?Sized,
549{
550 type Ref = &'a T;
551
552 unsafe fn to_ref(self) -> Self::Ref {
553 self.inner.as_ref()
554 }
555
556 fn from_ref(this: Self::Ref) -> Self {
557 Self::new(NonNull::from(this))
558 }
559}
560
561pub type Reference<'a, M, T> = <Address<M, T> as Referential<'a>>::Ref;
563
564pub trait SliceReferential<'a>: Referential<'a> + self::seal::Sealed {
566 type ElementAddr;
568
569 unsafe fn from_raw_parts(ptr: Self::ElementAddr, len: usize) -> Self::Ref;
581}
582
583impl<'a, T> SliceReferential<'a> for Address<Const, [T]>
584where T: 'a
585{
586 type ElementAddr = Address<Const, T>;
587
588 unsafe fn from_raw_parts(ptr: Self::ElementAddr, len: usize) -> Self::Ref {
589 slice::from_raw_parts(ptr.to_const(), len)
590 }
591}
592
593impl<'a, M, T> SliceReferential<'a> for Address<Frozen<M>, [T]>
594where
595 M: Mutability,
596 T: 'a,
597{
598 type ElementAddr = Address<Frozen<M>, T>;
599
600 unsafe fn from_raw_parts(ptr: Self::ElementAddr, len: usize) -> Self::Ref {
601 slice::from_raw_parts(ptr.to_const(), len)
602 }
603}
604
605impl<'a, T> SliceReferential<'a> for Address<Mut, [T]>
606where T: 'a
607{
608 type ElementAddr = Address<Mut, T>;
609
610 unsafe fn from_raw_parts(ptr: Self::ElementAddr, len: usize) -> Self::Ref {
611 slice::from_raw_parts_mut(ptr.to_mut(), len)
612 }
613}
614
615#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
617pub struct NullPtrError;
618
619impl Display for NullPtrError {
620 #[inline]
621 fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
622 write!(fmt, "wyz::Address cannot contain a null pointer")
623 }
624}
625
626#[cfg(feature = "std")]
627impl std::error::Error for NullPtrError {
628}
629
630#[doc(hidden)]
631mod seal {
632 #[doc(hidden)]
633 pub trait Sealed {}
634}