Skip to content

Add Transmogrify concept with sus::mog<T>() #289

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 17 commits into from
Jul 31, 2023
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
6 changes: 6 additions & 0 deletions STYLE.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,9 @@ footguns, crashes, bugs, and UB.
* They don't mutate through a global or parameter mutable reference or pointer.
* Thus they don't have observable side effects. Calling them on the same input
values multiple times always produces the same output.
* Additionally, if the function does not deref a pointer, access through
a reference, or access any static variables, it may be marked
`sus_pure_const`.
1. If a type has implicit ctor from T then it should have assignment from T.
The same is not true for an explicit ctor: no assignment should be present
for that type.
3 changes: 3 additions & 0 deletions subspace/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ target_sources(subspace PUBLIC
"num/__private/unsigned_integer_consts.inc"
"num/__private/unsigned_integer_methods.inc"
"num/__private/unsigned_integer_methods_impl.inc"
"num/transmogrify.h"
"num/float.h"
"num/float_concepts.h"
"num/float_impl.h"
Expand Down Expand Up @@ -225,6 +226,7 @@ if(${SUBSPACE_BUILD_TESTS})
"choice/choice_types_unittest.cc"
"choice/choice_unittest.cc"
"convert/subclass_unittest.cc"
"construct/to_bits_unittest.cc"
"containers/array_unittest.cc"
"containers/invalidation_off_size_unittest.cc"
"containers/invalidation_on_size_unittest.cc"
Expand Down Expand Up @@ -258,6 +260,7 @@ if(${SUBSPACE_BUILD_TESTS})
"mem/take_unittest.cc"
"num/__private/literals_unittest.cc"
"num/cmath_macros_unittest.cc"
"num/transmogrify_unittest.cc"
"num/f32_unittest.cc"
"num/f64_unittest.cc"
"num/i8_unittest.cc"
Expand Down
4 changes: 2 additions & 2 deletions subspace/choice/choice_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ TEST(Choice, ConstructorFunction1Value) {
}
{
// into() as an input to the tuple.
U u = sus::choice<Order::First>(sus::into(1));
U u = sus::choice<Order::First>(sus::into(1_u16));
EXPECT_EQ(u.as<Order::First>(), 1_u32);
}
{
Expand Down Expand Up @@ -187,7 +187,7 @@ TEST(Choice, ConstructorFunctionMoreThan1Value) {
}
{
// into() as an input to the tuple.
U u = sus::choice<Order::First>(1u, sus::into(2));
U u = sus::choice<Order::First>(1u, sus::into(2_u16));
EXPECT_EQ(u.as<Order::First>().into_inner<0>(), 1_u32);
EXPECT_EQ(u.as<Order::First>().into_inner<1>(), 2_u32);
}
Expand Down
11 changes: 5 additions & 6 deletions subspace/construct/from.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

#include <concepts>

#include "subspace/mem/forward.h"
#include "subspace/result/__private/is_result_type.h"

namespace sus::construct {
Expand Down Expand Up @@ -48,7 +49,7 @@ namespace sus::construct {
/// ```
template <class ToType, class FromType>
concept From = requires(FromType&& from) {
{ ToType::from(static_cast<FromType&&>(from)) } -> std::same_as<ToType>;
{ ToType::from(::sus::forward<FromType>(from)) } -> std::same_as<ToType>;
};

/// A concept that indicates `ToType` can be (sometimes) constructed from a
Expand All @@ -59,11 +60,9 @@ concept From = requires(FromType&& from) {
/// `sus::Result`.
template <class ToType, class FromType>
concept TryFrom = requires(FromType&& from) {
{ ToType::try_from(static_cast<FromType&&>(from)) };
requires std::same_as<
typename ::sus::result::__private::IsResultType<decltype(ToType::try_from(
static_cast<FromType&&>(from)))>::ok_type,
ToType>;
{
ToType::try_from(::sus::forward<FromType>(from))
} -> ::sus::result::__private::IsResultWithSuccessType<ToType>;
};

} // namespace sus::construct
22 changes: 22 additions & 0 deletions subspace/construct/from_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@
#include "subspace/construct/from.h"

#include "subspace/construct/into.h"
#include "subspace/result/result.h"

using sus::construct::From;
using sus::construct::TryFrom;

namespace {

Expand Down Expand Up @@ -44,4 +46,24 @@ static_assert(!From<WithFromS, int>);
static_assert(!From<FromReturnsVoid, int>);
static_assert(!From<FromReturnsElse, int>);

enum Error {};

struct TryYes {
static sus::Result<TryYes, Error> try_from(S) { return sus::ok(TryYes()); }
};
struct TryNoResult {
static TryYes try_from(S) { return TryYes(); }
};
struct TryWrongResult {
static sus::Result<S, Error> try_from(S) { return sus::ok(S()); }
};
struct TryVoidResult {
static sus::Result<void, Error> try_from(S) { return sus::ok(); }
};

static_assert(TryFrom<TryYes, S>);
static_assert(!TryFrom<TryNoResult, S>);
static_assert(!TryFrom<TryWrongResult, S>);
static_assert(!TryFrom<TryVoidResult, S>);

} // namespace
49 changes: 36 additions & 13 deletions subspace/construct/into.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,12 @@
#include "subspace/construct/__private/into_ref.h"
#include "subspace/construct/from.h"
#include "subspace/macros/compiler.h"
#include "subspace/macros/lifetimebound.h"
#include "subspace/mem/forward.h"

namespace sus::construct {

/// A concept that declares `FromType` can be converted to `ToType`, through the
/// A concept that declares `FromType` can be converted to `ToType` through the
/// `From` concept or through an identity transformation.
///
/// When true, `ToType::from(FromType)` can be used to construct `ToType`,
Expand Down Expand Up @@ -84,25 +86,22 @@ template <class FromType>
requires(!std::is_const_v<std::remove_reference_t<FromType>> &&
std::is_rvalue_reference_v<FromType &&> &&
!std::is_array_v<FromType>)
constexpr inline auto into(
FromType&& from sus_if_clang([[clang::lifetimebound]])) noexcept {
constexpr inline auto into(FromType&& from sus_lifetimebound) noexcept {
return __private::IntoRef(
static_cast<std::remove_reference_t<FromType>&&>(from));
}

template <class FromType>
requires(std::is_trivially_copyable_v<FromType> && !std::is_array_v<FromType>)
constexpr inline auto into(
const FromType& from sus_if_clang([[clang::lifetimebound]])) noexcept {
constexpr inline auto into(const FromType& from sus_lifetimebound) noexcept {
return __private::IntoRef<const FromType&>(from);
}

template <class FromType>
requires(!std::is_const_v<std::remove_reference_t<FromType>> &&
std::is_trivially_move_constructible_v<FromType> &&
!std::is_array_v<FromType>)
constexpr inline auto into(
FromType& from sus_if_clang([[clang::lifetimebound]])) noexcept {
constexpr inline auto into(FromType& from sus_lifetimebound) noexcept {
return __private::IntoRef(
static_cast<std::remove_reference_t<FromType>&&>(from));
}
Expand All @@ -113,7 +112,7 @@ constexpr inline auto into(
/// satisfied.
template <class FromType, size_t N>
constexpr inline auto array_into(
FromType (&from)[N] sus_if_clang([[clang::lifetimebound]])) noexcept {
FromType (&from)[N] sus_lifetimebound) noexcept {
return __private::IntoRefArray<FromType, N>(from);
}

Expand All @@ -128,8 +127,7 @@ constexpr inline auto array_into(
template <class FromType>
requires(!std::is_const_v<std::remove_reference_t<FromType>> &&
!std::is_array_v<FromType>)
constexpr inline auto move_into(
FromType& from sus_if_clang([[clang::lifetimebound]])) noexcept {
constexpr inline auto move_into(FromType& from sus_lifetimebound) noexcept {
return __private::IntoRef(
static_cast<std::remove_cv_t<std::remove_reference_t<FromType>>&&>(from));
}
Expand All @@ -138,13 +136,37 @@ template <class FromType>
requires(std::is_rvalue_reference_v<FromType &&> &&
!std::is_const_v<std::remove_reference_t<FromType>> &&
!std::is_array_v<FromType>)
constexpr inline auto move_into(
FromType&& from sus_if_clang([[clang::lifetimebound]])) noexcept {
constexpr inline auto move_into(FromType&& from sus_lifetimebound) noexcept {
return __private::IntoRef(
static_cast<std::remove_cv_t<std::remove_reference_t<FromType>>&&>(from));
}

// TODO: Consider adding sus::try_into() and a TryInto concept?
/// A concept that declares `FromType` can (sometimes) be converted to `ToType`
/// through the `TryFrom` concept or through an identity transformation.
template <class FromType, class ToType>
concept TryInto = ::sus::construct::TryFrom<ToType, FromType> ||
std::same_as<ToType, FromType>;

/// Attempts to convert from the given value to a `ToType`.
///
/// Unlike `into()`, this function can not use type deduction to determine the
/// receiving type as it needs to determine the Result type and allow the caller
/// the chance to handle the error condition.
///
/// The `TryFrom` concept requires a `try_from()` method that returns a
/// `Result`. That `Result` will be the return type of this function.
///
/// # Example
/// ```
/// auto valid = sus::try_into<u8>(123_i32).unwrap_or_default();
/// sus::check(valid == 123);
/// auto invalid = sus::try_into<u8>(-1_i32).unwrap_or_default();
/// sus::check(invalid == 0);
/// ```
template <class ToType, TryInto<ToType> FromType>
constexpr inline auto try_into(FromType&& from) noexcept {
return ToType::try_from(::sus::forward<FromType>(from));
}

} // namespace sus::construct

Expand All @@ -153,4 +175,5 @@ namespace sus {
using ::sus::construct::array_into;
using ::sus::construct::into;
using ::sus::construct::move_into;
using ::sus::construct::try_into;
} // namespace sus
8 changes: 8 additions & 0 deletions subspace/construct/into_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "googletest/include/gtest/gtest.h"
#include "subspace/macros/__private/compiler_bugs.h"
#include "subspace/mem/forward.h"
#include "subspace/prelude.h"
#include "subspace/test/behaviour_types.h"

using sus::construct::From;
Expand Down Expand Up @@ -156,4 +157,11 @@ TEST(Into, Concept) {
EXPECT_EQ(f(S(3)).got_value, 3);
}

TEST(TryInto, Example) {
auto valid = sus::try_into<u8>(123_i32).unwrap_or_default();
sus::check(valid == 123u);
auto invalid = sus::try_into<u8>(-1_i32).unwrap_or_default();
sus::check(invalid == 0u);
}

} // namespace
Loading