|
| 1 | +/** |
| 2 | + * This software is distributed under the terms of the MIT License. |
| 3 | + * Copyright (c) 2023 LXRobotics. |
| 4 | + * Author: Alexander Entinger <[email protected]> |
| 5 | + * Contributors: https://github.com/107-systems/107-Arduino-Cyphal-Support/graphs/contributors. |
| 6 | + */ |
| 7 | + |
| 8 | +/************************************************************************************** |
| 9 | + * INCLUDE |
| 10 | + **************************************************************************************/ |
| 11 | + |
| 12 | +#include "kv_littlefs.h" |
| 13 | + |
| 14 | +#if __GNUC__ >= 11 |
| 15 | + |
| 16 | +#include <map> |
| 17 | +#include <string> |
| 18 | +#include <variant> |
| 19 | +#include <sstream> |
| 20 | + |
| 21 | +/************************************************************************************** |
| 22 | + * NAMESPACE |
| 23 | + **************************************************************************************/ |
| 24 | + |
| 25 | +namespace cyphal::support::platform::storage::littlefs |
| 26 | +{ |
| 27 | + |
| 28 | +/************************************************************************************** |
| 29 | + * PRIVATE FREE FUNCTIONS |
| 30 | + **************************************************************************************/ |
| 31 | + |
| 32 | +[[nodiscard]] static inline std::string toFilename(std::string_view const key) |
| 33 | +{ |
| 34 | + auto const key_hash = std::hash<std::string_view>{}(key); |
| 35 | + std::stringstream key_filename; |
| 36 | + key_filename << key_hash; |
| 37 | + return key_filename.str(); |
| 38 | +} |
| 39 | + |
| 40 | +[[nodiscard]] static inline Error toError(::littlefs::Error const err) |
| 41 | +{ |
| 42 | + static std::map<::littlefs::Error, Error> const LITTLEFS_TO_STORAGE_ERROR_MAP = |
| 43 | + { |
| 44 | + {::littlefs::Error::IO , Error::IO}, |
| 45 | + {::littlefs::Error::CORRUPT , Error::Internal}, |
| 46 | + {::littlefs::Error::NOENT , Error::Existence}, |
| 47 | + {::littlefs::Error::EXIST , Error::Existence}, |
| 48 | + {::littlefs::Error::NOTDIR , Error::Existence}, |
| 49 | + {::littlefs::Error::ISDIR , Error::Existence}, |
| 50 | + {::littlefs::Error::NOTEMPTY , Error::Existence}, |
| 51 | + {::littlefs::Error::BADF , Error::Internal}, |
| 52 | + {::littlefs::Error::FBIG , Error::Capacity}, |
| 53 | + {::littlefs::Error::INVAL , Error::API}, |
| 54 | + {::littlefs::Error::NOSPC , Error::Capacity}, |
| 55 | + {::littlefs::Error::NOMEM , Error::Internal}, |
| 56 | + {::littlefs::Error::NOATTR , Error::API}, |
| 57 | + {::littlefs::Error::NAMETOOLONG , Error::API}, |
| 58 | + {::littlefs::Error::NO_FD_ENTRY , Error::API}, |
| 59 | + }; |
| 60 | + |
| 61 | + return LITTLEFS_TO_STORAGE_ERROR_MAP.at(err); |
| 62 | +} |
| 63 | + |
| 64 | +/************************************************************************************** |
| 65 | + * CTOR/DTOR |
| 66 | + **************************************************************************************/ |
| 67 | + |
| 68 | +KeyValueStorage::KeyValueStorage(::littlefs::Filesystem & filesystem) |
| 69 | +: _filesystem{filesystem} |
| 70 | +{ } |
| 71 | + |
| 72 | +/************************************************************************************** |
| 73 | + * PUBLIC MEMBER FUNCTIONS |
| 74 | + **************************************************************************************/ |
| 75 | + |
| 76 | +auto KeyValueStorage::get(const std::string_view key, const std::size_t size, void* const data) const |
| 77 | + -> std::variant<Error, std::size_t> |
| 78 | +{ |
| 79 | + auto const rc_open = _filesystem.open(toFilename(key), ::littlefs::OpenFlag::RDONLY); |
| 80 | + if (const auto * const err = std::get_if<::littlefs::Error>(&rc_open)) |
| 81 | + return toError(*err); |
| 82 | + |
| 83 | + auto const file_hdl = std::get<::littlefs::FileHandle>(rc_open); |
| 84 | + |
| 85 | + auto const rc_read = _filesystem.read(file_hdl, data, size); |
| 86 | + if (const auto * const err = std::get_if<::littlefs::Error>(&rc_read)) |
| 87 | + { |
| 88 | + (void)_filesystem.close(file_hdl); |
| 89 | + return toError(*err); |
| 90 | + } |
| 91 | + |
| 92 | + (void)_filesystem.close(file_hdl); |
| 93 | + |
| 94 | + return std::get<size_t>(rc_read); |
| 95 | +} |
| 96 | + |
| 97 | +auto KeyValueStorage::put(const std::string_view key, const std::size_t size, const void* const data) |
| 98 | + -> std::optional<Error> |
| 99 | +{ |
| 100 | + auto const rc_open = _filesystem.open(toFilename(key), ::littlefs::OpenFlag::WRONLY | ::littlefs::OpenFlag::CREAT | ::littlefs::OpenFlag::TRUNC); |
| 101 | + if (const auto * const err = std::get_if<::littlefs::Error>(&rc_open)) |
| 102 | + return toError(*err); |
| 103 | + |
| 104 | + auto const file_hdl = std::get<::littlefs::FileHandle>(rc_open); |
| 105 | + |
| 106 | + auto const rc_write = _filesystem.write(file_hdl, data, size); |
| 107 | + if (const auto * const err = std::get_if<::littlefs::Error>(&rc_write)) |
| 108 | + { |
| 109 | + (void)_filesystem.close(file_hdl); |
| 110 | + return toError(*err); |
| 111 | + } |
| 112 | + |
| 113 | + (void)_filesystem.close(file_hdl); |
| 114 | + |
| 115 | + size_t const bytes_written = std::get<size_t>(rc_write); |
| 116 | + if (bytes_written != size) |
| 117 | + return Error::Capacity; |
| 118 | + |
| 119 | + return std::nullopt; |
| 120 | +} |
| 121 | + |
| 122 | +auto KeyValueStorage::drop(const std::string_view key) -> std::optional<Error> |
| 123 | +{ |
| 124 | + if (auto const opt_err = _filesystem.remove(toFilename(key)); opt_err.has_value()) |
| 125 | + return toError(opt_err.value()); |
| 126 | + |
| 127 | + return std::nullopt; |
| 128 | +} |
| 129 | + |
| 130 | +/************************************************************************************** |
| 131 | + * NAMESPACE |
| 132 | + **************************************************************************************/ |
| 133 | + |
| 134 | +} /* cyphal::support::platform::storage::littlefs */ |
| 135 | + |
| 136 | +#endif /* __GNUC__ >= 11 */ |
0 commit comments