| OLD | NEW |
| (Empty) |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #ifndef BLIMP_HELIUM_COMPOUND_SYNCABLE_H_ | |
| 6 #define BLIMP_HELIUM_COMPOUND_SYNCABLE_H_ | |
| 7 | |
| 8 #include <stdint.h> | |
| 9 #include <map> | |
| 10 #include <memory> | |
| 11 #include <string> | |
| 12 #include <utility> | |
| 13 #include <vector> | |
| 14 | |
| 15 #include "base/callback.h" | |
| 16 #include "base/logging.h" | |
| 17 #include "base/macros.h" | |
| 18 #include "base/memory/ptr_util.h" | |
| 19 #include "base/stl_util.h" | |
| 20 #include "blimp/helium/blimp_helium_export.h" | |
| 21 #include "blimp/helium/serializable_struct.h" | |
| 22 #include "blimp/helium/syncable.h" | |
| 23 #include "third_party/protobuf/src/google/protobuf/io/coded_stream.h" | |
| 24 #include "third_party/protobuf/src/google/protobuf/io/zero_copy_stream_impl_lite
.h" | |
| 25 | |
| 26 namespace blimp { | |
| 27 namespace helium { | |
| 28 | |
| 29 struct CompoundChangeset; | |
| 30 | |
| 31 // Base class for defining Syncables that are containers for other Syncables. | |
| 32 // It manages an internal registry of child Syncables that is declaratively | |
| 33 // populated at class construction time. It manages serialization and | |
| 34 // deserialization across its registered Syncables, combining the serialized | |
| 35 // output inside a simple map-based changeset. | |
| 36 // | |
| 37 // Example usage: | |
| 38 // | |
| 39 // struct ParentSyncable : public CompoundSyncable { | |
| 40 // explicit ParentSyncable() | |
| 41 // : child1(CreateAndRegister<Child1>()), | |
| 42 // child2(CreateAndRegister<Child2>()) {} | |
| 43 // | |
| 44 // RegisteredSyncable<Child1> child1; | |
| 45 // RegisteredSyncable<Child2> child2; | |
| 46 // | |
| 47 // private: | |
| 48 // DISALLOW_COPY_AND_ASSIGN(SampleCompoundSyncable); | |
| 49 // }; | |
| 50 // | |
| 51 class BLIMP_HELIUM_EXPORT CompoundSyncable | |
| 52 : public Syncable<CompoundChangeset> { | |
| 53 public: | |
| 54 CompoundSyncable(); | |
| 55 ~CompoundSyncable() override; | |
| 56 | |
| 57 // Syncable implementation. | |
| 58 std::unique_ptr<CompoundChangeset> CreateChangeset( | |
| 59 Revision from) const override; | |
| 60 void ApplyChangeset(const CompoundChangeset& changeset) override; | |
| 61 void ReleaseBefore(Revision from) override; | |
| 62 Revision GetRevision() const override; | |
| 63 bool ValidateChangeset(const CompoundChangeset& changeset) const override; | |
| 64 void SetLocalUpdateCallback( | |
| 65 const base::Closure& local_update_callback) override; | |
| 66 | |
| 67 protected: | |
| 68 // Defines the methods needed to access changesets and revision in Syncables | |
| 69 // in a Syncable type-agnostic manner, so that they may be accessed in an | |
| 70 // aggregated fashion using |members_|. | |
| 71 class RegisteredSyncableBase { | |
| 72 public: | |
| 73 virtual ~RegisteredSyncableBase() = default; | |
| 74 | |
| 75 // Parses and validate a changeset from |input_stream|. | |
| 76 // The parsed changeset is retained within |this| for later use by | |
| 77 // ApplyChangeset(). | |
| 78 // Returns true if the parse and validation steps both succeded. | |
| 79 virtual bool ParseAndValidate( | |
| 80 google::protobuf::io::CodedInputStream* input_stream) = 0; | |
| 81 virtual void ApplyChangeset() = 0; | |
| 82 | |
| 83 // Methods to be proxied directly to the Syncable implementation. | |
| 84 virtual Revision GetRevision() = 0; | |
| 85 virtual void CreateChangeset( | |
| 86 Revision from, | |
| 87 google::protobuf::io::CodedOutputStream* output_stream) const = 0; | |
| 88 virtual void SetLocalUpdateCallback( | |
| 89 const base::Closure& local_update_callback) = 0; | |
| 90 virtual void ReleaseBefore(Revision revision) = 0; | |
| 91 }; | |
| 92 | |
| 93 template <typename SyncableType> | |
| 94 class RegisteredSyncable : public RegisteredSyncableBase { | |
| 95 public: | |
| 96 ~RegisteredSyncable() = default; | |
| 97 RegisteredSyncable(RegisteredSyncable<SyncableType>&& other) = default; | |
| 98 | |
| 99 SyncableType* get() { return member_.get(); } | |
| 100 SyncableType* operator->() { return member_.get(); } | |
| 101 | |
| 102 // RegisteredSyncableBase implementation. | |
| 103 bool ParseAndValidate( | |
| 104 google::protobuf::io::CodedInputStream* input_stream) override; | |
| 105 virtual void ApplyChangeset(); | |
| 106 Revision GetRevision() override; | |
| 107 void CreateChangeset( | |
| 108 Revision from, | |
| 109 google::protobuf::io::CodedOutputStream* output_stream) const override; | |
| 110 void SetLocalUpdateCallback( | |
| 111 const base::Closure& local_update_callback) override; | |
| 112 void ReleaseBefore(Revision revision) override; | |
| 113 | |
| 114 private: | |
| 115 friend class CompoundSyncable; | |
| 116 | |
| 117 // Make class only constructable by CompoundSyncable, so that there is a | |
| 118 // strong guarantee that a RegisteredSyncable was created by | |
| 119 // SyncableRegistry::CreateAndRegister(). | |
| 120 explicit RegisteredSyncable(std::unique_ptr<SyncableType> member) | |
| 121 : member_(std::move(member)) {} | |
| 122 | |
| 123 std::unique_ptr<SyncableType> member_; | |
| 124 std::unique_ptr<typename SyncableType::Changeset> parsed_changeset_; | |
| 125 | |
| 126 DISALLOW_COPY_AND_ASSIGN(RegisteredSyncable); | |
| 127 }; | |
| 128 | |
| 129 template <typename T, typename... ConstructorArgs> | |
| 130 RegisteredSyncable<T> CreateAndRegister(ConstructorArgs... args); | |
| 131 | |
| 132 private: | |
| 133 // Tracks all Syncables* which have been created with CreateAndRegister(). | |
| 134 std::vector<RegisteredSyncableBase*> members_; | |
| 135 | |
| 136 DISALLOW_COPY_AND_ASSIGN(CompoundSyncable); | |
| 137 }; | |
| 138 | |
| 139 template <typename SyncableType> | |
| 140 bool CompoundSyncable::RegisteredSyncable<SyncableType>::ParseAndValidate( | |
| 141 google::protobuf::io::CodedInputStream* input_stream) { | |
| 142 DCHECK(!parsed_changeset_); | |
| 143 parsed_changeset_ = base::MakeUnique<typename SyncableType::Changeset>(); | |
| 144 return (parsed_changeset_->Parse(input_stream) && | |
| 145 member_->ValidateChangeset(*parsed_changeset_)); | |
| 146 } | |
| 147 | |
| 148 template <typename SyncableType> | |
| 149 void CompoundSyncable::RegisteredSyncable<SyncableType>::ApplyChangeset() { | |
| 150 DCHECK(parsed_changeset_); | |
| 151 member_->ApplyChangeset(*parsed_changeset_); | |
| 152 parsed_changeset_.reset(); | |
| 153 } | |
| 154 | |
| 155 template <typename SyncableType> | |
| 156 Revision CompoundSyncable::RegisteredSyncable<SyncableType>::GetRevision() { | |
| 157 return member_->GetRevision(); | |
| 158 } | |
| 159 | |
| 160 template <typename SyncableType> | |
| 161 void CompoundSyncable::RegisteredSyncable<SyncableType>::CreateChangeset( | |
| 162 Revision from, | |
| 163 google::protobuf::io::CodedOutputStream* output_stream) const { | |
| 164 std::unique_ptr<typename SyncableType::Changeset> changeset = | |
| 165 member_->CreateChangeset(from); | |
| 166 changeset->Serialize(output_stream); | |
| 167 } | |
| 168 | |
| 169 template <typename SyncableType> | |
| 170 void CompoundSyncable::RegisteredSyncable<SyncableType>::SetLocalUpdateCallback( | |
| 171 const base::Closure& local_update_callback) { | |
| 172 member_->SetLocalUpdateCallback(local_update_callback); | |
| 173 } | |
| 174 | |
| 175 template <typename SyncableType> | |
| 176 void CompoundSyncable::RegisteredSyncable<SyncableType>::ReleaseBefore( | |
| 177 Revision revision) { | |
| 178 member_->ReleaseBefore(revision); | |
| 179 } | |
| 180 | |
| 181 template <typename SyncableType, typename... ConstructorArgs> | |
| 182 CompoundSyncable::RegisteredSyncable<SyncableType> | |
| 183 CompoundSyncable::CreateAndRegister(ConstructorArgs... args) { | |
| 184 RegisteredSyncable<SyncableType> new_member( | |
| 185 base::MakeUnique<SyncableType>(std::forward<ConstructorArgs>(args)...)); | |
| 186 members_.push_back(&new_member); | |
| 187 return new_member; | |
| 188 } | |
| 189 | |
| 190 // Stores the serialized changesets of all CompoundSyncable members. | |
| 191 struct BLIMP_HELIUM_EXPORT CompoundChangeset : public SerializableStruct { | |
| 192 public: | |
| 193 CompoundChangeset(); | |
| 194 ~CompoundChangeset() override; | |
| 195 | |
| 196 // Convenience function for parsing a serialized changeset as Changeset. | |
| 197 template <typename ChangesetType> | |
| 198 ChangesetType ParseForTest(int index) const; | |
| 199 | |
| 200 // Sparse representation of serialized changed fields, indexed by their | |
| 201 // 0-based field index. | |
| 202 Field<std::map<int32_t, std::string>> compound_changesets; | |
| 203 | |
| 204 private: | |
| 205 DISALLOW_COPY_AND_ASSIGN(CompoundChangeset); | |
| 206 }; | |
| 207 | |
| 208 template <typename ChangesetType> | |
| 209 ChangesetType CompoundChangeset::ParseForTest(int index) const { | |
| 210 DCHECK(base::ContainsKey(compound_changesets, index)); | |
| 211 | |
| 212 google::protobuf::io::ArrayInputStream raw_input_stream( | |
| 213 compound_changesets().at(index).data(), | |
| 214 compound_changesets().at(index).size()); | |
| 215 google::protobuf::io::CodedInputStream input_stream(&raw_input_stream); | |
| 216 | |
| 217 ChangesetType output; | |
| 218 CHECK(output.Parse(input_stream)); | |
| 219 return output; | |
| 220 } | |
| 221 | |
| 222 } // namespace helium | |
| 223 } // namespace blimp | |
| 224 | |
| 225 #endif // BLIMP_HELIUM_COMPOUND_SYNCABLE_H_ | |
| OLD | NEW |