22
22
#include " subspace/construct/__private/into_ref.h"
23
23
#include " subspace/construct/from.h"
24
24
#include " subspace/macros/compiler.h"
25
+ #include " subspace/macros/lifetimebound.h"
26
+ #include " subspace/mem/forward.h"
25
27
26
28
namespace sus ::construct {
27
29
28
- // / A concept that declares `FromType` can be converted to `ToType`, through the
30
+ // / A concept that declares `FromType` can be converted to `ToType` through the
29
31
// / `From` concept or through an identity transformation.
30
32
// /
31
33
// / When true, `ToType::from(FromType)` can be used to construct `ToType`,
@@ -84,25 +86,22 @@ template <class FromType>
84
86
requires (!std::is_const_v<std::remove_reference_t <FromType>> &&
85
87
std::is_rvalue_reference_v<FromType &&> &&
86
88
!std::is_array_v<FromType>)
87
- constexpr inline auto into (
88
- FromType&& from sus_if_clang ([[clang::lifetimebound]])) noexcept {
89
+ constexpr inline auto into (FromType&& from sus_lifetimebound) noexcept {
89
90
return __private::IntoRef (
90
91
static_cast <std::remove_reference_t <FromType>&&>(from));
91
92
}
92
93
93
94
template <class FromType >
94
95
requires (std::is_trivially_copyable_v<FromType> && !std::is_array_v<FromType>)
95
- constexpr inline auto into(
96
- const FromType& from sus_if_clang ([[clang::lifetimebound]])) noexcept {
96
+ constexpr inline auto into (const FromType& from sus_lifetimebound) noexcept {
97
97
return __private::IntoRef<const FromType&>(from);
98
98
}
99
99
100
100
template <class FromType >
101
101
requires (!std::is_const_v<std::remove_reference_t <FromType>> &&
102
102
std::is_trivially_move_constructible_v<FromType> &&
103
103
!std::is_array_v<FromType>)
104
- constexpr inline auto into(
105
- FromType& from sus_if_clang ([[clang::lifetimebound]])) noexcept {
104
+ constexpr inline auto into (FromType& from sus_lifetimebound) noexcept {
106
105
return __private::IntoRef (
107
106
static_cast <std::remove_reference_t <FromType>&&>(from));
108
107
}
@@ -113,7 +112,7 @@ constexpr inline auto into(
113
112
// / satisfied.
114
113
template <class FromType , size_t N>
115
114
constexpr inline auto array_into (
116
- FromType (&from)[N] sus_if_clang([[clang::lifetimebound]]) ) noexcept {
115
+ FromType (&from)[N] sus_lifetimebound ) noexcept {
117
116
return __private::IntoRefArray<FromType, N>(from);
118
117
}
119
118
@@ -128,8 +127,7 @@ constexpr inline auto array_into(
128
127
template <class FromType >
129
128
requires (!std::is_const_v<std::remove_reference_t <FromType>> &&
130
129
!std::is_array_v<FromType>)
131
- constexpr inline auto move_into(
132
- FromType& from sus_if_clang ([[clang::lifetimebound]])) noexcept {
130
+ constexpr inline auto move_into(FromType& from sus_lifetimebound) noexcept {
133
131
return __private::IntoRef (
134
132
static_cast <std::remove_cv_t <std::remove_reference_t <FromType>>&&>(from));
135
133
}
@@ -138,13 +136,37 @@ template <class FromType>
138
136
requires (std::is_rvalue_reference_v<FromType &&> &&
139
137
!std::is_const_v<std::remove_reference_t <FromType>> &&
140
138
!std::is_array_v<FromType>)
141
- constexpr inline auto move_into(
142
- FromType&& from sus_if_clang ([[clang::lifetimebound]])) noexcept {
139
+ constexpr inline auto move_into(FromType&& from sus_lifetimebound) noexcept {
143
140
return __private::IntoRef (
144
141
static_cast <std::remove_cv_t <std::remove_reference_t <FromType>>&&>(from));
145
142
}
146
143
147
- // TODO: Consider adding sus::try_into() and a TryInto concept?
144
+ // / A concept that declares `FromType` can (sometimes) be converted to `ToType`
145
+ // / through the `TryFrom` concept or through an identity transformation.
146
+ template <class FromType , class ToType >
147
+ concept TryInto = ::sus::construct::TryFrom<ToType, FromType> ||
148
+ std::same_as<ToType, FromType>;
149
+
150
+ // / Attempts to convert from the given value to a `ToType`.
151
+ // /
152
+ // / Unlike `into()`, this function can not use type deduction to determine the
153
+ // / receiving type as it needs to determine the Result type and allow the caller
154
+ // / the chance to handle the error condition.
155
+ // /
156
+ // / The `TryFrom` concept requires a `try_from()` method that returns a
157
+ // / `Result`. That `Result` will be the return type of this function.
158
+ // /
159
+ // / # Example
160
+ // / ```
161
+ // / auto valid = sus::try_into<u8>(123_i32).unwrap_or_default();
162
+ // / sus::check(valid == 123);
163
+ // / auto invalid = sus::try_into<u8>(-1_i32).unwrap_or_default();
164
+ // / sus::check(invalid == 0);
165
+ // / ```
166
+ template <class ToType , TryInto<ToType> FromType>
167
+ constexpr inline auto try_into (FromType&& from) noexcept {
168
+ return ToType::try_from (::sus::forward<FromType>(from));
169
+ }
148
170
149
171
} // namespace sus::construct
150
172
@@ -153,4 +175,5 @@ namespace sus {
153
175
using ::sus::construct::array_into;
154
176
using ::sus::construct::into;
155
177
using ::sus::construct::move_into;
178
+ using ::sus::construct::try_into;
156
179
} // namespace sus
0 commit comments