99
1010namespace zest {
1111
12- // custom error types inherit from the ResultError class, which enforces that custom error types
13- // have some shared functionality.
12+ /* *
13+ * @brief Base class for custom error types used in the Result class.
14+ * @details Enforces stacktrace and timestamp functionality for derived error types.
15+ */
1416class ResultError {
1517 public:
16- // since this constructor has no arguments, it'll be called implicitly by the constructor of any
17- // child class.
18+ /* *
19+ * @brief Construct a new ResultError object.
20+ * @details Captures the current stacktrace and system time automatically.
21+ */
1822 ResultError ()
1923 : stacktrace(std::stacktrace::current()),
2024 time (std::chrono::system_clock::now()) {}
2125
22- std::stacktrace stacktrace;
23- std::chrono::time_point<std::chrono::system_clock> time;
26+ std::stacktrace stacktrace; // /< Captured stacktrace at error creation.
27+ std::chrono::time_point<std::chrono::system_clock> time; // /< Timestamp of error creation.
2428};
2529
26- // Some primitive types such as float, double, etc may have a standardized "sentinel" value.
27- // For example, a function that returns a float may return INFINITY if an error occurs .
28- // Usually the maximum value of the type is returned if there is an error .
29- // This trait helps simplify DX .
30- // This trait can also be specialized for custom types (e.g unitized types)
30+ /* *
31+ * @brief Trait to define a "sentinel" value for types indicating an error state .
32+ * @tparam T Type to provide a sentinel value for .
33+ * @note Specialize this template for custom types if needed .
34+ */
3135template <typename T>
3236class SentinelValue ;
3337
34- // concept which can be used to determine if a type has a sentinel value
38+ /* *
39+ * @brief Concept to check if a type has a defined sentinel value.
40+ * @tparam T Type to check.
41+ */
3542template <typename T>
3643concept Sentinel = requires (const T& val) { SentinelValue<T>::value; };
3744
38- // templated variable which can be used to simplify usage of HasSentinel
45+ /* *
46+ * @brief Helper variable to simplify access to a type's sentinel value.
47+ * @tparam T Type with a defined sentinel (must satisfy Sentinel concept).
48+ */
3949template <Sentinel T>
4050constexpr T sentinel_v = SentinelValue<T>::value;
4151
42- // partial specialization for HasSentinel.
43- // any integral type (e.g double, int, uint8, etc) has a sentinel value equal to its maximum value.
44- // floating-point numbers with infinity support have sentinel values equal to infinity.
52+ /* *
53+ * @brief Partial specialization of SentinelValue for integral and floating-point types.
54+ * @tparam T Integral or floating-point type.
55+ * @details Uses infinity for floating-point types if available; otherwise uses max value.
56+ */
4557template <typename T>
46- requires (std::integral<T> || std::floating_point<T>)
58+ requires (std::integral<T> || std::floating_point<T>)
4759class SentinelValue <T> {
4860 public:
4961 static constexpr T get () {
@@ -54,49 +66,60 @@ class SentinelValue<T> {
5466 }
5567 }
5668
57- static constexpr T value = get();
69+ static constexpr T value = get(); // /< Precomputed sentinel value for type T.
5870};
5971
60- // Result class.
61- // An alternative to std::expected, where an expected value can be contained alongside an unexpected
62- // error value.
63- // This means that Result will always contain an expected value.
64- // Therefore, if the user does not check if a function returned an error, an exception will NOT be
65- // thrown, and therefore the thread won't crash.
66- // Constraint: requires at least 1 possible Error type
67- // Constraint: Error types must inherit from ResultError
72+ /* *
73+ * @brief Result class for expected value or error handling (similar to std::expected).
74+ * @tparam T Type of the expected value.
75+ * @tparam Errs List of possible error types (must inherit from ResultError).
76+ * @note Errors are stored in a variant, and the value is always initialized.
77+ */
6878template <typename T, typename ... Errs>
6979 requires (sizeof ...(Errs) > 0 ) && (std::derived_from<Errs, ResultError> && ...)
7080class Result {
7181 public:
72- // Construct a Result with a value and no error value.
73- // Constraint: type T can be constructed from type U
82+ /* *
83+ * @brief Construct a Result with a normal value (no error).
84+ * @tparam U Type convertible to T.
85+ * @param value Value to initialize the result with.
86+ */
7487 template <typename U>
7588 requires std::constructible_from<T, U>
7689 constexpr Result (U&& value)
7790 : error(std::monostate()),
7891 value(std::forward<U>(value)) {}
7992
80- // Construct a Result with a value and an error value.
81- // Constraint: type T can be constructed from type U
82- // Constraint: E in Errs
93+ /* *
94+ * @brief Construct a Result with a value and an error.
95+ * @tparam U Type convertible to T.
96+ * @tparam E Error type (must be in Errs).
97+ * @param value Value to store.
98+ * @param error Error to store.
99+ */
83100 template <typename U, typename E>
84101 requires std::constructible_from<T, U> && (std::same_as<std::remove_cvref<E>, Errs> || ...)
85102 constexpr Result (U&& value, E&& error)
86103 : value(std::forward<U>(value)),
87104 error(std::forward<E>(error)) {}
88105
89- // Construct a Result with an error, initializing the normal value to its sentinel value.
90- // Constraint: type T has a sentinel value
91- // Constraint: E in Errs
106+ /* *
107+ * @brief Construct a Result with an error, initializing the value to its sentinel.
108+ * @tparam E Error type (must be in Errs).
109+ * @param error Error to store.
110+ * @note Requires T to have a defined sentinel value (via SentinelValue<T>).
111+ */
92112 template <typename E>
93113 requires Sentinel<T> && (std::same_as<std::remove_cvref<E>, Errs> || ...)
94114 constexpr Result (E&& error)
95115 : error(std::forward<E>(error)),
96116 value(sentinel_v<T>) {}
97117
98- // Get the given error type, if it exists
99- // Constraint: E in Errs
118+ /* *
119+ * @brief Get an error of type E if present (const-qualified overload).
120+ * @tparam E Error type to retrieve.
121+ * @return std::optional<E> Contains the error if present; otherwise nullopt.
122+ */
100123 template <typename E>
101124 requires (std::same_as<E, Errs> || ...)
102125 constexpr std::optional<E> get () const & {
@@ -107,8 +130,11 @@ class Result {
107130 }
108131 }
109132
110- // Get the given error type, if it exists
111- // Constraint: E in Errs
133+ /* *
134+ * @brief Get an error of type E if present (rvalue overload).
135+ * @tparam E Error type to retrieve.
136+ * @return std::optional<E> Contains the error if present; otherwise nullopt.
137+ */
112138 template <typename E>
113139 requires (std::same_as<E, Errs> || ...)
114140 constexpr std::optional<E> get () && {
@@ -119,63 +145,86 @@ class Result {
119145 }
120146 }
121147
122- // get the normal value
148+ /* *
149+ * @brief Get the stored value (const-qualified overload).
150+ * @return T Copy of the stored value.
151+ */
123152 template <typename U = T>
124153 requires std::same_as<U, T>
125154 constexpr T get () const & {
126155 return value;
127156 }
128157
129- // get the normal value
158+ /* *
159+ * @brief Get the stored value (rvalue overload).
160+ * @return T Moved value.
161+ */
130162 template <typename U = T>
131163 requires std::same_as<U, T>
132164 constexpr T get () && {
133165 return std::move (value);
134166 }
135167
136- // implicit conversion operator
168+ /* *
169+ * @brief Implicit conversion to the stored value (const-qualified).
170+ */
137171 constexpr operator T () const & {
138172 return value;
139173 };
140174
141- // implicit conversion operator
175+ /* *
176+ * @brief Implicit conversion to the stored value (rvalue).
177+ */
142178 constexpr operator T () && {
143179 return std::move (value);
144180 }
145181
146- // comparison operator overload
182+ /* *
183+ * @brief Equality comparison operator.
184+ * @tparam U Type of the other result's value.
185+ * @tparam Es Other result's error types.
186+ * @param other Result to compare with.
187+ * @return true If values are equal.
188+ */
147189 template <typename U, typename ... Es>
148190 requires std::equality_comparable_with<T, U>
149191 constexpr bool operator ==(const Result<U, Es...>& other) {
150192 return value == other.value ;
151193 }
152194
153- // a variant that could contain any of the specified error types
154- std::variant<std::monostate, Errs...> error;
155- // the normal value
156- T value;
195+ std::variant<std::monostate, Errs...> error; // /< Variant holding an error or monostate.
196+ T value; // /< The stored value (always initialized).
157197};
158198
159- // Result specialization for a value of type void, which would otherwise be impossible.
160- // This specialization simply does not hold a "normal" value
161- // Constraint: requires at least 1 possible Error type
162- // Constraint: Error types must inherit from ResultError
199+ /* *
200+ * @brief Result specialization for void value type (no stored value).
201+ * @tparam Errs List of possible error types (must inherit from ResultError).
202+ */
163203template <typename ... Errs>
164204 requires (sizeof ...(Errs) > 0 ) && (std::derived_from<Errs, ResultError> && ...)
165205class Result <void , Errs...> {
166206 public:
167- // construct with an error value
207+ /* *
208+ * @brief Construct a Result with an error.
209+ * @tparam E Error type (must be in Errs).
210+ * @param error Error to store.
211+ */
168212 template <typename E>
169213 requires (std::same_as<std::remove_cvref<E>, Errs> || ...)
170214 constexpr Result (E&& error)
171215 : error(std::forward<E>(error)) {}
172216
173- // construct with no error value
217+ /* *
218+ * @brief Construct a Result with no error (success state).
219+ */
174220 constexpr Result ()
175221 : error(std::monostate()) {}
176222
177- // Get the given error type, if it exists
178- // Constraint: E in Errs
223+ /* *
224+ * @brief Get an error of type E if present (const-qualified overload).
225+ * @tparam E Error type to retrieve.
226+ * @return std::optional<E> Contains the error if present; otherwise nullopt.
227+ */
179228 template <typename E>
180229 requires (std::same_as<E, Errs> || ...)
181230 constexpr std::optional<E> get () const & {
@@ -186,8 +235,11 @@ class Result<void, Errs...> {
186235 }
187236 }
188237
189- // Get the given error type, if it exists
190- // Constraint: E in Errs
238+ /* *
239+ * @brief Get an error of type E if present (rvalue overload).
240+ * @tparam E Error type to retrieve.
241+ * @return std::optional<E> Contains the error if present; otherwise nullopt.
242+ */
191243 template <typename E>
192244 requires (std::same_as<E, Errs> || ...)
193245 constexpr std::optional<E> get () && {
@@ -198,6 +250,7 @@ class Result<void, Errs...> {
198250 }
199251 }
200252
201- std::variant<std::monostate, Errs...> error;
253+ std::variant<std::monostate, Errs...> error; // /< Variant holding an error or monostate.
202254};
255+
203256} // namespace zest
0 commit comments