载入中...
搜索中...
未找到
EditorPersistence.cpp
浏览该文件的文档.
2
3namespace eve::editor {
4namespace {
5
6EditorValue operationValue(const DomainOperation& operation) {
8 value["type"] = EditorValue(operation.type);
9 value["inverseType"] = EditorValue(operation.inverseType);
10 value["target"] = EditorValue(operation.target.value());
11 value["payload"] = operation.payload;
12 value["inverse"] = operation.inverse;
13 value["hasInverse"] = EditorValue(operation.hasInverse);
14 value["mergeKey"] = EditorValue(operation.mergeKey);
15 return EditorValue(std::move(value));
16}
17
18DomainOperation decodeOperation(const EditorValue& value) {
20 const auto* object = value.getIf<EditorValue::Object>();
21 if (!object) return operation;
22 const auto text = [&](const char* key) {
23 auto found = object->find(key);
24 const auto* result = found == object->end() ? nullptr : found->second.getIf<std::string>();
25 return result ? *result : std::string{};
26 };
27 operation.type = text("type");
28 operation.inverseType = text("inverseType");
29 operation.target = TargetId(text("target"));
30 operation.mergeKey = text("mergeKey");
31 auto payload = object->find("payload");
32 if (payload != object->end()) operation.payload = payload->second;
33 auto inverse = object->find("inverse");
34 if (inverse != object->end()) operation.inverse = inverse->second;
35 auto hasInverse = object->find("hasInverse");
36 const auto* flag = hasInverse == object->end() ? nullptr : hasInverse->second.getIf<bool>();
37 operation.hasInverse = flag && *flag;
38 return operation;
39}
40
41Result<EditorPersistenceSnapshot> persistenceError(EditorStatus status, const char* rule, std::string message) {
42 return eve::editing::failed<EditorPersistenceSnapshot>(status, RuleId(rule), std::move(message));
43}
44
45} // namespace
46
48 if (!store_ || resourceUri_.empty())
49 return persistenceError(EditorStatus::Rejected, "editor.persistence.invalid",
50 "Persistence store and URI are required");
51 auto stored = store_->read(resourceUri_);
52 if (!stored.ok()) {
53 if (stored.code() == EditorStatus::NotFound) {
55 empty.kind = kind_;
56 return eve::editing::applied<EditorPersistenceSnapshot>(std::move(empty));
57 }
59 }
60 return decode(kind_, stored.value());
61}
62
64 EditorValue content,
65 std::vector<DomainOperation> journal) {
66 if (!store_ || base.kind != kind_)
67 return persistenceError(EditorStatus::Rejected, "editor.persistence.kind-mismatch",
68 "Persistence checkpoint belongs to another backend kind");
69 EditorValue::Array serializedJournal;
70 for (const DomainOperation& operation : journal) serializedJournal.push_back(operationValue(operation));
71 EditorValue::Object envelope;
72 envelope["schemaVersion"] = EditorValue(1);
73 envelope["content"] = content;
74 envelope["journal"] = EditorValue(std::move(serializedJournal));
75 auto stored =
76 store_->compareAndSwap(resourceUri_, base.revision, base.contentHash, EditorValue(std::move(envelope)));
78 return decode(kind_, stored.value());
79}
80
81Result<EditorPersistenceSnapshot> EditorPersistenceAdapter::decode(EditorPersistenceKind kind,
82 const StoredDocument& stored) {
83 const auto* envelope = stored.content.getIf<EditorValue::Object>();
84 if (!envelope)
85 return persistenceError(EditorStatus::Failed, "editor.persistence.invalid-envelope",
86 "Persistence checkpoint must be an object");
87 const auto content = envelope->find("content");
88 const auto journal = envelope->find("journal");
89 const auto* journalValues = journal == envelope->end() ? nullptr : journal->second.getIf<EditorValue::Array>();
90 if (content == envelope->end() || !journalValues)
91 return persistenceError(EditorStatus::Failed, "editor.persistence.invalid-envelope",
92 "Persistence checkpoint content or journal is missing");
94 result.kind = kind;
95 result.revision = stored.revision;
96 result.contentHash = stored.contentHash;
97 result.content = content->second;
98 for (const EditorValue& value : *journalValues) result.journal.push_back(decodeOperation(value));
99 return eve::editing::applied<EditorPersistenceSnapshot>(std::move(result));
100}
101
102} // namespace eve::editor
ActionParameterOperation operation
double value
Value::Object payload
std::vector< std::uint8_t > stored
Definition Evpack.cpp:171
std::string message
std::uint32_t key
wgpu::PopErrorScopeStatus status
std::string text
TokenKind kind
bool found
Json object
Move-only operation result carrying either a value or Status.
Definition Result.h:155
static Result failure(Status status)
Construct a failed result from a structured status.
Definition Result.h:175
Deterministic owning value tree shared by authoring hosts.
std::vector< Value > Array
std::map< std::string, Value > Object
Result< EditorPersistenceSnapshot > commit(const EditorPersistenceSnapshot &base, EditorValue content, std::vector< DomainOperation > journal)
Atomically commit a checkpoint against its loaded revision/hash.
Result< EditorPersistenceSnapshot > load() const
Load the last committed checkpoint and journal.
virtual Result< StoredDocument > read(const std::string &resourceUri) const =0
Read the latest value for a resource URI.
virtual Result< StoredDocument > compareAndSwap(const std::string &resourceUri, Revision expectedRevision, const std::string &expectedContentHash, const EditorValue &content)=0
Replace a value only when the expected disk revision still matches.
eve::editing::Value EditorValue
Compatibility alias for the UI-independent authoring value tree.
Definition EditorValue.h:8
eve::editing::TargetId TargetId
Definition EditorIds.h:29
eve::editing::RuleId RuleId
Definition EditorIds.h:32
EditorPersistenceKind
Persistence target selected by a game/editor host.
eve::editing::DomainOperation DomainOperation
eve::StatusCode EditorStatus
Definition EditorResult.h:8
DomainOperation public API.
Loaded checkpoint plus the domain operations recorded with it.
Value snapshot returned by an atomic document store.