yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
transaction.h
Go to the documentation of this file.
1// Transaction helper for atomic ROM operations with rollback
2//
3// Usage:
4// yaze::Transaction tx(rom);
5// auto status = tx.WriteByte(addr, val)
6// .WriteWord(addr2, val2)
7// .Commit();
8//
9// If any write fails before Commit, subsequent operations are skipped and
10// Commit() will Rollback() previously applied writes in reverse order.
11
12#include <cstdint>
13#include <string>
14#include <variant>
15#include <vector>
16
17#include "absl/status/status.h"
19#include "rom/rom.h"
20
21namespace yaze {
22
24 public:
25 explicit Transaction(Rom& rom) : rom_(rom) {}
26
27 Transaction& WriteByte(int address, uint8_t value) {
28 if (!status_.ok())
29 return *this;
30 auto original = rom_.ReadByte(address);
31 if (!original.ok()) {
32 status_ = original.status();
33 return *this;
34 }
35 status_ = rom_.WriteByte(address, value);
36 if (status_.ok()) {
37 operations_.push_back({address, static_cast<uint8_t>(*original),
39 }
40 return *this;
41 }
42
43 Transaction& WriteWord(int address, uint16_t value) {
44 if (!status_.ok())
45 return *this;
46 auto original = rom_.ReadWord(address);
47 if (!original.ok()) {
48 status_ = original.status();
49 return *this;
50 }
51 status_ = rom_.WriteWord(address, value);
52 if (status_.ok()) {
53 operations_.push_back({address, static_cast<uint16_t>(*original),
55 }
56 return *this;
57 }
58
59 Transaction& WriteLong(int address, uint32_t value) {
60 if (!status_.ok())
61 return *this;
62 auto original = rom_.ReadLong(address);
63 if (!original.ok()) {
64 status_ = original.status();
65 return *this;
66 }
67 status_ = rom_.WriteLong(address, value);
68 if (status_.ok()) {
69 operations_.push_back({address, static_cast<uint32_t>(*original),
71 }
72 return *this;
73 }
74
75 Transaction& WriteVector(int address, const std::vector<uint8_t>& data) {
76 if (!status_.ok())
77 return *this;
78 auto original =
79 rom_.ReadByteVector(address, static_cast<uint32_t>(data.size()));
80 if (!original.ok()) {
81 status_ = original.status();
82 return *this;
83 }
84 status_ = rom_.WriteVector(address, data);
85 if (status_.ok()) {
86 operations_.push_back({address, *original, OperationType::kWriteVector});
87 }
88 return *this;
89 }
90
91 Transaction& WriteColor(int address, const gfx::SnesColor& color) {
92 if (!status_.ok())
93 return *this;
94 // Store original raw 16-bit value for rollback via WriteWord.
95 auto original_word = rom_.ReadWord(address);
96 if (!original_word.ok()) {
97 status_ = original_word.status();
98 return *this;
99 }
100 status_ = rom_.WriteColor(address, color);
101 if (status_.ok()) {
102 operations_.push_back({address, static_cast<uint16_t>(*original_word),
104 }
105 return *this;
106 }
107
108 absl::Status Commit() {
109 if (!status_.ok()) {
110 Rollback();
111 }
112 return status_;
113 }
114
115 void Rollback() {
116 for (auto it = operations_.rbegin(); it != operations_.rend(); ++it) {
117 const auto& op = *it;
118 switch (op.type) {
120 (void)rom_.WriteByte(op.address,
121 std::get<uint8_t>(op.original_value));
122 break;
124 (void)rom_.WriteWord(op.address,
125 std::get<uint16_t>(op.original_value));
126 break;
128 (void)rom_.WriteLong(op.address,
129 std::get<uint32_t>(op.original_value));
130 break;
132 (void)rom_.WriteVector(
133 op.address, std::get<std::vector<uint8_t>>(op.original_value));
134 break;
136 (void)rom_.WriteWord(op.address,
137 std::get<uint16_t>(op.original_value));
138 break;
139 }
140 }
141 operations_.clear();
142 }
143
144 private:
145 enum class OperationType {
151 };
152
153 struct Operation {
155 std::variant<uint8_t, uint16_t, uint32_t, std::vector<uint8_t>>
158 };
159
161 absl::Status status_;
162 std::vector<Operation> operations_;
163};
164
165// Whole-buffer transaction used by coordinated editor saves. Individual
166// editor serializers do not share a Transaction instance and may resize the
167// ROM, so recording only writes made through Transaction is insufficient for
168// the File > Save ROM pipeline. This guard snapshots the complete in-memory
169// state and restores it unless the caller commits after the atomic disk write.
171 public:
173 : rom_(rom),
174 data_(rom.vector()),
175 filename_(rom.filename()),
176 dirty_(rom.dirty()) {}
177
180
182 if (!committed_) {
183 Rollback();
184 }
185 }
186
187 void Commit() { committed_ = true; }
188
189 void Rollback() {
190 if (committed_) {
191 return;
192 }
194 // Keep Rom::size() synchronized if a serializer resized the buffer.
195 rom_.Expand(static_cast<int>(data_.size()));
198 committed_ = true;
199 }
200
201 private:
203 std::vector<uint8_t> data_;
204 std::string filename_;
205 bool dirty_ = false;
206 bool committed_ = false;
207};
208
209} // namespace yaze
The Rom class is used to load, save, and modify Rom data. This is a generic SNES ROM container and do...
Definition rom.h:28
absl::StatusOr< std::vector< uint8_t > > ReadByteVector(uint32_t offset, uint32_t length) const
Definition rom.cc:541
absl::Status WriteColor(uint32_t address, const gfx::SnesColor &color)
Definition rom.cc:688
absl::Status WriteByte(int addr, uint8_t value)
Definition rom.cc:586
absl::StatusOr< uint8_t > ReadByte(int offset) const
Definition rom.cc:518
void set_dirty(bool dirty)
Definition rom.h:146
absl::Status WriteVector(int addr, std::vector< uint8_t > data)
Definition rom.cc:658
void Expand(int size)
Definition rom.h:60
absl::StatusOr< uint16_t > ReadWord(int offset) const
Definition rom.cc:526
auto & mutable_vector()
Definition rom.h:156
auto set_filename(std::string_view name)
Definition rom.h:158
absl::Status WriteWord(int addr, uint16_t value)
Definition rom.cc:605
absl::Status WriteLong(uint32_t addr, uint32_t value)
Definition rom.cc:632
absl::StatusOr< uint32_t > ReadLong(int offset) const
Definition rom.cc:533
ScopedRomTransaction(const ScopedRomTransaction &)=delete
std::vector< uint8_t > data_
ScopedRomTransaction & operator=(const ScopedRomTransaction &)=delete
Transaction(Rom &rom)
Definition transaction.h:25
Transaction & WriteVector(int address, const std::vector< uint8_t > &data)
Definition transaction.h:75
std::vector< Operation > operations_
Transaction & WriteLong(int address, uint32_t value)
Definition transaction.h:59
Transaction & WriteWord(int address, uint16_t value)
Definition transaction.h:43
absl::Status Commit()
Transaction & WriteByte(int address, uint8_t value)
Definition transaction.h:27
absl::Status status_
Transaction & WriteColor(int address, const gfx::SnesColor &color)
Definition transaction.h:91
SNES Color container.
Definition snes_color.h:110
std::variant< uint8_t, uint16_t, uint32_t, std::vector< uint8_t > > original_value