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
4bbccd70
Commit
4bbccd70
authored
Aug 02, 2020
by
Dominik Charousset
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Re-implement inspector_access
parent
4eae4034
Changes
12
Hide whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
1343 additions
and
298 deletions
+1343
-298
libcaf_core/CMakeLists.txt
libcaf_core/CMakeLists.txt
+1
-0
libcaf_core/caf/fwd.hpp
libcaf_core/caf/fwd.hpp
+2
-1
libcaf_core/caf/inspector_access.hpp
libcaf_core/caf/inspector_access.hpp
+471
-21
libcaf_core/caf/load_inspector.hpp
libcaf_core/caf/load_inspector.hpp
+80
-164
libcaf_core/caf/save_inspector.hpp
libcaf_core/caf/save_inspector.hpp
+62
-48
libcaf_core/caf/sec.hpp
libcaf_core/caf/sec.hpp
+8
-1
libcaf_core/caf/type_id.hpp
libcaf_core/caf/type_id.hpp
+4
-0
libcaf_core/test/core-test.hpp
libcaf_core/test/core-test.hpp
+1
-1
libcaf_core/test/load_inspector.cpp
libcaf_core/test/load_inspector.cpp
+204
-27
libcaf_core/test/nasty.cpp
libcaf_core/test/nasty.cpp
+54
-0
libcaf_core/test/nasty.hpp
libcaf_core/test/nasty.hpp
+273
-0
libcaf_core/test/save_inspector.cpp
libcaf_core/test/save_inspector.cpp
+183
-35
No files found.
libcaf_core/CMakeLists.txt
View file @
4bbccd70
...
...
@@ -198,6 +198,7 @@ endif()
add_executable
(
caf-core-test
test/core-test.cpp
test/nasty.cpp
$<TARGET_OBJECTS:libcaf_core_obj>
)
caf_core_set_default_properties
(
caf-core-test
)
...
...
libcaf_core/caf/fwd.hpp
View file @
4bbccd70
...
...
@@ -30,10 +30,10 @@ namespace caf {
// -- 1 param templates --------------------------------------------------------
template
<
class
>
class
[[
nodiscard
]]
error_code
;
template
<
class
>
class
behavior_type_of
;
template
<
class
>
class
dictionary
;
template
<
class
>
class
downstream
;
template
<
class
>
class
[[
nodiscard
]]
error_code
;
template
<
class
>
class
expected
;
template
<
class
>
class
intrusive_cow_ptr
;
template
<
class
>
class
intrusive_ptr
;
...
...
@@ -45,6 +45,7 @@ template <class> class stream_sink;
template
<
class
>
class
stream_source
;
template
<
class
>
class
weak_intrusive_ptr
;
template
<
class
>
struct
inspector_access
;
template
<
class
>
struct
timeout_definition
;
template
<
class
>
struct
type_id
;
...
...
libcaf_core/caf/inspector_access.hpp
View file @
4bbccd70
...
...
@@ -18,28 +18,202 @@
#pragma once
#include <tuple>
#include "caf/detail/inspect.hpp"
#include "caf/detail/type_list.hpp"
#include "caf/error.hpp"
#include "caf/fwd.hpp"
#include "caf/optional.hpp"
#include "caf/sec.hpp"
#include "caf/span.hpp"
#include "caf/sum_type_access.hpp"
#include "caf/variant.hpp"
namespace
caf
{
/// Customization point for adding support for a custom type. The default
/// implementation requires an `inspect` overload for `T` that is available via
/// ADL.
// -- utility function objects and functions for load and save inspectors ------
namespace
detail
{
/// Utility class for predicates that always return `true`.
struct
always_true_t
{
template
<
class
...
Ts
>
[[
nodiscard
]]
constexpr
bool
operator
()(
Ts
&&
...)
const
noexcept
{
return
true
;
}
};
/// Predicate that always returns `true`.
constexpr
auto
always_true
=
always_true_t
{};
/// Returns a mutable reference to `x`.
template
<
class
T
>
T
&
as_mutable_ref
(
T
&
x
)
{
return
x
;
}
/// Returns a mutable reference to `x`.
template
<
class
T
>
struct
inspector_access
{
T
&
as_mutable_ref
(
const
T
&
x
)
{
return
const_cast
<
T
&>
(
x
);
}
/// Checks whether the inspector has a `value` overload for `T`.
template
<
class
Inspector
,
class
T
>
class
is_trivially_inspectable
{
private:
template
<
class
U
>
static
auto
sfinae
(
Inspector
&
f
,
U
&
x
)
->
decltype
(
f
.
value
(
x
),
std
::
true_type
{});
static
std
::
false_type
sfinae
(
Inspector
&
,
...);
using
sfinae_result
=
decltype
(
sfinae
(
std
::
declval
<
Inspector
&>
(),
std
::
declval
<
T
&>
()));
public:
static
constexpr
bool
value
=
sfinae_result
::
value
;
};
}
// namespace detail
/// Calls `f.value(x)` if this is a valid expression,
/// `inspector_access<T>::apply_value(f, x)` otherwise.
template
<
class
Inspector
,
class
T
>
bool
inspect_value
(
Inspector
&
f
,
T
&
x
)
{
if
constexpr
(
detail
::
is_trivially_inspectable
<
Inspector
,
T
>::
value
)
{
return
f
.
value
(
x
);
}
else
{
return
inspector_access
<
T
>::
apply_value
(
f
,
x
);
}
}
/// @copydoc inspect_value
template
<
class
Inspector
,
class
T
>
bool
inspect_value
(
Inspector
&
f
,
const
T
&
x
)
{
if
constexpr
(
detail
::
is_trivially_inspectable
<
Inspector
,
T
>::
value
)
{
return
f
.
value
(
const_cast
<
T
&>
(
x
));
}
else
{
return
inspector_access
<
T
>::
apply_value
(
f
,
const_cast
<
T
&>
(
x
));
}
}
template
<
class
Inspector
,
class
Get
,
class
Set
>
bool
inspect_value
(
Inspector
&
f
,
Get
&&
get
,
Set
&&
set
)
{
using
value_type
=
std
::
decay_t
<
decltype
(
get
())
>
;
if
constexpr
(
Inspector
::
is_loading
)
{
auto
tmp
=
value_type
{};
if
(
inspect_value
(
f
,
tmp
))
return
set
(
std
::
move
(
tmp
));
return
false
;
}
else
{
auto
&&
x
=
get
();
return
inspect_value
(
f
,
detail
::
as_mutable_ref
(
x
));
}
}
/// Provides default implementations for `save_field`, `load_field`, and
/// `apply_value`.
template
<
class
T
>
struct
inspector_access_base
{
/// Saves a mandatory field to `f`.
template
<
class
Inspector
>
static
bool
apply
(
Inspector
&
f
,
T
&
x
)
{
static
bool
save_field
(
Inspector
&
f
,
string_view
field_name
,
T
&
x
)
{
return
f
.
begin_field
(
field_name
)
&&
inspect_value
(
f
,
x
)
&&
f
.
end_field
();
}
/// Saves an optional field to `f`.
template
<
class
Inspector
,
class
IsPresent
,
class
Get
>
static
bool
save_field
(
Inspector
&
f
,
string_view
field_name
,
IsPresent
&
is_present
,
Get
&
get
)
{
if
(
is_present
())
{
auto
&&
x
=
get
();
return
f
.
begin_field
(
field_name
,
true
)
//
&&
inspect_value
(
f
,
x
)
//
&&
f
.
end_field
();
}
return
f
.
begin_field
(
field_name
,
false
)
&&
f
.
end_field
();
}
/// Loads a mandatory field from `f`.
template
<
class
Inspector
,
class
IsValid
,
class
SyncValue
>
static
bool
load_field
(
Inspector
&
f
,
string_view
field_name
,
T
&
x
,
IsValid
&
is_valid
,
SyncValue
&
sync_value
)
{
if
(
f
.
begin_field
(
field_name
)
&&
inspect_value
(
f
,
x
))
{
if
(
!
is_valid
(
x
))
return
f
.
load_field_failed
(
field_name
,
sec
::
field_invariant_check_failed
);
if
(
!
sync_value
())
return
f
.
load_field_failed
(
field_name
,
sec
::
field_value_synchronization_failed
);
return
f
.
end_field
();
}
return
false
;
}
/// Loads an optional field from `f`, calling `set_fallback` if the source
/// contains no value for `x`.
template
<
class
Inspector
,
class
IsValid
,
class
SyncValue
,
class
SetFallback
>
static
bool
load_field
(
Inspector
&
f
,
string_view
field_name
,
T
&
x
,
IsValid
&
is_valid
,
SyncValue
&
sync_value
,
SetFallback
&
set_fallback
)
{
bool
is_present
=
false
;
if
(
!
f
.
begin_field
(
field_name
,
is_present
))
return
false
;
if
(
is_present
)
{
if
(
!
inspect_value
(
f
,
x
))
return
false
;
if
(
!
is_valid
(
x
))
return
f
.
load_field_failed
(
field_name
,
sec
::
field_invariant_check_failed
);
if
(
!
sync_value
())
return
f
.
load_field_failed
(
field_name
,
sec
::
field_value_synchronization_failed
);
return
f
.
end_field
();
}
set_fallback
();
return
f
.
end_field
();
}
};
/// Default implementation for @ref inspector_access.
template
<
class
T
>
struct
default_inspector_access
:
inspector_access_base
<
T
>
{
/// Applies `x` as an object to `f`.
template
<
class
Inspector
>
[[
nodiscard
]]
static
bool
apply_object
(
Inspector
&
f
,
T
&
x
)
{
using
detail
::
inspect
;
using
result_type
=
decltype
(
inspect
(
f
,
x
));
if
constexpr
(
std
::
is_same
<
result_type
,
bool
>::
value
)
return
inspect
(
f
,
x
);
else
return
apply_deprecated
(
f
,
x
);
// User-provided `inspect` overloads come first.
if
constexpr
(
detail
::
is_inspectable
<
Inspector
,
T
>::
value
)
{
using
result_type
=
decltype
(
inspect
(
f
,
x
));
if
constexpr
(
std
::
is_same
<
result_type
,
bool
>::
value
)
return
inspect
(
f
,
x
);
else
return
apply_deprecated
(
f
,
x
);
}
else
if
constexpr
(
Inspector
::
is_loading
)
{
return
load_object
(
f
,
x
);
}
else
{
return
save_object
(
f
,
x
);
}
}
/// Applies `x` as a single value to `f`.
template
<
class
Inspector
>
[[
nodiscard
]]
static
bool
apply_value
(
Inspector
&
f
,
T
&
x
)
{
return
apply_object
(
f
,
x
);
}
template
<
class
Inspector
>
[[
nodiscard
]]
static
bool
load_object
(
Inspector
&
f
,
T
&
x
)
{
if
constexpr
(
std
::
is_arithmetic
<
T
>::
value
)
{
return
f
.
object
(
x
).
fields
(
f
.
field
(
"value"
,
x
));
}
}
template
<
class
Inspector
>
[[
deprecated
(
"inspect() overloads should return bool"
)]]
static
bool
[[
deprecated
(
"inspect() overloads should return bool"
)]]
//
[[
nodiscard
]]
static
bool
apply_deprecated
(
Inspector
&
f
,
T
&
x
)
{
if
(
auto
err
=
inspect
(
f
,
x
))
{
f
.
set_error
(
std
::
move
(
err
));
...
...
@@ -49,23 +223,299 @@ struct inspector_access {
}
};
/// Customization point to influence how inspectors treat fields of type `T`.
/// Customization point for adding support for a custom type. The default
/// implementation requires an `inspect` overload for `T` that is available via
/// ADL.
template
<
class
T
>
struct
inspector_access_traits
{
static
constexpr
bool
is_optional
=
false
;
static
constexpr
bool
is_sum_type
=
false
;
struct
inspector_access
:
default_inspector_access
<
T
>
{};
template
<
class
...
Ts
>
struct
inspector_access
<
std
::
tuple
<
Ts
...
>>
{
// -- boilerplate ------------------------------------------------------------
using
value_type
=
std
::
tuple
<
Ts
...
>
;
using
tuple_indexes
=
std
::
make_index_sequence
<
sizeof
...(
Ts
)
>
;
template
<
class
Inspector
>
static
bool
apply_object
(
Inspector
&
f
,
value_type
&
x
)
{
return
f
.
object
(
x
).
fields
(
f
.
field
(
"value"
,
x
));
}
template
<
class
Inspector
>
static
bool
apply_value
(
Inspector
&
f
,
value_type
&
x
)
{
return
apply_object
(
f
,
x
);
}
// -- saving -----------------------------------------------------------------
template
<
class
Inspector
,
class
IsPresent
,
class
Get
,
size_t
...
Is
>
static
bool
save_field
(
Inspector
&
f
,
string_view
field_name
,
IsPresent
&&
is_present
,
Get
&&
get
,
std
::
index_sequence
<
Is
...
>
)
{
if
(
is_present
())
{
auto
&&
x
=
get
();
return
f
.
begin_field
(
field_name
,
true
)
//
&&
f
.
begin_tuple
(
sizeof
...(
Ts
))
//
&&
(
inspect_value
(
f
,
std
::
get
<
Is
>
(
x
))
&&
...)
//
&&
f
.
end_tuple
()
//
&&
f
.
end_field
();
}
else
{
return
f
.
begin_field
(
field_name
,
false
)
&&
f
.
end_field
();
}
}
template
<
class
Inspector
,
class
IsPresent
,
class
Get
>
static
bool
save_field
(
Inspector
&
f
,
string_view
field_name
,
IsPresent
&&
is_present
,
Get
&&
get
)
{
return
save_field
(
f
,
field_name
,
std
::
forward
<
IsPresent
>
(
is_present
),
std
::
forward
<
Get
>
(
get
),
tuple_indexes
{});
}
template
<
class
Inspector
,
size_t
...
Is
>
static
bool
save_field
(
Inspector
&
f
,
string_view
field_name
,
value_type
&
x
,
std
::
index_sequence
<
Is
...
>
)
{
return
f
.
begin_field
(
field_name
)
//
&&
f
.
begin_tuple
(
sizeof
...(
Ts
))
//
&&
(
inspect_value
(
f
,
std
::
get
<
Is
>
(
x
))
&&
...)
//
&&
f
.
end_tuple
()
//
&&
f
.
end_field
();
}
template
<
class
Inspector
>
static
bool
save_field
(
Inspector
&
f
,
string_view
field_name
,
value_type
&
x
)
{
return
save_field
(
f
,
field_name
,
x
,
tuple_indexes
{});
}
// -- loading ----------------------------------------------------------------
template
<
class
Inspector
,
class
IsValid
,
class
SyncValue
,
size_t
...
Is
>
static
bool
load_field
(
Inspector
&
f
,
string_view
field_name
,
value_type
&
x
,
IsValid
&
is_valid
,
SyncValue
&
sync_value
,
std
::
index_sequence
<
Is
...
>
)
{
if
(
f
.
begin_field
(
field_name
)
//
&&
f
.
begin_tuple
(
sizeof
...(
Ts
))
//
&&
(
inspect_value
(
f
,
std
::
get
<
Is
>
(
x
))
&&
...))
{
if
(
!
is_valid
(
x
))
return
f
.
load_field_failed
(
field_name
,
sec
::
field_invariant_check_failed
);
if
(
!
sync_value
())
return
f
.
load_field_failed
(
field_name
,
sec
::
field_value_synchronization_failed
);
return
f
.
end_tuple
()
&&
f
.
end_field
();
}
return
false
;
}
template
<
class
Inspector
,
class
IsValid
,
class
SyncValue
>
static
bool
load_field
(
Inspector
&
f
,
string_view
field_name
,
value_type
&
x
,
IsValid
&
is_valid
,
SyncValue
&
sync_value
)
{
return
load_field
(
f
,
field_name
,
x
,
is_valid
,
sync_value
,
tuple_indexes
{});
}
template
<
class
Inspector
,
class
IsValid
,
class
SyncValue
,
class
SetFallback
,
size_t
...
Is
>
static
bool
load_field
(
Inspector
&
f
,
string_view
field_name
,
value_type
&
x
,
IsValid
&
is_valid
,
SyncValue
&
sync_value
,
SetFallback
&
set_fallback
,
std
::
index_sequence
<
Is
...
>
)
{
bool
is_present
=
false
;
if
(
!
f
.
begin_field
(
field_name
,
is_present
))
return
false
;
if
(
is_present
)
{
if
(
!
f
.
begin_tuple
(
sizeof
...(
Ts
))
//
||
!
(
inspect_value
(
f
,
std
::
get
<
Is
>
(
x
))
&&
...))
return
false
;
if
(
!
is_valid
(
x
))
return
f
.
load_field_failed
(
field_name
,
sec
::
field_invariant_check_failed
);
if
(
!
sync_value
())
return
f
.
load_field_failed
(
field_name
,
sec
::
field_value_synchronization_failed
);
return
f
.
end_tuple
()
&&
f
.
end_field
();
}
set_fallback
();
return
f
.
end_field
();
}
template
<
class
Inspector
,
class
IsValid
,
class
SyncValue
,
class
SetFallback
>
static
bool
load_field
(
Inspector
&
f
,
string_view
field_name
,
value_type
&
x
,
IsValid
&
is_valid
,
SyncValue
&
sync_value
,
SetFallback
&
set_fallback
)
{
return
load_field
(
f
,
field_name
,
x
,
is_valid
,
sync_value
,
set_fallback
,
tuple_indexes
{});
}
};
template
<
class
T
>
struct
inspector_access_traits
<
optional
<
T
>>
{
static
constexpr
bool
is_optional
=
true
;
static
constexpr
bool
is_sum_type
=
false
;
struct
inspector_access
<
optional
<
T
>>
{
using
value_type
=
optional
<
T
>
;
template
<
class
Inspector
>
[[
nodiscard
]]
static
bool
apply_object
(
Inspector
&
f
,
value_type
&
x
)
{
return
f
.
object
(
x
).
fields
(
f
.
field
(
"value"
,
x
));
}
template
<
class
Inspector
>
[[
nodiscard
]]
static
bool
apply_value
(
Inspector
&
f
,
value_type
&
)
{
f
.
set_error
(
make_error
(
sec
::
runtime_error
,
"apply_value called on an optional"
));
return
false
;
}
template
<
class
Inspector
>
static
bool
save_field
(
Inspector
&
f
,
string_view
field_name
,
value_type
&
x
)
{
auto
is_present
=
[
&
x
]
{
return
static_cast
<
bool
>
(
x
);
};
auto
get
=
[
&
x
]
{
return
*
x
;
};
return
inspector_access
<
T
>::
save_field
(
f
,
field_name
,
is_present
,
get
);
}
template
<
class
Inspector
,
class
IsPresent
,
class
Get
>
static
bool
save_field
(
Inspector
&
f
,
string_view
field_name
,
IsPresent
&
is_present
,
Get
&
get
)
{
if
(
is_present
())
{
auto
&&
x
=
get
();
return
save_field
(
f
,
field_name
,
detail
::
as_mutable_ref
(
x
));
}
return
f
.
begin_field
(
field_name
,
false
)
&&
f
.
end_field
();
}
template
<
class
Inspector
,
class
IsValid
,
class
SyncValue
>
static
bool
load_field
(
Inspector
&
f
,
string_view
field_name
,
value_type
&
x
,
IsValid
&
is_valid
,
SyncValue
&
sync_value
)
{
auto
tmp
=
T
{};
auto
set_x
=
[
&
]
{
x
=
std
::
move
(
tmp
);
return
sync_value
();
};
auto
reset
=
[
&
x
]
{
x
=
value_type
{};
};
return
inspector_access
<
T
>::
load_field
(
f
,
field_name
,
tmp
,
is_valid
,
set_x
,
reset
);
}
template
<
class
Inspector
,
class
IsValid
,
class
SyncValue
,
class
SetFallback
>
static
bool
load_field
(
Inspector
&
f
,
string_view
field_name
,
value_type
&
x
,
IsValid
&
is_valid
,
SyncValue
&
sync_value
,
SetFallback
&
set_fallback
)
{
auto
tmp
=
T
{};
auto
set_x
=
[
&
]
{
x
=
std
::
move
(
tmp
);
return
sync_value
();
};
return
inspector_access
<
T
>::
load_field
(
f
,
field_name
,
tmp
,
is_valid
,
set_x
,
set_fallback
);
}
};
template
<
class
...
Ts
>
struct
inspector_access_traits
<
variant
<
Ts
...
>>
{
static
constexpr
bool
is_optional
=
false
;
static
constexpr
bool
is_sum_type
=
true
;
struct
inspector_access
<
variant
<
Ts
...
>>
{
using
value_type
=
variant
<
Ts
...
>
;
static
constexpr
type_id_t
allowed_types
[]
=
{
type_id_v
<
Ts
>
...};
template
<
class
Inspector
>
[[
nodiscard
]]
static
bool
apply_object
(
Inspector
&
f
,
value_type
&
x
)
{
return
f
.
object
(
x
).
fields
(
f
.
field
(
"value"
,
x
));
}
template
<
class
Inspector
>
[[
nodiscard
]]
static
bool
apply_value
(
Inspector
&
f
,
value_type
&
)
{
f
.
set_error
(
make_error
(
sec
::
runtime_error
,
"apply_value called on a variant"
));
return
false
;
}
template
<
class
Inspector
>
static
bool
save_field
(
Inspector
&
f
,
string_view
field_name
,
value_type
&
x
)
{
auto
g
=
[
&
f
](
auto
&
y
)
{
return
inspect_value
(
f
,
y
);
};
return
f
.
begin_field
(
field_name
,
make_span
(
allowed_types
),
x
.
index
())
//
&&
visit
(
g
,
x
)
//
&&
f
.
end_field
();
}
template
<
class
Inspector
,
class
IsPresent
,
class
Get
>
static
bool
save_field
(
Inspector
&
f
,
string_view
field_name
,
IsPresent
&
is_present
,
Get
&
get
)
{
if
(
is_present
())
{
auto
&&
x
=
get
();
auto
g
=
[
&
f
](
auto
&
y
)
{
return
inspect_value
(
f
,
y
);
};
return
f
.
begin_field
(
field_name
,
true
,
make_span
(
allowed_types
),
x
.
index
())
//
&&
visit
(
g
,
x
)
//
&&
f
.
end_field
();
}
return
f
.
begin_field
(
field_name
,
false
,
make_span
(
allowed_types
),
0
)
//
&&
f
.
end_field
();
}
template
<
class
Inspector
>
static
bool
load_variant_value
(
Inspector
&
f
,
string_view
field_name
,
value_type
&
,
type_id_t
,
detail
::
type_list
<>
)
{
return
f
.
load_field_failed
(
field_name
,
sec
::
invalid_field_type
);
}
template
<
class
Inspector
,
class
U
,
class
...
Us
>
static
bool
load_variant_value
(
Inspector
&
f
,
string_view
field_name
,
value_type
&
x
,
type_id_t
runtime_type
,
detail
::
type_list
<
U
,
Us
...
>
)
{
if
(
type_id_v
<
U
>
==
runtime_type
)
{
auto
tmp
=
U
{};
if
(
!
inspect_value
(
f
,
tmp
))
return
false
;
x
=
std
::
move
(
tmp
);
return
true
;
}
detail
::
type_list
<
Us
...
>
token
;
return
load_variant_value
(
f
,
field_name
,
x
,
runtime_type
,
token
);
}
template
<
class
Inspector
,
class
IsValid
,
class
SyncValue
>
static
bool
load_field
(
Inspector
&
f
,
string_view
field_name
,
value_type
&
x
,
IsValid
&
is_valid
,
SyncValue
&
sync_value
)
{
size_t
type_index
=
std
::
numeric_limits
<
size_t
>::
max
();
if
(
!
f
.
begin_field
(
field_name
,
make_span
(
allowed_types
),
type_index
))
return
false
;
if
(
type_index
>=
std
::
size
(
allowed_types
))
return
f
.
load_field_failed
(
field_name
,
sec
::
invalid_field_type
);
auto
runtime_type
=
allowed_types
[
type_index
];
detail
::
type_list
<
Ts
...
>
types
;
if
(
!
load_variant_value
(
f
,
field_name
,
x
,
runtime_type
,
types
))
return
false
;
if
(
!
is_valid
(
x
))
return
f
.
load_field_failed
(
field_name
,
sec
::
field_invariant_check_failed
);
if
(
!
sync_value
())
return
f
.
load_field_failed
(
field_name
,
sec
::
field_value_synchronization_failed
);
return
f
.
end_field
();
}
template
<
class
Inspector
,
class
IsValid
,
class
SyncValue
,
class
SetFallback
>
static
bool
load_field
(
Inspector
&
f
,
string_view
field_name
,
value_type
&
x
,
IsValid
&
is_valid
,
SyncValue
&
sync_value
,
SetFallback
&
set_fallback
)
{
bool
is_present
=
false
;
size_t
type_index
=
std
::
numeric_limits
<
size_t
>::
max
();
if
(
!
f
.
begin_field
(
field_name
,
is_present
,
make_span
(
allowed_types
),
type_index
))
return
false
;
if
(
is_present
)
{
if
(
type_index
>=
std
::
size
(
allowed_types
))
return
f
.
load_field_failed
(
field_name
,
sec
::
invalid_field_type
);
auto
runtime_type
=
allowed_types
[
type_index
];
detail
::
type_list
<
Ts
...
>
types
;
if
(
!
load_variant_value
(
f
,
field_name
,
x
,
runtime_type
,
types
))
return
false
;
if
(
!
is_valid
(
x
))
return
f
.
load_field_failed
(
field_name
,
sec
::
field_invariant_check_failed
);
if
(
!
sync_value
())
return
f
.
load_field_failed
(
field_name
,
sec
::
field_value_synchronization_failed
);
}
else
{
set_fallback
();
}
return
f
.
end_field
();
}
};
}
// namespace caf
libcaf_core/caf/load_inspector.hpp
View file @
4bbccd70
...
...
@@ -21,9 +21,7 @@
#include <type_traits>
#include <utility>
#include "caf/error.hpp"
#include "caf/inspector_access.hpp"
#include "caf/sec.hpp"
#include "caf/string_view.hpp"
namespace
caf
{
...
...
@@ -34,7 +32,7 @@ namespace caf {
/// for the DSL.
class
load_inspector
{
public:
// -- con
tants -
--------------------------------------------------------------
// -- con
stants
--------------------------------------------------------------
/// Convenience constant to indicate success of a processing step.
static
constexpr
bool
ok
=
true
;
...
...
@@ -52,77 +50,43 @@ public:
/// A load inspector overrides the state of an object.
static
constexpr
bool
writes_state
=
true
;
// -- error management -------------------------------------------------------
template
<
class
Inspector
>
static
void
set_invariant_check_error
(
Inspector
&
f
,
string_view
field_name
,
string_view
object_name
)
{
std
::
string
msg
=
"invalid argument to field "
;
msg
.
insert
(
msg
.
end
(),
field_name
.
begin
(),
field_name
.
end
());
msg
+=
" for object of type "
;
msg
.
insert
(
msg
.
end
(),
object_name
.
begin
(),
object_name
.
end
());
msg
+=
": invariant check failed"
;
f
.
set_error
(
make_error
(
caf
::
sec
::
invalid_argument
,
std
::
move
(
msg
)));
}
template
<
class
Inspector
>
static
void
set_field_store_error
(
Inspector
&
f
,
string_view
field_name
,
string_view
object_name
)
{
std
::
string
msg
=
"invalid argument to field "
;
msg
.
insert
(
msg
.
end
(),
field_name
.
begin
(),
field_name
.
end
());
msg
+=
" for object of type "
;
msg
.
insert
(
msg
.
end
(),
object_name
.
begin
(),
object_name
.
end
());
msg
+=
": setter returned false"
;
f
.
set_error
(
make_error
(
caf
::
sec
::
invalid_argument
,
std
::
move
(
msg
)));
}
/// Inspecting objects, fields and values always returns a `bool`.
using
result_type
=
bool
;
// -- DSL types for regular fields -------------------------------------------
template
<
class
T
,
class
Predicate
>
template
<
class
T
,
class
U
,
class
Predicate
>
struct
field_with_invariant_and_fallback_t
{
string_view
field_name
;
T
*
val
;
T
fallback
;
U
fallback
;
Predicate
predicate
;
template
<
class
Inspector
>
bool
operator
()(
string_view
object_name
,
Inspector
&
f
)
{
bool
is_present
=
false
;
if
(
!
f
.
begin_field
(
field_name
,
is_present
))
return
stop
;
if
(
is_present
)
{
if
(
inspector_access
<
T
>::
apply
(
f
,
*
val
)
&&
f
.
end_field
())
{
if
(
predicate
(
*
val
))
return
ok
;
set_invariant_check_error
(
f
,
field_name
,
object_name
);
}
return
stop
;
}
*
val
=
std
::
move
(
fallback
);
return
f
.
end_field
();
bool
operator
()(
Inspector
&
f
)
{
auto
reset
=
[
this
]
{
*
val
=
std
::
move
(
fallback
);
};
return
inspector_access
<
T
>::
load_field
(
f
,
field_name
,
*
val
,
predicate
,
detail
::
always_true
,
reset
);
}
};
template
<
class
T
>
template
<
class
T
,
class
U
>
struct
field_with_fallback_t
{
string_view
field_name
;
T
*
val
;
T
fallback
;
U
fallback
;
template
<
class
Inspector
>
bool
operator
()(
string_view
,
Inspector
&
f
)
{
bool
is_present
=
false
;
if
(
!
f
.
begin_field
(
field_name
,
is_present
))
return
stop
;
if
(
is_present
)
return
inspector_access
<
T
>::
apply
(
f
,
*
val
)
&&
f
.
end_field
();
*
val
=
std
::
move
(
fallback
);
return
f
.
end_field
();
bool
operator
()(
Inspector
&
f
)
{
auto
reset
=
[
this
]
{
*
val
=
std
::
move
(
fallback
);
};
return
inspector_access
<
T
>::
load_field
(
f
,
field_name
,
*
val
,
detail
::
always_true
,
detail
::
always_true
,
reset
);
}
template
<
class
Predicate
>
auto
invariant
(
Predicate
predicate
)
&&
{
return
field_with_invariant_and_fallback_t
<
T
,
Predicate
>
{
return
field_with_invariant_and_fallback_t
<
T
,
U
,
Predicate
>
{
field_name
,
val
,
std
::
move
(
fallback
),
...
...
@@ -138,19 +102,14 @@ public:
Predicate
predicate
;
template
<
class
Inspector
>
bool
operator
()(
string_view
object_name
,
Inspector
&
f
)
{
if
(
f
.
begin_field
(
field_name
)
//
&&
inspector_access
<
T
>::
apply
(
f
,
*
val
)
//
&&
f
.
end_field
())
{
if
(
predicate
(
*
val
))
return
ok
;
set_invariant_check_error
(
f
,
field_name
,
object_name
);
}
return
stop
;
bool
operator
()(
Inspector
&
f
)
{
return
inspector_access
<
T
>::
load_field
(
f
,
field_name
,
*
val
,
predicate
,
detail
::
always_true
);
}
auto
fallback
(
T
value
)
&&
{
return
field_with_invariant_and_fallback_t
<
T
,
Predicate
>
{
template
<
class
U
>
auto
fallback
(
U
value
)
&&
{
return
field_with_invariant_and_fallback_t
<
T
,
U
,
Predicate
>
{
field_name
,
val
,
std
::
move
(
value
),
...
...
@@ -165,31 +124,15 @@ public:
T
*
val
;
template
<
class
Inspector
>
bool
operator
()(
string_view
,
Inspector
&
f
)
{
if
constexpr
(
inspector_access_traits
<
T
>::
is_optional
)
{
bool
is_present
=
false
;
if
(
!
f
.
begin_field
(
field_name
,
is_present
))
return
stop
;
using
value_type
=
std
::
decay_t
<
decltype
(
**
val
)
>
;
if
(
is_present
)
{
auto
tmp
=
value_type
{};
if
(
!
inspector_access
<
value_type
>::
apply
(
f
,
tmp
))
return
stop
;
*
val
=
std
::
move
(
tmp
);
return
f
.
end_field
();
}
else
{
*
val
=
T
{};
return
f
.
end_field
();
}
}
else
{
return
f
.
begin_field
(
field_name
)
//
&&
inspector_access
<
T
>::
apply
(
f
,
*
val
)
//
&&
f
.
end_field
();
}
bool
operator
()(
Inspector
&
f
)
{
return
inspector_access
<
T
>::
load_field
(
f
,
field_name
,
*
val
,
detail
::
always_true
,
detail
::
always_true
);
}
auto
fallback
(
T
value
)
&&
{
return
field_with_fallback_t
<
T
>
{
field_name
,
val
,
std
::
move
(
value
)};
template
<
class
U
>
auto
fallback
(
U
value
)
&&
{
return
field_with_fallback_t
<
T
,
U
>
{
field_name
,
val
,
std
::
move
(
value
)};
}
template
<
class
Predicate
>
...
...
@@ -204,66 +147,46 @@ public:
// -- DSL types for virtual fields (getter and setter access) ----------------
template
<
class
T
,
class
Set
,
class
Predicate
>
template
<
class
T
,
class
Set
,
class
U
,
class
Predicate
>
struct
virt_field_with_invariant_and_fallback_t
{
string_view
field_name
;
Set
set
;
T
fallback
;
U
fallback
;
Predicate
predicate
;
template
<
class
Inspector
>
bool
operator
()(
string_view
object_name
,
Inspector
&
f
)
{
bool
is_present
=
false
;
if
(
!
f
.
begin_field
(
field_name
,
is_present
))
return
stop
;
if
(
is_present
)
{
auto
tmp
=
T
{};
if
(
!
inspector_access
<
T
>::
apply
(
f
,
tmp
))
return
stop
;
if
(
!
predicate
(
tmp
))
{
set_invariant_check_error
(
f
,
field_name
,
object_name
);
return
stop
;
}
if
(
!
set
(
std
::
move
(
tmp
)))
{
set_field_store_error
(
f
,
field_name
,
object_name
);
return
stop
;
}
return
f
.
end_field
();
}
if
(
!
set
(
std
::
move
(
fallback
)))
{
set_field_store_error
(
f
,
field_name
,
object_name
);
return
stop
;
}
return
f
.
end_field
();
bool
operator
()(
Inspector
&
f
)
{
auto
tmp
=
T
{};
auto
sync
=
[
this
,
&
tmp
]
{
return
set
(
std
::
move
(
tmp
));
};
auto
reset
=
[
this
]
{
set
(
std
::
move
(
fallback
));
};
return
inspector_access
<
T
>::
load_field
(
f
,
field_name
,
tmp
,
predicate
,
sync
,
reset
);
}
};
template
<
class
T
,
class
Set
>
template
<
class
T
,
class
Set
,
class
U
>
struct
virt_field_with_fallback_t
{
string_view
field_name
;
Set
set
;
T
fallback
;
U
fallback
;
template
<
class
Inspector
>
bool
operator
()(
string_view
object_name
,
Inspector
&
f
)
{
bool
is_present
=
false
;
if
(
!
f
.
begin_field
(
field_name
,
is_present
))
return
stop
;
if
(
is_present
)
{
auto
tmp
=
T
{};
if
(
!
inspector_access
<
T
>::
apply
(
f
,
tmp
))
return
stop
;
if
(
!
set
(
std
::
move
(
tmp
)))
{
set_field_store_error
(
f
,
field_name
,
object_name
);
return
stop
;
}
return
f
.
end_field
();
}
if
(
!
set
(
std
::
move
(
fallback
)))
{
set_field_store_error
(
f
,
field_name
,
object_name
);
return
stop
;
}
return
f
.
end_field
();
bool
operator
()(
Inspector
&
f
)
{
auto
tmp
=
T
{};
auto
sync
=
[
this
,
&
tmp
]
{
return
set
(
std
::
move
(
tmp
));
};
auto
reset
=
[
this
]
{
set
(
std
::
move
(
fallback
));
};
return
inspector_access
<
T
>::
load_field
(
f
,
field_name
,
tmp
,
detail
::
always_true
,
sync
,
reset
);
}
template
<
class
Predicate
>
auto
invariant
(
Predicate
predicate
)
&&
{
return
virt_field_with_invariant_and_fallback_t
<
T
,
Set
,
U
,
Predicate
>
{
field_name
,
std
::
move
(
set
),
std
::
move
(
fallback
),
std
::
move
(
predicate
),
};
}
};
...
...
@@ -274,25 +197,16 @@ public:
Predicate
predicate
;
template
<
class
Inspector
>
bool
operator
()(
string_view
object_name
,
Inspector
&
f
)
{
if
(
!
f
.
begin_field
(
field_name
))
return
stop
;
bool
operator
()(
Inspector
&
f
)
{
auto
tmp
=
T
{};
if
(
!
inspector_access
<
T
>::
apply
(
f
,
tmp
))
return
stop
;
if
(
!
predicate
(
tmp
))
{
set_invariant_check_error
(
f
,
field_name
,
object_name
);
return
stop
;
}
if
(
!
set
(
std
::
move
(
tmp
)))
{
set_field_store_error
(
f
,
field_name
,
object_name
);
return
stop
;
}
return
f
.
end_field
();
auto
sync
=
[
this
,
&
tmp
]
{
return
set
(
std
::
move
(
tmp
));
};
return
inspector_access
<
T
>::
load_field
(
f
,
field_name
,
tmp
,
predicate
,
sync
);
}
auto
fallback
(
T
value
)
&&
{
return
virt_field_with_invariant_and_fallback_t
<
T
,
Set
,
Predicate
>
{
template
<
class
U
>
auto
fallback
(
U
value
)
&&
{
return
virt_field_with_invariant_and_fallback_t
<
T
,
Set
,
U
,
Predicate
>
{
field_name
,
std
::
move
(
set
),
std
::
move
(
value
),
...
...
@@ -307,24 +221,30 @@ public:
Set
set
;
template
<
class
Inspector
>
bool
operator
()(
string_view
,
Inspector
&
f
)
{
if
(
!
f
.
begin_field
(
field_name
))
return
stop
;
bool
operator
()(
Inspector
&
f
)
{
auto
tmp
=
T
{};
if
(
!
inspector_access
<
T
>::
apply
(
f
,
tmp
))
return
stop
;
if
(
!
set
(
std
::
move
(
tmp
)))
{
}
return
f
.
end_field
();
auto
sync
=
[
this
,
&
tmp
]
{
return
set
(
std
::
move
(
tmp
));
};
return
inspector_access
<
T
>::
load_field
(
f
,
field_name
,
tmp
,
detail
::
always_true
,
sync
);
}
auto
fallback
(
T
value
)
&&
{
return
virt_field_with_fallback_t
<
T
,
Set
>
{
template
<
class
U
>
auto
fallback
(
U
value
)
&&
{
return
virt_field_with_fallback_t
<
T
,
Set
,
U
>
{
field_name
,
std
::
move
(
set
),
std
::
move
(
value
),
};
}
template
<
class
Predicate
>
auto
invariant
(
Predicate
predicate
)
&&
{
return
virt_field_with_invariant_t
<
T
,
Set
,
Predicate
>
{
field_name
,
std
::
move
(
set
),
std
::
move
(
predicate
),
};
}
};
template
<
class
Inspector
>
...
...
@@ -334,8 +254,7 @@ public:
template
<
class
...
Fields
>
bool
fields
(
Fields
&&
...
fs
)
{
return
f
->
begin_object
(
object_name
)
&&
(
fs
(
object_name
,
*
f
)
&&
...)
&&
f
->
end_object
();
return
f
->
begin_object
(
object_name
)
&&
(
fs
(
*
f
)
&&
...)
&&
f
->
end_object
();
}
auto
pretty_name
(
string_view
name
)
&&
{
...
...
@@ -353,9 +272,6 @@ public:
template
<
class
Get
,
class
Set
>
static
auto
field
(
string_view
name
,
Get
get
,
Set
set
)
{
using
field_type
=
std
::
decay_t
<
decltype
(
get
())
>
;
using
set_result
=
decltype
(
set
(
std
::
declval
<
field_type
>
()));
static_assert
(
std
::
is_same
<
set_result
,
bool
>::
value
,
"setters of fields must return bool"
);
return
virt_field_t
<
field_type
,
Set
>
{
name
,
set
};
}
};
...
...
libcaf_core/caf/save_inspector.hpp
View file @
4bbccd70
...
...
@@ -18,9 +18,7 @@
#pragma once
#include "caf/error.hpp"
#include "caf/inspector_access.hpp"
#include "caf/sec.hpp"
#include "caf/string_view.hpp"
namespace
caf
{
...
...
@@ -31,7 +29,7 @@ namespace caf {
/// for the DSL.
class
save_inspector
{
public:
// -- con
tants -
--------------------------------------------------------------
// -- con
stants
--------------------------------------------------------------
/// Convenience constant to indicate success of a processing step.
static
constexpr
bool
ok
=
true
;
...
...
@@ -49,78 +47,95 @@ public:
/// A load inspector never modifies the state of an object.
static
constexpr
bool
writes_state
=
false
;
/// Inspecting objects, fields and values always returns a `bool`.
using
result_type
=
bool
;
// -- DSL types for regular fields -------------------------------------------
template
<
class
T
,
class
U
>
struct
field_with_fallback_t
{
string_view
field_name
;
T
*
val
;
U
fallback
;
template
<
class
Inspector
>
bool
operator
()(
Inspector
&
f
)
{
auto
is_present
=
[
this
]
{
return
*
val
!=
fallback
;
};
auto
get
=
[
this
]
{
return
*
val
;
};
return
inspector_access
<
T
>::
save_field
(
f
,
field_name
,
is_present
,
get
);
}
template
<
class
Predicate
>
field_with_fallback_t
&&
invariant
(
Predicate
&&
)
&&
{
return
std
::
move
(
*
this
);
}
};
template
<
class
T
>
struct
field_t
{
string_view
field_name
;
T
*
val
;
template
<
class
Inspector
>
bool
operator
()(
string_view
,
Inspector
&
f
)
{
if
constexpr
(
inspector_access_traits
<
T
>::
is_optional
)
{
auto
&
ref
=
*
val
;
using
value_type
=
std
::
decay_t
<
decltype
(
*
ref
)
>
;
if
(
ref
)
{
return
f
.
begin_field
(
field_name
,
true
)
//
&&
inspector_access
<
value_type
>::
apply
(
f
,
*
ref
)
//
&&
f
.
end_field
();
}
else
{
return
f
.
begin_field
(
field_name
,
false
)
&&
f
.
end_field
();
}
}
else
{
return
f
.
begin_field
(
field_name
)
//
&&
inspector_access
<
T
>::
apply
(
f
,
*
val
)
//
&&
f
.
end_field
();
}
bool
operator
()(
Inspector
&
f
)
{
return
inspector_access
<
T
>::
save_field
(
f
,
field_name
,
*
val
);
}
template
<
class
U
nused
>
field_t
&
fallback
(
Unused
&&
)
{
return
*
this
;
template
<
class
U
>
auto
fallback
(
U
value
)
&&
{
return
field_with_fallback_t
<
T
,
U
>
{
field_name
,
val
,
std
::
move
(
value
)}
;
}
template
<
class
Predicate
>
field_t
invariant
(
Predicate
&&
)
{
return
*
this
;
field_t
&&
invariant
(
Predicate
&&
)
&&
{
return
std
::
move
(
*
this
)
;
}
};
// -- DSL types for virtual fields (getter and setter access) ----------------
template
<
class
T
,
class
Get
,
class
U
>
struct
virt_field_with_fallback_t
{
string_view
field_name
;
Get
get
;
U
fallback
;
template
<
class
Inspector
>
bool
operator
()(
Inspector
&
f
)
{
auto
is_present
=
[
this
]
{
return
get
()
!=
fallback
;
};
return
inspector_access
<
T
>::
save_field
(
f
,
field_name
,
is_present
,
get
);
}
template
<
class
Predicate
>
virt_field_with_fallback_t
&&
invariant
(
Predicate
&&
)
&&
{
return
std
::
move
(
*
this
);
}
};
template
<
class
T
,
class
Get
>
struct
virt_field_t
{
string_view
field_name
;
Get
get
;
template
<
class
Inspector
>
bool
operator
()(
string_view
,
Inspector
&
f
)
{
if
(
!
f
.
begin_field
(
field_name
))
return
stop
;
auto
&&
value
=
get
();
using
value_type
=
std
::
remove_reference_t
<
decltype
(
value
)
>
;
if
constexpr
(
std
::
is_const
<
value_type
>::
value
)
{
// Force a mutable reference, because the inspect API requires it. This
// const_cast is always safe, because we never actually modify the
// object.
using
mutable_ref
=
std
::
remove_const_t
<
value_type
>&
;
if
(
!
inspector_access
<
T
>::
apply
(
f
,
const_cast
<
mutable_ref
>
(
value
)))
return
stop
;
}
else
{
if
(
!
inspector_access
<
T
>::
apply
(
f
,
value
))
return
stop
;
}
return
f
.
end_field
();
bool
operator
()(
Inspector
&
f
)
{
auto
&&
x
=
get
();
return
inspector_access
<
T
>::
save_field
(
f
,
field_name
,
detail
::
as_mutable_ref
(
x
));
}
template
<
class
Unused
>
virt_field_t
&
fallback
(
Unused
&&
)
{
return
*
this
;
template
<
class
U
>
auto
fallback
(
U
value
)
&&
{
return
virt_field_with_fallback_t
<
T
,
Get
,
U
>
{
field_name
,
std
::
move
(
get
),
std
::
move
(
value
),
};
}
template
<
class
Predicate
>
virt_field_t
invariant
(
Predicate
&&
)
{
return
*
this
;
virt_field_t
&&
invariant
(
Predicate
&&
)
&&
{
return
std
::
move
(
*
this
)
;
}
};
...
...
@@ -131,8 +146,7 @@ public:
template
<
class
...
Fields
>
bool
fields
(
Fields
&&
...
fs
)
{
return
f
->
begin_object
(
object_name
)
&&
(
fs
(
object_name
,
*
f
)
&&
...)
&&
f
->
end_object
();
return
f
->
begin_object
(
object_name
)
&&
(
fs
(
*
f
)
&&
...)
&&
f
->
end_object
();
}
auto
pretty_name
(
string_view
name
)
&&
{
...
...
libcaf_core/caf/sec.hpp
View file @
4bbccd70
...
...
@@ -136,7 +136,7 @@ enum class sec : uint8_t {
malformed_basp_message
,
/// The middleman closed a connection because it failed to serialize or
/// deserialize a payload.
serializing_basp_payload_failed
,
serializing_basp_payload_failed
=
50
,
/// The middleman closed a connection to itself or an already connected node.
redundant_connection
,
/// Resolving a path on a remote node failed.
...
...
@@ -145,6 +145,13 @@ enum class sec : uint8_t {
no_tracing_context
,
/// No request produced a valid result.
all_requests_failed
,
/// Deserialization failed, because an invariant got violated after reading
/// the content of a field.
field_invariant_check_failed
=
55
,
/// Deserialization failed, because a setter rejected the input.
field_value_synchronization_failed
,
/// Deserialization failed, because the source announced an invalid type.
invalid_field_type
,
};
/// @relates sec
...
...
libcaf_core/caf/type_id.hpp
View file @
4bbccd70
...
...
@@ -37,6 +37,10 @@ namespace caf {
/// Internal representation of a type ID.
using
type_id_t
=
uint16_t
;
/// Special value equal to the greatest possible value for `type_id_t`.
/// Generally indicates that no type ID for a given type exists.
constexpr
type_id_t
invalid_type_id
=
65535
;
/// Maps the type `T` to a globally unique ID.
template
<
class
T
>
struct
type_id
;
...
...
libcaf_core/test/core-test.hpp
View file @
4bbccd70
...
...
@@ -240,8 +240,8 @@ enum dummy_enum { de_foo, de_bar };
CAF_BEGIN_TYPE_ID_BLOCK
(
core_test
,
caf
::
first_custom_type_id
)
ADD_TYPE_ID
((
caf
::
stream
<
int32_t
>
)
)
ADD_TYPE_ID
((
caf
::
stream
<
std
::
string
>
)
)
ADD_TYPE_ID
((
caf
::
stream
<
std
::
pair
<
level
,
std
::
string
>>
)
)
ADD_TYPE_ID
((
caf
::
stream
<
std
::
string
>
)
)
ADD_TYPE_ID
((
dummy_enum
))
ADD_TYPE_ID
((
dummy_enum_class
))
ADD_TYPE_ID
((
dummy_struct
))
...
...
libcaf_core/test/load_inspector.cpp
View file @
4bbccd70
...
...
@@ -26,33 +26,11 @@
#include <string>
#include <vector>
namespace
caf
{
#include "caf/span.hpp"
#include "caf/type_id.hpp"
#include "caf/variant.hpp"
template
<
>
struct
inspector_access
<
std
::
string
>
{
template
<
class
Inspector
>
static
bool
apply
(
Inspector
&
f
,
std
::
string
&
x
)
{
return
f
.
value
(
x
);
}
};
template
<
>
struct
inspector_access
<
int32_t
>
{
template
<
class
Inspector
>
static
bool
apply
(
Inspector
&
f
,
int32_t
&
x
)
{
return
f
.
value
(
x
);
}
};
template
<
>
struct
inspector_access
<
double
>
{
template
<
class
Inspector
>
static
bool
apply
(
Inspector
&
f
,
double
&
x
)
{
return
f
.
value
(
x
);
}
};
}
// namespace caf
#include "nasty.hpp"
using
namespace
caf
;
...
...
@@ -153,6 +131,28 @@ bool inspect(Inspector& f, foobar& x) {
f
.
field
(
"bar"
,
get_bar
,
set_bar
));
}
struct
dummy_message
{
static
inline
string_view
tname
=
"dummy_message"
;
variant
<
std
::
string
,
double
>
content
;
};
template
<
class
Inspector
>
bool
inspect
(
Inspector
&
f
,
dummy_message
&
x
)
{
return
f
.
object
(
x
).
fields
(
f
.
field
(
"content"
,
x
.
content
));
}
struct
fallback_dummy_message
{
static
inline
string_view
tname
=
"fallback_dummy_message"
;
variant
<
std
::
string
,
double
>
content
;
};
template
<
class
Inspector
>
bool
inspect
(
Inspector
&
f
,
fallback_dummy_message
&
x
)
{
return
f
.
object
(
x
).
fields
(
f
.
field
(
"content"
,
x
.
content
).
fallback
(
42.0
));
}
struct
testee
:
load_inspector
{
std
::
string
log
;
...
...
@@ -162,6 +162,11 @@ struct testee : load_inspector {
err
=
std
::
move
(
x
);
}
bool
load_field_failed
(
string_view
,
sec
code
)
{
set_error
(
make_error
(
code
));
return
stop
;
}
size_t
indent
=
0
;
void
new_line
()
{
...
...
@@ -206,6 +211,26 @@ struct testee : load_inspector {
return
ok
;
}
bool
begin_field
(
string_view
name
,
span
<
const
type_id_t
>
,
size_t
&
type_index
)
{
new_line
();
indent
+=
2
;
log
+=
"begin variant field "
;
log
.
insert
(
log
.
end
(),
name
.
begin
(),
name
.
end
());
type_index
=
0
;
return
ok
;
}
bool
begin_field
(
string_view
name
,
bool
&
is_present
,
span
<
const
type_id_t
>
,
size_t
&
)
{
new_line
();
indent
+=
2
;
log
+=
"begin optional variant field "
;
log
.
insert
(
log
.
end
(),
name
.
begin
(),
name
.
end
());
is_present
=
false
;
return
ok
;
}
bool
end_field
()
{
indent
-=
2
;
new_line
();
...
...
@@ -213,14 +238,36 @@ struct testee : load_inspector {
return
ok
;
}
bool
begin_tuple
(
size_t
size
)
{
new_line
();
indent
+=
2
;
log
+=
"begin tuple of size "
;
log
+=
std
::
to_string
(
size
);
return
ok
;
}
bool
end_tuple
()
{
indent
-=
2
;
new_line
();
log
+=
"end tuple"
;
return
ok
;
}
template
<
class
T
>
bool
value
(
T
&
x
)
{
std
::
enable_if_t
<
std
::
is_arithmetic
<
T
>::
value
,
bool
>
value
(
T
&
x
)
{
new_line
();
log
+=
type_name_v
<
T
>
;
log
+=
" value"
;
x
=
T
{};
return
ok
;
}
bool
value
(
std
::
string
&
x
)
{
new_line
();
log
+=
"std::string value"
;
x
.
clear
();
return
ok
;
}
};
struct
fixture
{
...
...
@@ -340,4 +387,134 @@ begin object foobar
end object)_"
);
}
CAF_TEST
(
load
inspectors
support
variant
fields
)
{
dummy_message
d
;
d
.
content
=
42.0
;
CAF_CHECK
(
inspect
(
f
,
d
));
// Our dummy inspector resets variants to their first type.
CAF_CHECK
(
holds_alternative
<
std
::
string
>
(
d
.
content
));
CAF_CHECK_EQUAL
(
f
.
log
,
R"_(
begin object dummy_message
begin variant field content
std::string value
end field
end object)_"
);
}
CAF_TEST
(
load
inspectors
support
variant
fields
with
fallbacks
)
{
fallback_dummy_message
d
;
d
.
content
=
std
::
string
{
"hello world"
};
CAF_CHECK
(
inspect
(
f
,
d
));
CAF_CHECK_EQUAL
(
d
.
content
,
42.0
);
CAF_CHECK_EQUAL
(
f
.
log
,
R"_(
begin object fallback_dummy_message
begin optional variant field content
end field
end object)_"
);
}
CAF_TEST
(
load
inspectors
support
nasty
data
structures
)
{
nasty
x
;
CAF_CHECK
(
inspect
(
f
,
x
));
CAF_CHECK_EQUAL
(
f
.
log
,
R"_(
begin object nasty
begin field field_01
int32_t value
end field
begin optional field field_02
end field
begin field field_03
int32_t value
end field
begin optional field field_04
end field
begin optional field field_05
end field
begin optional field field_06
end field
begin optional field field_07
end field
begin optional field field_08
end field
begin variant field field_09
std::string value
end field
begin optional variant field field_10
end field
begin variant field field_11
std::string value
end field
begin optional variant field field_12
end field
begin field field_13
begin tuple of size 2
std::string value
int32_t value
end tuple
end field
begin optional field field_14
end field
begin field field_15
begin tuple of size 2
std::string value
int32_t value
end tuple
end field
begin optional field field_16
end field
begin field field_17
int32_t value
end field
begin optional field field_18
end field
begin field field_19
int32_t value
end field
begin optional field field_20
end field
begin optional field field_21
end field
begin optional field field_22
end field
begin optional field field_23
end field
begin optional field field_24
end field
begin variant field field_25
std::string value
end field
begin optional variant field field_26
end field
begin variant field field_27
std::string value
end field
begin optional variant field field_28
end field
begin field field_29
begin tuple of size 2
std::string value
int32_t value
end tuple
end field
begin optional field field_30
end field
begin field field_31
begin tuple of size 2
std::string value
int32_t value
end tuple
end field
begin optional field field_32
end field
begin optional variant field field_33
end field
begin optional field field_34
end field
begin optional variant field field_35
end field
begin optional field field_36
end field
end object)_"
);
}
CAF_TEST_FIXTURE_SCOPE_END
()
libcaf_core/test/nasty.cpp
0 → 100644
View file @
4bbccd70
#include "nasty.hpp"
std
::
string
to_string
(
weekday
x
)
{
switch
(
x
)
{
default:
return
"???"
;
case
weekday
:
:
monday
:
return
"monday"
;
case
weekday
:
:
tuesday
:
return
"tuesday"
;
case
weekday
:
:
wednesday
:
return
"wednesday"
;
case
weekday
:
:
thursday
:
return
"thursday"
;
case
weekday
:
:
friday
:
return
"friday"
;
case
weekday
:
:
saturday
:
return
"saturday"
;
case
weekday
:
:
sunday
:
return
"sunday"
;
}
}
bool
parse
(
std
::
string_view
input
,
weekday
&
dest
)
{
if
(
input
==
"monday"
)
{
dest
=
weekday
::
monday
;
return
true
;
}
if
(
input
==
"tuesday"
)
{
dest
=
weekday
::
tuesday
;
return
true
;
}
if
(
input
==
"wednesday"
)
{
dest
=
weekday
::
wednesday
;
return
true
;
}
if
(
input
==
"thursday"
)
{
dest
=
weekday
::
thursday
;
return
true
;
}
if
(
input
==
"friday"
)
{
dest
=
weekday
::
friday
;
return
true
;
}
if
(
input
==
"saturday"
)
{
dest
=
weekday
::
saturday
;
return
true
;
}
if
(
input
==
"sunday"
)
{
dest
=
weekday
::
sunday
;
return
true
;
}
return
false
;
}
libcaf_core/test/nasty.hpp
0 → 100644
View file @
4bbccd70
#pragma once
#include <cstdint>
#include <string>
#include <tuple>
#include "caf/inspector_access.hpp"
#include "caf/optional.hpp"
#include "caf/string_view.hpp"
#include "caf/variant.hpp"
enum
class
weekday
{
monday
,
tuesday
,
wednesday
,
thursday
,
friday
,
saturday
,
sunday
,
};
std
::
string
to_string
(
weekday
x
);
bool
parse
(
std
::
string_view
input
,
weekday
&
dest
);
namespace
caf
{
template
<
>
struct
inspector_access
<
weekday
>
:
inspector_access_base
<
weekday
>
{
using
default_impl
=
default_inspector_access
<
weekday
>
;
template
<
class
Inspector
>
static
bool
apply_object
(
Inspector
&
f
,
weekday
&
x
)
{
if
constexpr
(
Inspector
::
has_human_readable_format
)
{
auto
get
=
[
&
x
]
{
return
to_string
(
x
);
};
auto
set
=
[
&
x
](
std
::
string
str
)
{
return
parse
(
str
,
x
);
};
f
.
object
(
x
).
fields
(
f
.
field
(
"value"
,
get
,
set
));
}
else
{
return
default_impl
::
apply_object
(
f
,
x
);
}
}
template
<
class
Inspector
>
static
bool
apply_value
(
Inspector
&
f
,
weekday
&
x
)
{
if
constexpr
(
Inspector
::
has_human_readable_format
)
{
auto
get
=
[
&
x
]
{
return
to_string
(
x
);
};
auto
set
=
[
&
x
](
std
::
string
str
)
{
return
parse
(
str
,
x
);
};
return
inspect_value
(
f
,
get
,
set
);
}
else
{
return
default_impl
::
apply_value
(
f
,
x
);
}
}
};
}
// namespace caf
#define ADD_GET_SET_FIELD(type, name) \
private: \
type name##_ = type{}; \
\
public: \
const auto& name() const noexcept { \
return name##_; \
} \
void name(type value) { \
name##_ = std::move(value); \
}
// A mean data type designed for maximum coverage of the inspect API.
class
nasty
{
public:
static
inline
caf
::
string_view
tname
=
"nasty"
;
using
optional_type
=
caf
::
optional
<
int32_t
>
;
using
variant_type
=
caf
::
variant
<
std
::
string
,
int32_t
>
;
using
tuple_type
=
std
::
tuple
<
std
::
string
,
int32_t
>
;
using
optional_variant_type
=
caf
::
optional
<
variant_type
>
;
using
optional_tuple_type
=
caf
::
optional
<
tuple_type
>
;
// Plain, direct access.
int32_t
field_01
=
0
;
// Plain, direct access, fallback (0).
int32_t
field_02
=
0
;
// Plain, direct access, invariant (>= 0).
int32_t
field_03
=
0
;
// Plain, direct access, fallback (0), invariant (>= 0).
int32_t
field_04
=
0
;
// Optional, direct access.
optional_type
field_05
;
// Optional, direct access, fallback (0).
optional_type
field_06
;
// Optional, direct access, invariant (>= 0).
optional_type
field_07
;
// Optional, direct access, fallback (0), invariant (>= 0).
optional_type
field_08
;
// Variant, direct access.
variant_type
field_09
;
// Variant, direct access, fallback (0).
variant_type
field_10
;
// Variant, direct access, invariant (>= 0).
variant_type
field_11
;
// Variant, direct access, fallback (0), invariant (>= 0).
variant_type
field_12
;
// Tuple, direct access.
tuple_type
field_13
;
// Tuple, direct access, fallback ("", 0).
tuple_type
field_14
;
// Tuple, direct access, invariant (>= 0).
tuple_type
field_15
;
// Tuple, direct access, fallback ("", 0), invariant (>= 0).
tuple_type
field_16
;
// Plain, get/set access.
ADD_GET_SET_FIELD
(
int32_t
,
field_17
)
// Plain, get/set access, fallback (0).
ADD_GET_SET_FIELD
(
int32_t
,
field_18
)
// Plain, get/set access, invariant (>= 0).
ADD_GET_SET_FIELD
(
int32_t
,
field_19
)
// Plain, get/set access, fallback (0), invariant (>= 0).
ADD_GET_SET_FIELD
(
int32_t
,
field_20
)
// Optional, get/set access.
ADD_GET_SET_FIELD
(
optional_type
,
field_21
)
// Optional, get/set access, fallback (0).
ADD_GET_SET_FIELD
(
optional_type
,
field_22
)
// Optional, get/set access, invariant (>= 0).
ADD_GET_SET_FIELD
(
optional_type
,
field_23
)
// Optional, get/set access, fallback (0), invariant (>= 0).
ADD_GET_SET_FIELD
(
optional_type
,
field_24
)
// Variant, get/set access.
ADD_GET_SET_FIELD
(
variant_type
,
field_25
)
// Variant, get/set access, fallback (0).
ADD_GET_SET_FIELD
(
variant_type
,
field_26
)
// Variant, get/set access, invariant (>= 0).
ADD_GET_SET_FIELD
(
variant_type
,
field_27
)
// Variant, get/set access, fallback (0), invariant (>= 0).
ADD_GET_SET_FIELD
(
variant_type
,
field_28
)
// Tuple, get/set access.
ADD_GET_SET_FIELD
(
tuple_type
,
field_29
)
// Tuple, get/set access, fallback ("", 0).
ADD_GET_SET_FIELD
(
tuple_type
,
field_30
)
// Tuple, get/set access, invariant (>= 0).
ADD_GET_SET_FIELD
(
tuple_type
,
field_31
)
// Tuple, get/set access, fallback ("", 0), invariant (>= 0).
ADD_GET_SET_FIELD
(
tuple_type
,
field_32
)
// Optional variant, direct access.
optional_variant_type
field_33
;
// Optional tuple, direct access.
optional_tuple_type
field_34
;
// Optional variant, get/set access.
ADD_GET_SET_FIELD
(
optional_variant_type
,
field_35
)
// Optional variant, get/set access.
ADD_GET_SET_FIELD
(
optional_tuple_type
,
field_36
)
// Plain, direct access with custom inspector_access.
weekday
field_37
;
// Plain, get/set access with custom inspector_access.
ADD_GET_SET_FIELD
(
weekday
,
field_38
)
};
#undef ADD_GET_SET_FIELD
#define DIRECT_FIELD(num) field("field_" #num, x.field_##num)
#define GET_SET_FIELD(num) \
field( \
"field_" #num, [&x]() -> decltype(auto) { return x.field_##num(); }, \
[&x](auto&& value) { \
x.field_##num(std::forward<decltype(value)>(value)); \
return true; \
})
template
<
class
Inspector
>
bool
inspect
(
Inspector
&
f
,
nasty
&
x
)
{
using
caf
::
get
;
using
caf
::
get_if
;
struct
{
bool
operator
()(
int32_t
x
)
{
return
x
>=
0
;
}
bool
operator
()(
const
nasty
::
optional_type
&
x
)
{
return
x
?
*
x
>=
0
:
true
;
}
bool
operator
()(
const
nasty
::
variant_type
&
x
)
{
if
(
auto
ptr
=
get_if
<
int32_t
>
(
&
x
))
return
*
ptr
>=
0
;
return
true
;
}
bool
operator
()(
const
nasty
::
tuple_type
&
x
)
{
return
get
<
1
>
(
x
)
>=
0
;
}
}
is_positive
;
nasty
::
variant_type
default_variant
{
int32_t
{
0
}};
nasty
::
tuple_type
default_tuple
{
""
,
0
};
return
f
.
object
(
x
).
fields
(
//
f
.
DIRECT_FIELD
(
01
),
//
f
.
DIRECT_FIELD
(
02
).
fallback
(
0
),
//
f
.
DIRECT_FIELD
(
03
).
invariant
(
is_positive
),
//
f
.
DIRECT_FIELD
(
04
).
fallback
(
0
).
invariant
(
is_positive
),
//
f
.
DIRECT_FIELD
(
05
),
//
f
.
DIRECT_FIELD
(
06
).
fallback
(
0
),
//
f
.
DIRECT_FIELD
(
07
).
invariant
(
is_positive
),
//
f
.
DIRECT_FIELD
(
08
).
fallback
(
0
).
invariant
(
is_positive
),
//
f
.
DIRECT_FIELD
(
09
),
//
f
.
DIRECT_FIELD
(
10
).
fallback
(
default_variant
),
//
f
.
DIRECT_FIELD
(
11
).
invariant
(
is_positive
),
//
f
.
DIRECT_FIELD
(
12
).
fallback
(
default_variant
).
invariant
(
is_positive
),
//
f
.
DIRECT_FIELD
(
13
),
//
f
.
DIRECT_FIELD
(
14
).
fallback
(
default_tuple
),
//
f
.
DIRECT_FIELD
(
15
).
invariant
(
is_positive
),
//
f
.
DIRECT_FIELD
(
16
).
fallback
(
default_tuple
).
invariant
(
is_positive
),
//
f
.
GET_SET_FIELD
(
17
),
//
f
.
GET_SET_FIELD
(
18
).
fallback
(
0
),
//
f
.
GET_SET_FIELD
(
19
).
invariant
(
is_positive
),
//
f
.
GET_SET_FIELD
(
20
).
fallback
(
0
).
invariant
(
is_positive
),
//
f
.
GET_SET_FIELD
(
21
),
//
f
.
GET_SET_FIELD
(
22
).
fallback
(
0
),
//
f
.
GET_SET_FIELD
(
23
).
invariant
(
is_positive
),
//
f
.
GET_SET_FIELD
(
24
).
fallback
(
0
).
invariant
(
is_positive
),
//
f
.
GET_SET_FIELD
(
25
),
//
f
.
GET_SET_FIELD
(
26
).
fallback
(
default_variant
),
//
f
.
GET_SET_FIELD
(
27
).
invariant
(
is_positive
),
//
f
.
GET_SET_FIELD
(
28
).
fallback
(
default_variant
).
invariant
(
is_positive
),
//
f
.
GET_SET_FIELD
(
29
),
//
f
.
GET_SET_FIELD
(
30
).
fallback
(
default_tuple
),
//
f
.
GET_SET_FIELD
(
31
).
invariant
(
is_positive
),
//
f
.
GET_SET_FIELD
(
32
).
fallback
(
default_tuple
).
invariant
(
is_positive
),
//
f
.
DIRECT_FIELD
(
33
),
//
f
.
DIRECT_FIELD
(
34
),
//
f
.
GET_SET_FIELD
(
35
),
//
f
.
GET_SET_FIELD
(
36
));
}
#undef DIRECT_FIELD
#undef GET_SET_FIELD
libcaf_core/test/save_inspector.cpp
View file @
4bbccd70
...
...
@@ -26,33 +26,7 @@
#include <string>
#include <vector>
namespace
caf
{
template
<
>
struct
inspector_access
<
std
::
string
>
{
template
<
class
Inspector
>
static
bool
apply
(
Inspector
&
f
,
std
::
string
&
x
)
{
return
f
.
value
(
x
);
}
};
template
<
>
struct
inspector_access
<
int32_t
>
{
template
<
class
Inspector
>
static
bool
apply
(
Inspector
&
f
,
int32_t
&
x
)
{
return
f
.
value
(
x
);
}
};
template
<
>
struct
inspector_access
<
double
>
{
template
<
class
Inspector
>
static
bool
apply
(
Inspector
&
f
,
double
&
x
)
{
return
f
.
value
(
x
);
}
};
}
// namespace caf
#include "nasty.hpp"
using
namespace
caf
;
...
...
@@ -174,6 +148,16 @@ struct testee : save_inspector {
return
object_t
<
testee
>
{
T
::
tname
,
this
};
}
template
<
class
T
>
auto
object
(
optional
<
T
>&
)
{
return
object_t
<
testee
>
{
"optional"
,
this
};
}
template
<
class
...
Ts
>
auto
object
(
variant
<
Ts
...
>&
)
{
return
object_t
<
testee
>
{
"variant"
,
this
};
}
bool
begin_object
(
string_view
object_name
)
{
new_line
();
indent
+=
2
;
...
...
@@ -205,6 +189,22 @@ struct testee : save_inspector {
return
ok
;
}
bool
begin_field
(
string_view
name
,
span
<
const
type_id_t
>
,
size_t
)
{
new_line
();
indent
+=
2
;
log
+=
"begin variant field "
;
log
.
insert
(
log
.
end
(),
name
.
begin
(),
name
.
end
());
return
ok
;
}
bool
begin_field
(
string_view
name
,
bool
,
span
<
const
type_id_t
>
,
size_t
)
{
new_line
();
indent
+=
2
;
log
+=
"begin optional variant field "
;
log
.
insert
(
log
.
end
(),
name
.
begin
(),
name
.
end
());
return
ok
;
}
bool
end_field
()
{
indent
-=
2
;
new_line
();
...
...
@@ -212,13 +212,34 @@ struct testee : save_inspector {
return
ok
;
}
bool
begin_tuple
(
size_t
size
)
{
new_line
();
indent
+=
2
;
log
+=
"begin tuple of size "
;
log
+=
std
::
to_string
(
size
);
return
ok
;
}
bool
end_tuple
()
{
indent
-=
2
;
new_line
();
log
+=
"end tuple"
;
return
ok
;
}
template
<
class
T
>
bool
value
(
const
T
&
)
{
std
::
enable_if_t
<
std
::
is_arithmetic
<
T
>::
value
,
bool
>
value
(
const
T
&
)
{
new_line
();
log
+=
type_name_v
<
T
>
;
log
+=
" value"
;
return
ok
;
}
bool
value
(
const
std
::
string
&
)
{
new_line
();
log
+=
"std::string value"
;
return
ok
;
}
};
struct
fixture
{
...
...
@@ -291,19 +312,38 @@ end object)_");
}
CAF_TEST
(
save
inspectors
support
fields
with
fallbacks
and
invariants
)
{
duration
d
{
"minutes"
,
42.0
};
CAF_CHECK_EQUAL
(
inspect
(
f
,
d
),
true
);
CAF_CHECK_EQUAL
(
d
.
unit
,
"minutes"
);
CAF_CHECK_EQUAL
(
d
.
count
,
42.0
);
CAF_CHECK_EQUAL
(
f
.
log
,
R"_(
CAF_MESSAGE
(
"save inspectors suppress fields with their default value"
);
{
duration
d
{
"seconds"
,
12.0
};
CAF_CHECK_EQUAL
(
inspect
(
f
,
d
),
true
);
CAF_CHECK_EQUAL
(
d
.
unit
,
"seconds"
);
CAF_CHECK_EQUAL
(
d
.
count
,
12.0
);
CAF_CHECK_EQUAL
(
f
.
log
,
R"_(
begin object duration
begin field unit
begin optional field unit
end field
begin field count
double value
end field
end object)_"
);
}
f
.
log
.
clear
();
CAF_MESSAGE
(
"save inspectors include fields with non-default value"
);
{
duration
d
{
"minutes"
,
42.0
};
CAF_CHECK_EQUAL
(
inspect
(
f
,
d
),
true
);
CAF_CHECK_EQUAL
(
d
.
unit
,
"minutes"
);
CAF_CHECK_EQUAL
(
d
.
count
,
42.0
);
CAF_CHECK_EQUAL
(
f
.
log
,
R"_(
begin object duration
begin optional field unit
std::string value
end field
begin field count
double value
end field
end object)_"
);
}
}
CAF_TEST
(
save
inspectors
support
fields
with
optional
values
)
{
...
...
@@ -335,7 +375,7 @@ CAF_TEST(save inspectors support fields with getters and setters) {
foobar
fb
;
fb
.
foo
(
"hello"
);
fb
.
bar
(
"world"
);
CAF_CHECK
_EQUAL
(
inspect
(
f
,
fb
),
true
);
CAF_CHECK
(
inspect
(
f
,
fb
)
);
CAF_CHECK_EQUAL
(
fb
.
foo
(),
"hello"
);
CAF_CHECK_EQUAL
(
fb
.
bar
(),
"world"
);
CAF_CHECK_EQUAL
(
f
.
log
,
R"_(
...
...
@@ -349,4 +389,112 @@ begin object foobar
end object)_"
);
}
CAF_TEST
(
save
inspectors
support
nasty
data
structures
)
{
nasty
x
;
CAF_CHECK
(
inspect
(
f
,
x
));
CAF_CHECK_EQUAL
(
f
.
log
,
R"_(
begin object nasty
begin field field_01
int32_t value
end field
begin optional field field_02
end field
begin field field_03
int32_t value
end field
begin optional field field_04
end field
begin optional field field_05
end field
begin optional field field_06
end field
begin optional field field_07
end field
begin optional field field_08
end field
begin variant field field_09
std::string value
end field
begin optional variant field field_10
std::string value
end field
begin variant field field_11
std::string value
end field
begin optional variant field field_12
std::string value
end field
begin field field_13
begin tuple of size 2
std::string value
int32_t value
end tuple
end field
begin optional field field_14
end field
begin field field_15
begin tuple of size 2
std::string value
int32_t value
end tuple
end field
begin optional field field_16
end field
begin field field_17
int32_t value
end field
begin optional field field_18
end field
begin field field_19
int32_t value
end field
begin optional field field_20
end field
begin optional field field_21
end field
begin optional field field_22
end field
begin optional field field_23
end field
begin optional field field_24
end field
begin variant field field_25
std::string value
end field
begin optional variant field field_26
std::string value
end field
begin variant field field_27
std::string value
end field
begin optional variant field field_28
std::string value
end field
begin field field_29
begin tuple of size 2
std::string value
int32_t value
end tuple
end field
begin optional field field_30
end field
begin field field_31
begin tuple of size 2
std::string value
int32_t value
end tuple
end field
begin optional field field_32
end field
begin optional variant field field_33
end field
begin optional field field_34
end field
begin optional variant field field_35
end field
begin optional field field_36
end field
end object)_"
);
}
CAF_TEST_FIXTURE_SCOPE_END
()
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