1//************************************ bs::framework - Copyright 2018 Marko Pintera **************************************//
2//*********** Licensed under the MIT license. See LICENSE.md for full terms. This notice is not to be removed. ***********//
3#pragma once
4
5#include "Prerequisites/BsPrerequisitesUtil.h"
6
7namespace bs
8{
9 struct SerializationContext;
10
11 /** @addtogroup Internal-Utility
12 * @{
13 */
14
15 /** @addtogroup Serialization-Internal
16 * @{
17 */
18
19 /**
20 * Represents an interface RTTI objects need to implement if they want to provide custom "diff" generation and applying.
21 */
22 class BS_UTILITY_EXPORT IDiff
23 {
24 public:
25 virtual ~IDiff() = default;
26
27 /**
28 * Generates per-field differences between the provided original and new object. Any field or array entry that is
29 * different in the new object compared to the original will be output in the resulting object, with a full
30 * hierarchy of that field.
31 *
32 * Will return null if there is no difference.
33 */
34 SPtr<SerializedObject> generateDiff(const SPtr<SerializedObject>& orgObj, const SPtr<SerializedObject>& newObj);
35
36 /**
37 * Applies a previously generated per-field differences to the provided object. This will essentially transform the
38 * original object the differences were generated for into the modified version.
39 */
40 void applyDiff(const SPtr<IReflectable>& object, const SPtr<SerializedObject>& diff, SerializationContext* context);
41
42 protected:
43 typedef UnorderedMap<SPtr<SerializedObject>, SPtr<SerializedObject>> ObjectMap;
44 typedef UnorderedMap<SPtr<SerializedObject>, SPtr<IReflectable>> DiffObjectMap;
45
46 /** Types of commands that are used when applying difference field values. */
47 enum DiffCommandType
48 {
49 Diff_Plain = 0x01,
50 Diff_Reflectable = 0x02,
51 Diff_ReflectablePtr = 0x03,
52 Diff_DataBlock = 0x04,
53 Diff_ArraySize = 0x05,
54 Diff_ObjectStart = 0x06,
55 Diff_ObjectEnd = 0x07,
56 Diff_SubObjectStart = 0x08,
57 Diff_ArrayFlag = 0x10
58 };
59
60 /**
61 * A command that is used for delaying writing to an object, it contains all necessary information for setting RTTI
62 * field values on an object.
63 */
64 struct DiffCommand
65 {
66 RTTIField* field;
67 UINT32 type;
68 SPtr<IReflectable> object;
69 UINT8* value;
70 SPtr<DataStream> streamValue;
71 UINT32 size;
72
73 union
74 {
75 UINT32 arrayIdx;
76 UINT32 arraySize;
77 RTTITypeBase* rttiType;
78 };
79 };
80
81 /**
82 * Recursive version of generateDiff(const SPtr<SerializedObject>&, const SPtr<SerializedObject>&).
83 *
84 * @see generateDiff(const SPtr<SerializedObject>&, const SPtr<SerializedObject>&)
85 */
86 virtual SPtr<SerializedObject> generateDiff(const SPtr<SerializedObject>& orgObj,
87 const SPtr<SerializedObject>& newObj, ObjectMap& objectMap) = 0;
88
89 /**
90 * Generates a difference between data of a specific field type indiscriminately of the specific field type.
91 *
92 * @see generateDiff(const SPtr<SerializedObject>&, const SPtr<SerializedObject>&)
93 */
94 SPtr<SerializedInstance> generateDiff(RTTITypeBase* rtti, UINT32 fieldType, const SPtr<SerializedInstance>& orgData,
95 const SPtr<SerializedInstance>& newData, ObjectMap& objectMap);
96
97 /**
98 * Recursive version of applyDiff(const SPtr<IReflectable>& object, const SPtr<SerializedObject>& diff). Outputs a
99 * set of commands that then must be executed in order to actually apply the difference to the provided object.
100 *
101 * @see applyDiff(const SPtr<IReflectable>& object, const SPtr<SerializedObject>& diff)
102 */
103 virtual void applyDiff(const SPtr<IReflectable>& object, const SPtr<SerializedObject>& diff, FrameAlloc& alloc,
104 DiffObjectMap& objectMap, FrameVector<DiffCommand>& diffCommands, SerializationContext* context) = 0;
105
106 /**
107 * Applies diff according to the diff handler retrieved from the provided RTTI object.
108 *
109 * @see applyDiff(const SPtr<IReflectable>& object, const SPtr<SerializedObject>& diff)
110 */
111 void applyDiff(RTTITypeBase* rtti, const SPtr<IReflectable>& object, const SPtr<SerializedObject>& diff,
112 FrameAlloc& alloc, DiffObjectMap& objectMap, FrameVector<DiffCommand>& diffCommands,
113 SerializationContext* context);
114 };
115
116 /**
117 * Generates and applies "diffs". Diffs contain per-field differences between an original and new object. These
118 * differences can be saved and then applied to an original object to transform it to the new version.
119 *
120 * @note Objects must be in intermediate serialized format generated by IntermediateSerializer.
121 */
122 class BS_UTILITY_EXPORT BinaryDiff : public IDiff
123 {
124 public:
125 using IDiff::generateDiff;
126
127 private:
128 /** @copydoc IDiff::generateDiff(const SPtr<SerializedObject>&, const SPtr<SerializedObject>&, ObjectMap&) */
129 SPtr<SerializedObject> generateDiff(const SPtr<SerializedObject>& orgObj, const SPtr<SerializedObject>& newObj,
130 ObjectMap& objectMap) override;
131
132
133 /**
134 * Generates a diff between two values of a single field.
135 *
136 * @param[in] field Field the values belong to.
137 * @param[in] rtti RTTI type owning the field.
138 * @param[in] oldData Old value of the field.
139 * @param[in] newData New value of the field.
140 * @param[in] objectMap A map that can be used for determining if an object way previously referenced so we
141 * don't generate a separate diff.
142 * @param[out] modification Object containing the diff value, if there is a difference.
143 * @return True if a difference is detected, false otherwise.
144 */
145 bool generateDiff(const RTTIField* field, RTTITypeBase* rtti, const SPtr<SerializedInstance>& oldData,
146 const SPtr<SerializedInstance>& newData, ObjectMap& objectMap,
147 SPtr<SerializedInstance>& modification);
148
149 /** @copydoc IDiff::applyDiff(const SPtr<IReflectable>&, const SPtr<SerializedObject>&, FrameAlloc&, DiffObjectMap&, FrameVector<DiffCommand>&) */
150 void applyDiff(const SPtr<IReflectable>& object, const SPtr<SerializedObject>& diff, FrameAlloc& alloc,
151 DiffObjectMap& objectMap, FrameVector<DiffCommand>& diffCommands, SerializationContext* context) override;
152 };
153
154 /** @} */
155 /** @} */
156}
157