77 lines
3.5 KiB
C++
77 lines
3.5 KiB
C++
#pragma once
|
||
// owned_manifest — the set of files the bank system ITSELF created; every file the
|
||
// capture path writes gets recorded here so prune can tell the system's own orphans
|
||
// (owned ∩ present − referenced) apart from hand-dropped files. Writes and persists
|
||
// the manifest only — no prune logic lives here.
|
||
//
|
||
// NOT a mirror of the bank index: removing/moving an index entry does NOT remove
|
||
// the file's manifest record (the manifest tracks files *created*; prune reconciles
|
||
// manifest-vs-index later). Only the capture add-path adds to it — no remove verb.
|
||
//
|
||
// Paths are ALWAYS project-relative (same invariant as Sample.relativePath). add()
|
||
// rejects an absolute path rather than guess a relativization — the pure model has
|
||
// no project root, so "normalizing" could point at the wrong file.
|
||
|
||
#include <optional>
|
||
#include <string>
|
||
#include <vector>
|
||
|
||
namespace reasampler::model {
|
||
|
||
// Outcome of an add(). Mirrors BankModel::AddResult's honesty — the op reports what
|
||
// happened rather than silently mutating on a bad request.
|
||
// - Added: the path was new and recorded.
|
||
// - AlreadyPresent: the path was already in the manifest (dedup no-op).
|
||
// - RejectedEmptyPath: the path was empty.
|
||
// - RejectedAbsolutePath: the path was absolute (relative-paths-only invariant).
|
||
enum class ManifestAddResult {
|
||
Added,
|
||
AlreadyPresent,
|
||
RejectedEmptyPath,
|
||
RejectedAbsolutePath,
|
||
};
|
||
|
||
// The owned-file manifest: an insertion-ordered, deduplicated set of project-relative
|
||
// paths the capture path has created. Insertion order is preserved so serialize()
|
||
// round-trips byte-identically (deterministic ext-state, mirror of the index).
|
||
class OwnedFileManifest {
|
||
public:
|
||
OwnedFileManifest() = default;
|
||
|
||
// Record a project-relative path as owned. Rejects an empty or absolute path (no
|
||
// mutation). A path already present is a dedup no-op (AlreadyPresent), so a repeat
|
||
// capture of an identical request does not double-record.
|
||
ManifestAddResult add(const std::string& relativePath);
|
||
|
||
// True iff the exact path string is recorded. Prune uses this to attribute a
|
||
// present file to the bank system. Exact string match — path normalization (if
|
||
// any) is the caller's concern, consistent across add and query.
|
||
bool contains(const std::string& relativePath) const;
|
||
|
||
// The owned paths in insertion order. Prune unions this with the on-disk file
|
||
// set; here it is the round-trip + query surface.
|
||
const std::vector<std::string>& paths() const { return paths_; }
|
||
|
||
std::size_t size() const { return paths_.size(); }
|
||
bool empty() const { return paths_.empty(); }
|
||
|
||
bool operator==(const OwnedFileManifest& o) const { return paths_ == o.paths_; }
|
||
|
||
// -- Persistence ---------------------------------------------------------
|
||
|
||
// Serialize to a JSON string (lossless round-trip): deserialize(serialize(x)) == x.
|
||
// An empty manifest serializes to a well-formed empty shape (round-trips to empty).
|
||
std::string serialize() const;
|
||
|
||
// Parse a manifest JSON produced by serialize(). std::nullopt on malformed input
|
||
// (the persist shell warns + falls back to an empty manifest, mirroring the bank /
|
||
// view malformed handling). An empty/absent stored value is the caller's concern
|
||
// (an empty string is not valid JSON) — the shell maps absence to a fresh manifest.
|
||
static std::optional<OwnedFileManifest> deserialize(const std::string& json);
|
||
|
||
private:
|
||
std::vector<std::string> paths_; // insertion order; deduplicated
|
||
};
|
||
|
||
} // namespace reasampler::model
|