| // Part of the Crubit project, under the Apache License v2.0 with LLVM |
| // Exceptions. See /LICENSE for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| |
| use crate::slice_ptr::get_raw_parts; |
| use crate::std::string_view; |
| use core::ptr; |
| |
| impl string_view { |
| /// Returns an equivalent Rust slice pointer. |
| /// |
| /// The resulting slice pointer is valid for the lifetime of the pointed-to |
| /// object. |
| /// |
| /// Note: For empty strings, the address of the slice pointer may not be the |
| /// same as the address of the string_view. Null pointers are converted |
| /// to valid, but dangling, pointers. |
| #[inline(always)] |
| pub fn as_raw_bytes(self) -> *const [u8] { |
| self.into() |
| } |
| } |
| |
| /// Equivalent to `as_raw_bytes()`. |
| impl From<string_view> for *const [u8] { |
| fn from(sv: string_view) -> Self { |
| // SAFETY: `&sv` is a valid pointer. `data()` does not dereference the |
| // string_view. |
| let mut data = unsafe { string_view::data(&sv) } as *const u8; |
| // TODO(b/249376862): use size(), which does not have the soundness issue below. |
| // let size = unsafe {string_view::size(&sv)}; |
| // SAFETY: `&sv` is a valid pointer, but the call to end() requires that the |
| // string_view not be dangling, so this is unsound. |
| // (If `sv` is dangling, then `end()` will perform pointer arithmetic on a |
| // dangling pointer, which is implementation defined (and treated on |
| // Clang as if it were UB).) |
| let size = |
| unsafe { string_view::end(&sv) } as usize - unsafe { string_view::begin(&sv) } as usize; |
| // Unlike C++, Rust does not allow for null data pointers in slices. |
| if data.is_null() { |
| data = ptr::NonNull::dangling().as_ptr(); |
| debug_assert_eq!(size, 0); |
| } |
| ptr::slice_from_raw_parts(data, size) |
| } |
| } |
| impl From<&[u8]> for string_view { |
| fn from(s: &[u8]) -> Self { |
| string_view::from(s as *const [u8]) |
| } |
| } |
| |
| impl From<&str> for string_view { |
| fn from(s: &str) -> Self { |
| string_view::from(s.as_bytes()) |
| } |
| } |
| |
| impl From<&core::ffi::CStr> for string_view { |
| fn from(cstr: &core::ffi::CStr) -> Self { |
| string_view::from(cstr.to_bytes()) |
| } |
| } |
| |
| impl From<*const [u8]> for string_view { |
| fn from(slice: *const [u8]) -> Self { |
| // TODO(jeanpierreda): We can't access the constructors at the moment. |
| // This little maneuver's gonna cost us 51 years of annoying build breakages |
| // later, so really we should try to get the constructors callable. |
| |
| // SAFETY: string_view (in Rust) is a `repr(C)` struct entirely composed of |
| // arrays of MaybeUninit<u8>, so this would be safe even without the |
| // zeroed(). With the zeroed, it's also safe even if we accidentally use |
| // the type without further initialization. (In C++, the fields are a |
| // pointer and an integer). |
| let mut sv = unsafe { <core::mem::MaybeUninit<string_view>>::zeroed().assume_init() }; |
| // We could also use the (unstable) to_raw_parts, but that feature may change |
| // over time. It's also difficult, for idiosyncratic reasons, to pipe in |
| // the feature flag to the automatically generated bindings for |
| // `string_view` that this file attaches onto, or to inject a dependency |
| // on a crate to put this logic into. (The crate this file is a part of is |
| // automatically generated by Crubit, and so we would need to tell |
| // Crubit to add these to the generated bindings for `std`.) So for now, |
| // the most expedient thing, and the thing least likely to break in a |
| // future version of Rust, to roll our own version of to_raw_parts, which uses |
| // transmute under the hood. |
| let (ptr, size) = get_raw_parts::<u8>(slice); |
| // SAFETY: there is no immediate UB, because we are converting to an array of |
| // MaybeUninit. There is also no later UB when read by C++, where it is |
| // interpreted as a pointer: any non-dangling valid Rust pointer is also |
| // a valid C++ pointer. The only time a dangling pointer exists is if |
| // size == 0, in which case we replace it with null, which is |
| // also a valid C++ pointer. |
| sv.__data_ = unsafe { core::mem::transmute(if size == 0 { 0 as *const _ } else { ptr }) }; |
| // SAFETY: there is no immediate UB, because we are converting to an array of |
| // MaybeUninit. There is also no later UB when read by C++, where it is |
| // interpreted as a `size_t`, which has the same set of object |
| // representations as `size : usize`. |
| sv.__size_ = unsafe { core::mem::transmute(size) }; |
| sv |
| } |
| } |