blob: 187c4c44db79dd81f8cfb9f2419a09412a1e316b [file] [log] [blame]
[email protected]261c877e2012-01-05 09:46:421// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]193f946b2011-12-22 18:31:472// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef BASE_JSON_JSON_VALUE_CONVERTER_H_
6#define BASE_JSON_JSON_VALUE_CONVERTER_H_
[email protected]193f946b2011-12-22 18:31:477
avi9b6f42932015-12-26 22:15:148#include <stddef.h>
9
dcheng093de9b2016-04-04 21:25:5110#include <memory>
[email protected]193f946b2011-12-22 18:31:4711#include <string>
12#include <vector>
13
dmichael7d09007e2014-12-18 22:30:1114#include "base/base_export.h"
[email protected]193f946b2011-12-22 18:31:4715#include "base/logging.h"
avi9b6f42932015-12-26 22:15:1416#include "base/macros.h"
[email protected]a9b8e0a2012-01-14 05:36:1217#include "base/memory/scoped_vector.h"
[email protected]d529cb02013-06-10 19:06:5718#include "base/strings/string16.h"
[email protected]eb62f7262013-03-30 14:29:0019#include "base/strings/string_piece.h"
[email protected]193f946b2011-12-22 18:31:4720#include "base/values.h"
21
22// JSONValueConverter converts a JSON value into a C++ struct in a
23// lightweight way.
24//
25// Usage:
26// For real examples, you may want to refer to _unittest.cc file.
27//
28// Assume that you have a struct like this:
29// struct Message {
30// int foo;
31// std::string bar;
32// static void RegisterJSONConverter(
33// JSONValueConverter<Message>* converter);
34// };
35//
36// And you want to parse a json data into this struct. First, you
37// need to declare RegisterJSONConverter() method in your struct.
38// // static
39// void Message::RegisterJSONConverter(
40// JSONValueConverter<Message>* converter) {
41// converter->RegisterIntField("foo", &Message::foo);
42// converter->RegisterStringField("bar", &Message::bar);
43// }
44//
45// Then, you just instantiate your JSONValueConverter of your type and call
46// Convert() method.
47// Message message;
48// JSONValueConverter<Message> converter;
49// converter.Convert(json, &message);
50//
[email protected]261c877e2012-01-05 09:46:4251// Convert() returns false when it fails. Here "fail" means that the value is
52// structurally different from expected, such like a string value appears
53// for an int field. Do not report failures for missing fields.
54// Also note that Convert() will modify the passed |message| even when it
55// fails for performance reason.
56//
[email protected]193f946b2011-12-22 18:31:4757// For nested field, the internal message also has to implement the registration
58// method. Then, just use RegisterNestedField() from the containing struct's
59// RegisterJSONConverter method.
60// struct Nested {
61// Message foo;
[email protected]261c877e2012-01-05 09:46:4262// static void RegisterJSONConverter(...) {
[email protected]193f946b2011-12-22 18:31:4763// ...
64// converter->RegisterNestedField("foo", &Nested::foo);
65// }
66// };
67//
[email protected]a9b8e0a2012-01-14 05:36:1268// For repeated field, we just assume ScopedVector for its container
[email protected]193f946b2011-12-22 18:31:4769// and you can put RegisterRepeatedInt or some other types. Use
70// RegisterRepeatedMessage for nested repeated fields.
71//
[email protected]6009ca92012-01-13 02:18:0272// Sometimes JSON format uses string representations for other types such
73// like enum, timestamp, or URL. You can use RegisterCustomField method
74// and specify a function to convert a StringPiece to your type.
75// bool ConvertFunc(const StringPiece& s, YourEnum* result) {
76// // do something and return true if succeed...
77// }
78// struct Message {
79// YourEnum ye;
80// ...
81// static void RegisterJSONConverter(...) {
82// ...
83// converter->RegsiterCustomField<YourEnum>(
84// "your_enum", &Message::ye, &ConvertFunc);
85// }
86// };
[email protected]193f946b2011-12-22 18:31:4787
88namespace base {
89
90template <typename StructType>
91class JSONValueConverter;
92
93namespace internal {
94
[email protected]983b9b72012-01-27 07:12:2195template<typename StructType>
[email protected]193f946b2011-12-22 18:31:4796class FieldConverterBase {
97 public:
[email protected]983b9b72012-01-27 07:12:2198 explicit FieldConverterBase(const std::string& path) : field_path_(path) {}
99 virtual ~FieldConverterBase() {}
100 virtual bool ConvertField(const base::Value& value, StructType* obj)
101 const = 0;
[email protected]193f946b2011-12-22 18:31:47102 const std::string& field_path() const { return field_path_; }
103
104 private:
105 std::string field_path_;
106 DISALLOW_COPY_AND_ASSIGN(FieldConverterBase);
107};
108
109template <typename FieldType>
110class ValueConverter {
111 public:
112 virtual ~ValueConverter() {}
[email protected]261c877e2012-01-05 09:46:42113 virtual bool Convert(const base::Value& value, FieldType* field) const = 0;
[email protected]193f946b2011-12-22 18:31:47114};
115
116template <typename StructType, typename FieldType>
[email protected]983b9b72012-01-27 07:12:21117class FieldConverter : public FieldConverterBase<StructType> {
[email protected]193f946b2011-12-22 18:31:47118 public:
119 explicit FieldConverter(const std::string& path,
120 FieldType StructType::* field,
121 ValueConverter<FieldType>* converter)
[email protected]983b9b72012-01-27 07:12:21122 : FieldConverterBase<StructType>(path),
[email protected]193f946b2011-12-22 18:31:47123 field_pointer_(field),
124 value_converter_(converter) {
125 }
126
nickc0b001062015-04-22 23:17:20127 bool ConvertField(const base::Value& value, StructType* dst) const override {
[email protected]261c877e2012-01-05 09:46:42128 return value_converter_->Convert(value, &(dst->*field_pointer_));
[email protected]193f946b2011-12-22 18:31:47129 }
130
131 private:
132 FieldType StructType::* field_pointer_;
dcheng093de9b2016-04-04 21:25:51133 std::unique_ptr<ValueConverter<FieldType>> value_converter_;
[email protected]193f946b2011-12-22 18:31:47134 DISALLOW_COPY_AND_ASSIGN(FieldConverter);
135};
136
137template <typename FieldType>
138class BasicValueConverter;
139
140template <>
dmichael7d09007e2014-12-18 22:30:11141class BASE_EXPORT BasicValueConverter<int> : public ValueConverter<int> {
[email protected]193f946b2011-12-22 18:31:47142 public:
143 BasicValueConverter() {}
144
dmichael7d09007e2014-12-18 22:30:11145 bool Convert(const base::Value& value, int* field) const override;
[email protected]193f946b2011-12-22 18:31:47146
147 private:
148 DISALLOW_COPY_AND_ASSIGN(BasicValueConverter);
149};
150
151template <>
dmichael7d09007e2014-12-18 22:30:11152class BASE_EXPORT BasicValueConverter<std::string>
153 : public ValueConverter<std::string> {
[email protected]193f946b2011-12-22 18:31:47154 public:
155 BasicValueConverter() {}
156
dmichael7d09007e2014-12-18 22:30:11157 bool Convert(const base::Value& value, std::string* field) const override;
[email protected]261c877e2012-01-05 09:46:42158
159 private:
160 DISALLOW_COPY_AND_ASSIGN(BasicValueConverter);
161};
162
163template <>
dmichael7d09007e2014-12-18 22:30:11164class BASE_EXPORT BasicValueConverter<string16>
165 : public ValueConverter<string16> {
[email protected]261c877e2012-01-05 09:46:42166 public:
167 BasicValueConverter() {}
168
dmichael7d09007e2014-12-18 22:30:11169 bool Convert(const base::Value& value, string16* field) const override;
[email protected]193f946b2011-12-22 18:31:47170
171 private:
172 DISALLOW_COPY_AND_ASSIGN(BasicValueConverter);
173};
174
175template <>
dmichael7d09007e2014-12-18 22:30:11176class BASE_EXPORT BasicValueConverter<double> : public ValueConverter<double> {
[email protected]193f946b2011-12-22 18:31:47177 public:
178 BasicValueConverter() {}
179
dmichael7d09007e2014-12-18 22:30:11180 bool Convert(const base::Value& value, double* field) const override;
[email protected]193f946b2011-12-22 18:31:47181
182 private:
183 DISALLOW_COPY_AND_ASSIGN(BasicValueConverter);
184};
185
186template <>
dmichael7d09007e2014-12-18 22:30:11187class BASE_EXPORT BasicValueConverter<bool> : public ValueConverter<bool> {
[email protected]193f946b2011-12-22 18:31:47188 public:
189 BasicValueConverter() {}
190
dmichael7d09007e2014-12-18 22:30:11191 bool Convert(const base::Value& value, bool* field) const override;
[email protected]193f946b2011-12-22 18:31:47192
193 private:
194 DISALLOW_COPY_AND_ASSIGN(BasicValueConverter);
195};
196
[email protected]6009ca92012-01-13 02:18:02197template <typename FieldType>
[email protected]038cf352012-04-13 00:14:15198class ValueFieldConverter : public ValueConverter<FieldType> {
199 public:
200 typedef bool(*ConvertFunc)(const base::Value* value, FieldType* field);
201
thestigcf9519fa2016-08-30 05:50:54202 explicit ValueFieldConverter(ConvertFunc convert_func)
[email protected]038cf352012-04-13 00:14:15203 : convert_func_(convert_func) {}
204
nickc0b001062015-04-22 23:17:20205 bool Convert(const base::Value& value, FieldType* field) const override {
[email protected]038cf352012-04-13 00:14:15206 return convert_func_(&value, field);
207 }
208
209 private:
210 ConvertFunc convert_func_;
211
212 DISALLOW_COPY_AND_ASSIGN(ValueFieldConverter);
213};
214
215template <typename FieldType>
[email protected]6009ca92012-01-13 02:18:02216class CustomFieldConverter : public ValueConverter<FieldType> {
217 public:
218 typedef bool(*ConvertFunc)(const StringPiece& value, FieldType* field);
219
thestigcf9519fa2016-08-30 05:50:54220 explicit CustomFieldConverter(ConvertFunc convert_func)
[email protected]6009ca92012-01-13 02:18:02221 : convert_func_(convert_func) {}
222
nickc0b001062015-04-22 23:17:20223 bool Convert(const base::Value& value, FieldType* field) const override {
[email protected]6009ca92012-01-13 02:18:02224 std::string string_value;
225 return value.GetAsString(&string_value) &&
226 convert_func_(string_value, field);
227 }
228
229 private:
230 ConvertFunc convert_func_;
231
232 DISALLOW_COPY_AND_ASSIGN(CustomFieldConverter);
233};
234
[email protected]193f946b2011-12-22 18:31:47235template <typename NestedType>
236class NestedValueConverter : public ValueConverter<NestedType> {
237 public:
238 NestedValueConverter() {}
239
nickc0b001062015-04-22 23:17:20240 bool Convert(const base::Value& value, NestedType* field) const override {
[email protected]261c877e2012-01-05 09:46:42241 return converter_.Convert(value, field);
[email protected]193f946b2011-12-22 18:31:47242 }
243
244 private:
245 JSONValueConverter<NestedType> converter_;
246 DISALLOW_COPY_AND_ASSIGN(NestedValueConverter);
247};
248
249template <typename Element>
[email protected]a9b8e0a2012-01-14 05:36:12250class RepeatedValueConverter : public ValueConverter<ScopedVector<Element> > {
[email protected]193f946b2011-12-22 18:31:47251 public:
252 RepeatedValueConverter() {}
253
nickc0b001062015-04-22 23:17:20254 bool Convert(const base::Value& value,
255 ScopedVector<Element>* field) const override {
[email protected]193f946b2011-12-22 18:31:47256 const base::ListValue* list = NULL;
257 if (!value.GetAsList(&list)) {
258 // The field is not a list.
[email protected]261c877e2012-01-05 09:46:42259 return false;
[email protected]193f946b2011-12-22 18:31:47260 }
261
262 field->reserve(list->GetSize());
263 for (size_t i = 0; i < list->GetSize(); ++i) {
[email protected]5d30f92bf2012-08-03 08:43:37264 const base::Value* element = NULL;
[email protected]193f946b2011-12-22 18:31:47265 if (!list->Get(i, &element))
266 continue;
267
dcheng093de9b2016-04-04 21:25:51268 std::unique_ptr<Element> e(new Element);
[email protected]50fa6f922012-01-26 19:32:36269 if (basic_converter_.Convert(*element, e.get())) {
270 field->push_back(e.release());
[email protected]a9b8e0a2012-01-14 05:36:12271 } else {
[email protected]261c877e2012-01-05 09:46:42272 DVLOG(1) << "failure at " << i << "-th element";
273 return false;
274 }
[email protected]193f946b2011-12-22 18:31:47275 }
[email protected]261c877e2012-01-05 09:46:42276 return true;
[email protected]193f946b2011-12-22 18:31:47277 }
278
279 private:
280 BasicValueConverter<Element> basic_converter_;
281 DISALLOW_COPY_AND_ASSIGN(RepeatedValueConverter);
282};
283
284template <typename NestedType>
285class RepeatedMessageConverter
[email protected]a9b8e0a2012-01-14 05:36:12286 : public ValueConverter<ScopedVector<NestedType> > {
[email protected]193f946b2011-12-22 18:31:47287 public:
288 RepeatedMessageConverter() {}
289
nickc0b001062015-04-22 23:17:20290 bool Convert(const base::Value& value,
291 ScopedVector<NestedType>* field) const override {
[email protected]193f946b2011-12-22 18:31:47292 const base::ListValue* list = NULL;
293 if (!value.GetAsList(&list))
[email protected]261c877e2012-01-05 09:46:42294 return false;
[email protected]193f946b2011-12-22 18:31:47295
296 field->reserve(list->GetSize());
297 for (size_t i = 0; i < list->GetSize(); ++i) {
[email protected]5d30f92bf2012-08-03 08:43:37298 const base::Value* element = NULL;
[email protected]193f946b2011-12-22 18:31:47299 if (!list->Get(i, &element))
300 continue;
301
dcheng093de9b2016-04-04 21:25:51302 std::unique_ptr<NestedType> nested(new NestedType);
[email protected]50fa6f922012-01-26 19:32:36303 if (converter_.Convert(*element, nested.get())) {
304 field->push_back(nested.release());
[email protected]a9b8e0a2012-01-14 05:36:12305 } else {
[email protected]261c877e2012-01-05 09:46:42306 DVLOG(1) << "failure at " << i << "-th element";
307 return false;
308 }
[email protected]193f946b2011-12-22 18:31:47309 }
[email protected]261c877e2012-01-05 09:46:42310 return true;
[email protected]193f946b2011-12-22 18:31:47311 }
312
313 private:
314 JSONValueConverter<NestedType> converter_;
315 DISALLOW_COPY_AND_ASSIGN(RepeatedMessageConverter);
316};
317
[email protected]4e1ec032012-05-03 18:31:54318template <typename NestedType>
319class RepeatedCustomValueConverter
320 : public ValueConverter<ScopedVector<NestedType> > {
321 public:
322 typedef bool(*ConvertFunc)(const base::Value* value, NestedType* field);
323
thestigcf9519fa2016-08-30 05:50:54324 explicit RepeatedCustomValueConverter(ConvertFunc convert_func)
[email protected]4e1ec032012-05-03 18:31:54325 : convert_func_(convert_func) {}
326
nickc0b001062015-04-22 23:17:20327 bool Convert(const base::Value& value,
328 ScopedVector<NestedType>* field) const override {
[email protected]4e1ec032012-05-03 18:31:54329 const base::ListValue* list = NULL;
330 if (!value.GetAsList(&list))
331 return false;
332
333 field->reserve(list->GetSize());
334 for (size_t i = 0; i < list->GetSize(); ++i) {
[email protected]5d30f92bf2012-08-03 08:43:37335 const base::Value* element = NULL;
[email protected]4e1ec032012-05-03 18:31:54336 if (!list->Get(i, &element))
337 continue;
338
dcheng093de9b2016-04-04 21:25:51339 std::unique_ptr<NestedType> nested(new NestedType);
[email protected]4e1ec032012-05-03 18:31:54340 if ((*convert_func_)(element, nested.get())) {
341 field->push_back(nested.release());
342 } else {
343 DVLOG(1) << "failure at " << i << "-th element";
344 return false;
345 }
346 }
347 return true;
348 }
349
350 private:
351 ConvertFunc convert_func_;
352 DISALLOW_COPY_AND_ASSIGN(RepeatedCustomValueConverter);
353};
354
355
[email protected]193f946b2011-12-22 18:31:47356} // namespace internal
357
358template <class StructType>
359class JSONValueConverter {
360 public:
361 JSONValueConverter() {
362 StructType::RegisterJSONConverter(this);
363 }
364
[email protected]193f946b2011-12-22 18:31:47365 void RegisterIntField(const std::string& field_name,
366 int StructType::* field) {
367 fields_.push_back(new internal::FieldConverter<StructType, int>(
368 field_name, field, new internal::BasicValueConverter<int>));
369 }
370
371 void RegisterStringField(const std::string& field_name,
[email protected]261c877e2012-01-05 09:46:42372 std::string StructType::* field) {
[email protected]193f946b2011-12-22 18:31:47373 fields_.push_back(new internal::FieldConverter<StructType, std::string>(
374 field_name, field, new internal::BasicValueConverter<std::string>));
375 }
376
[email protected]261c877e2012-01-05 09:46:42377 void RegisterStringField(const std::string& field_name,
378 string16 StructType::* field) {
379 fields_.push_back(new internal::FieldConverter<StructType, string16>(
380 field_name, field, new internal::BasicValueConverter<string16>));
381 }
382
[email protected]193f946b2011-12-22 18:31:47383 void RegisterBoolField(const std::string& field_name,
384 bool StructType::* field) {
385 fields_.push_back(new internal::FieldConverter<StructType, bool>(
386 field_name, field, new internal::BasicValueConverter<bool>));
387 }
388
389 void RegisterDoubleField(const std::string& field_name,
390 double StructType::* field) {
391 fields_.push_back(new internal::FieldConverter<StructType, double>(
392 field_name, field, new internal::BasicValueConverter<double>));
393 }
394
395 template <class NestedType>
396 void RegisterNestedField(
397 const std::string& field_name, NestedType StructType::* field) {
398 fields_.push_back(new internal::FieldConverter<StructType, NestedType>(
399 field_name,
400 field,
401 new internal::NestedValueConverter<NestedType>));
402 }
403
[email protected]6009ca92012-01-13 02:18:02404 template <typename FieldType>
405 void RegisterCustomField(
406 const std::string& field_name,
407 FieldType StructType::* field,
408 bool (*convert_func)(const StringPiece&, FieldType*)) {
409 fields_.push_back(new internal::FieldConverter<StructType, FieldType>(
410 field_name,
411 field,
412 new internal::CustomFieldConverter<FieldType>(convert_func)));
413 }
414
[email protected]038cf352012-04-13 00:14:15415 template <typename FieldType>
416 void RegisterCustomValueField(
417 const std::string& field_name,
418 FieldType StructType::* field,
419 bool (*convert_func)(const base::Value*, FieldType*)) {
420 fields_.push_back(new internal::FieldConverter<StructType, FieldType>(
421 field_name,
422 field,
423 new internal::ValueFieldConverter<FieldType>(convert_func)));
424 }
425
[email protected]193f946b2011-12-22 18:31:47426 void RegisterRepeatedInt(const std::string& field_name,
[email protected]a9b8e0a2012-01-14 05:36:12427 ScopedVector<int> StructType::* field) {
[email protected]193f946b2011-12-22 18:31:47428 fields_.push_back(
[email protected]a9b8e0a2012-01-14 05:36:12429 new internal::FieldConverter<StructType, ScopedVector<int> >(
[email protected]193f946b2011-12-22 18:31:47430 field_name, field, new internal::RepeatedValueConverter<int>));
431 }
432
433 void RegisterRepeatedString(const std::string& field_name,
[email protected]a9b8e0a2012-01-14 05:36:12434 ScopedVector<std::string> StructType::* field) {
[email protected]193f946b2011-12-22 18:31:47435 fields_.push_back(
[email protected]a9b8e0a2012-01-14 05:36:12436 new internal::FieldConverter<StructType, ScopedVector<std::string> >(
[email protected]193f946b2011-12-22 18:31:47437 field_name,
438 field,
439 new internal::RepeatedValueConverter<std::string>));
440 }
441
[email protected]261c877e2012-01-05 09:46:42442 void RegisterRepeatedString(const std::string& field_name,
[email protected]a9b8e0a2012-01-14 05:36:12443 ScopedVector<string16> StructType::* field) {
[email protected]261c877e2012-01-05 09:46:42444 fields_.push_back(
[email protected]a9b8e0a2012-01-14 05:36:12445 new internal::FieldConverter<StructType, ScopedVector<string16> >(
[email protected]261c877e2012-01-05 09:46:42446 field_name,
447 field,
448 new internal::RepeatedValueConverter<string16>));
449 }
450
[email protected]193f946b2011-12-22 18:31:47451 void RegisterRepeatedDouble(const std::string& field_name,
[email protected]a9b8e0a2012-01-14 05:36:12452 ScopedVector<double> StructType::* field) {
[email protected]193f946b2011-12-22 18:31:47453 fields_.push_back(
[email protected]a9b8e0a2012-01-14 05:36:12454 new internal::FieldConverter<StructType, ScopedVector<double> >(
[email protected]193f946b2011-12-22 18:31:47455 field_name, field, new internal::RepeatedValueConverter<double>));
456 }
457
458 void RegisterRepeatedBool(const std::string& field_name,
[email protected]a9b8e0a2012-01-14 05:36:12459 ScopedVector<bool> StructType::* field) {
[email protected]193f946b2011-12-22 18:31:47460 fields_.push_back(
[email protected]a9b8e0a2012-01-14 05:36:12461 new internal::FieldConverter<StructType, ScopedVector<bool> >(
[email protected]193f946b2011-12-22 18:31:47462 field_name, field, new internal::RepeatedValueConverter<bool>));
463 }
464
465 template <class NestedType>
[email protected]4e1ec032012-05-03 18:31:54466 void RegisterRepeatedCustomValue(
467 const std::string& field_name,
468 ScopedVector<NestedType> StructType::* field,
469 bool (*convert_func)(const base::Value*, NestedType*)) {
470 fields_.push_back(
471 new internal::FieldConverter<StructType, ScopedVector<NestedType> >(
472 field_name,
473 field,
474 new internal::RepeatedCustomValueConverter<NestedType>(
475 convert_func)));
476 }
477
478 template <class NestedType>
[email protected]193f946b2011-12-22 18:31:47479 void RegisterRepeatedMessage(const std::string& field_name,
[email protected]a9b8e0a2012-01-14 05:36:12480 ScopedVector<NestedType> StructType::* field) {
[email protected]193f946b2011-12-22 18:31:47481 fields_.push_back(
[email protected]a9b8e0a2012-01-14 05:36:12482 new internal::FieldConverter<StructType, ScopedVector<NestedType> >(
[email protected]193f946b2011-12-22 18:31:47483 field_name,
484 field,
485 new internal::RepeatedMessageConverter<NestedType>));
486 }
487
[email protected]261c877e2012-01-05 09:46:42488 bool Convert(const base::Value& value, StructType* output) const {
[email protected]193f946b2011-12-22 18:31:47489 const DictionaryValue* dictionary_value = NULL;
490 if (!value.GetAsDictionary(&dictionary_value))
[email protected]261c877e2012-01-05 09:46:42491 return false;
[email protected]193f946b2011-12-22 18:31:47492
thestigcf9519fa2016-08-30 05:50:54493 for (size_t i = 0; i < fields_.size(); ++i) {
[email protected]983b9b72012-01-27 07:12:21494 const internal::FieldConverterBase<StructType>* field_converter =
495 fields_[i];
[email protected]a61890e2012-07-27 22:27:11496 const base::Value* field = NULL;
[email protected]a9b8e0a2012-01-14 05:36:12497 if (dictionary_value->Get(field_converter->field_path(), &field)) {
498 if (!field_converter->ConvertField(*field, output)) {
499 DVLOG(1) << "failure at field " << field_converter->field_path();
[email protected]261c877e2012-01-05 09:46:42500 return false;
501 }
[email protected]193f946b2011-12-22 18:31:47502 }
503 }
[email protected]261c877e2012-01-05 09:46:42504 return true;
[email protected]193f946b2011-12-22 18:31:47505 }
506
507 private:
[email protected]983b9b72012-01-27 07:12:21508 ScopedVector<internal::FieldConverterBase<StructType> > fields_;
[email protected]193f946b2011-12-22 18:31:47509
510 DISALLOW_COPY_AND_ASSIGN(JSONValueConverter);
511};
512
513} // namespace base
514
515#endif // BASE_JSON_JSON_VALUE_CONVERTER_H_