I'm proposing two groups of enhancements to CStr:
-
Ability to convert a
c_char
pointer to aCStr
pointer. This is useful to create an owning wrapper type around aCStr
allocated by a C library. This could even be a genericLibcBox<CStr>
, which only needs to care aboutCStr
in 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
NonNull
variant 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
ptr
must contain a valid nul terminator at the end of the string. ptr
must be valid for reads of bytes up to and including the nul terminator. This means in particular:- The entire memory range of this
CStr
must be contained within a single allocated object! - The pointer may be null for the
*const
and*mut
variants
- The entire memory range of this
- The nul terminator must be within
isize::MAX
fromptr
(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
CStr
is 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
CStr
as a[NonZero<u8>]
A
CStr
without 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
CStr
doesn't store its length.CString
could 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_char
instead of, or in addition to,u8
in these APIs. But the unpredictable signedness of that type is annoying, so I preferu8
.