Skip to content
Open
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
1 change: 1 addition & 0 deletions include/safe.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@
#include <safe/int.hpp>
#include <safe/match.hpp>
#include <safe/object.hpp>
#include <safe/safe_cast.hpp>
#include <safe/value.hpp>
#include <safe/var.hpp>
4 changes: 2 additions & 2 deletions include/safe/detail/fwd.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,12 @@ template <typename T> struct unsafe_cast_ferry {

template <typename T>
requires(safe::Var<T>)
[[nodiscard]] constexpr auto unsafe_cast(auto const &src) {
[[nodiscard]] SAFE_INLINE constexpr auto unsafe_cast(auto const &src) {
return T{safe::unsafe_cast_ferry{src}};
}

template <typename T>
requires(!safe::Var<T>)
[[nodiscard]] constexpr auto unsafe_cast(auto const &src) {
[[nodiscard]] SAFE_INLINE constexpr auto unsafe_cast(auto const &src) {
return src;
}
17 changes: 17 additions & 0 deletions include/safe/safe_cast.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#pragma once

#include <safe/detail/concepts.hpp>
#include <safe/detail/fwd.hpp>
#include <safe/var.hpp>

#include <concepts>

template <typename To, safe::Var From>
requires(std::is_convertible_v<typename From::value_type, To>)
[[nodiscard]] SAFE_INLINE constexpr To safe_cast(From const &src) {
static_assert(safe::detail::integral_type<To>::requirement >=
From::requirement,
"The safe value must fit within the target value type.");

return static_cast<To>(src.unsafe_value_);
}
2 changes: 2 additions & 0 deletions test/safe/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
add_subdirectory(array)
add_subdirectory(var)
add_subdirectory(safe_cast)

function(add_test_suites)
foreach(test_file ${ARGN})
Expand Down Expand Up @@ -34,6 +35,7 @@ add_test_suites(
var.cpp
match.cpp
array.cpp
safe_cast.cpp
dsl/add.cpp
dsl/divide.cpp
dsl/intersection.cpp
Expand Down
33 changes: 33 additions & 0 deletions test/safe/safe_cast.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#include "gmock/gmock.h"
#include "gtest/gtest.h"

#include <cstdint>
#include <type_traits>

#include <safe.hpp>

using ::testing::_;
using ::testing::InSequence;
using ::testing::Return;

using namespace safe::interval_types;
using namespace safe::int_types;
using namespace safe::literals;

TEST(safe_cast_test, cast_same_type) {
auto v = safe_cast<std::int32_t>(42_s32);
EXPECT_EQ(v, 42);
static_assert(std::is_same_v<std::int32_t, decltype(v)>);
}

TEST(safe_cast_test, cast_narrower_type) {
auto v = safe_cast<std::uint8_t>(42_s32);
EXPECT_EQ(v, 42);
static_assert(std::is_same_v<std::uint8_t, decltype(v)>);
}

TEST(safe_cast_test, cast_different_sign) {
auto v = safe_cast<std::uint32_t>(99_s32);
EXPECT_EQ(v, 99);
static_assert(std::is_same_v<std::uint32_t, decltype(v)>);
}
9 changes: 9 additions & 0 deletions test/safe/safe_cast/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
function(add_fail_tests)
foreach(name ${ARGN})
add_compile_fail_test("${name}.cpp" LIBRARIES safe_arithmetic)
endforeach()
endfunction()

add_fail_tests(
incompatible_sign_cast
incompatible_range_cast)
9 changes: 9 additions & 0 deletions test/safe/safe_cast/incompatible_range_cast.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#include <cstdint>

#include <safe.hpp>

using namespace safe::interval_types;
using namespace safe::int_types;
using namespace safe::literals;

auto main() -> int { auto v = safe_cast<std::uint8_t>(420_u32); }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: Add an EXPECT line to ensure a nice error

9 changes: 9 additions & 0 deletions test/safe/safe_cast/incompatible_sign_cast.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#include <cstdint>

#include <safe.hpp>

using namespace safe::interval_types;
using namespace safe::int_types;
using namespace safe::literals;

auto main() -> int { auto v = safe_cast<std::uint32_t>(-99_s32); }