ptrplus/
lib.rs

1#![cfg_attr(not(feature = "std"), no_std)]
2
3#[cfg(feature = "std")]
4extern crate core;
5
6#[cfg(feature = "alloc")]
7extern crate alloc;
8
9use core::cell::{Cell, RefCell};
10#[cfg(feature = "alloc")]
11use core::ops::Deref;
12use core::ptr::{self, NonNull};
13#[cfg(feature = "std")]
14use std::ffi::{CStr, CString};
15#[cfg(feature = "std")]
16use std::os::raw::c_char;
17
18#[cfg(feature = "alloc")]
19use alloc::boxed::Box;
20#[cfg(feature = "alloc")]
21use alloc::rc::Rc;
22#[cfg(feature = "alloc")]
23use alloc::sync::Arc;
24
25macro_rules! asptr_wrapper {
26    ($name:ident) => {
27        impl<T> AsPtr for $name<T> {
28            type Raw = T;
29            #[inline]
30            fn as_ptr(&self) -> *const T {
31                $name::as_ptr(self)
32            }
33        }
34    };
35}
36
37#[cfg(feature = "alloc")]
38macro_rules! owned_ptr_wrapper {
39    ($name:ident) => {
40        impl<T: ?Sized> IntoRaw for $name<T> {
41            type Raw = T;
42            fn into_raw(self) -> *mut T {
43                $name::into_raw(self) as *mut T
44            }
45        }
46        impl<T: ?Sized> FromRaw<T> for $name<T> {
47            unsafe fn from_raw(raw: *mut T) -> $name<T> {
48                $name::from_raw(raw)
49            }
50        }
51    };
52}
53
54/// Trait for types that implement `as_ptr`.
55///
56/// This is implemented by types which can be converted
57/// to a pointer from a borrowed reference.
58///
59/// # Example
60/// ```
61/// use ptrplus::AsPtr;
62///
63/// let x: &u32 = &5;
64/// let y: *const u32 = x.as_ptr();
65/// unsafe {
66///     assert_eq!(*y, 5);
67/// }
68/// ```
69///
70/// ```
71/// use ptrplus::AsPtr;
72///
73/// let x = 5;
74/// let o1: Option<&u32> = None;
75/// let o2: Option<&u32> = Some(&x);
76///
77/// assert!(o1.as_ptr().is_null());
78/// assert!(!o2.as_ptr().is_null());
79/// unsafe {
80///     assert_eq!(*o2.as_ptr(), 5);
81/// }
82/// ```
83pub trait AsPtr {
84    /// The type pointed to
85    ///
86    /// `as_ptr` will return a pointer to this type
87    type Raw: ?Sized;
88
89    /// Returns a raw pointer to the contained content
90    ///
91    /// The caller must ensure `self` outlives the pointer
92    /// that is returned, or else it will end up pointing
93    /// to garbage.
94    ///
95    /// Mutating `self` may also invalidate this pointer,
96    /// depending on the implementation.
97    fn as_ptr(&self) -> *const Self::Raw;
98}
99
100impl<T> AsPtr for [T] {
101    type Raw = T;
102    #[inline]
103    fn as_ptr(&self) -> *const T {
104        <[T]>::as_ptr(self)
105    }
106}
107
108impl<'a, T: ?Sized> AsPtr for &'a T {
109    type Raw = T;
110    #[inline]
111    fn as_ptr(&self) -> *const T {
112        *self as *const T
113    }
114}
115
116impl<T: ?Sized> AsPtr for NonNull<T> {
117    type Raw = T;
118    #[inline]
119    fn as_ptr(&self) -> *const T {
120        NonNull::as_ptr(*self)
121    }
122}
123
124impl<T: ?Sized> AsPtr for *const T {
125    type Raw = T;
126    #[inline]
127    fn as_ptr(&self) -> *const T {
128        *self
129    }
130}
131
132#[cfg(feature = "std")]
133impl AsPtr for CStr {
134    type Raw = c_char;
135    #[inline]
136    fn as_ptr(&self) -> *const c_char {
137        CStr::as_ptr(self)
138    }
139}
140
141#[cfg(feature = "std")]
142impl AsPtr for CString {
143    type Raw = c_char;
144    #[inline]
145    fn as_ptr(&self) -> *const c_char {
146        CStr::as_ptr(self)
147    }
148}
149
150#[cfg(feature = "alloc")]
151impl<T: ?Sized> AsPtr for Box<T> {
152    type Raw = T;
153    #[inline]
154    fn as_ptr(&self) -> *const T {
155        self.deref().as_ptr()
156    }
157}
158
159impl<T> AsPtr for Option<T>
160where
161    T: AsPtr,
162    T::Raw: Sized,
163{
164    type Raw = T::Raw;
165    #[inline]
166    fn as_ptr(&self) -> *const T::Raw {
167        match self {
168            Some(ref v) => v.as_ptr(),
169            None => ptr::null(),
170        }
171    }
172}
173
174asptr_wrapper!(Cell);
175asptr_wrapper!(RefCell);
176#[cfg(feature = "alloc")]
177asptr_wrapper!(Rc);
178#[cfg(feature = "alloc")]
179asptr_wrapper!(Arc);
180
181/// Trait for types that implement `into_raw`
182///
183/// This is implemented by types that can be converted
184/// into a pointer by consuming ownership of the object
185///
186/// # Example
187/// ```
188/// use ptrplus::IntoRaw;
189///
190/// let x: Box<u32> = Box::new(5);
191/// let y: *mut u32 = IntoRaw::into_raw(x);
192/// unsafe {
193///   assert_eq!(*y, 5);
194///   *y = 6;
195///   Box::from_raw(y);
196/// }
197///
198/// ```
199///
200/// ```
201/// use ptrplus::{FromRaw, IntoRaw};
202///
203/// let o1: Option<Box<u32>> = None;
204/// let o2: Option<Box<u32>> = Some(Box::new(5));
205///
206/// let p1: *mut u32 = o1.into_raw();
207/// let p2: *mut u32 = o2.into_raw();
208///
209/// assert!(p1.is_null());
210/// assert!(!p2.is_null());
211/// unsafe {
212///     assert_eq!(*p2, 5);
213///     let o1: Option<Box<u32>> = Option::from_raw(p1);
214///     let o2: Option<Box<u32>> = Option::from_raw(p2);
215///     assert!(o1.is_none());
216///     assert!(!o2.is_none());
217/// }
218/// ```
219pub trait IntoRaw {
220    /// The type pointed to
221    ///
222    /// `into_raw` returns a mutable pointer to this type
223    type Raw: ?Sized;
224
225    /// Consumes `self` returning the wrapped raw pointer.
226    ///
227    /// After calling this method, the caller is responsable
228    /// for making sure any resources attached to this pointer
229    /// (such as memory) are cleaned up. The proper way to do this
230    /// is to convert the pointer back to `Self`.
231    ///
232    /// See `FromRaw`
233    fn into_raw(self) -> *mut Self::Raw;
234}
235
236#[cfg(feature = "std")]
237impl IntoRaw for CString {
238    type Raw = c_char;
239    #[inline]
240    fn into_raw(self) -> *mut c_char {
241        CString::into_raw(self)
242    }
243}
244
245impl<T: ?Sized> IntoRaw for *mut T {
246    type Raw = T;
247    #[inline]
248    fn into_raw(self) -> *mut T {
249        self
250    }
251}
252
253impl<T: ?Sized> IntoRaw for NonNull<T> {
254    type Raw = T;
255    #[inline]
256    fn into_raw(self) -> *mut T {
257        self.as_ptr()
258    }
259}
260
261impl<T> IntoRaw for Option<T>
262where
263    T: IntoRaw,
264    T::Raw: Sized,
265{
266    type Raw = T::Raw;
267    #[inline]
268    fn into_raw(self) -> *mut T::Raw {
269        match self {
270            Some(v) => v.into_raw(),
271            None => ptr::null_mut(),
272        }
273    }
274}
275
276/// Trait for types that can be created from a raw pointer
277///
278/// # Examples
279/// ```
280/// use ptrplus::{FromRaw, IntoRaw};
281///
282/// let x: Box<u32> = Box::new(5);
283/// let y = x.into_raw();
284/// let z: Box<u32> = unsafe { FromRaw::from_raw(y) };
285/// assert_eq!(*z, 5);
286///
287/// ```
288///
289pub trait FromRaw<T: ?Sized> {
290    /// Create `Self` from a raw pointer
291    ///
292    /// After calling this method the raw pointer
293    /// is owned by the resulting object. This
294    /// means that the resulting object should
295    /// clean up any resources associated with
296    /// the pointer (such as memory).
297    ///
298    /// # Safety
299    ///
300    /// `raw` must be a pointer that is compatible with
301    /// the resulting type. For example, if `Self` is
302    /// `Box<T>`, then `raw` must be a pointer to memory allocated
303    /// as a Box. The exact requirements depend on the implementation.
304    ///
305    /// Generally, the `raw` pointer must be the result of a previous
306    /// call to `into_raw` on the corresponding type. This the case for
307    /// types such as `Box`, `Rc`, and `Arc`. If the documentation
308    /// for the implementation does not say otherwise, assume this is the
309    /// case.
310    ///
311    /// Additionally, this function takes ownership of the pointer. If
312    /// `raw` or an alias thereof is used after calling this function
313    /// it can potentially result in double-free, data races, or other
314    /// undefined behavior.
315    unsafe fn from_raw(raw: *mut T) -> Self;
316}
317
318/// *Safety:* `from_raw` should only be called on a pointer originating
319/// from a [`CString`].
320#[cfg(feature = "std")]
321impl FromRaw<c_char> for CString {
322    #[inline]
323    unsafe fn from_raw(raw: *mut c_char) -> CString {
324        CString::from_raw(raw)
325    }
326}
327
328/// This implementation is always safe
329impl<T: ?Sized> FromRaw<T> for *mut T {
330    #[inline]
331    unsafe fn from_raw(raw: *mut T) -> *mut T {
332        raw
333    }
334}
335
336/// This implementation is always safe
337impl<T: ?Sized> FromRaw<T> for *const T {
338    #[inline]
339    unsafe fn from_raw(raw: *mut T) -> *const T {
340        raw
341    }
342}
343
344/// ## Safety
345/// The input pointer must be non-null.
346///
347/// `Option<NonNull<T>>::from_raw` can be used if the pointer may be null.
348impl<T: ?Sized> FromRaw<T> for NonNull<T> {
349    #[inline]
350    unsafe fn from_raw(raw: *mut T) -> NonNull<T> {
351        NonNull::new_unchecked(raw)
352    }
353}
354
355/// ## Safety
356/// The input pointer must either be null (resulting in `None`), or be safe
357/// to convert into the inner pointer type.
358impl<T, U: ?Sized> FromRaw<U> for Option<T>
359where
360    T: FromRaw<U>,
361{
362    unsafe fn from_raw(raw: *mut U) -> Option<T> {
363        if raw.is_null() {
364            None
365        } else {
366            Some(T::from_raw(raw))
367        }
368    }
369}
370
371#[cfg(feature = "alloc")]
372owned_ptr_wrapper!(Box);
373#[cfg(feature = "alloc")]
374owned_ptr_wrapper!(Rc);
375#[cfg(feature = "alloc")]
376owned_ptr_wrapper!(Arc);
377
378pub trait FromRawFamily {
379    type Pointer<T: ?Sized>;
380
381    /// Create `Pointer<T>` from a raw pointer
382    ///
383    /// After calling this method the raw pointer
384    /// is owned by the resulting object. This
385    /// means that the resulting object should
386    /// clean up any resources associated with
387    /// the pointer (such as memory).
388    ///
389    /// # Safety
390    ///
391    /// `raw` must be a pointer that is compatible with
392    /// the resulting type. For example, if `Pointer<T>` is
393    /// `Box<T>`, then `raw` must be a pointer to memory allocated
394    /// as a Box. The exact requirements depend on the implementation.
395    ///
396    /// Generally, the `raw` pointer must be the result of a previous
397    /// call to `into_raw` on the corresponding type. This the case for
398    /// types such as `Box`, `Rc`, and `Arc`. If the documentation
399    /// for the implementation does not say otherwise, assume this is the
400    /// case.
401    ///
402    /// Additionally, this function takes ownership of the pointer. If
403    /// `raw` or an alias thereof is used after calling this function
404    /// it can potentially result in double-free, data races, or other
405    /// undefined behavior.
406    unsafe fn from_raw<T: ?Sized>(raw: *mut T) -> Self::Pointer<T>;
407}
408
409macro_rules! from_raw_family_impl {
410    ($family:ident($t:ty) $v:ident => $from_raw:expr) => {
411        pub struct $family;
412        impl FromRawFamily for $family {
413            type Pointer<T: ?Sized> = $t;
414            unsafe fn from_raw<T: ?Sized>($v: *mut T) -> Self::Pointer<T> {
415                $from_raw
416            }
417        }
418    };
419}
420
421from_raw_family_impl!(MutPtrFamily(*mut T) r => r);
422from_raw_family_impl!(ConstPtrFamily(*const T) r => r);
423from_raw_family_impl!(NonNullFamily(NonNull<T>) r => NonNull::new_unchecked(r));
424
425/// Family of Options of a certain pointer type.
426pub struct OptionFromRawFamily<P> {
427    _phantom: core::marker::PhantomData<P>,
428}
429/// ## Safety
430/// The input pointer must either be null (resulting in `None`), or be safe
431/// to convert into the inner pointer type.
432impl<P: FromRawFamily> FromRawFamily for OptionFromRawFamily<P> {
433    type Pointer<T: ?Sized> = Option<P::Pointer<T>>;
434    unsafe fn from_raw<T: ?Sized>(raw: *mut T) -> Self::Pointer<T> {
435        if raw.is_null() {
436            None
437        } else {
438            Some(P::from_raw(raw))
439        }
440    }
441}
442
443macro_rules! owned_pointer_kind {
444        ($name:ident, $ptr_name:ident) => {
445            from_raw_family_impl!($name($ptr_name<T>) r => $ptr_name::from_raw(r));
446        };
447    }
448
449#[cfg(feature = "alloc")]
450owned_pointer_kind!(BoxFamily, Box);
451#[cfg(feature = "alloc")]
452owned_pointer_kind!(RcFamily, Rc);
453#[cfg(feature = "alloc")]
454owned_pointer_kind!(ArcFamily, Arc);
455
456#[cfg(test)]
457mod tests {
458    use super::*;
459
460    macro_rules! as_ptr_test {
461        ($name:ident, $t:ty, $init:expr, $compare:expr) => {
462            #[test]
463            fn $name() {
464                let x = $init;
465                let y: *const <$t as AsPtr>::Raw = <$t as AsPtr>::as_ptr(&x);
466                unsafe {
467                    assert_eq!(*y, $compare);
468                }
469            }
470        };
471    }
472
473    as_ptr_test!(ref_as_ptr, &u32, &5, 5);
474    //as_ptr_test!(slice_as_ptr, &[u32], &[5, 2]);
475    as_ptr_test!(nonnull_as_ptr, NonNull<u32>, NonNull::from(&5), 5);
476    as_ptr_test!(ptr_as_ptr, *const u32, &5u32 as *const u32, 5);
477    #[cfg(feature = "std")]
478    as_ptr_test!(
479        cstr_as_ptr,
480        CStr,
481        CStr::from_bytes_with_nul("abc\0".as_bytes()).unwrap(),
482        'a' as c_char
483    );
484    #[cfg(feature = "std")]
485    as_ptr_test!(
486        cstring_as_ptr,
487        CString,
488        CString::new("abc").unwrap(),
489        'a' as c_char
490    );
491    #[cfg(feature = "alloc")]
492    as_ptr_test!(box_as_ptr, Box<u16>, Box::new(3u16), 3);
493    as_ptr_test!(cell_as_ptr, Cell<u16>, Cell::new(7u16), 7);
494    as_ptr_test!(refcell_as_ptr, RefCell<u16>, RefCell::new(7u16), 7);
495    #[cfg(feature = "alloc")]
496    as_ptr_test!(rc_as_ptr, Rc<u16>, Rc::new(8u16), 8);
497    #[cfg(feature = "alloc")]
498    as_ptr_test!(arc_as_ptr, Arc<u16>, Arc::new(8u16), 8);
499
500    as_ptr_test!(some_as_ptr, Option<&u32>, Some(&1u32), 1);
501    #[test]
502    fn none_as_ptr() {
503        let x: Option<&u16> = None;
504        let y: *const u16 = <Option<&u16> as AsPtr>::as_ptr(&x);
505        assert!(y.is_null());
506    }
507
508    #[cfg(feature = "alloc")]
509    macro_rules! from_into_test {
510        ($name:ident, $t:ty, $init: expr, $cmp:expr) => {
511            #[test]
512            fn $name() {
513                let orig = $init;
514                let p = <$t as IntoRaw>::into_raw(orig);
515                let back = unsafe { <$t as FromRaw<_>>::from_raw(p) };
516                assert_eq!(*back, $cmp);
517            }
518        };
519    }
520
521    #[cfg(feature = "std")]
522    from_into_test!(
523        cstring_from_into,
524        CString,
525        CString::new("abc").unwrap(),
526        *CStr::from_bytes_with_nul("abc\0".as_bytes()).unwrap()
527    );
528    #[cfg(feature = "alloc")]
529    from_into_test!(box_from_into, Box<u16>, Box::new(4u16), 4);
530    #[cfg(feature = "alloc")]
531    from_into_test!(rc_from_into, Rc<u16>, Rc::new(4u16), 4);
532    #[cfg(feature = "alloc")]
533    from_into_test!(arc_from_into, Arc<u16>, Arc::new(4u16), 4);
534
535    #[test]
536    fn ptr_from_into() {
537        let mut data: u32 = 10;
538        let p = <*mut u32 as IntoRaw>::into_raw(&mut data);
539        unsafe {
540            let mptr: *mut u32 = <*mut u32 as FromRaw<_>>::from_raw(p);
541            *mptr = 54;
542        }
543        unsafe {
544            let cptr = <*const u32 as FromRaw<_>>::from_raw(p);
545            assert_eq!(*cptr, 54);
546        }
547    }
548
549    #[test]
550    fn nonnull_from_into() {
551        let mut data: u32 = 10;
552        let p = <NonNull<u32> as IntoRaw>::into_raw(NonNull::from(&mut data));
553        unsafe {
554            *p = 34;
555            let p = <NonNull<u32> as FromRaw<_>>::from_raw(p);
556            assert_eq!(p, NonNull::from(&data));
557        }
558        assert_eq!(data, 34);
559    }
560
561    #[test]
562    fn some_from_into() {
563        let mut data: u32 = 10;
564        let p = <Option<*mut u32> as IntoRaw>::into_raw(Some(&mut data));
565        unsafe {
566            *p = 54;
567            let p = <Option<*const u32> as FromRaw<_>>::from_raw(p);
568            assert_eq!(p, Some(&data as *const u32));
569        };
570        assert_eq!(data, 54);
571    }
572
573    #[test]
574    fn none_into() {
575        assert!(<Option<*mut u16> as IntoRaw>::into_raw(None).is_null());
576    }
577
578    #[test]
579    fn none_from() {
580        let p = unsafe { <Option<*mut u16> as FromRaw<_>>::from_raw(core::ptr::null_mut()) };
581        assert_eq!(p, None);
582    }
583
584    /// # Safety
585    /// It must be safe to convert a `*mut V::Raw` into a `F::Pointer<V::Raw>`
586    fn family_round_trip<F: FromRawFamily, V>(v: F::Pointer<V>) -> F::Pointer<V>
587    where
588        F::Pointer<V>: IntoRaw<Raw = V>,
589    {
590        let p = v.into_raw();
591        unsafe { F::from_raw(p) }
592    }
593
594    fn test_from_family<F: FromRawFamily, V>(p: F::Pointer<V>, cmp: &V)
595    where
596        F::Pointer<V>: IntoRaw<Raw = V> + Deref<Target = V>,
597        V: std::fmt::Debug + Eq,
598    {
599        let ptr = family_round_trip::<F, _>(p);
600        assert_eq!(&*ptr, cmp);
601    }
602
603    #[test]
604    fn mut_ptr_family() {
605        let mut x = 4;
606        let p = family_round_trip::<MutPtrFamily, _>(&mut x as *mut _);
607        assert_eq!(p, &mut x as *mut _);
608        assert_eq!(unsafe { *p }, 4);
609    }
610
611    #[test]
612    fn const_ptr_family() {
613        let mut x = 23;
614        let p = unsafe { ConstPtrFamily::from_raw(&mut x as *mut _) };
615        assert_eq!(p, &x as *const _);
616        assert_eq!(unsafe { *p }, 23);
617    }
618
619    #[test]
620    fn nonnull_family() {
621        let mut x = 23;
622        let p = unsafe { NonNull::from_raw(&mut x as *mut _) };
623        assert_eq!(p, (&x).into());
624        assert_eq!(unsafe { *p.as_ref() }, 23);
625    }
626
627    #[test]
628    fn option_family_none() {
629        let n = ptr::null_mut::<u8>();
630
631        assert!(unsafe { OptionFromRawFamily::<MutPtrFamily>::from_raw(n) }.is_none());
632    }
633
634    #[test]
635    fn option_family_some() {
636        let mut x = 89;
637
638        let p = unsafe { OptionFromRawFamily::<MutPtrFamily>::from_raw(&mut x as *mut _) };
639        assert!(p.is_some());
640        assert_eq!(p, Some(&mut x as *mut _));
641        assert_eq!(unsafe { *p.unwrap() }, 89);
642    }
643
644    #[test]
645    fn box_family() {
646        test_from_family::<BoxFamily, _>(Box::new(16), &16);
647    }
648
649    #[test]
650    fn rc_family() {
651        test_from_family::<RcFamily, _>(Rc::new(16), &16);
652    }
653
654    #[test]
655    fn arc_family() {
656        test_from_family::<ArcFamily, _>(Arc::new(16), &16);
657    }
658}