37#ifndef A11_DATA_SERIALIZATION_H_
38#define A11_DATA_SERIALIZATION_H_
50#include <absl/base/nullability.h>
51#include <absl/status/status.h>
52#include <absl/status/status_macros.h>
53#include <absl/status/statusor.h>
54#include <absl/strings/str_cat.h>
83inline constexpr std::string_view
kBytesMimetype =
"application/octet-stream";
114 std::shared_ptr<const SerializationRegistry> registry)
115 : value_(std::move(
value)),
116 tag_(std::move(
tag)),
118 registry_(std::move(registry)) {}
120 [[nodiscard]] std::string_view
tag()
const override {
return tag_; }
122 [[nodiscard]] std::string_view
mimetype()
const override {
return mimetype_; }
124 [[nodiscard]]
const void* absl_nonnull
address()
const override {
128 [[nodiscard]] absl::StatusOr<Bytes>
Encode()
const override;
134 return sizeof(T) + 64;
139 const std::string tag_;
140 const std::string mimetype_;
141 const std::shared_ptr<const SerializationRegistry> registry_;
153 if (chunk.
object ==
nullptr || chunk.
object->tag() != tag) {
158 return *
static_cast<const T*
>(chunk.
object->address());
175 template <
typename T>
176 using Serializer = std::function<absl::StatusOr<Chunk>(
const T&)>;
179 template <
typename T>
191 template <
typename T>
196 return absl::InvalidArgumentError(
"serializer must be callable");
198 return RegisterSerializerErased(
199 typeid(T), std::move(type_name),
mimetype,
200 [serializer = std::move(serializer)](
201 const void* absl_nonnull
value) -> absl::StatusOr<Chunk> {
202 if (
value ==
nullptr) {
203 return absl::InvalidArgumentError(
"serializer value is null");
208 absl::StatusOr<Chunk> chunk;
210 [&] { chunk = serializer(*
static_cast<const T*
>(
value)); },
228 template <
typename T>
233 return absl::InvalidArgumentError(
"deserializer must be callable");
235 return RegisterDeserializerErased(
236 typeid(T), std::move(type_name),
mimetype,
237 [deserializer = std::move(deserializer)](
238 const Chunk& chunk) -> absl::StatusOr<std::any> {
240 absl::StatusOr<T> result;
242 [&] { result = deserializer(chunk); },
"deserializer");
247 return result.status();
249 return std::any(std::move(*result));
267 template <
typename T>
268 absl::Status
Register(
const std::string& type_name,
271 ABSL_RETURN_IF_ERROR(
272 RegisterSerializer<T>(type_name,
mimetype, std::move(serializer)));
273 absl::Status status =
274 RegisterDeserializer<T>(type_name,
mimetype, std::move(deserializer));
276 RemoveSerializer(
typeid(T), type_name,
mimetype);
279 return absl::OkStatus();
290 template <
typename T>
292 std::string_view
mimetype = {})
const {
307 template <
typename T>
310 const std::vector<std::string>& mimetype_patterns = {})
const {
311 ABSL_ASSIGN_OR_RETURN(std::any result,
312 FromChunkErased(chunk,
typeid(T), mimetype_patterns));
315 T* absl_nullable
value = std::any_cast<T>(&result);
316 if (
value ==
nullptr) {
317 return absl::InternalError(
318 absl::StrCat(
"A deserializer produced ", result.type().name(),
319 ", which is not the requested ",
typeid(T).name()));
321 return std::move(*
value);
332 using ErasedSerializer =
333 std::function<absl::StatusOr<Chunk>(
const void* absl_nonnull
value)>;
334 using ErasedDeserializer =
335 std::function<absl::StatusOr<std::any>(
const Chunk& chunk)>;
337 struct SerializerRegistration;
338 struct DeserializerRegistration;
341 static constexpr size_t kImplSize = 192;
342 static constexpr size_t kImplAlignment =
alignof(std::max_align_t);
344 Impl* absl_nonnull GetImpl();
345 [[nodiscard]]
const Impl* absl_nonnull GetImpl()
const;
347 absl::Status RegisterSerializerErased(std::type_index
type,
348 std::string type_name,
350 ErasedSerializer serializer);
351 absl::Status RegisterDeserializerErased(std::type_index
type,
352 std::string type_name,
354 ErasedDeserializer deserializer);
355 void RemoveSerializer(std::type_index
type, std::string_view type_name,
358 absl::StatusOr<Chunk> ToChunkErased(std::type_index
type,
359 const void* absl_nonnull
value,
361 absl::StatusOr<std::any> FromChunkErased(
362 const Chunk& chunk, std::type_index requested_type,
363 const std::vector<std::string>& mimetype_patterns)
const;
365 alignas(kImplAlignment) std::byte impl_[kImplSize];
373 if (registry_ ==
nullptr) {
374 return absl::FailedPreconditionError(
375 absl::StrCat(
"a chunk carrying a ", tag_,
376 " was asked for its bytes, but no serialization registry "
379 ABSL_ASSIGN_OR_RETURN(
Chunk encoded,
380 registry_->ToChunk<T>(value_, mimetype_));
381 return std::move(encoded.
data);
396 std::shared_ptr<const SerializationRegistry> registry) {
402 chunk.
object = std::make_shared<const TypedChunkObject<T>>(
404 std::move(registry));
An in-process value a chunk may carry instead of its encoded bytes.
Definition types.h:146
Definition serialization.h:161
absl::Status RegisterDefaults()
Installs the standard JSON and MessagePack codecs.
Definition serialization.cc:493
size_t serializer_count() const
Number of registered serializers.
Definition serialization.cc:512
std::function< absl::StatusOr< Chunk >(const T &)> Serializer
Callable turning a T into a Chunk.
Definition serialization.h:176
SerializationRegistry & operator=(const SerializationRegistry &)=delete
std::function< absl::StatusOr< T >(const Chunk &)> Deserializer
Callable reconstructing a T from a Chunk.
Definition serialization.h:180
absl::StatusOr< Chunk > ToChunk(const T &value, std::string_view mimetype={}) const
Serializes value into a Chunk.
Definition serialization.h:291
absl::Status RegisterSerializer(std::string type_name, const std::string &mimetype, Serializer< T > serializer)
Registers a serializer for type T and an exact media type.
Definition serialization.h:192
size_t deserializer_count() const
Number of registered deserializers.
Definition serialization.cc:518
absl::Status RegisterDeserializer(std::string type_name, const std::string &mimetype, Deserializer< T > deserializer)
Registers a deserializer for type T and an exact media type.
Definition serialization.h:229
~SerializationRegistry()
Definition serialization.cc:275
absl::Status Register(const std::string &type_name, const std::string &mimetype, Serializer< T > serializer, Deserializer< T > deserializer)
Atomically registers a serializer/deserializer pair for T.
Definition serialization.h:268
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:308
SerializationRegistry(const SerializationRegistry &)=delete
The local fast path: a value in a chunk, encoded only if needed.
Definition serialization.h:111
size_t ApproxBytes() const override
A size estimate that does not encode anything.
Definition serialization.h:130
std::string_view tag() const override
The serialisation tag of the held type.
Definition serialization.h:120
TypedChunkObject(T value, std::string tag, std::string mimetype, std::shared_ptr< const SerializationRegistry > registry)
Definition serialization.h:113
std::string_view mimetype() const override
The mimetype the value would be encoded as.
Definition serialization.h:122
absl::StatusOr< Bytes > Encode() const override
Encodes the value, for whoever needs bytes after all.
Definition serialization.h:372
const void *absl_nonnull address() const override
The address of the held value.
Definition serialization.h:124
std::string value
Definition discover.cc:114
Turns what a caller's callable throws into a Status, at the boundary.
constexpr std::string_view kBytesMimetype
Media type of opaque bytes carried as themselves.
Definition serialization.h:83
constexpr std::string_view kJsonMimetype
Media type of the built-in JSON codec.
Definition serialization.h:62
constexpr std::string_view kTextMimetype
Media type of UTF-8 text carried as itself.
Definition serialization.h:73
SerializationRegistry & GlobalSerializationRegistry()
Returns the process-wide registry (defaults pre-installed).
Definition serialization.cc:524
constexpr std::string_view kMsgpackMimetype
Media type of the built-in MessagePack codec.
Definition serialization.h:64
Chunk MakeChunkObject(T value, std::string tag, std::string mimetype, std::shared_ptr< const SerializationRegistry > registry)
Builds a chunk carrying value, with no bytes produced.
Definition serialization.h:395
std::optional< T > TryTakeObject(const Chunk &chunk, std::string_view tag)
Takes the value out of chunk, if it is carrying one of type T.
Definition serialization.h:152
absl::Status Attempt(Callable &&callable, std::string_view what)
Runs callable, reporting anything it throws as a Status.
Definition exception_guard.h:114
std::string mimetype
Definition sqlite_chunk_store.cc:191
A unit of data: bytes plus optional descriptive metadata.
Definition types.h:185
std::optional< ChunkMetadata > metadata
Optional payload metadata.
Definition types.h:186
Bytes data
Inline byte payload.
Definition types.h:188
std::shared_ptr< const ChunkObject > object
The value this chunk stands for, when its bytes have not been produced.
Definition types.h:196
A11's core wire value types: chunks, node fragments and messages.