11 #include <daw/daw_hide.h>
12 #include <daw/daw_string_view.h>
13 #include <daw/daw_unreachable.h>
22 #include <string_view>
24 namespace daw::json::json_details {
25 struct missing_member {
26 char const *member_name;
28 template<
typename StringView,
29 std::enable_if_t<(not std::is_same_v<StringView, missing_member>),
30 std::nullptr_t> =
nullptr>
31 explicit constexpr missing_member( StringView name )
32 : member_name( name.data( ) ) {}
34 template<std::
size_t N>
35 explicit constexpr missing_member(
char const ( &s )[N] )
39 struct missing_token {
41 explicit constexpr missing_token(
char c )
48 enum class ErrorReason {
53 InvalidNumberUnexpectedQuoting,
60 InvalidStringHighASCII,
61 ExpectedKeyValueToStartWithBrace,
62 ExpectedKeyValueArrayToStartWithBracket,
80 ExpectedArrayOrClassStart,
83 AttemptToAccessPastEndOfValue,
84 OutOfOrderOrderedMembers,
85 MissingMemberNameOrEndOfClass,
88 ExpectedMemberNotFound,
89 ExpectedTokenNotFound,
90 UnexpectedJSONVariantType
93 constexpr std::string_view reason_message( ErrorReason er ) {
94 using namespace std::string_view_literals;
96 case ErrorReason::Unknown:
97 return "Unknown reason for error"sv;
98 case ErrorReason::UnexpectedEndOfData:
99 return "Unexpected end of data"sv;
100 case ErrorReason::InvalidNumber:
101 return "Invalid Number"sv;
102 case ErrorReason::InvalidNumberStart:
103 return R
"(Invalid Number started, expected a "0123456789-")"sv;
104 case ErrorReason::InvalidNumberUnexpectedQuoting:
105 return "Unexpected double quote prior to number"sv;
106 case ErrorReason::InvalidTimestamp:
107 return "Invalid Timestamp"sv;
108 case ErrorReason::InvalidUTFEscape:
109 return "Invalid UTF Escape"sv;
110 case ErrorReason::InvalidUTFCodepoint:
111 return "Invalid UTF Codepoint"sv;
112 case ErrorReason::InvalidEndOfValue:
113 return R
"(Did not find \",}]" at end of value)"sv;
114 case ErrorReason::InvalidLiteral:
115 return "Literal data was corrupt"sv;
116 case ErrorReason::InvalidString:
117 return "Invalid or corrupt string"sv;
118 case ErrorReason::InvalidStringHighASCII:
119 return "String support limited to 0x20 < chr <= 0x7F when "
120 "DisallowHighEightBit is true"sv;
121 case ErrorReason::ExpectedKeyValueToStartWithBrace:
122 return "Expected key/value's JSON type to be of class type and beginning "
124 case ErrorReason::ExpectedKeyValueArrayToStartWithBracket:
125 return "Expected key/value's JSON type to be of array type and beginning "
127 case ErrorReason::InvalidArrayStart:
128 return "Expected array type to begin with '['"sv;
129 case ErrorReason::InvalidClassStart:
130 return "Expected class type to begin with '{'"sv;
131 case ErrorReason::InvalidStartOfValue:
132 return "Unexpected character data at start of value"sv;
133 case ErrorReason::InvalidTrue:
134 return "Expected true not found"sv;
135 case ErrorReason::InvalidFalse:
136 return "Expected false not found"sv;
137 case ErrorReason::InvalidNull:
138 return "Expected null not found"sv;
139 case ErrorReason::UnexpectedNull:
140 return "An unexpected null value was encountered while serializing"sv;
141 case ErrorReason::NumberIsNaN:
142 return "NaN encountered while serializing to JSON Number literal"sv;
143 case ErrorReason::NumberIsInf:
144 return "Infinity encountered while serializing to JSON Number literal"sv;
145 case ErrorReason::NumberOutOfRange:
146 return "Number is outside of the representable range"sv;
147 case ErrorReason::EmptyJSONDocument:
148 return "Attempt to parse an empty JSON document"sv;
149 case ErrorReason::EmptyJSONPath:
150 return "Empty JSON Path specified"sv;
151 case ErrorReason::JSONPathNotFound:
152 return "JSON Path specified not found in document"sv;
153 case ErrorReason::InvalidJSONPath:
154 return "Invalid JSON Path specified"sv;
155 case ErrorReason::NullOutputIterator:
156 return "Null pointer specified for output"sv;
157 case ErrorReason::MissingMemberNameOrEndOfClass:
158 return "Missing member name or end of class"sv;
159 case ErrorReason::MissingMemberName:
160 return "Missing member name"sv;
161 case ErrorReason::InvalidMemberName:
162 return "Member names must be JSON strings"sv;
163 case ErrorReason::ExpectedArrayOrClassStart:
164 return "Expected start of a JSON class or array"sv;
165 case ErrorReason::UnknownMember:
166 return "Could not find member in JSON class"sv;
167 case ErrorReason::InvalidBracketing:
168 return "Invalid Bracketing"sv;
169 case ErrorReason::AttemptToAccessPastEndOfValue:
170 return "A value of known size was accessed past the end"sv;
171 case ErrorReason::OutOfOrderOrderedMembers:
172 return "Order of ordered members must be ascending"sv;
173 case ErrorReason::MemberNotFound:
174 return "Expected member not found"sv;
175 case ErrorReason::TagMemberNotFound:
176 return "Expected tag member not found, they are required for tagged "
178 case ErrorReason::ExpectedMemberNotFound:
179 return "Expected member missing"sv;
180 case ErrorReason::ExpectedTokenNotFound:
181 return "Expected token missing"sv;
182 case ErrorReason::UnexpectedJSONVariantType:
183 return "Unexpected JSON Variant Type"sv;
193 class json_exception {
194 ErrorReason m_reason = ErrorReason::Unknown;
195 char const *m_data =
nullptr;
196 char const *m_parse_loc =
nullptr;
197 static constexpr
char token_addr[256] = { };
199 static constexpr
char const *get_token_addr(
char c ) {
200 return token_addr +
static_cast<int>(
static_cast<unsigned char>( c ) );
203 static constexpr
char get_token(
char const *p ) {
204 return static_cast<char>(
static_cast<unsigned char>( p - token_addr ) );
208 constexpr json_exception( ) =
default;
210 explicit constexpr json_exception( ErrorReason reason )
211 : m_reason( reason ) {}
213 explicit constexpr json_exception( json_details::missing_member mm )
214 : m_reason( ErrorReason::MemberNotFound )
215 , m_data( mm.member_name ) {}
217 explicit constexpr json_exception( json_details::missing_token mt )
218 : m_reason( ErrorReason::ExpectedTokenNotFound )
219 , m_data( get_token_addr( mt.token ) ) {}
221 explicit constexpr json_exception( json_details::missing_member mm,
222 std::string_view location )
223 : m_reason( ErrorReason::MemberNotFound )
224 , m_data( mm.member_name )
225 , m_parse_loc( location.data( ) ) {}
227 explicit constexpr json_exception( json_details::missing_token mt,
228 char const *location )
229 : m_reason( ErrorReason::ExpectedTokenNotFound )
230 , m_data( get_token_addr( mt.token ) )
231 , m_parse_loc( location ) {}
233 explicit constexpr json_exception( ErrorReason reason,
234 char const *location )
236 , m_parse_loc( location ) {}
238 [[nodiscard]] constexpr ErrorReason reason_type( )
const {
242 [[nodiscard]]
inline std::string reason( )
const {
243 #if defined( __clang__ )
244 #pragma clang diagnostic push
245 #pragma clang diagnostic ignored "-Wswitch-enum"
248 case ErrorReason::MemberNotFound: {
249 using namespace std::string_literals;
250 return "Could not find required class member '"s +
251 static_cast<std::string
>( m_data ) +
"'"s;
253 case ErrorReason::ExpectedTokenNotFound: {
254 using namespace std::string_literals;
255 return "Could not find expected parse token '"s + get_token( m_data ) +
259 return std::string( ( reason_message( m_reason ) ) );
261 #if defined( __clang__ )
262 #pragma clang diagnostic pop
266 [[nodiscard]] constexpr
char const *parse_location( )
const {
277 to_formatted_string( json_exception
const &je,
278 char const *json_document =
nullptr ) {
279 using namespace std::string_literals;
280 std::string result =
"reason: "s + je.reason( );
281 if( json_document ==
nullptr or je.parse_location( ) ==
nullptr ) {
284 auto const previous_char_count =
285 std::min(
static_cast<std::size_t
>( 50 ),
286 static_cast<std::size_t
>(
287 std::distance( json_document, je.parse_location( ) + 1 ) ) );
288 auto const loc_data = std::string_view(
289 std::prev( je.parse_location( ),
290 static_cast<std::ptrdiff_t
>( previous_char_count ) ),
291 previous_char_count + 1 );
293 result +=
"\nlocation:\x1b[1m";
296 std::accumulate( loc_data.data( ), loc_data.data( ) + loc_data.size( ),
297 std::string{ }, []( std::string s,
char c ) {
298 if( ( c !=
'\n' ) & ( c !=
'\r' ) ) {
304 result +=
"\x1b[0m\n";