Coverage Report

Created: 2026-01-15 06:54

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