Skip to content

Commit deb7bfb

Browse files
committed
feat(api): full program serialization supported
1 parent b9436ce commit deb7bfb

File tree

7 files changed

+79
-41
lines changed

7 files changed

+79
-41
lines changed

libs/api/include/rtbot/FactoryOp.h

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -57,15 +57,9 @@ class FactoryOp {
5757

5858
static Program createProgram(string const& json_string) { return Program(json_string); }
5959

60-
Bytes collect(string const& programId) {
61-
if (this->programs.count(programId) == 0) throw runtime_error("Program " + programId + " was not found");
62-
return programs.at(programId).collect();
63-
}
60+
Bytes serialize(string const& programId);
6461

65-
void restore(string const& programId, Bytes const& bytes) {
66-
if (this->programs.count(programId) == 0) throw runtime_error("Program " + programId + " was not found");
67-
programs.at(programId).restore(bytes);
68-
}
62+
string createProgram(string const& id, Bytes const& bytes);
6963

7064
string createProgram(string const& id, string const& json_program);
7165

libs/api/include/rtbot/Program.h

Lines changed: 29 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include <map>
55
#include <memory>
66
#include <optional>
7+
#include <string>
78

89
#include "rtbot/Operator.h"
910

@@ -13,41 +14,46 @@ using namespace std;
1314

1415
struct Program {
1516
private:
17+
string program_json;
1618
map<string, Op_ptr<uint64_t, double>> all_op; // from id to operator
1719
string entryOperator; // id of the entry operator
1820
map<string, vector<string>> outputFilter;
1921

2022
public:
2123
explicit Program(string const& json_string);
24+
explicit Program(Bytes const& bytes) {
25+
// create an iterator
26+
Bytes::const_iterator bytes_it = bytes.begin();
27+
// read the size of the program json
28+
uint64_t size = *reinterpret_cast<const uint64_t*>(&(*bytes_it));
29+
bytes_it += sizeof(size);
30+
// read the program json
31+
program_json = string(bytes_it, bytes_it + size);
32+
bytes_it += size;
33+
34+
// init the program
35+
init();
36+
37+
// load the state of the operators
38+
while (bytes_it != bytes.end()) {
39+
// read the size of the operator id
40+
size = *reinterpret_cast<const uint64_t*>(&(*bytes_it));
41+
bytes_it += sizeof(size);
42+
string opId(bytes_it, bytes_it + size);
43+
bytes_it += size;
44+
45+
// read the operator state
46+
all_op.at(opId)->restore(bytes_it);
47+
}
48+
}
2249

2350
Program(Program const&) = delete;
2451
void operator=(Program const&) = delete;
2552
Program(Program&& other) = default;
2653

27-
Bytes collect() {
28-
Bytes bytes;
29-
for (auto it = this->all_op.begin(); it != this->all_op.end(); ++it) {
30-
Bytes opBytes = it->second->collect();
31-
bytes.insert(bytes.end(), opBytes.begin(), opBytes.end());
32-
}
33-
34-
return bytes;
35-
}
36-
37-
void restore(Bytes const& bytes) {
38-
Bytes::const_iterator bytes_it = bytes.begin();
39-
for (auto it = this->all_op.begin(); it != this->all_op.end(); ++it) {
40-
it->second->restore(bytes_it);
41-
}
42-
}
54+
void init();
4355

44-
string debug() {
45-
string toReturn;
46-
for (auto it = this->all_op.begin(); it != this->all_op.end(); ++it) {
47-
toReturn += "\n " + it->second->debug("");
48-
}
49-
return toReturn;
50-
}
56+
Bytes serialize();
5157

5258
string getProgramEntryOperatorId() { return entryOperator; }
5359

libs/api/include/rtbot/bindings.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,8 @@
1313
using namespace std;
1414
using namespace rtbot;
1515

16-
Bytes collect(string const& programId);
17-
// after creating a program, we can restore it with the a collected state
18-
void restore(string const& programId, Bytes const& bytes);
16+
Bytes serializeProgram(string const& programId);
17+
void createProgram(string const& programId, Bytes const& bytes);
1918

2019
ProgramMessage<uint64_t, double> processMessageMapNative(string const& programId,
2120
const OperatorMessage<uint64_t, double>& messagesMap);

libs/api/src/FactoryOp.cpp

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -401,9 +401,20 @@ void from_json(const json& j, Pipeline<T, V>& p) {
401401

402402
/* Operators serialization - deserialization - end */
403403

404+
Bytes FactoryOp::serialize(string const& programId) {
405+
if (this->programs.count(programId) == 0) throw runtime_error("Program " + programId + " was not found");
406+
return programs.at(programId).serialize();
407+
}
408+
409+
string FactoryOp::createProgram(string const& id, Bytes const& bytes) {
410+
if (this->programs.count(id) > 0) throw runtime_error("Program " + id + " already exists");
411+
programs.emplace(id, Program(bytes));
412+
return id;
413+
}
414+
404415
string FactoryOp::createProgram(string const& id, string const& json_program) {
405416
try {
406-
programs.emplace(id, createProgram(json_program));
417+
programs.emplace(id, Program(json_program));
407418
return "";
408419
} catch (const json::parse_error& e) {
409420
// output exception information

libs/api/src/Program.cpp

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,12 @@ inline void from_json(const json& j, OpConnection& p) {
3434
}
3535

3636
Program::Program(const string& json_string) {
37-
auto j = json::parse(json_string);
37+
program_json = json_string;
38+
init();
39+
}
3840

41+
void Program::init() {
42+
auto j = json::parse(program_json);
3943
this->entryOperator = j.value("entryOperator", "");
4044

4145
if (this->entryOperator.empty()) throw runtime_error("Entry operator was not specified");
@@ -72,6 +76,31 @@ Program::Program(const string& json_string) {
7276
}
7377
}
7478

79+
Bytes Program::serialize() {
80+
Bytes bytes;
81+
82+
// save the program json definition, starting with the size of the string
83+
uint64_t size = program_json.size();
84+
bytes.insert(bytes.end(), reinterpret_cast<const unsigned char*>(&size),
85+
reinterpret_cast<const unsigned char*>(&size) + sizeof(size));
86+
bytes.insert(bytes.end(), program_json.begin(), program_json.end());
87+
88+
// save the state of the operators
89+
for (auto& [opId, op] : all_op) {
90+
// save the size of the operator id
91+
size = opId.size();
92+
bytes.insert(bytes.end(), reinterpret_cast<const unsigned char*>(&size),
93+
reinterpret_cast<const unsigned char*>(&size) + sizeof(size));
94+
bytes.insert(bytes.end(), opId.begin(), opId.end());
95+
96+
// save the operator state
97+
Bytes opBytes = op->collect();
98+
bytes.insert(bytes.end(), opBytes.begin(), opBytes.end());
99+
}
100+
101+
return bytes;
102+
}
103+
75104
string Program::getProgram() {
76105
string out = "";
77106
for (auto it = this->all_op.begin(); it != this->all_op.end(); ++it) {

libs/api/src/bindings.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,9 @@ void from_json(const json& j, Message<T, V>& p) {
4040

4141
} // namespace rtbot
4242

43-
Bytes collect(string const& programId) { return factory.collect(programId); }
43+
Bytes serializeProgram(string const& programId) { return factory.serialize(programId); }
4444

45-
void restore(string const& programId, Bytes const& bytes) { factory.restore(programId, bytes); }
45+
void createProgram(string const& programId, Bytes const& bytes) { factory.createProgram(programId, bytes); }
4646

4747
ProgramMessage<uint64_t, double> processMessageMapNative(string const& programId,
4848
const OperatorMessage<uint64_t, double>& messagesMap) {

libs/api/test/test_program_collect_restore.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,9 @@ TEST_CASE("Program collect and restore") {
4646
auto output = program.receive(messagesMap);
4747
}
4848

49-
Bytes bytes = program.collect();
49+
Bytes bytes = program.serialize();
5050
// create a new program
51-
auto program2 = FactoryOp::createProgram(json.dump().c_str());
52-
program2.restore(bytes);
51+
auto program2 = Program(bytes);
5352

5453
// send the second half of the data
5554
for (int i = half; i < v.size(); i++) {

0 commit comments

Comments
 (0)