new persistence manager component

Signed-off-by: Peter Siegmund <developer@mars3142.org>
This commit is contained in:
2025-06-23 23:10:42 +02:00
parent c6f0c4572d
commit 0c8c831eea
16 changed files with 92 additions and 119 deletions

View File

@@ -4,6 +4,7 @@ if (NOT DEFINED ENV{IDF_PATH})
add_subdirectory(imgui)
add_subdirectory(insa)
add_subdirectory(led-manager)
add_subdirectory(persistence-manager)
target_link_libraries(components INTERFACE ImGui)
endif ()

View File

@@ -17,7 +17,7 @@
// Project-specific headers
#include "common/Widget.h"
#include "common/IPersistenceManager.h"
#include "../../persistence-manager/include/IPersistenceManager.h"
#include "u8g2.h"
class MenuItem;

View File

@@ -5,6 +5,7 @@ if (DEFINED ENV{IDF_PATH})
PRIV_REQUIRES
u8g2
esp_event
persistence-manager
)
return()
endif ()
@@ -23,4 +24,5 @@ target_include_directories(${PROJECT_NAME} PUBLIC include)
target_link_libraries(${PROJECT_NAME} PRIVATE
SDL3::SDL3
persistence-manager
)

View File

@@ -1,4 +1,5 @@
#pragma once
#include "SDL3/SDL_render.h"
#include <cstdint>
@@ -12,7 +13,7 @@ class Matrix
void Render() const;
SDL_WindowID windowId() const;
[[nodiscard]] SDL_WindowID windowId() const;
private:
void DrawColoredGrid() const;

View File

@@ -1,6 +1,6 @@
#pragma once
#include "stdint.h"
#include <cstdint>
enum
{
@@ -15,8 +15,8 @@ typedef struct
int value;
} led_event_data_t;
uint64_t wled_init(void);
uint64_t wled_init();
uint64_t register_handler(void);
uint64_t register_handler();
uint64_t send_event(uint32_t event, led_event_data_t *payload);

View File

@@ -1,4 +1,4 @@
#include "../../include/Matrix.h"
#include "Matrix.h"
#include "SDL3/SDL.h"
@@ -36,7 +36,7 @@ void Matrix::DrawColoredGrid() const
h = m_rows - 1 - h_raw;
}
const auto rectSize = cellSize - 2.0f * spacing;
constexpr auto rectSize = cellSize - 2.0f * spacing;
const auto x = static_cast<float>(w) * cellSize + spacing;
const auto y = static_cast<float>(h) * cellSize + spacing;

View File

@@ -0,0 +1,24 @@
if (DEFINED ENV{IDF_PATH})
idf_component_register(SRCS
src/hal_esp32/PersistenceManager.cpp
INCLUDE_DIRS "include"
REQUIRES
nvs_flash
)
return()
endif ()
cmake_minimum_required(VERSION 3.30)
project(persistence-manager)
add_library(${PROJECT_NAME} STATIC
src/hal_native/PersistenceManager.cpp
)
include_directories(include)
target_include_directories(${PROJECT_NAME} PUBLIC include)
target_link_libraries(${PROJECT_NAME} PRIVATE
SDL3::SDL3
)

View File

