Files
iKvxx/include/ikvxx/ikvxx.hpp
GigabiteStudios 5500cd6984
Some checks failed
Build / cmake-build (push) Failing after 20s
Build / unit-tests (push) Failing after 24s
feat(file): Expose API to inspect iKv file format and storage kind
2026-06-19 16:50:55 -05:00

166 lines
5.5 KiB
C++

#pragma once
#include <cstddef>
#include <cstdint>
#include <memory>
#include <stdexcept>
#include <string>
#include <vector>
struct ikv_node_t;
namespace ikv {
/// Runtime value types exposed by iKv.
enum ValueType {
nullValue = 0,
stringValue,
intValue,
realValue,
booleanValue,
objectValue,
arrayValue
};
/// On-disk iKv format versions supported for explicit writes.
enum class Version : unsigned { v1 = 1, v2 = 2 };
/// Serialized storage kind of an iKv document.
enum class StorageKind : unsigned {
unknown = 0,
text,
binary
};
/// File format information reported by the library.
struct FileFormat {
StorageKind storage = StorageKind::unknown;
Version version = Version::v2;
};
/// Error raised for invalid types, unsupported operations, parse failures,
/// and I/O failures.
class Error : public std::runtime_error {
public:
using std::runtime_error::runtime_error;
};
/// RAII handle to an iKv root or a node owned by an iKv tree.
///
/// Copies share ownership of the same tree. Child handles remain valid while their
/// node exists, but should be reacquired after replacing that node or refreshing the root.
class Value {
public:
using ArrayIndex = std::uint32_t;
/// Creates an object or array root. Scalar roots are not supported by iKv.
explicit Value(ValueType type = objectValue, std::string root_name = "root");
Value(const Value&) = default;
/// Structural assignment is unavailable because iKv cannot clone arbitrary subtrees.
Value& operator=(const Value&) = delete;
/// Parses auto-detected iKv1 or iKv2 text.
static Value parse(const std::string& text);
/// Loads an auto-detected iKv1 or iKv2 text file.
static Value load(const std::string& path);
/// Parses an iKv binary buffer. The resulting tree owns any required data.
static Value fromBinary(const void* data, std::size_t size);
/// Loads an auto-detected binary iKv file.
static Value loadBinary(const std::string& path);
/// Returns the node's runtime type, or nullValue for a missing member.
ValueType type() const noexcept;
bool isNull() const noexcept;
bool isString() const noexcept;
bool isInt() const noexcept;
bool isDouble() const noexcept;
bool isBool() const noexcept;
bool isObject() const noexcept;
bool isArray() const noexcept;
bool empty() const;
std::size_t size() const;
std::string name() const;
bool isMember(const std::string& key) const;
/// Looks up an object member. A missing non-const member returns an assignable null Value.
Value operator[](const std::string& key);
Value operator[](const char* key);
Value operator[](const std::string& key) const;
Value operator[](const char* key) const;
Value operator[](ArrayIndex index);
Value operator[](int index);
Value operator[](ArrayIndex index) const;
Value operator[](int index) const;
/// Returns an object member or a shared copy of fallback when the key is absent.
Value get(const std::string& key, const Value& fallback) const;
/// Assigns a scalar to an object member returned by operator[].
Value& operator=(const std::string& value);
Value& operator=(const char* value);
Value& operator=(std::int64_t value);
Value& operator=(int value);
Value& operator=(double value);
Value& operator=(bool value);
/// Adds or replaces an object member and returns a handle to it.
Value makeObject(const std::string& key);
/// Adds an array member. nullValue creates an untyped array.
Value makeArray(const std::string& key, ValueType element_type = nullValue);
/// Appends to an array. Typed arrays reject incompatible values with Error.
Value append(const std::string& value);
Value append(const char* value);
Value append(std::int64_t value);
Value append(int value);
Value append(double value);
Value append(bool value);
Value appendObject();
std::string asString() const;
std::int64_t asInt64() const;
int asInt() const;
double asDouble() const;
bool asBool() const;
ikv_node_t* get_node() const { return node_; }
/// Writes text or binary output, using iKv2 unless a version is specified.
void write(const std::string& path, Version version = Version::v2) const;
void writeBinary(const std::string& path, Version version = Version::v2) const;
std::vector<std::uint8_t> toBinary(Version version = Version::v2) const;
/// Replaces this root in place from a text or binary path while preserving shared handles.
/// Only mutable root Values can be refreshed; failure leaves the existing tree unchanged.
void refresh(const std::string& path);
private:
struct Deleter { void operator()(ikv_node_t* node) const noexcept; };
using Owner = std::shared_ptr<ikv_node_t>;
Value(Owner owner, ikv_node_t* node, ikv_node_t* parent, std::string key, bool read_only = false);
static Value adopt(ikv_node_t* node);
void require(ValueType expected, const char* operation) const;
void requireMutable(const char* operation) const;
void requireObjectParent(const char* operation) const;
Value appended(std::size_t old_size);
Owner owner_;
ikv_node_t* node_ = nullptr;
ikv_node_t* parent_ = nullptr;
std::string key_;
bool read_only_ = false;
};
/// Inspects an iKv file and reports whether it is text or binary plus its version.
/// Throws Error when the file cannot be identified.
FileFormat inspectFile(const std::string& path);
} // namespace ikv