Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in / Register
Toggle navigation
C
capnproto
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Packages
Packages
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
submodule
capnproto
Commits
3f928587
Unverified
Commit
3f928587
authored
7 years ago
by
Kenton Varda
Committed by
GitHub
7 years ago
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #628 from capnproto/json-omit-defaults
Add option to omit default-valued primitives from JSON output.
parents
328e6f5b
71721e5c
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
74 additions
and
28 deletions
+74
-28
json.c++
c++/src/capnp/compat/json.c++
+5
-2
json.h
c++/src/capnp/compat/json.h
+6
-0
dynamic-test.c++
c++/src/capnp/dynamic-test.c++
+10
-0
dynamic.c++
c++/src/capnp/dynamic.c++
+27
-12
dynamic.h
c++/src/capnp/dynamic.h
+26
-14
No files found.
c++/src/capnp/compat/json.c++
View file @
3f928587
...
...
@@ -49,6 +49,7 @@ struct FieldHash {
struct
JsonCodec
::
Impl
{
bool
prettyPrint
=
false
;
HasMode
hasMode
=
HasMode
::
NON_NULL
;
size_t
maxNestingDepth
=
64
;
std
::
unordered_map
<
Type
,
HandlerBase
*
,
TypeHash
>
typeHandlers
;
...
...
@@ -195,6 +196,8 @@ void JsonCodec::setMaxNestingDepth(size_t maxNestingDepth) {
impl
->
maxNestingDepth
=
maxNestingDepth
;
}
void
JsonCodec
::
setHasMode
(
HasMode
mode
)
{
impl
->
hasMode
=
mode
;
}
kj
::
String
JsonCodec
::
encode
(
DynamicValue
::
Reader
value
,
Type
type
)
const
{
MallocMessageBuilder
message
;
auto
json
=
message
.
getRoot
<
JsonValue
>
();
...
...
@@ -308,7 +311,7 @@ void JsonCodec::encode(DynamicValue::Reader input, Type type, JsonValue::Builder
uint
fieldCount
=
0
;
for
(
auto
i
:
kj
::
indices
(
nonUnionFields
))
{
fieldCount
+=
(
hasField
[
i
]
=
structValue
.
has
(
nonUnionFields
[
i
]));
fieldCount
+=
(
hasField
[
i
]
=
structValue
.
has
(
nonUnionFields
[
i
]
,
impl
->
hasMode
));
}
// We try to write the union field, if any, in proper order with the rest.
...
...
@@ -318,7 +321,7 @@ void JsonCodec::encode(DynamicValue::Reader input, Type type, JsonValue::Builder
KJ_IF_MAYBE
(
field
,
which
)
{
// Even if the union field is null, if it is not the default field of the union then we
// have to print it anyway.
unionFieldIsNull
=
!
structValue
.
has
(
*
field
);
unionFieldIsNull
=
!
structValue
.
has
(
*
field
,
impl
->
hasMode
);
if
(
field
->
getProto
().
getDiscriminantValue
()
!=
0
||
!
unionFieldIsNull
)
{
++
fieldCount
;
}
else
{
...
...
This diff is collapsed.
Click to expand it.
c++/src/capnp/compat/json.h
View file @
3f928587
...
...
@@ -74,6 +74,12 @@ public:
// Set maximum nesting depth when decoding JSON to prevent highly nested input from overflowing
// the call stack. The default is 64.
void
setHasMode
(
HasMode
mode
);
// Normally, primitive field values are always included even if they are equal to the default
// value (HasMode::NON_NULL -- only null pointers are omitted). You can use
// setHasMode(HasMode::NON_DEFAULT) to specify that default-valued primitive fields should be
// omitted as well.
template
<
typename
T
>
kj
::
String
encode
(
T
&&
value
)
const
;
// Encode any Cap'n Proto value to JSON, including primitives and
...
...
This diff is collapsed.
Click to expand it.
c++/src/capnp/dynamic-test.c++
View file @
3f928587
...
...
@@ -422,15 +422,20 @@ TEST(DynamicApi, Has) {
// Primitive fields are always present even if set to default.
EXPECT_TRUE
(
root
.
has
(
"int32Field"
));
EXPECT_FALSE
(
root
.
has
(
"int32Field"
,
HasMode
::
NON_DEFAULT
));
root
.
set
(
"int32Field"
,
123
);
EXPECT_TRUE
(
root
.
has
(
"int32Field"
));
EXPECT_TRUE
(
root
.
has
(
"int32Field"
,
HasMode
::
NON_DEFAULT
));
root
.
set
(
"int32Field"
,
-
12345678
);
EXPECT_TRUE
(
root
.
has
(
"int32Field"
));
EXPECT_FALSE
(
root
.
has
(
"int32Field"
,
HasMode
::
NON_DEFAULT
));
// Pointers are absent until initialized.
EXPECT_FALSE
(
root
.
has
(
"structField"
));
EXPECT_FALSE
(
root
.
has
(
"structField"
,
HasMode
::
NON_DEFAULT
));
root
.
init
(
"structField"
);
EXPECT_TRUE
(
root
.
has
(
"structField"
));
EXPECT_TRUE
(
root
.
has
(
"structField"
,
HasMode
::
NON_DEFAULT
));
}
TEST
(
DynamicApi
,
HasWhenEmpty
)
{
...
...
@@ -443,6 +448,11 @@ TEST(DynamicApi, HasWhenEmpty) {
EXPECT_TRUE
(
root
.
has
(
"int32Field"
));
EXPECT_FALSE
(
root
.
has
(
"structField"
));
EXPECT_FALSE
(
root
.
has
(
"int32List"
));
EXPECT_FALSE
(
root
.
has
(
"voidField"
,
HasMode
::
NON_DEFAULT
));
EXPECT_FALSE
(
root
.
has
(
"int32Field"
,
HasMode
::
NON_DEFAULT
));
EXPECT_FALSE
(
root
.
has
(
"structField"
,
HasMode
::
NON_DEFAULT
));
EXPECT_FALSE
(
root
.
has
(
"int32List"
,
HasMode
::
NON_DEFAULT
));
}
TEST
(
DynamicApi
,
SetEnumFromNative
)
{
...
...
This diff is collapsed.
Click to expand it.
c++/src/capnp/dynamic.c++
View file @
3f928587
...
...
@@ -414,7 +414,7 @@ DynamicValue::Pipeline DynamicStruct::Pipeline::get(StructSchema::Field field) {
KJ_UNREACHABLE
;
}
bool
DynamicStruct
::
Reader
::
has
(
StructSchema
::
Field
field
)
const
{
bool
DynamicStruct
::
Reader
::
has
(
StructSchema
::
Field
field
,
HasMode
mode
)
const
{
KJ_REQUIRE
(
field
.
getContainingStruct
()
==
schema
,
"`field` is not a field of this struct."
);
auto
proto
=
field
.
getProto
();
...
...
@@ -441,20 +441,35 @@ bool DynamicStruct::Reader::has(StructSchema::Field field) const {
switch
(
type
.
which
())
{
case
schema
:
:
Type
::
VOID
:
// Void is always equal to the default.
return
mode
==
HasMode
::
NON_NULL
;
case
schema
:
:
Type
::
BOOL
:
return
mode
==
HasMode
::
NON_NULL
||
reader
.
getDataField
<
bool
>
(
assumeDataOffset
(
slot
.
getOffset
()),
0
)
!=
0
;
case
schema
:
:
Type
::
INT8
:
case
schema
:
:
Type
::
INT16
:
case
schema
:
:
Type
::
INT32
:
case
schema
:
:
Type
::
INT64
:
case
schema
:
:
Type
::
UINT8
:
return
mode
==
HasMode
::
NON_NULL
||
reader
.
getDataField
<
uint8_t
>
(
assumeDataOffset
(
slot
.
getOffset
()),
0
)
!=
0
;
case
schema
:
:
Type
::
INT16
:
case
schema
:
:
Type
::
UINT16
:
case
schema
:
:
Type
::
ENUM
:
return
mode
==
HasMode
::
NON_NULL
||
reader
.
getDataField
<
uint16_t
>
(
assumeDataOffset
(
slot
.
getOffset
()),
0
)
!=
0
;
case
schema
:
:
Type
::
INT32
:
case
schema
:
:
Type
::
UINT32
:
case
schema
:
:
Type
::
UINT64
:
case
schema
:
:
Type
::
FLOAT32
:
return
mode
==
HasMode
::
NON_NULL
||
reader
.
getDataField
<
uint32_t
>
(
assumeDataOffset
(
slot
.
getOffset
()),
0
)
!=
0
;
case
schema
:
:
Type
::
INT64
:
case
schema
:
:
Type
::
UINT64
:
case
schema
:
:
Type
::
FLOAT64
:
case
schema
:
:
Type
::
ENUM
:
// Primitive types are always present.
return
true
;
return
mode
==
HasMode
::
NON_NULL
||
reader
.
getDataField
<
uint64_t
>
(
assumeDataOffset
(
slot
.
getOffset
()),
0
)
!=
0
;
case
schema
:
:
Type
::
TEXT
:
case
schema
:
:
Type
::
DATA
:
...
...
@@ -985,11 +1000,11 @@ DynamicValue::Builder DynamicStruct::Builder::get(kj::StringPtr name) {
DynamicValue
::
Pipeline
DynamicStruct
::
Pipeline
::
get
(
kj
::
StringPtr
name
)
{
return
get
(
schema
.
getFieldByName
(
name
));
}
bool
DynamicStruct
::
Reader
::
has
(
kj
::
StringPtr
name
)
const
{
return
has
(
schema
.
getFieldByName
(
name
));
bool
DynamicStruct
::
Reader
::
has
(
kj
::
StringPtr
name
,
HasMode
mode
)
const
{
return
has
(
schema
.
getFieldByName
(
name
)
,
mode
);
}
bool
DynamicStruct
::
Builder
::
has
(
kj
::
StringPtr
name
)
{
return
has
(
schema
.
getFieldByName
(
name
));
bool
DynamicStruct
::
Builder
::
has
(
kj
::
StringPtr
name
,
HasMode
mode
)
{
return
has
(
schema
.
getFieldByName
(
name
)
,
mode
);
}
void
DynamicStruct
::
Builder
::
set
(
kj
::
StringPtr
name
,
const
DynamicValue
::
Reader
&
value
)
{
set
(
schema
.
getFieldByName
(
name
),
value
);
...
...
This diff is collapsed.
Click to expand it.
c++/src/capnp/dynamic.h
View file @
3f928587
...
...
@@ -169,6 +169,21 @@ private:
// -------------------------------------------------------------------
enum
class
HasMode
:
uint8_t
{
// Specifies the meaning of "has(field)".
NON_NULL
,
// "has(field)" only returns false if the field is a pointer and the pointer is null. This is the
// default behavior.
NON_DEFAULT
// "has(field)" returns false if the field is set to its default value. This differs from
// NON_NULL only in the handling of primitive values.
//
// "Equal to default value" is technically defined as the field value being encoded as all-zero
// on the wire (since primitive values are XORed by their defined default value when encoded).
};
class
DynamicStruct
::
Reader
{
public
:
typedef
DynamicStruct
Reads
;
...
...
@@ -191,12 +206,10 @@ public:
DynamicValue
::
Reader
get
(
StructSchema
::
Field
field
)
const
;
// Read the given field value.
bool
has
(
StructSchema
::
Field
field
)
const
;
// Tests whether the given field is set to its default value. For pointer values, this does
// not actually traverse the value comparing it with the default, but simply returns true if the
// pointer is non-null. For members of unions, has() returns false if the union member is not
// active, but does not necessarily return true if the member is active (depends on the field's
// value).
bool
has
(
StructSchema
::
Field
field
,
HasMode
mode
=
HasMode
::
NON_NULL
)
const
;
// Tests whether the given field is "present". If the field is a union member and is not the
// active member, this always returns false. Otherwise, the field's value is interpreted
// according to `mode`.
kj
::
Maybe
<
StructSchema
::
Field
>
which
()
const
;
// If the struct contains an (unnamed) union, and the currently-active field within that union
...
...
@@ -206,7 +219,7 @@ public:
// newer version of the protocol and is using a field of the union that you don't know about yet.
DynamicValue
::
Reader
get
(
kj
::
StringPtr
name
)
const
;
bool
has
(
kj
::
StringPtr
name
)
const
;
bool
has
(
kj
::
StringPtr
name
,
HasMode
mode
=
HasMode
::
NON_NULL
)
const
;
// Shortcuts to access fields by name. These throw exceptions if no such field exists.
private
:
...
...
@@ -261,12 +274,11 @@ public:
DynamicValue
::
Builder
get
(
StructSchema
::
Field
field
);
// Read the given field value.
inline
bool
has
(
StructSchema
::
Field
field
)
{
return
asReader
().
has
(
field
);
}
// Tests whether the given field is set to its default value. For pointer values, this does
// not actually traverse the value comparing it with the default, but simply returns true if the
// pointer is non-null. For members of unions, has() returns whether the field is currently
// active and the union as a whole is non-default -- so, the only time has() will return false
// for an active union field is if it is the default active field and it has its default value.
inline
bool
has
(
StructSchema
::
Field
field
,
HasMode
mode
=
HasMode
::
NON_NULL
)
{
return
asReader
().
has
(
field
,
mode
);
}
// Tests whether the given field is "present". If the field is a union member and is not the
// active member, this always returns false. Otherwise, the field's value is interpreted
// according to `mode`.
kj
::
Maybe
<
StructSchema
::
Field
>
which
();
// If the struct contains an (unnamed) union, and the currently-active field within that union
...
...
@@ -292,7 +304,7 @@ public:
// field null.
DynamicValue
::
Builder
get
(
kj
::
StringPtr
name
);
bool
has
(
kj
::
StringPtr
name
);
bool
has
(
kj
::
StringPtr
name
,
HasMode
mode
=
HasMode
::
NON_NULL
);
void
set
(
kj
::
StringPtr
name
,
const
DynamicValue
::
Reader
&
value
);
void
set
(
kj
::
StringPtr
name
,
std
::
initializer_list
<
DynamicValue
::
Reader
>
value
);
DynamicValue
::
Builder
init
(
kj
::
StringPtr
name
);
...
...
This diff is collapsed.
Click to expand it.
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