|
29 | 29 | #include <cstdint> |
30 | 30 | #include <optional> |
31 | 31 | #include <string_view> |
| 32 | +#include <type_traits> |
| 33 | +#include <utility> |
| 34 | +#include <variant> |
32 | 35 |
|
33 | 36 | namespace lx200 |
34 | 37 | { |
@@ -78,20 +81,96 @@ enum class PrecisionMode : uint8_t { |
78 | 81 | }; |
79 | 82 |
|
80 | 83 | /** |
81 | | - * @brief Parse result codes |
82 | | - * |
83 | | - * Indicates success or specific failure mode for parsing operations. |
84 | | - * Success = 0 for zassert_ok compatibility |
| 84 | + * @brief Parse error types |
85 | 85 | */ |
86 | | -enum class ParseResult : uint8_t { |
87 | | - Success = 0, ///< Parsing succeeded (0 for compatibility) |
88 | | - Incomplete, ///< Need more characters |
89 | | - ErrorInvalidFormat, ///< Format doesn't match expected pattern |
90 | | - ErrorOutOfRange, ///< Numeric value out of valid range |
91 | | - ErrorBufferFull, ///< Command exceeds buffer capacity |
92 | | - ErrorGeneral ///< Other parsing error |
| 86 | +enum class ParseError : uint8_t { |
| 87 | + Incomplete = 1, |
| 88 | + InvalidFormat, |
| 89 | + OutOfRange, |
| 90 | + BufferFull, |
| 91 | + General |
| 92 | +}; |
| 93 | + |
| 94 | +/** |
| 95 | + * @brief Unit type for void Results |
| 96 | + */ |
| 97 | +struct Unit {}; |
| 98 | + |
| 99 | +/** |
| 100 | + * @brief Functional Result<T> type based on std::variant |
| 101 | + * |
| 102 | + * Type-safe error handling that replaces error codes. |
| 103 | + */ |
| 104 | +template<typename T> |
| 105 | +class Result { |
| 106 | +private: |
| 107 | + std::variant<T, ParseError> data_; |
| 108 | + |
| 109 | +public: |
| 110 | + constexpr explicit Result(const T& value) noexcept : data_(value) {} |
| 111 | + constexpr explicit Result(T&& value) noexcept : data_(std::move(value)) {} |
| 112 | + constexpr explicit Result(ParseError error) noexcept : data_(error) {} |
| 113 | + |
| 114 | + constexpr bool is_ok() const noexcept { |
| 115 | + return std::holds_alternative<T>(data_); |
| 116 | + } |
| 117 | + |
| 118 | + constexpr bool is_error() const noexcept { |
| 119 | + return std::holds_alternative<ParseError>(data_); |
| 120 | + } |
| 121 | + |
| 122 | + constexpr const T& value() const { |
| 123 | + return std::get<T>(data_); |
| 124 | + } |
| 125 | + |
| 126 | + constexpr T& value() { |
| 127 | + return std::get<T>(data_); |
| 128 | + } |
| 129 | + |
| 130 | + constexpr ParseError error() const { |
| 131 | + return std::get<ParseError>(data_); |
| 132 | + } |
| 133 | + |
| 134 | + constexpr T value_or(const T& default_value) const { |
| 135 | + return is_ok() ? value() : default_value; |
| 136 | + } |
| 137 | + |
| 138 | + template<typename OkFn, typename ErrFn> |
| 139 | + constexpr auto match(OkFn&& ok_fn, ErrFn&& err_fn) const { |
| 140 | + return is_ok() ? ok_fn(value()) : err_fn(error()); |
| 141 | + } |
93 | 142 | }; |
94 | 143 |
|
| 144 | +/** |
| 145 | + * @brief Result type for void operations |
| 146 | + */ |
| 147 | +using VoidResult = Result<Unit>; |
| 148 | + |
| 149 | +/** |
| 150 | + * @brief Factory for successful Results |
| 151 | + */ |
| 152 | +template<typename T> |
| 153 | +constexpr Result<std::remove_reference_t<T>> Ok(const T& value) noexcept { |
| 154 | + return Result<std::remove_reference_t<T>>(value); |
| 155 | +} |
| 156 | + |
| 157 | +template<typename T> |
| 158 | +constexpr Result<std::remove_reference_t<T>> Ok(T&& value) noexcept { |
| 159 | + return Result<std::remove_reference_t<T>>(std::forward<T>(value)); |
| 160 | +} |
| 161 | + |
| 162 | +constexpr VoidResult Ok() noexcept { |
| 163 | + return VoidResult(Unit{}); |
| 164 | +} |
| 165 | + |
| 166 | +/** |
| 167 | + * @brief Factory for error Results |
| 168 | + */ |
| 169 | +template<typename T> |
| 170 | +constexpr Result<std::remove_reference_t<T>> Err(ParseError error) noexcept { |
| 171 | + return Result<std::remove_reference_t<T>>(error); |
| 172 | +} |
| 173 | + |
95 | 174 | /* ======================================================================== |
96 | 175 | * Coordinate Structures |
97 | 176 | * ======================================================================== */ |
@@ -317,13 +396,13 @@ class ParserState |
317 | 396 | * @brief Feed one character to the parser |
318 | 397 | * |
319 | 398 | * @param c Character to process |
320 | | - * @return ParseResult indicating current state |
| 399 | + * @return VoidResult |
321 | 400 | * |
322 | | - * Returns Success when '#' terminator received. |
323 | | - * Returns Incomplete while building command. |
324 | | - * Returns error codes for invalid input. |
| 401 | + * Returns Ok() when character accepted (including terminator). |
| 402 | + * Check is_command_ready() after Ok() to see if command complete. |
| 403 | + * Returns Err() for invalid input or buffer full. |
325 | 404 | */ |
326 | | - ParseResult feed_character(char c) noexcept; |
| 405 | + VoidResult feed_character(char c) noexcept; |
327 | 406 |
|
328 | 407 | /** |
329 | 408 | * @brief Check if a complete command is ready |
@@ -404,66 +483,58 @@ class ParserState |
404 | 483 | }; |
405 | 484 |
|
406 | 485 | /* ======================================================================== |
407 | | - * Parsing Functions |
| 486 | + * Functional Parsing API - Result<T> based |
408 | 487 | * ======================================================================== */ |
409 | 488 |
|
410 | 489 | /** |
411 | 490 | * @brief Parse Right Ascension coordinate string |
412 | 491 | * |
413 | 492 | * @param str String in format HH:MM:SS or HH:MM.T |
414 | 493 | * @param mode Precision mode (High or Low) |
415 | | - * @param[out] coord Parsed coordinate on success |
416 | | - * @return ParseResult::Success or error code |
| 494 | + * @return Result<RACoordinate> containing parsed coordinate or error |
417 | 495 | */ |
418 | | -ParseResult parse_ra_coordinate(std::string_view str, PrecisionMode mode, |
419 | | - RACoordinate &coord) noexcept; |
| 496 | +Result<RACoordinate> parse_ra(std::string_view str, PrecisionMode mode) noexcept; |
420 | 497 |
|
421 | 498 | /** |
422 | 499 | * @brief Parse Declination coordinate string |
423 | 500 | * |
424 | 501 | * @param str String in format sDD*MM:SS or sDD*MM |
425 | 502 | * @param mode Precision mode (High or Low) |
426 | | - * @param[out] coord Parsed coordinate on success |
427 | | - * @return ParseResult::Success or error code |
| 503 | + * @return Result<DECCoordinate> containing parsed coordinate or error |
428 | 504 | */ |
429 | | -ParseResult parse_dec_coordinate(std::string_view str, PrecisionMode mode, |
430 | | - DECCoordinate &coord) noexcept; |
| 505 | +Result<DECCoordinate> parse_dec(std::string_view str, PrecisionMode mode) noexcept; |
431 | 506 |
|
432 | 507 | /** |
433 | 508 | * @brief Parse Latitude coordinate string |
434 | 509 | * |
435 | 510 | * @param str String in format sDD*MM |
436 | | - * @param[out] coord Parsed coordinate on success |
437 | | - * @return ParseResult::Success or error code |
| 511 | + * @return Result<LatitudeCoordinate> containing parsed coordinate or error |
438 | 512 | */ |
439 | | -ParseResult parse_latitude_coordinate(std::string_view str, LatitudeCoordinate &coord) noexcept; |
| 513 | +Result<LatitudeCoordinate> parse_latitude(std::string_view str) noexcept; |
440 | 514 |
|
441 | 515 | /** |
442 | 516 | * @brief Parse Longitude coordinate string |
443 | 517 | * |
444 | 518 | * @param str String in format DDD*MM |
445 | | - * @param[out] coord Parsed coordinate on success |
446 | | - * @return ParseResult::Success or error code |
| 519 | + * @return Result<LongitudeCoordinate> containing parsed coordinate or error |
447 | 520 | */ |
448 | | -ParseResult parse_longitude_coordinate(std::string_view str, LongitudeCoordinate &coord) noexcept; |
| 521 | +Result<LongitudeCoordinate> parse_longitude(std::string_view str) noexcept; |
449 | 522 |
|
450 | 523 | /** |
451 | 524 | * @brief Parse Time value string |
452 | 525 | * |
453 | 526 | * @param str String in format HH:MM:SS |
454 | | - * @param[out] time Parsed time on success |
455 | | - * @return ParseResult::Success or error code |
| 527 | + * @return Result<TimeValue> containing parsed time or error |
456 | 528 | */ |
457 | | -ParseResult parse_time_value(std::string_view str, TimeValue &time) noexcept; |
| 529 | +Result<TimeValue> parse_time(std::string_view str) noexcept; |
458 | 530 |
|
459 | 531 | /** |
460 | 532 | * @brief Parse Date value string |
461 | 533 | * |
462 | 534 | * @param str String in format MM/DD/YY |
463 | | - * @param[out] date Parsed date on success |
464 | | - * @return ParseResult::Success or error code |
| 535 | + * @return Result<DateValue> containing parsed date or error |
465 | 536 | */ |
466 | | -ParseResult parse_date_value(std::string_view str, DateValue &date) noexcept; |
| 537 | +Result<DateValue> parse_date(std::string_view str) noexcept; |
467 | 538 |
|
468 | 539 | } // namespace lx200 |
469 | 540 |
|
|
0 commit comments