Skip to content

Commit ef08101

Browse files
refactor: Replace ParseResult enum with Result<T> variant
- Remove ParseResult enum, add Result<T> based on std::variant - Update all parsing functions to return Result<T> or VoidResult - Implement functional error handling with Ok()/Err() factories - Add match() and value_or() methods for functional composition - Rewrite all 98 tests for Result<T> API (100% passing) Breaking changes: - ParseResult enum removed entirely - All parse functions now return Result<T> instead of out-parameters - feed_character() returns VoidResult instead of ParseResult
1 parent 96cb2c1 commit ef08101

6 files changed

Lines changed: 1268 additions & 1296 deletions

File tree

include/lx200/lx200.hpp

Lines changed: 108 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@
2929
#include <cstdint>
3030
#include <optional>
3131
#include <string_view>
32+
#include <type_traits>
33+
#include <utility>
34+
#include <variant>
3235

3336
namespace lx200
3437
{
@@ -78,20 +81,96 @@ enum class PrecisionMode : uint8_t {
7881
};
7982

8083
/**
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
8585
*/
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+
}
93142
};
94143

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+
95174
/* ========================================================================
96175
* Coordinate Structures
97176
* ======================================================================== */
@@ -317,13 +396,13 @@ class ParserState
317396
* @brief Feed one character to the parser
318397
*
319398
* @param c Character to process
320-
* @return ParseResult indicating current state
399+
* @return VoidResult
321400
*
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.
325404
*/
326-
ParseResult feed_character(char c) noexcept;
405+
VoidResult feed_character(char c) noexcept;
327406

328407
/**
329408
* @brief Check if a complete command is ready
@@ -404,66 +483,58 @@ class ParserState
404483
};
405484

406485
/* ========================================================================
407-
* Parsing Functions
486+
* Functional Parsing API - Result<T> based
408487
* ======================================================================== */
409488

410489
/**
411490
* @brief Parse Right Ascension coordinate string
412491
*
413492
* @param str String in format HH:MM:SS or HH:MM.T
414493
* @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
417495
*/
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;
420497

421498
/**
422499
* @brief Parse Declination coordinate string
423500
*
424501
* @param str String in format sDD*MM:SS or sDD*MM
425502
* @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
428504
*/
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;
431506

432507
/**
433508
* @brief Parse Latitude coordinate string
434509
*
435510
* @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
438512
*/
439-
ParseResult parse_latitude_coordinate(std::string_view str, LatitudeCoordinate &coord) noexcept;
513+
Result<LatitudeCoordinate> parse_latitude(std::string_view str) noexcept;
440514

441515
/**
442516
* @brief Parse Longitude coordinate string
443517
*
444518
* @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
447520
*/
448-
ParseResult parse_longitude_coordinate(std::string_view str, LongitudeCoordinate &coord) noexcept;
521+
Result<LongitudeCoordinate> parse_longitude(std::string_view str) noexcept;
449522

450523
/**
451524
* @brief Parse Time value string
452525
*
453526
* @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
456528
*/
457-
ParseResult parse_time_value(std::string_view str, TimeValue &time) noexcept;
529+
Result<TimeValue> parse_time(std::string_view str) noexcept;
458530

459531
/**
460532
* @brief Parse Date value string
461533
*
462534
* @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
465536
*/
466-
ParseResult parse_date_value(std::string_view str, DateValue &date) noexcept;
537+
Result<DateValue> parse_date(std::string_view str) noexcept;
467538

468539
} // namespace lx200
469540

0 commit comments

Comments
 (0)