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
11// Allow writing to a Writer incrementally
12
14
17
18#if defined( DAW_JSON_HAS_REFLECTION )
19#include <daw/daw_concepts.h>
20#endif
21
22#include <daw/daw_move.h>
23#include <daw/traits/daw_traits_remove_cvref.h>
24
25#include <type_traits>
26#include <vector>
27
28namespace daw::json {
29 inline namespace DAW_JSON_VER {
30 namespace json_writer_details {
31 template<typename JsonClass, typename Value>
32 using json_write_value_class_t = typename daw::conditional_t<
33 std::is_same_v<use_default, JsonClass>,
34 json_details::ident_trait<json_details::json_deduced_type, Value>,
35 json_details::ident_trait<json_details::json_deduced_type,
36 JsonClass>>::type;
37
38 enum class json_writer_states : std::uint8_t {
42 json_writer_nothing,
46 json_writer_object,
50 json_writer_array
51 };
52 } // namespace json_writer_details
53
54 template<typename WritableType, typename StackType, auto... PolicyFlags>
56 using iterator_t =
57 decltype( json_details::make_output_iterator<PolicyFlags...>(
58 std::declval<WritableType>( ) ) );
59
60 StackType m_stack{ };
61 json_writer_details::json_writer_states m_current_state =
62 json_writer_details::json_writer_states::json_writer_nothing;
63 bool m_is_first = true;
64 bool m_is_key_written = false;
66
67 constexpr void
68 push_state( json_writer_details::json_writer_states new_state ) {
69 m_stack.push_back( m_current_state );
70 m_current_state = new_state;
71 }
72
73 constexpr void pop_state( ) {
74 daw_json_ensure( not m_stack.empty( ), ErrorReason::OutputError );
75 m_current_state = m_stack.back( );
76 m_stack.pop_back( );
77 }
78
79 constexpr void write_item_prefix( ) {
80 daw_json_ensure( not m_is_key_written, ErrorReason::OutputError );
81 if( not m_is_first ) {
82 m_writer.put( ',' );
83 } else {
84 m_is_first = false;
85 }
86 m_writer.next_member( );
87 }
88
89 constexpr void prepare_value( ) {
90 if( m_current_state ==
91 json_writer_details::json_writer_states::json_writer_nothing ) {
92 daw_json_ensure( m_is_first, ErrorReason::OutputError );
93 return;
94 }
95 if( m_current_state ==
96 json_writer_details::json_writer_states::json_writer_object ) {
97 daw_json_ensure( m_is_key_written, ErrorReason::OutputError );
98 m_is_key_written = false;
99 return;
100 }
101 if( m_current_state !=
102 json_writer_details::json_writer_states::json_writer_nothing ) {
103 write_item_prefix( );
104 }
105 }
106
107 template<typename JsonClass = use_default, typename T>
108 constexpr void do_write_value( T const &value ) {
109 prepare_value( );
110 to_json<JsonClass>( value, m_writer.get( ) );
111 m_is_first = false;
112 }
113
114 public:
115 template<typename W>
116 explicit constexpr json_writer_t( W &&writer )
117 : m_writer( json_details::make_output_iterator<PolicyFlags...>(
118 DAW_FWD( writer ) ) ) {}
119 json_writer_t( json_writer_t const & ) = delete;
121 json_writer_t( json_writer_t &&other ) = delete;
123
124 constexpr void finalize( ) {
125 if( m_is_key_written ) {
126 write_value( nullptr );
127 }
128 while( m_current_state !=
129 json_writer_details::json_writer_states::json_writer_nothing ) {
130 switch( m_current_state ) {
131 case json_writer_details::json_writer_states::json_writer_object:
132 close_object( );
133 break;
134 case json_writer_details::json_writer_states::json_writer_array:
135 close_array( );
136 break;
137 case json_writer_details::json_writer_states::json_writer_nothing:
138 default:
139 break;
140 }
141 }
142 }
143
144 constexpr void reset( ) {
145 finalize( );
146 m_current_state =
147 json_writer_details::json_writer_states::json_writer_nothing;
148 m_is_first = true;
149 m_is_key_written = false;
150 }
151
152 DAW_CPP20_CX_DTOR ~json_writer_t( ) noexcept(
153 noexcept( m_writer.put( ' ' ) ) ) {
154 finalize( );
155 }
156
157 constexpr void open_object( ) {
158 prepare_value( );
159 push_state(
160 json_writer_details::json_writer_states::json_writer_object );
161 m_writer.put( '{' );
162 m_writer.add_indent( );
163 m_is_first = true;
164 }
165
166 constexpr void close_object( ) {
168 m_current_state ==
169 json_writer_details::json_writer_states::json_writer_object,
170 ErrorReason::OutputError );
171 if( m_is_key_written ) {
172 write_value( nullptr );
173 }
174 m_writer.del_indent( );
175 if( not m_is_first ) {
176 m_writer.next_member( );
177 }
178 m_writer.put( '}' );
179 pop_state( );
180 m_is_first = false;
181 }
182
183 constexpr void open_array( ) {
184 prepare_value( );
185 push_state(
186 json_writer_details::json_writer_states::json_writer_array );
187 m_is_first = true;
188 m_writer.add_indent( );
189 m_writer.put( '[' );
190 }
191
192 constexpr void close_array( ) {
194 m_current_state ==
195 json_writer_details::json_writer_states::json_writer_array,
196 ErrorReason::OutputError );
197 m_writer.del_indent( );
198 if( not m_is_first ) {
199 m_writer.next_member( );
200 }
201 m_writer.put( ']' );
202 pop_state( );
203 m_is_first = false;
204 }
205
206 constexpr void write_value( std::nullptr_t ) {
207 write_null( );
208 }
209
210 template<typename JsonClass = use_default, typename T>
211 constexpr void write_value( T const &value ) {
213 m_current_state !=
214 json_writer_details::json_writer_states::json_writer_object or
215 m_is_key_written,
216 ErrorReason::OutputError );
218 m_current_state !=
219 json_writer_details::json_writer_states::json_writer_nothing or
220 m_is_first,
221 ErrorReason::OutputError );
222 do_write_value<JsonClass>( value );
223 }
224
225 template<typename T, typename T2, typename... Ts>
226 constexpr void write_value( T const &value, T2 const &value2,
227 Ts const &...values ) {
229 m_current_state !=
230 json_writer_details::json_writer_states::json_writer_object or
231 m_is_key_written,
232 ErrorReason::OutputError );
234 m_current_state !=
235 json_writer_details::json_writer_states::json_writer_nothing or
236 m_is_first,
237 ErrorReason::OutputError );
238 open_array( );
239 write_array_values( value, value2, values... );
240 close_array( );
241 }
242
243 template<typename JsonClass = use_default, typename T>
244 constexpr void write_value( std::initializer_list<T> const &values ) {
246 m_current_state !=
247 json_writer_details::json_writer_states::json_writer_object or
248 m_is_key_written,
249 ErrorReason::OutputError );
251 m_current_state !=
252 json_writer_details::json_writer_states::json_writer_nothing or
253 m_is_first,
254 ErrorReason::OutputError );
255 open_array( );
256 write_array_values<JsonClass>( values );
257 close_array( );
258 }
259
260 template<typename JsonClass = use_default, std::size_t N>
261 constexpr void write_value( char const ( &str )[N] ) {
263 m_current_state !=
264 json_writer_details::json_writer_states::json_writer_object or
265 m_is_key_written,
266 ErrorReason::OutputError );
268 m_current_state !=
269 json_writer_details::json_writer_states::json_writer_nothing or
270 m_is_first,
271 ErrorReason::OutputError );
272 do_write_value<JsonClass>( daw::string_view( str, N - 1 ) );
273 }
274
275 constexpr void add_key( daw::string_view name ) {
276 if( m_is_key_written ) {
277 write_value( nullptr );
278 }
280 m_current_state ==
281 json_writer_details::json_writer_states::json_writer_object,
282 ErrorReason::OutputError );
283
284 write_item_prefix( );
285 m_writer.write( "\"", name, "\":", m_writer.space );
286 m_is_key_written = true;
287 }
288
289 constexpr void write_key_value( daw::string_view name, std::nullptr_t ) {
290 add_key( name );
291 write_null( );
292 }
293
294 template<typename JsonClass = use_default, typename T>
295 constexpr void write_key_value( daw::string_view name,
296 std::initializer_list<T> const &values ) {
297 add_key( name );
298 open_array( );
299 write_array_values<JsonClass>( values );
300 close_array( );
301 }
302
303 template<typename JsonClass = use_default, typename T>
304 constexpr void write_key_value( daw::string_view name, T const &value ) {
305 add_key( name );
306 write_value<JsonClass>( value );
307 }
308
309 template<typename T, typename T2, typename... Ts>
310 constexpr void write_key_value( daw::string_view name, T const &value,
311 T2 const &value2, Ts const &...values ) {
312 add_key( name );
313 open_array( );
314 write_array_values( value, value2, values... );
315 close_array( );
316 }
317
318 template<typename JsonClass = use_default, std::size_t N>
319 constexpr void write_key_value( daw::string_view name,
320 char const ( &str )[N] ) {
321 add_key( name );
322 write_value<JsonClass>( daw::string_view( str, N - 1 ) );
323 }
324
325 // Must be in array state
326 template<
327 typename JsonClass = use_default,
328 typename Range DAW_ENABLEIF( daw::traits::is_container_like_v<Range> )>
329 DAW_REQUIRES( daw::traits::is_container_like_v<Range> )
330 constexpr void write_array_values( Range const &values ) {
332 m_current_state ==
333 json_writer_details::json_writer_states::json_writer_array,
334 ErrorReason::OutputError );
335 for( auto const &value : values ) {
336 do_write_value<JsonClass>( value );
337 }
338 }
339
340 template<typename JsonClass = use_default, typename T>
341 constexpr void
342 write_array_values( std::initializer_list<T> const &values ) {
344 m_current_state ==
345 json_writer_details::json_writer_states::json_writer_array,
346 ErrorReason::OutputError );
347 for( auto const &value : values ) {
348 write_value<JsonClass>( value );
349 }
350 }
351
352 template<typename T, typename... Ts>
353 constexpr void write_array_values( T const &value, Ts const &...values ) {
355 m_current_state ==
356 json_writer_details::json_writer_states::json_writer_array,
357 ErrorReason::OutputError );
358 write_value( value );
359 (void)( ( write_value( values ), true ) and ... );
360 }
361
362 constexpr void write_boolean( bool b ) {
363 write_value( b );
364 }
365
366 constexpr void write_null( ) {
368 m_current_state !=
369 json_writer_details::json_writer_states::json_writer_nothing or
370 m_is_first,
371 ErrorReason::OutputError );
372 prepare_value( );
373 m_writer.write( "null" );
374 m_is_first = false;
375 }
376
377 template<typename JsonClass = use_default, typename T>
378 constexpr void write_number( T const &value ) {
379 using JsonMember =
380 json_writer_details::json_write_value_class_t<JsonClass, T>;
381 constexpr JsonBaseParseTypes json_base_type =
382 JsonMember::underlying_json_type;
383 static_assert(
384 json_base_type == JsonBaseParseTypes::Number or
385 json_base_type == JsonBaseParseTypes::Bool,
386 "The underlying mapping must be a number or boolean type" );
387 if constexpr( json_base_type == JsonBaseParseTypes::Bool ) {
388 write_value<JsonClass>( static_cast<bool>( value ) ? 1 : 0 );
389 return;
390 } else {
391 write_value<JsonClass>( value );
392 }
393 }
394
396 template<typename JsonClass = use_default, typename T>
397 constexpr void write_string( T const &value ) {
398 using JsonMember =
399 json_writer_details::json_write_value_class_t<JsonClass, T>;
400 constexpr JsonBaseParseTypes json_base_type =
401 JsonMember::underlying_json_type;
402 if constexpr( json_base_type == JsonBaseParseTypes::String ) {
403 write_value<JsonClass>( value );
404 } else if constexpr( json_base_type == JsonBaseParseTypes::Bool or
405 json_base_type == JsonBaseParseTypes::Number ) {
406 prepare_value( );
407 m_writer.put( '"' );
408 to_json<JsonClass>( value, m_writer.get( ) );
409 m_writer.put( '"' );
410 m_is_first = false;
411 } else {
412 auto const tmp = to_json( value );
413 do_write_value<json_string_no_name<>>( tmp );
414 }
415 }
416
417 template<typename JsonClass = use_default, std::size_t N>
418 constexpr void write_string( char const ( &str )[N] ) {
419 write_value<JsonClass>( daw::string_view( str, N - 1 ) );
420 }
421
422#if defined( DAW_JSON_HAS_REFLECTION )
423 constexpr void write_enum_string( daw::EnumType auto e ) {
424 write_string( refl_details::enum_to_string( e ) );
425 }
426#endif
427 };
428
429 template<auto... PolicyFlags, typename WriterType>
430 constexpr auto json_writer( WriterType &&writer ) {
432 std::vector<json_writer_details::json_writer_states>,
433 PolicyFlags...>( writer );
434 }
435 } // namespace DAW_JSON_VER
436} // 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_string(T const &value)
When outputting a class, uses default to_json.
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_key_value(daw::string_view name, char const (&str)[N])
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.
constexpr auto json_writer(WriterType &&writer)
DAW_CPP20_CX_ALLOC std::string to_json(Value const &value, options::output_flags_t< PolicyFlags... > flgs)
Definition daw_to_json.h:78
Customization point traits.
#define DAW_JSON_VER
The version string used in namespace definitions. Must be a valid namespace name.
Definition version.h:20