summaryrefslogtreecommitdiffstats
path: root/sync/internal_api/public
diff options
context:
space:
mode:
authortim@chromium.org <tim@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-06-07 17:50:19 +0000
committertim@chromium.org <tim@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-06-07 17:50:19 +0000
commit3f8556a0cf934ee6e2e4a37b22b05dbf0a9c4a90 (patch)
treedcb6050b16ce934a4102da5ac7f2d501ceb4e988 /sync/internal_api/public
parent03c1007443b4be55364755441c83a66ec12cff81 (diff)
downloadchromium_src-3f8556a0cf934ee6e2e4a37b22b05dbf0a9c4a90.zip
chromium_src-3f8556a0cf934ee6e2e4a37b22b05dbf0a9c4a90.tar.gz
chromium_src-3f8556a0cf934ee6e2e4a37b22b05dbf0a9c4a90.tar.bz2
sync: create internal_api/public to house sync/ files needed by chrome/browser/sync.
Note on sync.gyp changes and .cc file moves: most files in /public have .h and their .cc side by side, as they are simple implementations. In some cases like model_type.cc (and others in a follow up patch, like sync_manager.cc) have only their header exposed in /public while the impl stays behind, because it needs to include things from within sync/, and /public has a strict include DEPS policy. This is in accordance with other /public folders (like content/). Cleans up DEPS files in sync + c/b/sync. Adds sync/{engine, sessions, syncable} to public/. There is more to come (moving things in internal_api/ into public). Not touching /notifier as that is in flux at the moment. BUG=131130 TEST= Review URL: https://chromiumcodereview.appspot.com/10532019 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@141038 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'sync/internal_api/public')
-rw-r--r--sync/internal_api/public/DEPS5
-rw-r--r--sync/internal_api/public/engine/model_safe_worker.cc75
-rw-r--r--sync/internal_api/public/engine/model_safe_worker.h87
-rw-r--r--sync/internal_api/public/engine/model_safe_worker_unittest.cc55
-rw-r--r--sync/internal_api/public/engine/passive_model_worker.cc28
-rw-r--r--sync/internal_api/public/engine/passive_model_worker.h40
-rw-r--r--sync/internal_api/public/engine/polling_constants.cc26
-rw-r--r--sync/internal_api/public/engine/polling_constants.h20
-rw-r--r--sync/internal_api/public/sessions/error_counters.cc17
-rw-r--r--sync/internal_api/public/sessions/error_counters.h33
-rw-r--r--sync/internal_api/public/sessions/sync_session_snapshot.cc173
-rw-r--r--sync/internal_api/public/sessions/sync_session_snapshot.h101
-rw-r--r--sync/internal_api/public/sessions/sync_source_info.cc36
-rw-r--r--sync/internal_api/public/sessions/sync_source_info.h42
-rw-r--r--sync/internal_api/public/sessions/syncer_status.cc44
-rw-r--r--sync/internal_api/public/sessions/syncer_status.h50
-rw-r--r--sync/internal_api/public/syncable/model_type.h175
-rw-r--r--sync/internal_api/public/syncable/model_type_payload_map.cc105
-rw-r--r--sync/internal_api/public/syncable/model_type_payload_map.h60
-rw-r--r--sync/internal_api/public/syncable/model_type_payload_map_unittest.cc46
-rw-r--r--sync/internal_api/public/syncable/model_type_test_util.cc52
-rw-r--r--sync/internal_api/public/syncable/model_type_test_util.h26
-rw-r--r--sync/internal_api/public/util/enum_set.h286
-rw-r--r--sync/internal_api/public/util/enum_set_unittest.cc195
-rw-r--r--sync/internal_api/public/util/syncer_error.cc36
-rw-r--r--sync/internal_api/public/util/syncer_error.h46
26 files changed, 1859 insertions, 0 deletions
diff --git a/sync/internal_api/public/DEPS b/sync/internal_api/public/DEPS
new file mode 100644
index 0000000..2a51ace
--- /dev/null
+++ b/sync/internal_api/public/DEPS
@@ -0,0 +1,5 @@
+include_rules = [
+ "-sync",
+ "+sync/internal_api/public",
+ "+sync/protocol",
+]
diff --git a/sync/internal_api/public/engine/model_safe_worker.cc b/sync/internal_api/public/engine/model_safe_worker.cc
new file mode 100644
index 0000000..2718acc
--- /dev/null
+++ b/sync/internal_api/public/engine/model_safe_worker.cc
@@ -0,0 +1,75 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sync/internal_api/public/engine/model_safe_worker.h"
+
+#include "base/json/json_writer.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/values.h"
+
+namespace browser_sync {
+
+base::DictionaryValue* ModelSafeRoutingInfoToValue(
+ const ModelSafeRoutingInfo& routing_info) {
+ base::DictionaryValue* dict = new base::DictionaryValue();
+ for (ModelSafeRoutingInfo::const_iterator it = routing_info.begin();
+ it != routing_info.end(); ++it) {
+ dict->SetString(syncable::ModelTypeToString(it->first),
+ ModelSafeGroupToString(it->second));
+ }
+ return dict;
+}
+
+std::string ModelSafeRoutingInfoToString(
+ const ModelSafeRoutingInfo& routing_info) {
+ scoped_ptr<DictionaryValue> dict(ModelSafeRoutingInfoToValue(routing_info));
+ std::string json;
+ base::JSONWriter::Write(dict.get(), &json);
+ return json;
+}
+
+syncable::ModelTypeSet GetRoutingInfoTypes(
+ const ModelSafeRoutingInfo& routing_info) {
+ syncable::ModelTypeSet types;
+ for (ModelSafeRoutingInfo::const_iterator it = routing_info.begin();
+ it != routing_info.end(); ++it) {
+ types.Put(it->first);
+ }
+ return types;
+}
+
+ModelSafeGroup GetGroupForModelType(const syncable::ModelType type,
+ const ModelSafeRoutingInfo& routes) {
+ ModelSafeRoutingInfo::const_iterator it = routes.find(type);
+ if (it == routes.end()) {
+ if (type != syncable::UNSPECIFIED && type != syncable::TOP_LEVEL_FOLDER)
+ LOG(WARNING) << "Entry does not belong to active ModelSafeGroup!";
+ return GROUP_PASSIVE;
+ }
+ return it->second;
+}
+
+std::string ModelSafeGroupToString(ModelSafeGroup group) {
+ switch (group) {
+ case GROUP_UI:
+ return "GROUP_UI";
+ case GROUP_DB:
+ return "GROUP_DB";
+ case GROUP_FILE:
+ return "GROUP_FILE";
+ case GROUP_HISTORY:
+ return "GROUP_HISTORY";
+ case GROUP_PASSIVE:
+ return "GROUP_PASSIVE";
+ case GROUP_PASSWORD:
+ return "GROUP_PASSWORD";
+ default:
+ NOTREACHED();
+ return "INVALID";
+ }
+}
+
+ModelSafeWorker::~ModelSafeWorker() {}
+
+} // namespace browser_sync
diff --git a/sync/internal_api/public/engine/model_safe_worker.h b/sync/internal_api/public/engine/model_safe_worker.h
new file mode 100644
index 0000000..1a6c371
--- /dev/null
+++ b/sync/internal_api/public/engine/model_safe_worker.h
@@ -0,0 +1,87 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SYNC_INTERNAL_API_PUBLIC_ENGINE_MODEL_SAFE_WORKER_H_
+#define SYNC_INTERNAL_API_PUBLIC_ENGINE_MODEL_SAFE_WORKER_H_
+#pragma once
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "base/callback.h"
+#include "base/memory/ref_counted.h"
+#include "sync/internal_api/public/syncable/model_type.h"
+#include "sync/internal_api/public/util/syncer_error.h"
+
+namespace base {
+class DictionaryValue;
+} // namespace
+
+namespace browser_sync {
+
+typedef base::Callback<enum SyncerError(void)> WorkCallback;
+
+enum ModelSafeGroup {
+ GROUP_PASSIVE = 0, // Models that are just "passively" being synced; e.g.
+ // changes to these models don't need to be pushed to a
+ // native model.
+ GROUP_UI, // Models that live on UI thread and are being synced.
+ GROUP_DB, // Models that live on DB thread and are being synced.
+ GROUP_FILE, // Models that live on FILE thread and are being synced.
+ GROUP_HISTORY, // Models that live on history thread and are being
+ // synced.
+ GROUP_PASSWORD, // Models that live on the password thread and are
+ // being synced. On windows and linux, this runs on the
+ // DB thread.
+ MODEL_SAFE_GROUP_COUNT,
+};
+
+std::string ModelSafeGroupToString(ModelSafeGroup group);
+
+// The Syncer uses a ModelSafeWorker for all tasks that could potentially
+// modify syncable entries (e.g under a WriteTransaction). The ModelSafeWorker
+// only knows how to do one thing, and that is take some work (in a fully
+// pre-bound callback) and have it performed (as in Run()) from a thread which
+// is guaranteed to be "model-safe", where "safe" refers to not allowing us to
+// cause an embedding application model to fall out of sync with the
+// syncable::Directory due to a race.
+class ModelSafeWorker : public base::RefCountedThreadSafe<ModelSafeWorker> {
+ public:
+ // Any time the Syncer performs model modifications (e.g employing a
+ // WriteTransaction), it should be done by this method to ensure it is done
+ // from a model-safe thread.
+ virtual SyncerError DoWorkAndWaitUntilDone(const WorkCallback& work) = 0;
+
+ virtual ModelSafeGroup GetModelSafeGroup() = 0;
+
+ protected:
+ virtual ~ModelSafeWorker();
+
+ private:
+ friend class base::RefCountedThreadSafe<ModelSafeWorker>;
+};
+
+// A map that details which ModelSafeGroup each syncable::ModelType
+// belongs to. Routing info can change in response to the user enabling /
+// disabling sync for certain types, as well as model association completions.
+typedef std::map<syncable::ModelType, ModelSafeGroup>
+ ModelSafeRoutingInfo;
+
+// Caller takes ownership of return value.
+base::DictionaryValue* ModelSafeRoutingInfoToValue(
+ const ModelSafeRoutingInfo& routing_info);
+
+std::string ModelSafeRoutingInfoToString(
+ const ModelSafeRoutingInfo& routing_info);
+
+syncable::ModelTypeSet GetRoutingInfoTypes(
+ const ModelSafeRoutingInfo& routing_info);
+
+ModelSafeGroup GetGroupForModelType(const syncable::ModelType type,
+ const ModelSafeRoutingInfo& routes);
+
+} // namespace browser_sync
+
+#endif // SYNC_INTERNAL_API_PUBLIC_ENGINE_MODEL_SAFE_WORKER_H_
diff --git a/sync/internal_api/public/engine/model_safe_worker_unittest.cc b/sync/internal_api/public/engine/model_safe_worker_unittest.cc
new file mode 100644
index 0000000..5304c13
--- /dev/null
+++ b/sync/internal_api/public/engine/model_safe_worker_unittest.cc
@@ -0,0 +1,55 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sync/internal_api/public/engine/model_safe_worker.h"
+
+#include "base/memory/scoped_ptr.h"
+#include "base/values.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace browser_sync {
+namespace {
+
+class ModelSafeWorkerTest : public ::testing::Test {
+};
+
+TEST_F(ModelSafeWorkerTest, ModelSafeRoutingInfoToValue) {
+ ModelSafeRoutingInfo routing_info;
+ routing_info[syncable::BOOKMARKS] = GROUP_PASSIVE;
+ routing_info[syncable::NIGORI] = GROUP_UI;
+ routing_info[syncable::PREFERENCES] = GROUP_DB;
+ DictionaryValue expected_value;
+ expected_value.SetString("Bookmarks", "GROUP_PASSIVE");
+ expected_value.SetString("Encryption keys", "GROUP_UI");
+ expected_value.SetString("Preferences", "GROUP_DB");
+ scoped_ptr<DictionaryValue> value(
+ ModelSafeRoutingInfoToValue(routing_info));
+ EXPECT_TRUE(value->Equals(&expected_value));
+}
+
+TEST_F(ModelSafeWorkerTest, ModelSafeRoutingInfoToString) {
+ ModelSafeRoutingInfo routing_info;
+ routing_info[syncable::BOOKMARKS] = GROUP_PASSIVE;
+ routing_info[syncable::NIGORI] = GROUP_UI;
+ routing_info[syncable::PREFERENCES] = GROUP_DB;
+ EXPECT_EQ(
+ "{\"Bookmarks\":\"GROUP_PASSIVE\",\"Encryption keys\":\"GROUP_UI\","
+ "\"Preferences\":\"GROUP_DB\"}",
+ ModelSafeRoutingInfoToString(routing_info));
+}
+
+TEST_F(ModelSafeWorkerTest, GetRoutingInfoTypes) {
+ ModelSafeRoutingInfo routing_info;
+ routing_info[syncable::BOOKMARKS] = GROUP_PASSIVE;
+ routing_info[syncable::NIGORI] = GROUP_UI;
+ routing_info[syncable::PREFERENCES] = GROUP_DB;
+ const syncable::ModelTypeSet expected_types(
+ syncable::BOOKMARKS,
+ syncable::NIGORI,
+ syncable::PREFERENCES);
+ EXPECT_TRUE(GetRoutingInfoTypes(routing_info).Equals(expected_types));
+}
+
+} // namespace
+} // namespace browser_sync
diff --git a/sync/internal_api/public/engine/passive_model_worker.cc b/sync/internal_api/public/engine/passive_model_worker.cc
new file mode 100644
index 0000000..26fccc1
--- /dev/null
+++ b/sync/internal_api/public/engine/passive_model_worker.cc
@@ -0,0 +1,28 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sync/internal_api/public/engine/passive_model_worker.h"
+
+#include "base/message_loop.h"
+
+namespace browser_sync {
+
+PassiveModelWorker::PassiveModelWorker(const MessageLoop* sync_loop)
+ : sync_loop_(sync_loop) {}
+
+PassiveModelWorker::~PassiveModelWorker() {
+}
+
+SyncerError PassiveModelWorker::DoWorkAndWaitUntilDone(
+ const WorkCallback& work) {
+ DCHECK_EQ(MessageLoop::current(), sync_loop_);
+ // Simply do the work on the current thread.
+ return work.Run();
+}
+
+ModelSafeGroup PassiveModelWorker::GetModelSafeGroup() {
+ return GROUP_PASSIVE;
+}
+
+} // namespace browser_sync
diff --git a/sync/internal_api/public/engine/passive_model_worker.h b/sync/internal_api/public/engine/passive_model_worker.h
new file mode 100644
index 0000000..7c0ddf3
--- /dev/null
+++ b/sync/internal_api/public/engine/passive_model_worker.h
@@ -0,0 +1,40 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SYNC_INTERNAL_API_PUBLIC_ENGINE_PASSIVE_MODEL_WORKER_H_
+#define SYNC_INTERNAL_API_PUBLIC_ENGINE_PASSIVE_MODEL_WORKER_H_
+#pragma once
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "sync/internal_api/public/engine/model_safe_worker.h"
+#include "sync/internal_api/public/util/syncer_error.h"
+
+class MessageLoop;
+
+namespace browser_sync {
+
+// Implementation of ModelSafeWorker for passive types. All work is
+// done on the same thread DoWorkAndWaitUntilDone (i.e., the sync
+// thread).
+class PassiveModelWorker : public ModelSafeWorker {
+ public:
+ explicit PassiveModelWorker(const MessageLoop* sync_loop);
+
+ // ModelSafeWorker implementation. Called on the sync thread.
+ virtual SyncerError DoWorkAndWaitUntilDone(
+ const WorkCallback& work) OVERRIDE;
+ virtual ModelSafeGroup GetModelSafeGroup() OVERRIDE;
+
+ private:
+ virtual ~PassiveModelWorker();
+
+ const MessageLoop* const sync_loop_;
+
+ DISALLOW_COPY_AND_ASSIGN(PassiveModelWorker);
+};
+
+} // namespace browser_sync
+
+#endif // SYNC_INTERNAL_API_PUBLIC_ENGINE_PASSIVE_MODEL_WORKER_H_
diff --git a/sync/internal_api/public/engine/polling_constants.cc b/sync/internal_api/public/engine/polling_constants.cc
new file mode 100644
index 0000000..d7fe753
--- /dev/null
+++ b/sync/internal_api/public/engine/polling_constants.cc
@@ -0,0 +1,26 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/basictypes.h"
+#include "sync/internal_api/public/engine/polling_constants.h"
+
+namespace browser_sync {
+
+// Server can overwrite these values via client commands.
+// Standard short poll. This is used when XMPP is off.
+// We use high values here to ensure that failure to receive poll updates from
+// the server doesn't result in rapid-fire polling from the client due to low
+// local limits.
+const int64 kDefaultShortPollIntervalSeconds = 3600 * 8;
+// Long poll is used when XMPP is on.
+const int64 kDefaultLongPollIntervalSeconds = 3600 * 12;
+
+// Maximum interval for exponential backoff.
+const int64 kMaxBackoffSeconds = 60 * 60 * 4; // 4 hours.
+
+// Backoff interval randomization factor.
+const int kBackoffRandomizationFactor = 2;
+
+} // namespace browser_sync
+
diff --git a/sync/internal_api/public/engine/polling_constants.h b/sync/internal_api/public/engine/polling_constants.h
new file mode 100644
index 0000000..9adfe92
--- /dev/null
+++ b/sync/internal_api/public/engine/polling_constants.h
@@ -0,0 +1,20 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Constants used by SyncScheduler when polling servers for updates.
+
+#ifndef SYNC_INTERNAL_API_PUBLIC_ENGINE_POLLING_CONSTANTS_H_
+#define SYNC_INTERNAL_API_PUBLIC_ENGINE_POLLING_CONSTANTS_H_
+#pragma once
+
+namespace browser_sync {
+
+extern const int64 kDefaultShortPollIntervalSeconds;
+extern const int64 kDefaultLongPollIntervalSeconds;
+extern const int64 kMaxBackoffSeconds;
+extern const int kBackoffRandomizationFactor;
+
+} // namespace browser_sync
+
+#endif // SYNC_INTERNAL_API_PUBLIC_ENGINE_POLLING_CONSTANTS_H_
diff --git a/sync/internal_api/public/sessions/error_counters.cc b/sync/internal_api/public/sessions/error_counters.cc
new file mode 100644
index 0000000..72ed2d1
--- /dev/null
+++ b/sync/internal_api/public/sessions/error_counters.cc
@@ -0,0 +1,17 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sync/internal_api/public/sessions/error_counters.h"
+
+namespace browser_sync {
+namespace sessions {
+
+ErrorCounters::ErrorCounters()
+ : last_download_updates_result(UNSET),
+ last_post_commit_result(UNSET),
+ last_process_commit_response_result(UNSET) {
+}
+
+} // namespace sessions
+} // namespace browser_sync
diff --git a/sync/internal_api/public/sessions/error_counters.h b/sync/internal_api/public/sessions/error_counters.h
new file mode 100644
index 0000000..a2f528c
--- /dev/null
+++ b/sync/internal_api/public/sessions/error_counters.h
@@ -0,0 +1,33 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SYNC_INTERNAL_API_PUBLIC_SESSIONS_ERROR_COUNTERS_H_
+#define SYNC_INTERNAL_API_PUBLIC_SESSIONS_ERROR_COUNTERS_H_
+#pragma once
+
+#include "base/basictypes.h"
+#include "sync/internal_api/public/util/syncer_error.h"
+#include "sync/protocol/sync_protocol_error.h"
+
+namespace browser_sync {
+namespace sessions {
+
+// Counters for various errors that can occur repeatedly during a sync session.
+// TODO(lipalani) : Rename this structure to Error.
+struct ErrorCounters {
+ ErrorCounters();
+
+ // Any protocol errors that we received during this sync session.
+ SyncProtocolError sync_protocol_error;
+
+ // Records the most recent results of PostCommit and GetUpdates commands.
+ SyncerError last_download_updates_result;
+ SyncerError last_post_commit_result;
+ SyncerError last_process_commit_response_result;
+};
+
+} // namespace sessions
+} // namespace browser_sync
+
+#endif // SYNC_INTERNAL_API_PUBLIC_SESSIONS_ERROR_COUNTERS_H_
diff --git a/sync/internal_api/public/sessions/sync_session_snapshot.cc b/sync/internal_api/public/sessions/sync_session_snapshot.cc
new file mode 100644
index 0000000..d058a4f
--- /dev/null
+++ b/sync/internal_api/public/sessions/sync_session_snapshot.cc
@@ -0,0 +1,173 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sync/internal_api/public/sessions/sync_session_snapshot.h"
+
+#include "base/json/json_writer.h"
+#include "base/values.h"
+
+namespace browser_sync {
+namespace sessions {
+
+SyncSessionSnapshot::SyncSessionSnapshot()
+ : num_server_changes_remaining_(0),
+ is_share_usable_(false),
+ has_more_to_sync_(false),
+ is_silenced_(false),
+ num_encryption_conflicts_(0),
+ num_hierarchy_conflicts_(0),
+ num_simple_conflicts_(0),
+ num_server_conflicts_(0),
+ notifications_enabled_(false),
+ num_entries_(0),
+ retry_scheduled_(false) {
+}
+
+SyncSessionSnapshot::SyncSessionSnapshot(
+ const SyncerStatus& syncer_status,
+ const ErrorCounters& errors,
+ int64 num_server_changes_remaining,
+ bool is_share_usable,
+ syncable::ModelTypeSet initial_sync_ended,
+ const syncable::ModelTypePayloadMap& download_progress_markers,
+ bool more_to_sync,
+ bool is_silenced,
+ int num_encryption_conflicts,
+ int num_hierarchy_conflicts,
+ int num_simple_conflicts,
+ int num_server_conflicts,
+ const SyncSourceInfo& source,
+ bool notifications_enabled,
+ size_t num_entries,
+ base::Time sync_start_time,
+ bool retry_scheduled)
+ : syncer_status_(syncer_status),
+ errors_(errors),
+ num_server_changes_remaining_(num_server_changes_remaining),
+ is_share_usable_(is_share_usable),
+ initial_sync_ended_(initial_sync_ended),
+ download_progress_markers_(download_progress_markers),
+ has_more_to_sync_(more_to_sync),
+ is_silenced_(is_silenced),
+ num_encryption_conflicts_(num_encryption_conflicts),
+ num_hierarchy_conflicts_(num_hierarchy_conflicts),
+ num_simple_conflicts_(num_simple_conflicts),
+ num_server_conflicts_(num_server_conflicts),
+ source_(source),
+ notifications_enabled_(notifications_enabled),
+ num_entries_(num_entries),
+ sync_start_time_(sync_start_time),
+ retry_scheduled_(retry_scheduled) {
+}
+
+SyncSessionSnapshot::~SyncSessionSnapshot() {}
+
+DictionaryValue* SyncSessionSnapshot::ToValue() const {
+ DictionaryValue* value = new DictionaryValue();
+ value->Set("syncerStatus", syncer_status_.ToValue());
+ // We don't care too much if we lose precision here.
+ value->SetInteger("numServerChangesRemaining",
+ static_cast<int>(num_server_changes_remaining_));
+ value->SetBoolean("isShareUsable", is_share_usable_);
+ value->Set("initialSyncEnded",
+ syncable::ModelTypeSetToValue(initial_sync_ended_));
+ value->Set("downloadProgressMarkers",
+ syncable::ModelTypePayloadMapToValue(download_progress_markers_));
+ value->SetBoolean("hasMoreToSync", has_more_to_sync_);
+ value->SetBoolean("isSilenced", is_silenced_);
+ // We don't care too much if we lose precision here, also.
+ value->SetInteger("numEncryptionConflicts",
+ num_encryption_conflicts_);
+ value->SetInteger("numHierarchyConflicts",
+ num_hierarchy_conflicts_);
+ value->SetInteger("numSimpleConflicts",
+ num_simple_conflicts_);
+ value->SetInteger("numServerConflicts",
+ num_server_conflicts_);
+ value->SetInteger("numEntries", num_entries_);
+ value->Set("source", source_.ToValue());
+ value->SetBoolean("notificationsEnabled", notifications_enabled_);
+ return value;
+}
+
+std::string SyncSessionSnapshot::ToString() const {
+ scoped_ptr<DictionaryValue> value(ToValue());
+ std::string json;
+ base::JSONWriter::WriteWithOptions(value.get(),
+ base::JSONWriter::OPTIONS_PRETTY_PRINT,
+ &json);
+ return json;
+}
+
+SyncerStatus SyncSessionSnapshot::syncer_status() const {
+ return syncer_status_;
+}
+
+ErrorCounters SyncSessionSnapshot::errors() const {
+ return errors_;
+}
+
+int64 SyncSessionSnapshot::num_server_changes_remaining() const {
+ return num_server_changes_remaining_;
+}
+
+bool SyncSessionSnapshot::is_share_usable() const {
+ return is_share_usable_;
+}
+
+syncable::ModelTypeSet SyncSessionSnapshot::initial_sync_ended() const {
+ return initial_sync_ended_;
+}
+
+syncable::ModelTypePayloadMap
+ SyncSessionSnapshot::download_progress_markers() const {
+ return download_progress_markers_;
+}
+
+bool SyncSessionSnapshot::has_more_to_sync() const {
+ return has_more_to_sync_;
+}
+
+bool SyncSessionSnapshot::is_silenced() const {
+ return is_silenced_;
+}
+
+int SyncSessionSnapshot::num_encryption_conflicts() const {
+ return num_encryption_conflicts_;
+}
+
+int SyncSessionSnapshot::num_hierarchy_conflicts() const {
+ return num_hierarchy_conflicts_;
+}
+
+int SyncSessionSnapshot::num_simple_conflicts() const {
+ return num_simple_conflicts_;
+}
+
+int SyncSessionSnapshot::num_server_conflicts() const {
+ return num_server_conflicts_;
+}
+
+SyncSourceInfo SyncSessionSnapshot::source() const {
+ return source_;
+}
+
+bool SyncSessionSnapshot::notifications_enabled() const {
+ return notifications_enabled_;
+}
+
+size_t SyncSessionSnapshot::num_entries() const {
+ return num_entries_;
+}
+
+base::Time SyncSessionSnapshot::sync_start_time() const {
+ return sync_start_time_;
+}
+
+bool SyncSessionSnapshot::retry_scheduled() const {
+ return retry_scheduled_;
+}
+
+} // namespace sessions
+} // namespace browser_sync
diff --git a/sync/internal_api/public/sessions/sync_session_snapshot.h b/sync/internal_api/public/sessions/sync_session_snapshot.h
new file mode 100644
index 0000000..9ed9465
--- /dev/null
+++ b/sync/internal_api/public/sessions/sync_session_snapshot.h
@@ -0,0 +1,101 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SYNC_INTERNAL_API_PUBLIC_SESSIONS_SYNC_SESSION_SNAPSHOT_H_
+#define SYNC_INTERNAL_API_PUBLIC_SESSIONS_SYNC_SESSION_SNAPSHOT_H_
+#pragma once
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/time.h"
+#include "sync/internal_api/public/sessions/error_counters.h"
+#include "sync/internal_api/public/sessions/sync_source_info.h"
+#include "sync/internal_api/public/sessions/syncer_status.h"
+#include "sync/internal_api/public/syncable/model_type.h"
+#include "sync/internal_api/public/syncable/model_type_payload_map.h"
+
+namespace base {
+class DictionaryValue;
+}
+
+namespace browser_sync {
+namespace sessions {
+
+// An immutable snapshot of state from a SyncSession. Convenient to use as
+// part of notifications as it is inherently thread-safe.
+// TODO(zea): if copying this all over the place starts getting expensive,
+// consider passing around immutable references instead of values.
+// Default copy and assign welcome.
+class SyncSessionSnapshot {
+ public:
+ SyncSessionSnapshot();
+ SyncSessionSnapshot(
+ const SyncerStatus& syncer_status,
+ const ErrorCounters& errors,
+ int64 num_server_changes_remaining,
+ bool is_share_usable,
+ syncable::ModelTypeSet initial_sync_ended,
+ const syncable::ModelTypePayloadMap& download_progress_markers,
+ bool more_to_sync,
+ bool is_silenced,
+ int num_encryption_conflicts,
+ int num_hierarchy_conflicts,
+ int num_simple_conflicts,
+ int num_server_conflicts,
+ const SyncSourceInfo& source,
+ bool notifications_enabled,
+ size_t num_entries,
+ base::Time sync_start_time,
+ bool retry_scheduled);
+ ~SyncSessionSnapshot();
+
+ // Caller takes ownership of the returned dictionary.
+ base::DictionaryValue* ToValue() const;
+
+ std::string ToString() const;
+
+ SyncerStatus syncer_status() const;
+ ErrorCounters errors() const;
+ int64 num_server_changes_remaining() const;
+ bool is_share_usable() const;
+ syncable::ModelTypeSet initial_sync_ended() const;
+ syncable::ModelTypePayloadMap download_progress_markers() const;
+ bool has_more_to_sync() const;
+ bool is_silenced() const;
+ int num_encryption_conflicts() const;
+ int num_hierarchy_conflicts() const;
+ int num_simple_conflicts() const;
+ int num_server_conflicts() const;
+ bool did_commit_items() const;
+ SyncSourceInfo source() const;
+ bool notifications_enabled() const;
+ size_t num_entries() const;
+ base::Time sync_start_time() const;
+ bool retry_scheduled() const;
+
+ private:
+ SyncerStatus syncer_status_;
+ ErrorCounters errors_;
+ int64 num_server_changes_remaining_;
+ bool is_share_usable_;
+ syncable::ModelTypeSet initial_sync_ended_;
+ syncable::ModelTypePayloadMap download_progress_markers_;
+ bool has_more_to_sync_;
+ bool is_silenced_;
+ int num_encryption_conflicts_;
+ int num_hierarchy_conflicts_;
+ int num_simple_conflicts_;
+ int num_server_conflicts_;
+ SyncSourceInfo source_;
+ bool notifications_enabled_;
+ size_t num_entries_;
+ base::Time sync_start_time_;
+ bool retry_scheduled_;
+};
+
+} // namespace sessions
+} // namespace browser_sync
+
+#endif // SYNC_INTERNAL_API_PUBLIC_SESSIONS_SYNC_SESSION_SNAPSHOT_H_
diff --git a/sync/internal_api/public/sessions/sync_source_info.cc b/sync/internal_api/public/sessions/sync_source_info.cc
new file mode 100644
index 0000000..191199b
--- /dev/null
+++ b/sync/internal_api/public/sessions/sync_source_info.cc
@@ -0,0 +1,36 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sync/internal_api/public/sessions/sync_source_info.h"
+
+#include "base/values.h"
+#include "sync/protocol/proto_enum_conversions.h"
+
+namespace browser_sync {
+namespace sessions {
+
+SyncSourceInfo::SyncSourceInfo()
+ : updates_source(sync_pb::GetUpdatesCallerInfo::UNKNOWN) {}
+
+SyncSourceInfo::SyncSourceInfo(
+ const syncable::ModelTypePayloadMap& t)
+ : updates_source(sync_pb::GetUpdatesCallerInfo::UNKNOWN), types(t) {}
+
+SyncSourceInfo::SyncSourceInfo(
+ const sync_pb::GetUpdatesCallerInfo::GetUpdatesSource& u,
+ const syncable::ModelTypePayloadMap& t)
+ : updates_source(u), types(t) {}
+
+SyncSourceInfo::~SyncSourceInfo() {}
+
+DictionaryValue* SyncSourceInfo::ToValue() const {
+ DictionaryValue* value = new DictionaryValue();
+ value->SetString("updatesSource",
+ GetUpdatesSourceString(updates_source));
+ value->Set("types", syncable::ModelTypePayloadMapToValue(types));
+ return value;
+}
+
+} // namespace sessions
+} // namespace browser_sync
diff --git a/sync/internal_api/public/sessions/sync_source_info.h b/sync/internal_api/public/sessions/sync_source_info.h
new file mode 100644
index 0000000..838e094
--- /dev/null
+++ b/sync/internal_api/public/sessions/sync_source_info.h
@@ -0,0 +1,42 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SYNC_INTERNAL_API_PUBLIC_SESSIONS_SYNC_SOURCE_INFO_H_
+#define SYNC_INTERNAL_API_PUBLIC_SESSIONS_SYNC_SOURCE_INFO_H_
+#pragma once
+
+#include "base/basictypes.h"
+#include "sync/internal_api/public/syncable/model_type.h"
+#include "sync/internal_api/public/syncable/model_type_payload_map.h"
+#include "sync/protocol/sync.pb.h"
+
+namespace base {
+class DictionaryValue;
+}
+
+namespace browser_sync {
+namespace sessions {
+
+// A container for the source of a sync session. This includes the update
+// source, the datatypes triggering the sync session, and possible session
+// specific payloads which should be sent to the server.
+struct SyncSourceInfo {
+ SyncSourceInfo();
+ explicit SyncSourceInfo(const syncable::ModelTypePayloadMap& t);
+ SyncSourceInfo(
+ const sync_pb::GetUpdatesCallerInfo::GetUpdatesSource& u,
+ const syncable::ModelTypePayloadMap& t);
+ ~SyncSourceInfo();
+
+ // Caller takes ownership of the returned dictionary.
+ base::DictionaryValue* ToValue() const;
+
+ sync_pb::GetUpdatesCallerInfo::GetUpdatesSource updates_source;
+ syncable::ModelTypePayloadMap types;
+};
+
+} // namespace sessions
+} // namespace browser_sync
+
+#endif // SYNC_INTERNAL_API_PUBLIC_SESSIONS_SYNC_SOURCE_INFO_H_
diff --git a/sync/internal_api/public/sessions/syncer_status.cc b/sync/internal_api/public/sessions/syncer_status.cc
new file mode 100644
index 0000000..efa0c43
--- /dev/null
+++ b/sync/internal_api/public/sessions/syncer_status.cc
@@ -0,0 +1,44 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sync/internal_api/public/sessions/syncer_status.h"
+
+#include "base/values.h"
+
+namespace browser_sync {
+namespace sessions {
+
+SyncerStatus::SyncerStatus()
+ : invalid_store(false),
+ num_successful_commits(0),
+ num_successful_bookmark_commits(0),
+ num_updates_downloaded_total(0),
+ num_tombstone_updates_downloaded_total(0),
+ num_reflected_updates_downloaded_total(0),
+ num_local_overwrites(0),
+ num_server_overwrites(0) {
+}
+
+SyncerStatus::~SyncerStatus() {
+}
+
+DictionaryValue* SyncerStatus::ToValue() const {
+ DictionaryValue* value = new DictionaryValue();
+ value->SetBoolean("invalidStore", invalid_store);
+ value->SetInteger("numSuccessfulCommits", num_successful_commits);
+ value->SetInteger("numSuccessfulBookmarkCommits",
+ num_successful_bookmark_commits);
+ value->SetInteger("numUpdatesDownloadedTotal",
+ num_updates_downloaded_total);
+ value->SetInteger("numTombstoneUpdatesDownloadedTotal",
+ num_tombstone_updates_downloaded_total);
+ value->SetInteger("numReflectedUpdatesDownloadedTotal",
+ num_reflected_updates_downloaded_total);
+ value->SetInteger("numLocalOverwrites", num_local_overwrites);
+ value->SetInteger("numServerOverwrites", num_server_overwrites);
+ return value;
+}
+
+} // namespace sessions
+} // namespace browser_sync
diff --git a/sync/internal_api/public/sessions/syncer_status.h b/sync/internal_api/public/sessions/syncer_status.h
new file mode 100644
index 0000000..7331ca3
--- /dev/null
+++ b/sync/internal_api/public/sessions/syncer_status.h
@@ -0,0 +1,50 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SYNC_INTERNAL_API_PUBLIC_SESSIONS_SYNCER_STATUS_H_
+#define SYNC_INTERNAL_API_PUBLIC_SESSIONS_SYNCER_STATUS_H_
+#pragma once
+
+#include "base/basictypes.h"
+#include "sync/internal_api/public/syncable/model_type.h"
+
+namespace base {
+class DictionaryValue;
+}
+
+namespace browser_sync {
+namespace sessions {
+
+// Data pertaining to the status of an active Syncer object.
+struct SyncerStatus {
+ SyncerStatus();
+ ~SyncerStatus();
+
+ // Caller takes ownership of the returned dictionary.
+ base::DictionaryValue* ToValue() const;
+
+ // True when we get such an INVALID_STORE error from the server.
+ bool invalid_store;
+ int num_successful_commits;
+ // This is needed for monitoring extensions activity.
+ int num_successful_bookmark_commits;
+
+ // Download event counters.
+ int num_updates_downloaded_total;
+ int num_tombstone_updates_downloaded_total;
+ int num_reflected_updates_downloaded_total;
+
+ // If the syncer encountered a MIGRATION_DONE code, these are the types that
+ // the client must now "migrate", by purging and re-downloading all updates.
+ syncable::ModelTypeSet types_needing_local_migration;
+
+ // Overwrites due to conflict resolution counters.
+ int num_local_overwrites;
+ int num_server_overwrites;
+};
+
+} // namespace sessions
+} // namespace browser_sync
+
+#endif // SYNC_INTERNAL_API_PUBLIC_SESSIONS_SYNCER_STATUS_H_
diff --git a/sync/internal_api/public/syncable/model_type.h b/sync/internal_api/public/syncable/model_type.h
new file mode 100644
index 0000000..b7b5fe3
--- /dev/null
+++ b/sync/internal_api/public/syncable/model_type.h
@@ -0,0 +1,175 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Enumerate the various item subtypes that are supported by sync.
+// Each sync object is expected to have an immutable object type.
+// An object's type is inferred from the type of data it holds.
+
+#ifndef SYNC_INTERNAL_API_PUBLIC_SYNCABLE_MODEL_TYPE_H_
+#define SYNC_INTERNAL_API_PUBLIC_SYNCABLE_MODEL_TYPE_H_
+#pragma once
+
+#include <set>
+#include <string>
+
+#include "base/logging.h"
+#include "base/time.h"
+#include "sync/internal_api/public/util/enum_set.h"
+
+namespace base {
+class ListValue;
+class StringValue;
+class Value;
+}
+
+namespace sync_pb {
+class EntitySpecifics;
+class SyncEntity;
+}
+
+namespace syncable {
+
+enum ModelType {
+ // Object type unknown. Objects may transition through
+ // the unknown state during their initial creation, before
+ // their properties are set. After deletion, object types
+ // are generally preserved.
+ UNSPECIFIED,
+ // A permanent folder whose children may be of mixed
+ // datatypes (e.g. the "Google Chrome" folder).
+ TOP_LEVEL_FOLDER,
+
+ // ------------------------------------ Start of "real" model types.
+ // The model types declared before here are somewhat special, as they
+ // they do not correspond to any browser data model. The remaining types
+ // are bona fide model types; all have a related browser data model and
+ // can be represented in the protocol using a specific Message type in the
+ // EntitySpecifics protocol buffer.
+ //
+ // A bookmark folder or a bookmark URL object.
+ BOOKMARKS,
+ FIRST_REAL_MODEL_TYPE = BOOKMARKS, // Declared 2nd, for debugger prettiness.
+
+ // A preference folder or a preference object.
+ PREFERENCES,
+ // A password folder or password object.
+ PASSWORDS,
+ // An AutofillProfile Object
+ AUTOFILL_PROFILE,
+ // An autofill folder or an autofill object.
+ AUTOFILL,
+
+ // A themes folder or a themes object.
+ THEMES,
+ // A typed_url folder or a typed_url object.
+ TYPED_URLS,
+ // An extension folder or an extension object.
+ EXTENSIONS,
+ // An object representing a set of Nigori keys.
+ NIGORI,
+ // An object representing a custom search engine.
+ SEARCH_ENGINES,
+ // An object representing a browser session.
+ SESSIONS,
+ // An app folder or an app object.
+ APPS,
+ // An app setting from the extension settings API.
+ APP_SETTINGS,
+ // An extension setting from the extension settings API.
+ EXTENSION_SETTINGS,
+ // App notifications.
+ APP_NOTIFICATIONS,
+ LAST_REAL_MODEL_TYPE = APP_NOTIFICATIONS,
+
+ // If you are adding a new sync datatype that is exposed to the user via the
+ // sync preferences UI, be sure to update the list in
+ // chrome/browser/sync/user_selectable_sync_type.h so that the UMA histograms
+ // for sync include your new type.
+
+ MODEL_TYPE_COUNT,
+};
+
+typedef browser_sync::EnumSet<
+ ModelType, FIRST_REAL_MODEL_TYPE, LAST_REAL_MODEL_TYPE> ModelTypeSet;
+typedef browser_sync::EnumSet<
+ ModelType, UNSPECIFIED, LAST_REAL_MODEL_TYPE> FullModelTypeSet;
+
+inline ModelType ModelTypeFromInt(int i) {
+ DCHECK_GE(i, 0);
+ DCHECK_LT(i, MODEL_TYPE_COUNT);
+ return static_cast<ModelType>(i);
+}
+
+void AddDefaultFieldValue(syncable::ModelType datatype,
+ sync_pb::EntitySpecifics* specifics);
+
+// Extract the model type of a SyncEntity protocol buffer. ModelType is a
+// local concept: the enum is not in the protocol. The SyncEntity's ModelType
+// is inferred from the presence of particular datatype field in the
+// entity specifics.
+ModelType GetModelType(const sync_pb::SyncEntity& sync_entity);
+
+// Extract the model type from an EntitySpecifics field. Note that there
+// are some ModelTypes (like TOP_LEVEL_FOLDER) that can't be inferred this way;
+// prefer using GetModelType where possible.
+ModelType GetModelTypeFromSpecifics(const sync_pb::EntitySpecifics& specifics);
+
+// If this returns false, we shouldn't bother maintaining a position
+// value (sibling ordering) for this item.
+bool ShouldMaintainPosition(ModelType model_type);
+
+// Determine a model type from the field number of its associated
+// EntitySpecifics field.
+ModelType GetModelTypeFromSpecificsFieldNumber(int field_number);
+
+// Return the field number of the EntitySpecifics field associated with
+// a model type.
+int GetSpecificsFieldNumberFromModelType(ModelType model_type);
+
+// TODO(sync): The functions below badly need some cleanup.
+
+// Returns a pointer to a string with application lifetime that represents
+// the name of |model_type|.
+const char* ModelTypeToString(ModelType model_type);
+
+// Handles all model types, and not just real ones.
+//
+// Caller takes ownership of returned value.
+base::StringValue* ModelTypeToValue(ModelType model_type);
+
+// Converts a Value into a ModelType - complement to ModelTypeToValue().
+ModelType ModelTypeFromValue(const base::Value& value);
+
+// Returns the ModelType corresponding to the name |model_type_string|.
+ModelType ModelTypeFromString(const std::string& model_type_string);
+
+std::string ModelTypeSetToString(ModelTypeSet model_types);
+
+// Caller takes ownership of returned list.
+base::ListValue* ModelTypeSetToValue(ModelTypeSet model_types);
+
+ModelTypeSet ModelTypeSetFromValue(const base::ListValue& value);
+
+// Returns a string corresponding to the syncable tag for this datatype.
+std::string ModelTypeToRootTag(ModelType type);
+
+// Convert a real model type to a notification type (used for
+// subscribing to server-issued notifications). Returns true iff
+// |model_type| was a real model type and |notification_type| was
+// filled in.
+bool RealModelTypeToNotificationType(ModelType model_type,
+ std::string* notification_type);
+
+// Converts a notification type to a real model type. Returns true
+// iff |notification_type| was the notification type of a real model
+// type and |model_type| was filled in.
+bool NotificationTypeToRealModelType(const std::string& notification_type,
+ ModelType* model_type);
+
+// Returns true if |model_type| is a real datatype
+bool IsRealDataType(ModelType model_type);
+
+} // namespace syncable
+
+#endif // SYNC_INTERNAL_API_PUBLIC_SYNCABLE_MODEL_TYPE_H_
diff --git a/sync/internal_api/public/syncable/model_type_payload_map.cc b/sync/internal_api/public/syncable/model_type_payload_map.cc
new file mode 100644
index 0000000..cff4c92
--- /dev/null
+++ b/sync/internal_api/public/syncable/model_type_payload_map.cc
@@ -0,0 +1,105 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sync/internal_api/public/syncable/model_type_payload_map.h"
+
+#include <vector>
+
+#include "base/base64.h"
+#include "base/json/json_writer.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/values.h"
+
+using browser_sync::ModelSafeRoutingInfo;
+namespace syncable {
+
+ModelTypePayloadMap ModelTypePayloadMapFromEnumSet(
+ syncable::ModelTypeSet types,
+ const std::string& payload) {
+ ModelTypePayloadMap types_with_payloads;
+ for (syncable::ModelTypeSet::Iterator it = types.First();
+ it.Good(); it.Inc()) {
+ types_with_payloads[it.Get()] = payload;
+ }
+ return types_with_payloads;
+}
+
+ModelTypeSet ModelTypePayloadMapToEnumSet(
+ const ModelTypePayloadMap& payload_map) {
+ ModelTypeSet types;
+ for (ModelTypePayloadMap::const_iterator it = payload_map.begin();
+ it != payload_map.end(); ++it) {
+ types.Put(it->first);
+ }
+ return types;
+}
+
+ModelTypePayloadMap ModelTypePayloadMapFromRoutingInfo(
+ const browser_sync::ModelSafeRoutingInfo& routes,
+ const std::string& payload) {
+ ModelTypePayloadMap types_with_payloads;
+ for (browser_sync::ModelSafeRoutingInfo::const_iterator i = routes.begin();
+ i != routes.end(); ++i) {
+ types_with_payloads[i->first] = payload;
+ }
+ return types_with_payloads;
+}
+
+std::string ModelTypePayloadMapToString(
+ const ModelTypePayloadMap& type_payloads) {
+ scoped_ptr<DictionaryValue> value(
+ ModelTypePayloadMapToValue(type_payloads));
+ std::string json;
+ base::JSONWriter::Write(value.get(), &json);
+ return json;
+}
+
+DictionaryValue* ModelTypePayloadMapToValue(
+ const ModelTypePayloadMap& type_payloads) {
+ DictionaryValue* value = new DictionaryValue();
+ for (ModelTypePayloadMap::const_iterator it = type_payloads.begin();
+ it != type_payloads.end(); ++it) {
+ // TODO(akalin): Unpack the value into a protobuf.
+ std::string base64_marker;
+ bool encoded = base::Base64Encode(it->second, &base64_marker);
+ DCHECK(encoded);
+ value->SetString(syncable::ModelTypeToString(it->first), base64_marker);
+ }
+ return value;
+}
+
+void CoalescePayloads(ModelTypePayloadMap* original,
+ const ModelTypePayloadMap& update) {
+ for (ModelTypePayloadMap::const_iterator i = update.begin();
+ i != update.end(); ++i) {
+ if (original->count(i->first) == 0) {
+ // If this datatype isn't already in our map, add it with
+ // whatever payload it has.
+ (*original)[i->first] = i->second;
+ } else if (i->second.length() > 0) {
+ // If this datatype is already in our map, we only overwrite the
+ // payload if the new one is non-empty.
+ (*original)[i->first] = i->second;
+ }
+ }
+}
+
+void PurgeStalePayload(ModelTypePayloadMap* original,
+ const ModelSafeRoutingInfo& routing_info) {
+ std::vector<ModelTypePayloadMap::iterator> iterators_to_delete;
+ for (ModelTypePayloadMap::iterator i = original->begin();
+ i != original->end(); ++i) {
+ if (routing_info.end() == routing_info.find(i->first)) {
+ iterators_to_delete.push_back(i);
+ }
+ }
+
+ for (std::vector<ModelTypePayloadMap::iterator>::iterator
+ it = iterators_to_delete.begin(); it != iterators_to_delete.end();
+ ++it) {
+ original->erase(*it);
+ }
+}
+
+} // namespace syncable
diff --git a/sync/internal_api/public/syncable/model_type_payload_map.h b/sync/internal_api/public/syncable/model_type_payload_map.h
new file mode 100644
index 0000000..1bf3884
--- /dev/null
+++ b/sync/internal_api/public/syncable/model_type_payload_map.h
@@ -0,0 +1,60 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Definition of ModelTypePayloadMap and various utility functions.
+
+#ifndef SYNC_INTERNAL_PUBLIC_API_SYNCABLE_MODEL_TYPE_PAYLOAD_MAP_H_
+#define SYNC_INTERNAL_PUBLIC_API_SYNCABLE_MODEL_TYPE_PAYLOAD_MAP_H_
+#pragma once
+
+#include <map>
+#include <string>
+
+#include "sync/internal_api/public/engine/model_safe_worker.h"
+#include "sync/internal_api/public/syncable/model_type.h"
+
+namespace base {
+class DictionaryValue;
+}
+
+namespace syncable {
+
+// A container that contains a set of datatypes with possible string
+// payloads.
+typedef std::map<ModelType, std::string> ModelTypePayloadMap;
+
+// Helper functions for building ModelTypePayloadMaps.
+
+// Make a TypePayloadMap from all the types in a ModelTypeSet using a
+// default payload.
+ModelTypePayloadMap ModelTypePayloadMapFromEnumSet(
+ ModelTypeSet model_types, const std::string& payload);
+
+ModelTypeSet ModelTypePayloadMapToEnumSet(
+ const ModelTypePayloadMap& payload_map);
+
+// Make a TypePayloadMap for all the enabled types in a
+// ModelSafeRoutingInfo using a default payload.
+ModelTypePayloadMap ModelTypePayloadMapFromRoutingInfo(
+ const browser_sync::ModelSafeRoutingInfo& routes,
+ const std::string& payload);
+
+std::string ModelTypePayloadMapToString(
+ const ModelTypePayloadMap& model_type_payloads);
+
+// Caller takes ownership of the returned dictionary.
+base::DictionaryValue* ModelTypePayloadMapToValue(
+ const ModelTypePayloadMap& model_type_payloads);
+
+// Coalesce |update| into |original|, overwriting only when |update| has
+// a non-empty payload.
+void CoalescePayloads(ModelTypePayloadMap* original,
+ const ModelTypePayloadMap& update);
+
+void PurgeStalePayload(ModelTypePayloadMap* original,
+ const browser_sync::ModelSafeRoutingInfo& routing_info);
+
+} // namespace syncable
+
+#endif // SYNC_INTERNAL_PUBLIC_API_SYNCABLE_MODEL_TYPE_PAYLOAD_MAP_H_
diff --git a/sync/internal_api/public/syncable/model_type_payload_map_unittest.cc b/sync/internal_api/public/syncable/model_type_payload_map_unittest.cc
new file mode 100644
index 0000000..4a18b34
--- /dev/null
+++ b/sync/internal_api/public/syncable/model_type_payload_map_unittest.cc
@@ -0,0 +1,46 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sync/internal_api/public/syncable/model_type_payload_map.h"
+
+#include <string>
+
+#include "base/base64.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/test/values_test_util.h"
+#include "base/values.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace syncable {
+namespace {
+
+using base::ExpectDictStringValue;
+
+class ModelTypePayloadMapTest : public testing::Test {};
+
+TEST_F(ModelTypePayloadMapTest, TypePayloadMapToSet) {
+ ModelTypePayloadMap payloads;
+ payloads[BOOKMARKS] = "bookmarkpayload";
+ payloads[APPS] = "";
+
+ const ModelTypeSet types(BOOKMARKS, APPS);
+ EXPECT_TRUE(ModelTypePayloadMapToEnumSet(payloads).Equals(types));
+}
+
+TEST_F(ModelTypePayloadMapTest, TypePayloadMapToValue) {
+ ModelTypePayloadMap payloads;
+ std::string encoded;
+ payloads[BOOKMARKS] = "bookmarkpayload";
+ base::Base64Encode(payloads[BOOKMARKS], &encoded);
+ payloads[APPS] = "";
+
+ scoped_ptr<DictionaryValue> value(ModelTypePayloadMapToValue(payloads));
+ EXPECT_EQ(2u, value->size());
+ ExpectDictStringValue(encoded, *value, "Bookmarks");
+ ExpectDictStringValue("", *value, "Apps");
+ EXPECT_FALSE(value->HasKey("Preferences"));
+}
+
+} // namespace
+} // namespace syncable
diff --git a/sync/internal_api/public/syncable/model_type_test_util.cc b/sync/internal_api/public/syncable/model_type_test_util.cc
new file mode 100644
index 0000000..36d1673
--- /dev/null
+++ b/sync/internal_api/public/syncable/model_type_test_util.cc
@@ -0,0 +1,52 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sync/internal_api/public/syncable/model_type_test_util.h"
+
+namespace syncable {
+
+void PrintTo(ModelTypeSet model_types, ::std::ostream* os) {
+ *os << ModelTypeSetToString(model_types);
+}
+
+namespace {
+
+// Matcher implementation for HasModelTypes().
+class HasModelTypesMatcher
+ : public ::testing::MatcherInterface<ModelTypeSet> {
+ public:
+ explicit HasModelTypesMatcher(ModelTypeSet expected_types)
+ : expected_types_(expected_types) {}
+
+ virtual ~HasModelTypesMatcher() {}
+
+ virtual bool MatchAndExplain(
+ ModelTypeSet model_types,
+ ::testing::MatchResultListener* listener) const {
+ // No need to annotate listener since we already define PrintTo().
+ return model_types.Equals(expected_types_);
+ }
+
+ virtual void DescribeTo(::std::ostream* os) const {
+ *os << "has model types " << ModelTypeSetToString(expected_types_);
+ }
+
+ virtual void DescribeNegationTo(::std::ostream* os) const {
+ *os << "doesn't have model types "
+ << ModelTypeSetToString(expected_types_);
+ }
+
+ private:
+ const ModelTypeSet expected_types_;
+
+ DISALLOW_COPY_AND_ASSIGN(HasModelTypesMatcher);
+};
+
+} // namespace
+
+::testing::Matcher<ModelTypeSet> HasModelTypes(ModelTypeSet expected_types) {
+ return ::testing::MakeMatcher(new HasModelTypesMatcher(expected_types));
+}
+
+} // namespace syncable
diff --git a/sync/internal_api/public/syncable/model_type_test_util.h b/sync/internal_api/public/syncable/model_type_test_util.h
new file mode 100644
index 0000000..173212f
--- /dev/null
+++ b/sync/internal_api/public/syncable/model_type_test_util.h
@@ -0,0 +1,26 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SYNC_INTERNAL_PUBLIC_API_SYNCABLE_MODEL_TYPE_TEST_UTIL_H_
+#define SYNC_INTERNAL_PUBLIC_API_SYNCABLE_MODEL_TYPE_TEST_UTIL_H_
+#pragma once
+
+#include <ostream>
+
+#include "sync/internal_api/public/syncable/model_type.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace syncable {
+
+// Defined for googletest. Forwards to ModelTypeSetToString().
+void PrintTo(ModelTypeSet model_types, ::std::ostream* os);
+
+// A gmock matcher for ModelTypeSet. Use like:
+//
+// EXPECT_CALL(mock, ProcessModelTypes(HasModelTypes(expected_types)));
+::testing::Matcher<ModelTypeSet> HasModelTypes(ModelTypeSet expected_types);
+
+} // namespace syncable
+
+#endif // SYNC_INTERNAL_PUBLIC_API_SYNCABLE_MODEL_TYPE_TEST_UTIL_H_
diff --git a/sync/internal_api/public/util/enum_set.h b/sync/internal_api/public/util/enum_set.h
new file mode 100644
index 0000000..de270d8
--- /dev/null
+++ b/sync/internal_api/public/util/enum_set.h
@@ -0,0 +1,286 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SYNC_INTERNAL_API_PUBLIC_UTIL_ENUM_SET_H_
+#define SYNC_INTERNAL_API_PUBLIC_UTIL_ENUM_SET_H_
+#pragma once
+
+#include <bitset>
+#include <cstddef>
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+
+namespace browser_sync {
+
+// Forward declarations needed for friend declarations.
+template <typename E, E MinEnumValue, E MaxEnumValue>
+class EnumSet;
+
+template <typename E, E Min, E Max>
+EnumSet<E, Min, Max> Union(EnumSet<E, Min, Max> set1,
+ EnumSet<E, Min, Max> set2);
+
+template <typename E, E Min, E Max>
+EnumSet<E, Min, Max> Intersection(EnumSet<E, Min, Max> set1,
+ EnumSet<E, Min, Max> set2);
+
+template <typename E, E Min, E Max>
+EnumSet<E, Min, Max> Difference(EnumSet<E, Min, Max> set1,
+ EnumSet<E, Min, Max> set2);
+
+// An EnumSet is a set that can hold enum values between a min and a
+// max value (inclusive of both). It's essentially a wrapper around
+// std::bitset<> with stronger type enforcement, more descriptive
+// member function names, and an iterator interface.
+//
+// If you're working with enums with a small number of possible values
+// (say, fewer than 64), you can efficiently pass around an EnumSet
+// for that enum around by value.
+
+template <typename E, E MinEnumValue, E MaxEnumValue>
+class EnumSet {
+ public:
+ typedef E EnumType;
+ static const E kMinValue = MinEnumValue;
+ static const E kMaxValue = MaxEnumValue;
+ static const size_t kValueCount = kMaxValue - kMinValue + 1;
+ COMPILE_ASSERT(kMinValue < kMaxValue,
+ min_value_must_be_less_than_max_value);
+
+ private:
+ // Declaration needed by Iterator.
+ typedef std::bitset<kValueCount> EnumBitSet;
+
+ public:
+ // Iterator is a forward-only read-only iterator for EnumSet. Its
+ // interface is deliberately distinct from an STL iterator as its
+ // semantics are substantially different.
+ //
+ // Example usage:
+ //
+ // for (EnumSet<...>::Iterator it = enums.First(); it.Good(); it.Inc()) {
+ // Process(it.Get());
+ // }
+ //
+ // The iterator must not be outlived by the set. In particular, the
+ // following is an error:
+ //
+ // EnumSet<...> SomeFn() { ... }
+ //
+ // /* ERROR */
+ // for (EnumSet<...>::Iterator it = SomeFun().First(); ...
+ //
+ // Also, there are no guarantees as to what will happen if you
+ // modify an EnumSet while traversing it with an iterator.
+ class Iterator {
+ public:
+ // A default-constructed iterator can't do anything except check
+ // Good(). You need to call First() on an EnumSet to get a usable
+ // iterator.
+ Iterator() : enums_(NULL), i_(kValueCount) {}
+ ~Iterator() {}
+
+ // Copy constructor and assignment welcome.
+
+ // Returns true iff the iterator points to an EnumSet and it
+ // hasn't yet traversed the EnumSet entirely.
+ bool Good() const {
+ return enums_ && i_ < kValueCount && enums_->test(i_);
+ }
+
+ // Returns the value the iterator currently points to. Good()
+ // must hold.
+ E Get() const {
+ CHECK(Good());
+ return FromIndex(i_);
+ }
+
+ // Moves the iterator to the next value in the EnumSet. Good()
+ // must hold. Takes linear time.
+ void Inc() {
+ CHECK(Good());
+ i_ = FindNext(i_ + 1);
+ }
+
+ private:
+ friend Iterator EnumSet::First() const;
+
+ explicit Iterator(const EnumBitSet& enums)
+ : enums_(&enums), i_(FindNext(0)) {}
+
+ size_t FindNext(size_t i) {
+ while ((i < kValueCount) && !enums_->test(i)) {
+ ++i;
+ }
+ return i;
+ }
+
+ const EnumBitSet* enums_;
+ size_t i_;
+ };
+
+ // You can construct an EnumSet with 0, 1, 2, or 3 initial values.
+
+ EnumSet() {}
+
+ explicit EnumSet(E value) {
+ Put(value);
+ }
+
+ EnumSet(E value1, E value2) {
+ Put(value1);
+ Put(value2);
+ }
+
+ EnumSet(E value1, E value2, E value3) {
+ Put(value1);
+ Put(value2);
+ Put(value3);
+ }
+
+ // Returns an EnumSet with all possible values.
+ static EnumSet All() {
+ EnumBitSet enums;
+ enums.set();
+ return EnumSet(enums);
+ }
+
+ ~EnumSet() {}
+
+ // Copy constructor and assignment welcome.
+
+ // Set operations. Put, Retain, and Remove are basically
+ // self-mutating versions of Union, Intersection, and Difference
+ // (defined below).
+
+ // Adds the given value (which must be in range) to our set.
+ void Put(E value) {
+ enums_.set(ToIndex(value));
+ }
+
+ // Adds all values in the given set to our set.
+ void PutAll(EnumSet other) {
+ enums_ |= other.enums_;
+ }
+
+ // There's no real need for a Retain(E) member function.
+
+ // Removes all values not in the given set from our set.
+ void RetainAll(EnumSet other) {
+ enums_ &= other.enums_;
+ }
+
+ // If the given value is in range, removes it from our set.
+ void Remove(E value) {
+ if (InRange(value)) {
+ enums_.reset(ToIndex(value));
+ }
+ }
+
+ // Removes all values in the given set from our set.
+ void RemoveAll(EnumSet other) {
+ enums_ &= ~other.enums_;
+ }
+
+ // Removes all values from our set.
+ void Clear() {
+ enums_.reset();
+ }
+
+ // Returns true iff the given value is in range and a member of our
+ // set.
+ bool Has(E value) const {
+ return InRange(value) && enums_.test(ToIndex(value));
+ }
+
+ // Returns true iff the given set is a subset of our set.
+ bool HasAll(EnumSet other) const {
+ return (enums_ & other.enums_) == other.enums_;
+ }
+
+ // Returns true iff our set and the given set contain exactly the
+ // same values.
+ bool Equals(const EnumSet& other) const {
+ return enums_ == other.enums_;
+ }
+
+ // Returns true iff our set is empty.
+ bool Empty() const {
+ return !enums_.any();
+ }
+
+ // Returns how many values our set has.
+ size_t Size() const {
+ return enums_.count();
+ }
+
+ // Returns an iterator pointing to the first element (if any).
+ Iterator First() const {
+ return Iterator(enums_);
+ }
+
+ private:
+ friend EnumSet Union<E, MinEnumValue, MaxEnumValue>(
+ EnumSet set1, EnumSet set2);
+ friend EnumSet Intersection<E, MinEnumValue, MaxEnumValue>(
+ EnumSet set1, EnumSet set2);
+ friend EnumSet Difference<E, MinEnumValue, MaxEnumValue>(
+ EnumSet set1, EnumSet set2);
+
+ explicit EnumSet(EnumBitSet enums) : enums_(enums) {}
+
+ static bool InRange(E value) {
+ return (value >= MinEnumValue) && (value <= MaxEnumValue);
+ }
+
+ // Converts a value to/from an index into |enums_|.
+
+ static size_t ToIndex(E value) {
+ DCHECK_GE(value, MinEnumValue);
+ DCHECK_LE(value, MaxEnumValue);
+ return value - MinEnumValue;
+ }
+
+ static E FromIndex(size_t i) {
+ DCHECK_LT(i, kValueCount);
+ return static_cast<E>(MinEnumValue + i);
+ }
+
+ EnumBitSet enums_;
+};
+
+template <typename E, E MinEnumValue, E MaxEnumValue>
+const E EnumSet<E, MinEnumValue, MaxEnumValue>::kMinValue;
+
+template <typename E, E MinEnumValue, E MaxEnumValue>
+const E EnumSet<E, MinEnumValue, MaxEnumValue>::kMaxValue;
+
+template <typename E, E MinEnumValue, E MaxEnumValue>
+const size_t EnumSet<E, MinEnumValue, MaxEnumValue>::kValueCount;
+
+// The usual set operations.
+
+template <typename E, E Min, E Max>
+EnumSet<E, Min, Max> Union(EnumSet<E, Min, Max> set1,
+ EnumSet<E, Min, Max> set2) {
+ return EnumSet<E, Min, Max>(set1.enums_ | set2.enums_);
+}
+
+template <typename E, E Min, E Max>
+EnumSet<E, Min, Max> Intersection(EnumSet<E, Min, Max> set1,
+ EnumSet<E, Min, Max> set2) {
+ return EnumSet<E, Min, Max>(set1.enums_ & set2.enums_);
+}
+
+template <typename E, E Min, E Max>
+EnumSet<E, Min, Max> Difference(EnumSet<E, Min, Max> set1,
+ EnumSet<E, Min, Max> set2) {
+ return EnumSet<E, Min, Max>(set1.enums_ & ~set2.enums_);
+}
+
+} // namespace browser_sync
+
+#endif // SYNC_INTERNAL_API_PUBLIC_UTIL_ENUM_SET_H_
diff --git a/sync/internal_api/public/util/enum_set_unittest.cc b/sync/internal_api/public/util/enum_set_unittest.cc
new file mode 100644
index 0000000..2caa1de
--- /dev/null
+++ b/sync/internal_api/public/util/enum_set_unittest.cc
@@ -0,0 +1,195 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sync/internal_api/public/util/enum_set.h"
+
+#include "base/basictypes.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace browser_sync {
+namespace {
+
+enum TestEnum {
+ TEST_0,
+ TEST_MIN = TEST_0,
+ TEST_1,
+ TEST_2,
+ TEST_3,
+ TEST_4,
+ TEST_MAX = TEST_4,
+ TEST_5
+};
+
+typedef EnumSet<TestEnum, TEST_MIN, TEST_MAX> TestEnumSet;
+
+class EnumSetTest : public ::testing::Test {};
+
+TEST_F(EnumSetTest, ClassConstants) {
+ TestEnumSet enums;
+ EXPECT_EQ(TEST_MIN, TestEnumSet::kMinValue);
+ EXPECT_EQ(TEST_MAX, TestEnumSet::kMaxValue);
+ EXPECT_EQ(static_cast<size_t>(5), TestEnumSet::kValueCount);
+}
+
+TEST_F(EnumSetTest, DefaultConstructor) {
+ const TestEnumSet enums;
+ EXPECT_TRUE(enums.Empty());
+ EXPECT_EQ(static_cast<size_t>(0), enums.Size());
+ EXPECT_FALSE(enums.Has(TEST_0));
+ EXPECT_FALSE(enums.Has(TEST_1));
+ EXPECT_FALSE(enums.Has(TEST_2));
+ EXPECT_FALSE(enums.Has(TEST_3));
+ EXPECT_FALSE(enums.Has(TEST_4));
+}
+
+TEST_F(EnumSetTest, OneArgConstructor) {
+ const TestEnumSet enums(TEST_3);
+ EXPECT_FALSE(enums.Empty());
+ EXPECT_EQ(static_cast<size_t>(1), enums.Size());
+ EXPECT_FALSE(enums.Has(TEST_0));
+ EXPECT_FALSE(enums.Has(TEST_1));
+ EXPECT_FALSE(enums.Has(TEST_2));
+ EXPECT_TRUE(enums.Has(TEST_3));
+ EXPECT_FALSE(enums.Has(TEST_4));
+}
+
+TEST_F(EnumSetTest, TwoArgConstructor) {
+ const TestEnumSet enums(TEST_3, TEST_1);
+ EXPECT_FALSE(enums.Empty());
+ EXPECT_EQ(static_cast<size_t>(2), enums.Size());
+ EXPECT_FALSE(enums.Has(TEST_0));
+ EXPECT_TRUE(enums.Has(TEST_1));
+ EXPECT_FALSE(enums.Has(TEST_2));
+ EXPECT_TRUE(enums.Has(TEST_3));
+ EXPECT_FALSE(enums.Has(TEST_4));
+}
+
+TEST_F(EnumSetTest, ThreeArgConstructor) {
+ const TestEnumSet enums(TEST_3, TEST_1, TEST_0);
+ EXPECT_FALSE(enums.Empty());
+ EXPECT_EQ(static_cast<size_t>(3), enums.Size());
+ EXPECT_TRUE(enums.Has(TEST_0));
+ EXPECT_TRUE(enums.Has(TEST_1));
+ EXPECT_FALSE(enums.Has(TEST_2));
+ EXPECT_TRUE(enums.Has(TEST_3));
+ EXPECT_FALSE(enums.Has(TEST_4));
+}
+
+TEST_F(EnumSetTest, All) {
+ const TestEnumSet enums(TestEnumSet::All());
+ EXPECT_FALSE(enums.Empty());
+ EXPECT_EQ(static_cast<size_t>(5), enums.Size());
+ EXPECT_TRUE(enums.Has(TEST_0));
+ EXPECT_TRUE(enums.Has(TEST_1));
+ EXPECT_TRUE(enums.Has(TEST_2));
+ EXPECT_TRUE(enums.Has(TEST_3));
+ EXPECT_TRUE(enums.Has(TEST_4));
+}
+
+TEST_F(EnumSetTest, Put) {
+ TestEnumSet enums(TEST_3);
+ enums.Put(TEST_2);
+ EXPECT_TRUE(enums.Equals(TestEnumSet(TEST_2, TEST_3)));
+ enums.Put(TEST_4);
+ EXPECT_TRUE(enums.Equals(TestEnumSet(TEST_2, TEST_3, TEST_4)));
+}
+
+TEST_F(EnumSetTest, PutAll) {
+ TestEnumSet enums(TEST_3, TEST_4);
+ enums.PutAll(TestEnumSet(TEST_2, TEST_3));
+ EXPECT_TRUE(enums.Equals(TestEnumSet(TEST_2, TEST_3, TEST_4)));
+}
+
+TEST_F(EnumSetTest, RetainAll) {
+ TestEnumSet enums(TEST_3, TEST_4);
+ enums.RetainAll(TestEnumSet(TEST_2, TEST_3));
+ EXPECT_TRUE(enums.Equals(TestEnumSet(TEST_3)));
+}
+
+TEST_F(EnumSetTest, Remove) {
+ TestEnumSet enums(TEST_3, TEST_4);
+ enums.Remove(TEST_0);
+ enums.Remove(TEST_2);
+ EXPECT_TRUE(enums.Equals(TestEnumSet(TEST_3, TEST_4)));
+ enums.Remove(TEST_3);
+ EXPECT_TRUE(enums.Equals(TestEnumSet(TEST_4)));
+ enums.Remove(TEST_4);
+ enums.Remove(TEST_5);
+ EXPECT_TRUE(enums.Empty());
+}
+
+TEST_F(EnumSetTest, RemoveAll) {
+ TestEnumSet enums(TEST_3, TEST_4);
+ enums.RemoveAll(TestEnumSet(TEST_2, TEST_3));
+ EXPECT_TRUE(enums.Equals(TestEnumSet(TEST_4)));
+}
+
+TEST_F(EnumSetTest, Clear) {
+ TestEnumSet enums(TEST_3, TEST_4);
+ enums.Clear();
+ EXPECT_TRUE(enums.Empty());
+}
+
+TEST_F(EnumSetTest, Has) {
+ const TestEnumSet enums(TEST_3, TEST_4);
+ EXPECT_FALSE(enums.Has(TEST_0));
+ EXPECT_FALSE(enums.Has(TEST_1));
+ EXPECT_FALSE(enums.Has(TEST_2));
+ EXPECT_TRUE(enums.Has(TEST_3));
+ EXPECT_TRUE(enums.Has(TEST_4));
+ EXPECT_FALSE(enums.Has(TEST_5));
+}
+
+TEST_F(EnumSetTest, HasAll) {
+ const TestEnumSet enums1(TEST_3, TEST_4);
+ const TestEnumSet enums2(TEST_2, TEST_3);
+ const TestEnumSet enums3 = Union(enums1, enums2);
+ EXPECT_TRUE(enums1.HasAll(enums1));
+ EXPECT_FALSE(enums1.HasAll(enums2));
+ EXPECT_FALSE(enums1.HasAll(enums3));
+
+ EXPECT_FALSE(enums2.HasAll(enums1));
+ EXPECT_TRUE(enums2.HasAll(enums2));
+ EXPECT_FALSE(enums2.HasAll(enums3));
+
+ EXPECT_TRUE(enums3.HasAll(enums1));
+ EXPECT_TRUE(enums3.HasAll(enums2));
+ EXPECT_TRUE(enums3.HasAll(enums3));
+}
+
+TEST_F(EnumSetTest, Iterators) {
+ const TestEnumSet enums1(TEST_3, TEST_4);
+ TestEnumSet enums2;
+ for (TestEnumSet::Iterator it = enums1.First(); it.Good(); it.Inc()) {
+ enums2.Put(it.Get());
+ }
+ EXPECT_TRUE(enums1.Equals(enums2));
+}
+
+TEST_F(EnumSetTest, Union) {
+ const TestEnumSet enums1(TEST_3, TEST_4);
+ const TestEnumSet enums2(TEST_2, TEST_3);
+ const TestEnumSet enums3 = Union(enums1, enums2);
+
+ EXPECT_TRUE(enums3.Equals(TestEnumSet(TEST_2, TEST_3, TEST_4)));
+}
+
+TEST_F(EnumSetTest, Intersection) {
+ const TestEnumSet enums1(TEST_3, TEST_4);
+ const TestEnumSet enums2(TEST_2, TEST_3);
+ const TestEnumSet enums3 = Intersection(enums1, enums2);
+
+ EXPECT_TRUE(enums3.Equals(TestEnumSet(TEST_3)));
+}
+
+TEST_F(EnumSetTest, Difference) {
+ const TestEnumSet enums1(TEST_3, TEST_4);
+ const TestEnumSet enums2(TEST_2, TEST_3);
+ const TestEnumSet enums3 = Difference(enums1, enums2);
+
+ EXPECT_TRUE(enums3.Equals(TestEnumSet(TEST_4)));
+}
+
+} // namespace
+} // namespace browser_sync
diff --git a/sync/internal_api/public/util/syncer_error.cc b/sync/internal_api/public/util/syncer_error.cc
new file mode 100644
index 0000000..b4ba578
--- /dev/null
+++ b/sync/internal_api/public/util/syncer_error.cc
@@ -0,0 +1,36 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sync/internal_api/public/util/syncer_error.h"
+
+#include "base/logging.h"
+
+namespace browser_sync {
+
+#define ENUM_CASE(x) case x: return #x; break;
+const char* GetSyncerErrorString(SyncerError value) {
+ switch (value) {
+ ENUM_CASE(UNSET);
+ ENUM_CASE(DIRECTORY_LOOKUP_FAILED);
+ ENUM_CASE(NETWORK_CONNECTION_UNAVAILABLE);
+ ENUM_CASE(NETWORK_IO_ERROR);
+ ENUM_CASE(SYNC_SERVER_ERROR);
+ ENUM_CASE(SYNC_AUTH_ERROR);
+ ENUM_CASE(SERVER_RETURN_INVALID_CREDENTIAL);
+ ENUM_CASE(SERVER_RETURN_UNKNOWN_ERROR);
+ ENUM_CASE(SERVER_RETURN_THROTTLED);
+ ENUM_CASE(SERVER_RETURN_TRANSIENT_ERROR);
+ ENUM_CASE(SERVER_RETURN_MIGRATION_DONE);
+ ENUM_CASE(SERVER_RETURN_CLEAR_PENDING);
+ ENUM_CASE(SERVER_RETURN_NOT_MY_BIRTHDAY);
+ ENUM_CASE(SERVER_RESPONSE_VALIDATION_FAILED);
+ ENUM_CASE(SYNCER_OK);
+ }
+ NOTREACHED();
+ return "INVALID";
+}
+#undef ENUM_CASE
+
+} // namespace browser_sync
+
diff --git a/sync/internal_api/public/util/syncer_error.h b/sync/internal_api/public/util/syncer_error.h
new file mode 100644
index 0000000..aa6ebb3
--- /dev/null
+++ b/sync/internal_api/public/util/syncer_error.h
@@ -0,0 +1,46 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SYNC_INTERNAL_API_PUBLIC_UTIL_SYNCER_ERROR_H_
+#define SYNC_INTERNAL_API_PUBLIC_UTIL_SYNCER_ERROR_H_
+#pragma once
+
+namespace browser_sync {
+
+// This enum describes all the ways a SyncerCommand can fail.
+//
+// SyncerCommands do many different things, but they share a common function
+// signature. This enum, the return value for all SyncerCommands, must be able
+// to describe any possible failure for all SyncerComand.
+//
+// For convenience, functions which are invoked only by SyncerCommands may also
+// return a SyncerError. It saves us having to write a conversion function, and
+// it makes refactoring easier.
+enum SyncerError {
+ UNSET = 0, // Default value.
+ DIRECTORY_LOOKUP_FAILED, // Local directory lookup failure.
+
+ NETWORK_CONNECTION_UNAVAILABLE, // Connectivity failure.
+ NETWORK_IO_ERROR, // Response buffer read error.
+ SYNC_SERVER_ERROR, // Non auth HTTP error.
+ SYNC_AUTH_ERROR, // HTTP auth error.
+
+ // Based on values returned by server. Most are defined in sync.proto.
+ SERVER_RETURN_INVALID_CREDENTIAL,
+ SERVER_RETURN_UNKNOWN_ERROR,
+ SERVER_RETURN_THROTTLED,
+ SERVER_RETURN_TRANSIENT_ERROR,
+ SERVER_RETURN_MIGRATION_DONE,
+ SERVER_RETURN_CLEAR_PENDING,
+ SERVER_RETURN_NOT_MY_BIRTHDAY,
+ SERVER_RESPONSE_VALIDATION_FAILED,
+
+ SYNCER_OK
+};
+
+const char * GetSyncerErrorString(SyncerError);
+
+} // namespace browser_sync
+
+#endif // SYNC_INTERNAL_API_PUBLIC_UTIL_SYNCER_ERROR_H_