@@ -114,42 +114,185 @@ struct Unit {};
114114/* *
115115 * @brief Functional Result<T> type based on std::variant
116116 *
117- * Type-safe error handling that replaces error codes.
117+ * Provides Rust-style error handling without exceptions or error codes.
118+ * A Result<T> either contains a successful value (Ok) or an error (Err).
119+ *
120+ * Key Benefits:
121+ * - Type-safe: Cannot accidentally ignore errors
122+ * - Composable: Chain operations with match()
123+ * - Zero-cost: No exceptions or dynamic allocation
124+ * - Explicit: Error handling is visible in function signatures
125+ *
126+ * @par Basic Usage:
127+ * @code
128+ * // Function returns Result instead of throwing or returning error codes
129+ * Result<RACoordinate> coord = parse_ra("12:34:56", PrecisionMode::High);
130+ *
131+ * // Check if successful
132+ * if (coord.is_ok()) {
133+ * RACoordinate ra = coord.value();
134+ * LOG_INF("RA: %02d:%02d:%02d", ra.hours, ra.minutes, ra.seconds);
135+ * } else {
136+ * ParseError err = coord.error();
137+ * LOG_ERR("Parse failed: %d", static_cast<int>(err));
138+ * }
139+ * @endcode
140+ *
141+ * @par Using value_or() for Defaults:
142+ * @code
143+ * // Provide fallback value on error
144+ * RACoordinate ra = parse_ra(input, mode).value_or(RACoordinate{0, 0, 0});
145+ * @endcode
146+ *
147+ * @par Pattern Matching with match():
148+ * @code
149+ * // Handle both cases functionally
150+ * auto message = parse_ra(input, mode).match(
151+ * [](const RACoordinate& ra) {
152+ * return format_ra(ra); // Success path
153+ * },
154+ * [](ParseError err) {
155+ * return std::string("Invalid"); // Error path
156+ * }
157+ * );
158+ * @endcode
159+ *
160+ * @par Chaining Operations:
161+ * @code
162+ * // Parse and validate in one expression
163+ * auto result = parse_ra(input, mode).match(
164+ * [](const RACoordinate& ra) -> Result<std::string> {
165+ * if (RACoordinate::is_valid(ra.hours, ra.minutes, ra.seconds)) {
166+ * return Ok(format_ra(ra));
167+ * }
168+ * return Err<std::string>(ParseError::OutOfRange);
169+ * },
170+ * [](ParseError err) -> Result<std::string> {
171+ * return Err<std::string>(err);
172+ * }
173+ * );
174+ * @endcode
175+ *
176+ * @par Creating Results:
177+ * @code
178+ * // Use factory functions for clarity
179+ * Result<int> success = Ok(42);
180+ * Result<int> failure = Err<int>(ParseError::InvalidFormat);
181+ * VoidResult void_ok = Ok(); // For void operations
182+ * VoidResult void_err = Err<Unit>(ParseError::General);
183+ * @endcode
184+ *
185+ * @tparam T The type of the success value
186+ *
187+ * @see Ok() - Factory for successful Results
188+ * @see Err() - Factory for error Results
189+ * @see VoidResult - Typedef for Result<Unit> (void operations)
118190 */
119191template <typename T>
120192class Result {
121193private:
122194 std::variant<T, ParseError> data_;
123195
124196public:
197+ // / Construct Result with success value (copy)
125198 constexpr explicit Result (const T& value) noexcept : data_(value) {}
199+
200+ // / Construct Result with success value (move)
126201 constexpr explicit Result (T&& value) noexcept : data_(std::move(value)) {}
202+
203+ // / Construct Result with error
127204 constexpr explicit Result (ParseError error) noexcept : data_(error) {}
128205
206+ /* *
207+ * @brief Check if Result contains a success value
208+ * @return true if Ok, false if Err
209+ */
129210 constexpr bool is_ok () const noexcept {
130211 return std::holds_alternative<T>(data_);
131212 }
132213
214+ /* *
215+ * @brief Check if Result contains an error
216+ * @return true if Err, false if Ok
217+ */
133218 constexpr bool is_error () const noexcept {
134219 return std::holds_alternative<ParseError>(data_);
135220 }
136221
222+ /* *
223+ * @brief Extract the success value (const)
224+ * @return Reference to the contained value
225+ * @throws std::bad_variant_access if Result is an error
226+ * @note Always check is_ok() before calling, or use value_or() for safety
227+ */
137228 constexpr const T& value () const {
138229 return std::get<T>(data_);
139230 }
140231
232+ /* *
233+ * @brief Extract the success value (mutable)
234+ * @return Mutable reference to the contained value
235+ * @throws std::bad_variant_access if Result is an error
236+ * @note Always check is_ok() before calling, or use value_or() for safety
237+ */
141238 constexpr T& value () {
142239 return std::get<T>(data_);
143240 }
144241
242+ /* *
243+ * @brief Extract the error value
244+ * @return The contained ParseError
245+ * @throws std::bad_variant_access if Result is Ok
246+ * @note Always check is_error() before calling
247+ */
145248 constexpr ParseError error () const {
146249 return std::get<ParseError>(data_);
147250 }
148251
252+ /* *
253+ * @brief Extract value or return default on error
254+ * @param default_value Value to return if Result is an error
255+ * @return The contained value if Ok, or default_value if Err
256+ *
257+ * @par Example:
258+ * @code
259+ * // Safe extraction without checking
260+ * RACoordinate ra = parse_ra(input, mode).value_or(RACoordinate{0, 0, 0});
261+ * @endcode
262+ */
149263 constexpr T value_or (const T& default_value) const {
150264 return is_ok () ? value () : default_value;
151265 }
152266
267+ /* *
268+ * @brief Pattern match on Result with callbacks
269+ * @param ok_fn Callback for success case: T -> R
270+ * @param err_fn Callback for error case: ParseError -> R
271+ * @return Result of calling the appropriate callback
272+ *
273+ * This is the functional way to handle Results, similar to Rust's match.
274+ * Both callbacks must return the same type R.
275+ *
276+ * @par Example - Simple Logging:
277+ * @code
278+ * parse_ra(input, mode).match(
279+ * [](const RACoordinate& ra) {
280+ * LOG_INF("Parsed: %02d:%02d:%02d", ra.hours, ra.minutes, ra.seconds);
281+ * },
282+ * [](ParseError err) {
283+ * LOG_ERR("Parse error: %d", static_cast<int>(err));
284+ * }
285+ * );
286+ * @endcode
287+ *
288+ * @par Example - Transforming Results:
289+ * @code
290+ * std::string message = parse_ra(input, mode).match(
291+ * [](const RACoordinate& ra) { return format_ra(ra); },
292+ * [](ParseError err) { return std::string("ERROR"); }
293+ * );
294+ * @endcode
295+ */
153296 template <typename OkFn, typename ErrFn>
154297 constexpr auto match (OkFn&& ok_fn, ErrFn&& err_fn) const {
155298 return is_ok () ? ok_fn (value ()) : err_fn (error ());
@@ -158,28 +301,90 @@ class Result {
158301
159302/* *
160303 * @brief Result type for void operations
304+ *
305+ * Use this for functions that can fail but don't return a value.
306+ * Equivalent to Result<Unit>.
307+ *
308+ * @par Example:
309+ * @code
310+ * VoidResult validate_input(const char* input) {
311+ * if (input == nullptr) {
312+ * return Err<Unit>(ParseError::InvalidFormat);
313+ * }
314+ * return Ok(); // Success with no value
315+ * }
316+ * @endcode
161317 */
162318using VoidResult = Result<Unit>;
163319
164320/* *
165321 * @brief Factory for successful Results
322+ *
323+ * Creates a Result<T> containing a success value. Use this instead of
324+ * calling Result<T> constructor directly for better type inference.
325+ *
326+ * @param value The success value to wrap
327+ * @return Result<T> containing the value
328+ *
329+ * @par Example - With Value:
330+ * @code
331+ * Result<int> parse_number(const char* str) {
332+ * int val = atoi(str);
333+ * if (val == 0 && str[0] != '0') {
334+ * return Err<int>(ParseError::InvalidFormat);
335+ * }
336+ * return Ok(val); // Type deduced as Result<int>
337+ * }
338+ * @endcode
339+ *
340+ * @par Example - Void (No Value):
341+ * @code
342+ * VoidResult check_bounds(int value) {
343+ * if (value < 0 || value > 100) {
344+ * return Err<Unit>(ParseError::OutOfRange);
345+ * }
346+ * return Ok(); // Success with no value
347+ * }
348+ * @endcode
166349 */
167350template <typename T>
168351constexpr Result<std::remove_reference_t <T>> Ok (const T& value) noexcept {
169352 return Result<std::remove_reference_t <T>>(value);
170353}
171354
355+ // / Factory for successful Results (move version)
172356template <typename T>
173357constexpr Result<std::remove_reference_t <T>> Ok (T&& value) noexcept {
174358 return Result<std::remove_reference_t <T>>(std::forward<T>(value));
175359}
176360
361+ // / Factory for successful void Results
177362constexpr VoidResult Ok () noexcept {
178363 return VoidResult (Unit{});
179364}
180365
181366/* *
182367 * @brief Factory for error Results
368+ *
369+ * Creates a Result<T> containing an error. The type T must be explicitly
370+ * specified since it cannot be inferred from the error value.
371+ *
372+ * @tparam T The success type (even though we're creating an error)
373+ * @param error The error to wrap
374+ * @return Result<T> containing the error
375+ *
376+ * @par Example:
377+ * @code
378+ * Result<RACoordinate> parse_ra(const char* str) {
379+ * if (str == nullptr) {
380+ * return Err<RACoordinate>(ParseError::InvalidFormat);
381+ * }
382+ * // ... parsing logic ...
383+ * return Ok(coordinate);
384+ * }
385+ * @endcode
386+ *
387+ * @note Type must be specified: Err<int>(error), not Err(error)
183388 */
184389template <typename T>
185390constexpr Result<std::remove_reference_t <T>> Err (ParseError error) noexcept {
0 commit comments