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
Feb 05, 2018
by
Kenton Varda
Committed by
GitHub
Feb 05, 2018
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
Show 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 {
...
@@ -49,6 +49,7 @@ struct FieldHash {
struct
JsonCodec
::
Impl
{
struct
JsonCodec
::
Impl
{
bool
prettyPrint
=
false
;
bool
prettyPrint
=
false
;
HasMode
hasMode
=
HasMode
::
NON_NULL
;
size_t
maxNestingDepth
=
64
;
size_t
maxNestingDepth
=
64
;
std
::
unordered_map
<
Type
,
HandlerBase
*
,
TypeHash
>
typeHandlers
;
std
::
unordered_map
<
Type
,
HandlerBase
*
,
TypeHash
>
typeHandlers
;
...
@@ -195,6 +196,8 @@ void JsonCodec::setMaxNestingDepth(size_t maxNestingDepth) {
...
@@ -195,6 +196,8 @@ void JsonCodec::setMaxNestingDepth(size_t maxNestingDepth) {
impl
->
maxNestingDepth
=
maxNestingDepth
;
impl
->
maxNestingDepth
=
maxNestingDepth
;
}
}
void
JsonCodec
::
setHasMode
(
HasMode
mode
)
{
impl
->
hasMode
=
mode
;
}
kj
::
String
JsonCodec
::
encode
(
DynamicValue
::
Reader
value
,
Type
type
)
const
{
kj
::
String
JsonCodec
::
encode
(
DynamicValue
::
Reader
value
,
Type
type
)
const
{
MallocMessageBuilder
message
;
MallocMessageBuilder
message
;
auto
json
=
message
.
getRoot
<
JsonValue
>
();
auto
json
=
message
.
getRoot
<
JsonValue
>
();
...
@@ -308,7 +311,7 @@ void JsonCodec::encode(DynamicValue::Reader input, Type type, JsonValue::Builder
...
@@ -308,7 +311,7 @@ void JsonCodec::encode(DynamicValue::Reader input, Type type, JsonValue::Builder
uint
fieldCount
=
0
;
uint
fieldCount
=
0
;
for
(
auto
i
:
kj
::
indices
(
nonUnionFields
))
{
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.
// 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
...
@@ -318,7 +321,7 @@ void JsonCodec::encode(DynamicValue::Reader input, Type type, JsonValue::Builder
KJ_IF_MAYBE
(
field
,
which
)
{
KJ_IF_MAYBE
(
field
,
which
)
{
// Even if the union field is null, if it is not the default field of the union then we
// Even if the union field is null, if it is not the default field of the union then we
// have to print it anyway.
// have to print it anyway.
unionFieldIsNull
=
!
structValue
.
has
(
*
field
);
unionFieldIsNull
=
!
structValue
.
has
(
*
field
,
impl
->
hasMode
);
if
(
field
->
getProto
().
getDiscriminantValue
()
!=
0
||
!
unionFieldIsNull
)
{
if
(
field
->
getProto
().
getDiscriminantValue
()
!=
0
||
!
unionFieldIsNull
)
{
++
fieldCount
;
++
fieldCount
;
}
else
{
}
else
{
...
...
c++/src/capnp/compat/json.h
View file @
3f928587
...
@@ -74,6 +74,12 @@ public:
...
@@ -74,6 +74,12 @@ public:
// Set maximum nesting depth when decoding JSON to prevent highly nested input from overflowing
// Set maximum nesting depth when decoding JSON to prevent highly nested input from overflowing
// the call stack. The default is 64.
// 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
>
template
<
typename
T
>
kj
::
String
encode
(
T
&&
value
)
const
;
kj
::
String
encode
(
T
&&
value
)
const
;
// Encode any Cap'n Proto value to JSON, including primitives and
// Encode any Cap'n Proto value to JSON, including primitives and
...
...
c++/src/capnp/dynamic-test.c++
View file @
3f928587
...
@@ -422,15 +422,20 @@ TEST(DynamicApi, Has) {
...
@@ -422,15 +422,20 @@ TEST(DynamicApi, Has) {
// Primitive fields are always present even if set to default.
// Primitive fields are always present even if set to default.
EXPECT_TRUE
(
root
.
has
(
"int32Field"
));
EXPECT_TRUE
(
root
.
has
(
"int32Field"
));
EXPECT_FALSE
(
root
.
has
(
"int32Field"
,
HasMode
::
NON_DEFAULT
));
root
.
set
(
"int32Field"
,
123
);
root
.
set
(
"int32Field"
,
123
);
EXPECT_TRUE
(
root
.
has
(
"int32Field"
));
EXPECT_TRUE
(
root
.
has
(
"int32Field"
));
EXPECT_TRUE
(
root
.
has
(
"int32Field"
,
HasMode
::
NON_DEFAULT
));
root
.
set
(
"int32Field"
,
-
12345678
);
root
.
set
(
"int32Field"
,
-
12345678
);
EXPECT_TRUE
(
root
.
has
(
"int32Field"
));
EXPECT_TRUE
(
root
.
has
(
"int32Field"
));
EXPECT_FALSE
(
root
.
has
(
"int32Field"
,
HasMode
::
NON_DEFAULT
));
// Pointers are absent until initialized.
// Pointers are absent until initialized.
EXPECT_FALSE
(
root
.
has
(
"structField"
));
EXPECT_FALSE
(
root
.
has
(
"structField"
));
EXPECT_FALSE
(
root
.
has
(
"structField"
,
HasMode
::
NON_DEFAULT
));
root
.
init
(
"structField"
);
root
.
init
(
"structField"
);
EXPECT_TRUE
(
root
.
has
(
"structField"
));
EXPECT_TRUE
(
root
.
has
(
"structField"
));
EXPECT_TRUE
(
root
.
has
(
"structField"
,
HasMode
::
NON_DEFAULT
));
}
}
TEST
(
DynamicApi
,
HasWhenEmpty
)
{
TEST
(
DynamicApi
,
HasWhenEmpty
)
{
...
@@ -443,6 +448,11 @@ TEST(DynamicApi, HasWhenEmpty) {
...
@@ -443,6 +448,11 @@ TEST(DynamicApi, HasWhenEmpty) {
EXPECT_TRUE
(
root
.
has
(
"int32Field"
));
EXPECT_TRUE
(
root
.
has
(
"int32Field"
));
EXPECT_FALSE
(
root
.
has
(
"structField"
));
EXPECT_FALSE
(
root
.
has
(
"structField"
));
EXPECT_FALSE
(
root
.
has
(
"int32List"
));
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
)
{
TEST
(
DynamicApi
,
SetEnumFromNative
)
{
...
...
c++/src/capnp/dynamic.c++
View file @
3f928587
...
@@ -414,7 +414,7 @@ DynamicValue::Pipeline DynamicStruct::Pipeline::get(StructSchema::Field field) {
...
@@ -414,7 +414,7 @@ DynamicValue::Pipeline DynamicStruct::Pipeline::get(StructSchema::Field field) {
KJ_UNREACHABLE
;
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."
);
KJ_REQUIRE
(
field
.
getContainingStruct
()
==
schema
,
"`field` is not a field of this struct."
);
auto
proto
=
field
.
getProto
();
auto
proto
=
field
.
getProto
();
...
@@ -441,20 +441,35 @@ bool DynamicStruct::Reader::has(StructSchema::Field field) const {
...
@@ -441,20 +441,35 @@ bool DynamicStruct::Reader::has(StructSchema::Field field) const {
switch
(
type
.
which
())
{
switch
(
type
.
which
())
{
case
schema
:
:
Type
::
VOID
:
case
schema
:
:
Type
::
VOID
:
// Void is always equal to the default.
return
mode
==
HasMode
::
NON_NULL
;
case
schema
:
:
Type
::
BOOL
:
case
schema
:
:
Type
::
BOOL
:
return
mode
==
HasMode
::
NON_NULL
||
reader
.
getDataField
<
bool
>
(
assumeDataOffset
(
slot
.
getOffset
()),
0
)
!=
0
;
case
schema
:
:
Type
::
INT8
:
case
schema
:
:
Type
::
INT8
:
case
schema
:
:
Type
::
INT16
:
case
schema
:
:
Type
::
INT32
:
case
schema
:
:
Type
::
INT64
:
case
schema
:
:
Type
::
UINT8
:
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
::
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
::
UINT32
:
case
schema
:
:
Type
::
UINT64
:
case
schema
:
:
Type
::
FLOAT32
:
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
::
FLOAT64
:
case
schema
:
:
Type
::
ENUM
:
return
mode
==
HasMode
::
NON_NULL
||
// Primitive types are always present.
reader
.
getDataField
<
uint64_t
>
(
assumeDataOffset
(
slot
.
getOffset
()),
0
)
!=
0
;
return
true
;
case
schema
:
:
Type
::
TEXT
:
case
schema
:
:
Type
::
TEXT
:
case
schema
:
:
Type
::
DATA
:
case
schema
:
:
Type
::
DATA
:
...
@@ -985,11 +1000,11 @@ DynamicValue::Builder DynamicStruct::Builder::get(kj::StringPtr name) {
...
@@ -985,11 +1000,11 @@ DynamicValue::Builder DynamicStruct::Builder::get(kj::StringPtr name) {
DynamicValue
::
Pipeline
DynamicStruct
::
Pipeline
::
get
(
kj
::
StringPtr
name
)
{
DynamicValue
::
Pipeline
DynamicStruct
::
Pipeline
::
get
(
kj
::
StringPtr
name
)
{
return
get
(
schema
.
getFieldByName
(
name
));
return
get
(
schema
.
getFieldByName
(
name
));
}
}
bool
DynamicStruct
::
Reader
::
has
(
kj
::
StringPtr
name
)
const
{
bool
DynamicStruct
::
Reader
::
has
(
kj
::
StringPtr
name
,
HasMode
mode
)
const
{
return
has
(
schema
.
getFieldByName
(
name
));
return
has
(
schema
.
getFieldByName
(
name
)
,
mode
);
}
}
bool
DynamicStruct
::
Builder
::
has
(
kj
::
StringPtr
name
)
{
bool
DynamicStruct
::
Builder
::
has
(
kj
::
StringPtr
name
,
HasMode
mode
)
{
return
has
(
schema
.
getFieldByName
(
name
));
return
has
(
schema
.
getFieldByName
(
name
)
,
mode
);
}
}
void
DynamicStruct
::
Builder
::
set
(
kj
::
StringPtr
name
,
const
DynamicValue
::
Reader
&
value
)
{
void
DynamicStruct
::
Builder
::
set
(
kj
::
StringPtr
name
,
const
DynamicValue
::
Reader
&
value
)
{
set
(
schema
.
getFieldByName
(
name
),
value
);
set
(
schema
.
getFieldByName
(
name
),
value
);
...
...
c++/src/capnp/dynamic.h
View file @
3f928587
...
@@ -169,6 +169,21 @@ private:
...
@@ -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
{
class
DynamicStruct
::
Reader
{
public
:
public
:
typedef
DynamicStruct
Reads
;
typedef
DynamicStruct
Reads
;
...
@@ -191,12 +206,10 @@ public:
...
@@ -191,12 +206,10 @@ public:
DynamicValue
::
Reader
get
(
StructSchema
::
Field
field
)
const
;
DynamicValue
::
Reader
get
(
StructSchema
::
Field
field
)
const
;
// Read the given field value.
// Read the given field value.
bool
has
(
StructSchema
::
Field
field
)
const
;
bool
has
(
StructSchema
::
Field
field
,
HasMode
mode
=
HasMode
::
NON_NULL
)
const
;
// Tests whether the given field is set to its default value. For pointer values, this does
// Tests whether the given field is "present". If the field is a union member and is not the
// not actually traverse the value comparing it with the default, but simply returns true if the
// active member, this always returns false. Otherwise, the field's value is interpreted
// pointer is non-null. For members of unions, has() returns false if the union member is not
// according to `mode`.
// active, but does not necessarily return true if the member is active (depends on the field's
// value).
kj
::
Maybe
<
StructSchema
::
Field
>
which
()
const
;
kj
::
Maybe
<
StructSchema
::
Field
>
which
()
const
;
// If the struct contains an (unnamed) union, and the currently-active field within that union
// If the struct contains an (unnamed) union, and the currently-active field within that union
...
@@ -206,7 +219,7 @@ public:
...
@@ -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.
// 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
;
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.
// Shortcuts to access fields by name. These throw exceptions if no such field exists.
private
:
private
:
...
@@ -261,12 +274,11 @@ public:
...
@@ -261,12 +274,11 @@ public:
DynamicValue
::
Builder
get
(
StructSchema
::
Field
field
);
DynamicValue
::
Builder
get
(
StructSchema
::
Field
field
);
// Read the given field value.
// Read the given field value.
inline
bool
has
(
StructSchema
::
Field
field
)
{
return
asReader
().
has
(
field
);
}
inline
bool
has
(
StructSchema
::
Field
field
,
HasMode
mode
=
HasMode
::
NON_NULL
)
// Tests whether the given field is set to its default value. For pointer values, this does
{
return
asReader
().
has
(
field
,
mode
);
}
// not actually traverse the value comparing it with the default, but simply returns true if the
// Tests whether the given field is "present". If the field is a union member and is not the
// pointer is non-null. For members of unions, has() returns whether the field is currently
// active member, this always returns false. Otherwise, the field's value is interpreted
// active and the union as a whole is non-default -- so, the only time has() will return false
// according to `mode`.
// for an active union field is if it is the default active field and it has its default value.
kj
::
Maybe
<
StructSchema
::
Field
>
which
();
kj
::
Maybe
<
StructSchema
::
Field
>
which
();
// If the struct contains an (unnamed) union, and the currently-active field within that union
// If the struct contains an (unnamed) union, and the currently-active field within that union
...
@@ -292,7 +304,7 @@ public:
...
@@ -292,7 +304,7 @@ public:
// field null.
// field null.
DynamicValue
::
Builder
get
(
kj
::
StringPtr
name
);
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
,
const
DynamicValue
::
Reader
&
value
);
void
set
(
kj
::
StringPtr
name
,
std
::
initializer_list
<
DynamicValue
::
Reader
>
value
);
void
set
(
kj
::
StringPtr
name
,
std
::
initializer_list
<
DynamicValue
::
Reader
>
value
);
DynamicValue
::
Builder
init
(
kj
::
StringPtr
name
);
DynamicValue
::
Builder
init
(
kj
::
StringPtr
name
);
...
...
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