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
ac1e532d
Commit
ac1e532d
authored
Aug 25, 2013
by
Kenton Varda
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Extend schema API to cover constants, test parsing of constants.
parent
bc7b57a7
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
322 additions
and
112 deletions
+322
-112
node-translator.c++
c++/src/capnp/compiler/node-translator.c++
+1
-1
dynamic-test.c++
c++/src/capnp/dynamic-test.c++
+7
-2
dynamic.c++
c++/src/capnp/dynamic.c++
+98
-52
dynamic.h
c++/src/capnp/dynamic.h
+76
-21
layout.c++
c++/src/capnp/layout.c++
+12
-0
layout.h
c++/src/capnp/layout.h
+8
-0
schema-parser-test.c++
c++/src/capnp/schema-parser-test.c++
+43
-9
schema.c++
c++/src/capnp/schema.c++
+40
-25
schema.h
c++/src/capnp/schema.h
+35
-1
stringify.c++
c++/src/capnp/stringify.c++
+2
-1
No files found.
c++/src/capnp/compiler/node-translator.c++
View file @
ac1e532d
...
@@ -1724,7 +1724,7 @@ kj::Maybe<DynamicValue::Reader> NodeTranslator::readConstant(
...
@@ -1724,7 +1724,7 @@ kj::Maybe<DynamicValue::Reader> NodeTranslator::readConstant(
if
(
constValue
.
getType
()
==
DynamicValue
::
OBJECT
)
{
if
(
constValue
.
getType
()
==
DynamicValue
::
OBJECT
)
{
// We need to assign an appropriate schema to this object.
// We need to assign an appropriate schema to this object.
DynamicObject
objValue
=
constValue
.
as
<
DynamicObject
>
();
DynamicObject
::
Reader
objValue
=
constValue
.
as
<
DynamicObject
>
();
auto
constType
=
constReader
.
getType
();
auto
constType
=
constReader
.
getType
();
switch
(
constType
.
which
())
{
switch
(
constType
.
which
())
{
case
schema
:
:
Type
::
STRUCT
:
case
schema
:
:
Type
::
STRUCT
:
...
...
c++/src/capnp/dynamic-test.c++
View file @
ac1e532d
...
@@ -193,7 +193,9 @@ TEST(DynamicApi, DynamicGenericObjects) {
...
@@ -193,7 +193,9 @@ TEST(DynamicApi, DynamicGenericObjects) {
checkDynamicTestMessage
(
checkDynamicTestMessage
(
root
.
asReader
().
get
(
"objectField"
).
as
<
DynamicObject
>
().
as
(
Schema
::
from
<
TestAllTypes
>
()));
root
.
asReader
().
get
(
"objectField"
).
as
<
DynamicObject
>
().
as
(
Schema
::
from
<
TestAllTypes
>
()));
checkDynamicTestMessage
(
checkDynamicTestMessage
(
root
.
get
(
"objectField"
).
as
<
DynamicObject
>
().
as
(
Schema
::
from
<
TestAllTypes
>
()));
root
.
asReader
().
get
(
"objectField"
).
as
<
DynamicObject
>
().
as
(
Schema
::
from
<
TestAllTypes
>
()));
checkDynamicTestMessage
(
root
.
get
(
"objectField"
).
as
<
DynamicObject
>
().
asReader
().
as
(
Schema
::
from
<
TestAllTypes
>
()));
checkDynamicTestMessage
(
checkDynamicTestMessage
(
root
.
getObject
(
"objectField"
,
Schema
::
from
<
TestAllTypes
>
()));
root
.
getObject
(
"objectField"
,
Schema
::
from
<
TestAllTypes
>
()));
...
@@ -219,7 +221,10 @@ TEST(DynamicApi, DynamicGenericObjects) {
...
@@ -219,7 +221,10 @@ TEST(DynamicApi, DynamicGenericObjects) {
root
.
asReader
().
get
(
"objectField"
).
as
<
DynamicObject
>
().
as
(
Schema
::
from
<
List
<
uint32_t
>>
()),
root
.
asReader
().
get
(
"objectField"
).
as
<
DynamicObject
>
().
as
(
Schema
::
from
<
List
<
uint32_t
>>
()),
{
123u
,
456u
,
789u
,
123456789u
});
{
123u
,
456u
,
789u
,
123456789u
});
checkList
<
uint32_t
>
(
checkList
<
uint32_t
>
(
root
.
get
(
"objectField"
).
as
<
DynamicObject
>
().
as
(
Schema
::
from
<
List
<
uint32_t
>>
()),
root
.
asReader
().
get
(
"objectField"
).
as
<
DynamicObject
>
().
as
(
Schema
::
from
<
List
<
uint32_t
>>
()),
{
123u
,
456u
,
789u
,
123456789u
});
checkList
<
uint32_t
>
(
root
.
get
(
"objectField"
).
as
<
DynamicObject
>
().
asReader
().
as
(
Schema
::
from
<
List
<
uint32_t
>>
()),
{
123u
,
456u
,
789u
,
123456789u
});
{
123u
,
456u
,
789u
,
123456789u
});
checkList
<
uint32_t
>
(
checkList
<
uint32_t
>
(
root
.
getObject
(
"objectField"
,
Schema
::
from
<
List
<
uint32_t
>>
()),
root
.
getObject
(
"objectField"
,
Schema
::
from
<
List
<
uint32_t
>>
()),
...
...
c++/src/capnp/dynamic.c++
View file @
ac1e532d
...
@@ -125,7 +125,7 @@ uint16_t DynamicEnum::asImpl(uint64_t requestedTypeId) const {
...
@@ -125,7 +125,7 @@ uint16_t DynamicEnum::asImpl(uint64_t requestedTypeId) const {
// =======================================================================================
// =======================================================================================
DynamicStruct
::
Reader
DynamicObject
::
as
(
StructSchema
schema
)
const
{
DynamicStruct
::
Reader
DynamicObject
::
Reader
::
as
(
StructSchema
schema
)
const
{
if
(
reader
.
kind
==
_
::
ObjectKind
::
NULL_POINTER
)
{
if
(
reader
.
kind
==
_
::
ObjectKind
::
NULL_POINTER
)
{
return
DynamicStruct
::
Reader
(
schema
,
_
::
StructReader
());
return
DynamicStruct
::
Reader
(
schema
,
_
::
StructReader
());
}
}
...
@@ -136,7 +136,7 @@ DynamicStruct::Reader DynamicObject::as(StructSchema schema) const {
...
@@ -136,7 +136,7 @@ DynamicStruct::Reader DynamicObject::as(StructSchema schema) const {
return
DynamicStruct
::
Reader
(
schema
,
reader
.
structReader
);
return
DynamicStruct
::
Reader
(
schema
,
reader
.
structReader
);
}
}
DynamicList
::
Reader
DynamicObject
::
as
(
ListSchema
schema
)
const
{
DynamicList
::
Reader
DynamicObject
::
Reader
::
as
(
ListSchema
schema
)
const
{
if
(
reader
.
kind
==
_
::
ObjectKind
::
NULL_POINTER
)
{
if
(
reader
.
kind
==
_
::
ObjectKind
::
NULL_POINTER
)
{
return
DynamicList
::
Reader
(
schema
,
_
::
ListReader
());
return
DynamicList
::
Reader
(
schema
,
_
::
ListReader
());
}
}
...
@@ -206,14 +206,13 @@ DynamicValue::Reader DynamicStruct::Reader::get(StructSchema::Field field) const
...
@@ -206,14 +206,13 @@ DynamicValue::Reader DynamicStruct::Reader::get(StructSchema::Field field) const
switch
(
type
.
which
())
{
switch
(
type
.
which
())
{
case
schema
:
:
Type
::
VOID
:
case
schema
:
:
Type
::
VOID
:
return
DynamicValue
::
Reader
(
return
reader
.
getDataField
<
Void
>
(
nonGroup
.
getOffset
()
*
ELEMENTS
);
reader
.
getDataField
<
Void
>
(
nonGroup
.
getOffset
()
*
ELEMENTS
));
#define HANDLE_TYPE(discrim, titleCase, type) \
#define HANDLE_TYPE(discrim, titleCase, type) \
case schema::Type::discrim: \
case schema::Type::discrim: \
return
DynamicValue::Reader(
reader.getDataField<type>( \
return reader.getDataField<type>( \
nonGroup.getOffset() * ELEMENTS, \
nonGroup.getOffset() * ELEMENTS, \
bitCast<_::Mask<type>>(dval.get##titleCase()))
)
;
bitCast<_::Mask<type>>(dval.get##titleCase()));
HANDLE_TYPE
(
BOOL
,
Bool
,
bool
)
HANDLE_TYPE
(
BOOL
,
Bool
,
bool
)
HANDLE_TYPE
(
INT8
,
Int8
,
int8_t
)
HANDLE_TYPE
(
INT8
,
Int8
,
int8_t
)
...
@@ -232,45 +231,43 @@ DynamicValue::Reader DynamicStruct::Reader::get(StructSchema::Field field) const
...
@@ -232,45 +231,43 @@ DynamicValue::Reader DynamicStruct::Reader::get(StructSchema::Field field) const
case
schema
:
:
Type
::
ENUM
:
{
case
schema
:
:
Type
::
ENUM
:
{
uint16_t
typedDval
;
uint16_t
typedDval
;
typedDval
=
dval
.
getEnum
();
typedDval
=
dval
.
getEnum
();
return
Dynamic
Value
::
Reader
(
Dynamic
Enum
(
return
DynamicEnum
(
field
.
getContainingStruct
().
getDependency
(
type
.
getEnum
()).
asEnum
(),
field
.
getContainingStruct
().
getDependency
(
type
.
getEnum
()).
asEnum
(),
reader
.
getDataField
<
uint16_t
>
(
nonGroup
.
getOffset
()
*
ELEMENTS
,
typedDval
))
)
;
reader
.
getDataField
<
uint16_t
>
(
nonGroup
.
getOffset
()
*
ELEMENTS
,
typedDval
));
}
}
case
schema
:
:
Type
::
TEXT
:
{
case
schema
:
:
Type
::
TEXT
:
{
Text
::
Reader
typedDval
=
dval
.
getText
();
Text
::
Reader
typedDval
=
dval
.
getText
();
return
DynamicValue
::
Reader
(
return
reader
.
getBlobField
<
Text
>
(
nonGroup
.
getOffset
()
*
POINTERS
,
reader
.
getBlobField
<
Text
>
(
nonGroup
.
getOffset
()
*
POINTERS
,
typedDval
.
begin
(),
typedDval
.
size
()
*
BYTES
);
typedDval
.
begin
(),
typedDval
.
size
()
*
BYTES
));
}
}
case
schema
:
:
Type
::
DATA
:
{
case
schema
:
:
Type
::
DATA
:
{
Data
::
Reader
typedDval
=
dval
.
getData
();
Data
::
Reader
typedDval
=
dval
.
getData
();
return
DynamicValue
::
Reader
(
return
reader
.
getBlobField
<
Data
>
(
nonGroup
.
getOffset
()
*
POINTERS
,
reader
.
getBlobField
<
Data
>
(
nonGroup
.
getOffset
()
*
POINTERS
,
typedDval
.
begin
(),
typedDval
.
size
()
*
BYTES
);
typedDval
.
begin
(),
typedDval
.
size
()
*
BYTES
));
}
}
case
schema
:
:
Type
::
LIST
:
{
case
schema
:
:
Type
::
LIST
:
{
auto
elementType
=
type
.
getList
();
auto
elementType
=
type
.
getList
();
return
Dynamic
Value
::
Reader
(
Dynamic
List
::
Reader
(
return
DynamicList
::
Reader
(
ListSchema
::
of
(
elementType
,
field
.
getContainingStruct
()),
ListSchema
::
of
(
elementType
,
field
.
getContainingStruct
()),
reader
.
getListField
(
nonGroup
.
getOffset
()
*
POINTERS
,
reader
.
getListField
(
nonGroup
.
getOffset
()
*
POINTERS
,
elementSizeFor
(
elementType
.
which
()),
elementSizeFor
(
elementType
.
which
()),
dval
.
getList
<
_
::
UncheckedMessage
>
()))
)
;
dval
.
getList
<
_
::
UncheckedMessage
>
()));
}
}
case
schema
:
:
Type
::
STRUCT
:
{
case
schema
:
:
Type
::
STRUCT
:
{
return
Dynamic
Value
::
Reader
(
Dynamic
Struct
::
Reader
(
return
DynamicStruct
::
Reader
(
field
.
getContainingStruct
().
getDependency
(
type
.
getStruct
()).
asStruct
(),
field
.
getContainingStruct
().
getDependency
(
type
.
getStruct
()).
asStruct
(),
reader
.
getStructField
(
nonGroup
.
getOffset
()
*
POINTERS
,
reader
.
getStructField
(
nonGroup
.
getOffset
()
*
POINTERS
,
dval
.
getStruct
<
_
::
UncheckedMessage
>
()))
)
;
dval
.
getStruct
<
_
::
UncheckedMessage
>
()));
}
}
case
schema
:
:
Type
::
OBJECT
:
{
case
schema
:
:
Type
::
OBJECT
:
{
return
Dynamic
Value
::
Reader
(
DynamicObject
(
return
Dynamic
Object
::
Reader
(
reader
.
getObjectField
(
nonGroup
.
getOffset
()
*
POINTERS
,
reader
.
getObjectField
(
nonGroup
.
getOffset
()
*
POINTERS
,
dval
.
getObject
<
_
::
UncheckedMessage
>
()))
)
;
dval
.
getObject
<
_
::
UncheckedMessage
>
()));
}
}
case
schema
:
:
Type
::
INTERFACE
:
case
schema
:
:
Type
::
INTERFACE
:
...
@@ -369,8 +366,8 @@ DynamicValue::Builder DynamicStruct::Builder::get(StructSchema::Field field) {
...
@@ -369,8 +366,8 @@ DynamicValue::Builder DynamicStruct::Builder::get(StructSchema::Field field) {
}
}
case
schema
:
:
Type
::
OBJECT
:
{
case
schema
:
:
Type
::
OBJECT
:
{
return
DynamicObject
(
return
DynamicObject
::
Builder
(
builder
.
asReader
().
getObjectField
(
builder
.
getObjectField
(
nonGroup
.
getOffset
()
*
POINTERS
,
nonGroup
.
getOffset
()
*
POINTERS
,
dval
.
getObject
<
_
::
UncheckedMessage
>
()));
dval
.
getObject
<
_
::
UncheckedMessage
>
()));
}
}
...
@@ -890,7 +887,7 @@ DynamicValue::Reader DynamicList::Reader::operator[](uint index) const {
...
@@ -890,7 +887,7 @@ DynamicValue::Reader DynamicList::Reader::operator[](uint index) const {
switch
(
schema
.
whichElementType
())
{
switch
(
schema
.
whichElementType
())
{
#define HANDLE_TYPE(name, discrim, typeName) \
#define HANDLE_TYPE(name, discrim, typeName) \
case schema::Type::discrim: \
case schema::Type::discrim: \
return
DynamicValue::Reader(reader.getDataElement<typeName>(index * ELEMENTS)
);
return
reader.getDataElement<typeName>(index * ELEMENTS
);
HANDLE_TYPE
(
void
,
VOID
,
Void
)
HANDLE_TYPE
(
void
,
VOID
,
Void
)
HANDLE_TYPE
(
bool
,
BOOL
,
bool
)
HANDLE_TYPE
(
bool
,
BOOL
,
bool
)
...
@@ -907,28 +904,26 @@ DynamicValue::Reader DynamicList::Reader::operator[](uint index) const {
...
@@ -907,28 +904,26 @@ DynamicValue::Reader DynamicList::Reader::operator[](uint index) const {
#undef HANDLE_TYPE
#undef HANDLE_TYPE
case
schema
:
:
Type
::
TEXT
:
case
schema
:
:
Type
::
TEXT
:
return
DynamicValue
::
Reader
(
reader
.
getBlobElement
<
Text
>
(
index
*
ELEMENTS
)
);
return
reader
.
getBlobElement
<
Text
>
(
index
*
ELEMENTS
);
case
schema
:
:
Type
::
DATA
:
case
schema
:
:
Type
::
DATA
:
return
DynamicValue
::
Reader
(
reader
.
getBlobElement
<
Data
>
(
index
*
ELEMENTS
)
);
return
reader
.
getBlobElement
<
Data
>
(
index
*
ELEMENTS
);
case
schema
:
:
Type
::
LIST
:
{
case
schema
:
:
Type
::
LIST
:
{
auto
elementType
=
schema
.
getListElementType
();
auto
elementType
=
schema
.
getListElementType
();
return
DynamicValue
::
Reader
(
DynamicList
::
Reader
(
return
DynamicList
::
Reader
(
elementType
,
reader
.
getListElement
(
elementType
,
reader
.
getListElement
(
index
*
ELEMENTS
,
elementSizeFor
(
elementType
.
whichElementType
())));
index
*
ELEMENTS
,
elementSizeFor
(
elementType
.
whichElementType
()))));
}
}
case
schema
:
:
Type
::
STRUCT
:
case
schema
:
:
Type
::
STRUCT
:
return
Dynamic
Value
::
Reader
(
DynamicStruct
::
Reader
(
return
Dynamic
Struct
::
Reader
(
schema
.
getStructElementType
(),
schema
.
getStructElementType
(),
reader
.
getStructElement
(
index
*
ELEMENTS
)
));
reader
.
getStructElement
(
index
*
ELEMENTS
));
case
schema
:
:
Type
::
ENUM
:
case
schema
:
:
Type
::
ENUM
:
return
Dynamic
Value
::
Reader
(
DynamicEnum
(
return
Dynamic
Enum
(
schema
.
getEnumElementType
(),
schema
.
getEnumElementType
(),
reader
.
getDataElement
<
uint16_t
>
(
index
*
ELEMENTS
)
));
reader
.
getDataElement
<
uint16_t
>
(
index
*
ELEMENTS
));
case
schema
:
:
Type
::
OBJECT
:
case
schema
:
:
Type
::
OBJECT
:
return
DynamicValue
::
Reader
(
DynamicObject
(
return
DynamicObject
::
Reader
(
reader
.
getObjectElement
(
index
*
ELEMENTS
));
reader
.
getObjectElement
(
index
*
ELEMENTS
)));
case
schema
:
:
Type
::
INTERFACE
:
case
schema
:
:
Type
::
INTERFACE
:
KJ_FAIL_ASSERT
(
"Interfaces not implemented."
)
{
KJ_FAIL_ASSERT
(
"Interfaces not implemented."
)
{
...
@@ -945,7 +940,7 @@ DynamicValue::Builder DynamicList::Builder::operator[](uint index) {
...
@@ -945,7 +940,7 @@ DynamicValue::Builder DynamicList::Builder::operator[](uint index) {
switch
(
schema
.
whichElementType
())
{
switch
(
schema
.
whichElementType
())
{
#define HANDLE_TYPE(name, discrim, typeName) \
#define HANDLE_TYPE(name, discrim, typeName) \
case schema::Type::discrim: \
case schema::Type::discrim: \
return
DynamicValue::Builder(builder.getDataElement<typeName>(index * ELEMENTS)
);
return
builder.getDataElement<typeName>(index * ELEMENTS
);
HANDLE_TYPE
(
void
,
VOID
,
Void
)
HANDLE_TYPE
(
void
,
VOID
,
Void
)
HANDLE_TYPE
(
bool
,
BOOL
,
bool
)
HANDLE_TYPE
(
bool
,
BOOL
,
bool
)
...
@@ -962,32 +957,32 @@ DynamicValue::Builder DynamicList::Builder::operator[](uint index) {
...
@@ -962,32 +957,32 @@ DynamicValue::Builder DynamicList::Builder::operator[](uint index) {
#undef HANDLE_TYPE
#undef HANDLE_TYPE
case
schema
:
:
Type
::
TEXT
:
case
schema
:
:
Type
::
TEXT
:
return
DynamicValue
::
Builder
(
builder
.
getBlobElement
<
Text
>
(
index
*
ELEMENTS
)
);
return
builder
.
getBlobElement
<
Text
>
(
index
*
ELEMENTS
);
case
schema
:
:
Type
::
DATA
:
case
schema
:
:
Type
::
DATA
:
return
DynamicValue
::
Builder
(
builder
.
getBlobElement
<
Data
>
(
index
*
ELEMENTS
)
);
return
builder
.
getBlobElement
<
Data
>
(
index
*
ELEMENTS
);
case
schema
:
:
Type
::
LIST
:
{
case
schema
:
:
Type
::
LIST
:
{
ListSchema
elementType
=
schema
.
getListElementType
();
ListSchema
elementType
=
schema
.
getListElementType
();
if
(
elementType
.
whichElementType
()
==
schema
::
Type
::
STRUCT
)
{
if
(
elementType
.
whichElementType
()
==
schema
::
Type
::
STRUCT
)
{
return
Dynamic
Value
::
Builder
(
Dynamic
List
::
Builder
(
elementType
,
return
DynamicList
::
Builder
(
elementType
,
builder
.
getStructListElement
(
builder
.
getStructListElement
(
index
*
ELEMENTS
,
index
*
ELEMENTS
,
structSizeFromSchema
(
elementType
.
getStructElementType
())))
)
;
structSizeFromSchema
(
elementType
.
getStructElementType
())));
}
else
{
}
else
{
return
Dynamic
Value
::
Builder
(
Dynamic
List
::
Builder
(
elementType
,
return
DynamicList
::
Builder
(
elementType
,
builder
.
getListElement
(
builder
.
getListElement
(
index
*
ELEMENTS
,
index
*
ELEMENTS
,
elementSizeFor
(
elementType
.
whichElementType
())))
)
;
elementSizeFor
(
elementType
.
whichElementType
())));
}
}
}
}
case
schema
:
:
Type
::
STRUCT
:
case
schema
:
:
Type
::
STRUCT
:
return
Dynamic
Value
::
Builder
(
DynamicStruct
::
Builder
(
return
Dynamic
Struct
::
Builder
(
schema
.
getStructElementType
(),
schema
.
getStructElementType
(),
builder
.
getStructElement
(
index
*
ELEMENTS
)
));
builder
.
getStructElement
(
index
*
ELEMENTS
));
case
schema
:
:
Type
::
ENUM
:
case
schema
:
:
Type
::
ENUM
:
return
Dynamic
Value
::
Builder
(
DynamicEnum
(
return
Dynamic
Enum
(
schema
.
getEnumElementType
(),
schema
.
getEnumElementType
(),
builder
.
getDataElement
<
uint16_t
>
(
index
*
ELEMENTS
)
));
builder
.
getDataElement
<
uint16_t
>
(
index
*
ELEMENTS
));
case
schema
:
:
Type
::
OBJECT
:
case
schema
:
:
Type
::
OBJECT
:
KJ_FAIL_ASSERT
(
"List(Object) not supported."
);
KJ_FAIL_ASSERT
(
"List(Object) not supported."
);
...
@@ -1103,24 +1098,24 @@ DynamicValue::Builder DynamicList::Builder::init(uint index, uint size) {
...
@@ -1103,24 +1098,24 @@ DynamicValue::Builder DynamicList::Builder::init(uint index, uint size) {
return
nullptr
;
return
nullptr
;
case
schema
:
:
Type
::
TEXT
:
case
schema
:
:
Type
::
TEXT
:
return
DynamicValue
::
Builder
(
builder
.
initBlobElement
<
Text
>
(
index
*
ELEMENTS
,
size
*
BYTES
)
);
return
builder
.
initBlobElement
<
Text
>
(
index
*
ELEMENTS
,
size
*
BYTES
);
case
schema
:
:
Type
::
DATA
:
case
schema
:
:
Type
::
DATA
:
return
DynamicValue
::
Builder
(
builder
.
initBlobElement
<
Data
>
(
index
*
ELEMENTS
,
size
*
BYTES
)
);
return
builder
.
initBlobElement
<
Data
>
(
index
*
ELEMENTS
,
size
*
BYTES
);
case
schema
:
:
Type
::
LIST
:
{
case
schema
:
:
Type
::
LIST
:
{
auto
elementType
=
schema
.
getListElementType
();
auto
elementType
=
schema
.
getListElementType
();
if
(
elementType
.
whichElementType
()
==
schema
::
Type
::
STRUCT
)
{
if
(
elementType
.
whichElementType
()
==
schema
::
Type
::
STRUCT
)
{
return
Dynamic
Value
::
Builder
(
Dynamic
List
::
Builder
(
return
DynamicList
::
Builder
(
elementType
,
builder
.
initStructListElement
(
elementType
,
builder
.
initStructListElement
(
index
*
ELEMENTS
,
size
*
ELEMENTS
,
index
*
ELEMENTS
,
size
*
ELEMENTS
,
structSizeFromSchema
(
elementType
.
getStructElementType
())))
)
;
structSizeFromSchema
(
elementType
.
getStructElementType
())));
}
else
{
}
else
{
return
Dynamic
Value
::
Builder
(
Dynamic
List
::
Builder
(
return
DynamicList
::
Builder
(
elementType
,
builder
.
initListElement
(
elementType
,
builder
.
initListElement
(
index
*
ELEMENTS
,
elementSizeFor
(
elementType
.
whichElementType
()),
index
*
ELEMENTS
,
elementSizeFor
(
elementType
.
whichElementType
()),
size
*
ELEMENTS
))
)
;
size
*
ELEMENTS
));
}
}
}
}
...
@@ -1147,6 +1142,47 @@ DynamicList::Reader DynamicList::Builder::asReader() const {
...
@@ -1147,6 +1142,47 @@ DynamicList::Reader DynamicList::Builder::asReader() const {
// =======================================================================================
// =======================================================================================
DynamicValue
::
Reader
::
Reader
(
ConstSchema
constant
)
{
auto
typeSchema
=
constant
.
getProto
().
getConst
().
getType
();
auto
value
=
constant
.
getProto
().
getConst
().
getValue
();
switch
(
typeSchema
.
which
())
{
case
schema
:
:
Type
::
VOID
:
*
this
=
capnp
::
VOID
;
break
;
case
schema
:
:
Type
::
BOOL
:
*
this
=
value
.
getBool
();
break
;
case
schema
:
:
Type
::
INT8
:
*
this
=
value
.
getInt8
();
break
;
case
schema
:
:
Type
::
INT16
:
*
this
=
value
.
getInt16
();
break
;
case
schema
:
:
Type
::
INT32
:
*
this
=
value
.
getInt32
();
break
;
case
schema
:
:
Type
::
INT64
:
*
this
=
value
.
getInt64
();
break
;
case
schema
:
:
Type
::
UINT8
:
*
this
=
value
.
getUint8
();
break
;
case
schema
:
:
Type
::
UINT16
:
*
this
=
value
.
getUint16
();
break
;
case
schema
:
:
Type
::
UINT32
:
*
this
=
value
.
getUint32
();
break
;
case
schema
:
:
Type
::
UINT64
:
*
this
=
value
.
getUint64
();
break
;
case
schema
:
:
Type
::
FLOAT32
:
*
this
=
value
.
getFloat32
();
break
;
case
schema
:
:
Type
::
FLOAT64
:
*
this
=
value
.
getFloat64
();
break
;
case
schema
:
:
Type
::
TEXT
:
*
this
=
value
.
getText
();
break
;
case
schema
:
:
Type
::
DATA
:
*
this
=
value
.
getData
();
break
;
case
schema
:
:
Type
::
ENUM
:
*
this
=
DynamicEnum
(
constant
.
getDependency
(
typeSchema
.
getEnum
()).
asEnum
(),
value
.
getEnum
());
break
;
case
schema
:
:
Type
::
STRUCT
:
*
this
=
value
.
getStruct
<
DynamicStruct
>
(
constant
.
getDependency
(
typeSchema
.
getStruct
()).
asStruct
());
break
;
case
schema
:
:
Type
::
LIST
:
*
this
=
value
.
getList
<
DynamicList
>
(
ListSchema
::
of
(
typeSchema
.
getList
(),
constant
));
break
;
case
schema
:
:
Type
::
OBJECT
:
*
this
=
value
.
getObject
<
DynamicObject
>
();
break
;
case
schema
:
:
Type
::
INTERFACE
:
KJ_FAIL_ASSERT
(
"Constants can't have interface type."
);
}
}
DynamicValue
::
Reader
DynamicValue
::
Builder
::
asReader
()
const
{
DynamicValue
::
Reader
DynamicValue
::
Builder
::
asReader
()
const
{
switch
(
type
)
{
switch
(
type
)
{
case
UNKNOWN
:
return
Reader
();
case
UNKNOWN
:
return
Reader
();
...
@@ -1161,7 +1197,7 @@ DynamicValue::Reader DynamicValue::Builder::asReader() const {
...
@@ -1161,7 +1197,7 @@ DynamicValue::Reader DynamicValue::Builder::asReader() const {
case
ENUM
:
return
Reader
(
enumValue
);
case
ENUM
:
return
Reader
(
enumValue
);
case
STRUCT
:
return
Reader
(
structValue
.
asReader
());
case
STRUCT
:
return
Reader
(
structValue
.
asReader
());
case
INTERFACE
:
KJ_FAIL_ASSERT
(
"Interfaces not implemented."
);
return
Reader
();
case
INTERFACE
:
KJ_FAIL_ASSERT
(
"Interfaces not implemented."
);
return
Reader
();
case
OBJECT
:
return
Reader
(
objectValue
);
case
OBJECT
:
return
Reader
(
objectValue
.
asReader
()
);
}
}
KJ_FAIL_ASSERT
(
"Missing switch case."
);
KJ_FAIL_ASSERT
(
"Missing switch case."
);
return
Reader
();
return
Reader
();
...
@@ -1407,6 +1443,16 @@ DynamicList::Builder PointerHelpers<DynamicList, Kind::UNKNOWN>::init(
...
@@ -1407,6 +1443,16 @@ DynamicList::Builder PointerHelpers<DynamicList, Kind::UNKNOWN>::init(
}
}
}
}
DynamicObject
::
Reader
PointerHelpers
<
DynamicObject
,
Kind
::
UNKNOWN
>::
get
(
StructReader
reader
,
WirePointerCount
index
)
{
return
DynamicObject
::
Reader
(
reader
.
getObjectField
(
index
,
nullptr
));
}
DynamicObject
::
Builder
PointerHelpers
<
DynamicObject
,
Kind
::
UNKNOWN
>::
get
(
StructBuilder
builder
,
WirePointerCount
index
)
{
return
DynamicObject
::
Builder
(
builder
.
getObjectField
(
index
,
nullptr
));
}
}
// namespace _ (private)
}
// namespace _ (private)
// -------------------------------------------------------------------
// -------------------------------------------------------------------
...
...
c++/src/capnp/dynamic.h
View file @
ac1e532d
...
@@ -71,7 +71,11 @@ struct DynamicValue {
...
@@ -71,7 +71,11 @@ struct DynamicValue {
class
Builder
;
class
Builder
;
};
};
class
DynamicEnum
;
class
DynamicEnum
;
class
DynamicObject
;
struct
DynamicObject
{
DynamicObject
()
=
delete
;
class
Reader
;
class
Builder
;
};
struct
DynamicStruct
{
struct
DynamicStruct
{
DynamicStruct
()
=
delete
;
DynamicStruct
()
=
delete
;
class
Reader
;
class
Reader
;
...
@@ -134,19 +138,18 @@ private:
...
@@ -134,19 +138,18 @@ private:
friend
struct
DynamicStruct
;
friend
struct
DynamicStruct
;
friend
struct
DynamicList
;
friend
struct
DynamicList
;
friend
struct
DynamicValue
;
template
<
typename
T
>
template
<
typename
T
>
friend
DynamicTypeFor
<
TypeIfEnum
<
T
>>
toDynamic
(
T
&&
value
);
friend
DynamicTypeFor
<
TypeIfEnum
<
T
>>
toDynamic
(
T
&&
value
);
};
};
// -------------------------------------------------------------------
// -------------------------------------------------------------------
class
DynamicObject
{
class
DynamicObject
::
Reader
{
// Represents an "Object" field of unknown type. This class behaves as a Reader. There is no
// Represents an "Object" field of unknown type.
// equivalent Builder; you must use getObject() or initObject() on the containing struct and
// specify a type if you want to build an Object field.
public
:
public
:
DynamicObject
()
=
default
;
Reader
()
=
default
;
template
<
typename
T
>
template
<
typename
T
>
inline
typename
T
::
Reader
as
()
const
{
return
AsImpl
<
T
>::
apply
(
*
this
);
}
inline
typename
T
::
Reader
as
()
const
{
return
AsImpl
<
T
>::
apply
(
*
this
);
}
...
@@ -158,7 +161,7 @@ public:
...
@@ -158,7 +161,7 @@ public:
private
:
private
:
_
::
ObjectReader
reader
;
_
::
ObjectReader
reader
;
inline
DynamicObject
(
_
::
ObjectReader
reader
)
:
reader
(
reader
)
{}
inline
Reader
(
_
::
ObjectReader
reader
)
:
reader
(
reader
)
{}
template
<
typename
T
,
Kind
kind
=
kind
<
T
>
()
>
struct
AsImpl
;
template
<
typename
T
,
Kind
kind
=
kind
<
T
>
()
>
struct
AsImpl
;
// Implementation backing the as() method. Needs to be a struct to allow partial
// Implementation backing the as() method. Needs to be a struct to allow partial
...
@@ -166,6 +169,34 @@ private:
...
@@ -166,6 +169,34 @@ private:
friend
struct
DynamicStruct
;
friend
struct
DynamicStruct
;
friend
struct
DynamicList
;
friend
struct
DynamicList
;
template
<
typename
T
,
Kind
K
>
friend
struct
_
::
PointerHelpers
;
friend
class
DynamicObject
::
Builder
;
};
class
DynamicObject
::
Builder
:
kj
::
DisallowConstCopy
{
// Represents an "Object" field of unknown type.
//
// You can't actually do anything with a DynamicObject::Builder except read it. It can't be
// converted to a Builder for any specific type because that could require initializing or
// updating the pointer that points *to* this object. Therefore, you must call
// DynamicStruct::Builder::{get,set,init}Object() and pass a type schema to build object fields.
public
:
Builder
()
=
default
;
Builder
(
Builder
&
)
=
default
;
Builder
(
Builder
&&
)
=
default
;
Reader
asReader
()
const
{
return
Reader
(
builder
.
asReader
());
}
private
:
_
::
ObjectBuilder
builder
;
inline
Builder
(
_
::
ObjectBuilder
builder
)
:
builder
(
builder
)
{}
friend
struct
DynamicStruct
;
friend
struct
DynamicList
;
template
<
typename
T
,
Kind
K
>
friend
struct
_
::
PointerHelpers
;
};
};
// -------------------------------------------------------------------
// -------------------------------------------------------------------
...
@@ -219,7 +250,7 @@ private:
...
@@ -219,7 +250,7 @@ private:
template
<
typename
T
,
Kind
K
>
template
<
typename
T
,
Kind
K
>
friend
struct
_
::
PointerHelpers
;
friend
struct
_
::
PointerHelpers
;
friend
class
DynamicObject
;
friend
struct
DynamicObject
;
friend
class
DynamicStruct
::
Builder
;
friend
class
DynamicStruct
::
Builder
;
friend
struct
DynamicList
;
friend
struct
DynamicList
;
friend
class
MessageReader
;
friend
class
MessageReader
;
...
@@ -366,7 +397,7 @@ private:
...
@@ -366,7 +397,7 @@ private:
template
<
typename
T
,
Kind
k
>
template
<
typename
T
,
Kind
k
>
friend
struct
_
::
PointerHelpers
;
friend
struct
_
::
PointerHelpers
;
friend
struct
DynamicStruct
;
friend
struct
DynamicStruct
;
friend
class
DynamicObject
;
friend
struct
DynamicObject
;
friend
class
DynamicList
::
Builder
;
friend
class
DynamicList
::
Builder
;
template
<
typename
T
,
::
capnp
::
Kind
k
>
template
<
typename
T
,
::
capnp
::
Kind
k
>
friend
struct
::
capnp
::
ToDynamic_
;
friend
struct
::
capnp
::
ToDynamic_
;
...
@@ -428,8 +459,8 @@ private:
...
@@ -428,8 +459,8 @@ private:
template
<>
struct
ReaderFor_
<
DynamicEnum
,
Kind
::
UNKNOWN
>
{
typedef
DynamicEnum
Type
;
};
template
<>
struct
ReaderFor_
<
DynamicEnum
,
Kind
::
UNKNOWN
>
{
typedef
DynamicEnum
Type
;
};
template
<>
struct
BuilderFor_
<
DynamicEnum
,
Kind
::
UNKNOWN
>
{
typedef
DynamicEnum
Type
;
};
template
<>
struct
BuilderFor_
<
DynamicEnum
,
Kind
::
UNKNOWN
>
{
typedef
DynamicEnum
Type
;
};
template
<>
struct
ReaderFor_
<
DynamicObject
,
Kind
::
UNKNOWN
>
{
typedef
DynamicObject
Type
;
};
template
<>
struct
ReaderFor_
<
DynamicObject
,
Kind
::
UNKNOWN
>
{
typedef
DynamicObject
::
Reader
Type
;
};
template
<>
struct
BuilderFor_
<
DynamicObject
,
Kind
::
UNKNOWN
>
{
typedef
DynamicObject
Type
;
};
template
<>
struct
BuilderFor_
<
DynamicObject
,
Kind
::
UNKNOWN
>
{
typedef
DynamicObject
::
Builder
Type
;
};
template
<>
struct
ReaderFor_
<
DynamicStruct
,
Kind
::
UNKNOWN
>
{
typedef
DynamicStruct
::
Reader
Type
;
};
template
<>
struct
ReaderFor_
<
DynamicStruct
,
Kind
::
UNKNOWN
>
{
typedef
DynamicStruct
::
Reader
Type
;
};
template
<>
struct
BuilderFor_
<
DynamicStruct
,
Kind
::
UNKNOWN
>
{
typedef
DynamicStruct
::
Builder
Type
;
};
template
<>
struct
BuilderFor_
<
DynamicStruct
,
Kind
::
UNKNOWN
>
{
typedef
DynamicStruct
::
Builder
Type
;
};
template
<>
struct
ReaderFor_
<
DynamicList
,
Kind
::
UNKNOWN
>
{
typedef
DynamicList
::
Reader
Type
;
};
template
<>
struct
ReaderFor_
<
DynamicList
,
Kind
::
UNKNOWN
>
{
typedef
DynamicList
::
Reader
Type
;
};
...
@@ -461,7 +492,8 @@ public:
...
@@ -461,7 +492,8 @@ public:
inline
Reader
(
const
DynamicList
::
Reader
&
value
);
inline
Reader
(
const
DynamicList
::
Reader
&
value
);
inline
Reader
(
DynamicEnum
value
);
inline
Reader
(
DynamicEnum
value
);
inline
Reader
(
const
DynamicStruct
::
Reader
&
value
);
inline
Reader
(
const
DynamicStruct
::
Reader
&
value
);
inline
Reader
(
DynamicObject
value
);
inline
Reader
(
const
DynamicObject
::
Reader
&
value
);
Reader
(
ConstSchema
constant
);
template
<
typename
T
,
typename
=
decltype
(
toDynamic
(
kj
::
instance
<
T
>
()))
>
template
<
typename
T
,
typename
=
decltype
(
toDynamic
(
kj
::
instance
<
T
>
()))
>
inline
Reader
(
T
value
)
:
Reader
(
toDynamic
(
value
))
{}
inline
Reader
(
T
value
)
:
Reader
(
toDynamic
(
value
))
{}
...
@@ -505,7 +537,7 @@ private:
...
@@ -505,7 +537,7 @@ private:
DynamicList
::
Reader
listValue
;
DynamicList
::
Reader
listValue
;
DynamicEnum
enumValue
;
DynamicEnum
enumValue
;
DynamicStruct
::
Reader
structValue
;
DynamicStruct
::
Reader
structValue
;
DynamicObject
objectValue
;
DynamicObject
::
Reader
objectValue
;
};
};
template
<
typename
T
,
Kind
kind
=
kind
<
T
>
()
>
struct
AsImpl
;
template
<
typename
T
,
Kind
kind
=
kind
<
T
>
()
>
struct
AsImpl
;
...
@@ -538,7 +570,7 @@ public:
...
@@ -538,7 +570,7 @@ public:
inline
Builder
(
DynamicList
::
Builder
value
);
inline
Builder
(
DynamicList
::
Builder
value
);
inline
Builder
(
DynamicEnum
value
);
inline
Builder
(
DynamicEnum
value
);
inline
Builder
(
DynamicStruct
::
Builder
value
);
inline
Builder
(
DynamicStruct
::
Builder
value
);
inline
Builder
(
DynamicObject
value
);
inline
Builder
(
DynamicObject
::
Builder
value
);
template
<
typename
T
,
typename
=
decltype
(
toDynamic
(
kj
::
instance
<
T
>
()))
>
template
<
typename
T
,
typename
=
decltype
(
toDynamic
(
kj
::
instance
<
T
>
()))
>
inline
Builder
(
T
value
)
:
Builder
(
toDynamic
(
value
))
{}
inline
Builder
(
T
value
)
:
Builder
(
toDynamic
(
value
))
{}
...
@@ -552,6 +584,13 @@ public:
...
@@ -552,6 +584,13 @@ public:
Reader
asReader
()
const
;
Reader
asReader
()
const
;
inline
Builder
(
Builder
&
other
)
{
memcpy
(
this
,
&
other
,
sizeof
(
*
this
));
}
inline
Builder
(
Builder
&&
other
)
{
memcpy
(
this
,
&
other
,
sizeof
(
*
this
));
}
static_assert
(
__has_trivial_copy
(
StructSchema
)
&&
__has_trivial_copy
(
ListSchema
),
"Assumptions made here do not hold."
);
// Hack: We know this type is trivially constructable but the use of DisallowConstCopy causes
// the compiler to believe otherwise.
private
:
private
:
Type
type
;
Type
type
;
...
@@ -566,7 +605,7 @@ private:
...
@@ -566,7 +605,7 @@ private:
DynamicList
::
Builder
listValue
;
DynamicList
::
Builder
listValue
;
DynamicEnum
enumValue
;
DynamicEnum
enumValue
;
DynamicStruct
::
Builder
structValue
;
DynamicStruct
::
Builder
structValue
;
DynamicObject
objectValue
;
DynamicObject
::
Builder
objectValue
;
};
};
template
<
typename
T
,
Kind
kind
=
kind
<
T
>
()
>
struct
AsImpl
;
template
<
typename
T
,
Kind
kind
=
kind
<
T
>
()
>
struct
AsImpl
;
...
@@ -577,7 +616,8 @@ private:
...
@@ -577,7 +616,8 @@ private:
kj
::
StringTree
KJ_STRINGIFY
(
const
DynamicValue
::
Reader
&
value
);
kj
::
StringTree
KJ_STRINGIFY
(
const
DynamicValue
::
Reader
&
value
);
kj
::
StringTree
KJ_STRINGIFY
(
const
DynamicValue
::
Builder
&
value
);
kj
::
StringTree
KJ_STRINGIFY
(
const
DynamicValue
::
Builder
&
value
);
kj
::
StringTree
KJ_STRINGIFY
(
DynamicEnum
value
);
kj
::
StringTree
KJ_STRINGIFY
(
DynamicEnum
value
);
kj
::
StringTree
KJ_STRINGIFY
(
const
DynamicObject
&
value
);
kj
::
StringTree
KJ_STRINGIFY
(
const
DynamicObject
::
Reader
&
value
);
kj
::
StringTree
KJ_STRINGIFY
(
const
DynamicObject
::
Builder
&
value
);
kj
::
StringTree
KJ_STRINGIFY
(
const
DynamicStruct
::
Reader
&
value
);
kj
::
StringTree
KJ_STRINGIFY
(
const
DynamicStruct
::
Reader
&
value
);
kj
::
StringTree
KJ_STRINGIFY
(
const
DynamicStruct
::
Builder
&
value
);
kj
::
StringTree
KJ_STRINGIFY
(
const
DynamicStruct
::
Builder
&
value
);
kj
::
StringTree
KJ_STRINGIFY
(
const
DynamicList
::
Reader
&
value
);
kj
::
StringTree
KJ_STRINGIFY
(
const
DynamicList
::
Reader
&
value
);
...
@@ -726,6 +766,14 @@ struct PointerHelpers<DynamicList, Kind::UNKNOWN> {
...
@@ -726,6 +766,14 @@ struct PointerHelpers<DynamicList, Kind::UNKNOWN> {
}
}
};
};
template
<>
struct
PointerHelpers
<
DynamicObject
,
Kind
::
UNKNOWN
>
{
// DynamicObject can only be used with get().
static
DynamicObject
::
Reader
get
(
StructReader
reader
,
WirePointerCount
index
);
static
DynamicObject
::
Builder
get
(
StructBuilder
builder
,
WirePointerCount
index
);
};
}
// namespace _ (private)
}
// namespace _ (private)
// =======================================================================================
// =======================================================================================
...
@@ -789,7 +837,6 @@ CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(unsigned long long, UINT, uint);
...
@@ -789,7 +837,6 @@ CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(unsigned long long, UINT, uint);
CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR
(
float
,
FLOAT
,
float
);
CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR
(
float
,
FLOAT
,
float
);
CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR
(
double
,
FLOAT
,
float
);
CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR
(
double
,
FLOAT
,
float
);
CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR
(
DynamicEnum
,
ENUM
,
enum
);
CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR
(
DynamicEnum
,
ENUM
,
enum
);
CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR
(
DynamicObject
,
OBJECT
,
object
);
#undef CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR
#undef CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR
#define CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(cppType, typeTag, fieldName) \
#define CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(cppType, typeTag, fieldName) \
...
@@ -802,6 +849,7 @@ CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(Text, TEXT, text);
...
@@ -802,6 +849,7 @@ CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(Text, TEXT, text);
CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR
(
Data
,
DATA
,
data
);
CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR
(
Data
,
DATA
,
data
);
CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR
(
DynamicList
,
LIST
,
list
);
CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR
(
DynamicList
,
LIST
,
list
);
CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR
(
DynamicStruct
,
STRUCT
,
struct
);
CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR
(
DynamicStruct
,
STRUCT
,
struct
);
CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR
(
DynamicObject
,
OBJECT
,
object
);
#undef CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR
#undef CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR
...
@@ -891,15 +939,15 @@ struct DynamicValue::Builder::AsImpl<T, Kind::LIST> {
...
@@ -891,15 +939,15 @@ struct DynamicValue::Builder::AsImpl<T, Kind::LIST> {
// -------------------------------------------------------------------
// -------------------------------------------------------------------
template
<
typename
T
>
template
<
typename
T
>
struct
DynamicObject
::
AsImpl
<
T
,
Kind
::
STRUCT
>
{
struct
DynamicObject
::
Reader
::
AsImpl
<
T
,
Kind
::
STRUCT
>
{
static
T
apply
(
DynamicObject
value
)
{
static
T
apply
(
DynamicObject
::
Reader
value
)
{
return
value
.
as
(
Schema
::
from
<
T
>
()).
template
as
<
T
>
();
return
value
.
as
(
Schema
::
from
<
T
>
()).
template
as
<
T
>
();
}
}
};
};
template
<
typename
T
>
template
<
typename
T
>
struct
DynamicObject
::
AsImpl
<
T
,
Kind
::
LIST
>
{
struct
DynamicObject
::
Reader
::
AsImpl
<
T
,
Kind
::
LIST
>
{
static
T
apply
(
DynamicObject
value
)
{
static
T
apply
(
DynamicObject
::
Reader
value
)
{
return
value
.
as
(
Schema
::
from
<
T
>
()).
template
as
<
T
>
();
return
value
.
as
(
Schema
::
from
<
T
>
()).
template
as
<
T
>
();
}
}
};
};
...
@@ -960,6 +1008,13 @@ inline DynamicList::Builder DynamicList::Builder::as<DynamicList>() {
...
@@ -960,6 +1008,13 @@ inline DynamicList::Builder DynamicList::Builder::as<DynamicList>() {
return
*
this
;
return
*
this
;
}
}
// -------------------------------------------------------------------
template
<
typename
T
>
ReaderFor
<
T
>
ConstSchema
::
as
()
const
{
return
DynamicValue
::
Reader
(
*
this
).
as
<
T
>
();
}
}
// namespace capnp
}
// namespace capnp
#endif // CAPNP_DYNAMIC_H_
#endif // CAPNP_DYNAMIC_H_
c++/src/capnp/layout.c++
View file @
ac1e532d
...
@@ -2537,6 +2537,18 @@ ObjectReader ListReader::getObjectElement(ElementCount index) const {
...
@@ -2537,6 +2537,18 @@ ObjectReader ListReader::getObjectElement(ElementCount index) const {
segment
,
checkAlignment
(
ptr
+
index
*
step
/
BITS_PER_BYTE
),
nullptr
,
nestingLimit
);
segment
,
checkAlignment
(
ptr
+
index
*
step
/
BITS_PER_BYTE
),
nullptr
,
nestingLimit
);
}
}
ObjectReader
ObjectBuilder
::
asReader
()
const
{
switch
(
kind
)
{
case
ObjectKind
:
:
NULL_POINTER
:
return
ObjectReader
();
case
ObjectKind
:
:
STRUCT
:
return
ObjectReader
(
structBuilder
.
asReader
());
case
ObjectKind
:
:
LIST
:
return
ObjectReader
(
listBuilder
.
asReader
());
}
KJ_UNREACHABLE
;
}
// =======================================================================================
// =======================================================================================
// OrphanBuilder
// OrphanBuilder
...
...
c++/src/capnp/layout.h
View file @
ac1e532d
...
@@ -710,6 +710,14 @@ struct ObjectBuilder {
...
@@ -710,6 +710,14 @@ struct ObjectBuilder {
:
kind
(
ObjectKind
::
STRUCT
),
structBuilder
(
structBuilder
)
{}
:
kind
(
ObjectKind
::
STRUCT
),
structBuilder
(
structBuilder
)
{}
ObjectBuilder
(
ListBuilder
listBuilder
)
ObjectBuilder
(
ListBuilder
listBuilder
)
:
kind
(
ObjectKind
::
LIST
),
listBuilder
(
listBuilder
)
{}
:
kind
(
ObjectKind
::
LIST
),
listBuilder
(
listBuilder
)
{}
ObjectReader
asReader
()
const
;
inline
ObjectBuilder
(
ObjectBuilder
&
other
)
{
memcpy
(
this
,
&
other
,
sizeof
(
*
this
));
}
inline
ObjectBuilder
(
ObjectBuilder
&&
other
)
{
memcpy
(
this
,
&
other
,
sizeof
(
*
this
));
}
// Hack: Compiler thinks StructBuilder and ListBuilder are non-trivially-copyable due to the
// inheritance from DisallowConstCopy, but that means the union causes ObjectBuilder's copy
// constructor to be deleted. We happen to know that trivial copying works here...
};
};
struct
ObjectReader
{
struct
ObjectReader
{
...
...
c++/src/capnp/schema-parser-test.c++
View file @
ac1e532d
...
@@ -91,7 +91,7 @@ TEST(SchemaParser, Basic) {
...
@@ -91,7 +91,7 @@ TEST(SchemaParser, Basic) {
};
};
ParsedSchema
barSchema
=
parser
.
parseFile
(
SchemaFile
::
newDiskFile
(
ParsedSchema
barSchema
=
parser
.
parseFile
(
SchemaFile
::
newDiskFile
(
kj
::
str
(
"foo2/bar2.capnp"
),
kj
::
str
(
"src/foo/bar.capnp"
)
,
importPath
,
reader
));
"foo2/bar2.capnp"
,
"src/foo/bar.capnp"
,
importPath
,
reader
));
auto
barProto
=
barSchema
.
getProto
();
auto
barProto
=
barSchema
.
getProto
();
EXPECT_EQ
(
0x8123456789abcdefull
,
barProto
.
getId
());
EXPECT_EQ
(
0x8123456789abcdefull
,
barProto
.
getId
());
...
@@ -110,24 +110,24 @@ TEST(SchemaParser, Basic) {
...
@@ -110,24 +110,24 @@ TEST(SchemaParser, Basic) {
EXPECT_EQ
(
0x856789abcdef1234ull
,
getFieldTypeFileId
(
barFields
[
3
]));
EXPECT_EQ
(
0x856789abcdef1234ull
,
getFieldTypeFileId
(
barFields
[
3
]));
auto
bazSchema
=
parser
.
parseFile
(
SchemaFile
::
newDiskFile
(
auto
bazSchema
=
parser
.
parseFile
(
SchemaFile
::
newDiskFile
(
kj
::
str
(
"not/used/because/already/loaded"
)
,
"not/used/because/already/loaded"
,
kj
::
str
(
"src/foo/baz.capnp"
)
,
importPath
,
reader
));
"src/foo/baz.capnp"
,
importPath
,
reader
));
EXPECT_EQ
(
0x823456789abcdef1ull
,
bazSchema
.
getProto
().
getId
());
EXPECT_EQ
(
0x823456789abcdef1ull
,
bazSchema
.
getProto
().
getId
());
EXPECT_EQ
(
"foo2/baz.capnp"
,
bazSchema
.
getProto
().
getDisplayName
());
EXPECT_EQ
(
"foo2/baz.capnp"
,
bazSchema
.
getProto
().
getDisplayName
());
auto
bazStruct
=
bazSchema
.
getNested
(
"Baz"
).
asStruct
();
auto
bazStruct
=
bazSchema
.
getNested
(
"Baz"
).
asStruct
();
EXPECT_EQ
(
bazStruct
,
barStruct
.
getDependency
(
bazStruct
.
getProto
().
getId
()));
EXPECT_EQ
(
bazStruct
,
barStruct
.
getDependency
(
bazStruct
.
getProto
().
getId
()));
auto
corgeSchema
=
parser
.
parseFile
(
SchemaFile
::
newDiskFile
(
auto
corgeSchema
=
parser
.
parseFile
(
SchemaFile
::
newDiskFile
(
kj
::
str
(
"not/used/because/already/loaded"
)
,
"not/used/because/already/loaded"
,
kj
::
str
(
"src/qux/corge.capnp"
)
,
importPath
,
reader
));
"src/qux/corge.capnp"
,
importPath
,
reader
));
EXPECT_EQ
(
0x83456789abcdef12ull
,
corgeSchema
.
getProto
().
getId
());
EXPECT_EQ
(
0x83456789abcdef12ull
,
corgeSchema
.
getProto
().
getId
());
EXPECT_EQ
(
"qux/corge.capnp"
,
corgeSchema
.
getProto
().
getDisplayName
());
EXPECT_EQ
(
"qux/corge.capnp"
,
corgeSchema
.
getProto
().
getDisplayName
());
auto
corgeStruct
=
corgeSchema
.
getNested
(
"Corge"
).
asStruct
();
auto
corgeStruct
=
corgeSchema
.
getNested
(
"Corge"
).
asStruct
();
EXPECT_EQ
(
corgeStruct
,
barStruct
.
getDependency
(
corgeStruct
.
getProto
().
getId
()));
EXPECT_EQ
(
corgeStruct
,
barStruct
.
getDependency
(
corgeStruct
.
getProto
().
getId
()));
auto
graultSchema
=
parser
.
parseFile
(
SchemaFile
::
newDiskFile
(
auto
graultSchema
=
parser
.
parseFile
(
SchemaFile
::
newDiskFile
(
kj
::
str
(
"not/used/because/already/loaded"
)
,
"not/used/because/already/loaded"
,
kj
::
str
(
"/usr/include/grault.capnp"
)
,
importPath
,
reader
));
"/usr/include/grault.capnp"
,
importPath
,
reader
));
EXPECT_EQ
(
0x8456789abcdef123ull
,
graultSchema
.
getProto
().
getId
());
EXPECT_EQ
(
0x8456789abcdef123ull
,
graultSchema
.
getProto
().
getId
());
EXPECT_EQ
(
"grault.capnp"
,
graultSchema
.
getProto
().
getDisplayName
());
EXPECT_EQ
(
"grault.capnp"
,
graultSchema
.
getProto
().
getDisplayName
());
auto
graultStruct
=
graultSchema
.
getNested
(
"Grault"
).
asStruct
();
auto
graultStruct
=
graultSchema
.
getNested
(
"Grault"
).
asStruct
();
...
@@ -136,11 +136,45 @@ TEST(SchemaParser, Basic) {
...
@@ -136,11 +136,45 @@ TEST(SchemaParser, Basic) {
// Try importing the other grault.capnp directly. It'll get the display name we specify since
// Try importing the other grault.capnp directly. It'll get the display name we specify since
// it wasn't imported before.
// it wasn't imported before.
auto
wrongGraultSchema
=
parser
.
parseFile
(
SchemaFile
::
newDiskFile
(
auto
wrongGraultSchema
=
parser
.
parseFile
(
SchemaFile
::
newDiskFile
(
kj
::
str
(
"weird/display/name.capnp"
)
,
"weird/display/name.capnp"
,
kj
::
str
(
"/opt/include/grault.capnp"
)
,
importPath
,
reader
));
"/opt/include/grault.capnp"
,
importPath
,
reader
));
EXPECT_EQ
(
0x8000000000000001ull
,
wrongGraultSchema
.
getProto
().
getId
());
EXPECT_EQ
(
0x8000000000000001ull
,
wrongGraultSchema
.
getProto
().
getId
());
EXPECT_EQ
(
"weird/display/name.capnp"
,
wrongGraultSchema
.
getProto
().
getDisplayName
());
EXPECT_EQ
(
"weird/display/name.capnp"
,
wrongGraultSchema
.
getProto
().
getDisplayName
());
}
}
TEST
(
SchemaParser
,
Constants
)
{
// This is actually a test of the full dynamic API stack for constants, because the schemas for
// constants are not actually accessible from the generated code API, so the only way to ever
// get a ConstSchema is by parsing it.
SchemaParser
parser
;
FakeFileReader
reader
;
reader
.
add
(
"const.capnp"
,
"@0x8123456789abcdef;
\n
"
"const uint32Const :UInt32 = 1234;
\n
"
"const listConst :List(Float32) = [1.25, 2.5, 3e4];
\n
"
"const structConst :Foo = (bar = 123, baz =
\"
qux
\"
);
\n
"
"struct Foo {
\n
"
" bar @0 :Int16;
\n
"
" baz @1 :Text;
\n
"
"}
\n
"
);
ParsedSchema
barSchema
=
parser
.
parseFile
(
SchemaFile
::
newDiskFile
(
"const.capnp"
,
"const.capnp"
,
nullptr
,
reader
));
EXPECT_EQ
(
1234
,
barSchema
.
getNested
(
"uint32Const"
).
asConst
().
as
<
uint32_t
>
());
auto
list
=
barSchema
.
getNested
(
"listConst"
).
asConst
().
as
<
DynamicList
>
();
ASSERT_EQ
(
3u
,
list
.
size
());
EXPECT_EQ
(
1.25
,
list
[
0
].
as
<
float
>
());
EXPECT_EQ
(
2.5
,
list
[
1
].
as
<
float
>
());
EXPECT_EQ
(
3e4
f
,
list
[
2
].
as
<
float
>
());
auto
structConst
=
barSchema
.
getNested
(
"structConst"
).
asConst
().
as
<
DynamicStruct
>
();
EXPECT_EQ
(
123
,
structConst
.
get
(
"bar"
).
as
<
int16_t
>
());
EXPECT_EQ
(
"qux"
,
structConst
.
get
(
"baz"
).
as
<
Text
>
());
}
}
// namespace
}
// namespace
}
// namespace capnp
}
// namespace capnp
c++/src/capnp/schema.c++
View file @
ac1e532d
...
@@ -77,12 +77,45 @@ InterfaceSchema Schema::asInterface() const {
...
@@ -77,12 +77,45 @@ InterfaceSchema Schema::asInterface() const {
return
InterfaceSchema
(
raw
);
return
InterfaceSchema
(
raw
);
}
}
ConstSchema
Schema
::
asConst
()
const
{
KJ_REQUIRE
(
getProto
().
isConst
(),
"Tried to use non-constant schema as a constant."
,
getProto
().
getDisplayName
());
return
ConstSchema
(
raw
);
}
void
Schema
::
requireUsableAs
(
const
_
::
RawSchema
*
expected
)
const
{
void
Schema
::
requireUsableAs
(
const
_
::
RawSchema
*
expected
)
const
{
KJ_REQUIRE
(
raw
==
expected
||
KJ_REQUIRE
(
raw
==
expected
||
(
raw
!=
nullptr
&&
expected
!=
nullptr
&&
raw
->
canCastTo
==
expected
),
(
raw
!=
nullptr
&&
expected
!=
nullptr
&&
raw
->
canCastTo
==
expected
),
"This schema is not compatible with the requested native type."
);
"This schema is not compatible with the requested native type."
);
}
}
uint32_t
Schema
::
getSchemaOffset
(
const
schema
::
Value
::
Reader
&
value
)
const
{
const
word
*
ptr
;
switch
(
value
.
which
())
{
case
schema
:
:
Value
::
TEXT
:
ptr
=
reinterpret_cast
<
const
word
*>
(
value
.
getText
().
begin
());
break
;
case
schema
:
:
Value
::
DATA
:
ptr
=
reinterpret_cast
<
const
word
*>
(
value
.
getData
().
begin
());
break
;
case
schema
:
:
Value
::
STRUCT
:
ptr
=
value
.
getStruct
<
_
::
UncheckedMessage
>
();
break
;
case
schema
:
:
Value
::
LIST
:
ptr
=
value
.
getList
<
_
::
UncheckedMessage
>
();
break
;
case
schema
:
:
Value
::
OBJECT
:
ptr
=
value
.
getObject
<
_
::
UncheckedMessage
>
();
break
;
default
:
KJ_FAIL_ASSERT
(
"getDefaultValueSchemaOffset() can only be called on struct, list, "
"and object fields."
);
}
return
ptr
-
raw
->
encodedNode
;
}
// =======================================================================================
// =======================================================================================
namespace
{
namespace
{
...
@@ -156,31 +189,7 @@ kj::Maybe<StructSchema::Field> StructSchema::getFieldByDiscriminant(uint16_t dis
...
@@ -156,31 +189,7 @@ kj::Maybe<StructSchema::Field> StructSchema::getFieldByDiscriminant(uint16_t dis
}
}
uint32_t
StructSchema
::
Field
::
getDefaultValueSchemaOffset
()
const
{
uint32_t
StructSchema
::
Field
::
getDefaultValueSchemaOffset
()
const
{
auto
defaultValue
=
proto
.
getNonGroup
().
getDefaultValue
();
return
parent
.
getSchemaOffset
(
proto
.
getNonGroup
().
getDefaultValue
());
const
word
*
ptr
;
switch
(
defaultValue
.
which
())
{
case
schema
:
:
Value
::
TEXT
:
ptr
=
reinterpret_cast
<
const
word
*>
(
defaultValue
.
getText
().
begin
());
break
;
case
schema
:
:
Value
::
DATA
:
ptr
=
reinterpret_cast
<
const
word
*>
(
defaultValue
.
getData
().
begin
());
break
;
case
schema
:
:
Value
::
STRUCT
:
ptr
=
defaultValue
.
getStruct
<
_
::
UncheckedMessage
>
();
break
;
case
schema
:
:
Value
::
LIST
:
ptr
=
defaultValue
.
getList
<
_
::
UncheckedMessage
>
();
break
;
case
schema
:
:
Value
::
OBJECT
:
ptr
=
defaultValue
.
getObject
<
_
::
UncheckedMessage
>
();
break
;
default
:
KJ_FAIL_ASSERT
(
"getDefaultValueSchemaOffset() can only be called on struct, list, "
"and object fields."
);
}
return
ptr
-
parent
.
raw
->
encodedNode
;
}
}
// -------------------------------------------------------------------
// -------------------------------------------------------------------
...
@@ -219,6 +228,12 @@ InterfaceSchema::Method InterfaceSchema::getMethodByName(kj::StringPtr name) con
...
@@ -219,6 +228,12 @@ InterfaceSchema::Method InterfaceSchema::getMethodByName(kj::StringPtr name) con
}
}
}
}
// -------------------------------------------------------------------
uint32_t
ConstSchema
::
getValueSchemaOffset
()
const
{
return
getSchemaOffset
(
getProto
().
getConst
().
getValue
());
}
// =======================================================================================
// =======================================================================================
ListSchema
ListSchema
::
of
(
schema
::
Type
::
Which
primitiveType
)
{
ListSchema
ListSchema
::
of
(
schema
::
Type
::
Which
primitiveType
)
{
...
...
c++/src/capnp/schema.h
View file @
ac1e532d
...
@@ -32,6 +32,7 @@ class Schema;
...
@@ -32,6 +32,7 @@ class Schema;
class
StructSchema
;
class
StructSchema
;
class
EnumSchema
;
class
EnumSchema
;
class
InterfaceSchema
;
class
InterfaceSchema
;
class
ConstSchema
;
class
ListSchema
;
class
ListSchema
;
template
<
typename
T
,
Kind
k
=
kind
<
T
>
()
>
struct
SchemaType_
{
typedef
Schema
Type
;
};
template
<
typename
T
,
Kind
k
=
kind
<
T
>
()
>
struct
SchemaType_
{
typedef
Schema
Type
;
};
...
@@ -57,6 +58,8 @@ public:
...
@@ -57,6 +58,8 @@ public:
// Get the Schema for a particular compiled-in type.
// Get the Schema for a particular compiled-in type.
schema
::
Node
::
Reader
getProto
()
const
;
schema
::
Node
::
Reader
getProto
()
const
;
// Get the underlying Cap'n Proto representation of the schema node. (Note that this accessor
// has performance comparable to accessors of struct-typed fields on Reader classes.)
kj
::
ArrayPtr
<
const
word
>
asUncheckedMessage
()
const
;
kj
::
ArrayPtr
<
const
word
>
asUncheckedMessage
()
const
;
// Get the encoded schema node content as a single message segment. It is safe to read as an
// Get the encoded schema node content as a single message segment. It is safe to read as an
...
@@ -84,7 +87,9 @@ public:
...
@@ -84,7 +87,9 @@ public:
StructSchema
asStruct
()
const
;
StructSchema
asStruct
()
const
;
EnumSchema
asEnum
()
const
;
EnumSchema
asEnum
()
const
;
InterfaceSchema
asInterface
()
const
;
InterfaceSchema
asInterface
()
const
;
// Cast the Schema to a specific type. Throws an exception if the type doesn't match.
ConstSchema
asConst
()
const
;
// Cast the Schema to a specific type. Throws an exception if the type doesn't match. Use
// getProto() to determine type, e.g. getProto().isStruct().
inline
bool
operator
==
(
const
Schema
&
other
)
const
{
return
raw
==
other
.
raw
;
}
inline
bool
operator
==
(
const
Schema
&
other
)
const
{
return
raw
==
other
.
raw
;
}
inline
bool
operator
!=
(
const
Schema
&
other
)
const
{
return
raw
!=
other
.
raw
;
}
inline
bool
operator
!=
(
const
Schema
&
other
)
const
{
return
raw
!=
other
.
raw
;
}
...
@@ -114,9 +119,12 @@ private:
...
@@ -114,9 +119,12 @@ private:
void
requireUsableAs
(
const
_
::
RawSchema
*
expected
)
const
;
void
requireUsableAs
(
const
_
::
RawSchema
*
expected
)
const
;
uint32_t
getSchemaOffset
(
const
schema
::
Value
::
Reader
&
value
)
const
;
friend
class
StructSchema
;
friend
class
StructSchema
;
friend
class
EnumSchema
;
friend
class
EnumSchema
;
friend
class
InterfaceSchema
;
friend
class
InterfaceSchema
;
friend
class
ConstSchema
;
friend
class
ListSchema
;
friend
class
ListSchema
;
friend
class
SchemaLoader
;
friend
class
SchemaLoader
;
};
};
...
@@ -401,6 +409,32 @@ private:
...
@@ -401,6 +409,32 @@ private:
// -------------------------------------------------------------------
// -------------------------------------------------------------------
class
ConstSchema
:
public
Schema
{
// Represents a constant declaration.
//
// `ConstSchema` can be implicitly cast to DynamicValue to read its value.
public
:
ConstSchema
()
=
default
;
template
<
typename
T
>
ReaderFor
<
T
>
as
()
const
;
// Read the constant's value. This is a convenience method equivalent to casting the ConstSchema
// to a DynamicValue and then calling its `as<T>()` method. For dependency reasons, this method
// is defined in <capnp/dynamic.h>, which you must #include explicitly.
uint32_t
getValueSchemaOffset
()
const
;
// Much like StructSchema::Field::getDefaultValueSchemaOffset(), if the constant has pointer
// type, this gets the offset from the beginning of the constant's schema node to a pointer
// representing the constant value.
private
:
ConstSchema
(
const
_
::
RawSchema
*
raw
)
:
Schema
(
raw
)
{}
friend
class
Schema
;
};
// -------------------------------------------------------------------
class
ListSchema
{
class
ListSchema
{
// ListSchema is a little different because list types are not described by schema nodes. So,
// ListSchema is a little different because list types are not described by schema nodes. So,
// ListSchema doesn't subclass Schema.
// ListSchema doesn't subclass Schema.
...
...
c++/src/capnp/stringify.c++
View file @
ac1e532d
...
@@ -267,7 +267,8 @@ kj::StringTree prettyPrint(DynamicList::Builder value) { return prettyPrint(valu
...
@@ -267,7 +267,8 @@ kj::StringTree prettyPrint(DynamicList::Builder value) { return prettyPrint(valu
kj
::
StringTree
KJ_STRINGIFY
(
const
DynamicValue
::
Reader
&
value
)
{
return
stringify
(
value
);
}
kj
::
StringTree
KJ_STRINGIFY
(
const
DynamicValue
::
Reader
&
value
)
{
return
stringify
(
value
);
}
kj
::
StringTree
KJ_STRINGIFY
(
const
DynamicValue
::
Builder
&
value
)
{
return
stringify
(
value
.
asReader
());
}
kj
::
StringTree
KJ_STRINGIFY
(
const
DynamicValue
::
Builder
&
value
)
{
return
stringify
(
value
.
asReader
());
}
kj
::
StringTree
KJ_STRINGIFY
(
DynamicEnum
value
)
{
return
stringify
(
value
);
}
kj
::
StringTree
KJ_STRINGIFY
(
DynamicEnum
value
)
{
return
stringify
(
value
);
}
kj
::
StringTree
KJ_STRINGIFY
(
const
DynamicObject
&
value
)
{
return
stringify
(
value
);
}
kj
::
StringTree
KJ_STRINGIFY
(
const
DynamicObject
::
Reader
&
value
)
{
return
stringify
(
value
);
}
kj
::
StringTree
KJ_STRINGIFY
(
const
DynamicObject
::
Builder
&
value
)
{
return
stringify
(
value
.
asReader
());
}
kj
::
StringTree
KJ_STRINGIFY
(
const
DynamicStruct
::
Reader
&
value
)
{
return
stringify
(
value
);
}
kj
::
StringTree
KJ_STRINGIFY
(
const
DynamicStruct
::
Reader
&
value
)
{
return
stringify
(
value
);
}
kj
::
StringTree
KJ_STRINGIFY
(
const
DynamicStruct
::
Builder
&
value
)
{
return
stringify
(
value
.
asReader
());
}
kj
::
StringTree
KJ_STRINGIFY
(
const
DynamicStruct
::
Builder
&
value
)
{
return
stringify
(
value
.
asReader
());
}
kj
::
StringTree
KJ_STRINGIFY
(
const
DynamicList
::
Reader
&
value
)
{
return
stringify
(
value
);
}
kj
::
StringTree
KJ_STRINGIFY
(
const
DynamicList
::
Reader
&
value
)
{
return
stringify
(
value
);
}
...
...
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