//********************************** Banshee Engine (www.banshee3d.com) **************************************************// //**************** Copyright (c) 2016 Marko Pintera (marko.pintera@gmail.com). All rights reserved. **********************// #pragma once #include "BsScriptEnginePrerequisites.h" #include "Reflection/BsIReflectable.h" namespace bs { /** @addtogroup SBansheeEngine * @{ */ /** * Handles creation and applying of managed diffs. A diff contains differences between two objects of identical types. * If the initial state of an object is known the recorded differences can be saved and applied to the original state to * restore the modified object. * * Differences are recorded per primitive field in an object. Complex objects are recursed. Special handling is * implemented to properly generate diffs for arrays, lists and dictionaries. * * All primitive types supported by managed serialization are supported (see ScriptPrimitiveType). */ class BS_SCR_BE_EXPORT ManagedSerializableDiff : public IReflectable { public: /** A base class for all modifications recorded in a diff. */ struct Modification : IReflectable { virtual ~Modification(); /************************************************************************/ /* RTTI */ /************************************************************************/ public: friend class ModificationRTTI; static RTTITypeBase* getRTTIStatic(); RTTITypeBase* getRTTI() const override; }; /** * Contains a modification of a specific field in an object along with information about the field and its parent * object. */ struct ModifiedField : IReflectable { ModifiedField() { } ModifiedField(const SPtr& parentType, const SPtr& fieldType, const SPtr& modification); SPtr parentType; /**< Type of the parent object the field belongs to. */ SPtr fieldType; /**< Data type of the field. */ SPtr modification; /**< Recorded modification(s) on the field. */ /************************************************************************/ /* RTTI */ /************************************************************************/ public: friend class ModifiedFieldRTTI; static RTTITypeBase* getRTTIStatic(); RTTITypeBase* getRTTI() const override; }; /** Represents a single modified array or list entry. */ struct ModifiedArrayEntry : IReflectable { ModifiedArrayEntry() { } ModifiedArrayEntry(UINT32 idx, const SPtr& modification); UINT32 idx; /**< Index of the array/list entry that is modified. */ SPtr modification; /**< Recorded modification(s) on the entry. */ /************************************************************************/ /* RTTI */ /************************************************************************/ public: friend class ModifiedArrayEntryRTTI; static RTTITypeBase* getRTTIStatic(); RTTITypeBase* getRTTI() const override; }; /** Represents a single modified dictionary entry. */ struct ModifiedDictionaryEntry : IReflectable { ModifiedDictionaryEntry() { } ModifiedDictionaryEntry(const SPtr& key, const SPtr& modification); SPtr key; /**< Serialized value of the key for the modified entry. */ SPtr modification; /**< Recorded modification(s) on the dictionary entry value. */ /************************************************************************/ /* RTTI */ /************************************************************************/ public: friend class ModifiedArrayEntryRTTI; static RTTITypeBase* getRTTIStatic(); RTTITypeBase* getRTTI() const override; }; /** * Contains data about all modifications in a single complex object (aside from arrays, list, dictionaries which are * handled specially). */ struct ModifiedObject : Modification { static SPtr create(); Vector entries; /**< A list of entries containing each modified field in the object. */ /************************************************************************/ /* RTTI */ /************************************************************************/ public: friend class ModifiedObjectRTTI; static RTTITypeBase* getRTTIStatic(); RTTITypeBase* getRTTI() const override; }; /** Contains data about all modifications in an array or a list. */ struct ModifiedArray : Modification { static SPtr create(); Vector entries; /**< A list of all modified array/list entries along with their indices. */ Vector origSizes; /**< Original size of the array/list (one size per dimension). */ Vector newSizes; /**< New size of the array/list (one size per dimension). */ /************************************************************************/ /* RTTI */ /************************************************************************/ public: friend class ModifiedArrayRTTI; static RTTITypeBase* getRTTIStatic(); RTTITypeBase* getRTTI() const override; }; /** Contains data about all modifications in a dictionary. */ struct ModifiedDictionary : Modification { static SPtr create(); /** A list of modified entries in the dictionary. */ Vector entries; /** A list of keys for entries that were removed from the dictionary. */ Vector> removed; /************************************************************************/ /* RTTI */ /************************************************************************/ public: friend class ModifiedDictionaryRTTI; static RTTITypeBase* getRTTIStatic(); RTTITypeBase* getRTTI() const override; }; /** Contains data about modification of a primitive field (field's new value). */ struct ModifiedEntry : Modification { ModifiedEntry() { } ModifiedEntry(const SPtr& value); static SPtr create(const SPtr& value); SPtr value; /************************************************************************/ /* RTTI */ /************************************************************************/ public: friend class ModifiedEntryRTTI; static RTTITypeBase* getRTTIStatic(); RTTITypeBase* getRTTI() const override; }; public: ManagedSerializableDiff(); ~ManagedSerializableDiff(); /** * Generates a new managed diff object by comparing two objects of the same type. Callers must ensure both objects * are not null and of identical types. * * @param[in] oldObj Original object. This is the object you can apply the diff to to convert it to @p newObj. * @param[in] newObj New modified object. Any values in this object that differ from the original object will be * recorded in the diff. * @return Returns null if objects are identical. */ static SPtr create(const SPtr& oldObj, const SPtr& newObj); /** * Applies the diff data stored in this object to the specified object, modifying all fields in the object to * correspond to the stored diff data. */ void apply(const SPtr& obj); private: /** * Recursively generates a diff between all fields of the specified objects. Returns null if objects are identical. */ SPtr generateDiff(const SPtr& oldObj, const SPtr& newObj); /** * Generates a diff between two fields. Fields can be of any type and the system will generate the diff * appropriately. Diff is generated recursively on all complex objects as well. Returns null if fields contain * identical data. */ SPtr generateDiff(const SPtr& oldData, const SPtr& newData, UINT32 fieldTypeId); /** * Applies an object modification to a managed object. Modifications are applied recursively. * * @param[in] mod Object modification to apply. * @param[in] obj Object to apply the modification to. * @return New field data in the case modification needed the object to be re-created instead of just modified. */ SPtr applyDiff(const SPtr& mod, const SPtr& obj); /** * Applies an array modification to a managed array. Modifications are applied recursively. * * @param[in] mod Array modification to apply. * @param[in] obj Array to apply the modification to. * @return New field data in the case modification needed the array to be re-created instead of just modified. */ SPtr applyDiff(const SPtr& mod, const SPtr& obj); /** * Applies an list modification to a managed list. Modifications are applied recursively. * * @param[in] mod List modification to apply. * @param[in] obj List to apply the modification to. * @return New field data in the case modification needed the list to be re-created instead of just modified. */ SPtr applyDiff(const SPtr& mod, const SPtr& obj); /** * Applies an dictionary modification to a managed dictionary. Modifications are applied recursively. * * @param[in] mod Dictionary modification to apply. * @param[in] obj Dictionary to apply the modification to. * @return New field data in the case modification needed the dictionary to be re-created instead of just modified. */ SPtr applyDiff(const SPtr& mod, const SPtr& obj); /** * Applies a modification to a single field. Field type is determined and the modification is applied to the * specific field type as needed. Modifications are applied recursively. * * @param[in] mod Modification to apply. * @param[in] fieldType Type of the field we're applying the modification to. * @param[in] origData Original data of the field. * @return New field data in the case modification needed the field data to be re-created instead * of just modified. */ SPtr applyDiff(const SPtr& mod, const SPtr& fieldType, const SPtr& origData); SPtr mModificationRoot; /************************************************************************/ /* RTTI */ /************************************************************************/ public: friend class ManagedSerializableDiffRTTI; static RTTITypeBase* getRTTIStatic(); RTTITypeBase* getRTTI() const override; }; /** @} */ }