A11 (C++ runtime)
Native C++ implementation of the A11 action and streaming runtime
Loading...
Searching...
No Matches
serialization.h
Go to the documentation of this file.
1// Copyright 2026 The A11 Authors.
2
15#ifndef A11_DATA_SERIALIZATION_H_
16#define A11_DATA_SERIALIZATION_H_
17
18#include <any>
19#include <cstddef>
20#include <functional>
21#include <string>
22#include <string_view>
23#include <typeindex>
24#include <typeinfo>
25#include <utility>
26#include <vector>
27
28#include <absl/base/nullability.h>
29#include <absl/status/status.h>
30#include <absl/status/statusor.h>
31
32#include "a11/data/types.h"
33
34namespace a11::data {
35
37inline constexpr std::string_view kJsonMimetype = "application/json";
39inline constexpr std::string_view kMsgpackMimetype = "application/x-msgpack";
40
51 public:
57 explicit SerializationRegistry(bool register_defaults = false);
59
62
64 template <typename T>
65 using Serializer = std::function<absl::StatusOr<Chunk>(const T&)>;
66
68 template <typename T>
69 using Deserializer = std::function<absl::StatusOr<T>(const Chunk&)>;
70
78 template <typename T>
79 absl::Status RegisterSerializer(std::string type_name, std::string mimetype,
80 Serializer<T> serializer) {
81 if (!serializer) {
82 return absl::InvalidArgumentError("serializer must be callable");
83 }
84 return RegisterSerializerErased(
85 typeid(T), std::move(type_name), std::move(mimetype),
86 [serializer = std::move(serializer)](
87 const void* absl_nonnull value) -> absl::StatusOr<Chunk> {
88 if (value == nullptr) {
89 return absl::InvalidArgumentError("serializer value is null");
90 }
91 try {
92 return serializer(*static_cast<const T*>(value));
93 } catch (const std::exception& error) {
94 return absl::UnknownError(error.what());
95 } catch (...) {
96 return absl::UnknownError(
97 "serializer raised a non-standard exception");
98 }
99 });
100 }
101
109 template <typename T>
110 absl::Status RegisterDeserializer(std::string type_name, std::string mimetype,
111 Deserializer<T> deserializer) {
112 if (!deserializer) {
113 return absl::InvalidArgumentError("deserializer must be callable");
114 }
115 return RegisterDeserializerErased(
116 typeid(T), std::move(type_name), std::move(mimetype),
117 [deserializer = std::move(deserializer)](
118 const Chunk& chunk) -> absl::StatusOr<std::any> {
119 try {
120 absl::StatusOr<T> result = deserializer(chunk);
121 if (!result.ok())
122 return result.status();
123 return std::any(std::move(*result));
124 } catch (const std::exception& error) {
125 return absl::UnknownError(error.what());
126 } catch (...) {
127 return absl::UnknownError(
128 "deserializer raised a non-standard exception");
129 }
130 });
131 }
132
145 template <typename T>
146 absl::Status Register(std::string type_name, std::string mimetype,
147 Serializer<T> serializer,
148 Deserializer<T> deserializer) {
149 absl::Status status =
150 RegisterSerializer<T>(type_name, mimetype, serializer);
151 if (!status.ok())
152 return status;
153 status = RegisterDeserializer<T>(std::move(type_name), std::move(mimetype),
154 std::move(deserializer));
155 if (!status.ok()) {
156 RemoveSerializer(typeid(T), type_name, mimetype);
157 return status;
158 }
159 return absl::OkStatus();
160 }
161
170 template <typename T>
171 absl::StatusOr<Chunk> ToChunk(const T& value,
172 std::string_view mimetype = {}) const {
173 return ToChunkErased(typeid(T), &value, mimetype);
174 }
175
185 template <typename T>
186 absl::StatusOr<T> FromChunk(
187 const Chunk& chunk,
188 const std::vector<std::string>& mimetype_patterns = {}) const {
189 absl::StatusOr<std::any> result =
190 FromChunkErased(chunk, typeid(T), mimetype_patterns);
191 if (!result.ok())
192 return result.status();
193 try {
194 return std::any_cast<T>(std::move(*result));
195 } catch (const std::bad_any_cast& error) {
196 return absl::InternalError(error.what());
197 }
198 }
199
201 absl::Status RegisterDefaults();
203 [[nodiscard]] size_t serializer_count() const;
205 [[nodiscard]] size_t deserializer_count() const;
206
207 private:
208 using ErasedSerializer =
209 std::function<absl::StatusOr<Chunk>(const void* absl_nonnull value)>;
210 using ErasedDeserializer =
211 std::function<absl::StatusOr<std::any>(const Chunk& chunk)>;
212
213 struct SerializerRegistration;
214 struct DeserializerRegistration;
215 struct Impl;
216
217 static constexpr size_t kImplSize = 192;
218 static constexpr size_t kImplAlignment = alignof(std::max_align_t);
219
220 Impl* absl_nonnull GetImpl();
221 const Impl* absl_nonnull GetImpl() const;
222
223 absl::Status RegisterSerializerErased(std::type_index type,
224 std::string type_name,
225 std::string mimetype,
226 ErasedSerializer serializer);
227 absl::Status RegisterDeserializerErased(std::type_index type,
228 std::string type_name,
229 std::string mimetype,
230 ErasedDeserializer deserializer);
231 void RemoveSerializer(std::type_index type, std::string_view type_name,
232 std::string_view mimetype);
233
234 absl::StatusOr<Chunk> ToChunkErased(std::type_index type,
235 const void* absl_nonnull value,
236 std::string_view mimetype) const;
237 absl::StatusOr<std::any> FromChunkErased(
238 const Chunk& chunk, std::type_index requested_type,
239 const std::vector<std::string>& mimetype_patterns) const;
240
241 alignas(kImplAlignment) std::byte impl_[kImplSize];
242};
243
245SerializationRegistry& GlobalSerializationRegistry();
246
247} // namespace a11::data
248
249#endif // A11_DATA_SERIALIZATION_H_
A registry of serializers and deserializers indexed by type and MIME.
Definition serialization.h:50
absl::Status RegisterDefaults()
Installs the standard JSON and MessagePack codecs.
Definition serialization.cc:489
size_t serializer_count() const
Number of registered serializers.
Definition serialization.cc:520
std::function< absl::StatusOr< Chunk >(const T &)> Serializer
Callable turning a T into a Chunk.
Definition serialization.h:65
absl::Status Register(std::string type_name, std::string mimetype, Serializer< T > serializer, Deserializer< T > deserializer)
Atomically registers a serializer/deserializer pair for T.
Definition serialization.h:146
absl::Status RegisterDeserializer(std::string type_name, std::string mimetype, Deserializer< T > deserializer)
Registers a deserializer for type T and an exact media type.
Definition serialization.h:110
SerializationRegistry & operator=(const SerializationRegistry &)=delete
std::function< absl::StatusOr< T >(const Chunk &)> Deserializer
Callable reconstructing a T from a Chunk.
Definition serialization.h:69
absl::StatusOr< Chunk > ToChunk(const T &value, std::string_view mimetype={}) const
Serializes value into a Chunk.
Definition serialization.h:171
size_t deserializer_count() const
Number of registered deserializers.
Definition serialization.cc:526
absl::Status RegisterSerializer(std::string type_name, std::string mimetype, Serializer< T > serializer)
Registers a serializer for type T and an exact media type.
Definition serialization.h:79
~SerializationRegistry()
Definition serialization.cc:233
absl::StatusOr< T > FromChunk(const Chunk &chunk, const std::vector< std::string > &mimetype_patterns={}) const
Deserializes chunk into a value of type T.
Definition serialization.h:186
SerializationRegistry(const SerializationRegistry &)=delete
Definition json.cc:22
constexpr std::string_view kJsonMimetype
Media type of the built-in JSON codec.
Definition serialization.h:37
SerializationRegistry & GlobalSerializationRegistry()
Returns the process-wide registry (defaults pre-installed).
Definition serialization.cc:532
constexpr std::string_view kMsgpackMimetype
Media type of the built-in MessagePack codec.
Definition serialization.h:39
Future< T > SubmitWithCancellationHook(absl::AnyInvocable< absl::StatusOr< T >() && > work, std::function< void()> cancellation_hook, thread::TreeOptions tree_options)
Run work on A11's fiber pool with application-specific cancellation.
Definition executor.h:30
A unit of data: bytes plus optional descriptive metadata.
Definition types.h:95
A11's core wire value types: chunks, node fragments and messages.