@@ -35,49 +35,21 @@ public:
* @brief Template method for type-safe retrieval of values
* @tparam T The type of value to retrieve
* @param key The key to look up
* @param defaultValue The default value to return if key is not found
* @return The stored value or default value if key doesn't exist
* @param defaultValue The default value to return if the key is not found
* @return The stored value or default value if the key doesn't exist
*/
template<typename T>
T GetValue(const std::string& key, const T& defaultValue = T{}) const {
[[nodiscard]] T GetValue(const std::string& key, const T& defaultValue = T{}) const {
return GetValueImpl<T>(key, defaultValue);
}
/**
* @brief Convenience methods for setting specific types
*/
void SetBool(const std::string& key, bool value) { SetValue(key, value); }
void SetInt(const std::string& key, int value) { SetValue(key, value); }
void SetFloat(const std::string& key, float value) { SetValue(key, value); }
void SetDouble(const std::string& key, double value) { SetValue(key, value); }
void SetString(const std::string& key, const std::string& value) { SetValue(key, value); }
/**
* @brief Convenience methods for getting specific types with default values
*/
bool GetBool(const std::string& key, bool defaultValue = false) const {
return GetValue(key, defaultValue);
}
int GetInt(const std::string& key, int defaultValue = 0) const {
return GetValue(key, defaultValue);
}
float GetFloat(const std::string& key, float defaultValue = 0.0f) const {
return GetValue(key, defaultValue);
}
double GetDouble(const std::string& key, double defaultValue = 0.0) const {
return GetValue(key, defaultValue);
}
std::string GetString(const std::string& key, const std::string& defaultValue = "") const {
return GetValue(key, defaultValue);
}
/**
* @brief Utility methods for key management
*/
virtual bool HasKey(const std::string& key) const = 0; ///< Check if a key exists
[[nodiscard]] virtual bool HasKey(const std::string& key) const = 0; ///< Check if a key exists
virtual void RemoveKey(const std::string& key) = 0; ///< Remove a key-value pair
virtual void Clear() = 0; ///< Clear all stored data
virtual size_t GetKeyCount() const = 0; ///< Get the number of stored keys
[[nodiscard]] virtual size_t GetKeyCount() const = 0; ///< Get the number of stored keys
/**
* @brief Persistence operations
@@ -96,11 +68,11 @@ protected:
virtual void SetValueImpl(const std::string& key, double value) = 0;
virtual void SetValueImpl(const std::string& key, const std::string& value) = 0;
virtual bool GetValueImpl(const std::string& key, bool defaultValue) const = 0;
virtual int GetValueImpl(const std::string& key, int defaultValue) const = 0;
virtual float GetValueImpl(const std::string& key, float defaultValue) const = 0;
virtual double GetValueImpl(const std::string& key, double defaultValue) const = 0;
virtual std::string GetValueImpl(const std::string& key, const std::string& defaultValue) const = 0;
[[nodiscard]] virtual bool GetValueImpl(const std::string& key, bool defaultValue) const = 0;
[[nodiscard]] virtual int GetValueImpl(const std::string& key, int defaultValue) const = 0;
[[nodiscard]] virtual float GetValueImpl(const std::string& key, float defaultValue) const = 0;
[[nodiscard]] virtual double GetValueImpl(const std::string& key, double defaultValue) const = 0;
[[nodiscard]] virtual std::string GetValueImpl(const std::string& key, const std::string& defaultValue) const = 0;
private:
/**
@@ -111,18 +83,18 @@ private:
* @return The retrieved value or default if not found
*/
template<typename T>
T GetValueImpl(const std::string& key, const T& defaultValue) const
[[nodiscard]] T GetValueImpl(const std::string& key, const T& defaultValue) const
{
if constexpr (std::is_same_v<T, bool>) {
return GetValueImpl(key, defaultValue);
return GetValueImpl(key, static_cast<bool>(defaultValue));
} else if constexpr (std::is_same_v<T, int>) {
return GetValueImpl(key, defaultValue);
return GetValueImpl(key, static_cast<int>(defaultValue));
} else if constexpr (std::is_same_v<T, float>) {
return GetValueImpl(key, defaultValue);
return GetValueImpl(key, static_cast<float>(defaultValue));
} else if constexpr (std::is_same_v<T, double>) {
return GetValueImpl(key, defaultValue);
return GetValueImpl(key, static_cast<double>(defaultValue));
} else if constexpr (std::is_same_v<T, std::string>) {
return GetValueImpl(key, defaultValue);
return GetValueImpl(key, static_cast<const std::string&>(defaultValue));
} else {
static_assert(std::is_same_v<T, bool> ||
std::is_same_v<T, int> ||
@@ -130,7 +102,7 @@ private:
std::is_same_v<T, double> ||
std::is_same_v<T, std::string>,
"Unsupported type for IPersistenceManager");
return defaultValue; // This line will never be reached, but satisfies compiler
return defaultValue; // This line will never be reached, but satisfies the compiler
}
}
};

