/src/jsoncons/include/jsoncons_ext/bson/decode_bson.hpp
Line | Count | Source |
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.53k | { |
80 | 4.53k | using value_type = T; |
81 | 4.53k | using result_type = read_result<value_type>; |
82 | | |
83 | 4.53k | std::error_code ec; |
84 | 4.53k | jsoncons::json_decoder<T> decoder; |
85 | 4.53k | auto adaptor = make_json_visitor_adaptor<json_visitor>(decoder); |
86 | 4.53k | bson_stream_reader reader(is, adaptor, options); |
87 | 4.53k | reader.read(ec); |
88 | 4.53k | if (JSONCONS_UNLIKELY(ec)) |
89 | 4.52k | { |
90 | 4.52k | return result_type{jsoncons::unexpect, ec, reader.line(), reader.column()}; |
91 | 4.52k | } |
92 | 14 | 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 | 14 | return result_type{decoder.get_result()}; |
97 | 14 | } |
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 | | using byte_allocator_type = typename std::allocator_traits<TempAlloc>:: template rebind_alloc<uint8_t>; |
216 | | using stream_source_type = stream_source<uint8_t,byte_allocator_type>; |
217 | | |
218 | | std::error_code ec; |
219 | | json_decoder<T,TempAlloc> decoder(aset.get_allocator(), aset.get_temp_allocator()); |
220 | | auto adaptor = make_json_visitor_adaptor<json_visitor>(decoder); |
221 | | basic_bson_reader<stream_source_type,TempAlloc> reader(stream_source_type(is,aset.get_temp_allocator()), |
222 | | adaptor, options, aset.get_temp_allocator()); |
223 | | reader.read(ec); |
224 | | if (JSONCONS_UNLIKELY(ec)) |
225 | | { |
226 | | return result_type{jsoncons::unexpect, ec, reader.line(), reader.column()}; |
227 | | } |
228 | | if (JSONCONS_UNLIKELY(!decoder.is_valid())) |
229 | | { |
230 | | return result_type{jsoncons::unexpect, conv_errc::conversion_failed, reader.line(), reader.column()}; |
231 | | } |
232 | | return result_type{decoder.get_result()}; |
233 | | } |
234 | | |
235 | | template <typename T,typename Alloc,typename TempAlloc > |
236 | | typename std::enable_if<!ext_traits::is_basic_json<T>::value,read_result<T>>::type |
237 | | try_decode_bson(const allocator_set<Alloc,TempAlloc>& aset, |
238 | | std::istream& is, |
239 | | const bson_decode_options& options = bson_decode_options()) |
240 | | { |
241 | | using value_type = T; |
242 | | using result_type = read_result<value_type>; |
243 | | |
244 | | std::error_code ec; |
245 | | basic_bson_cursor<binary_stream_source,TempAlloc> cursor(std::allocator_arg, aset.get_temp_allocator(), is, options, ec); |
246 | | if (JSONCONS_UNLIKELY(ec)) |
247 | | { |
248 | | return result_type{jsoncons::unexpect, ec, cursor.line(), cursor.column()}; |
249 | | } |
250 | | |
251 | | return reflect::decode_traits<T>::try_decode(aset, cursor); |
252 | | } |
253 | | |
254 | | template <typename T, typename... Args> |
255 | | T decode_bson(Args&& ... args) |
256 | 4.53k | { |
257 | 4.53k | auto result = try_decode_bson<T>(std::forward<Args>(args)...); |
258 | 4.53k | if (!result) |
259 | 4.52k | { |
260 | 4.52k | JSONCONS_THROW(ser_error(result.error().code(), result.error().line(), result.error().column())); |
261 | 4.52k | } |
262 | 14 | return std::move(*result); |
263 | 4.53k | } |
264 | | |
265 | | } // namespace bson |
266 | | } // namespace jsoncons |
267 | | |
268 | | #endif // JSONCONS_EXT_BSON_DECODE_BSON_HPP |