diff --git a/src/ystdlib/io_interface/CMakeLists.txt b/src/ystdlib/io_interface/CMakeLists.txt index 0f638a4..b276a32 100644 --- a/src/ystdlib/io_interface/CMakeLists.txt +++ b/src/ystdlib/io_interface/CMakeLists.txt @@ -8,6 +8,7 @@ cpp_library( PRIVATE_SOURCES ReaderInterface.cpp PUBLIC_LINK_LIBRARIES + ystdlib::error_handling ystdlib::wrapped_facade_headers TESTS_SOURCES test/test_ReaderInterface.cpp diff --git a/src/ystdlib/io_interface/ErrorCode.cpp b/src/ystdlib/io_interface/ErrorCode.cpp new file mode 100644 index 0000000..1e906ef --- /dev/null +++ b/src/ystdlib/io_interface/ErrorCode.cpp @@ -0,0 +1,37 @@ +#include "ErrorCode.hpp" + +#include + +#include + +using ystdlib::io_interface::ErrorCodeEnum; +using ErrorCategory = ystdlib::error_handling::ErrorCategory; + +template <> +auto ErrorCategory::name() const noexcept -> char const* { + return "ystdlib::io_interface::ErrorCode"; +} + +template <> +auto ErrorCategory::message(ErrorCodeEnum error_enum) const -> std::string { + switch (error_enum) { + case ErrorCodeEnum::BadParam: + return "Supplied parameters are invalid."; + case ErrorCodeEnum::BufferFull: + return "The output buffer is full and cannot accept more data."; + case ErrorCodeEnum::Corrupt: + return "The data is corrupted or malformed."; + case ErrorCodeEnum::EndOfFile: + return "End of file reached."; + case ErrorCodeEnum::EndOfStream: + return "End of the data stream reached."; + case ErrorCodeEnum::OutOfBounds: + return "Attempted to access data outside of valid bounds."; + case ErrorCodeEnum::OutOfMemory: + return "Memory allocation failed."; + case ErrorCodeEnum::Truncated: + return "The data was unexpectedly truncated or cut off."; + default: + return "Unrecognized ystdlib::io_interface::ErrorCodeEnum."; + } +} diff --git a/src/ystdlib/io_interface/ErrorCode.hpp b/src/ystdlib/io_interface/ErrorCode.hpp index 7dfb2ea..ea6bea1 100644 --- a/src/ystdlib/io_interface/ErrorCode.hpp +++ b/src/ystdlib/io_interface/ErrorCode.hpp @@ -1,33 +1,25 @@ #ifndef YSTDLIB_IO_INTERFACE_ERRORCODE_HPP #define YSTDLIB_IO_INTERFACE_ERRORCODE_HPP -// NOLINTBEGIN +#include + +#include namespace ystdlib::io_interface { -typedef enum { - ErrorCode_Success = 0, - ErrorCode_BadParam, - ErrorCode_BadParam_DB_URI, - ErrorCode_Corrupt, - ErrorCode_errno, - ErrorCode_EndOfFile, - ErrorCode_FileExists, - ErrorCode_FileNotFound, - ErrorCode_NoMem, - ErrorCode_NotInit, - ErrorCode_NotReady, - ErrorCode_OutOfBounds, - ErrorCode_TooLong, - ErrorCode_Truncated, - ErrorCode_Unsupported, - ErrorCode_NoAccess, - ErrorCode_Failure, - ErrorCode_Failure_Metadata_Corrupted, - ErrorCode_MetadataCorrupted, - ErrorCode_Failure_DB_Bulk_Write, - ErrorCode_Failure_Network, -} ErrorCode; +enum class ErrorCodeEnum : uint8_t { + BadParam, + BufferFull, + Corrupt, + EndOfFile, + EndOfStream, + OutOfBounds, + OutOfMemory, + Truncated +}; + +using ErrorCode = ystdlib::error_handling::ErrorCode; } // namespace ystdlib::io_interface -// NOLINTEND +YSTDLIB_ERROR_HANDLING_MARK_AS_ERROR_CODE_ENUM(ystdlib::io_interface::ErrorCodeEnum); + #endif // YSTDLIB_IO_INTERFACE_ERRORCODE_HPP diff --git a/src/ystdlib/io_interface/ReaderInterface.cpp b/src/ystdlib/io_interface/ReaderInterface.cpp index 425eb7a..8b57b2f 100644 --- a/src/ystdlib/io_interface/ReaderInterface.cpp +++ b/src/ystdlib/io_interface/ReaderInterface.cpp @@ -1,64 +1,61 @@ #include "ReaderInterface.hpp" #include +#include #include +#include + #include "ErrorCode.hpp" namespace ystdlib::io_interface { -auto -ReaderInterface::read_to_delimiter(char delim, bool keep_delimiter, bool append, std::string& str) - -> ErrorCode { - if (false == append) { - str.clear(); +auto ReaderInterface::read(size_t num_bytes) -> Result { + std::string str(num_bytes, 0); + auto const num_bytes_read{YSTDLIB_ERROR_HANDLING_TRYX(read({str.data(), num_bytes}))}; + str.resize(num_bytes_read); + return str; +} + +auto ReaderInterface::read_exact_length(std::span buf) -> Result { + auto const num_bytes_read{YSTDLIB_ERROR_HANDLING_TRYX(read(buf))}; + if (0 == num_bytes_read) { + return ErrorCode{ErrorCodeEnum::EndOfStream}; } + if (num_bytes_read < buf.size()) { + return ErrorCode{ErrorCodeEnum::Truncated}; + } + return ystdlib::error_handling::success(); +} - auto const original_str_length{str.length()}; +auto ReaderInterface::read_exact_length(size_t num_bytes) -> Result { + std::string str(num_bytes, 0); + YSTDLIB_ERROR_HANDLING_TRYV(read_exact_length({str.data(), num_bytes})); + return str; +} - // Read character by character into str, until we find a delimiter +auto ReaderInterface::read_to_delimiter(char delim, bool keep_delimiter) -> Result { char c{0}; - size_t num_bytes_read{0}; - while (true) { - auto const error_code{read(&c, 1, num_bytes_read)}; - if (ErrorCode_Success != error_code) { - if (ErrorCode_EndOfFile == error_code && str.length() > original_str_length) { - return ErrorCode_Success; - } - return error_code; - } - - if (delim == c) { - break; - } + std::string str; + // The first read needs to succeed + c = YSTDLIB_ERROR_HANDLING_TRYX(read_numeric_value()); + while (delim != c) { str += c; + auto const result{read_numeric_value()}; + if (result.has_error()) { + auto const error{result.error()}; + if (ErrorCode{ErrorCodeEnum::EndOfStream} == error + || ErrorCode{ErrorCodeEnum::EndOfFile} == error) + { + return str; + } + return error; + } + c = result.value(); } - - // Add delimiter if necessary if (keep_delimiter) { str += delim; } - - return ErrorCode_Success; -} - -auto ReaderInterface::read_exact_length(char* buf, size_t num_bytes) -> ErrorCode { - size_t num_bytes_read{0}; - auto const error_code{read(buf, num_bytes, num_bytes_read)}; - if (ErrorCode_Success != error_code) { - return error_code; - } - if (num_bytes_read < num_bytes) { - return ErrorCode_Truncated; - } - - return ErrorCode_Success; -} - -auto ReaderInterface::read_string(size_t const str_length, std::string& str) -> ErrorCode { - // Resize string to fit str_length - str.resize(str_length); - - return read_exact_length(str.data(), str_length); + return str; } } // namespace ystdlib::io_interface diff --git a/src/ystdlib/io_interface/ReaderInterface.hpp b/src/ystdlib/io_interface/ReaderInterface.hpp index f14611b..1af495c 100644 --- a/src/ystdlib/io_interface/ReaderInterface.hpp +++ b/src/ystdlib/io_interface/ReaderInterface.hpp @@ -2,15 +2,18 @@ #define YSTDLIB_IO_INTERFACE_READERINTERFACE_HPP #include +#include #include +#include #include -#include "ErrorCode.hpp" - namespace ystdlib::io_interface { class ReaderInterface { public: + template + using Result = ystdlib::error_handling::Result; + // Constructor ReaderInterface() = default; @@ -26,66 +29,72 @@ class ReaderInterface { virtual ~ReaderInterface() = default; // Methods - /* - * Reads up to the given number of bytes from the underlying medium into the given buffer. + /** + * Performs a read that attempts to fill the given buffer. * @param buf - * @param num_bytes_to_read - * @param num_bytes_read Returns the actual number of bytes read. + * @return The number of bytes read. */ - [[nodiscard]] virtual auto read(char* buf, size_t num_bytes_to_read, size_t& num_bytes_read) - -> ErrorCode - = 0; + [[nodiscard]] virtual auto read(std::span buf) -> Result = 0; /** - * Reads up to the next delimiter from the underlying medium into the given string. - * @param delim The delimiter to stop at. - * @param keep_delimiter Whether to include the delimiter in the output string or not. - * @param append Whether to append to the given string or replace its contents. - * @param str Returns the string read. + * Performs a read of up to the requested byte count. + * @param num_bytes + * @return The data read as a string. */ - [[nodiscard]] virtual auto - read_to_delimiter(char delim, bool keep_delimiter, bool append, std::string& str) -> ErrorCode; + [[nodiscard]] virtual auto read(size_t num_bytes) -> Result; /** - * Reads the given number of bytes from the underlying medium into the given buffer. + * Performs a read that completely fills the given buffer. * @param buf - * @param num_bytes Number of bytes to read. */ - [[nodiscard]] virtual auto read_exact_length(char* buf, size_t num_bytes) -> ErrorCode; + [[nodiscard]] virtual auto read_exact_length(std::span buf) -> Result; /** - * @param value Returns the read numeric value. + * Performs a read that must return exactly the requested byte count. + * @param num_bytes + * @return The data read as a string. */ - template - [[nodiscard]] auto read_numeric_value(ValueType& value) -> ErrorCode; + [[nodiscard]] virtual auto read_exact_length(size_t num_bytes) -> Result; /** - * @param str_length - * @param str Returns the string read. + * Performs a reads of up to the next delimiter. + * @param buf + * @param delim The delimiter to stop at. + * @param keep_delimiter Whether to include the delimiter in the output. + * @return The data read as a string. */ - [[nodiscard]] virtual auto read_string(size_t str_length, std::string& str) -> ErrorCode; + [[nodiscard]] virtual auto read_to_delimiter(char delim, bool keep_delimiter) + -> Result; + + /** + * @return The numeric value read. + */ + template + [[nodiscard]] auto read_numeric_value() -> Result; /** * Seeks from the beginning to the given position. * @param pos */ - [[nodiscard]] virtual auto seek_from_begin(size_t pos) -> ErrorCode = 0; + [[nodiscard]] virtual auto seek_from_begin(size_t pos) -> Result = 0; /** * Seeks from the current position to the next position by the given offset amount. * @param offset */ - [[nodiscard]] virtual auto seek_from_current(off_t offset) -> ErrorCode = 0; + [[nodiscard]] virtual auto seek_from_current(off_t offset) -> Result = 0; /** - * @param pos Returns the current position of the read pointer. + * @return The current position of the read pointer. */ - [[nodiscard]] virtual auto get_pos(size_t& pos) -> ErrorCode = 0; + [[nodiscard]] virtual auto get_pos() -> Result = 0; }; template -auto ReaderInterface::read_numeric_value(ValueType& value) -> ErrorCode { - return read_exact_length(static_cast(&value), sizeof(ValueType)); +auto ReaderInterface::read_numeric_value() -> Result { + ValueType value{}; + YSTDLIB_ERROR_HANDLING_TRYV(read_exact_length({static_cast(&value), sizeof(ValueType)})); + return value; } } // namespace ystdlib::io_interface diff --git a/src/ystdlib/io_interface/WriterInterface.hpp b/src/ystdlib/io_interface/WriterInterface.hpp index 14a8cec..7b2eaba 100644 --- a/src/ystdlib/io_interface/WriterInterface.hpp +++ b/src/ystdlib/io_interface/WriterInterface.hpp @@ -2,15 +2,18 @@ #define YSTDLIB_IO_INTERFACE_WRITERINTERFACE_HPP #include +#include #include +#include #include -#include "ErrorCode.hpp" - namespace ystdlib::io_interface { class WriterInterface { public: + template + using Result = ystdlib::error_handling::Result; + // Constructor WriterInterface() = default; @@ -27,59 +30,52 @@ class WriterInterface { // Methods /** - * Writes the given data to the underlying medium. + * Performs a writes of the given data. * @param data - * @param data_length */ - [[nodiscard]] virtual auto write(char const* data, size_t data_length) -> ErrorCode = 0; + [[nodiscard]] virtual auto write(std::span data) -> Result = 0; /** - * Forces any buffered output data to be available at the underlying medium. + * Forces any buffered written data to be available at the output. */ - [[nodiscard]] virtual auto flush() -> ErrorCode = 0; + [[nodiscard]] virtual auto flush() -> Result = 0; /** - * Writes a numeric value to the underlying medium. - * @param val + * Performs a writes of the given numeric value. + * @param value */ template - [[nodiscard]] auto write_numeric_value(ValueType value) -> ErrorCode; - - /** - * Writes a character to the underlying medium. - * @param c - */ - [[nodiscard]] virtual auto write_char(char c) -> ErrorCode { return write(&c, 1); } + [[nodiscard]] auto write_numeric_value(ValueType value) -> Result; /** - * Writes a string to the underlying medium. + * Performs a writes of the given string. * @param str */ - [[nodiscard]] virtual auto write_string(std::string const& str) -> ErrorCode { - return write(str.c_str(), str.length()); + [[nodiscard]] virtual auto write_string(std::string const& str) -> Result { + return write({str.c_str(), str.length()}); } /** * Seeks from the beginning to the given position. * @param pos */ - [[nodiscard]] virtual auto seek_from_begin(size_t pos) -> ErrorCode = 0; + [[nodiscard]] virtual auto seek_from_begin(size_t pos) -> Result = 0; /** * Seeks from the current position to the next position by the given offset amount. * @param offset */ - [[nodiscard]] virtual auto seek_from_current(off_t offset) -> ErrorCode = 0; + [[nodiscard]] virtual auto seek_from_current(off_t offset) -> Result = 0; /** - * @param pos Returns the current position of the read pointer. + * @return The current position of the write pointer. */ - [[nodiscard]] virtual auto get_pos(size_t& pos) -> ErrorCode = 0; + [[nodiscard]] virtual auto get_pos() -> Result = 0; }; template -auto WriterInterface::write_numeric_value(ValueType val) -> ErrorCode { - return write(static_cast(&val), sizeof(ValueType)); +auto WriterInterface::write_numeric_value(ValueType val) -> Result { + return write({static_cast(&val), sizeof(ValueType)}); } } // namespace ystdlib::io_interface