View File

@@ -0,0 +1,58 @@
#pragma once
#include "IPersistenceManager.h"
#include <string>
#include <unordered_map>
#include <nvs.h>
#include <nvs_flash.h>
/**
* @class PersistenceManager
* @brief ESP32-specific implementation using NVS (Non-Volatile Storage)
* @details This implementation uses ESP32's NVS API for persistent storage
* in flash memory, providing a platform-optimized solution for
* embedded systems.
*/
class PersistenceManager final : public IPersistenceManager
{
private:
nvs_handle_t nvs_handle_;
std::string namespace_;
bool initialized_;
public:
explicit PersistenceManager(const std::string &nvs_namespace = "config");
~PersistenceManager() override;
bool HasKey(const std::string &key) const override;
void RemoveKey(const std::string &key) override;
void Clear() override;
size_t GetKeyCount() const override;
bool Save() override;
bool Load() override;
bool Initialize();
void Deinitialize();
bool IsInitialized() const
{
return initialized_;
}
protected:
void SetValueImpl(const std::string &key, bool value) override;
void SetValueImpl(const std::string &key, int value) override;
void SetValueImpl(const std::string &key, float value) override;
void SetValueImpl(const std::string &key, double value) override;
void SetValueImpl(const std::string &key, const std::string &value) override;
bool GetValueImpl(const std::string &key, bool defaultValue) const override;
int GetValueImpl(const std::string &key, int defaultValue) const override;
float GetValueImpl(const std::string &key, float defaultValue) const override;
double GetValueImpl(const std::string &key, double defaultValue) const override;
std::string GetValueImpl(const std::string &key, const std::string &defaultValue) const override;
private:
bool EnsureInitialized() const;
};

View File

@@ -0,0 +1,63 @@
#pragma once
#include "../IPersistenceManager.h"
#include <SDL3/SDL.h>
#include <unordered_map>
#include <variant>
class PersistenceManager final : public IPersistenceManager {
public:
using ValueType = std::variant<
bool,
int,
float,
double,
std::string
>;
private:
std::unordered_map<std::string, ValueType> m_data;
std::string m_filename;
public:
explicit PersistenceManager(std::string filename = "settings.dat");
~PersistenceManager() override;
[[nodiscard]] bool HasKey(const std::string& key) const override;
void RemoveKey(const std::string& key) override;
void Clear() override;
[[nodiscard]] size_t GetKeyCount() const override { return m_data.size(); }
bool Save() override;
bool Load() override;
bool SaveToFile(const std::string& filename);
bool LoadFromFile(const std::string& filename);
protected:
void SetValueImpl(const std::string& key, bool value) override;
void SetValueImpl(const std::string& key, int value) override;
void SetValueImpl(const std::string& key, float value) override;
void SetValueImpl(const std::string& key, double value) override;
void SetValueImpl(const std::string& key, const std::string& value) override;
[[nodiscard]] bool GetValueImpl(const std::string& key, bool defaultValue) const override;
[[nodiscard]] int GetValueImpl(const std::string& key, int defaultValue) const override;
[[nodiscard]] float GetValueImpl(const std::string& key, float defaultValue) const override;
[[nodiscard]] double GetValueImpl(const std::string& key, double defaultValue) const override;
[[nodiscard]] std::string GetValueImpl(const std::string& key, const std::string& defaultValue) const override;
private:
static bool WriteValueToStream(SDL_IOStream* stream, const ValueType& value) ;
static bool ReadValueFromStream(SDL_IOStream* stream, ValueType& value) ;
enum class TypeId : uint8_t {
BOOL = 0,
INT = 1,
FLOAT = 2,
DOUBLE = 3,
STRING = 4
};
static TypeId GetTypeId(const ValueType& value);
};

View File

