Coverage Report

Created: 2025-08-29 06:24

/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