summary refs log tree commit diff stats
path: root/src/impls/cstr.rs
blob: 700ae134f48dbf476b6b96c54ae115b750c64e3a (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
use std::ffi::CStr;
use std::os::raw::c_char;

use crate::*;

/// Conversion from [`CStr`] to [`ConstLtPtr`].
impl AsLtPtr for CStr {
    /// The target type of this conversion.
    type Target = c_char;

    /// Returns the inner pointer to this C string.
    ///
    /// The returned pointer points to a contiguous region of memory terminated
    /// with a 0 byte to represent the end of the string.
    ///
    /// # Examples
    ///
    /// `ltptr` protects you from dangling pointers: (adapted from
    /// [`CStr::as_ptr`])
    ///
    /// ```rust compile_fail
    /// use std::ffi::CString;
    /// use ltptr::AsLtPtr;
    ///
    /// let ptr = CString::new("Hello").unwrap().as_lt_ptr();
    /// unsafe {
    ///     // would be dangling but the compiler prevents this from compiling
    ///     ptr.as_raw();
    /// }
    /// ```
    ///
    /// Which you can fix by adding a binding:
    ///
    /// ```rust
    /// use std::ffi::CString;
    /// use ltptr::AsLtPtr;
    ///
    /// let hello = CString::new("Hello").unwrap();
    /// let ptr = hello.as_lt_ptr();
    /// unsafe {
    ///     // perfectly fine
    ///     ptr.as_raw();
    /// }
    /// ```
    #[inline]
    fn as_lt_ptr(&self) -> ConstLtPtr<'_, c_char> {
        unsafe { ConstLtPtr::from_raw(self.as_ptr()) }
    }
}

/// Conversion from [`ConstLtPtr`] of [`c_char`] to [`CStr`].
impl FromLtPtr<c_char> for CStr {
    /// Wraps a raw C string with a safe C string wrapper.
    ///
    /// # Safety
    ///
    /// See [`CStr::from_ptr`] for the safety requirements.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use std::ffi::CStr;
    /// use std::ffi::CString;
    /// use std::os::raw::c_char;
    /// use ltptr::AsLtPtr;
    /// use ltptr::ConstLtPtr;
    /// use ltptr::FromLtPtr;
    ///
    /// unsafe fn foo(ptr: ConstLtPtr<'_, c_char>) {
    ///     let first = unsafe { CStr::from_lt_ptr(ptr) }.to_str().to_owned();
    /// }
    ///
    /// let hello = CString::new("Hello").unwrap();
    /// let ptr = hello.as_lt_ptr();
    /// unsafe { foo(ptr) };
    /// ```
    #[inline]
    unsafe fn from_lt_ptr(ptr: ConstLtPtr<'_, c_char>) -> &CStr {
        unsafe { CStr::from_ptr(ptr.as_raw()) }
    }
}