@@ -0,0 +1,292 @@
#include "hal_esp32/PersistenceManager.h"
#include <cstring>
#include <esp_log.h>
static const char *TAG = "PersistenceManager";
PersistenceManager::PersistenceManager(const std::string &nvs_namespace)
: namespace_(nvs_namespace), initialized_(false)
{
Initialize();
}
PersistenceManager::~PersistenceManager()
{
Deinitialize();
}
bool PersistenceManager::Initialize()
{
if (initialized_)
{
return true;
}
// Initialize NVS
esp_err_t err = nvs_flash_init();
if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND)
{
ESP_ERROR_CHECK(nvs_flash_erase());
err = nvs_flash_init();
}
if (err != ESP_OK)
{
ESP_LOGE(TAG, "Failed to initialize NVS flash: %s", esp_err_to_name(err));
return false;
}
// Open NVS handle
err = nvs_open(namespace_.c_str(), NVS_READWRITE, &nvs_handle_);
if (err != ESP_OK)
{
ESP_LOGE(TAG, "Failed to open NVS handle: %s", esp_err_to_name(err));
return false;
}
initialized_ = true;
ESP_LOGI(TAG, "PersistenceManager initialized with namespace: %s", namespace_.c_str());
return true;
}
void PersistenceManager::Deinitialize()
{
if (initialized_)
{
nvs_close(nvs_handle_);
initialized_ = false;
}
}
bool PersistenceManager::EnsureInitialized() const
{
if (!initialized_)
{
ESP_LOGE(TAG, "PersistenceManager not initialized");
return false;
}
return true;
}
bool PersistenceManager::HasKey(const std::string &key) const
{
if (!EnsureInitialized())
return false;
size_t required_size = 0;
esp_err_t err = nvs_get_blob(nvs_handle_, key.c_str(), nullptr, &required_size);
return err == ESP_OK;
}
void PersistenceManager::RemoveKey(const std::string &key)
{
if (!EnsureInitialized())
return;
esp_err_t err = nvs_erase_key(nvs_handle_, key.c_str());
if (err != ESP_OK && err != ESP_ERR_NVS_NOT_FOUND)
{
ESP_LOGE(TAG, "Failed to remove key '%s': %s", key.c_str(), esp_err_to_name(err));
}
}
void PersistenceManager::Clear()
{
if (!EnsureInitialized())
return;
esp_err_t err = nvs_erase_all(nvs_handle_);
if (err != ESP_OK)
{
ESP_LOGE(TAG, "Failed to clear all keys: %s", esp_err_to_name(err));
}
}
size_t PersistenceManager::GetKeyCount() const
{
if (!EnsureInitialized())
return 0;
nvs_iterator_t it = nullptr;
esp_err_t err = nvs_entry_find(NVS_DEFAULT_PART_NAME, namespace_.c_str(), NVS_TYPE_ANY, &it);
if (err != ESP_OK || it == nullptr)
{
return 0;
}
size_t count = 0;
while (it != nullptr)
{
count++;
err = nvs_entry_next(&it);
if (err != ESP_OK)
{
break;
}
}
nvs_release_iterator(it);
return count;
}
bool PersistenceManager::Save()
{
if (!EnsureInitialized())
return false;
esp_err_t err = nvs_commit(nvs_handle_);
if (err != ESP_OK)
{
ESP_LOGE(TAG, "Failed to commit NVS: %s", esp_err_to_name(err));
return false;
}
return true;
}
bool PersistenceManager::Load()
{
return EnsureInitialized();
}
void PersistenceManager::SetValueImpl(const std::string &key, bool value)
{
if (!EnsureInitialized())
return;
uint8_t val = value ? 1 : 0;
esp_err_t err = nvs_set_u8(nvs_handle_, key.c_str(), val);
if (err != ESP_OK)
{
ESP_LOGE(TAG, "Failed to set bool key '%s': %s", key.c_str(), esp_err_to_name(err));
}
}
void PersistenceManager::SetValueImpl(const std::string &key, int value)
{
if (!EnsureInitialized())
return;
esp_err_t err = nvs_set_i32(nvs_handle_, key.c_str(), value);
if (err != ESP_OK)
{
ESP_LOGE(TAG, "Failed to set int key '%s': %s", key.c_str(), esp_err_to_name(err));
}
}
void PersistenceManager::SetValueImpl(const std::string &key, float value)
{
if (!EnsureInitialized())
return;
esp_err_t err = nvs_set_blob(nvs_handle_, key.c_str(), &value, sizeof(float));
if (err != ESP_OK)
{
ESP_LOGE(TAG, "Failed to set float key '%s': %s", key.c_str(), esp_err_to_name(err));
}
}
void PersistenceManager::SetValueImpl(const std::string &key, double value)
{
if (!EnsureInitialized())
return;
esp_err_t err = nvs_set_blob(nvs_handle_, key.c_str(), &value, sizeof(double));
if (err != ESP_OK)
{
ESP_LOGE(TAG, "Failed to set double key '%s': %s", key.c_str(), esp_err_to_name(err));
}
}
void PersistenceManager::SetValueImpl(const std::string &key, const std::string &value)
{
if (!EnsureInitialized())
return;
esp_err_t err = nvs_set_str(nvs_handle_, key.c_str(), value.c_str());
if (err != ESP_OK)
{
ESP_LOGE(TAG, "Failed to set string key '%s': %s", key.c_str(), esp_err_to_name(err));
}
}
bool PersistenceManager::GetValueImpl(const std::string &key, bool defaultValue) const
{
if (!EnsureInitialized())
return defaultValue;
uint8_t value;
esp_err_t err = nvs_get_u8(nvs_handle_, key.c_str(), &value);
if (err != ESP_OK)
{
return defaultValue;
}
return value != 0;
}
int PersistenceManager::GetValueImpl(const std::string &key, int defaultValue) const
{
if (!EnsureInitialized())
return defaultValue;
int32_t value;
esp_err_t err = nvs_get_i32(nvs_handle_, key.c_str(), &value);
if (err != ESP_OK)
{
return defaultValue;
}
return static_cast<int>(value);
}
float PersistenceManager::GetValueImpl(const std::string &key, float defaultValue) const
{
if (!EnsureInitialized())
return defaultValue;
float value;
size_t required_size = sizeof(float);
esp_err_t err = nvs_get_blob(nvs_handle_, key.c_str(), &value, &required_size);
if (err != ESP_OK || required_size != sizeof(float))
{
return defaultValue;
}
return value;
}
double PersistenceManager::GetValueImpl(const std::string &key, double defaultValue) const
{
if (!EnsureInitialized())
return defaultValue;
double value;
size_t required_size = sizeof(double);
esp_err_t err = nvs_get_blob(nvs_handle_, key.c_str(), &value, &required_size);
if (err != ESP_OK || required_size != sizeof(double))
{
return defaultValue;
}
return value;
}
std::string PersistenceManager::GetValueImpl(const std::string &key, const std::string &defaultValue) const
{
if (!EnsureInitialized())
return defaultValue;
size_t required_size = 0;
esp_err_t err = nvs_get_str(nvs_handle_, key.c_str(), nullptr, &required_size);
if (err != ESP_OK)
{
return defaultValue;
}
std::string value(required_size - 1, '\0'); // -1 for null terminator
err = nvs_get_str(nvs_handle_, key.c_str(), value.data(), &required_size);
if (err != ESP_OK)
{
return defaultValue;
}
return value;
}

