// yabridge: a Wine plugin bridge // Copyright (C) 2020-2026 Robbert van der Helm // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . #pragma once #include #include #include #include "../../serialization/common.h" namespace bitsery { namespace ext { /** * An adapter for serializing zero-copy references to objects using * `MessageHandler`. The idea is that when serializing, we just read data * from the object pointed at by the reference. Then when deserializing, we'll * write the data to some backing `std::option` (so we don't have to * initialize an unused object on the serializing side), and we'll then change * our reference to point to the value contained within that option. * * This lets us serialize 'references' to objects that can be backed by actual * persistent objects. That way we can avoid allocations during the processing * loop. */ template class MessageReference { public: /** * @param backing_object The object we'll deserialize into, so we can point * the `MessageReference` to this object. On the serializing side this * won't be touched. */ MessageReference(std::optional& backing_object) : backing_object_(backing_object){}; template void serialize(Ser& ser, const ::MessageReference& object_ref, Fnc&&) const { ser.object(object_ref.get()); } template void deserialize(Des& des, ::MessageReference& object_ref, Fnc&&) const { if (!backing_object_) { backing_object_.emplace(); } // Since we cannot directly deserialize into a reference, we'll // deserialize into this (persistent) backing object and then point the // reference to this object. des.object(*backing_object_); object_ref = *backing_object_; } private: /** * This contains the actual `T` we'll deserialize into so we can point the * reference to that object after deserializing. */ std::optional& backing_object_; }; } // namespace ext namespace traits { template struct ExtensionTraits, ::MessageReference> { using TValue = void; static constexpr bool SupportValueOverload = false; static constexpr bool SupportObjectOverload = true; static constexpr bool SupportLambdaOverload = false; }; } // namespace traits } // namespace bitsery