1//     __ _____ _____ _____
2//  __|  |   __|     |   | |  JSON for Modern C++
3// |  |  |__   |  |  | | | |  version 3.11.2
4// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
5//
6// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
7// SPDX-License-Identifier: MIT
8
9#pragma once
10
11#include <cstddef> // nullptr_t
12#include <exception> // exception
13#include <stdexcept> // runtime_error
14#include <string> // to_string
15#include <vector> // vector
16
17#include <nlohmann/detail/value_t.hpp>
18#include <nlohmann/detail/string_escape.hpp>
19#include <nlohmann/detail/input/position_t.hpp>
20#include <nlohmann/detail/macro_scope.hpp>
21#include <nlohmann/detail/meta/cpp_future.hpp>
22#include <nlohmann/detail/meta/type_traits.hpp>
23#include <nlohmann/detail/string_concat.hpp>
24
25
26NLOHMANN_JSON_NAMESPACE_BEGIN
27namespace detail
28{
29
30////////////////
31// exceptions //
32////////////////
33
34/// @brief general exception of the @ref basic_json class
35/// @sa https://json.nlohmann.me/api/basic_json/exception/
36class exception : public std::exception
37{
38  public:
39    /// returns the explanatory string
40    const char* what() const noexcept override
41    {
42        return m.what();
43    }
44
45    /// the id of the exception
46    const int id; // NOLINT(cppcoreguidelines-non-private-member-variables-in-classes)
47
48  protected:
49    JSON_HEDLEY_NON_NULL(3)
50    exception(int id_, const char* what_arg) : id(id_), m(what_arg) {} // NOLINT(bugprone-throw-keyword-missing)
51
52    static std::string name(const std::string& ename, int id_)
53    {
54        return concat("[json.exception.", ename, '.', std::to_string(id_), "] ");
55    }
56
57    static std::string diagnostics(std::nullptr_t /*leaf_element*/)
58    {
59        return "";
60    }
61
62    template<typename BasicJsonType>
63    static std::string diagnostics(const BasicJsonType* leaf_element)
64    {
65#if JSON_DIAGNOSTICS
66        std::vector<std::string> tokens;
67        for (const auto* current = leaf_element; current != nullptr && current->m_parent != nullptr; current = current->m_parent)
68        {
69            switch (current->m_parent->type())
70            {
71                case value_t::array:
72                {
73                    for (std::size_t i = 0; i < current->m_parent->m_value.array->size(); ++i)
74                    {
75                        if (&current->m_parent->m_value.array->operator[](i) == current)
76                        {
77                            tokens.emplace_back(std::to_string(i));
78                            break;
79                        }
80                    }
81                    break;
82                }
83
84                case value_t::object:
85                {
86                    for (const auto& element : *current->m_parent->m_value.object)
87                    {
88                        if (&element.second == current)
89                        {
90                            tokens.emplace_back(element.first.c_str());
91                            break;
92                        }
93                    }
94                    break;
95                }
96
97                case value_t::null: // LCOV_EXCL_LINE
98                case value_t::string: // LCOV_EXCL_LINE
99                case value_t::boolean: // LCOV_EXCL_LINE
100                case value_t::number_integer: // LCOV_EXCL_LINE
101                case value_t::number_unsigned: // LCOV_EXCL_LINE
102                case value_t::number_float: // LCOV_EXCL_LINE
103                case value_t::binary: // LCOV_EXCL_LINE
104                case value_t::discarded: // LCOV_EXCL_LINE
105                default:   // LCOV_EXCL_LINE
106                    break; // LCOV_EXCL_LINE
107            }
108        }
109
110        if (tokens.empty())
111        {
112            return "";
113        }
114
115        auto str = std::accumulate(tokens.rbegin(), tokens.rend(), std::string{},
116                                   [](const std::string & a, const std::string & b)
117        {
118            return concat(a, '/', detail::escape(b));
119        });
120        return concat('(', str, ") ");
121#else
122        static_cast<void>(leaf_element);
123        return "";
124#endif
125    }
126
127  private:
128    /// an exception object as storage for error messages
129    std::runtime_error m;
130};
131
132/// @brief exception indicating a parse error
133/// @sa https://json.nlohmann.me/api/basic_json/parse_error/
134class parse_error : public exception
135{
136  public:
137    /*!
138    @brief create a parse error exception
139    @param[in] id_       the id of the exception
140    @param[in] pos       the position where the error occurred (or with
141                         chars_read_total=0 if the position cannot be
142                         determined)
143    @param[in] what_arg  the explanatory string
144    @return parse_error object
145    */
146    template<typename BasicJsonContext, enable_if_t<is_basic_json_context<BasicJsonContext>::value, int> = 0>
147    static parse_error create(int id_, const position_t& pos, const std::string& what_arg, BasicJsonContext context)
148    {
149        std::string w = concat(exception::name("parse_error", id_), "parse error",
150                               position_string(pos), ": ", exception::diagnostics(context), what_arg);
151        return {id_, pos.chars_read_total, w.c_str()};
152    }
153
154    template<typename BasicJsonContext, enable_if_t<is_basic_json_context<BasicJsonContext>::value, int> = 0>
155    static parse_error create(int id_, std::size_t byte_, const std::string& what_arg, BasicJsonContext context)
156    {
157        std::string w = concat(exception::name("parse_error", id_), "parse error",
158                               (byte_ != 0 ? (concat(" at byte ", std::to_string(byte_))) : ""),
159                               ": ", exception::diagnostics(context), what_arg);
160        return {id_, byte_, w.c_str()};
161    }
162
163    /*!
164    @brief byte index of the parse error
165
166    The byte index of the last read character in the input file.
167
168    @note For an input with n bytes, 1 is the index of the first character and
169          n+1 is the index of the terminating null byte or the end of file.
170          This also holds true when reading a byte vector (CBOR or MessagePack).
171    */
172    const std::size_t byte;
173
174  private:
175    parse_error(int id_, std::size_t byte_, const char* what_arg)
176        : exception(id_, what_arg), byte(byte_) {}
177
178    static std::string position_string(const position_t& pos)
179    {
180        return concat(" at line ", std::to_string(pos.lines_read + 1),
181                      ", column ", std::to_string(pos.chars_read_current_line));
182    }
183};
184
185/// @brief exception indicating errors with iterators
186/// @sa https://json.nlohmann.me/api/basic_json/invalid_iterator/
187class invalid_iterator : public exception
188{
189  public:
190    template<typename BasicJsonContext, enable_if_t<is_basic_json_context<BasicJsonContext>::value, int> = 0>
191    static invalid_iterator create(int id_, const std::string& what_arg, BasicJsonContext context)
192    {
193        std::string w = concat(exception::name("invalid_iterator", id_), exception::diagnostics(context), what_arg);
194        return {id_, w.c_str()};
195    }
196
197  private:
198    JSON_HEDLEY_NON_NULL(3)
199    invalid_iterator(int id_, const char* what_arg)
200        : exception(id_, what_arg) {}
201};
202
203/// @brief exception indicating executing a member function with a wrong type
204/// @sa https://json.nlohmann.me/api/basic_json/type_error/
205class type_error : public exception
206{
207  public:
208    template<typename BasicJsonContext, enable_if_t<is_basic_json_context<BasicJsonContext>::value, int> = 0>
209    static type_error create(int id_, const std::string& what_arg, BasicJsonContext context)
210    {
211        std::string w = concat(exception::name("type_error", id_), exception::diagnostics(context), what_arg);
212        return {id_, w.c_str()};
213    }
214
215  private:
216    JSON_HEDLEY_NON_NULL(3)
217    type_error(int id_, const char* what_arg) : exception(id_, what_arg) {}
218};
219
220/// @brief exception indicating access out of the defined range
221/// @sa https://json.nlohmann.me/api/basic_json/out_of_range/
222class out_of_range : public exception
223{
224  public:
225    template<typename BasicJsonContext, enable_if_t<is_basic_json_context<BasicJsonContext>::value, int> = 0>
226    static out_of_range create(int id_, const std::string& what_arg, BasicJsonContext context)
227    {
228        std::string w = concat(exception::name("out_of_range", id_), exception::diagnostics(context), what_arg);
229        return {id_, w.c_str()};
230    }
231
232  private:
233    JSON_HEDLEY_NON_NULL(3)
234    out_of_range(int id_, const char* what_arg) : exception(id_, what_arg) {}
235};
236
237/// @brief exception indicating other library errors
238/// @sa https://json.nlohmann.me/api/basic_json/other_error/
239class other_error : public exception
240{
241  public:
242    template<typename BasicJsonContext, enable_if_t<is_basic_json_context<BasicJsonContext>::value, int> = 0>
243    static other_error create(int id_, const std::string& what_arg, BasicJsonContext context)
244    {
245        std::string w = concat(exception::name("other_error", id_), exception::diagnostics(context), what_arg);
246        return {id_, w.c_str()};
247    }
248
249  private:
250    JSON_HEDLEY_NON_NULL(3)
251    other_error(int id_, const char* what_arg) : exception(id_, what_arg) {}
252};
253
254}  // namespace detail
255NLOHMANN_JSON_NAMESPACE_END
256