Index: third_party/libaddressinput/chromium/cpp/src/country_rules_retriever.cc |
diff --git a/third_party/libaddressinput/chromium/cpp/src/country_rules_retriever.cc b/third_party/libaddressinput/chromium/cpp/src/country_rules_retriever.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..f7ad6a4037b3a6cf7f5e6cb4b4592acc5469ad38 |
--- /dev/null |
+++ b/third_party/libaddressinput/chromium/cpp/src/country_rules_retriever.cc |
@@ -0,0 +1,258 @@ |
+// Copyright (C) 2013 Google Inc. |
+// |
+// Licensed under the Apache License, Version 2.0 (the "License"); |
+// you may not use this file except in compliance with the License. |
+// You may obtain a copy of the License at |
+// |
+// http://www.apache.org/licenses/LICENSE-2.0 |
+// |
+// Unless required by applicable law or agreed to in writing, software |
+// distributed under the License is distributed on an "AS IS" BASIS, |
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
+// See the License for the specific language governing permissions and |
+// limitations under the License. |
+// |
+// CountryRulesRetriever uses Helper to download Rulesets (a tree of rules) for |
+// country codes. Helper builds a Ruleset and passes it to the |
+// CountryRulesRetriever::Callback in a scoped pointer. Helper uses a map of |
+// lookup keys (e.g. "data/CA/AB--fr") to RequestData objects to keep track of |
+// how the Ruleset should be built. |
+ |
+#include "country_rules_retriever.h" |
+ |
+#include <libaddressinput/address_field.h> |
+#include <libaddressinput/callback.h> |
+#include <libaddressinput/util/basictypes.h> |
+#include <libaddressinput/util/scoped_ptr.h> |
+ |
+#include <cassert> |
+#include <cstddef> |
+#include <string> |
+ |
+#include "retriever.h" |
+#include "rule.h" |
+#include "ruleset.h" |
+ |
+namespace i18n { |
+namespace addressinput { |
+ |
+namespace { |
+ |
+// Stores auxiliary information about data requests sent to Retriever. This data |
+// is not returned as part of the ruleset, but is useful in constructing the |
+// ruleset asynchronously. |
+struct RequestData { |
+ // Does not take ownership of |parent|. |
+ RequestData(Ruleset* parent, |
+ AddressField level, |
+ bool is_language_code, |
+ const std::string& id) |
+ : parent(parent), |
+ level(level), |
+ is_language_code(is_language_code), |
+ id(id) {} |
+ ~RequestData() {} |
+ |
+ // The parent ruleset of the data being downloaded. If NULL, then this is the |
+ // root ruleset at the COUNTRY level. The language-specific and sub-region |
+ // rules are added to this ruleset. Owned by |Helper|. |
+ Ruleset* parent; |
+ |
+ // The level of the data being requested. Ranges from COUNTRY to |
+ // DEPENDENT_LOCALITY. If COUNTRY, then the rule should use default rules from |
+ // Rule::GetDefault(). |
+ AddressField level; |
+ |
+ // If true, then |id| is a language. The data received for this request should |
+ // be placed into a language-specific rule. |
+ bool is_language_code; |
+ |
+ // Can be a region name (e.g. "CA") or a language (e.g. "fr"). Used to add a |
+ // sub-region or a language-specific rule to |parent|. |
+ std::string id; |
+}; |
+ |
+// Retrieves a ruleset for a single country code. |
+class Helper { |
+ public: |
+ // Uses |retriever| to recursively retrieve the ruleset for |country_code|. |
+ // Invokes |rules_ready| callback when done. |
+ Helper(const std::string& country_code, |
+ scoped_ptr<CountryRulesRetriever::Callback> rules_ready, |
+ const Retriever& retriever) |
+ : country_code_(country_code), |
+ rules_ready_(rules_ready.Pass()), |
+ retriever_(retriever), |
+ root_(), |
+ num_requested_(1), |
+ num_received_(0), |
+ success_(true), |
+ default_language_(), |
+ languages_(), |
+ requests_() { |
+ // Key construction: |
+ // https://code.google.com/p/libaddressinput/wiki/AddressValidationMetadata |
+ // Example of a country-level key: "data/CA". |
+ std::string key = "data/" + country_code_; |
+ requests_.insert(std::make_pair( |
+ key, RequestData(NULL, COUNTRY, false, std::string()))); |
+ retriever_.Retrieve(key, BuildCallback(this, &Helper::OnDataReady)); |
+ } |
+ |
+ private: |
+ ~Helper() {} |
+ |
+ void OnDataReady(bool success, |
+ const std::string& key, |
+ const std::string& data) { |
+ success_ &= success; |
+ ++num_received_; |
+ |
+ std::map<std::string, RequestData>::iterator request_it = |
+ requests_.find(key); |
+ assert(request_it != requests_.end()); |
+ RequestData& request = request_it->second; |
+ |
+ // All country-level rules are based on the default rule. |
+ scoped_ptr<Rule> rule(new Rule); |
+ if (request.level == COUNTRY) { |
+ rule->CopyFrom(Rule::GetDefault()); |
+ } |
+ |
+ success &= rule->ParseSerializedRule(data); |
+ |
+ // The default language and all supported languages for the country code are |
+ // in the country-level rule without a language code identifier. For |
+ // example: "data/CA". |
+ if (request.level == COUNTRY && !request.is_language_code) { |
+ default_language_ = rule->GetLanguage(); |
+ languages_ = rule->GetLanguages(); |
+ } |
+ |
+ Ruleset* ruleset = NULL; |
+ if (request.level == COUNTRY) { |
+ root_.reset(new Ruleset(rule.Pass())); |
+ ruleset = root_.get(); |
+ } else if (request.is_language_code) { |
+ assert(request.parent != NULL); |
+ request.parent->AddLanguageCode(request.id, rule.Pass()); |
+ // The |ruleset| is intentionally NULL. |
+ } else { |
+ assert(request.parent != NULL); |
+ ruleset = request.parent->AddSubRegion(request.id, rule.Pass()); |
+ } |
+ |
+ if (!request.is_language_code) { |
+ // Retrieve the language-specific rules for this region. |
+ for (std::vector<std::string>::const_iterator |
+ lang_it = languages_.begin(); |
+ lang_it != languages_.end(); |
+ ++lang_it) { |
+ if (*lang_it != default_language_) { |
+ // Example of a language-specific key: "data/CA--fr". |
+ std::string language_code_key = key + "--" + *lang_it; |
+ requests_.insert(std::make_pair( |
+ key, RequestData(ruleset, request.level, true, *lang_it))); |
+ ++num_requested_; |
+ retriever_.Retrieve( |
+ language_code_key, BuildCallback(this, &Helper::OnDataReady)); |
+ } |
+ } |
+ |
+ if (request.level < DEPENDENT_LOCALITY) { |
+ assert(ruleset->GetRule() != NULL); |
+ // Retrieve the sub-region rules for this region. |
+ for (std::vector<std::string>::const_iterator |
+ subkey_it = ruleset->GetRule()->GetSubKeys().begin(); |
+ subkey_it != ruleset->GetRule()->GetSubKeys().end(); |
+ ++subkey_it) { |
+ // Example of a sub-region key: "data/CA/AB". |
+ std::string sub_region_key = key + "/" + *subkey_it; |
+ requests_.insert(std::make_pair( |
+ key, |
+ RequestData(ruleset, |
+ static_cast<AddressField>(request.level + 1), |
+ false, |
+ *subkey_it))); |
+ ++num_requested_; |
+ retriever_.Retrieve( |
+ sub_region_key, BuildCallback(this, &Helper::OnDataReady)); |
+ } |
+ } |
+ } |
+ |
+ if (num_received_ == num_requested_) { |
+ (*rules_ready_)(success_, country_code_, root_.Pass()); |
+ delete this; |
+ } |
+ } |
+ |
+ // The country code for which to retrieve the ruleset. Passed to the callback |
+ // method to identify the ruleset. Examples: "US", "CA", "CH", etc. |
+ const std::string country_code_; |
+ |
+ // The callback to invoke when the ruleset has been retrieved. |
+ scoped_ptr<CountryRulesRetriever::Callback> rules_ready_; |
+ |
+ // The data retriever that can download serialized rules for one sub-region at |
+ // a time. |
+ const Retriever& retriever_; |
+ |
+ // The top-level ruleset for the country code. Passed to the callback method |
+ // as the result of the query. |
+ scoped_ptr<Ruleset> root_; |
+ |
+ // The number of requests sent to Retriever. Used to keep track of pending |
+ // requests. |
+ int num_requested_; |
+ |
+ // The number of responses received from Retriever. Used to determine when the |
+ // ruleset construction is finished, by comparing this number to |
+ // |num_requested_|. |
+ int num_received_; |
+ |
+ // True if all requests to Retriever succeeded. Passed to the callback method |
+ // as an indication of whether ruleset retrieval succeeded. |
+ bool success_; |
+ |
+ // The default language for the country code. This value is parsed from the |
+ // country-level rule for the country code and is used to filter out the |
+ // default language from the list of all supported languages for a country. |
+ // For example, the list of supported languages for Canada is ["en", "fr"], |
+ // but the default language is "en". Data requests for "data/CA/AB--fr" will |
+ // succeed, but "data/CA/AB--en" will not return data. |
+ std::string default_language_; |
+ |
+ // The list of all supported languages for the country code. This value is |
+ // parsed from the country-level rule for the country and is used to download |
+ // language-specific rules. |
+ std::vector<std::string> languages_; |
+ |
+ // A map of data keys (e.g., "data/CA/AB--fr") to information that will help |
+ // to parse the response data and place it in the correct location in the |
+ // ruleset. For example, the RequestData for "data/CA/AB--fr" will specify |
+ // that the retrieved rule is the "fr" language-specific rule for "data/CA/AB" |
+ // ruleset. |
+ std::map<std::string, RequestData> requests_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(Helper); |
+}; |
+ |
+} // namespace |
+ |
+CountryRulesRetriever::CountryRulesRetriever( |
+ scoped_ptr<const Retriever> retriever) |
+ : retriever_(retriever.Pass()) { |
+ assert(retriever_ != NULL); |
+} |
+ |
+CountryRulesRetriever::~CountryRulesRetriever() {} |
+ |
+void CountryRulesRetriever::RetrieveRules( |
+ const std::string& country_code, |
+ scoped_ptr<Callback> rules_ready) const { |
+ new Helper(country_code, rules_ready.Pass(), *retriever_); |
Evan Stade
2014/01/06 22:54:19
this seems dangerous. How do you know Helper won't
please use gerrit instead
2014/01/06 23:44:35
This helper uses the same safety measure as all ot
Evan Stade
2014/01/07 00:03:15
Recall how I wanted to make it a rule that you onl
please use gerrit instead
2014/01/07 01:54:38
Done.
|
+} |
+ |
+} // namespace addressinput |
+} // namespace i18n |