Skip to content

Commit 016a7d2

Browse files
committed
Allow CTAD for fine::Ok and fine::Error
Class Template Argument Deduction allows class templates to be inferred from constructor arguments, which removes the need for `fine::ok` and `fine::error` as special factory functions.
1 parent 662c321 commit 016a7d2

File tree

3 files changed

+32
-54
lines changed

3 files changed

+32
-54
lines changed

README.md

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -470,27 +470,26 @@ When it comes to NIFs, errors often indicate unexpected failures and
470470
raising an exception makes sense, however you may also want to handle
471471
certain errors gracefully by returning `:ok`/`:error` tuples, similarly
472472
to usual Elixir functions. Fine provides `Ok<Args...>` and `Error<Args...>`
473-
types for this purpose, along with their respective factories `fine::ok` and
474-
`fine::error`:
473+
types for this purpose.
475474
476475
```c++
477476
fine::Ok<> example() {
478-
return fine::ok();
477+
return fine::Ok();
479478
}
480479
// :ok
481480
482481
fine::Ok<int64_t> example() {
483-
return fine::ok(1); // implicit conversion
482+
return fine::Ok(1);
484483
}
485484
// {:ok, 1}
486485
487486
fine::Error<> example() {
488-
return fine::error();
487+
return fine::Error();
489488
}
490489
// :error
491490
492491
fine::Error<std::string> example() {
493-
return fine::error("something went wrong"); // implicit conversion
492+
return fine::Error("something went wrong");
494493
}
495494
// {:error, "something went wrong"}
496495
```
@@ -499,12 +498,12 @@ You can use `std::variant` to express a union of possible result types
499498
a NIF may return:
500499
501500
```c++
502-
std::variant<fine::Ok<int64_t>, fine::Error<std::string>> find_meaning(ErlNifEnv *env) {
503-
if (...) {
504-
return fine::error("something went wrong");
501+
std::variant<fine::Ok<int64_t, int64_t>, fine::Error<std::string>> divmod(ErlNifEnv *env, int64_t a, int64_t b) {
502+
if (b == 0) {
503+
return fine::Error("division by zero");
505504
}
506505
507-
return fine::ok(42);
506+
return fine::Ok(a / b, a % b);
508507
}
509508
```
510509

c_include/fine.hpp

Lines changed: 14 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -142,38 +142,27 @@ class Term {
142142
ERL_NIF_TERM term;
143143
};
144144

