Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
A
Actor Framework
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Metrics
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
cpp-libs
Actor Framework
Commits
a3b6ddc5
Commit
a3b6ddc5
authored
Nov 03, 2022
by
Dominik Charousset
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'topic/neverlord/json-api'
parents
7168be7a
c5bb6a65
Changes
28
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
28 changed files
with
3232 additions
and
84 deletions
+3232
-84
CHANGELOG.md
CHANGELOG.md
+7
-0
libcaf_core/CMakeLists.txt
libcaf_core/CMakeLists.txt
+8
-0
libcaf_core/caf/detail/json.hpp
libcaf_core/caf/detail/json.hpp
+766
-10
libcaf_core/caf/detail/monotonic_buffer_resource.hpp
libcaf_core/caf/detail/monotonic_buffer_resource.hpp
+5
-5
libcaf_core/caf/fwd.hpp
libcaf_core/caf/fwd.hpp
+5
-0
libcaf_core/caf/json.hpp
libcaf_core/caf/json.hpp
+12
-0
libcaf_core/caf/json_array.hpp
libcaf_core/caf/json_array.hpp
+174
-0
libcaf_core/caf/json_builder.hpp
libcaf_core/caf/json_builder.hpp
+244
-0
libcaf_core/caf/json_object.hpp
libcaf_core/caf/json_object.hpp
+178
-0
libcaf_core/caf/json_reader.hpp
libcaf_core/caf/json_reader.hpp
+11
-0
libcaf_core/caf/json_value.hpp
libcaf_core/caf/json_value.hpp
+185
-0
libcaf_core/caf/json_writer.hpp
libcaf_core/caf/json_writer.hpp
+9
-1
libcaf_core/caf/parser_state.hpp
libcaf_core/caf/parser_state.hpp
+2
-0
libcaf_core/caf/type_id.hpp
libcaf_core/caf/type_id.hpp
+4
-1
libcaf_core/src/detail/json.cpp
libcaf_core/src/detail/json.cpp
+287
-39
libcaf_core/src/init_global_meta_objects.cpp
libcaf_core/src/init_global_meta_objects.cpp
+3
-0
libcaf_core/src/json_array.cpp
libcaf_core/src/json_array.cpp
+15
-0
libcaf_core/src/json_builder.cpp
libcaf_core/src/json_builder.cpp
+504
-0
libcaf_core/src/json_object.cpp
libcaf_core/src/json_object.cpp
+26
-0
libcaf_core/src/json_reader.cpp
libcaf_core/src/json_reader.cpp
+31
-7
libcaf_core/src/json_value.cpp
libcaf_core/src/json_value.cpp
+146
-0
libcaf_core/src/json_writer.cpp
libcaf_core/src/json_writer.cpp
+19
-21
libcaf_core/test/core-test.hpp
libcaf_core/test/core-test.hpp
+29
-0
libcaf_core/test/detail/json.cpp
libcaf_core/test/detail/json.cpp
+6
-0
libcaf_core/test/json_array.cpp
libcaf_core/test/json_array.cpp
+67
-0
libcaf_core/test/json_builder.cpp
libcaf_core/test/json_builder.cpp
+152
-0
libcaf_core/test/json_object.cpp
libcaf_core/test/json_object.cpp
+74
-0
libcaf_core/test/json_value.cpp
libcaf_core/test/json_value.cpp
+263
-0
No files found.
CHANGELOG.md
View file @
a3b6ddc5
...
...
@@ -3,6 +3,13 @@
All notable changes to this project will be documented in this file. The format
is based on
[
Keep a Changelog
](
https://keepachangelog.com
)
.
## [Unreleased]
### Added
-
The new classes
`json_value`
,
`json_array`
and
`json_object`
allow working
with JSON inputs directly. Actors can also pass around JSON values safely.
## [0.19.0-rc.1] - 2020-10-31
### Added
...
...
libcaf_core/CMakeLists.txt
View file @
a3b6ddc5
...
...
@@ -161,7 +161,11 @@ caf_add_component(
src/ipv6_address.cpp
src/ipv6_endpoint.cpp
src/ipv6_subnet.cpp
src/json_array.cpp
src/json_builder.cpp
src/json_object.cpp
src/json_reader.cpp
src/json_value.cpp
src/json_writer.cpp
src/load_inspector.cpp
src/local_actor.cpp
...
...
@@ -313,7 +317,11 @@ caf_add_component(
ipv6_address
ipv6_endpoint
ipv6_subnet
json_array
json_builder
json_object
json_reader
json_value
json_writer
load_inspector
logger
...
...
libcaf_core/caf/detail/json.hpp
View file @
a3b6ddc5
This diff is collapsed.
Click to expand it.
libcaf_core/caf/detail/monotonic_buffer_resource.hpp
View file @
a3b6ddc5
...
...
@@ -55,20 +55,20 @@ public:
using
other
=
allocator
<
U
>
;
};
explicit
allocator
(
monotonic_buffer_resource
*
mbr
)
:
mbr_
(
mbr
)
{
constexpr
explicit
allocator
(
monotonic_buffer_resource
*
mbr
)
:
mbr_
(
mbr
)
{
// nop
}
allocator
()
:
mbr_
(
nullptr
)
{
constexpr
allocator
()
:
mbr_
(
nullptr
)
{
// nop
}
allocator
(
const
allocator
&
)
=
default
;
constexpr
allocator
(
const
allocator
&
)
=
default
;
allocator
&
operator
=
(
const
allocator
&
)
=
default
;
constexpr
allocator
&
operator
=
(
const
allocator
&
)
=
default
;
template
<
class
U
>
allocator
(
const
allocator
<
U
>&
other
)
:
mbr_
(
other
.
resource
())
{
constexpr
allocator
(
const
allocator
<
U
>&
other
)
:
mbr_
(
other
.
resource
())
{
// nop
}
...
...
libcaf_core/caf/fwd.hpp
View file @
a3b6ddc5
...
...
@@ -110,6 +110,11 @@ class ipv4_subnet;
class
ipv6_address
;
class
ipv6_endpoint
;
class
ipv6_subnet
;
class
json_array
;
class
json_object
;
class
json_reader
;
class
json_value
;
class
json_writer
;
class
local_actor
;
class
mailbox_element
;
class
message
;
...
...
libcaf_core/caf/json.hpp
0 → 100644
View file @
a3b6ddc5
// This file is part of CAF, the C++ Actor Framework. See the file LICENSE in
// the main distribution directory for license terms and copyright or visit
// https://github.com/actor-framework/actor-framework/blob/master/LICENSE.
#pragma once
#include "caf/json_array.hpp"
#include "caf/json_builder.hpp"
#include "caf/json_object.hpp"
#include "caf/json_reader.hpp"
#include "caf/json_value.hpp"
#include "caf/json_writer.hpp"
libcaf_core/caf/json_array.hpp
0 → 100644
View file @
a3b6ddc5
// This file is part of CAF, the C++ Actor Framework. See the file LICENSE in
// the main distribution directory for license terms and copyright or visit
// https://github.com/actor-framework/actor-framework/blob/master/LICENSE.
#pragma once
#include "caf/detail/core_export.hpp"
#include "caf/detail/json.hpp"
#include "caf/fwd.hpp"
#include "caf/json_value.hpp"
#include <iterator>
#include <memory>
namespace
caf
{
/// Represents a JSON array.
class
CAF_CORE_EXPORT
json_array
{
public:
// -- friends ----------------------------------------------------------------
friend
class
json_value
;
// -- member types -----------------------------------------------------------
class
const_iterator
{
public:
using
difference_type
=
ptrdiff_t
;
using
value_type
=
json_value
;
using
pointer
=
value_type
*
;
using
reference
=
value_type
&
;
using
iterator_category
=
std
::
forward_iterator_tag
;
const_iterator
(
detail
::
json
::
value
::
array
::
const_iterator
iter
,
detail
::
json
::
storage
*
storage
)
:
iter_
(
iter
),
storage_
(
storage
)
{
// nop
}
const_iterator
()
noexcept
:
storage_
(
nullptr
)
{
// nop
}
const_iterator
(
const
const_iterator
&
)
=
default
;
const_iterator
&
operator
=
(
const
const_iterator
&
)
=
default
;
json_value
value
()
const
noexcept
{
return
json_value
{
std
::
addressof
(
*
iter_
),
storage_
};
}
json_value
operator
*
()
const
noexcept
{
return
value
();
}
const_iterator
&
operator
++
()
noexcept
{
++
iter_
;
return
*
this
;
}
const_iterator
operator
++
(
int
)
noexcept
{
return
{
iter_
++
,
storage_
};
}
bool
equal_to
(
const
const_iterator
&
other
)
const
noexcept
{
return
iter_
==
other
.
iter_
;
}
private:
detail
::
json
::
value
::
array
::
const_iterator
iter_
;
detail
::
json
::
storage
*
storage_
;
};
// -- constructors, destructors, and assignment operators --------------------
json_array
()
noexcept
:
arr_
(
detail
::
json
::
empty_array
())
{
// nop
}
json_array
(
json_array
&&
)
noexcept
=
default
;
json_array
(
const
json_array
&
)
noexcept
=
default
;
json_array
&
operator
=
(
json_array
&&
)
noexcept
=
default
;
json_array
&
operator
=
(
const
json_array
&
)
noexcept
=
default
;
// -- properties -------------------------------------------------------------
/// Checks whether the array has no members.
bool
empty
()
const
noexcept
{
return
arr_
->
empty
();
}
/// Alias for @c empty.
bool
is_empty
()
const
noexcept
{
return
empty
();
}
/// Returns the number of key-value pairs in this array.
size_t
size
()
const
noexcept
{
return
arr_
->
size
();
}
const_iterator
begin
()
const
noexcept
{
return
{
arr_
->
begin
(),
storage_
.
get
()};
}
const_iterator
end
()
const
noexcept
{
return
{
arr_
->
end
(),
storage_
.
get
()};
}
// -- printing ---------------------------------------------------------------
template
<
class
Buffer
>
void
print_to
(
Buffer
&
buf
,
size_t
indentation_factor
=
0
)
const
{
detail
::
json
::
print_to
(
buf
,
*
arr_
,
indentation_factor
);
}
// -- serialization ----------------------------------------------------------
template
<
class
Inspector
>
friend
bool
inspect
(
Inspector
&
inspector
,
json_array
&
arr
)
{
if
constexpr
(
Inspector
::
is_loading
)
{
auto
storage
=
make_counted
<
detail
::
json
::
storage
>
();
auto
*
internal_arr
=
detail
::
json
::
make_array
(
storage
);
if
(
!
detail
::
json
::
load
(
inspector
,
*
internal_arr
,
storage
))
return
false
;
arr
=
json_array
{
internal_arr
,
std
::
move
(
storage
)};
return
true
;
}
else
{
return
detail
::
json
::
save
(
inspector
,
*
arr
.
arr_
);
}
}
private:
json_array
(
const
detail
::
json
::
value
::
array
*
obj
,
detail
::
json
::
storage_ptr
sptr
)
noexcept
:
arr_
(
obj
),
storage_
(
sptr
)
{
// nop
}
const
detail
::
json
::
value
::
array
*
arr_
=
nullptr
;
detail
::
json
::
storage_ptr
storage_
;
};
// -- free functions -----------------------------------------------------------
inline
bool
operator
==
(
const
json_array
::
const_iterator
&
lhs
,
const
json_array
::
const_iterator
&
rhs
)
noexcept
{
return
lhs
.
equal_to
(
rhs
);
}
inline
bool
operator
!=
(
const
json_array
::
const_iterator
&
lhs
,
const
json_array
::
const_iterator
&
rhs
)
noexcept
{
return
!
lhs
.
equal_to
(
rhs
);
}
inline
bool
operator
==
(
const
json_array
&
lhs
,
const
json_array
&
rhs
)
noexcept
{
return
std
::
equal
(
lhs
.
begin
(),
lhs
.
end
(),
rhs
.
begin
(),
rhs
.
end
());
}
inline
bool
operator
!=
(
const
json_array
&
lhs
,
const
json_array
&
rhs
)
noexcept
{
return
!
(
lhs
==
rhs
);
}
/// @relates json_array
CAF_CORE_EXPORT
std
::
string
to_string
(
const
json_array
&
arr
);
}
// namespace caf
libcaf_core/caf/json_builder.hpp
0 → 100644
View file @
a3b6ddc5
// This file is part of CAF, the C++ Actor Framework. See the file LICENSE in
// the main distribution directory for license terms and copyright or visit
// https://github.com/actor-framework/actor-framework/blob/master/LICENSE.
#pragma once
#include "caf/detail/core_export.hpp"
#include "caf/detail/json.hpp"
#include "caf/json_value.hpp"
#include "caf/json_writer.hpp"
#include "caf/serializer.hpp"
namespace
caf
{
/// Serializes an inspectable object to a @ref json_value.
class
json_builder
:
public
serializer
{
public:
// -- member types -----------------------------------------------------------
using
super
=
serializer
;
using
type
=
json_writer
::
type
;
// -- constructors, destructors, and assignment operators --------------------
json_builder
();
explicit
json_builder
(
actor_system
&
sys
);
explicit
json_builder
(
execution_unit
*
ctx
);
json_builder
(
const
json_builder
&
)
=
delete
;
json_builder
&
operator
=
(
const
json_builder
&
)
=
delete
;
~
json_builder
()
override
;
// -- properties -------------------------------------------------------------
/// Returns whether the writer omits empty fields entirely (true) or renders
/// empty fields as `$field: null` (false).
[[
nodiscard
]]
bool
skip_empty_fields
()
const
noexcept
{
return
skip_empty_fields_
;
}
/// Configures whether the writer omits empty fields.
void
skip_empty_fields
(
bool
value
)
noexcept
{
skip_empty_fields_
=
value
;
}
/// Returns whether the writer omits '@type' annotations for JSON objects.
[[
nodiscard
]]
bool
skip_object_type_annotation
()
const
noexcept
{
return
skip_object_type_annotation_
;
}
/// Configures whether the writer omits '@type' annotations for JSON objects.
void
skip_object_type_annotation
(
bool
value
)
noexcept
{
skip_object_type_annotation_
=
value
;
}
/// Returns the suffix for generating type annotation fields for variant
/// fields. For example, CAF inserts field called "@foo${field_type_suffix}"
/// for a variant field called "foo".
[[
nodiscard
]]
std
::
string_view
field_type_suffix
()
const
noexcept
{
return
field_type_suffix_
;
}
/// Configures whether the writer omits empty fields.
void
field_type_suffix
(
std
::
string_view
suffix
)
noexcept
{
field_type_suffix_
=
suffix
;
}
// -- modifiers --------------------------------------------------------------
/// Restores the writer to its initial state.
void
reset
();
/// Seals the JSON value, i.e., rendering it immutable, and returns it. After
/// calling this member function, the @ref json_builder is in a moved-from
/// state and users may only call @c reset to start a new building process or
/// destroy this instance.
json_value
seal
();
// -- overrides --------------------------------------------------------------
bool
begin_object
(
type_id_t
type
,
std
::
string_view
name
)
override
;
bool
end_object
()
override
;
bool
begin_field
(
std
::
string_view
)
override
;
bool
begin_field
(
std
::
string_view
name
,
bool
is_present
)
override
;
bool
begin_field
(
std
::
string_view
name
,
span
<
const
type_id_t
>
types
,
size_t
index
)
override
;
bool
begin_field
(
std
::
string_view
name
,
bool
is_present
,
span
<
const
type_id_t
>
types
,
size_t
index
)
override
;
bool
end_field
()
override
;
bool
begin_tuple
(
size_t
size
)
override
;
bool
end_tuple
()
override
;
bool
begin_key_value_pair
()
override
;
bool
end_key_value_pair
()
override
;
bool
begin_sequence
(
size_t
size
)
override
;
bool
end_sequence
()
override
;
bool
begin_associative_array
(
size_t
size
)
override
;
bool
end_associative_array
()
override
;
bool
value
(
std
::
byte
x
)
override
;
bool
value
(
bool
x
)
override
;
bool
value
(
int8_t
x
)
override
;
bool
value
(
uint8_t
x
)
override
;
bool
value
(
int16_t
x
)
override
;
bool
value
(
uint16_t
x
)
override
;
bool
value
(
int32_t
x
)
override
;
bool
value
(
uint32_t
x
)
override
;
bool
value
(
int64_t
x
)
override
;
bool
value
(
uint64_t
x
)
override
;
bool
value
(
float
x
)
override
;
bool
value
(
double
x
)
override
;
bool
value
(
long
double
x
)
override
;
bool
value
(
std
::
string_view
x
)
override
;
bool
value
(
const
std
::
u16string
&
x
)
override
;
bool
value
(
const
std
::
u32string
&
x
)
override
;
bool
value
(
span
<
const
std
::
byte
>
x
)
override
;
private:
// -- implementation details -------------------------------------------------
template
<
class
T
>
bool
number
(
T
);
using
key_type
=
std
::
string_view
;
// -- state management -------------------------------------------------------
void
init
();
// Returns the current top of the stack or `null` if empty.
type
top
();
// Returns the current top of the stack or `null` if empty.
template
<
class
T
=
detail
::
json
::
value
>
T
*
top_ptr
();
// Returns the current top-level object.
detail
::
json
::
object
*
top_obj
();
// Enters a new level of nesting.
void
push
(
detail
::
json
::
value
*
,
type
);
// Enters a new level of nesting with type member.
void
push
(
detail
::
json
::
value
::
member
*
);
// Enters a new level of nesting with type key.
void
push
(
key_type
*
);
// Backs up one level of nesting.
bool
pop
();
// Backs up one level of nesting but checks that current top is `t` before.
bool
pop_if
(
type
t
);
// Sets an error reason that the inspector failed to write a t.
void
fail
(
type
t
);
// Checks whether any element in the stack has the type `object`.
bool
inside_object
()
const
noexcept
;
// -- member variables -------------------------------------------------------
// Our output.
detail
::
json
::
value
*
val_
;
// Storage for the assembled output.
detail
::
json
::
storage_ptr
storage_
;
struct
entry
{
union
{
detail
::
json
::
value
*
val_ptr
;
detail
::
json
::
member
*
mem_ptr
;
key_type
*
key_ptr
;
};
type
t
;
entry
(
detail
::
json
::
value
*
ptr
,
type
ptr_type
)
noexcept
{
val_ptr
=
ptr
;
t
=
ptr_type
;
}
explicit
entry
(
detail
::
json
::
member
*
ptr
)
noexcept
{
mem_ptr
=
ptr
;
t
=
type
::
member
;
}
explicit
entry
(
key_type
*
ptr
)
noexcept
{
key_ptr
=
ptr
;
t
=
type
::
key
;
}
entry
(
const
entry
&
)
noexcept
=
default
;
entry
&
operator
=
(
const
entry
&
)
noexcept
=
default
;
};
// Bookkeeping for where we are in the current object.
std
::
vector
<
entry
>
stack_
;
// Configures whether we omit empty fields entirely (true) or render empty
// fields as `$field: null` (false).
bool
skip_empty_fields_
=
json_writer
::
skip_empty_fields_default
;
// Configures whether we omit the top-level '@type' annotation.
bool
skip_object_type_annotation_
=
false
;
std
::
string_view
field_type_suffix_
=
json_writer
::
field_type_suffix_default
;
};
}
// namespace caf
libcaf_core/caf/json_object.hpp
0 → 100644
View file @
a3b6ddc5
// This file is part of CAF, the C++ Actor Framework. See the file LICENSE in
// the main distribution directory for license terms and copyright or visit
// https://github.com/actor-framework/actor-framework/blob/master/LICENSE.
#pragma once
#include "caf/detail/core_export.hpp"
#include "caf/detail/json.hpp"
#include "caf/fwd.hpp"
#include "caf/json_value.hpp"
#include <iterator>
namespace
caf
{
/// Represents a JSON object.
class
CAF_CORE_EXPORT
json_object
{
public:
// -- friends ----------------------------------------------------------------
friend
class
json_value
;
// -- member types -----------------------------------------------------------
class
const_iterator
{
public:
using
difference_type
=
ptrdiff_t
;
using
value_type
=
std
::
pair
<
std
::
string_view
,
json_value
>
;
using
pointer
=
value_type
*
;
using
reference
=
value_type
&
;
using
iterator_category
=
std
::
forward_iterator_tag
;
const_iterator
(
detail
::
json
::
value
::
object
::
const_iterator
iter
,
detail
::
json
::
storage
*
storage
)
:
iter_
(
iter
),
storage_
(
storage
)
{
// nop
}
const_iterator
()
noexcept
=
default
;
const_iterator
(
const
const_iterator
&
)
=
default
;
const_iterator
&
operator
=
(
const
const_iterator
&
)
=
default
;
std
::
string_view
key
()
const
noexcept
{
return
iter_
->
key
;
}
json_value
value
()
const
noexcept
{
return
json_value
{
iter_
->
val
,
storage_
};
}
value_type
operator
*
()
const
noexcept
{
return
{
key
(),
value
()};
}
const_iterator
&
operator
++
()
noexcept
{
++
iter_
;
return
*
this
;
}
const_iterator
operator
++
(
int
)
noexcept
{
return
{
iter_
++
,
storage_
};
}
bool
equal_to
(
const
const_iterator
&
other
)
const
noexcept
{
return
iter_
==
other
.
iter_
;
}
private:
detail
::
json
::
value
::
object
::
const_iterator
iter_
;
detail
::
json
::
storage
*
storage_
=
nullptr
;
};
// -- constructors, destructors, and assignment operators --------------------
json_object
()
noexcept
:
obj_
(
detail
::
json
::
empty_object
())
{
// nop
}
json_object
(
json_object
&&
)
noexcept
=
default
;
json_object
(
const
json_object
&
)
noexcept
=
default
;
json_object
&
operator
=
(
json_object
&&
)
noexcept
=
default
;
json_object
&
operator
=
(
const
json_object
&
)
noexcept
=
default
;
// -- properties -------------------------------------------------------------
/// Checks whether the object has no members.
bool
empty
()
const
noexcept
{
return
!
obj_
||
obj_
->
empty
();
}
/// Alias for @c empty.
bool
is_empty
()
const
noexcept
{
return
empty
();
}
/// Returns the number of key-value pairs in this object.
size_t
size
()
const
noexcept
{
return
obj_
?
obj_
->
size
()
:
0u
;
}
/// Returns the value for @p key or an @c undefined value if the object does
/// not contain a value for @p key.
json_value
value
(
std
::
string_view
key
)
const
;
const_iterator
begin
()
const
noexcept
{
return
{
obj_
->
begin
(),
storage_
.
get
()};
}
const_iterator
end
()
const
noexcept
{
return
{
obj_
->
end
(),
storage_
.
get
()};
}
// -- printing ---------------------------------------------------------------
template
<
class
Buffer
>
void
print_to
(
Buffer
&
buf
,
size_t
indentation_factor
=
0
)
const
{
detail
::
json
::
print_to
(
buf
,
*
obj_
,
indentation_factor
);
}
// -- serialization ----------------------------------------------------------
template
<
class
Inspector
>
friend
bool
inspect
(
Inspector
&
inspector
,
json_object
&
obj
)
{
if
constexpr
(
Inspector
::
is_loading
)
{
auto
storage
=
make_counted
<
detail
::
json
::
storage
>
();
auto
*
internal_obj
=
detail
::
json
::
make_object
(
storage
);
if
(
!
detail
::
json
::
load
(
inspector
,
*
internal_obj
,
storage
))
return
false
;
obj
=
json_object
{
internal_obj
,
std
::
move
(
storage
)};
return
true
;
}
else
{
return
detail
::
json
::
save
(
inspector
,
*
obj
.
obj_
);
}
}
private:
json_object
(
const
detail
::
json
::
value
::
object
*
obj
,
detail
::
json
::
storage_ptr
sptr
)
noexcept
:
obj_
(
obj
),
storage_
(
sptr
)
{
// nop
}
const
detail
::
json
::
value
::
object
*
obj_
=
nullptr
;
detail
::
json
::
storage_ptr
storage_
;
};
inline
bool
operator
==
(
const
json_object
::
const_iterator
&
lhs
,
const
json_object
::
const_iterator
&
rhs
)
noexcept
{
return
lhs
.
equal_to
(
rhs
);
}
inline
bool
operator
!=
(
const
json_object
::
const_iterator
&
lhs
,
const
json_object
::
const_iterator
&
rhs
)
noexcept
{
return
!
lhs
.
equal_to
(
rhs
);
}
inline
bool
operator
==
(
const
json_object
&
lhs
,
const
json_object
&
rhs
)
noexcept
{
return
std
::
equal
(
lhs
.
begin
(),
lhs
.
end
(),
rhs
.
begin
(),
rhs
.
end
());
}
inline
bool
operator
!=
(
const
json_object
&
lhs
,
const
json_object
&
rhs
)
noexcept
{
return
!
(
lhs
==
rhs
);
}
/// @relates json_object
CAF_CORE_EXPORT
std
::
string
to_string
(
const
json_object
&
val
);
}
// namespace caf
libcaf_core/caf/json_reader.hpp
View file @
a3b6ddc5
...
...
@@ -133,6 +133,17 @@ public:
/// @note Implicitly calls `reset`.
bool
load
(
std
::
string_view
json_text
);
/// Parses the content of the file under the given @p path. After loading the
/// content of the JSON file, the reader is ready for attempting to
/// deserialize inspectable objects.
/// @note Implicitly calls `reset`.
bool
load_file
(
const
char
*
path
);
/// @copydoc load_file
bool
load_file
(
const
std
::
string
&
path
)
{
return
load_file
(
path
.
c_str
());
}
/// Reverts the state of the reader back to where it was after calling `load`.
/// @post The reader is ready for attempting to deserialize another
/// inspectable object.
...
...
libcaf_core/caf/json_value.hpp
0 → 100644
View file @
a3b6ddc5
// This file is part of CAF, the C++ Actor Framework. See the file LICENSE in
// the main distribution directory for license terms and copyright or visit
// https://github.com/actor-framework/actor-framework/blob/master/LICENSE.
#pragma once
#include "caf/detail/core_export.hpp"
#include "caf/detail/json.hpp"
#include "caf/fwd.hpp"
#include "caf/make_counted.hpp"
#include <string>
#include <string_view>
namespace
caf
{
/// Represents an immutable JSON value.
class
CAF_CORE_EXPORT
json_value
{
public:
// -- constructors, destructors, and assignment operators --------------------
json_value
()
noexcept
:
val_
(
detail
::
json
::
null_value
())
{
// nop
}
json_value
(
const
detail
::
json
::
value
*
val
,
detail
::
json
::
storage_ptr
sptr
)
noexcept
:
val_
(
val
),
storage_
(
sptr
)
{
// nop
}
json_value
(
json_value
&&
)
noexcept
=
default
;
json_value
(
const
json_value
&
)
noexcept
=
default
;
json_value
&
operator
=
(
json_value
&&
)
noexcept
=
default
;
json_value
&
operator
=
(
const
json_value
&
)
noexcept
=
default
;
// -- factories --------------------------------------------------------------
static
json_value
undefined
()
noexcept
{
return
json_value
{
detail
::
json
::
undefined_value
(),
nullptr
};
}
// -- properties -------------------------------------------------------------
/// Checks whether the value is @c null.
bool
is_null
()
const
noexcept
{
return
val_
->
is_null
();
}
/// Checks whether the value is undefined. This special state indicates that a
/// previous key lookup failed.
bool
is_undefined
()
const
noexcept
{
return
val_
->
is_undefined
();
}
/// Checks whether the value is an @c int64_t.
bool
is_integer
()
const
noexcept
{
return
val_
->
is_integer
();
}
/// Checks whether the value is a @c double.
bool
is_double
()
const
noexcept
{
return
val_
->
is_double
();
}
/// Checks whether the value is a number, i.e., an @c int64_t or a @c double.
bool
is_number
()
const
noexcept
{
return
is_integer
()
||
is_double
();
}
/// Checks whether the value is a @c bool.
bool
is_bool
()
const
noexcept
{
return
val_
->
is_bool
();
}
/// Checks whether the value is a JSON string (@c std::string_view).
bool
is_string
()
const
noexcept
{
return
val_
->
is_string
();
}
/// Checks whether the value is an JSON array.
bool
is_array
()
const
noexcept
{
return
val_
->
is_array
();
}
/// Checks whether the value is a JSON object.
bool
is_object
()
const
noexcept
{
return
val_
->
is_object
();
}
// -- conversion -------------------------------------------------------------
int64_t
to_integer
(
int64_t
fallback
=
0
)
const
;
double
to_double
(
double
fallback
=
0.0
)
const
;
bool
to_bool
(
bool
fallback
=
false
)
const
;
std
::
string_view
to_string
()
const
;
std
::
string_view
to_string
(
std
::
string_view
fallback
)
const
;
json_array
to_array
()
const
;
json_array
to_array
(
json_array
fallback
)
const
;
json_object
to_object
()
const
;
json_object
to_object
(
json_object
fallback
)
const
;
// -- comparison -------------------------------------------------------------
bool
equal_to
(
const
json_value
&
other
)
const
noexcept
;
// -- parsing ----------------------------------------------------------------
/// Attempts to parse @p str as JSON input into a self-contained value.
static
expected
<
json_value
>
parse
(
std
::
string_view
str
);
/// Attempts to parse @p str as JSON input into a value that avoids copies
/// where possible by pointing into @p str.
/// @warning The returned @ref json_value may hold pointers into @p str. Thus,
/// the input *must* outlive the @ref json_value and any other JSON
/// objects created from that value.
static
expected
<
json_value
>
parse_shallow
(
std
::
string_view
str
);
/// Attempts to parse @p str as JSON input. Decodes JSON in place and points
/// back into the @p str for all strings in the JSON input.
/// @warning The returned @ref json_value may hold pointers into @p str. Thus,
/// the input *must* outlive the @ref json_value and any other JSON
/// objects created from that value.
static
expected
<
json_value
>
parse_in_situ
(
std
::
string
&
str
);
/// Attempts to parse the content of the file at @p path as JSON input into a
/// self-contained value.
static
expected
<
json_value
>
parse_file
(
const
char
*
path
);
/// @copydoc parse_file
static
expected
<
json_value
>
parse_file
(
const
std
::
string
&
path
);
// -- printing ---------------------------------------------------------------
template
<
class
Buffer
>
void
print_to
(
Buffer
&
buf
,
size_t
indentation_factor
=
0
)
const
{
detail
::
json
::
print_to
(
buf
,
*
val_
,
indentation_factor
);
}
// -- serialization ----------------------------------------------------------
template
<
class
Inspector
>
friend
bool
inspect
(
Inspector
&
inspector
,
json_value
&
val
)
{
if
constexpr
(
Inspector
::
is_loading
)
{
auto
storage
=
make_counted
<
detail
::
json
::
storage
>
();
auto
*
internal_val
=
detail
::
json
::
make_value
(
storage
);
if
(
!
detail
::
json
::
load
(
inspector
,
*
internal_val
,
storage
))
return
false
;
val
=
json_value
{
internal_val
,
std
::
move
(
storage
)};
return
true
;
}
else
{
return
detail
::
json
::
save
(
inspector
,
*
val
.
val_
);
}
}
private:
const
detail
::
json
::
value
*
val_
;
detail
::
json
::
storage_ptr
storage_
;
};
// -- free functions -----------------------------------------------------------
inline
bool
operator
==
(
const
json_value
&
lhs
,
const
json_value
&
rhs
)
{
return
lhs
.
equal_to
(
rhs
);
}
inline
bool
operator
!=
(
const
json_value
&
lhs
,
const
json_value
&
rhs
)
{
return
!
(
lhs
==
rhs
);
}
/// @relates json_value
CAF_CORE_EXPORT
std
::
string
to_string
(
const
json_value
&
val
);
}
// namespace caf
libcaf_core/caf/json_writer.hpp
View file @
a3b6ddc5
...
...
@@ -210,7 +210,7 @@ private:
void
init
();
// Returns the current top of the stack or `null
_literal
` if empty.
// Returns the current top of the stack or `null` if empty.
type
top
();
// Enters a new level of nesting.
...
...
@@ -300,4 +300,12 @@ private:
const
type_id_mapper
*
mapper_
=
&
default_mapper_
;
};
/// @relates json_writer::type
CAF_CORE_EXPORT
std
::
string_view
as_json_type_name
(
json_writer
::
type
t
);
/// @relates json_writer::type
constexpr
bool
can_morph
(
json_writer
::
type
from
,
json_writer
::
type
to
)
{
return
from
==
json_writer
::
type
::
element
&&
to
!=
json_writer
::
type
::
member
;
}
}
// namespace caf
libcaf_core/caf/parser_state.hpp
View file @
a3b6ddc5
...
...
@@ -16,6 +16,8 @@ namespace caf {
/// Stores all information necessary for implementing an FSM-based parser.
template
<
class
Iterator
,
class
Sentinel
>
struct
parser_state
{
using
iterator_type
=
Iterator
;
/// Current position of the parser.
Iterator
i
;
...
...
libcaf_core/caf/type_id.hpp
View file @
a3b6ddc5
...
...
@@ -405,7 +405,6 @@ CAF_BEGIN_TYPE_ID_BLOCK(core_module, 0)
CAF_ADD_TYPE_ID
(
core_module
,
(
caf
::
cow_string
))
CAF_ADD_TYPE_ID
(
core_module
,
(
caf
::
cow_u16string
))
CAF_ADD_TYPE_ID
(
core_module
,
(
caf
::
cow_u32string
))
CAF_ADD_TYPE_ID
(
core_module
,
(
caf
::
dictionary
<
caf
::
config_value
>
)
)
CAF_ADD_TYPE_ID
(
core_module
,
(
caf
::
down_msg
))
CAF_ADD_TYPE_ID
(
core_module
,
(
caf
::
error
))
CAF_ADD_TYPE_ID
(
core_module
,
(
caf
::
exit_msg
))
...
...
@@ -419,6 +418,9 @@ CAF_BEGIN_TYPE_ID_BLOCK(core_module, 0)
CAF_ADD_TYPE_ID
(
core_module
,
(
caf
::
ipv6_address
))
CAF_ADD_TYPE_ID
(
core_module
,
(
caf
::
ipv6_endpoint
))
CAF_ADD_TYPE_ID
(
core_module
,
(
caf
::
ipv6_subnet
))
CAF_ADD_TYPE_ID
(
core_module
,
(
caf
::
json_array
))
CAF_ADD_TYPE_ID
(
core_module
,
(
caf
::
json_object
))
CAF_ADD_TYPE_ID
(
core_module
,
(
caf
::
json_value
))
CAF_ADD_TYPE_ID
(
core_module
,
(
caf
::
message
))
CAF_ADD_TYPE_ID
(
core_module
,
(
caf
::
message_id
))
CAF_ADD_TYPE_ID
(
core_module
,
(
caf
::
node_down_msg
))
...
...
@@ -426,6 +428,7 @@ CAF_BEGIN_TYPE_ID_BLOCK(core_module, 0)
CAF_ADD_TYPE_ID
(
core_module
,
(
caf
::
none_t
))
CAF_ADD_TYPE_ID
(
core_module
,
(
caf
::
pec
))
CAF_ADD_TYPE_ID
(
core_module
,
(
caf
::
sec
))
CAF_ADD_TYPE_ID
(
core_module
,
(
caf
::
settings
))
CAF_ADD_TYPE_ID
(
core_module
,
(
caf
::
shared_action_ptr
))
CAF_ADD_TYPE_ID
(
core_module
,
(
caf
::
stream
))
CAF_ADD_TYPE_ID
(
core_module
,
(
caf
::
stream_abort_msg
))
...
...
libcaf_core/src/detail/json.cpp
View file @
a3b6ddc5
This diff is collapsed.
Click to expand it.
libcaf_core/src/init_global_meta_objects.cpp
View file @
a3b6ddc5
...
...
@@ -21,6 +21,9 @@
#include "caf/ipv6_address.hpp"
#include "caf/ipv6_endpoint.hpp"
#include "caf/ipv6_subnet.hpp"
#include "caf/json_array.hpp"
#include "caf/json_object.hpp"
#include "caf/json_value.hpp"
#include "caf/message.hpp"
#include "caf/message_id.hpp"
#include "caf/node_id.hpp"
...
...
libcaf_core/src/json_array.cpp
0 → 100644
View file @
a3b6ddc5
// This file is part of CAF, the C++ Actor Framework. See the file LICENSE in
// the main distribution directory for license terms and copyright or visit
// https://github.com/actor-framework/actor-framework/blob/master/LICENSE.
#include "caf/json_array.hpp"
namespace
caf
{
std
::
string
to_string
(
const
json_array
&
arr
)
{
std
::
string
result
;
arr
.
print_to
(
result
);
return
result
;
}
}
// namespace caf
libcaf_core/src/json_builder.cpp
0 → 100644
View file @
a3b6ddc5
This diff is collapsed.
Click to expand it.
libcaf_core/src/json_object.cpp
0 → 100644
View file @
a3b6ddc5
// This file is part of CAF, the C++ Actor Framework. See the file LICENSE in
// the main distribution directory for license terms and copyright or visit
// https://github.com/actor-framework/actor-framework/blob/master/LICENSE.
#include "caf/json_object.hpp"
namespace
caf
{
// -- properties ---------------------------------------------------------------
json_value
json_object
::
value
(
std
::
string_view
key
)
const
{
auto
pred
=
[
key
](
const
auto
&
member
)
{
return
member
.
key
==
key
;
};
auto
i
=
std
::
find_if
(
obj_
->
begin
(),
obj_
->
end
(),
pred
);
if
(
i
!=
obj_
->
end
())
{
return
{
i
->
val
,
storage_
};
}
return
json_value
::
undefined
();
}
std
::
string
to_string
(
const
json_object
&
obj
)
{
std
::
string
result
;
obj
.
print_to
(
result
);
return
result
;
}
}
// namespace caf
libcaf_core/src/json_reader.cpp
View file @
a3b6ddc5
...
...
@@ -8,6 +8,8 @@
#include "caf/detail/print.hpp"
#include "caf/string_algorithms.hpp"
#include <fstream>
namespace
{
static
constexpr
const
char
class_name
[]
=
"caf::json_reader"
;
...
...
@@ -145,19 +147,41 @@ json_reader::~json_reader() {
bool
json_reader
::
load
(
std
::
string_view
json_text
)
{
reset
();
string_parser_state
ps
{
json_text
.
begin
(),
json_text
.
end
()};
root_
=
detail
::
json
::
parse_shallow
(
ps
,
&
buf_
);
if
(
ps
.
code
!=
pec
::
success
)
{
set_error
(
make_error
(
ps
));
st_
=
nullptr
;
return
false
;
}
err_
.
reset
();
detail
::
monotonic_buffer_resource
::
allocator
<
stack_type
>
alloc
{
&
buf_
};
st_
=
new
(
alloc
.
allocate
(
1
))
stack_type
(
stack_allocator
{
&
buf_
});
st_
->
reserve
(
16
);
st_
->
emplace_back
(
root_
);
return
true
;
}
bool
json_reader
::
load_file
(
const
char
*
path
)
{
using
iterator_t
=
std
::
istreambuf_iterator
<
char
>
;
reset
();
std
::
ifstream
input
{
path
};
if
(
!
input
.
is_open
())
{
emplace_error
(
sec
::
cannot_open_file
);
return
false
;
}
detail
::
json
::
file_parser_state
ps
{
iterator_t
{
input
},
iterator_t
{}};
root_
=
detail
::
json
::
parse
(
ps
,
&
buf_
);
if
(
ps
.
code
!=
pec
::
success
)
{
set_error
(
make_error
(
ps
));
st_
=
nullptr
;
return
false
;
}
else
{
err_
.
reset
();
detail
::
monotonic_buffer_resource
::
allocator
<
stack_type
>
alloc
{
&
buf_
};
st_
=
new
(
alloc
.
allocate
(
1
))
stack_type
(
stack_allocator
{
&
buf_
});
st_
->
reserve
(
16
);
st_
->
emplace_back
(
root_
);
return
true
;
}
err_
.
reset
();
detail
::
monotonic_buffer_resource
::
allocator
<
stack_type
>
alloc
{
&
buf_
};
st_
=
new
(
alloc
.
allocate
(
1
))
stack_type
(
stack_allocator
{
&
buf_
});
st_
->
reserve
(
16
);
st_
->
emplace_back
(
root_
);
return
true
;
}
void
json_reader
::
revert
()
{
...
...
libcaf_core/src/json_value.cpp
0 → 100644
View file @
a3b6ddc5
// This file is part of CAF, the C++ Actor Framework. See the file LICENSE in
// the main distribution directory for license terms and copyright or visit
// https://github.com/actor-framework/actor-framework/blob/master/LICENSE.
#include "caf/json_value.hpp"
#include "caf/expected.hpp"
#include "caf/json_array.hpp"
#include "caf/json_object.hpp"
#include "caf/make_counted.hpp"
#include "caf/parser_state.hpp"
#include <fstream>
namespace
caf
{
// -- conversion ---------------------------------------------------------------
int64_t
json_value
::
to_integer
(
int64_t
fallback
)
const
{
if
(
is_integer
())
{
return
std
::
get
<
int64_t
>
(
val_
->
data
);
}
if
(
is_double
())
{
return
static_cast
<
int64_t
>
(
std
::
get
<
double
>
(
val_
->
data
));
}
return
fallback
;
}
double
json_value
::
to_double
(
double
fallback
)
const
{
if
(
is_double
())
{
return
std
::
get
<
double
>
(
val_
->
data
);
}
if
(
is_integer
())
{
return
static_cast
<
double
>
(
std
::
get
<
int64_t
>
(
val_
->
data
));
}
return
fallback
;
}
bool
json_value
::
to_bool
(
bool
fallback
)
const
{
if
(
is_bool
())
{
return
std
::
get
<
bool
>
(
val_
->
data
);
}
return
fallback
;
}
std
::
string_view
json_value
::
to_string
()
const
{
return
to_string
(
std
::
string_view
{});
}
std
::
string_view
json_value
::
to_string
(
std
::
string_view
fallback
)
const
{
if
(
is_string
())
{
return
std
::
get
<
std
::
string_view
>
(
val_
->
data
);
}
return
fallback
;
}
json_object
json_value
::
to_object
()
const
{
return
to_object
(
json_object
{});
}
json_object
json_value
::
to_object
(
json_object
fallback
)
const
{
if
(
is_object
())
{
return
json_object
{
&
std
::
get
<
detail
::
json
::
object
>
(
val_
->
data
),
storage_
};
}
return
fallback
;
}
json_array
json_value
::
to_array
()
const
{
return
to_array
(
json_array
{});
}
json_array
json_value
::
to_array
(
json_array
fallback
)
const
{
if
(
is_array
())
{
return
json_array
{
&
std
::
get
<
detail
::
json
::
array
>
(
val_
->
data
),
storage_
};
}
return
fallback
;
}
// -- comparison ---------------------------------------------------------------
bool
json_value
::
equal_to
(
const
json_value
&
other
)
const
noexcept
{
if
(
val_
==
other
.
val_
)
{
return
true
;
}
if
(
val_
!=
nullptr
&&
other
.
val_
!=
nullptr
)
{
return
*
val_
==
*
other
.
val_
;
}
return
false
;
}
// -- parsing ------------------------------------------------------------------
expected
<
json_value
>
json_value
::
parse
(
std
::
string_view
str
)
{
auto
storage
=
make_counted
<
detail
::
json
::
storage
>
();
string_parser_state
ps
{
str
.
begin
(),
str
.
end
()};
auto
root
=
detail
::
json
::
parse
(
ps
,
&
storage
->
buf
);
if
(
ps
.
code
==
pec
::
success
)
return
{
json_value
{
root
,
std
::
move
(
storage
)}};
return
{
make_error
(
ps
)};
}
expected
<
json_value
>
json_value
::
parse_shallow
(
std
::
string_view
str
)
{
auto
storage
=
make_counted
<
detail
::
json
::
storage
>
();
string_parser_state
ps
{
str
.
begin
(),
str
.
end
()};
auto
root
=
detail
::
json
::
parse_shallow
(
ps
,
&
storage
->
buf
);
if
(
ps
.
code
==
pec
::
success
)
return
{
json_value
{
root
,
std
::
move
(
storage
)}};
return
{
make_error
(
ps
)};
}
expected
<
json_value
>
json_value
::
parse_in_situ
(
std
::
string
&
str
)
{
auto
storage
=
make_counted
<
detail
::
json
::
storage
>
();
detail
::
json
::
mutable_string_parser_state
ps
{
str
.
data
(),
str
.
data
()
+
str
.
size
()};
auto
root
=
detail
::
json
::
parse_in_situ
(
ps
,
&
storage
->
buf
);
if
(
ps
.
code
==
pec
::
success
)
return
{
json_value
{
root
,
std
::
move
(
storage
)}};
return
{
make_error
(
ps
)};
}
expected
<
json_value
>
json_value
::
parse_file
(
const
char
*
path
)
{
using
iterator_t
=
std
::
istreambuf_iterator
<
char
>
;
std
::
ifstream
input
{
path
};
if
(
!
input
.
is_open
())
return
make_error
(
sec
::
cannot_open_file
);
auto
storage
=
make_counted
<
detail
::
json
::
storage
>
();
detail
::
json
::
file_parser_state
ps
{
iterator_t
{
input
},
iterator_t
{}};
auto
root
=
detail
::
json
::
parse
(
ps
,
&
storage
->
buf
);
if
(
ps
.
code
==
pec
::
success
)
return
{
json_value
{
root
,
std
::
move
(
storage
)}};
return
{
make_error
(
ps
)};
}
expected
<
json_value
>
json_value
::
parse_file
(
const
std
::
string
&
path
)
{
return
parse_file
(
path
.
c_str
());
}
// -- free functions -----------------------------------------------------------
std
::
string
to_string
(
const
json_value
&
val
)
{
std
::
string
result
;
val
.
print_to
(
result
);
return
result
;
}
}
// namespace caf
libcaf_core/src/json_writer.cpp
View file @
a3b6ddc5
...
...
@@ -13,17 +13,9 @@ namespace {
static
constexpr
const
char
class_name
[]
=
"caf::json_writer"
;
constexpr
bool
can_morph
(
json_writer
::
type
from
,
json_writer
::
type
to
)
{
return
from
==
json_writer
::
type
::
element
&&
to
!=
json_writer
::
type
::
member
;
}
constexpr
const
char
*
json_type_names
[]
=
{
"element"
,
"object"
,
"member"
,
"array"
,
"string"
,
"number"
,
"bool"
,
"null"
};
constexpr
const
char
*
json_type_name
(
json_writer
::
type
t
)
{
return
json_type_names
[
static_cast
<
uint8_t
>
(
t
)];
}
constexpr
std
::
string_view
json_type_names
[]
=
{
"element"
,
"object"
,
"member"
,
"array"
,
"string"
,
"number"
,
"bool"
,
"null"
};
char
last_non_ws_char
(
const
std
::
vector
<
char
>&
buf
)
{
auto
not_ws
=
[](
char
c
)
{
return
!
std
::
isspace
(
c
);
};
...
...
@@ -104,7 +96,7 @@ bool json_writer::begin_object(type_id_t id, std::string_view name) {
pop
();
return
true
;
};
if
(
inside_object
()
||
skip_object_type_annotation_
)
if
(
skip_object_type_annotation_
||
inside_object
()
)
return
begin_associative_array
(
0
);
else
return
begin_associative_array
(
0
)
// Put opening paren, ...
...
...
@@ -140,7 +132,7 @@ bool json_writer::begin_field(std::string_view name, bool is_present) {
return
true
;
default:
{
std
::
string
str
=
"expected object, found "
;
str
+=
json_type_name
(
t
);
str
+=
as_
json_type_name
(
t
);
emplace_error
(
sec
::
runtime_error
,
class_name
,
__func__
,
std
::
move
(
str
));
return
false
;
}
...
...
@@ -222,7 +214,7 @@ bool json_writer::begin_key_value_pair() {
return
true
;
default:
{
std
::
string
str
=
"expected object, found "
;
str
+=
json_type_name
(
t
);
str
+=
as_
json_type_name
(
t
);
emplace_error
(
sec
::
runtime_error
,
class_name
,
__func__
,
std
::
move
(
str
));
return
false
;
}
...
...
@@ -489,12 +481,12 @@ bool json_writer::pop_if(type t) {
return
true
;
}
else
{
std
::
string
str
=
"pop_if failed: expected "
;
str
+=
json_type_name
(
t
);
str
+=
as_
json_type_name
(
t
);
if
(
stack_
.
empty
())
{
str
+=
", found an empty stack"
;
}
else
{
str
+=
", found "
;
str
+=
json_type_name
(
stack_
.
back
().
t
);
str
+=
as_
json_type_name
(
stack_
.
back
().
t
);
}
emplace_error
(
sec
::
runtime_error
,
std
::
move
(
str
));
return
false
;
...
...
@@ -509,13 +501,13 @@ bool json_writer::pop_if_next(type t) {
return
true
;
}
else
{
std
::
string
str
=
"pop_if_next failed: expected "
;
str
+=
json_type_name
(
t
);
str
+=
as_
json_type_name
(
t
);
if
(
stack_
.
size
()
<
2
)
{
str
+=
", found a stack of size "
;
detail
::
print
(
str
,
stack_
.
size
());
}
else
{
str
+=
", found "
;
str
+=
json_type_name
(
stack_
[
stack_
.
size
()
-
2
].
t
);
str
+=
as_
json_type_name
(
stack_
[
stack_
.
size
()
-
2
].
t
);
}
emplace_error
(
sec
::
runtime_error
,
std
::
move
(
str
));
return
false
;
...
...
@@ -536,9 +528,9 @@ bool json_writer::morph(type t, type& prev) {
return
true
;
}
else
{
std
::
string
str
=
"cannot convert "
;
str
+=
json_type_name
(
stack_
.
back
().
t
);
str
+=
as_
json_type_name
(
stack_
.
back
().
t
);
str
+=
" to "
;
str
+=
json_type_name
(
t
);
str
+=
as_
json_type_name
(
t
);
emplace_error
(
sec
::
runtime_error
,
std
::
move
(
str
));
return
false
;
}
...
...
@@ -555,7 +547,7 @@ void json_writer::unsafe_morph(type t) {
void
json_writer
::
fail
(
type
t
)
{
std
::
string
str
=
"failed to write a "
;
str
+=
json_type_name
(
t
);
str
+=
as_
json_type_name
(
t
);
str
+=
": invalid position (begin/end mismatch?)"
;
emplace_error
(
sec
::
runtime_error
,
std
::
move
(
str
));
}
...
...
@@ -589,4 +581,10 @@ void json_writer::sep() {
}
}
// -- free functions -----------------------------------------------------------
std
::
string_view
as_json_type_name
(
json_writer
::
type
t
)
{
return
json_type_names
[
static_cast
<
uint8_t
>
(
t
)];
}
}
// namespace caf
libcaf_core/test/core-test.hpp
View file @
a3b6ddc5
#pragma once
#include "caf/binary_deserializer.hpp"
#include "caf/binary_serializer.hpp"
#include "caf/byte_buffer.hpp"
#include "caf/cow_vector.hpp"
#include "caf/fwd.hpp"
#include "caf/result.hpp"
...
...
@@ -13,6 +16,32 @@
#include <string>
#include <utility>
// -- utility for testing serialization round-trips ----------------------------
template
<
class
T
>
T
deep_copy
(
const
T
&
val
)
{
using
namespace
std
::
literals
;
caf
::
byte_buffer
buf
;
{
caf
::
binary_serializer
sink
{
nullptr
,
buf
};
if
(
!
sink
.
apply
(
val
))
{
auto
msg
=
"serialization failed in deep_copy: "
s
;
msg
+=
to_string
(
sink
.
get_error
());
CAF_RAISE_ERROR
(
msg
.
c_str
());
}
}
auto
result
=
T
{};
{
caf
::
binary_deserializer
sink
{
nullptr
,
buf
};
if
(
!
sink
.
apply
(
result
))
{
auto
msg
=
"deserialization failed in deep_copy: "
s
;
msg
+=
to_string
(
sink
.
get_error
());
CAF_RAISE_ERROR
(
msg
.
c_str
());
}
}
return
result
;
}
// -- forward declarations for all unit test suites ----------------------------
using
float_actor
=
caf
::
typed_actor
<
caf
::
result
<
void
>
(
float
)
>
;
...
...
libcaf_core/test/detail/json.cpp
View file @
a3b6ddc5
...
...
@@ -106,6 +106,12 @@ void stringify(std::string& str, size_t, detail::json::null_t) {
str
+=
"null"
;
}
void
stringify
(
std
::
string
&
str
,
size_t
,
detail
::
json
::
undefined_t
)
{
// The parser never emits undefined objects, but we still need to provide an
// overload for this type.
str
+=
"null"
;
}
void
stringify
(
std
::
string
&
str
,
size_t
indent
,
const
detail
::
json
::
array
&
xs
)
{
if
(
xs
.
empty
())
{
str
+=
"[]"
;
...
...
libcaf_core/test/json_array.cpp
0 → 100644
View file @
a3b6ddc5
// This file is part of CAF, the C++ Actor Framework. See the file LICENSE in
// the main distribution directory for license terms and copyright or visit
// https://github.com/actor-framework/actor-framework/blob/master/LICENSE.
#define CAF_SUITE json_array
#include "caf/json_array.hpp"
#include "core-test.hpp"
#include "caf/json_array.hpp"
#include "caf/json_value.hpp"
using
namespace
caf
;
using
namespace
std
::
literals
;
namespace
{
std
::
string
printed
(
const
json_array
&
arr
)
{
std
::
string
result
;
arr
.
print_to
(
result
,
2
);
return
result
;
}
}
// namespace
TEST_CASE
(
"default-constructed"
)
{
auto
arr
=
json_array
{};
CHECK
(
arr
.
empty
());
CHECK
(
arr
.
is_empty
());
CHECK
(
arr
.
begin
()
==
arr
.
end
());
CHECK_EQ
(
arr
.
size
(),
0u
);
CHECK_EQ
(
to_string
(
arr
),
"[]"
);
CHECK_EQ
(
printed
(
arr
),
"[]"
);
CHECK_EQ
(
deep_copy
(
arr
),
arr
);
}
TEST_CASE
(
"from empty array"
)
{
auto
arr
=
json_value
::
parse
(
"[]"
)
->
to_array
();
CHECK
(
arr
.
empty
());
CHECK
(
arr
.
is_empty
());
CHECK
(
arr
.
begin
()
==
arr
.
end
());
CHECK_EQ
(
arr
.
size
(),
0u
);
CHECK_EQ
(
to_string
(
arr
),
"[]"
);
CHECK_EQ
(
printed
(
arr
),
"[]"
);
CHECK_EQ
(
deep_copy
(
arr
),
arr
);
}
TEST_CASE
(
"from non-empty array"
)
{
auto
arr
=
json_value
::
parse
(
R"_([1, "two", 3.0])_"
)
->
to_array
();
CHECK
(
!
arr
.
empty
());
CHECK
(
!
arr
.
is_empty
());
CHECK
(
arr
.
begin
()
!=
arr
.
end
());
REQUIRE_EQ
(
arr
.
size
(),
3u
);
CHECK_EQ
((
*
arr
.
begin
()).
to_integer
(),
1
);
std
::
vector
<
json_value
>
vals
;
for
(
const
auto
&
val
:
arr
)
{
vals
.
emplace_back
(
val
);
}
REQUIRE_EQ
(
vals
.
size
(),
3u
);
CHECK_EQ
(
vals
[
0
].
to_integer
(),
1
);
CHECK_EQ
(
vals
[
1
].
to_string
(),
"two"
);
CHECK_EQ
(
vals
[
2
].
to_double
(),
3.0
);
CHECK_EQ
(
to_string
(
arr
),
R"_([1, "two", 3])_"
);
CHECK_EQ
(
printed
(
arr
),
"[
\n
1,
\n
\"
two
\"
,
\n
3
\n
]"
);
CHECK_EQ
(
deep_copy
(
arr
),
arr
);
}
libcaf_core/test/json_builder.cpp
0 → 100644
View file @
a3b6ddc5
// This file is part of CAF, the C++ Actor Framework. See the file LICENSE in
// the main distribution directory for license terms and copyright or visit
// https://github.com/actor-framework/actor-framework/blob/master/LICENSE.
#define CAF_SUITE json_builder
#include "caf/json_builder.hpp"
#include "core-test.hpp"
#include "caf/json_value.hpp"
#include <string_view>
using
namespace
caf
;
using
namespace
std
::
literals
;
namespace
{
struct
fixture
{
fixture
()
{
builder
.
skip_object_type_annotation
(
true
);
}
std
::
string
printed
(
const
json_value
&
val
,
size_t
indentation_factor
=
0
)
{
std
::
string
result
;
val
.
print_to
(
result
,
indentation_factor
);
return
result
;
}
json_builder
builder
;
};
}
// namespace
BEGIN_FIXTURE_SCOPE
(
fixture
)
TEST_CASE
(
"empty JSON value"
)
{
auto
val
=
builder
.
seal
();
CHECK
(
val
.
is_null
());
}
TEST_CASE
(
"integer"
)
{
CHECK
(
builder
.
value
(
int32_t
{
42
}));
auto
val
=
builder
.
seal
();
CHECK
(
val
.
is_integer
());
CHECK_EQ
(
val
.
to_integer
(),
42
);
}
TEST_CASE
(
"floating point"
)
{
CHECK
(
builder
.
value
(
4.2
));
auto
val
=
builder
.
seal
();
CHECK
(
val
.
is_double
());
CHECK_EQ
(
val
.
to_double
(),
4.2
);
}
TEST_CASE
(
"boolean"
)
{
CHECK
(
builder
.
value
(
true
));
auto
val
=
builder
.
seal
();
CHECK
(
val
.
is_bool
());
CHECK_EQ
(
val
.
to_bool
(),
true
);
}
TEST_CASE
(
"string"
)
{
CHECK
(
builder
.
value
(
"Hello, world!"
sv
));
auto
val
=
builder
.
seal
();
CHECK
(
val
.
is_string
());
CHECK_EQ
(
val
.
to_string
(),
"Hello, world!"
sv
);
}
TEST_CASE
(
"array"
)
{
auto
xs
=
std
::
vector
{
1
,
2
,
3
};
CHECK
(
builder
.
apply
(
xs
));
auto
val
=
builder
.
seal
();
CHECK
(
val
.
is_array
());
CHECK_EQ
(
printed
(
val
),
"[1, 2, 3]"
sv
);
}
TEST_CASE
(
"flat object"
)
{
auto
req
=
my_request
{
10
,
20
};
if
(
!
CHECK
(
builder
.
apply
(
req
)))
{
MESSAGE
(
"builder: "
<<
builder
.
get_error
());
}
auto
val
=
builder
.
seal
();
CHECK
(
val
.
is_object
());
CHECK_EQ
(
printed
(
val
),
R"_({"a": 10, "b": 20})_"
);
}
TEST_CASE
(
"flat object with type annotation"
)
{
builder
.
skip_object_type_annotation
(
false
);
auto
req
=
my_request
{
10
,
20
};
if
(
!
CHECK
(
builder
.
apply
(
req
)))
{
MESSAGE
(
"builder: "
<<
builder
.
get_error
());
}
auto
val
=
builder
.
seal
();
CHECK
(
val
.
is_object
());
CHECK_EQ
(
printed
(
val
),
R"_({"@type": "my_request", "a": 10, "b": 20})_"
);
}
namespace
{
constexpr
std
::
string_view
rect_str
=
R"_({
"top-left": {
"x": 10,
"y": 10
},
"bottom-right": {
"x": 20,
"y": 20
}
})_"
;
}
// namespace
TEST_CASE
(
"nested object"
)
{
auto
rect
=
rectangle
{{
10
,
10
},
{
20
,
20
}};
if
(
!
CHECK
(
builder
.
apply
(
rect
)))
{
MESSAGE
(
"builder: "
<<
builder
.
get_error
());
}
auto
val
=
builder
.
seal
();
CHECK
(
val
.
is_object
());
CHECK_EQ
(
printed
(
val
,
2
),
rect_str
);
}
namespace
{
constexpr
std
::
string_view
annotated_rect_str
=
R"_({
"@type": "rectangle",
"top-left": {
"x": 10,
"y": 10
},
"bottom-right": {
"x": 20,
"y": 20
}
})_"
;
}
// namespace
TEST_CASE
(
"nested object with type annotation"
)
{
builder
.
skip_object_type_annotation
(
false
);
auto
rect
=
rectangle
{{
10
,
10
},
{
20
,
20
}};
if
(
!
CHECK
(
builder
.
apply
(
rect
)))
{
MESSAGE
(
"builder: "
<<
builder
.
get_error
());
}
auto
val
=
builder
.
seal
();
CHECK
(
val
.
is_object
());
CHECK_EQ
(
printed
(
val
,
2
),
annotated_rect_str
);
}
END_FIXTURE_SCOPE
()
libcaf_core/test/json_object.cpp
0 → 100644
View file @
a3b6ddc5
// This file is part of CAF, the C++ Actor Framework. See the file LICENSE in
// the main distribution directory for license terms and copyright or visit
// https://github.com/actor-framework/actor-framework/blob/master/LICENSE.
#define CAF_SUITE json_object
#include "caf/json_object.hpp"
#include "core-test.hpp"
#include "caf/json_array.hpp"
#include "caf/json_value.hpp"
using
namespace
caf
;
using
namespace
std
::
literals
;
namespace
{
std
::
string
printed
(
const
json_object
&
obj
)
{
std
::
string
result
;
obj
.
print_to
(
result
,
2
);
return
result
;
}
}
// namespace
TEST_CASE
(
"default-constructed"
)
{
auto
obj
=
json_object
{};
CHECK
(
obj
.
empty
());
CHECK
(
obj
.
is_empty
());
CHECK
(
obj
.
begin
()
==
obj
.
end
());
CHECK_EQ
(
obj
.
size
(),
0u
);
CHECK
(
obj
.
value
(
"foo"
).
is_undefined
());
CHECK_EQ
(
to_string
(
obj
),
"{}"
);
CHECK_EQ
(
printed
(
obj
),
"{}"
);
CHECK_EQ
(
deep_copy
(
obj
),
obj
);
}
TEST_CASE
(
"from empty object"
)
{
auto
obj
=
json_value
::
parse
(
"{}"
)
->
to_object
();
CHECK
(
obj
.
empty
());
CHECK
(
obj
.
is_empty
());
CHECK
(
obj
.
begin
()
==
obj
.
end
());
CHECK_EQ
(
obj
.
size
(),
0u
);
CHECK
(
obj
.
value
(
"foo"
).
is_undefined
());
CHECK_EQ
(
to_string
(
obj
),
"{}"
);
CHECK_EQ
(
printed
(
obj
),
"{}"
);
CHECK_EQ
(
deep_copy
(
obj
),
obj
);
}
TEST_CASE
(
"from non-empty object"
)
{
auto
obj
=
json_value
::
parse
(
R"_({"a": "one", "b": 2})_"
)
->
to_object
();
CHECK
(
!
obj
.
empty
());
CHECK
(
!
obj
.
is_empty
());
CHECK
(
obj
.
begin
()
!=
obj
.
end
());
REQUIRE_EQ
(
obj
.
size
(),
2u
);
CHECK_EQ
(
obj
.
begin
().
key
(),
"a"
);
CHECK_EQ
(
obj
.
begin
().
value
().
to_string
(),
"one"
);
CHECK_EQ
(
obj
.
value
(
"a"
).
to_string
(),
"one"
);
CHECK_EQ
(
obj
.
value
(
"b"
).
to_integer
(),
2
);
CHECK
(
obj
.
value
(
"c"
).
is_undefined
());
std
::
vector
<
std
::
pair
<
std
::
string_view
,
json_value
>>
vals
;
for
(
const
auto
&
val
:
obj
)
{
vals
.
emplace_back
(
val
);
}
REQUIRE_EQ
(
vals
.
size
(),
2u
);
CHECK_EQ
(
vals
[
0
].
first
,
"a"
);
CHECK_EQ
(
vals
[
0
].
second
.
to_string
(),
"one"
);
CHECK_EQ
(
vals
[
1
].
first
,
"b"
);
CHECK_EQ
(
vals
[
1
].
second
.
to_integer
(),
2
);
CHECK_EQ
(
to_string
(
obj
),
R"_({"a": "one", "b": 2})_"
);
CHECK_EQ
(
printed
(
obj
),
"{
\n
\"
a
\"
:
\"
one
\"
,
\n
\"
b
\"
: 2
\n
}"
);
CHECK_EQ
(
deep_copy
(
obj
),
obj
);
}
libcaf_core/test/json_value.cpp
0 → 100644
View file @
a3b6ddc5
// This file is part of CAF, the C++ Actor Framework. See the file LICENSE in
// the main distribution directory for license terms and copyright or visit
// https://github.com/actor-framework/actor-framework/blob/master/LICENSE.
#define CAF_SUITE json_value
#include "caf/json_value.hpp"
#include "core-test.hpp"
#include "caf/binary_deserializer.hpp"
#include "caf/binary_serializer.hpp"
#include "caf/json_array.hpp"
#include "caf/json_object.hpp"
using
namespace
caf
;
using
namespace
std
::
literals
;
namespace
{
std
::
string
printed
(
const
json_value
&
val
)
{
std
::
string
result
;
val
.
print_to
(
result
,
2
);
return
result
;
}
}
// namespace
TEST_CASE
(
"default-constructed"
)
{
auto
val
=
json_value
{};
CHECK
(
val
.
is_null
());
CHECK
(
!
val
.
is_undefined
());
CHECK
(
!
val
.
is_integer
());
CHECK
(
!
val
.
is_integer
());
CHECK
(
!
val
.
is_double
());
CHECK
(
!
val
.
is_number
());
CHECK
(
!
val
.
is_bool
());
CHECK
(
!
val
.
is_string
());
CHECK
(
!
val
.
is_array
());
CHECK
(
!
val
.
is_object
());
CHECK_EQ
(
val
.
to_integer
(),
0
);
CHECK_EQ
(
val
.
to_double
(),
0.0
);
CHECK_EQ
(
val
.
to_bool
(),
false
);
CHECK_EQ
(
val
.
to_string
(),
""
sv
);
CHECK_EQ
(
val
.
to_object
().
size
(),
0u
);
CHECK_EQ
(
to_string
(
val
),
"null"
);
CHECK_EQ
(
printed
(
val
),
"null"
);
CHECK_EQ
(
deep_copy
(
val
),
val
);
}
TEST_CASE
(
"from undefined"
)
{
auto
val
=
json_value
::
undefined
();
CHECK
(
!
val
.
is_null
());
CHECK
(
val
.
is_undefined
());
CHECK
(
!
val
.
is_integer
());
CHECK
(
!
val
.
is_integer
());
CHECK
(
!
val
.
is_double
());
CHECK
(
!
val
.
is_number
());
CHECK
(
!
val
.
is_bool
());
CHECK
(
!
val
.
is_string
());
CHECK
(
!
val
.
is_array
());
CHECK
(
!
val
.
is_object
());
CHECK_EQ
(
val
.
to_integer
(),
0
);
CHECK_EQ
(
val
.
to_double
(),
0.0
);
CHECK_EQ
(
val
.
to_bool
(),
false
);
CHECK_EQ
(
val
.
to_string
(),
""
sv
);
CHECK_EQ
(
val
.
to_object
().
size
(),
0u
);
CHECK_EQ
(
to_string
(
val
),
"null"
);
CHECK_EQ
(
printed
(
val
),
"null"
);
CHECK_EQ
(
deep_copy
(
val
),
val
);
}
TEST_CASE
(
"from integer"
)
{
auto
val
=
unbox
(
json_value
::
parse
(
"42"
));
CHECK
(
!
val
.
is_null
());
CHECK
(
!
val
.
is_undefined
());
CHECK
(
val
.
is_integer
());
CHECK
(
!
val
.
is_double
());
CHECK
(
val
.
is_number
());
CHECK
(
!
val
.
is_bool
());
CHECK
(
!
val
.
is_string
());
CHECK
(
!
val
.
is_array
());
CHECK
(
!
val
.
is_object
());
CHECK_EQ
(
val
.
to_integer
(),
42
);
CHECK_EQ
(
val
.
to_double
(),
42.0
);
CHECK_EQ
(
val
.
to_bool
(),
false
);
CHECK_EQ
(
val
.
to_string
(),
""
sv
);
CHECK_EQ
(
val
.
to_object
().
size
(),
0u
);
CHECK_EQ
(
to_string
(
val
),
"42"
);
CHECK_EQ
(
printed
(
val
),
"42"
);
CHECK_EQ
(
deep_copy
(
val
),
val
);
}
TEST_CASE
(
"from double"
)
{
auto
val
=
unbox
(
json_value
::
parse
(
"42.0"
));
CHECK
(
!
val
.
is_null
());
CHECK
(
!
val
.
is_undefined
());
CHECK
(
!
val
.
is_integer
());
CHECK
(
val
.
is_double
());
CHECK
(
val
.
is_number
());
CHECK
(
!
val
.
is_bool
());
CHECK
(
!
val
.
is_string
());
CHECK
(
!
val
.
is_array
());
CHECK
(
!
val
.
is_object
());
CHECK_EQ
(
val
.
to_integer
(),
42
);
CHECK_EQ
(
val
.
to_double
(),
42.0
);
CHECK_EQ
(
val
.
to_bool
(),
false
);
CHECK_EQ
(
val
.
to_string
(),
""
sv
);
CHECK_EQ
(
val
.
to_object
().
size
(),
0u
);
CHECK_EQ
(
to_string
(
val
),
"42"
);
CHECK_EQ
(
printed
(
val
),
"42"
);
CHECK_EQ
(
deep_copy
(
val
),
val
);
}
TEST_CASE
(
"from bool"
)
{
auto
val
=
unbox
(
json_value
::
parse
(
"true"
));
CHECK
(
!
val
.
is_null
());
CHECK
(
!
val
.
is_undefined
());
CHECK
(
!
val
.
is_integer
());
CHECK
(
!
val
.
is_double
());
CHECK
(
!
val
.
is_number
());
CHECK
(
val
.
is_bool
());
CHECK
(
!
val
.
is_string
());
CHECK
(
!
val
.
is_array
());
CHECK
(
!
val
.
is_object
());
CHECK_EQ
(
val
.
to_integer
(),
0
);
CHECK_EQ
(
val
.
to_double
(),
0.0
);
CHECK_EQ
(
val
.
to_bool
(),
true
);
CHECK_EQ
(
val
.
to_string
(),
""
sv
);
CHECK_EQ
(
val
.
to_object
().
size
(),
0u
);
CHECK_EQ
(
to_string
(
val
),
"true"
);
CHECK_EQ
(
printed
(
val
),
"true"
);
CHECK_EQ
(
deep_copy
(
val
),
val
);
}
TEST_CASE
(
"from string"
)
{
auto
val
=
unbox
(
json_value
::
parse
(
R"_("Hello, world!")_"
));
CHECK
(
!
val
.
is_null
());
CHECK
(
!
val
.
is_undefined
());
CHECK
(
!
val
.
is_integer
());
CHECK
(
!
val
.
is_double
());
CHECK
(
!
val
.
is_number
());
CHECK
(
!
val
.
is_bool
());
CHECK
(
val
.
is_string
());
CHECK
(
!
val
.
is_array
());
CHECK
(
!
val
.
is_object
());
CHECK_EQ
(
val
.
to_integer
(),
0
);
CHECK_EQ
(
val
.
to_double
(),
0.0
);
CHECK_EQ
(
val
.
to_bool
(),
false
);
CHECK_EQ
(
val
.
to_string
(),
"Hello, world!"
sv
);
CHECK_EQ
(
val
.
to_object
().
size
(),
0u
);
CHECK_EQ
(
to_string
(
val
),
R"_("Hello, world!")_"
);
CHECK_EQ
(
printed
(
val
),
R"_("Hello, world!")_"
);
CHECK_EQ
(
deep_copy
(
val
),
val
);
}
TEST_CASE
(
"from empty array"
)
{
auto
val
=
unbox
(
json_value
::
parse
(
"[]"
));
CHECK
(
!
val
.
is_null
());
CHECK
(
!
val
.
is_undefined
());
CHECK
(
!
val
.
is_integer
());
CHECK
(
!
val
.
is_double
());
CHECK
(
!
val
.
is_number
());
CHECK
(
!
val
.
is_bool
());
CHECK
(
!
val
.
is_string
());
CHECK
(
val
.
is_array
());
CHECK
(
!
val
.
is_object
());
CHECK_EQ
(
val
.
to_integer
(),
0
);
CHECK_EQ
(
val
.
to_double
(),
0.0
);
CHECK_EQ
(
val
.
to_bool
(),
false
);
CHECK_EQ
(
val
.
to_string
(),
""
sv
);
CHECK_EQ
(
val
.
to_array
().
size
(),
0u
);
CHECK_EQ
(
val
.
to_object
().
size
(),
0u
);
CHECK_EQ
(
to_string
(
val
),
"[]"
);
CHECK_EQ
(
printed
(
val
),
"[]"
);
CHECK_EQ
(
deep_copy
(
val
),
val
);
}
TEST_CASE
(
"from array of size 1"
)
{
auto
val
=
unbox
(
json_value
::
parse
(
"[1]"
));
CHECK
(
!
val
.
is_null
());
CHECK
(
!
val
.
is_undefined
());
CHECK
(
!
val
.
is_integer
());
CHECK
(
!
val
.
is_double
());
CHECK
(
!
val
.
is_number
());
CHECK
(
!
val
.
is_bool
());
CHECK
(
!
val
.
is_string
());
CHECK
(
val
.
is_array
());
CHECK
(
!
val
.
is_object
());
CHECK_EQ
(
val
.
to_integer
(),
0
);
CHECK_EQ
(
val
.
to_double
(),
0.0
);
CHECK_EQ
(
val
.
to_bool
(),
false
);
CHECK_EQ
(
val
.
to_string
(),
""
sv
);
CHECK_EQ
(
val
.
to_array
().
size
(),
1u
);
CHECK_EQ
(
val
.
to_object
().
size
(),
0u
);
CHECK_EQ
(
to_string
(
val
),
"[1]"
);
CHECK_EQ
(
printed
(
val
),
"[
\n
1
\n
]"
);
CHECK_EQ
(
deep_copy
(
val
),
val
);
}
TEST_CASE
(
"from array of size 3"
)
{
auto
val
=
unbox
(
json_value
::
parse
(
"[1, 2, 3]"
));
CHECK
(
!
val
.
is_null
());
CHECK
(
!
val
.
is_undefined
());
CHECK
(
!
val
.
is_integer
());
CHECK
(
!
val
.
is_double
());
CHECK
(
!
val
.
is_number
());
CHECK
(
!
val
.
is_bool
());
CHECK
(
!
val
.
is_string
());
CHECK
(
val
.
is_array
());
CHECK
(
!
val
.
is_object
());
CHECK_EQ
(
val
.
to_integer
(),
0
);
CHECK_EQ
(
val
.
to_double
(),
0.0
);
CHECK_EQ
(
val
.
to_bool
(),
false
);
CHECK_EQ
(
val
.
to_string
(),
""
sv
);
CHECK_EQ
(
val
.
to_array
().
size
(),
3u
);
CHECK_EQ
(
val
.
to_object
().
size
(),
0u
);
CHECK_EQ
(
to_string
(
val
),
"[1, 2, 3]"
);
CHECK_EQ
(
printed
(
val
),
"[
\n
1,
\n
2,
\n
3
\n
]"
);
CHECK_EQ
(
deep_copy
(
val
),
val
);
}
TEST_CASE
(
"from empty object"
)
{
auto
val
=
unbox
(
json_value
::
parse
(
"{}"
));
CHECK
(
!
val
.
is_null
());
CHECK
(
!
val
.
is_undefined
());
CHECK
(
!
val
.
is_integer
());
CHECK
(
!
val
.
is_double
());
CHECK
(
!
val
.
is_number
());
CHECK
(
!
val
.
is_bool
());
CHECK
(
!
val
.
is_string
());
CHECK
(
!
val
.
is_array
());
CHECK
(
val
.
is_object
());
CHECK_EQ
(
val
.
to_integer
(),
0
);
CHECK_EQ
(
val
.
to_double
(),
0.0
);
CHECK_EQ
(
val
.
to_bool
(),
false
);
CHECK_EQ
(
val
.
to_string
(),
""
sv
);
CHECK_EQ
(
val
.
to_object
().
size
(),
0u
);
CHECK_EQ
(
to_string
(
val
),
"{}"
);
CHECK_EQ
(
printed
(
val
),
"{}"
);
CHECK_EQ
(
deep_copy
(
val
),
val
);
}
TEST_CASE
(
"from non-empty object"
)
{
auto
val
=
unbox
(
json_value
::
parse
(
R"_({"foo": "bar"})_"
));
CHECK
(
!
val
.
is_null
());
CHECK
(
!
val
.
is_undefined
());
CHECK
(
!
val
.
is_integer
());
CHECK
(
!
val
.
is_double
());
CHECK
(
!
val
.
is_number
());
CHECK
(
!
val
.
is_bool
());
CHECK
(
!
val
.
is_string
());
CHECK
(
!
val
.
is_array
());
CHECK
(
val
.
is_object
());
CHECK_EQ
(
val
.
to_integer
(),
0
);
CHECK_EQ
(
val
.
to_double
(),
0.0
);
CHECK_EQ
(
val
.
to_bool
(),
false
);
CHECK_EQ
(
val
.
to_string
(),
""
sv
);
CHECK_EQ
(
val
.
to_object
().
size
(),
1u
);
CHECK_EQ
(
to_string
(
val
),
R"_({"foo": "bar"})_"
);
CHECK_EQ
(
printed
(
val
),
"{
\n
\"
foo
\"
:
\"
bar
\"\n
}"
);
CHECK_EQ
(
deep_copy
(
val
),
val
);
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment