| // 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 |
| |
| #ifndef THIRD_PARTY_CRUBIT_SUPPORT_RS_STD_STR_REF_H_ |
| #define THIRD_PARTY_CRUBIT_SUPPORT_RS_STD_STR_REF_H_ |
| |
| #include <stdbool.h> |
| |
| #include <cassert> |
| #include <cstddef> |
| #include <cstdint> |
| #include <optional> |
| |
| #include "crubit/support/annotations_internal.h" |
| #include "absl/base/attributes.h" |
| #include "absl/base/nullability.h" |
| #include "absl/strings/string_view.h" |
| #include "support/internal/check_no_mutable_aliasing.h" |
| #include "support/rs_std/internal/is_utf8.h" |
| #include "support/rs_std/slice_ref.h" |
| |
| namespace rs_std { |
| namespace internal { |
| |
| // A call to this function is used to trigger a compiler error when a `StrRef` |
| // is constructed from non-UTF8 data. |
| // |
| // It is intentionally not-`constexpr` so that calls to it from a constexpr |
| // context will result in a compiler error. |
| inline void StrRefArgumentMustBeUtf8() {} |
| |
| } // namespace internal |
| |
| // `rs_std::StrRef` is a C++ representation of a pointer or reference to a |
| // Rust `str`. `StrRef` is like a `&str` or `*const str`. `StrRef` |
| // is trivially destructible, copyable, and moveable. |
| // `rust_builtin_type_abi_assumptions.md` documents the ABI compatibility of |
| // these types. |
| // |
| // It is easily convertible to and from `absl::string_view`, but otherwise |
| // offers no interesting functionality. Note that, unlike `absl::string_view`, |
| // `StrRef` can only contain valid UTF8. |
| // |
| // See <internal link> for history on the design and rationale of this API. |
| class CRUBIT_INTERNAL_RUST_TYPE("&str") ABSL_ATTRIBUTE_TRIVIAL_ABI |
| StrRef final { |
| public: |
| // Returns a `StrRef` containing the given `string_view`, or nullopt if the |
| // `string_view` is not valid UTF8. |
| constexpr static std::optional<StrRef> FromUtf8( |
| absl::string_view string_view) noexcept { |
| if (!internal::IsUtf8(string_view)) { |
| return std::nullopt; |
| } |
| return StrRef(UnsafePromiseUtf8(), string_view); |
| } |
| |
| // Returns a `StrRef` containing the given `string_view` without performing |
| // UTF8 validation. |
| // |
| // NOTE: other code relies on `StrRef` being valid UTF8, so calls to this |
| // function may result in undefined behavior if `string_view` is not UTF8. |
| constexpr static StrRef FromUtf8Unchecked( |
| absl::string_view string_view) noexcept { |
| return StrRef(UnsafePromiseUtf8(), string_view); |
| } |
| |
| // consteval implict conversion from `const char*` so that string |
| // literals can be used as `StrRef` arguments while still requiring runtime |
| // UTF8 validation to be explicit. |
| // |
| // Note: consider this constructor for an implicit conversion waiver. |
| explicit consteval StrRef(const char* absl_nonnull char_ptr) noexcept |
| : StrRef(absl::string_view(char_ptr)) {} |
| |
| // consteval implict conversion from `absl::string_view`. |
| // |
| // Note: consider this constructor for an implicit conversion waiver. |
| explicit consteval StrRef(absl::string_view string_view) noexcept : slice_() { |
| if (!string_view.empty()) { |
| // We cannot use `static_assert` because C++ does not treat arguments |
| // to `consteval` functions as constants. |
| // Note that this check is still guaranteed to be evaluated at compile |
| // time because this function is `consteval`. |
| if (!internal::IsUtf8(string_view)) { |
| internal::StrRefArgumentMustBeUtf8(); |
| } |
| slice_ = SliceRef<const char>(string_view); |
| } |
| } |
| |
| // Note: consider conversion operator for an implicit conversion waiver. |
| explicit constexpr operator absl::string_view() const noexcept { |
| return absl::string_view(slice_.data(), slice_.size()); |
| } |
| |
| // Creates a default `StrRef` - one that represents an empty slice. |
| // To mirror slices in Rust, the data pointer is not null. |
| constexpr StrRef() noexcept = default; |
| constexpr StrRef(const StrRef&) = default; |
| constexpr StrRef& operator=(const StrRef&) = default; |
| |
| // A mirror of Rust's `len` method. |
| constexpr size_t len() const noexcept { return slice_.size(); } |
| constexpr bool empty() const noexcept { return slice_.size() == 0; } |
| |
| constexpr const char* data() const noexcept { return slice_.data(); } |
| constexpr size_t size() const noexcept { return slice_.size(); } |
| |
| constexpr absl::string_view to_string_view() const noexcept { |
| return absl::string_view(data(), size()); |
| } |
| |
| // Support automatic stringification with absl::StrCat and absl::StrFormat. |
| template <typename Sink> |
| friend void AbslStringify(Sink& sink, const StrRef& str) { |
| sink.Append(str.to_string_view()); |
| } |
| |
| private: |
| // Private token used to select the `StrRef` constructor which does not |
| // perform UTF8 validation. |
| struct UnsafePromiseUtf8 {}; |
| |
| // Private constructor which does not perform UTF8 validation. |
| constexpr StrRef(UnsafePromiseUtf8, absl::string_view string_view) noexcept |
| : slice_(string_view) {} |
| |
| SliceRef<const char> slice_; |
| }; |
| |
| // Note: Operators are defined twice multiple times in order to support |
| // comparison to potentially non-UTF8 `absl::string_view`s. |
| |
| constexpr bool operator==(StrRef lhs, StrRef rhs) noexcept { |
| return lhs.to_string_view() == rhs.to_string_view(); |
| } |
| |
| constexpr bool operator==(StrRef lhs, absl::string_view rhs) noexcept { |
| return lhs.to_string_view() == rhs; |
| } |
| |
| constexpr bool operator==(absl::string_view lhs, StrRef rhs) noexcept { |
| return rhs == lhs; |
| } |
| |
| constexpr auto operator<=>(StrRef lhs, StrRef rhs) noexcept { |
| return lhs.to_string_view() <=> rhs.to_string_view(); |
| } |
| |
| constexpr auto operator<=>(StrRef lhs, absl::string_view rhs) noexcept { |
| return lhs.to_string_view() <=> rhs; |
| } |
| |
| constexpr auto operator<=>(absl::string_view lhs, StrRef rhs) noexcept { |
| return lhs <=> rhs.to_string_view(); |
| } |
| |
| } // namespace rs_std |
| |
| namespace crubit::internal { |
| |
| template <> |
| struct PtrLike<rs_std::StrRef> { |
| static constexpr bool kIsConst = true; |
| static PtrData AsPtrData(rs_std::StrRef t) { |
| uintptr_t start = reinterpret_cast<uintptr_t>(t.data()); |
| return { |
| .start = start, |
| .end = start + t.size(), |
| }; |
| } |
| }; |
| |
| } // namespace crubit::internal |
| |
| #endif // THIRD_PARTY_CRUBIT_SUPPORT_RS_STD_STR_REF_H_ |