145-
namespace __private__ {
146-
template <class T> struct UnwrapRefwrapper {
147-
using type = T;
148-
};
149-
150-
template <class T> struct UnwrapRefwrapper<std::reference_wrapper<T>> {
151-
using type = T &;
152-
};
153-
154-
template <class T>
155-
using UnwrapDecayType =
156-
typename UnwrapRefwrapper<typename std::decay<T>::type>::type;
157-
} // namespace __private__
158-
159145
// Represents a `:ok` tagged tuple, useful as a NIF result.
160146
template <typename... Args> class Ok {
161147
public:
162148
using Items = std::tuple<Args...>;
163149

164-
Ok(Items &&items) : m_items(std::forward<Items>(items)) {}
150+
template <typename = std::enable_if_t<std::is_default_constructible_v<Items>>>
151+
Ok() : m_items() {}
152+
153+
explicit Ok(Args... items) : m_items{std::move(items)...} {}
165154

166155
template <typename... UArgs>
167-
Ok(const Ok<UArgs...> &other) : m_items{other.items()} {}
156+
Ok(const Ok<UArgs...> &other) : m_items(other.items()) {}
168157

169158
template <typename... UArgs>
170-
Ok(Ok<UArgs...> &&other) : m_items{other.items()} {}
159+
Ok(Ok<UArgs...> &&other) : m_items(std::move(other).items()) {}
171160

172161
const Items &items() const & noexcept { return m_items; }
173162

174163
Items &items() & noexcept { return m_items; }
175164

176-
Items &&items() && noexcept { return m_items; }
165+
Items &&items() && noexcept { return std::move(m_items); }
177166

178167
private:
179168
std::tuple<Args...> m_items;
@@ -184,37 +173,27 @@ template <typename... Args> class Error {
184173
public:
185174
using Items = std::tuple<Args...>;
186175

187-
Error(Items &&items) : m_items(std::forward<Items>(items)) {}
176+
template <typename = std::enable_if_t<std::is_default_constructible_v<Items>>>
177+
Error() : m_items() {}
178+
179+
explicit Error(Args... items) : m_items{std::move(items)...} {}
188180

189181
template <typename... UArgs>
190-
Error(const Error<UArgs...> &other) : m_items{other.items()} {}
182+
Error(const Error<UArgs...> &other) : m_items(other.items()) {}
191183

192184
template <typename... UArgs>
193-
Error(Error<UArgs...> &&other) : m_items{other.items()} {}
185+
Error(Error<UArgs...> &&other) : m_items(std::move(other).items()) {}
194186

195187
const Items &items() const & noexcept { return m_items; }
196188

197189
Items &items() & noexcept { return m_items; }
198190

199-
Items &&items() && noexcept { return m_items; }
191+
Items &&items() && noexcept { return std::move(m_items); }
200192

201193
private:
202194
std::tuple<Args...> m_items;
203195
};
204196

205-
template <typename... Args>
206-
inline static Ok<__private__::UnwrapDecayType<Args>...> ok(Args &&...args) {
207-
return Ok<__private__::UnwrapDecayType<Args>...>{
208-
std::make_tuple(std::forward<Args>(args)...)};
209-
}
210-
211-
template <typename... Args>
212-
inline static Error<__private__::UnwrapDecayType<Args>...>
213-
error(Args &&...args) {
214-
return Error<__private__::UnwrapDecayType<Args>...>{
215-
std::make_tuple(std::forward<Args>(args)...)};
216-
}
217-
218197
namespace __private__ {
219198
template <typename T> struct ResourceWrapper {
220199
T resource;

test/c_src/finest.cpp

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -144,32 +144,32 @@ FINE_NIF(codec_tuple_int64_and_string, 0);
144144

145145
Result<std::string, int64_t> codec_result_string_int64_ok(ErlNifEnv *,
146146
std::string term) {
147-
return fine::ok(term);
147+
return fine::Ok(term);
148148
}
149149
FINE_NIF(codec_result_string_int64_ok, 0);
150150

151151
Result<std::string, int64_t> codec_result_string_int64_error(ErlNifEnv *,
152152
int64_t term) {
153-
return fine::error(term);
153+
return fine::Error(term);
154154
}
155155
FINE_NIF(codec_result_string_int64_error, 0);
156156

157157
Result<std::string, int64_t>
158158
codec_result_string_int64_ok_conversion(ErlNifEnv *) {
159-
return fine::ok("fine");
159+
return fine::Ok("fine");
160160
}
161161
FINE_NIF(codec_result_string_int64_ok_conversion, 0);
162162

163163
Result<std::string, int64_t>
164164
codec_result_string_int64_error_conversion(ErlNifEnv *) {
165165
uint16_t result = 42;
166-
return fine::error(result);
166+
return fine::Error(result);
167167
}
168168
FINE_NIF(codec_result_string_int64_error_conversion, 0);
169169

170170
std::variant<fine::Ok<int64_t, std::string>, fine::Error<>>
171171
codec_result_int64_string_void_ok_conversion(ErlNifEnv *) {
172-
return fine::ok(static_cast<int32_t>(201702), "c++17");
172+
return fine::Ok(static_cast<int32_t>(201702), "c++17");
173173
}
174174
FINE_NIF(codec_result_int64_string_void_ok_conversion, 0);
175175

@@ -197,19 +197,19 @@ FINE_NIF(codec_struct, 0);
197197
ExError codec_struct_exception(ErlNifEnv *, ExError term) { return term; }
198198
FINE_NIF(codec_struct_exception, 0);
199199

200-
fine::Ok<> codec_ok_empty(ErlNifEnv *) { return fine::ok(); }
200+
fine::Ok<> codec_ok_empty(ErlNifEnv *) { return fine::Ok(); }
201201
FINE_NIF(codec_ok_empty, 0);
202202

203203
fine::Ok<int64_t> codec_ok_int64(ErlNifEnv *, int64_t term) {
204-
return fine::ok(term);
204+
return fine::Ok(term);
205205
}
206206
FINE_NIF(codec_ok_int64, 0);
207207

208-
fine::Error<> codec_error_empty(ErlNifEnv *) { return fine::error(); }
208+
fine::Error<> codec_error_empty(ErlNifEnv *) { return fine::Error(); }
209209
FINE_NIF(codec_error_empty, 0);
210210

211211
fine::Error<std::string> codec_error_string(ErlNifEnv *, std::string term) {
212-
return fine::error(term);
212+
return fine::Error(term);
213213
}
214214
FINE_NIF(codec_error_string, 0);
215215

0 commit comments

Comments
 (0)