farm-ng-core
expected.h
Go to the documentation of this file.
1 // Copyright 2022, farm-ng inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #pragma once
16 
18 
19 #include <tl/expected.hpp>
20 
21 #include <iostream>
22 #include <optional>
23 #include <string>
24 #include <vector>
25 
26 namespace farm_ng {
27 
28 struct Error {
29  std::vector<ErrorDetail> details;
30 };
31 
32 std::ostream& operator<<(std::ostream& os, Error const& error);
33 
34 struct Success {};
35 
36 template <class TT, class TE = Error>
37 using Expected = tl::expected<TT, TE>;
38 
39 namespace details {
40 
41 template <class TT, class TE>
42 struct UnwrapImpl<tl::expected<TT, TE>> {
43  static auto impl(
44  tl::expected<TT, TE>& wrapper,
45  char const* wrapper_cstr,
46  ::farm_ng::ErrorDetail detail) -> decltype(*wrapper) {
47  if (!bool(wrapper)) {
49  "[FARM_UNWRAP failed in {}:{}]", detail.file, detail.line);
51  "expected type `{}` does not contain a valid value", wrapper_cstr);
52  if (!detail.msg.empty()) {
53  ::fmt::print(stderr, "{}", detail.msg);
54  }
55  ::fmt::print(stderr, "{}", wrapper.error());
57  }
58  return *wrapper;
59  }
60 };
61 } // namespace details
62 } // namespace farm_ng
63 
64 // You might want to disable callstacks in tests where one wishes to compare
65 // exact strings of error messages.
66 #ifdef FARM_ERROR_CALLSTACK_DISABLED
67 
68 #define FARM_ERROR_DETAIL(...) \
69  ::farm_ng::ErrorDetail { \
70  .file = "n/a", .line = 0, .msg = FARM_FORMAT(__VA_ARGS__) \
71  }
72 
73 #else
74 
75 #define FARM_ERROR_DETAIL(...) \
76  ::farm_ng::ErrorDetail { \
77  .file = __FILE__, .line = __LINE__, .msg = FARM_FORMAT(__VA_ARGS__) \
78  }
79 #endif
80 
81 #define FARM_ERROR_REPORT(cstr, ...) \
82  ::farm_ng::Error { \
83  .details = { FARM_ERROR_DETAIL(cstr, ##__VA_ARGS__) } \
84  }
85 
86 #define FARM_UNEXPECTED(cstr, ...) \
87  ::tl::make_unexpected(FARM_ERROR_REPORT(cstr, ##__VA_ARGS__))
88 
89 /// Assigns `*expression` to `var` of `Type`, but returns error if there is
90 /// one.
91 #define FARM_TRY(Type, var, expression) \
92  auto maybe##var = (expression); \
93  if (!maybe##var) { \
94  auto error = maybe##var.error(); \
95  error.details.emplace_back( \
96  FARM_ERROR_DETAIL("FARM_TRY propagated error.\n")); \
97  return ::tl::make_unexpected(error); \
98  } \
99  Type var = ::std::move(*maybe##var);
100 
101 #define FARM_ASSERT_OR_ERROR(condition, ...) \
102  if (!(condition)) { \
103  return FARM_UNEXPECTED( \
104  "bool({}) not true.\n{}", #condition, FARM_FORMAT(__VA_ARGS__)); \
105  } \
106  do { \
107  } while (false)
108 
109 namespace farm_ng {
110 template <class TT, class TE = Error>
112  return expected ? std::optional<TT>(std::move(*expected)) : std::nullopt;
113 }
114 
115 template <class TT>
116 Expected<TT> fromOptional(std::optional<TT> optional) {
117  return optional ? Expected<TT>(std::move(*optional))
118  : FARM_UNEXPECTED("std::nullopt");
119 }
120 
121 } // namespace farm_ng
farm_ng
Definition: backtrace.cpp:102
FARM_IMPL_LOG_PRINTLN
#define FARM_IMPL_LOG_PRINTLN(...)
Definition: format.h:56
farm_ng::ErrorDetail
Definition: logger.h:401
farm_ng::fromExpected
std::optional< TT > fromExpected(Expected< TT, TE > expected)
Definition: expected.h:111
logger.h
farm_ng::Error
Definition: expected.h:28
farm_ng::details::UnwrapImpl
Definition: logger.h:503
farm_ng::operator<<
auto operator<<(std::ostream &os, Error const &error) -> std::ostream &
Definition: expected.cpp:19
expected
farm_ng_core_logging Console string format and CHECK macros Depends on expected(both part of future c++standards)
farm_ng::details::UnwrapImpl< tl::expected< TT, TE > >::impl
static auto impl(tl::expected< TT, TE > &wrapper, char const *wrapper_cstr, ::farm_ng::ErrorDetail detail) -> decltype(*wrapper)
Definition: expected.h:43
farm_ng::Error::details
std::vector< ErrorDetail > details
Definition: expected.h:29
FARM_UNEXPECTED
#define FARM_UNEXPECTED(cstr,...)
Definition: expected.h:86
farm_ng::fromOptional
Expected< TT > fromOptional(std::optional< TT > optional)
Definition: expected.h:116
FARM_IMPL_ABORT
#define FARM_IMPL_ABORT()
Definition: format.h:62
farm_ng::Expected
tl::expected< TT, TE > Expected
Definition: expected.h:37
farm_ng::Success
Definition: expected.h:34