/src/jsoncons/include/jsoncons_ext/bson/bson_encoder.hpp
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright 2013-2025 Daniel Parker |
2 | | // Distributed under the Boost license, Version 1.0. |
3 | | // (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |
4 | | |
5 | | // See https://github.com/danielaparker/jsoncons for latest version |
6 | | |
7 | | #ifndef JSONCONS_EXT_BSON_BSON_ENCODER_HPP |
8 | | #define JSONCONS_EXT_BSON_BSON_ENCODER_HPP |
9 | | |
10 | | #include <cstddef> |
11 | | #include <cstdint> |
12 | | #include <iterator> |
13 | | #include <limits> // std::numeric_limits |
14 | | #include <memory> |
15 | | #include <string> |
16 | | #include <system_error> |
17 | | #include <utility> // std::move |
18 | | #include <vector> |
19 | | |
20 | | #include <jsoncons/config/compiler_support.hpp> |
21 | | #include <jsoncons/config/jsoncons_config.hpp> |
22 | | #include <jsoncons/json_type.hpp> |
23 | | #include <jsoncons/json_visitor.hpp> |
24 | | #include <jsoncons/semantic_tag.hpp> |
25 | | #include <jsoncons/ser_context.hpp> |
26 | | #include <jsoncons/sink.hpp> |
27 | | #include <jsoncons/utility/binary.hpp> |
28 | | #include <jsoncons/utility/byte_string.hpp> |
29 | | #include <jsoncons/utility/unicode_traits.hpp> |
30 | | |
31 | | #include <jsoncons_ext/bson/bson_decimal128.hpp> |
32 | | #include <jsoncons_ext/bson/bson_error.hpp> |
33 | | #include <jsoncons_ext/bson/bson_oid.hpp> |
34 | | #include <jsoncons_ext/bson/bson_options.hpp> |
35 | | #include <jsoncons_ext/bson/bson_type.hpp> |
36 | | |
37 | | namespace jsoncons { |
38 | | namespace bson { |
39 | | |
40 | | template <typename Sink=jsoncons::binary_stream_sink,typename Allocator=std::allocator<char>> |
41 | | class basic_bson_encoder final : public basic_json_visitor<char> |
42 | | { |
43 | | enum class decimal_parse_state { start, integer, exp1, exp2, fraction1 }; |
44 | | static constexpr int64_t nanos_in_milli = 1000000; |
45 | | static constexpr int64_t nanos_in_second = 1000000000; |
46 | | static constexpr int64_t millis_in_second = 1000; |
47 | | public: |
48 | | using allocator_type = Allocator; |
49 | | using char_type = char; |
50 | | using typename basic_json_visitor<char>::string_view_type; |
51 | | using sink_type = Sink; |
52 | | |
53 | | private: |
54 | | struct stack_item |
55 | | { |
56 | | jsoncons::bson::bson_container_type type_; |
57 | | std::size_t offset_{0}; |
58 | | std::size_t name_offset_{0}; |
59 | | std::size_t index_{0}; |
60 | | |
61 | | stack_item(jsoncons::bson::bson_container_type type, std::size_t offset) noexcept |
62 | 94.8k | : type_(type), offset_(offset) |
63 | 94.8k | { |
64 | 94.8k | } |
65 | | |
66 | | std::size_t offset() const |
67 | 5.37k | { |
68 | 5.37k | return offset_; |
69 | 5.37k | } |
70 | | |
71 | | std::size_t member_offset() const |
72 | 114k | { |
73 | 114k | return name_offset_; |
74 | 114k | } |
75 | | |
76 | | void member_offset(std::size_t offset) |
77 | 93.0k | { |
78 | 93.0k | name_offset_ = offset; |
79 | 93.0k | } |
80 | | |
81 | | std::size_t next_index() |
82 | 3.79M | { |
83 | 3.79M | return index_++; |
84 | 3.79M | } |
85 | | |
86 | | bool is_object() const |
87 | 3.91M | { |
88 | 3.91M | return type_ == jsoncons::bson::bson_container_type::document; |
89 | 3.91M | } |
90 | | |
91 | | |
92 | | }; |
93 | | |
94 | | sink_type sink_; |
95 | | const bson_encode_options options_; |
96 | | allocator_type alloc_; |
97 | | |
98 | | std::vector<stack_item> stack_; |
99 | | std::vector<uint8_t> buffer_; |
100 | | int nesting_depth_{0}; |
101 | | public: |
102 | | |
103 | | // Noncopyable and nonmoveable |
104 | | basic_bson_encoder(const basic_bson_encoder&) = delete; |
105 | | basic_bson_encoder(basic_bson_encoder&&) = delete; |
106 | | |
107 | | explicit basic_bson_encoder(Sink&& sink, |
108 | | const Allocator& alloc = Allocator()) |
109 | 3.01k | : basic_bson_encoder(std::forward<Sink>(sink), |
110 | 3.01k | bson_encode_options(), |
111 | 3.01k | alloc) |
112 | 3.01k | { |
113 | 3.01k | } |
114 | | |
115 | | explicit basic_bson_encoder(Sink&& sink, |
116 | | const bson_encode_options& options, |
117 | | const Allocator& alloc = Allocator()) |
118 | 3.01k | : sink_(std::forward<Sink>(sink)), |
119 | 3.01k | options_(options), |
120 | 3.01k | alloc_(alloc) |
121 | 3.01k | { |
122 | 3.01k | } |
123 | | |
124 | | ~basic_bson_encoder() noexcept |
125 | 3.01k | { |
126 | 3.01k | sink_.flush(); |
127 | 3.01k | } |
128 | | |
129 | | basic_bson_encoder& operator=(const basic_bson_encoder&) = delete; |
130 | | basic_bson_encoder& operator=(basic_bson_encoder&&) = delete; |
131 | | |
132 | | void reset() |
133 | | { |
134 | | stack_.clear(); |
135 | | buffer_.clear(); |
136 | | nesting_depth_ = 0; |
137 | | } |
138 | | |
139 | | void reset(Sink&& sink) |
140 | | { |
141 | | sink_ = std::move(sink); |
142 | | reset(); |
143 | | } |
144 | | |
145 | | private: |
146 | | // Implementing methods |
147 | | |
148 | | void visit_flush() override |
149 | 6 | { |
150 | 6 | sink_.flush(); |
151 | 6 | } |
152 | | |
153 | | JSONCONS_VISITOR_RETURN_TYPE visit_begin_object(semantic_tag, const ser_context&, std::error_code& ec) override |
154 | 54.3k | { |
155 | 54.3k | if (JSONCONS_UNLIKELY(++nesting_depth_ > options_.max_nesting_depth())) |
156 | 3.97k | { |
157 | 3.97k | ec = bson_errc::max_nesting_depth_exceeded; |
158 | 3.97k | JSONCONS_VISITOR_RETURN; |
159 | 3.97k | } |
160 | 50.3k | if (buffer_.size() > 0) |
161 | 47.3k | { |
162 | 47.3k | if (stack_.empty()) |
163 | 0 | { |
164 | 0 | ec = bson_errc::expected_bson_document; |
165 | 0 | JSONCONS_VISITOR_RETURN; |
166 | 0 | } |
167 | 47.3k | before_value(jsoncons::bson::bson_type::document_type); |
168 | 47.3k | } |
169 | | |
170 | 50.3k | stack_.emplace_back(jsoncons::bson::bson_container_type::document, buffer_.size()); |
171 | 50.3k | buffer_.insert(buffer_.end(), sizeof(int32_t), 0); |
172 | | |
173 | 50.3k | JSONCONS_VISITOR_RETURN; |
174 | 50.3k | } |
175 | | |
176 | | JSONCONS_VISITOR_RETURN_TYPE visit_end_object(const ser_context&, std::error_code&) override |
177 | 842 | { |
178 | 842 | JSONCONS_ASSERT(!stack_.empty()); |
179 | 842 | --nesting_depth_; |
180 | | |
181 | 842 | buffer_.push_back(0x00); |
182 | | |
183 | 842 | std::size_t length = buffer_.size() - stack_.back().offset(); |
184 | 842 | binary::native_to_little(static_cast<uint32_t>(length), buffer_.begin()+stack_.back().offset()); |
185 | | |
186 | 842 | stack_.pop_back(); |
187 | 842 | if (stack_.empty()) |
188 | 139 | { |
189 | 139 | for (auto c : buffer_) |
190 | 2.14M | { |
191 | 2.14M | sink_.push_back(c); |
192 | 2.14M | } |
193 | 139 | } |
194 | 842 | JSONCONS_VISITOR_RETURN; |
195 | 842 | } |
196 | | |
197 | | JSONCONS_VISITOR_RETURN_TYPE visit_begin_array(semantic_tag, const ser_context&, std::error_code& ec) override |
198 | 1.00M | { |
199 | 1.00M | if (JSONCONS_UNLIKELY(++nesting_depth_ > options_.max_nesting_depth())) |
200 | 963k | { |
201 | 963k | ec = bson_errc::max_nesting_depth_exceeded; |
202 | 963k | JSONCONS_VISITOR_RETURN; |
203 | 963k | } |
204 | 44.4k | if (buffer_.size() > 0) |
205 | 44.4k | { |
206 | 44.4k | if (stack_.empty()) |
207 | 0 | { |
208 | 0 | ec = bson_errc::expected_bson_document; |
209 | 0 | JSONCONS_VISITOR_RETURN; |
210 | 0 | } |
211 | 44.4k | before_value(jsoncons::bson::bson_type::array_type); |
212 | 44.4k | } |
213 | 44.4k | stack_.emplace_back(jsoncons::bson::bson_container_type::array, buffer_.size()); |
214 | 44.4k | buffer_.insert(buffer_.end(), sizeof(int32_t), 0); |
215 | 44.4k | JSONCONS_VISITOR_RETURN; |
216 | 44.4k | } |
217 | | |
218 | | JSONCONS_VISITOR_RETURN_TYPE visit_end_array(const ser_context&, std::error_code&) override |
219 | 1.84k | { |
220 | 1.84k | JSONCONS_ASSERT(!stack_.empty()); |
221 | 1.84k | --nesting_depth_; |
222 | | |
223 | 1.84k | buffer_.push_back(0x00); |
224 | | |
225 | 1.84k | std::size_t length = buffer_.size() - stack_.back().offset(); |
226 | 1.84k | binary::native_to_little(static_cast<uint32_t>(length), buffer_.begin()+stack_.back().offset()); |
227 | | |
228 | 1.84k | stack_.pop_back(); |
229 | 1.84k | if (stack_.empty()) |
230 | 0 | { |
231 | 0 | for (auto c : buffer_) |
232 | 0 | { |
233 | 0 | sink_.push_back(c); |
234 | 0 | } |
235 | 0 | } |
236 | 1.84k | JSONCONS_VISITOR_RETURN; |
237 | 1.84k | } |
238 | | |
239 | | JSONCONS_VISITOR_RETURN_TYPE visit_key(const string_view_type& name, const ser_context&, std::error_code&) override |
240 | 93.0k | { |
241 | 93.0k | stack_.back().member_offset(buffer_.size()); |
242 | 93.0k | buffer_.push_back(0x00); // reserve space for code |
243 | 93.0k | for (auto c : name) |
244 | 904k | { |
245 | 904k | buffer_.push_back(c); |
246 | 904k | } |
247 | 93.0k | buffer_.push_back(0x00); |
248 | 93.0k | JSONCONS_VISITOR_RETURN; |
249 | 93.0k | } |
250 | | |
251 | | JSONCONS_VISITOR_RETURN_TYPE visit_null(semantic_tag tag, const ser_context&, std::error_code& ec) override |
252 | 3.77M | { |
253 | 3.77M | if (stack_.empty()) |
254 | 0 | { |
255 | 0 | ec = bson_errc::expected_bson_document; |
256 | 0 | JSONCONS_VISITOR_RETURN; |
257 | 0 | } |
258 | 3.77M | switch (tag) |
259 | 3.77M | { |
260 | 1.39k | case semantic_tag::undefined: |
261 | 1.39k | before_value(jsoncons::bson::bson_type::undefined_type); |
262 | 1.39k | break; |
263 | 3.77M | default: |
264 | 3.77M | before_value(jsoncons::bson::bson_type::null_type); |
265 | 3.77M | break; |
266 | 3.77M | } |
267 | 3.77M | JSONCONS_VISITOR_RETURN; |
268 | 3.77M | } |
269 | | |
270 | | JSONCONS_VISITOR_RETURN_TYPE visit_bool(bool val, semantic_tag, const ser_context&, std::error_code& ec) override |
271 | 3.40k | { |
272 | 3.40k | if (stack_.empty()) |
273 | 0 | { |
274 | 0 | ec = bson_errc::expected_bson_document; |
275 | 0 | JSONCONS_VISITOR_RETURN; |
276 | 0 | } |
277 | 3.40k | before_value(jsoncons::bson::bson_type::bool_type); |
278 | 3.40k | if (val) |
279 | 2.16k | { |
280 | 2.16k | buffer_.push_back(0x01); |
281 | 2.16k | } |
282 | 1.23k | else |
283 | 1.23k | { |
284 | 1.23k | buffer_.push_back(0x00); |
285 | 1.23k | } |
286 | | |
287 | 3.40k | JSONCONS_VISITOR_RETURN; |
288 | 3.40k | } |
289 | | |
290 | | JSONCONS_VISITOR_RETURN_TYPE visit_string(const string_view_type& sv, semantic_tag tag, const ser_context&, std::error_code& ec) override |
291 | 28.0k | { |
292 | 28.0k | if (stack_.empty()) |
293 | 0 | { |
294 | 0 | ec = bson_errc::expected_bson_document; |
295 | 0 | JSONCONS_VISITOR_RETURN; |
296 | 0 | } |
297 | | |
298 | 28.0k | switch (tag) |
299 | 28.0k | { |
300 | 14.8k | case semantic_tag::float128: |
301 | 14.8k | { |
302 | 14.8k | before_value(jsoncons::bson::bson_type::decimal128_type); |
303 | 14.8k | decimal128_t dec; |
304 | 14.8k | auto rc = decimal128_from_chars(sv.data(), sv.data()+sv.size(), dec); |
305 | 14.8k | if (rc.ec != std::errc()) |
306 | 869 | { |
307 | 869 | ec = bson_errc::invalid_decimal128_string; |
308 | 869 | JSONCONS_VISITOR_RETURN; |
309 | 869 | } |
310 | 13.9k | binary::native_to_little(dec.low,std::back_inserter(buffer_)); |
311 | 13.9k | binary::native_to_little(dec.high,std::back_inserter(buffer_)); |
312 | 13.9k | break; |
313 | 14.8k | } |
314 | 7.61k | case semantic_tag::id: |
315 | 7.61k | { |
316 | 7.61k | before_value(jsoncons::bson::bson_type::object_id_type); |
317 | 7.61k | oid_t oid(sv); |
318 | 7.61k | for (auto b : oid) |
319 | 91.3k | { |
320 | 91.3k | buffer_.push_back(b); |
321 | 91.3k | } |
322 | 7.61k | break; |
323 | 14.8k | } |
324 | 2.22k | case semantic_tag::regex: |
325 | 2.22k | { |
326 | 2.22k | before_value(jsoncons::bson::bson_type::regex_type); |
327 | 2.22k | std::size_t first = sv.find_first_of('/'); |
328 | 2.22k | std::size_t last = sv.find_last_of('/'); |
329 | 2.22k | if (first == string_view::npos || last == string_view::npos || first == last) |
330 | 0 | { |
331 | 0 | ec = bson_errc::invalid_regex_string; |
332 | 0 | JSONCONS_VISITOR_RETURN; |
333 | 0 | } |
334 | 2.22k | string_view regex = sv.substr(first+1,last-1); |
335 | 2.22k | for (auto c : regex) |
336 | 4.36M | { |
337 | 4.36M | buffer_.push_back(c); |
338 | 4.36M | } |
339 | 2.22k | buffer_.push_back(0x00); |
340 | 2.22k | string_view options = sv.substr(last+1); |
341 | 2.22k | for (auto c : options) |
342 | 1.89M | { |
343 | 1.89M | buffer_.push_back(c); |
344 | 1.89M | } |
345 | 2.22k | buffer_.push_back(0x00); |
346 | 2.22k | break; |
347 | 2.22k | } |
348 | 3.34k | default: |
349 | 3.34k | switch (tag) |
350 | 3.34k | { |
351 | 855 | case semantic_tag::code: |
352 | 855 | before_value(jsoncons::bson::bson_type::javascript_type); |
353 | 855 | break; |
354 | 2.48k | default: |
355 | 2.48k | before_value(jsoncons::bson::bson_type::string_type); |
356 | 2.48k | break; |
357 | 3.34k | } |
358 | 3.34k | std::size_t offset = buffer_.size(); |
359 | 3.34k | buffer_.insert(buffer_.end(), sizeof(int32_t), 0); |
360 | 3.34k | std::size_t string_offset = buffer_.size(); |
361 | 3.34k | auto sink = unicode_traits::validate(sv.data(), sv.size()); |
362 | 3.34k | if (sink.ec != unicode_traits::conv_errc()) |
363 | 0 | { |
364 | 0 | ec = bson_errc::invalid_utf8_text_string; |
365 | 0 | JSONCONS_VISITOR_RETURN; |
366 | 0 | } |
367 | 3.34k | for (auto c : sv) |
368 | 3.06M | { |
369 | 3.06M | buffer_.push_back(c); |
370 | 3.06M | } |
371 | 3.34k | buffer_.push_back(0x00); |
372 | 3.34k | std::size_t length = buffer_.size() - string_offset; |
373 | 3.34k | binary::native_to_little(static_cast<uint32_t>(length), buffer_.begin()+offset); |
374 | 3.34k | break; |
375 | 28.0k | } |
376 | | |
377 | 28.0k | JSONCONS_VISITOR_RETURN; |
378 | 28.0k | } |
379 | | |
380 | | JSONCONS_VISITOR_RETURN_TYPE visit_byte_string(const byte_string_view& b, |
381 | | semantic_tag, |
382 | | const ser_context&, |
383 | | std::error_code& ec) override |
384 | 0 | { |
385 | 0 | if (stack_.empty()) |
386 | 0 | { |
387 | 0 | ec = bson_errc::expected_bson_document; |
388 | 0 | JSONCONS_VISITOR_RETURN; |
389 | 0 | } |
390 | 0 | before_value(jsoncons::bson::bson_type::binary_type); |
391 | |
|
392 | 0 | std::size_t offset = buffer_.size(); |
393 | 0 | buffer_.insert(buffer_.end(), sizeof(int32_t), 0); |
394 | 0 | std::size_t string_offset = buffer_.size(); |
395 | |
|
396 | 0 | buffer_.push_back(0x80); // default subtype |
397 | |
|
398 | 0 | for (auto c : b) |
399 | 0 | { |
400 | 0 | buffer_.push_back(c); |
401 | 0 | } |
402 | 0 | std::size_t length = buffer_.size() - string_offset - 1; |
403 | 0 | binary::native_to_little(static_cast<uint32_t>(length), buffer_.begin()+offset); |
404 | |
|
405 | 0 | JSONCONS_VISITOR_RETURN; |
406 | 0 | } |
407 | | |
408 | | JSONCONS_VISITOR_RETURN_TYPE visit_byte_string(const byte_string_view& b, |
409 | | uint64_t ext_tag, |
410 | | const ser_context&, |
411 | | std::error_code& ec) override |
412 | 2.95k | { |
413 | 2.95k | if (stack_.empty()) |
414 | 0 | { |
415 | 0 | ec = bson_errc::expected_bson_document; |
416 | 0 | JSONCONS_VISITOR_RETURN; |
417 | 0 | } |
418 | 2.95k | before_value(jsoncons::bson::bson_type::binary_type); |
419 | | |
420 | 2.95k | std::size_t offset = buffer_.size(); |
421 | 2.95k | buffer_.insert(buffer_.end(), sizeof(int32_t), 0); |
422 | 2.95k | std::size_t string_offset = buffer_.size(); |
423 | | |
424 | 2.95k | buffer_.push_back(static_cast<uint8_t>(ext_tag)); // default subtype |
425 | | |
426 | 2.95k | for (auto c : b) |
427 | 4.83M | { |
428 | 4.83M | buffer_.push_back(c); |
429 | 4.83M | } |
430 | 2.95k | std::size_t length = buffer_.size() - string_offset - 1; |
431 | 2.95k | binary::native_to_little(static_cast<uint32_t>(length), buffer_.begin()+offset); |
432 | | |
433 | 2.95k | JSONCONS_VISITOR_RETURN; |
434 | 2.95k | } |
435 | | |
436 | | JSONCONS_VISITOR_RETURN_TYPE visit_int64(int64_t val, |
437 | | semantic_tag tag, |
438 | | const ser_context&, |
439 | | std::error_code& ec) override |
440 | 7.08k | { |
441 | 7.08k | static constexpr int64_t min_value_div_1000 = (std::numeric_limits<int64_t>::min)() / 1000; |
442 | 7.08k | static constexpr int64_t max_value_div_1000 = (std::numeric_limits<int64_t>::max)() / 1000; |
443 | 7.08k | if (stack_.empty()) |
444 | 0 | { |
445 | 0 | ec = bson_errc::expected_bson_document; |
446 | 0 | JSONCONS_VISITOR_RETURN; |
447 | 0 | } |
448 | | |
449 | 7.08k | switch (tag) |
450 | 7.08k | { |
451 | 0 | case semantic_tag::epoch_second: |
452 | 0 | if (val < min_value_div_1000) |
453 | 0 | { |
454 | 0 | ec = bson_errc::datetime_too_small; |
455 | 0 | JSONCONS_VISITOR_RETURN; |
456 | 0 | } |
457 | 0 | if (val > max_value_div_1000) |
458 | 0 | { |
459 | 0 | ec = bson_errc::datetime_too_large; |
460 | 0 | JSONCONS_VISITOR_RETURN; |
461 | 0 | } |
462 | 0 | before_value(jsoncons::bson::bson_type::datetime_type); |
463 | 0 | binary::native_to_little(val*millis_in_second,std::back_inserter(buffer_)); |
464 | 0 | break; |
465 | 986 | case semantic_tag::epoch_milli: |
466 | 986 | before_value(jsoncons::bson::bson_type::datetime_type); |
467 | 986 | binary::native_to_little(val,std::back_inserter(buffer_)); |
468 | 986 | break; |
469 | 0 | case semantic_tag::epoch_nano: |
470 | 0 | before_value(jsoncons::bson::bson_type::datetime_type); |
471 | 0 | if (val != 0) |
472 | 0 | { |
473 | 0 | val /= nanos_in_milli; |
474 | 0 | } |
475 | 0 | binary::native_to_little(static_cast<int64_t>(val),std::back_inserter(buffer_)); |
476 | 0 | break; |
477 | 6.09k | default: |
478 | 6.09k | { |
479 | 6.09k | if (val >= (std::numeric_limits<int32_t>::lowest)() && val <= (std::numeric_limits<int32_t>::max)()) |
480 | 3.53k | { |
481 | 3.53k | before_value(jsoncons::bson::bson_type::int32_type); |
482 | 3.53k | binary::native_to_little(static_cast<uint32_t>(val),std::back_inserter(buffer_)); |
483 | 3.53k | } |
484 | 2.56k | else |
485 | 2.56k | { |
486 | 2.56k | before_value(jsoncons::bson::bson_type::int64_type); |
487 | 2.56k | binary::native_to_little(static_cast<int64_t>(val),std::back_inserter(buffer_)); |
488 | 2.56k | } |
489 | 6.09k | break; |
490 | 0 | } |
491 | 7.08k | } |
492 | 7.08k | JSONCONS_VISITOR_RETURN; |
493 | 7.08k | } |
494 | | |
495 | | JSONCONS_VISITOR_RETURN_TYPE visit_uint64(uint64_t val, |
496 | | semantic_tag tag, |
497 | | const ser_context&, |
498 | | std::error_code& ec) override |
499 | 2.15k | { |
500 | 2.15k | static constexpr uint64_t max_value_div_1000 = (std::numeric_limits<uint64_t>::max)() / 1000; |
501 | 2.15k | if (stack_.empty()) |
502 | 0 | { |
503 | 0 | ec = bson_errc::expected_bson_document; |
504 | 0 | JSONCONS_VISITOR_RETURN; |
505 | 0 | } |
506 | | |
507 | 2.15k | switch (tag) |
508 | 2.15k | { |
509 | 0 | case semantic_tag::epoch_second: |
510 | 0 | if (val > max_value_div_1000) |
511 | 0 | { |
512 | 0 | ec = bson_errc::datetime_too_large; |
513 | 0 | JSONCONS_VISITOR_RETURN; |
514 | 0 | } |
515 | 0 | before_value(jsoncons::bson::bson_type::datetime_type); |
516 | 0 | binary::native_to_little(static_cast<int64_t>(val*millis_in_second),std::back_inserter(buffer_)); |
517 | 0 | break; |
518 | 0 | case semantic_tag::epoch_milli: |
519 | 0 | before_value(jsoncons::bson::bson_type::datetime_type); |
520 | 0 | binary::native_to_little(static_cast<int64_t>(val),std::back_inserter(buffer_)); |
521 | 0 | break; |
522 | 0 | case semantic_tag::epoch_nano: |
523 | 0 | before_value(jsoncons::bson::bson_type::datetime_type); |
524 | 0 | if (val != 0) |
525 | 0 | { |
526 | 0 | val /= nanos_in_second; |
527 | 0 | } |
528 | 0 | binary::native_to_little(static_cast<int64_t>(val),std::back_inserter(buffer_)); |
529 | 0 | break; |
530 | 2.15k | default: |
531 | 2.15k | { |
532 | 2.15k | if (val <= static_cast<uint64_t>((std::numeric_limits<int32_t>::max)())) |
533 | 870 | { |
534 | 870 | before_value(jsoncons::bson::bson_type::int32_type); |
535 | 870 | binary::native_to_little(static_cast<uint32_t>(val),std::back_inserter(buffer_)); |
536 | 870 | } |
537 | 1.28k | else if (val <= static_cast<uint64_t>((std::numeric_limits<int64_t>::max)())) |
538 | 911 | { |
539 | 911 | before_value(jsoncons::bson::bson_type::int64_type); |
540 | 911 | binary::native_to_little(static_cast<uint64_t>(val),std::back_inserter(buffer_)); |
541 | 911 | } |
542 | 373 | else |
543 | 373 | { |
544 | 373 | ec = bson_errc::number_too_large; |
545 | 373 | JSONCONS_VISITOR_RETURN; |
546 | 373 | } |
547 | 1.78k | break; |
548 | 2.15k | } |
549 | 2.15k | } |
550 | 2.15k | JSONCONS_VISITOR_RETURN; |
551 | 2.15k | } |
552 | | |
553 | | JSONCONS_VISITOR_RETURN_TYPE visit_double(double val, |
554 | | semantic_tag, |
555 | | const ser_context&, |
556 | | std::error_code& ec) override |
557 | 1.05k | { |
558 | 1.05k | if (stack_.empty()) |
559 | 0 | { |
560 | 0 | ec = bson_errc::expected_bson_document; |
561 | 0 | JSONCONS_VISITOR_RETURN; |
562 | 0 | } |
563 | 1.05k | before_value(jsoncons::bson::bson_type::double_type); |
564 | 1.05k | binary::native_to_little(val,std::back_inserter(buffer_)); |
565 | 1.05k | JSONCONS_VISITOR_RETURN; |
566 | 1.05k | } |
567 | | |
568 | | void before_value(uint8_t code) |
569 | 3.91M | { |
570 | 3.91M | JSONCONS_ASSERT(!stack_.empty()); |
571 | 3.91M | if (stack_.back().is_object()) |
572 | 114k | { |
573 | 114k | buffer_[stack_.back().member_offset()] = code; |
574 | 114k | } |
575 | 3.79M | else |
576 | 3.79M | { |
577 | 3.79M | buffer_.push_back(code); |
578 | 3.79M | std::string name = std::to_string(stack_.back().next_index()); |
579 | 3.79M | buffer_.insert(buffer_.end(), name.begin(), name.end()); |
580 | 3.79M | buffer_.push_back(0x00); |
581 | 3.79M | } |
582 | 3.91M | } |
583 | | }; |
584 | | |
585 | | using bson_stream_encoder = basic_bson_encoder<jsoncons::binary_stream_sink>; |
586 | | using bson_bytes_encoder = basic_bson_encoder<jsoncons::bytes_sink<std::vector<uint8_t>>>; |
587 | | |
588 | | } // namespace bson |
589 | | } // namespace jsoncons |
590 | | |
591 | | #endif // JSONCONS_EXT_BSON_BSON_ENCODER_HPP |