/src/jsoncons/include/jsoncons_ext/bson/decode_bson.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_DECODE_BSON_HPP |
8 | | #define JSONCONS_EXT_BSON_DECODE_BSON_HPP |
9 | | |
10 | | #include <istream> // std::basic_istream |
11 | | #include <type_traits> // std::enable_if |
12 | | |
13 | | #include <jsoncons/allocator_set.hpp> |
14 | | #include <jsoncons/basic_json.hpp> |
15 | | #include <jsoncons/config/compiler_support.hpp> |
16 | | #include <jsoncons/conv_error.hpp> |
17 | | #include <jsoncons/json_decoder.hpp> |
18 | | #include <jsoncons/json_visitor.hpp> |
19 | | #include <jsoncons/reflect/decode_traits.hpp> |
20 | | #include <jsoncons/ser_util.hpp> |
21 | | #include <jsoncons/source.hpp> |
22 | | #include <jsoncons/utility/more_type_traits.hpp> |
23 | | |
24 | | #include <jsoncons_ext/bson/bson_cursor.hpp> |
25 | | #include <jsoncons_ext/bson/bson_options.hpp> |
26 | | #include <jsoncons_ext/bson/bson_reader.hpp> |
27 | | |
28 | | namespace jsoncons { |
29 | | namespace bson { |
30 | | |
31 | | template <typename T,typename BytesLike> |
32 | | typename std::enable_if<ext_traits::is_basic_json<T>::value && |
33 | | ext_traits::is_byte_sequence<BytesLike>::value,read_result<T>>::type |
34 | | try_decode_bson(const BytesLike& v, |
35 | | const bson_decode_options& options = bson_decode_options()) |
36 | | { |
37 | | using value_type = T; |
38 | | using result_type = read_result<value_type>; |
39 | | |
40 | | std::error_code ec; |
41 | | jsoncons::json_decoder<T> decoder; |
42 | | auto adaptor = make_json_visitor_adaptor<json_visitor>(decoder); |
43 | | basic_bson_reader<jsoncons::bytes_source> reader(v, adaptor, options); |
44 | | reader.read(ec); |
45 | | if (JSONCONS_UNLIKELY(ec)) |
46 | | { |
47 | | return result_type{jsoncons::unexpect, ec, reader.line(), reader.column()}; |
48 | | } |
49 | | if (JSONCONS_UNLIKELY(!decoder.is_valid())) |
50 | | { |
51 | | return result_type{jsoncons::unexpect, conv_errc::conversion_failed, reader.line(), reader.column()}; |
52 | | } |
53 | | return result_type{decoder.get_result()}; |
54 | | } |
55 | | |
56 | | template <typename T,typename BytesLike> |
57 | | typename std::enable_if<!ext_traits::is_basic_json<T>::value && |
58 | | ext_traits::is_byte_sequence<BytesLike>::value,read_result<T>>::type |
59 | | try_decode_bson(const BytesLike& v, |
60 | | const bson_decode_options& options = bson_decode_options()) |
61 | | { |
62 | | using value_type = T; |
63 | | using result_type = read_result<value_type>; |
64 | | |
65 | | std::error_code ec; |
66 | | basic_bson_cursor<bytes_source> cursor(v, options, ec); |
67 | | if (JSONCONS_UNLIKELY(ec)) |
68 | | { |
69 | | return result_type{jsoncons::unexpect, ec, cursor.line(), cursor.column()}; |
70 | | } |
71 | | |
72 | | return reflect::decode_traits<T>::try_decode(make_alloc_set(), cursor); |
73 | | } |
74 | | |
75 | | template <typename T> |
76 | | typename std::enable_if<ext_traits::is_basic_json<T>::value,read_result<T>>::type |
77 | | try_decode_bson(std::istream& is, |
78 | | const bson_decode_options& options = bson_decode_options()) |
79 | 4.25k | { |
80 | 4.25k | using value_type = T; |
81 | 4.25k | using result_type = read_result<value_type>; |
82 | | |
83 | 4.25k | std::error_code ec; |
84 | 4.25k | jsoncons::json_decoder<T> decoder; |
85 | 4.25k | auto adaptor = make_json_visitor_adaptor<json_visitor>(decoder); |
86 | 4.25k | bson_stream_reader reader(is, adaptor, options); |
87 | 4.25k | reader.read(ec); |
88 | 4.25k | if (JSONCONS_UNLIKELY(ec)) |
89 | 4.23k | { |
90 | 4.23k | return result_type{jsoncons::unexpect, ec, reader.line(), reader.column()}; |
91 | 4.23k | } |
92 | 13 | if (JSONCONS_UNLIKELY(!decoder.is_valid())) |
93 | 0 | { |
94 | 0 | return result_type{jsoncons::unexpect, conv_errc::conversion_failed, reader.line(), reader.column()}; |
95 | 0 | } |
96 | 13 | return result_type{decoder.get_result()}; |
97 | 13 | } |
98 | | |
99 | | template <typename T> |
100 | | typename std::enable_if<!ext_traits::is_basic_json<T>::value,read_result<T>>::type |
101 | | try_decode_bson(std::istream& is, |
102 | | const bson_decode_options& options = bson_decode_options()) |
103 | | { |
104 | | using value_type = T; |
105 | | using result_type = read_result<value_type>; |
106 | | |
107 | | std::error_code ec; |
108 | | basic_bson_cursor<binary_stream_source> cursor(is, options, ec); |
109 | | if (JSONCONS_UNLIKELY(ec)) |
110 | | { |
111 | | return result_type{jsoncons::unexpect, ec, cursor.line(), cursor.column()}; |
112 | | } |
113 | | |
114 | | return reflect::decode_traits<T>::try_decode(make_alloc_set(), cursor); |
115 | | } |
116 | | |
117 | | template <typename T,typename InputIt> |
118 | | typename std::enable_if<ext_traits::is_basic_json<T>::value,read_result<T>>::type |
119 | | try_decode_bson(InputIt first, InputIt last, |
120 | | const bson_decode_options& options = bson_decode_options()) |
121 | | { |
122 | | using value_type = T; |
123 | | using result_type = read_result<value_type>; |
124 | | |
125 | | std::error_code ec; |
126 | | jsoncons::json_decoder<T> decoder; |
127 | | auto adaptor = make_json_visitor_adaptor<json_visitor>(decoder); |
128 | | basic_bson_reader<binary_iterator_source<InputIt>> reader(binary_iterator_source<InputIt>(first, last), adaptor, options); |
129 | | reader.read(ec); |
130 | | if (JSONCONS_UNLIKELY(ec)) |
131 | | { |
132 | | return result_type{jsoncons::unexpect, ec, reader.line(), reader.column()}; |
133 | | } |
134 | | if (JSONCONS_UNLIKELY(!decoder.is_valid())) |
135 | | { |
136 | | return result_type{jsoncons::unexpect, conv_errc::conversion_failed, reader.line(), reader.column()}; |
137 | | } |
138 | | return result_type{decoder.get_result()}; |
139 | | } |
140 | | |
141 | | template <typename T,typename InputIt> |
142 | | typename std::enable_if<!ext_traits::is_basic_json<T>::value,read_result<T>>::type |
143 | | try_decode_bson(InputIt first, InputIt last, |
144 | | const bson_decode_options& options = bson_decode_options()) |
145 | | { |
146 | | using value_type = T; |
147 | | using result_type = read_result<value_type>; |
148 | | |
149 | | std::error_code ec; |
150 | | basic_bson_cursor<binary_iterator_source<InputIt>> cursor(binary_iterator_source<InputIt>(first, last), options, ec); |
151 | | if (JSONCONS_UNLIKELY(ec)) |
152 | | { |
153 | | return result_type{jsoncons::unexpect, ec, cursor.line(), cursor.column()}; |
154 | | } |
155 | | |
156 | | return reflect::decode_traits<T>::try_decode(make_alloc_set(), cursor); |
157 | | } |
158 | | |
159 | | // With leading allocator_set parameter |
160 | | |
161 | | template <typename T,typename BytesLike,typename Alloc,typename TempAlloc > |
162 | | typename std::enable_if<ext_traits::is_basic_json<T>::value && |
163 | | ext_traits::is_byte_sequence<BytesLike>::value,read_result<T>>::type |
164 | | try_decode_bson(const allocator_set<Alloc,TempAlloc>& aset, |
165 | | const BytesLike& v, |
166 | | const bson_decode_options& options = bson_decode_options()) |
167 | | { |
168 | | using value_type = T; |
169 | | using result_type = read_result<value_type>; |
170 | | |
171 | | std::error_code ec; |
172 | | json_decoder<T,TempAlloc> decoder(aset.get_allocator(), aset.get_temp_allocator()); |
173 | | auto adaptor = make_json_visitor_adaptor<json_visitor>(decoder); |
174 | | basic_bson_reader<jsoncons::bytes_source,TempAlloc> reader(v, adaptor, options, aset.get_temp_allocator()); |
175 | | reader.read(ec); |
176 | | if (JSONCONS_UNLIKELY(ec)) |
177 | | { |
178 | | return result_type{jsoncons::unexpect, ec, reader.line(), reader.column()}; |
179 | | } |
180 | | if (JSONCONS_UNLIKELY(!decoder.is_valid())) |
181 | | { |
182 | | return result_type{jsoncons::unexpect, conv_errc::conversion_failed, reader.line(), reader.column()}; |
183 | | } |
184 | | return result_type{decoder.get_result()}; |
185 | | } |
186 | | |
187 | | template <typename T,typename BytesLike,typename Alloc,typename TempAlloc > |
188 | | typename std::enable_if<!ext_traits::is_basic_json<T>::value && |
189 | | ext_traits::is_byte_sequence<BytesLike>::value,read_result<T>>::type |
190 | | try_decode_bson(const allocator_set<Alloc,TempAlloc>& aset, |
191 | | const BytesLike& v, |
192 | | const bson_decode_options& options = bson_decode_options()) |
193 | | { |
194 | | using value_type = T; |
195 | | using result_type = read_result<value_type>; |
196 | | |
197 | | std::error_code ec; |
198 | | basic_bson_cursor<bytes_source,TempAlloc> cursor(std::allocator_arg, aset.get_temp_allocator(), v, options, ec); |
199 | | if (JSONCONS_UNLIKELY(ec)) |
200 | | { |
201 | | return result_type{jsoncons::unexpect, ec, cursor.line(), cursor.column()}; |
202 | | } |
203 | | |
204 | | return reflect::decode_traits<T>::try_decode(aset, cursor); |
205 | | } |
206 | | |
207 | | template <typename T,typename Alloc,typename TempAlloc > |
208 | | typename std::enable_if<ext_traits::is_basic_json<T>::value,read_result<T>>::type |
209 | | try_decode_bson(const allocator_set<Alloc,TempAlloc>& aset, |
210 | | std::istream& is, |
211 | | const bson_decode_options& options = bson_decode_options()) |
212 | | { |
213 | | using value_type = T; |
214 | | using result_type = read_result<value_type>; |
215 | | |
216 | | std::error_code ec; |
217 | | json_decoder<T,TempAlloc> decoder(aset.get_allocator(), aset.get_temp_allocator()); |
218 | | auto adaptor = make_json_visitor_adaptor<json_visitor>(decoder); |
219 | | basic_bson_reader<jsoncons::binary_stream_source,TempAlloc> reader(is, adaptor, options, aset.get_temp_allocator()); |
220 | | reader.read(ec); |
221 | | if (JSONCONS_UNLIKELY(ec)) |
222 | | { |
223 | | return result_type{jsoncons::unexpect, ec, reader.line(), reader.column()}; |
224 | | } |
225 | | if (JSONCONS_UNLIKELY(!decoder.is_valid())) |
226 | | { |
227 | | return result_type{jsoncons::unexpect, conv_errc::conversion_failed, reader.line(), reader.column()}; |
228 | | } |
229 | | return result_type{decoder.get_result()}; |
230 | | } |
231 | | |
232 | | template <typename T,typename Alloc,typename TempAlloc > |
233 | | typename std::enable_if<!ext_traits::is_basic_json<T>::value,read_result<T>>::type |
234 | | try_decode_bson(const allocator_set<Alloc,TempAlloc>& aset, |
235 | | std::istream& is, |
236 | | const bson_decode_options& options = bson_decode_options()) |
237 | | { |
238 | | using value_type = T; |
239 | | using result_type = read_result<value_type>; |
240 | | |
241 | | std::error_code ec; |
242 | | basic_bson_cursor<binary_stream_source,TempAlloc> cursor(std::allocator_arg, aset.get_temp_allocator(), is, options, ec); |
243 | | if (JSONCONS_UNLIKELY(ec)) |
244 | | { |
245 | | return result_type{jsoncons::unexpect, ec, cursor.line(), cursor.column()}; |
246 | | } |
247 | | |
248 | | return reflect::decode_traits<T>::try_decode(aset, cursor); |
249 | | } |
250 | | |
251 | | template <typename T, typename... Args> |
252 | | T decode_bson(Args&& ... args) |
253 | 4.25k | { |
254 | 4.25k | auto result = try_decode_bson<T>(std::forward<Args>(args)...); |
255 | 4.25k | if (!result) |
256 | 4.23k | { |
257 | 4.23k | JSONCONS_THROW(ser_error(result.error().code(), result.error().line(), result.error().column())); |
258 | 4.23k | } |
259 | 13 | return std::move(*result); |
260 | 4.25k | } |
261 | | |
262 | | } // namespace bson |
263 | | } // namespace jsoncons |
264 | | |
265 | | #endif // JSONCONS_EXT_BSON_DECODE_BSON_HPP |