forked from google/libnop
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathstream.cpp
199 lines (169 loc) · 6.42 KB
/
stream.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
// Copyright 2017 The Native Object Protocols Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <ctime>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include <nop/serializer.h>
#include <nop/structure.h>
#include <nop/utility/die.h>
#include <nop/utility/stream_reader.h>
#include <nop/utility/stream_writer.h>
#include "stream_utilities.h"
#include "string_to_hex.h"
using nop::Deserializer;
using nop::Optional;
using nop::Serializer;
using nop::StreamReader;
using nop::StreamWriter;
using nop::StringToHex;
//
// An example of reading and writing structured data to streams. This example
// defines a couple of serializable types and demonstrates the serialization of
// an externally defined structure from the C standard library.
//
// Here we describe struct tm from the standard library, which is code we don't
// own and can't change to include an annotation. The NOP_EXTERNAL_STRUCTURE()
// macro annotates types we don't own so that the serializer can understand how
// to work with them. The annotation must be in the same namespace as the
// structure is originally defined in. NOTE: struct tm is orignally defined in
// the global namespace, even though the header <ctime> also aliases it into the
// std namespace. The annotation must be defined in the ORIGINAL namespace of
// the annotated type because the compiler only considers the original namespace
// during name lookup.
NOP_EXTERNAL_STRUCTURE(tm, tm_sec, tm_min, tm_hour, tm_mday, tm_mon, tm_year,
tm_wday, tm_yday, tm_isdst);
namespace {
// A user-defined type with private memebrs may be annotated. Annotated types
// must be default constrictible. Annotation does not affect the size or
// function of the class: all of the necessary information is captured in the
// type system.
class UserDefinedA {
public:
UserDefinedA() = default;
UserDefinedA(const std::string& a, std::vector<int> b)
: a_{a}, b_{std::move(b)} {}
UserDefinedA(const UserDefinedA&) = default;
UserDefinedA(UserDefinedA&&) = default;
UserDefinedA& operator=(const UserDefinedA&) = default;
UserDefinedA& operator=(UserDefinedA&&) = default;
const std::string a() const { return a_; }
const std::vector<int> b() const { return b_; }
private:
std::string a_;
std::vector<int> b_;
NOP_STRUCTURE(UserDefinedA, a_, b_);
};
// All enum and enum class types are serializable.
enum class EnumA {
Foo,
Bar,
Baz,
};
// A structure with internal annotation. The annotation only defines a nested
// type, which does not affect the size or funcion of the structure.
struct UserDefinedB {
int a;
float b;
std::string c;
std::vector<UserDefinedA> d;
std::tm e;
EnumA f;
Optional<std::string> g;
NOP_STRUCTURE(UserDefinedB, a, b, c, d, e, f, g);
};
// Prints a struct tm to the given stream.
std::ostream& operator<<(std::ostream& stream, const std::tm& tm) {
stream << "tm{" << tm.tm_sec << ", " << tm.tm_min << ", " << tm.tm_hour
<< ", " << tm.tm_mday << ", " << tm.tm_mon << ", " << tm.tm_year
<< ", " << tm.tm_wday << ", " << tm.tm_yday << ", " << tm.tm_isdst
<< "}";
return stream;
}
// Prints a EnumA value to the given stream.
std::ostream& operator<<(std::ostream& stream, const EnumA& value) {
switch (value) {
case EnumA::Foo:
stream << "EnumA::Foo";
break;
case EnumA::Bar:
stream << "EnumA::Bar";
break;
case EnumA::Baz:
stream << "EnumA::Baz";
break;
default:
using Type = std::underlying_type<EnumA>::type;
stream << "EnumA::<" + std::to_string(static_cast<Type>(value)) + ">";
break;
}
return stream;
}
// Prints an Optional<T> type to the given stream.
template <typename T>
std::ostream& operator<<(std::ostream& stream, const Optional<T>& value) {
stream << "Optional{";
if (value)
stream << value.get();
else
stream << "<empty>";
stream << "}";
return stream;
}
// Prints a UserDefinedB type to the given stream.
std::ostream& operator<<(std::ostream& stream, const UserDefinedB& message) {
stream << "UserDefinedB{" << message.a << ", " << message.b << ", "
<< message.c << ", " << message.d << ", " << message.e << ", "
<< message.f << ", " << message.g << "}";
return stream;
}
// Prints a UserDefinedA type to the given stream.
std::ostream& operator<<(std::ostream& stream, const UserDefinedA& message) {
stream << "UserDefinedA{" << message.a() << ", " << message.b() << "}";
return stream;
}
// Prints an error message to std::cerr when the Status<T> || Die() expression
// evaluates to false.
auto Die() { return nop::Die(std::cerr); }
} // anonymous namespace
int main(int /*argc*/, char** /*argv*/) {
// Construct a serializer to output to a std::stringstream.
Serializer<StreamWriter<std::stringstream>> serializer;
// Get the local time to write out with the message structure.
std::time_t time = std::time(nullptr);
std::tm local_time = *std::localtime(&time);
// Write a UserDefinedB structure to the stream.
UserDefinedB message_out{10,
20.f,
"foo",
{{"bar", {1, 2, 3}}, {"baz", {4, 5, 6}}},
local_time,
EnumA::Baz,
Optional<std::string>{"bif"}};
std::cout << "Writing: " << message_out << std::endl << std::endl;
serializer.Write(message_out) || Die();
// Dump the serialized data as a hex string.
std::string data = serializer.writer().stream().str();
std::cout << "Serialized data: " << StringToHex(data) << std::endl
<< std::endl;
// Construct a deserializer to read from a std::stringstream.
Deserializer<StreamReader<std::stringstream>> deserializer{data};
// Read a UserDefinedB structure from the stream.
UserDefinedB message_in;
deserializer.Read(&message_in) || Die();
// Print the UserDefinedB structure.
std::cout << "Read : " << message_in << std::endl;
return 0;
}