22 void operator()(
void* ptr) {
23 Release(Context, ptr);
26 void (*Release)(
void*,
void*) =
nullptr;
27 void* Context =
nullptr;
30template<
typename TLambda>
33 std::is_empty_v<TLambda> ||
sizeof(TLambda) <=
sizeof(
void*),
34 "Lambda must be stateless or capture only one pointer-sized value");
38 static std::enable_if_t<std::is_empty_v<std::decay_t<F>>,
TContextDeleter>
40 auto func_ptr = +[](
void* ,
void* ptr) {
41 std::decay_t<F>{}(ptr);
47 static std::enable_if_t<!std::is_empty_v<std::decay_t<F>>,
TContextDeleter>
49 void* captured_ptr = ExtractCapturedPointer(lambda);
51 auto func_ptr = +[](
void* ctx,
void* ptr) {
52 using LambdaType = std::decay_t<F>;
53 alignas(LambdaType)
char buffer[
sizeof(LambdaType)];
54 *
reinterpret_cast<void**
>(buffer) = ctx;
55 auto* lambda_ptr =
reinterpret_cast<LambdaType*
>(buffer);
64 static void* ExtractCapturedPointer(
const F& lambda) {
65 return *
reinterpret_cast<void* const*
>(&lambda);
72 template<
typename TFunc>
77 void operator()(
void* ptr) {
100 using TRawPtr = std::unique_ptr<void, TBlobDeleter>;
117constexpr bool is_pod_v = std::is_trivially_copyable_v<T> && std::is_standard_layout_v<T>;
119template<
typename T,
typename =
void>
124 std::is_empty_v<T> &&
125 std::is_trivial_v<T> &&
126 std::is_standard_layout_v<T>
127>> : std::false_type {};
133constexpr size_t sizeof_data() {
134 if constexpr (has_data_members_v<T>) {
141template<
typename T,
typename TAllocator,
typename... Args>
142typename std::enable_if_t<is_pod_v<T>, TBlob>
143SerializePodNear(TAllocator& alloc, Args&&... args)
145 constexpr uint32_t size = sizeof_data<T>();
147 TBlob::TRawPtr rawPtr =
nullptr;
149 if constexpr (size > 0) {
150 auto* data = alloc.Acquire(size);
151 new (data) T(std::forward<Args>(args)...);
153 rawPtr = TBlob::TRawPtr(data, TBlobDeleter{[&alloc](
void* ptr) {
161template<
typename T,
typename TAllocator,
typename... Args>
162typename std::enable_if_t<!is_pod_v<T>, TBlob>
163SerializeNonPodNear(TAllocator& alloc, Args&&... args)
165 T* obj =
new T(std::forward<Args>(args)...);
167 auto rawPtr = TBlob::TRawPtr(obj, TBlobDeleter{[](
void* ptr) {
168 delete reinterpret_cast<T*
>(ptr);
185template<
typename T,
typename TAllocator,
typename... Args>
186TBlob SerializeNear(TAllocator& alloc, Args&&... args)
188 if constexpr (is_pod_v<T>) {
189 return SerializePodNear<T>(alloc, std::forward<Args>(args)...);
191 return SerializeNonPodNear<T>(alloc, std::forward<Args>(args)...);
212void SerializeToStream(
const T& obj, std::ostringstream& oss)
214 static_assert(
sizeof(T) == 0,
"Serialization not implemented for this type");
228TBlob SerializeFar(TBlob blob)
230 if constexpr (is_pod_v<T>) {
234 T* obj =
reinterpret_cast<T*
>(blob.Data.get());
235 std::ostringstream oss;
236 SerializeToStream(*obj, oss);
237 void* data = ::operator
new(oss.str().size());
238 std::memcpy(data, oss.str().data(), oss.str().size());
239 auto rawPtr = TBlob::TRawPtr(data, TBlobDeleter{[](
void* ptr) {
240 ::operator
delete(ptr);
262template<
typename T,
typename TStream,
typename... Args>
263void SerializeFarInplace(TStream& stream, TActorId sender, TActorId recipient, Args&&... args)
265 if constexpr (is_pod_v<T>) {
266 constexpr auto size = sizeof_data<T>() +
sizeof(THeader);
267 auto buf = stream.Acquire(size);
268 char* p =
static_cast<char*
>(buf.data());
269 new (p) THeader {sender, recipient, T::MessageId, sizeof_data<T>()};
270 p +=
sizeof(THeader);
271 new (p) T(std::forward<Args>(args)...);
280 std::ostringstream oss;
281 SerializeToStream(T(std::forward<Args>(args)...), oss);
282 auto size = oss.str().size() +
sizeof(THeader);
283 auto buf = stream.Acquire(size);
284 char* p =
static_cast<char*
>(buf.data());
285 new (p) THeader {sender, recipient, T::MessageId,
static_cast<uint32_t
>(oss.str().size())};
286 p +=
sizeof(THeader);
287 std::memcpy(p, oss.str().data(), oss.str().size());
303auto DeserializeNear(
const TBlob& blob) -> std::conditional_t<sizeof_data<T>() == 0, T, T&> {
304 if constexpr (sizeof_data<T>() == 0) {
307 return *
reinterpret_cast<T*
>(blob.Data.get());
326void DeserializeFromStream(T& obj, std::istringstream& iss) {
327 static_assert(
sizeof(T) == 0,
"Deserialization not implemented for this type");
341auto DeserializeFar(
const TBlob& blob) -> std::conditional_t<is_pod_v<T> && (sizeof_data<T>()>0), T&, T> {
342 if constexpr (is_pod_v<T>) {
343 return DeserializeNear<T>(blob);
345 std::istringstream iss(std::string(
reinterpret_cast<const char*
>(blob.Data.get()), blob.Size));
347 DeserializeFromStream(obj, iss);
Definition messages.hpp:69
Opaque message payload with Near/Far duality.
Definition messages.hpp:99
uint32_t Size
Payload size in bytes (0 for empty/sentinel blobs)
Definition messages.hpp:102
TRawPtr Data
Owned payload (Near: object ptr; Far: byte buffer)
Definition messages.hpp:101
PointerType
Definition messages.hpp:103
@ Near
Live object pointer — valid only within the same process.
@ Far
Serialized byte buffer — safe to copy across the network.
Definition messages.hpp:14
Definition messages.hpp:31
Definition messages.hpp:120