I'm proposing two groups of enhancements to CStr:
-
Ability to convert a
c_charpointer to aCStrpointer. This is useful to create an owning wrapper type around aCStrallocated by a C library. This could even be a genericLibcBox<CStr>, which only needs to care aboutCStrin a constructor method.One or more of the following:
unsafe fn non_null_from_raw(ptr: NonNull<c_char>) -> NonNull<CStr>; unsafe fn ptr_from_raw(ptr: *const c_char) -> *const CStr; unsafe fn ptr_mut_from_raw(ptr: *mut c_char) -> *mut CStr;For the owned-wrapper use-case, the
NonNullvariant would be most convenient, but similar types tend to offer raw-ptr based APIs instead.For now, these would have almost the same safety precondition as
CStr::from_ptr:- The memory pointed to by
ptrmust contain a valid nul terminator at the end of the string. ptrmust be valid for reads of bytes up to and including the nul terminator. This means in particular:- The entire memory range of this
CStrmust be contained within a single allocated object! - The pointer may be null for the
*constand*mutvariants
- The entire memory range of this
- The nul terminator must be within
isize::MAXfromptr(not sure if this one should be included)
Note: This operation is intended to be a 0-cost cast but it is currently implemented with an up-front calculation of the length of the string. This is not guaranteed to always be the case.
If
CStris changed to a type that doesn't store the length, these methods will still work, but the safety preconditions could be removed and the function marked as safe. - The memory pointed to by
-
Enable accessing a
CStras a[NonZero<u8>]A
CStrwithout the terminator has exactly the same invariants as[NonZero<u8>]. This means manipulating it as[NonZero<u8>]is safe and infallible.Possible functions:
fn to_non_null_bytes(self: &CStr) -> &[NonZero<u8>]; fn to_non_null_bytes_mut(self: &mut CStr) -> &mut [NonZero<u8>]; impl AsRef<[NonZero<u8>]> for CStr; impl AsRef<[NonZero<u8>]> for CString; impl AsMut<[NonZero<u8>]> for CStr; impl AsMut<[NonZero<u8>]> for CString;The above functions would have O(1) runtime for now, and O(n) if
CStrdoesn't store its length.CStringcould add support for infallible concatenation of non-zero slices:impl Extend<NonZero<u8>] for CString; fn extend_from_slice(&mut self, slice: &[NonZero<u8>]);It would be possible to use
c_charinstead of, or in addition to,u8in these APIs. But the unpredictable signedness of that type is annoying, so I preferu8.