Q-W1 pt2: core/shell/app relocation + sub-namespaces; one concrete ui::Rect (LTRB fork retired); slot_map split from bank_book; BankIndex→BankModel; 59/59 green
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
#pragma once
|
||||
// owned_manifest — the pure core of the owned-file manifest seam (Phase B, B-cap).
|
||||
//
|
||||
// PURE MODULE (CLAUDE.md §load-bearing split): NO REAPER types, NO SWELL, NO
|
||||
// vendor/ includes. Standard library only. Unit-tested outside the DAW — the same
|
||||
// "small pure type + JSON round-trip" pattern as wav_trim / tab_strip.
|
||||
//
|
||||
// -- What it is --------------------------------------------------------------
|
||||
//
|
||||
// The set of files the bank system ITSELF created — every file the capture path
|
||||
// writes gets recorded here. Phase R prune consumes it to tell the system's own
|
||||
// orphans (owned ∩ present − referenced) apart from hand-dropped files. B-cap only
|
||||
// WRITES and PERSISTS the manifest; no prune logic lives here (fork R-D, settled
|
||||
// 2026-07-24: "defer the feature, design the seam").
|
||||
//
|
||||
// -- What it is NOT ----------------------------------------------------------
|
||||
//
|
||||
// It is NOT a mirror of the bank index. Removing or moving an index entry does NOT
|
||||
// remove the file's manifest record: the manifest tracks files *created*, and prune
|
||||
// (Phase R) reconciles manifest-vs-index later. The ONLY thing that adds to it is
|
||||
// the capture add-path. There is deliberately no remove verb here.
|
||||
//
|
||||
// -- The relative-paths-only invariant ---------------------------------------
|
||||
//
|
||||
// A manifest path is ALWAYS project-relative (same invariant as Sample.relativePath
|
||||
// and the persisted BankModel). add() rejects an absolute path rather than guess a
|
||||
// relativization — the pure model has no project root, so a "normalization" would be
|
||||
// a guess that could point at the wrong file (mirror of BankModel::add's rejection).
|
||||
|
||||
#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. Phase R 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. Phase R 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
|
||||
Reference in New Issue
Block a user