SaverInfo & AtomicWrite
Overview
Step 3.1.1 of the Command Architecture Roadmap introduces two pieces of core infrastructure for uniform data saving:
SaverInfo— a metadata struct describing a registered saver’s capabilities.AtomicWrite— a utility for crash-safe file writes.
These live in src/DataManager/IO/core/ alongside the existing LoaderRegistry.
SaverInfo
SaverInfo (src/DataManager/IO/core/SaverInfo.hpp) describes a single saver capability within a format loader:
| Field | Type | Description |
|---|---|---|
format |
std::string |
Format identifier (e.g., "csv", "capnproto") |
data_type |
DM_DataType |
The data type this saver handles |
description |
std::string |
Human-readable summary |
schema |
ParameterSchema |
Compile-time extracted parameter schema |
IFormatLoader::getSaverInfo()
A new virtual method on IFormatLoader:
virtual std::vector<SaverInfo> getSaverInfo() const { return {}; }Subclasses that implement save() should override this method to advertise their save capabilities along with typed parameter schemas extracted via extractParameterSchema<OptionStruct>().
LoaderRegistry::getSupportedSaveFormats()
Two query methods on LoaderRegistry aggregate saver metadata from all registered loaders:
std::vector<SaverInfo> getSupportedSaveFormats() const;
std::vector<SaverInfo> getSupportedSaveFormats(DM_DataType type) const;The first returns all saver capabilities; the second filters by data type.
AtomicWrite
atomicWriteFile() (src/DataManager/IO/core/AtomicWrite.hpp) provides crash-safe file writing:
bool atomicWriteFile(
std::filesystem::path const & target_path,
std::function<bool(std::ostream &)> const & write_callback);Algorithm:
- Create parent directories if they don’t exist.
- Write to
target_path.tmpvia the callback. - If the callback succeeds and the stream is good, rename
.tmp→ target. - On any failure, remove the
.tmpfile and leave the target untouched.
This ensures that a crash mid-write cannot corrupt an existing file.
Registration Overloads
registerInternalLoaders() and registerExternalLoaders() now have overloads accepting a LoaderRegistry & parameter:
void registerInternalLoaders(LoaderRegistry & registry);
void registerExternalLoaders(LoaderRegistry & registry);These enable tests to use a fresh (non-singleton) registry instance.
Tests
tests/DataManager/IO/atomic_write.test.cpp— 6 test cases covering success, failure, directory creation, overwrite, original preservation, and binary data.tests/DataManager/IO/saver_registry.test.cpp— 6 test cases verifying empty registry queries, loaders-without-savers queries, and a stub loader with a saver.