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 @@
...
@@ -3,6 +3,13 @@
All notable changes to this project will be documented in this file. The format
All notable changes to this project will be documented in this file. The format
is based on
[
Keep a Changelog
](
https://keepachangelog.com
)
.
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
## [0.19.0-rc.1] - 2020-10-31
### Added
### Added
...
...
libcaf_core/CMakeLists.txt
View file @
a3b6ddc5
...
@@ -161,7 +161,11 @@ caf_add_component(
...
@@ -161,7 +161,11 @@ caf_add_component(
src/ipv6_address.cpp
src/ipv6_address.cpp
src/ipv6_endpoint.cpp
src/ipv6_endpoint.cpp
src/ipv6_subnet.cpp
src/ipv6_subnet.cpp
src/json_array.cpp
src/json_builder.cpp
src/json_object.cpp
src/json_reader.cpp
src/json_reader.cpp
src/json_value.cpp
src/json_writer.cpp
src/json_writer.cpp
src/load_inspector.cpp
src/load_inspector.cpp
src/local_actor.cpp
src/local_actor.cpp
...
@@ -313,7 +317,11 @@ caf_add_component(
...
@@ -313,7 +317,11 @@ caf_add_component(
ipv6_address
ipv6_address
ipv6_endpoint
ipv6_endpoint
ipv6_subnet
ipv6_subnet
json_array
json_builder
json_object
json_reader
json_reader
json_value
json_writer
json_writer
load_inspector
load_inspector
logger
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:
...
@@ -55,20 +55,20 @@ public:
using
other
=
allocator
<
U
>
;
using
other
=
allocator
<
U
>
;
};
};
explicit
allocator
(
monotonic_buffer_resource
*
mbr
)
:
mbr_
(
mbr
)
{
constexpr
explicit
allocator
(
monotonic_buffer_resource
*
mbr
)
:
mbr_
(
mbr
)
{
// nop
// nop
}
}
allocator
()
:
mbr_
(
nullptr
)
{
constexpr
allocator
()
:
mbr_
(
nullptr
)
{
// nop
// nop
}
}
allocator
(
const
allocator
&
)
=
default
;
constexpr
allocator
(
const
allocator
&
)
=
default
;
allocator
&
operator
=
(
const
allocator
&
)
=
default
;
constexpr
allocator
&
operator
=
(
const
allocator
&
)
=
default
;
template
<
class
U
>
template
<
class
U
>
allocator
(
const
allocator
<
U
>&
other
)
:
mbr_
(
other
.
resource
())
{
constexpr
allocator
(
const
allocator
<
U
>&
other
)
:
mbr_
(
other
.
resource
())
{
// nop
// nop
}
}
...
...
libcaf_core/caf/fwd.hpp
View file @
a3b6ddc5
...
@@ -110,6 +110,11 @@ class ipv4_subnet;
...
@@ -110,6 +110,11 @@ class ipv4_subnet;
class
ipv6_address
;
class
ipv6_address
;
class
ipv6_endpoint
;
class
ipv6_endpoint
;
class
ipv6_subnet
;
class
ipv6_subnet
;
class
json_array
;
class
json_object
;
class
json_reader
;
class
json_value
;
class
json_writer
;
class
local_actor
;
class
local_actor
;
class
mailbox_element
;
class
mailbox_element
;
class
message
;
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:
...
@@ -133,6 +133,17 @@ public:
/// @note Implicitly calls `reset`.
/// @note Implicitly calls `reset`.
bool
load
(
std
::
string_view
json_text
);
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`.
/// Reverts the state of the reader back to where it was after calling `load`.
/// @post The reader is ready for attempting to deserialize another
/// @post The reader is ready for attempting to deserialize another
/// inspectable object.
/// 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:
...
@@ -210,7 +210,7 @@ private:
void
init
();
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
();
type
top
();
// Enters a new level of nesting.
// Enters a new level of nesting.
...
@@ -300,4 +300,12 @@ private:
...
@@ -300,4 +300,12 @@ private:
const
type_id_mapper
*
mapper_
=
&
default_mapper_
;
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
}
// namespace caf
libcaf_core/caf/parser_state.hpp
View file @
a3b6ddc5
...
@@ -16,6 +16,8 @@ namespace caf {
...
@@ -16,6 +16,8 @@ namespace caf {
/// Stores all information necessary for implementing an FSM-based parser.
/// Stores all information necessary for implementing an FSM-based parser.
template
<
class
Iterator
,
class
Sentinel
>
template
<
class
Iterator
,
class
Sentinel
>
struct
parser_state
{
struct
parser_state
{
using
iterator_type
=
Iterator
;
/// Current position of the parser.
/// Current position of the parser.
Iterator
i
;
Iterator
i
;
...
...
libcaf_core/caf/type_id.hpp
View file @
a3b6ddc5
...
@@ -405,7 +405,6 @@ CAF_BEGIN_TYPE_ID_BLOCK(core_module, 0)
...
@@ -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_string
))
CAF_ADD_TYPE_ID
(
core_module
,
(
caf
::
cow_u16string
))
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
::
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
::
down_msg
))
CAF_ADD_TYPE_ID
(
core_module
,
(
caf
::
error
))
CAF_ADD_TYPE_ID
(
core_module
,
(
caf
::
error
))
CAF_ADD_TYPE_ID
(
core_module
,
(
caf
::
exit_msg
))
CAF_ADD_TYPE_ID
(
core_module
,
(
caf
::
exit_msg
))
...
@@ -419,6 +418,9 @@ CAF_BEGIN_TYPE_ID_BLOCK(core_module, 0)
...
@@ -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_address
))
CAF_ADD_TYPE_ID
(
core_module
,
(
caf
::
ipv6_endpoint
))
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
::
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
))
CAF_ADD_TYPE_ID
(
core_module
,
(
caf
::
message_id
))
CAF_ADD_TYPE_ID
(
core_module
,
(
caf
::
message_id
))
CAF_ADD_TYPE_ID
(
core_module
,
(
caf
::
node_down_msg
))
CAF_ADD_TYPE_ID
(
core_module
,
(
caf
::
node_down_msg
))
...
@@ -426,6 +428,7 @@ CAF_BEGIN_TYPE_ID_BLOCK(core_module, 0)
...
@@ -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
::
none_t
))
CAF_ADD_TYPE_ID
(
core_module
,
(
caf
::
pec
))
CAF_ADD_TYPE_ID
(
core_module
,
(
caf
::
pec
))
CAF_ADD_TYPE_ID
(
core_module
,
(
caf
::
sec
))
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
::
shared_action_ptr
))
CAF_ADD_TYPE_ID
(
core_module
,
(
caf
::
stream
))
CAF_ADD_TYPE_ID
(
core_module
,
(
caf
::
stream
))
CAF_ADD_TYPE_ID
(
core_module
,
(
caf
::
stream_abort_msg
))
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 @@
...
@@ -21,6 +21,9 @@
#include "caf/ipv6_address.hpp"
#include "caf/ipv6_address.hpp"
#include "caf/ipv6_endpoint.hpp"
#include "caf/ipv6_endpoint.hpp"
#include "caf/ipv6_subnet.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.hpp"
#include "caf/message_id.hpp"
#include "caf/message_id.hpp"
#include "caf/node_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 @@
...
@@ -8,6 +8,8 @@
#include "caf/detail/print.hpp"
#include "caf/detail/print.hpp"
#include "caf/string_algorithms.hpp"
#include "caf/string_algorithms.hpp"
#include <fstream>
namespace
{
namespace
{
static
constexpr
const
char
class_name
[]
=
"caf::json_reader"
;
static
constexpr
const
char
class_name
[]
=
"caf::json_reader"
;
...
@@ -145,19 +147,41 @@ json_reader::~json_reader() {
...
@@ -145,19 +147,41 @@ json_reader::~json_reader() {
bool
json_reader
::
load
(
std
::
string_view
json_text
)
{
bool
json_reader
::
load
(
std
::
string_view
json_text
)
{
reset
();
reset
();
string_parser_state
ps
{
json_text
.
begin
(),
json_text
.
end
()};
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_
);
root_
=
detail
::
json
::
parse
(
ps
,
&
buf_
);
if
(
ps
.
code
!=
pec
::
success
)
{
if
(
ps
.
code
!=
pec
::
success
)
{
set_error
(
make_error
(
ps
));
set_error
(
make_error
(
ps
));
st_
=
nullptr
;
st_
=
nullptr
;
return
false
;
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
()
{
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 {
...
@@ -13,17 +13,9 @@ namespace {
static
constexpr
const
char
class_name
[]
=
"caf::json_writer"
;
static
constexpr
const
char
class_name
[]
=
"caf::json_writer"
;
constexpr
bool
can_morph
(
json_writer
::
type
from
,
json_writer
::
type
to
)
{
constexpr
std
::
string_view
json_type_names
[]
=
{
"element"
,
"object"
,
"member"
,
return
from
==
json_writer
::
type
::
element
&&
to
!=
json_writer
::
type
::
member
;
"array"
,
"string"
,
"number"
,
}
"bool"
,
"null"
};
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
)];
}
char
last_non_ws_char
(
const
std
::
vector
<
char
>&
buf
)
{
char
last_non_ws_char
(
const
std
::
vector
<
char
>&
buf
)
{
auto
not_ws
=
[](
char
c
)
{
return
!
std
::
isspace
(
c
);
};
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) {
...
@@ -104,7 +96,7 @@ bool json_writer::begin_object(type_id_t id, std::string_view name) {
pop
();
pop
();
return
true
;
return
true
;
};
};
if
(
inside_object
()
||
skip_object_type_annotation_
)
if
(
skip_object_type_annotation_
||
inside_object
()
)
return
begin_associative_array
(
0
);
return
begin_associative_array
(
0
);
else
else
return
begin_associative_array
(
0
)
// Put opening paren, ...
return
begin_associative_array
(
0
)
// Put opening paren, ...
...
@@ -140,7 +132,7 @@ bool json_writer::begin_field(std::string_view name, bool is_present) {
...
@@ -140,7 +132,7 @@ bool json_writer::begin_field(std::string_view name, bool is_present) {
return
true
;
return
true
;
default:
{
default:
{
std
::
string
str
=
"expected object, found "
;
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
));
emplace_error
(
sec
::
runtime_error
,
class_name
,
__func__
,
std
::
move
(
str
));
return
false
;
return
false
;
}
}
...
@@ -222,7 +214,7 @@ bool json_writer::begin_key_value_pair() {
...
@@ -222,7 +214,7 @@ bool json_writer::begin_key_value_pair() {
return
true
;
return
true
;
default:
{
default:
{
std
::
string
str
=
"expected object, found "
;
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
));
emplace_error
(
sec
::
runtime_error
,
class_name
,
__func__
,
std
::
move
(
str
));
return
false
;
return
false
;
}
}
...
@@ -489,12 +481,12 @@ bool json_writer::pop_if(type t) {
...
@@ -489,12 +481,12 @@ bool json_writer::pop_if(type t) {
return
true
;
return
true
;
}
else
{
}
else
{
std
::
string
str
=
"pop_if failed: expected "
;
std
::
string
str
=
"pop_if failed: expected "
;
str
+=
json_type_name
(
t
);
str
+=
as_
json_type_name
(
t
);
if
(
stack_
.
empty
())
{
if
(
stack_
.
empty
())
{
str
+=
", found an empty stack"
;
str
+=
", found an empty stack"
;
}
else
{
}
else
{
str
+=
", found "
;
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
));
emplace_error
(
sec
::
runtime_error
,
std
::
move
(
str
));
return
false
;
return
false
;
...
@@ -509,13 +501,13 @@ bool json_writer::pop_if_next(type t) {
...
@@ -509,13 +501,13 @@ bool json_writer::pop_if_next(type t) {
return
true
;
return
true
;
}
else
{
}
else
{
std
::
string
str
=
"pop_if_next failed: expected "
;
std
::
string
str
=
"pop_if_next failed: expected "
;
str
+=
json_type_name
(
t
);
str
+=
as_
json_type_name
(
t
);
if
(
stack_
.
size
()
<
2
)
{
if
(
stack_
.
size
()
<
2
)
{
str
+=
", found a stack of size "
;
str
+=
", found a stack of size "
;
detail
::
print
(
str
,
stack_
.
size
());
detail
::
print
(
str
,
stack_
.
size
());
}
else
{
}
else
{
str
+=
", found "
;
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
));
emplace_error
(
sec
::
runtime_error
,
std
::
move
(
str
));
return
false
;
return
false
;
...
@@ -536,9 +528,9 @@ bool json_writer::morph(type t, type& prev) {
...
@@ -536,9 +528,9 @@ bool json_writer::morph(type t, type& prev) {
return
true
;
return
true
;
}
else
{
}
else
{
std
::
string
str
=
"cannot convert "
;
std
::
string
str
=
"cannot convert "
;
str
+=
json_type_name
(
stack_
.
back
().
t
);
str
+=
as_
json_type_name
(
stack_
.
back
().
t
);
str
+=
" to "
;
str
+=
" to "
;
str
+=
json_type_name
(
t
);
str
+=
as_
json_type_name
(
t
);
emplace_error
(
sec
::
runtime_error
,
std
::
move
(
str
));
emplace_error
(
sec
::
runtime_error
,
std
::
move
(
str
));
return
false
;
return
false
;
}
}
...
@@ -555,7 +547,7 @@ void json_writer::unsafe_morph(type t) {
...
@@ -555,7 +547,7 @@ void json_writer::unsafe_morph(type t) {
void
json_writer
::
fail
(
type
t
)
{
void
json_writer
::
fail
(
type
t
)
{
std
::
string
str
=
"failed to write a "
;
std
::
string
str
=
"failed to write a "
;
str
+=
json_type_name
(
t
);
str
+=
as_
json_type_name
(
t
);
str
+=
": invalid position (begin/end mismatch?)"
;
str
+=
": invalid position (begin/end mismatch?)"
;
emplace_error
(
sec
::
runtime_error
,
std
::
move
(
str
));
emplace_error
(
sec
::
runtime_error
,
std
::
move
(
str
));
}
}
...
@@ -589,4 +581,10 @@ void json_writer::sep() {
...
@@ -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
}
// namespace caf
libcaf_core/test/core-test.hpp
View file @
a3b6ddc5
#pragma once
#pragma once
#include "caf/binary_deserializer.hpp"
#include "caf/binary_serializer.hpp"
#include "caf/byte_buffer.hpp"
#include "caf/cow_vector.hpp"
#include "caf/cow_vector.hpp"
#include "caf/fwd.hpp"
#include "caf/fwd.hpp"
#include "caf/result.hpp"
#include "caf/result.hpp"
...
@@ -13,6 +16,32 @@
...
@@ -13,6 +16,32 @@
#include <string>
#include <string>
#include <utility>
#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 ----------------------------
// -- forward declarations for all unit test suites ----------------------------
using
float_actor
=
caf
::
typed_actor
<
caf
::
result
<
void
>
(
float
)
>
;
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) {
...
@@ -106,6 +106,12 @@ void stringify(std::string& str, size_t, detail::json::null_t) {
str
+=
"null"
;
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
)
{
void
stringify
(
std
::
string
&
str
,
size_t
indent
,
const
detail
::
json
::
array
&
xs
)
{
if
(
xs
.
empty
())
{
if
(
xs
.
empty
())
{
str
+=
"[]"
;
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