DAW JSON Link
Loading...
Searching...
No Matches
daw_json_writer.h
Go to the documentation of this file.
1// Copyright (c) Darrell Wright
2//
3// Distributed under the Boost Software License, Version 1.0. (See accompanying
4// file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
5//
6// Official repository: https://github.com/beached/daw_json_link
7//
8
9#pragma once
10
12
15
16#if defined( DAW_JSON_HAS_REFLECTION )
17#include <daw/daw_concepts.h>
18#endif
19
20#include <daw/daw_move.h>
21#include <daw/traits/daw_traits_remove_cvref.h>
22
23#include <type_traits>
24#include <vector>
25
26namespace daw::json {
27 inline namespace DAW_JSON_VER {
28 namespace json_writer_details {
29 template<typename JsonClass, typename Value>
30 using json_write_value_class_t =
31 json_details::json_serialize_deduced_type<JsonClass, Value>;
32
33 enum class json_writer_states : std::uint8_t {
37 json_writer_nothing,
41 json_writer_object,
45 json_writer_array
46 };
47 } // namespace json_writer_details
48
49 template<typename WritableType, typename StackType, auto... PolicyFlags>
51 using iterator_t =
52 decltype( json_details::make_output_iterator<PolicyFlags...>(
53 std::declval<WritableType>( ) ) );
54
55 StackType m_stack{ };
56 json_writer_details::json_writer_states m_current_state =
57 json_writer_details::json_writer_states::json_writer_nothing;
58 bool m_is_first = true;
59 bool m_is_key_written = false;
61
62 constexpr void
63 push_state( json_writer_details::json_writer_states new_state ) {
64 m_stack.push_back( m_current_state );
65 m_current_state = new_state;
66 }
67
68 constexpr void pop_state( ) {
69 daw_json_ensure( not m_stack.empty( ), ErrorReason::OutputError );
70 m_current_state = m_stack.back( );
71 m_stack.pop_back( );
72 }
73
74 constexpr void write_item_prefix( ) {
75 daw_json_ensure( not m_is_key_written, ErrorReason::OutputError );
76 if( not m_is_first ) {
77 m_writer.put( ',' );
78 } else {
79 m_is_first = false;
80 }
81 m_writer.next_member( );
82 }
83
84 constexpr void prepare_value( ) {
85 if( m_current_state ==
86 json_writer_details::json_writer_states::json_writer_nothing ) {
87 daw_json_ensure( m_is_first, ErrorReason::OutputError );
88 return;
89 }
90 if( m_current_state ==
91 json_writer_details::json_writer_states::json_writer_object ) {
92 daw_json_ensure( m_is_key_written, ErrorReason::OutputError );
93 m_is_key_written = false;
94 return;
95 }
96 if( m_current_state !=
97 json_writer_details::json_writer_states::json_writer_nothing ) {
98 write_item_prefix( );
99 }
100 }
101
102 template<typename JsonClass = use_default, typename T>
103 constexpr void do_write_value( T const &value ) {
104 if constexpr( json_details::is_char_pointer_v<T> ) {
105 // Same as to_json: a nul terminated string, nullptr is null. An
106 // explicit JsonClass is given the string_view
107 if( value == nullptr ) {
108 prepare_value( );
109 m_writer.write( "null" );
110 m_is_first = false;
111 } else {
112 do_write_value<JsonClass>( daw::string_view( value ) );
113 }
114 } else if constexpr( json_details::is_char_array_v<T> ) {
115 // Same as to_json: exclude the trailing nul. An explicit JsonClass
116 // is given the string_view
117 do_write_value<JsonClass>(
118 daw::string_view( value, std::extent_v<T> - 1U ) );
119 } else {
120 using json_class_t =
121 json_details::json_serialize_deduced_type<JsonClass, T>;
122 prepare_value( );
123 if constexpr( std::is_pointer_v<std::remove_reference_t<T>> ) {
124 if( not value ) {
125 m_writer.write( "null" );
126 } else {
127 m_writer =
128 json_details::member_to_string<json_class_t>( m_writer, value );
129 }
130 } else {
131 m_writer =
132 json_details::member_to_string<json_class_t>( m_writer, value );
133 }
134 m_is_first = false;
135 }
136 }
137
138 public:
139 template<typename W>
140 explicit constexpr json_writer_t( W &&writer DAW_LIFETIME_BOUND )
141 : m_writer( json_details::make_output_iterator<PolicyFlags...>(
142 DAW_FWD( writer ) ) ) {}
143 json_writer_t( json_writer_t const & ) = delete;
145 json_writer_t( json_writer_t &&other ) = delete;
147
148 constexpr void finalize( ) {
149 if( m_is_key_written ) {
150 write_value( nullptr );
151 }
152 while( m_current_state !=
153 json_writer_details::json_writer_states::json_writer_nothing ) {
154 switch( m_current_state ) {
155 case json_writer_details::json_writer_states::json_writer_object:
156 close_object( );
157 break;
158 case json_writer_details::json_writer_states::json_writer_array:
159 close_array( );
160 break;
161 case json_writer_details::json_writer_states::json_writer_nothing:
162 default:
163 break;
164 }
165 }
166 }
167
168 constexpr void reset( ) {
169 finalize( );
170 m_current_state =
171 json_writer_details::json_writer_states::json_writer_nothing;
172 m_is_first = true;
173 m_is_key_written = false;
174 }
175
176 DAW_CPP20_CX_DTOR ~json_writer_t( ) noexcept(
177 noexcept( m_writer.put( ' ' ) ) ) {
178 finalize( );
179 }
180
181 constexpr void open_object( ) {
182 prepare_value( );
183 push_state(
184 json_writer_details::json_writer_states::json_writer_object );
185 m_writer.put( '{' );
186 m_writer.add_indent( );
187 m_is_first = true;
188 }
189
190 constexpr void close_object( ) {
192 m_current_state ==
193 json_writer_details::json_writer_states::json_writer_object,
194 ErrorReason::OutputError );
195 if( m_is_key_written ) {
196 write_value( nullptr );
197 }
198 m_writer.del_indent( );
199 if( not m_is_first ) {
200 if constexpr( iterator_t::output_trailing_comma ==
201 options::OutputTrailingComma::Yes ) {
202 m_writer.put( ',' );
203 }
204 m_writer.next_member( );
205 }
206 m_writer.put( '}' );
207 pop_state( );
208 m_is_first = false;
209 }
210
211 constexpr void open_array( ) {
212 prepare_value( );
213 push_state(
214 json_writer_details::json_writer_states::json_writer_array );
215 m_is_first = true;
216 m_writer.add_indent( );
217 m_writer.put( '[' );
218 }
219
220 constexpr void close_array( ) {
222 m_current_state ==
223 json_writer_details::json_writer_states::json_writer_array,
224 ErrorReason::OutputError );
225 m_writer.del_indent( );
226 if( not m_is_first ) {
227 if constexpr( iterator_t::output_trailing_comma ==
228 options::OutputTrailingComma::Yes ) {
229 m_writer.put( ',' );
230 }
231 m_writer.next_member( );
232 }
233 m_writer.put( ']' );
234 pop_state( );
235 m_is_first = false;
236 }
237
238 constexpr void write_value( std::nullptr_t ) {
239 write_null( );
240 }
241
242 template<typename JsonClass = use_default, typename T>
243 constexpr void write_value( T const &value ) {
245 m_current_state !=
246 json_writer_details::json_writer_states::json_writer_object or
247 m_is_key_written,
248 ErrorReason::OutputError );
250 m_current_state !=
251 json_writer_details::json_writer_states::json_writer_nothing or
252 m_is_first,
253 ErrorReason::OutputError );
254
255 do_write_value<JsonClass>( value );
256 }
257
258 template<typename T, typename T2, typename... Ts>
259 constexpr void write_value( T const &value, T2 const &value2,
260 Ts const &...values ) {
262 m_current_state !=
263 json_writer_details::json_writer_states::json_writer_object or
264 m_is_key_written,
265 ErrorReason::OutputError );
267 m_current_state !=
268 json_writer_details::json_writer_states::json_writer_nothing or
269 m_is_first,
270 ErrorReason::OutputError );
271 open_array( );
272 write_array_values( value, value2, values... );
273 close_array( );
274 }
275
276 template<typename JsonClass = use_default, typename T>
277 constexpr void write_value( std::initializer_list<T> const &values ) {
279 m_current_state !=
280 json_writer_details::json_writer_states::json_writer_object or
281 m_is_key_written,
282 ErrorReason::OutputError );
284 m_current_state !=
285 json_writer_details::json_writer_states::json_writer_nothing or
286 m_is_first,
287 ErrorReason::OutputError );
288 open_array( );
289 write_array_values<JsonClass>( values );
290 close_array( );
291 }
292
293 template<JSONNAMETYPE Name>
294 constexpr void add_static_key( ) {
295 if( m_is_key_written ) {
296 write_value( nullptr );
297 }
299 m_current_state ==
300 json_writer_details::json_writer_states::json_writer_object,
301 ErrorReason::OutputError );
302
303 write_item_prefix( );
304 m_writer.write(
305 '"', json_details::encode_json_name_v<Name>, "\":", m_writer.space );
306 m_is_key_written = true;
307 }
308
309 constexpr void add_key( daw::string_view name ) {
310 if( m_is_key_written ) {
311 write_value( nullptr );
312 }
314 m_current_state ==
315 json_writer_details::json_writer_states::json_writer_object,
316 ErrorReason::OutputError );
317
318 write_item_prefix( );
319 if constexpr( iterator_t::allow_escaped_names ) {
320 m_writer.put( '"' );
321 m_writer = json_details::encode_name( m_writer, name );
322 m_writer.write( "\":", m_writer.space );
323 } else {
324 m_writer.write( '"', name, "\":", m_writer.space );
325 }
326 m_is_key_written = true;
327 }
328
329 constexpr void write_key_value( daw::string_view name, std::nullptr_t ) {
330 add_key( name );
331 write_null( );
332 }
333
334 template<typename JsonClass = use_default, typename T>
335 constexpr void write_key_value( daw::string_view name,
336 std::initializer_list<T> const &values ) {
337 add_key( name );
338 open_array( );
339 write_array_values<JsonClass>( values );
340 close_array( );
341 }
342
343 template<typename JsonClass = use_default, typename T>
344 constexpr void write_key_value( daw::string_view name, T const &value ) {
345 add_key( name );
346 write_value<JsonClass>( value );
347 }
348
349 template<typename T, typename T2, typename... Ts>
350 constexpr void write_key_value( daw::string_view name, T const &value,
351 T2 const &value2, Ts const &...values ) {
352 add_key( name );
353 open_array( );
354 write_array_values( value, value2, values... );
355 close_array( );
356 }
357 //***
358 template<JSONNAMETYPE Name>
359 constexpr void write_static_key_value( std::nullptr_t ) {
360 add_static_key<Name>( );
361 write_null( );
362 }
363
364 template<JSONNAMETYPE Name, typename JsonClass = use_default, typename T>
365 constexpr void
366 write_static_key_value( std::initializer_list<T> const &values ) {
367 add_static_key<Name>( );
368 open_array( );
369 write_array_values<JsonClass>( values );
370 close_array( );
371 }
372
373 template<JSONNAMETYPE Name, typename JsonClass = use_default, typename T>
374 constexpr void write_static_key_value( T const &value ) {
375 add_static_key<Name>( );
376 write_value<JsonClass>( value );
377 }
378
379 template<JSONNAMETYPE Name, typename T, typename T2, typename... Ts>
380 constexpr void write_static_key_value( T const &value, T2 const &value2,
381 Ts const &...values ) {
382 add_static_key<Name>( );
383 open_array( );
384 write_array_values( value, value2, values... );
385 close_array( );
386 }
387
388 // Must be in array state
389 template<
390 typename JsonClass = use_default,
391 typename Range DAW_ENABLEIF( daw::traits::is_container_like_v<Range> )>
392 DAW_REQUIRES( daw::traits::is_container_like_v<Range> )
393 constexpr void write_array_values( Range const &values ) {
395 m_current_state ==
396 json_writer_details::json_writer_states::json_writer_array,
397 ErrorReason::OutputError );
398 for( auto const &value : values ) {
399 do_write_value<JsonClass>( value );
400 }
401 }
402
403 template<typename JsonClass = use_default, typename T>
404 constexpr void
405 write_array_values( std::initializer_list<T> const &values ) {
407 m_current_state ==
408 json_writer_details::json_writer_states::json_writer_array,
409 ErrorReason::OutputError );
410 for( auto const &value : values ) {
411 write_value<JsonClass>( value );
412 }
413 }
414
415 template<typename T, typename... Ts>
416 constexpr void write_array_values( T const &value, Ts const &...values ) {
418 m_current_state ==
419 json_writer_details::json_writer_states::json_writer_array,
420 ErrorReason::OutputError );
421 write_value( value );
422 (void)( ( write_value( values ), true ) and ... );
423 }
424
425 constexpr void write_boolean( bool b ) {
426 write_value( b );
427 }
428
429 constexpr void write_null( ) {
431 m_current_state !=
432 json_writer_details::json_writer_states::json_writer_nothing or
433 m_is_first,
434 ErrorReason::OutputError );
435 prepare_value( );
436 m_writer.write( "null" );
437 m_is_first = false;
438 }
439
440 template<typename JsonClass = use_default, typename T>
441 constexpr void write_number( T const &value ) {
442 using JsonMember =
443 json_writer_details::json_write_value_class_t<JsonClass, T>;
444 DAW_CPP23_STATIC_LOCAL constexpr JsonBaseParseTypes json_base_type =
445 JsonMember::underlying_json_type;
446 static_assert(
447 json_base_type == JsonBaseParseTypes::Number or
448 json_base_type == JsonBaseParseTypes::Bool,
449 "The underlying mapping must be a number or boolean type" );
450 if constexpr( json_base_type == JsonBaseParseTypes::Bool ) {
451 write_value<JsonClass>( static_cast<bool>( value ) ? 1 : 0 );
452 return;
453 } else {
454 write_value<JsonClass>( value );
455 }
456 }
457
458 private:
459 template<typename T>
460 DAW_CPP20_CX_ALLOC void write_string_class( T const &value ) {
461 using json_class_t =
462 json_details::json_serialize_deduced_type<use_default, T>;
463 auto tmp = std::string{ };
464 auto tmp_iterator =
465 json_details::make_output_iterator<PolicyFlags...>( tmp );
466 tmp_iterator.indentation_level = m_writer.indentation_level;
467 (void)json_details::member_to_string<json_class_t>( tmp_iterator,
468 value );
469 do_write_value<json_string_no_name<>>( tmp );
470 }
471
472 public:
473 template<typename JsonClass = use_default, typename T>
474 constexpr void write_string( T const &value ) {
475 if constexpr( json_details::is_char_pointer_v<T> or
476 json_details::is_char_array_v<T> ) {
477 write_value<JsonClass>( value );
478 } else {
479 write_string_impl<JsonClass>( value );
480 }
481 }
482
483 private:
484 template<typename JsonClass, typename T>
485 constexpr void write_string_impl( T const &value ) {
486 using JsonMember =
487 json_writer_details::json_write_value_class_t<JsonClass, T>;
488 DAW_CPP23_STATIC_LOCAL constexpr JsonBaseParseTypes json_base_type =
489 JsonMember::underlying_json_type;
490 if constexpr( json_base_type == JsonBaseParseTypes::String ) {
491 write_value<JsonClass>( value );
492 } else if constexpr( json_base_type == JsonBaseParseTypes::Bool or
493 json_base_type == JsonBaseParseTypes::Number ) {
494 prepare_value( );
495 m_writer.put( '"' );
496 m_writer =
497 json_details::member_to_string<JsonMember>( m_writer, value );
498 m_writer.put( '"' );
499 m_is_first = false;
500 } else {
501 write_string_class( value );
502 }
503 }
504
505#if defined( DAW_JSON_HAS_REFLECTION )
506 public:
507 constexpr void write_enum_string( daw::EnumType auto e ) {
508 write_string( refl_details::enum_to_string( e ) );
509 }
510
513 template<json_options_t NumberOptions = number_opts_def>
514 constexpr void write_enum_string_or_number( daw::EnumType auto e ) {
515 write_value<
516 refl_details::enum_string_or_number<decltype( e ), NumberOptions>>(
517 e );
518 }
519#endif
520 };
521
522 template<auto... PolicyFlags, typename WriterType>
523 constexpr auto json_writer( WriterType &&writer DAW_LIFETIME_BOUND ) {
525 std::vector<json_writer_details::json_writer_states>,
526 PolicyFlags...>( writer );
527 }
528 } // namespace DAW_JSON_VER
529} // namespace daw::json
DAW_CPP20_CX_DTOR ~json_writer_t() noexcept(noexcept(m_writer.put(' ')))
constexpr void write_array_values(std::initializer_list< T > const &values)
constexpr void write_key_value(daw::string_view name, std::nullptr_t)
constexpr void write_static_key_value(std::initializer_list< T > const &values)
json_writer_t & operator=(json_writer_t &&)=delete
json_writer_t & operator=(json_writer_t const &)=delete
constexpr void write_value(T const &value, T2 const &value2, Ts const &...values)
constexpr void push_state(json_writer_details::json_writer_states new_state)
constexpr void write_key_value(daw::string_view name, std::initializer_list< T > const &values)
constexpr void write_value(std::initializer_list< T > const &values)
constexpr void write_static_key_value(T const &value, T2 const &value2, Ts const &...values)
constexpr void write_array_values(T const &value, Ts const &...values)
decltype(json_details::make_output_iterator< PolicyFlags... >(std::declval< WritableType >())) iterator_t
constexpr void write_key_value(daw::string_view name, T const &value, T2 const &value2, Ts const &...values)
constexpr void write_key_value(daw::string_view name, T const &value)
#define daw_json_ensure(Bool,...)
Ensure that Bool is true. If false pass rest of args to daw_json_error.
DAW_REQUIRES(daw::json::json_details::is_container_opted_into_json_iostreams_v< Container >) std
An opt in ostream interface for containers of types that have JSON mappings.
#define JSONNAMETYPE
constexpr auto json_writer(WriterType &&writer DAW_LIFETIME_BOUND)
string_writer grows its string with resize_and_overwrite, leaving the new bytes uninitialized,...
#define DAW_JSON_VER
The version string used in namespace definitions. Must be a valid namespace name.
Definition version.h:20