• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2012 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "base/json/json_reader.h"
6 
7 #include <utility>
8 
9 #include "base/logging.h"
10 #include "base/rust_buildflags.h"
11 #include "third_party/abseil-cpp/absl/types/optional.h"
12 
13 #if BUILDFLAG(BUILD_RUST_JSON_READER)
14 #include "base/strings/string_piece_rust.h"
15 #include "third_party/rust/serde_json_lenient/v0_1/wrapper/functions.h"
16 #include "third_party/rust/serde_json_lenient/v0_1/wrapper/lib.rs.h"
17 #else
18 #include "base/json/json_parser.h"
19 #endif
20 
21 namespace base {
22 
23 #if BUILDFLAG(BUILD_RUST_JSON_READER)
24 
25 namespace {
26 using serde_json_lenient::ContextPointer;
27 
ListAppendList(ContextPointer & ctx,size_t reserve)28 ContextPointer& ListAppendList(ContextPointer& ctx, size_t reserve) {
29   auto& value = reinterpret_cast<base::Value&>(ctx);
30   value.GetList().reserve(reserve);
31   value.GetList().Append(base::Value::List());
32   return reinterpret_cast<ContextPointer&>(value.GetList().back());
33 }
34 
ListAppendDict(ContextPointer & ctx)35 ContextPointer& ListAppendDict(ContextPointer& ctx) {
36   auto& value = reinterpret_cast<base::Value&>(ctx);
37   value.GetList().Append(base::Value::Dict());
38   return reinterpret_cast<ContextPointer&>(value.GetList().back());
39 }
40 
ListAppendNone(ContextPointer & ctx)41 void ListAppendNone(ContextPointer& ctx) {
42   auto& value = reinterpret_cast<base::Value&>(ctx);
43   value.GetList().Append(base::Value());
44 }
45 
46 template <class T, class As = T>
ListAppendValue(ContextPointer & ctx,T v)47 void ListAppendValue(ContextPointer& ctx, T v) {
48   auto& value = reinterpret_cast<base::Value&>(ctx);
49   value.GetList().Append(As{v});
50 }
51 
DictSetList(ContextPointer & ctx,rust::Str key,size_t reserve)52 ContextPointer& DictSetList(ContextPointer& ctx,
53                             rust::Str key,
54                             size_t reserve) {
55   auto& value = reinterpret_cast<base::Value&>(ctx);
56   base::Value::List list;
57   list.reserve(reserve);
58   value.SetKey(base::RustStrToStringPiece(key), base::Value(std::move(list)));
59   return reinterpret_cast<ContextPointer&>(
60       *value.GetDict().Find(base::RustStrToStringPiece(key)));
61 }
62 
DictSetDict(ContextPointer & ctx,rust::Str key)63 ContextPointer& DictSetDict(ContextPointer& ctx, rust::Str key) {
64   auto& value = reinterpret_cast<base::Value&>(ctx);
65   value.SetKey(base::RustStrToStringPiece(key),
66                base::Value(base::Value::Dict()));
67   return reinterpret_cast<ContextPointer&>(
68       *value.GetDict().Find(base::RustStrToStringPiece(key)));
69 }
70 
DictSetNone(ContextPointer & ctx,rust::Str key)71 void DictSetNone(ContextPointer& ctx, rust::Str key) {
72   auto& value = reinterpret_cast<base::Value&>(ctx);
73   value.SetKey(base::RustStrToStringPiece(key), base::Value());
74 }
75 
76 template <class T, class As = T>
DictSetValue(ContextPointer & ctx,rust::Str key,T v)77 void DictSetValue(ContextPointer& ctx, rust::Str key, T v) {
78   auto& value = reinterpret_cast<base::Value&>(ctx);
79   value.SetKey(base::RustStrToStringPiece(key), base::Value(As{v}));
80 }
81 
DecodeJSONInRust(const base::StringPiece & json,int options,size_t max_depth)82 JSONReader::Result DecodeJSONInRust(const base::StringPiece& json,
83                                     int options,
84                                     size_t max_depth) {
85   const serde_json_lenient::JsonOptions rust_options = {
86       .allow_trailing_commas =
87           (options & base::JSON_ALLOW_TRAILING_COMMAS) != 0,
88       .replace_invalid_characters =
89           (options & base::JSON_REPLACE_INVALID_CHARACTERS) != 0,
90       .allow_comments = (options & base::JSON_ALLOW_COMMENTS) != 0,
91       .allow_control_chars = (options & base::JSON_ALLOW_CONTROL_CHARS) != 0,
92       .allow_vert_tab = (options & base::JSON_ALLOW_VERT_TAB) != 0,
93       .allow_x_escapes = (options & base::JSON_ALLOW_X_ESCAPES) != 0,
94       .max_depth = max_depth,
95   };
96   const serde_json_lenient::Functions functions = {
97       .list_append_none_fn = ListAppendNone,
98       .list_append_bool_fn = ListAppendValue<bool>,
99       .list_append_i32_fn = ListAppendValue<int32_t>,
100       .list_append_f64_fn = ListAppendValue<double>,
101       .list_append_str_fn = ListAppendValue<rust::Str, std::string>,
102       .list_append_list_fn = ListAppendList,
103       .list_append_dict_fn = ListAppendDict,
104       .dict_set_none_fn = DictSetNone,
105       .dict_set_bool_fn = DictSetValue<bool>,
106       .dict_set_i32_fn = DictSetValue<int32_t>,
107       .dict_set_f64_fn = DictSetValue<double>,
108       .dict_set_str_fn = DictSetValue<rust::Str, std::string>,
109       .dict_set_list_fn = DictSetList,
110       .dict_set_dict_fn = DictSetDict,
111   };
112 
113   base::Value value(base::Value::Type::LIST);
114   auto& ctx = reinterpret_cast<ContextPointer&>(value);
115   serde_json_lenient::DecodeError error;
116   bool ok = serde_json_lenient::decode_json(
117       base::StringPieceToRustSlice(json), rust_options, functions, ctx, error);
118 
119   if (!ok) {
120     return base::unexpected(base::JSONReader::Error{
121         .message = std::string(error.message),
122         .line = error.line,
123         .column = error.column,
124     });
125   }
126 
127   return std::move(std::move(value.GetList()).back());
128 }
129 
130 }  // anonymous namespace
131 
132 #endif  // BUILDFLAG(BUILD_RUST_JSON_READER)
133 
134 // static
Read(StringPiece json,int options,size_t max_depth)135 absl::optional<Value> JSONReader::Read(StringPiece json,
136                                        int options,
137                                        size_t max_depth) {
138 #if BUILDFLAG(BUILD_RUST_JSON_READER)
139   JSONReader::Result result = DecodeJSONInRust(json, options, max_depth);
140   if (!result.has_value()) {
141     return absl::nullopt;
142   }
143   return std::move(*result);
144 #else   // BUILDFLAG(BUILD_RUST_JSON_READER)
145   internal::JSONParser parser(options, max_depth);
146   return parser.Parse(json);
147 #endif  // BUILDFLAG(BUILD_RUST_JSON_READER)
148 }
149 
150 // static
ReadAndReturnValueWithError(StringPiece json,int options)151 JSONReader::Result JSONReader::ReadAndReturnValueWithError(StringPiece json,
152                                                            int options) {
153 #if BUILDFLAG(BUILD_RUST_JSON_READER)
154   return DecodeJSONInRust(json, options, internal::kAbsoluteMaxDepth);
155 #else   // BUILDFLAG(BUILD_RUST_JSON_READER)
156   internal::JSONParser parser(options);
157   auto value = parser.Parse(json);
158   if (!value) {
159     Error error;
160     error.message = parser.GetErrorMessage();
161     error.line = parser.error_line();
162     error.column = parser.error_column();
163     return base::unexpected(std::move(error));
164   }
165 
166   return std::move(*value);
167 #endif  // BUILDFLAG(BUILD_RUST_JSON_READER)
168 }
169 
170 }  // namespace base
171