View File

@@ -0,0 +1,336 @@
#include "hal_native/PersistenceManager.h"
#include <SDL3/SDL.h>
#include <utility>
PersistenceManager::PersistenceManager(std::string filename) : m_filename(std::move(filename))
{
if (!SDL_WasInit(SDL_INIT_EVENTS))
{
SDL_Init(SDL_INIT_EVENTS);
}
}
PersistenceManager::~PersistenceManager()
{
Save();
}
bool PersistenceManager::HasKey(const std::string &key) const
{
return m_data.contains(key);
}
void PersistenceManager::RemoveKey(const std::string &key)
{
m_data.erase(key);
}
void PersistenceManager::Clear()
{
m_data.clear();
}
bool PersistenceManager::Save()
{
return SaveToFile(m_filename);
}
bool PersistenceManager::Load()
{
return LoadFromFile(m_filename);
}
bool PersistenceManager::SaveToFile(const std::string &filename)
{
SDL_IOStream *stream = SDL_IOFromFile(filename.c_str(), "wb");
if (!stream)
{
SDL_Log("Error opening file for writing: %s", SDL_GetError());
return false;
}
const size_t count = m_data.size();
if (SDL_WriteIO(stream, &count, sizeof(count)) != sizeof(count))
{
SDL_Log("Error writing count: %s", SDL_GetError());
SDL_CloseIO(stream);
return false;
}
for (const auto &[key, value] : m_data)
{
size_t keyLength = key.length();
if (SDL_WriteIO(stream, &keyLength, sizeof(keyLength)) != sizeof(keyLength))
{
SDL_Log("Error writing key length: %s", SDL_GetError());
SDL_CloseIO(stream);
return false;
}
if (SDL_WriteIO(stream, key.c_str(), keyLength) != keyLength)
{
SDL_Log("Error writing key: %s", SDL_GetError());
SDL_CloseIO(stream);
return false;
}
if (!WriteValueToStream(stream, value))
{
SDL_CloseIO(stream);
return false;
}
}
SDL_CloseIO(stream);
return true;
}
bool PersistenceManager::LoadFromFile(const std::string &filename)
{
SDL_IOStream *stream = SDL_IOFromFile(filename.c_str(), "rb");
if (!stream)
{
SDL_Log("File not found or error opening: %s", SDL_GetError());
return false;
}
m_data.clear();
size_t count;
if (SDL_ReadIO(stream, &count, sizeof(count)) != sizeof(count))
{
SDL_Log("Error reading count: %s", SDL_GetError());
SDL_CloseIO(stream);
return false;
}
for (size_t i = 0; i < count; ++i)
{
size_t keyLength;
if (SDL_ReadIO(stream, &keyLength, sizeof(keyLength)) != sizeof(keyLength))
{
SDL_Log("Error reading key length: %s", SDL_GetError());
SDL_CloseIO(stream);
return false;
}
std::string key(keyLength, '\0');
if (SDL_ReadIO(stream, key.data(), keyLength) != keyLength)
{
SDL_Log("Error reading key: %s", SDL_GetError());
SDL_CloseIO(stream);
return false;
}
ValueType value;
if (!ReadValueFromStream(stream, value))
{
SDL_CloseIO(stream);
return false;
}
m_data[key] = value;
}
SDL_CloseIO(stream);
return true;
}
void PersistenceManager::SetValueImpl(const std::string &key, bool value)
{
m_data[key] = value;
}
void PersistenceManager::SetValueImpl(const std::string &key, int value)
{
m_data[key] = value;
}
void PersistenceManager::SetValueImpl(const std::string &key, float value)
{
m_data[key] = value;
}
void PersistenceManager::SetValueImpl(const std::string &key, double value)
{
m_data[key] = value;
}
void PersistenceManager::SetValueImpl(const std::string &key, const std::string &value)
{
m_data[key] = value;
}
bool PersistenceManager::GetValueImpl(const std::string &key, bool defaultValue) const
{
if (const auto it = m_data.find(key); it != m_data.end() && std::holds_alternative<bool>(it->second))
{
return std::get<bool>(it->second);
}
return defaultValue;
}
int PersistenceManager::GetValueImpl(const std::string &key, int defaultValue) const
{
if (const auto it = m_data.find(key); it != m_data.end() && std::holds_alternative<int>(it->second))
{
return std::get<int>(it->second);
}
return defaultValue;
}
float PersistenceManager::GetValueImpl(const std::string &key, float defaultValue) const
{
if (const auto it = m_data.find(key); it != m_data.end() && std::holds_alternative<float>(it->second))
{
return std::get<float>(it->second);
}
return defaultValue;
}
double PersistenceManager::GetValueImpl(const std::string &key, double defaultValue) const
{
if (const auto it = m_data.find(key); it != m_data.end() && std::holds_alternative<double>(it->second))
{
return std::get<double>(it->second);
}
return defaultValue;
}
std::string PersistenceManager::GetValueImpl(const std::string &key, const std::string &defaultValue) const
{
if (const auto it = m_data.find(key); it != m_data.end() && std::holds_alternative<std::string>(it->second))
{
return std::get<std::string>(it->second);
}
return defaultValue;
}
bool PersistenceManager::WriteValueToStream(SDL_IOStream *stream, const ValueType &value)
{
const TypeId typeId = GetTypeId(value);
if (SDL_WriteIO(stream, &typeId, sizeof(typeId)) != sizeof(typeId))
{
SDL_Log("Error writing type ID: %s", SDL_GetError());
return false;
}
switch (typeId)
{
case TypeId::BOOL: {
const bool val = std::get<bool>(value);
return SDL_WriteIO(stream, &val, sizeof(val)) == sizeof(val);
}
case TypeId::INT: {
const int val = std::get<int>(value);
return SDL_WriteIO(stream, &val, sizeof(val)) == sizeof(val);
}
case TypeId::FLOAT: {
const float val = std::get<float>(value);
return SDL_WriteIO(stream, &val, sizeof(val)) == sizeof(val);
}
case TypeId::DOUBLE: {
const double val = std::get<double>(value);
return SDL_WriteIO(stream, &val, sizeof(val)) == sizeof(val);
}
case TypeId::STRING: {
const auto &str = std::get<std::string>(value);
const size_t length = str.length();
if (SDL_WriteIO(stream, &length, sizeof(length)) != sizeof(length))
{
return false;
}
return SDL_WriteIO(stream, str.c_str(), length) == length;
}
}
return false;
}
bool PersistenceManager::ReadValueFromStream(SDL_IOStream *stream, ValueType &value)
{
TypeId typeId;
if (SDL_ReadIO(stream, &typeId, sizeof(typeId)) != sizeof(typeId))
{
SDL_Log("Error reading type ID: %s", SDL_GetError());
return false;
}
switch (typeId)
{
case TypeId::BOOL: {
bool val;
if (SDL_ReadIO(stream, &val, sizeof(val)) == sizeof(val))
{
value = val;
return true;
}
break;
}
case TypeId::INT: {
int val;
if (SDL_ReadIO(stream, &val, sizeof(val)) == sizeof(val))
{
value = val;
return true;
}
break;
}
case TypeId::FLOAT: {
float val;
if (SDL_ReadIO(stream, &val, sizeof(val)) == sizeof(val))
{
value = val;
return true;
}
break;
}
case TypeId::DOUBLE: {
double val;
if (SDL_ReadIO(stream, &val, sizeof(val)) == sizeof(val))
{
value = val;
return true;
}
break;
}
case TypeId::STRING: {
size_t length;
if (SDL_ReadIO(stream, &length, sizeof(length)) != sizeof(length))
{
return false;
}
std::string str(length, '\0');
if (SDL_ReadIO(stream, str.data(), length) == length)
{
value = str;
return true;
}
break;
}
}
SDL_Log("Error reading value: %s", SDL_GetError());
return false;
}
PersistenceManager::TypeId PersistenceManager::GetTypeId(const ValueType &value)
{
if (std::holds_alternative<bool>(value))
return TypeId::BOOL;
if (std::holds_alternative<int>(value))
return TypeId::INT;
if (std::holds_alternative<float>(value))
return TypeId::FLOAT;
if (std::holds_alternative<double>(value))
return TypeId::DOUBLE;
if (std::holds_alternative<std::string>(value))
return TypeId::STRING;
return TypeId::BOOL;
}