Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions support/rs_std/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,33 @@ cc_library(
],
)

cc_library(
name = "int",
hdrs = ["int.h"],
aspect_hints = ["//features:experimental"],
compatible_with = ["//buildenv/target:non_prod"],
tags = [
"alt_dep=//support/public:int",
"avoid_dep",
],
visibility = [
"//visibility:public",
],
deps = [
"//support:annotations",
],
)

crubit_cc_test(
name = "int_test",
srcs = ["int_test.cc"],
deps = [
":int",
"@fuzztest//:fuzztest_gtest_main",
"@googletest//:gmock",
],
)

alias(
name = "rs_char",
actual = "//support/rs_std:char",
Expand Down
18 changes: 18 additions & 0 deletions support/rs_std/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,23 @@ source_set("dyn_erased_future_cc") {
]
}

source_set("int") {
public_configs = [ "$crubit_src_dir:config" ]
if (defined(crubit_gn_configs_to_remove)) {
configs -= crubit_gn_configs_to_remove
}
if (defined(crubit_gn_support_configs_to_add)) {
configs += crubit_gn_support_configs_to_add
}

public = [
"int.h",
]
deps = [
"$crubit_src_dir/support:annotations",
]
}

source_set("iterator_adapter") {
public_configs = [ "$crubit_src_dir:config" ]
if (defined(crubit_gn_configs_to_remove)) {
Expand Down Expand Up @@ -330,6 +347,7 @@ group("rs_std_cpp") {
":char",
":dyn_callable",
":dyn_erased_future_cc",
":int",
":iterator_adapter",
":lossy_formatter_for_bindings",
":option",
Expand Down
13 changes: 13 additions & 0 deletions support/rs_std/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,19 @@ target_link_libraries(crubit_support_rs_std_dyn_erased_future_cc INTERFACE
crubit_support_rs_std_waker
)

add_library(crubit_support_rs_std_int INTERFACE
"int.h"
)
set_target_properties(crubit_support_rs_std_int PROPERTIES LINKER_LANGUAGE CXX)

target_include_directories(crubit_support_rs_std_int INTERFACE
"${CMAKE_CURRENT_SOURCE_DIR}/../.."
)

target_link_libraries(crubit_support_rs_std_int INTERFACE
crubit_support_annotations
)

add_library(crubit_support_rs_std_iterator_adapter INTERFACE
"iterator_adapter.h"
)
Expand Down
115 changes: 115 additions & 0 deletions support/rs_std/int.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
// 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

// IWYU pragma: private, include "support/rs_std/int.h"

#ifndef CRUBIT_SUPPORT_RS_STD_INT_H_
#define CRUBIT_SUPPORT_RS_STD_INT_H_

#include <compare>
#include <cstdint>
#include <type_traits>

#include "support/annotations.h"

namespace rs_std {

// `rs_std::usize` is a C++ representation of the `usize` type from Rust when
// used as a template argument inside template specializations (such as
// `rs_std::Option<T>`). This prevents C++ explicit template specialization
// redefinition errors or overload collisions between `usize`, `u64`, and `u32`.
class CRUBIT_INTERNAL_RUST_TYPE("usize") CRUBIT_INTERNAL_SAME_ABI usize final {
public:
constexpr usize() noexcept = default;

// Implicit constructing conversion from standard integer types.
// NOLINTNEXTLINE(google-explicit-constructor)
constexpr usize(::std::uintptr_t value) noexcept : value_(value) {}

constexpr usize(const usize&) noexcept = default;
constexpr usize& operator=(const usize&) noexcept = default;

// Implicit conversion back to `::std::uintptr_t` for seamless indexing and
// arithmetic in C++.
// NOLINTNEXTLINE(google-explicit-constructor)
constexpr operator ::std::uintptr_t() const noexcept { return value_; }

friend constexpr bool operator==(usize lhs, usize rhs) noexcept = default;
friend constexpr std::strong_ordering operator<=>(
usize lhs, usize rhs) noexcept = default;

friend constexpr usize operator+(usize lhs, usize rhs) noexcept {
return usize(lhs.value_ + rhs.value_);
}
friend constexpr usize operator-(usize lhs, usize rhs) noexcept {
return usize(lhs.value_ - rhs.value_);
}
constexpr usize& operator+=(usize rhs) noexcept {
value_ += rhs.value_;
return *this;
}
constexpr usize& operator-=(usize rhs) noexcept {
value_ -= rhs.value_;
return *this;
}

private:
::std::uintptr_t value_ = 0;
};

static_assert(sizeof(usize) == sizeof(::std::uintptr_t));
static_assert(alignof(usize) == alignof(::std::uintptr_t));
static_assert(::std::is_trivially_copyable_v<usize>);
static_assert(::std::is_trivially_destructible_v<usize>);

// `rs_std::isize` is a C++ representation of the `isize` type from Rust when
// used as a template argument inside template specializations (such as
// `rs_std::Option<T>`). This prevents C++ explicit template specialization
// redefinition errors or overload collisions between `isize`, `i64`, and `i32`.
class CRUBIT_INTERNAL_RUST_TYPE("isize") CRUBIT_INTERNAL_SAME_ABI isize final {
public:
constexpr isize() noexcept = default;

// Implicit constructing conversion from standard integer types.
// NOLINTNEXTLINE(google-explicit-constructor)
constexpr isize(::std::intptr_t value) noexcept : value_(value) {}

constexpr isize(const isize&) noexcept = default;
constexpr isize& operator=(const isize&) noexcept = default;

// Implicit conversion back to `::std::intptr_t` for seamless arithmetic and
// conversion in C++.
// NOLINTNEXTLINE(google-explicit-constructor)
constexpr operator ::std::intptr_t() const noexcept { return value_; }

friend constexpr bool operator==(isize lhs, isize rhs) noexcept = default;
friend constexpr auto operator<=>(isize lhs, isize rhs) noexcept = default;

friend constexpr isize operator+(isize lhs, isize rhs) noexcept {
return isize(lhs.value_ + rhs.value_);
}
friend constexpr isize operator-(isize lhs, isize rhs) noexcept {
return isize(lhs.value_ - rhs.value_);
}
constexpr isize& operator+=(isize rhs) noexcept {
value_ += rhs.value_;
return *this;
}
constexpr isize& operator-=(isize rhs) noexcept {
value_ -= rhs.value_;
return *this;
}

private:
::std::intptr_t value_ = 0;
};

static_assert(sizeof(isize) == sizeof(::std::intptr_t));
static_assert(alignof(isize) == alignof(::std::intptr_t));
static_assert(::std::is_trivially_copyable_v<isize>);
static_assert(::std::is_trivially_destructible_v<isize>);

} // namespace rs_std

#endif // CRUBIT_SUPPORT_RS_STD_INT_H_
72 changes: 72 additions & 0 deletions support/rs_std/int_test.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// 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

#include "support/rs_std/int.h"

#include <cstdint>
#include <type_traits>

#include "gtest/gtest.h"

namespace {

static_assert(std::is_nothrow_default_constructible_v<rs_std::usize>);
static_assert(std::is_trivially_destructible_v<rs_std::usize>);
static_assert(std::is_trivially_copyable_v<rs_std::usize>);
static_assert(std::is_trivially_copy_constructible_v<rs_std::usize>);
static_assert(std::is_trivially_copy_assignable_v<rs_std::usize>);
static_assert(std::is_trivially_move_constructible_v<rs_std::usize>);
static_assert(std::is_trivially_move_assignable_v<rs_std::usize>);
static_assert(sizeof(rs_std::usize) == sizeof(std::uintptr_t));
static_assert(alignof(rs_std::usize) == alignof(std::uintptr_t));

static_assert(std::is_nothrow_default_constructible_v<rs_std::isize>);
static_assert(std::is_trivially_destructible_v<rs_std::isize>);
static_assert(std::is_trivially_copyable_v<rs_std::isize>);
static_assert(std::is_trivially_copy_constructible_v<rs_std::isize>);
static_assert(std::is_trivially_copy_assignable_v<rs_std::isize>);
static_assert(std::is_trivially_move_constructible_v<rs_std::isize>);
static_assert(std::is_trivially_move_assignable_v<rs_std::isize>);
static_assert(sizeof(rs_std::isize) == sizeof(std::intptr_t));
static_assert(alignof(rs_std::isize) == alignof(std::intptr_t));

TEST(UsizeTest, DefaultConstructor) {
rs_std::usize value;
EXPECT_EQ(value, rs_std::usize(0));
}

TEST(UsizeTest, ImplicitConversions) {
rs_std::usize val = 42;
std::uintptr_t raw = val;
EXPECT_EQ(raw, 42);
}

TEST(UsizeTest, ArithmeticAndComparisons) {
rs_std::usize a = 10;
rs_std::usize b = 20;
EXPECT_LT(a, b);
EXPECT_EQ(a + b, rs_std::usize(30));
EXPECT_EQ(b - a, rs_std::usize(10));
}

TEST(IsizeTest, DefaultConstructor) {
rs_std::isize value;
EXPECT_EQ(value, rs_std::isize(0));
}

TEST(IsizeTest, ImplicitConversions) {
rs_std::isize val = -42;
std::intptr_t raw = val;
EXPECT_EQ(raw, -42);
}

TEST(IsizeTest, ArithmeticAndComparisons) {
rs_std::isize a = -10;
rs_std::isize b = 20;
EXPECT_LT(a, b);
EXPECT_EQ(a + b, rs_std::isize(10));
EXPECT_EQ(b - a, rs_std::isize(30));
}

} // namespace
Loading