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
18cfa132
Commit
18cfa132
authored
May 10, 2013
by
Kenton Varda
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Dynamic API WIP.
parent
1a515be7
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
1454 additions
and
6 deletions
+1454
-6
dynamic.c++
c++/src/capnproto/dynamic.c++
+616
-0
dynamic.h
c++/src/capnproto/dynamic.h
+815
-0
generated-header-support.h
c++/src/capnproto/generated-header-support.h
+16
-3
CxxGenerator.hs
compiler/src/CxxGenerator.hs
+2
-0
c++-header.mustache
compiler/src/c++-header.mustache
+5
-3
No files found.
c++/src/capnproto/dynamic.c++
0 → 100644
View file @
18cfa132
// Copyright (c) 2013, Kenton Varda <temporal@gmail.com>
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#define CAPNPROTO_PRIVATE
#include "dynamic.h"
#include "logging.h"
#include <unordered_map>
#include <string>
namespace
capnproto
{
struct
IdTextHash
{
static
size_t
hash
(
std
::
pair
<
uint64_t
,
Text
::
Reader
>
p
)
{
// djb2a hash, but seeded with ID.
size_t
result
=
p
.
first
;
int
c
;
const
char
*
str
=
p
.
second
.
c_str
();
while
((
c
=
*
str
++
))
{
result
=
((
result
<<
5
)
+
result
)
^
c
;
// (result * 33) ^ c
}
return
result
;
}
};
struct
SchemaPool
::
Impl
{
std
::
unordered_map
<
uint64_t
,
schema
::
Node
::
Reader
>
nodeMap
;
std
::
unordered_map
<
std
::
pair
<
uint64_t
,
std
::
string
>
,
schema
::
StructNode
::
Member
::
Reader
,
IdTextHash
>
memberMap
;
std
::
unordered_map
<
std
::
pair
<
uint64_t
,
std
::
string
>
,
schema
::
EnumNode
::
Enumerant
::
Reader
,
IdTextHash
>
enumerantMap
;
};
SchemaPool
::~
SchemaPool
()
{
delete
impl
;
}
// TODO(soon): Implement this. Need to copy, ick.
//void add(schema::Node::Reader node) {
//}
void
SchemaPool
::
addNoCopy
(
schema
::
Node
::
Reader
node
)
{
if
(
impl
==
nullptr
)
{
impl
=
new
Impl
;
}
// TODO(soon): Check if node is in base.
// TODO(soon): Check if existing node came from generated code.
auto
entry
=
std
::
make_pair
(
node
.
getId
(),
node
);
auto
ins
=
impl
->
nodeMap
.
insert
(
entry
);
if
(
!
ins
.
second
)
{
// TODO(soon): Check for compatibility.
FAIL_CHECK
(
"TODO: Check schema compatibility when adding."
);
}
}
bool
SchemaPool
::
has
(
uint64_t
id
)
const
{
return
(
impl
!=
nullptr
&&
impl
->
nodeMap
.
count
(
id
)
!=
0
)
||
(
base
!=
nullptr
&&
base
->
has
(
id
));
}
DynamicStruct
::
Reader
SchemaPool
::
getRoot
(
MessageReader
&
message
,
uint64_t
typeId
)
const
{
}
DynamicStruct
::
Builder
SchemaPool
::
getRoot
(
MessageBuilder
&
message
,
uint64_t
typeId
)
const
{
}
// =======================================================================================
namespace
{
template
<
typename
T
,
typename
U
>
CAPNPROTO_ALWAYS_INLINE
(
T
bitCast
(
U
value
));
template
<
typename
T
,
typename
U
>
inline
T
bitCast
(
U
value
)
{
static_assert
(
sizeof
(
T
)
==
sizeof
(
U
),
"Size must match."
);
return
value
;
}
template
<>
inline
float
bitCast
<
float
,
uint32_t
>
(
uint32_t
value
)
{
float
result
;
memcpy
(
&
result
,
&
value
,
sizeof
(
value
));
return
result
;
}
template
<>
inline
double
bitCast
<
double
,
uint64_t
>
(
uint64_t
value
)
{
double
result
;
memcpy
(
&
result
,
&
value
,
sizeof
(
value
));
return
result
;
}
template
<>
inline
uint32_t
bitCast
<
uint32_t
,
float
>
(
float
value
)
{
uint32_t
result
;
memcpy
(
&
result
,
&
value
,
sizeof
(
value
));
return
result
;
}
template
<>
inline
uint64_t
bitCast
<
uint64_t
,
double
>
(
double
value
)
{
uint64_t
result
;
memcpy
(
&
result
,
&
value
,
sizeof
(
value
));
return
result
;
}
internal
::
FieldSize
elementSizeFor
(
schema
::
Type
::
Reader
elementType
)
{
switch
(
elementType
.
getBody
().
which
())
{
case
schema
:
:
Type
::
Body
::
VOID_TYPE
:
return
internal
::
FieldSize
::
VOID
;
case
schema
:
:
Type
::
Body
::
BOOL_TYPE
:
return
internal
::
FieldSize
::
BIT
;
case
schema
:
:
Type
::
Body
::
INT8_TYPE
:
return
internal
::
FieldSize
::
BYTE
;
case
schema
:
:
Type
::
Body
::
INT16_TYPE
:
return
internal
::
FieldSize
::
TWO_BYTES
;
case
schema
:
:
Type
::
Body
::
INT32_TYPE
:
return
internal
::
FieldSize
::
FOUR_BYTES
;
case
schema
:
:
Type
::
Body
::
INT64_TYPE
:
return
internal
::
FieldSize
::
EIGHT_BYTES
;
case
schema
:
:
Type
::
Body
::
UINT8_TYPE
:
return
internal
::
FieldSize
::
BYTE
;
case
schema
:
:
Type
::
Body
::
UINT16_TYPE
:
return
internal
::
FieldSize
::
TWO_BYTES
;
case
schema
:
:
Type
::
Body
::
UINT32_TYPE
:
return
internal
::
FieldSize
::
FOUR_BYTES
;
case
schema
:
:
Type
::
Body
::
UINT64_TYPE
:
return
internal
::
FieldSize
::
EIGHT_BYTES
;
case
schema
:
:
Type
::
Body
::
FLOAT32_TYPE
:
return
internal
::
FieldSize
::
FOUR_BYTES
;
case
schema
:
:
Type
::
Body
::
FLOAT64_TYPE
:
return
internal
::
FieldSize
::
EIGHT_BYTES
;
case
schema
:
:
Type
::
Body
::
TEXT_TYPE
:
return
internal
::
FieldSize
::
REFERENCE
;
case
schema
:
:
Type
::
Body
::
DATA_TYPE
:
return
internal
::
FieldSize
::
REFERENCE
;
case
schema
:
:
Type
::
Body
::
LIST_TYPE
:
return
internal
::
FieldSize
::
REFERENCE
;
case
schema
:
:
Type
::
Body
::
ENUM_TYPE
:
return
internal
::
FieldSize
::
TWO_BYTES
;
case
schema
:
:
Type
::
Body
::
STRUCT_TYPE
:
return
internal
::
FieldSize
::
INLINE_COMPOSITE
;
case
schema
:
:
Type
::
Body
::
INTERFACE_TYPE
:
return
internal
::
FieldSize
::
REFERENCE
;
case
schema
:
:
Type
::
Body
::
OBJECT_TYPE
:
FAIL_CHECK
(
"List(Object) not supported."
);
}
FAIL_CHECK
(
"Can't get here."
);
return
internal
::
FieldSize
::
VOID
;
}
}
// namespace
// =======================================================================================
schema
::
EnumNode
::
Reader
DynamicEnum
::
getSchema
()
{
return
schema
.
getBody
().
getEnumNode
();
}
Maybe
<
schema
::
EnumNode
::
Enumerant
::
Reader
>
DynamicEnum
::
getEnumerant
()
{
auto
enumerants
=
getSchema
().
getEnumerants
();
if
(
value
<
enumerants
.
size
())
{
return
enumerants
[
value
];
}
else
{
return
nullptr
;
}
}
Maybe
<
schema
::
EnumNode
::
Enumerant
::
Reader
>
DynamicEnum
::
findEnumerantByName
(
Text
::
Reader
name
)
{
auto
iter
=
pool
->
impl
->
enumerantMap
.
find
(
std
::
make_pair
(
schema
.
getId
(),
name
));
if
(
iter
==
pool
->
impl
->
enumerantMap
.
end
())
{
return
nullptr
;
}
else
{
return
iter
->
second
;
}
}
uint16_t
DynamicEnum
::
toImpl
(
uint64_t
requestedTypeId
)
{
VALIDATE_INPUT
(
requestedTypeId
==
schema
.
getId
(),
"Type mismatch in DynamicEnum.to()."
)
{
// Go on with value.
}
return
value
;
}
// =======================================================================================
DynamicStruct
::
Reader
DynamicObject
::
Reader
::
toStruct
(
schema
::
Node
::
Reader
schema
)
{
PRECOND
(
schema
.
getBody
().
which
()
==
schema
::
Node
::
Body
::
STRUCT_NODE
,
"toStruct() passed a non-struct schema."
);
if
(
reader
.
kind
==
internal
::
ObjectKind
::
NULL_POINTER
)
{
return
DynamicStruct
::
Reader
(
pool
,
schema
,
internal
::
StructReader
());
}
VALIDATE_INPUT
(
reader
.
kind
==
internal
::
ObjectKind
::
STRUCT
,
"Object is not a struct."
)
{
return
DynamicStruct
::
Reader
(
pool
,
schema
,
internal
::
StructReader
());
}
return
DynamicStruct
::
Reader
(
pool
,
schema
,
reader
.
structReader
);
}
DynamicStruct
::
Builder
DynamicObject
::
Builder
::
toStruct
(
schema
::
Node
::
Reader
schema
)
{
PRECOND
(
schema
.
getBody
().
which
()
==
schema
::
Node
::
Body
::
STRUCT_NODE
,
"toStruct() passed a non-struct schema."
);
if
(
builder
.
kind
==
internal
::
ObjectKind
::
NULL_POINTER
)
{
return
DynamicStruct
::
Builder
(
pool
,
schema
,
internal
::
StructBuilder
());
}
VALIDATE_INPUT
(
builder
.
kind
==
internal
::
ObjectKind
::
STRUCT
,
"Object is not a struct."
)
{
return
DynamicStruct
::
Builder
(
pool
,
schema
,
internal
::
StructBuilder
());
}
return
DynamicStruct
::
Builder
(
pool
,
schema
,
builder
.
structBuilder
);
}
DynamicStruct
::
Reader
DynamicObject
::
Reader
::
toStruct
(
uint64_t
typeId
)
{
return
toStruct
(
pool
->
getStruct
(
typeId
));
}
DynamicStruct
::
Builder
DynamicObject
::
Builder
::
toStruct
(
uint64_t
typeId
)
{
return
toStruct
(
pool
->
getStruct
(
typeId
));
}
DynamicList
::
Reader
DynamicObject
::
Reader
::
toList
(
schema
::
Type
::
Reader
elementType
)
{
return
toList
(
internal
::
ListSchema
(
elementType
));
}
DynamicList
::
Builder
DynamicObject
::
Builder
::
toList
(
schema
::
Type
::
Reader
elementType
)
{
return
toList
(
internal
::
ListSchema
(
elementType
));
}
DynamicList
::
Reader
DynamicObject
::
Reader
::
toList
(
internal
::
ListSchema
schema
)
{
if
(
reader
.
kind
==
internal
::
ObjectKind
::
NULL_POINTER
)
{
return
DynamicList
::
Reader
(
pool
,
schema
,
internal
::
ListReader
());
}
VALIDATE_INPUT
(
reader
.
kind
==
internal
::
ObjectKind
::
LIST
,
"Object is not a list."
)
{
return
DynamicList
::
Reader
(
pool
,
schema
,
internal
::
ListReader
());
}
return
DynamicList
::
Reader
(
pool
,
schema
,
reader
.
listReader
);
}
DynamicList
::
Builder
DynamicObject
::
Builder
::
toList
(
internal
::
ListSchema
schema
)
{
if
(
builder
.
kind
==
internal
::
ObjectKind
::
NULL_POINTER
)
{
return
DynamicList
::
Builder
(
pool
,
schema
,
internal
::
ListBuilder
());
}
VALIDATE_INPUT
(
builder
.
kind
==
internal
::
ObjectKind
::
LIST
,
"Object is not a list."
)
{
return
DynamicList
::
Builder
(
pool
,
schema
,
internal
::
ListBuilder
());
}
return
DynamicList
::
Builder
(
pool
,
schema
,
builder
.
listBuilder
);
}
// =======================================================================================
schema
::
StructNode
::
Union
::
Reader
DynamicUnion
::
Reader
::
getSchema
()
{
return
schema
.
getBody
().
getUnionMember
();
}
schema
::
StructNode
::
Union
::
Reader
DynamicUnion
::
Builder
::
getSchema
()
{
return
schema
.
getBody
().
getUnionMember
();
}
Maybe
<
schema
::
StructNode
::
Member
::
Reader
>
DynamicUnion
::
Reader
::
which
()
{
auto
uschema
=
getSchema
();
auto
members
=
uschema
.
getMembers
();
uint16_t
discrim
=
reader
.
getDataField
<
uint32_t
>
(
uschema
.
getDiscriminantOffset
()
*
ELEMENTS
);
if
(
discrim
<
members
.
size
())
{
return
members
[
discrim
];
}
else
{
return
nullptr
;
}
}
Maybe
<
schema
::
StructNode
::
Member
::
Reader
>
DynamicUnion
::
Builder
::
which
()
{
auto
uschema
=
getSchema
();
auto
members
=
uschema
.
getMembers
();
uint16_t
discrim
=
builder
.
getDataField
<
uint32_t
>
(
uschema
.
getDiscriminantOffset
()
*
ELEMENTS
);
if
(
discrim
<
members
.
size
())
{
return
members
[
discrim
];
}
else
{
return
nullptr
;
}
}
DynamicValue
::
Reader
DynamicUnion
::
Reader
::
get
()
{
auto
w
=
which
();
RECOVERABLE_PRECOND
(
w
!=
nullptr
,
"Can't get() unknown union value."
)
{
return
DynamicValue
::
Reader
(
Void
::
VOID
);
}
auto
body
=
w
->
getBody
();
CHECK
(
body
.
which
()
==
schema
::
StructNode
::
Member
::
Body
::
FIELD_MEMBER
,
"Unsupported union member type."
);
return
DynamicValue
::
Reader
(
DynamicStruct
::
Reader
::
getFieldImpl
(
pool
,
reader
,
body
.
getFieldMember
()));
}
DynamicValue
::
Builder
DynamicUnion
::
Builder
::
get
()
{
auto
w
=
which
();
RECOVERABLE_PRECOND
(
w
!=
nullptr
,
"Can't get() unknown union value."
)
{
return
DynamicValue
::
Builder
(
Void
::
VOID
);
}
auto
body
=
w
->
getBody
();
CHECK
(
body
.
which
()
==
schema
::
StructNode
::
Member
::
Body
::
FIELD_MEMBER
,
"Unsupported union member type."
);
return
DynamicValue
::
Builder
(
DynamicStruct
::
Builder
::
getFieldImpl
(
pool
,
builder
,
body
.
getFieldMember
()));
}
void
DynamicUnion
::
Builder
::
set
(
schema
::
StructNode
::
Field
::
Reader
field
,
DynamicValue
::
Reader
value
)
{
auto
uschema
=
getSchema
();
builder
.
setDataField
<
uint16_t
>
(
uschema
.
getTagOffset
(),
field
.
getIndex
());
DynamicStruct
::
Builder
::
setFieldImpl
(
pool
,
builder
,
field
,
value
);
}
// =======================================================================================
DynamicValue
::
Reader
DynamicStruct
::
Reader
::
getFieldImpl
(
const
SchemaPool
*
pool
,
internal
::
StructReader
reader
,
schema
::
StructNode
::
Field
::
Reader
field
)
{
auto
type
=
field
.
getType
().
getBody
();
auto
dval
=
field
.
getDefaultValue
().
getBody
();
switch
(
type
.
which
())
{
case
schema
:
:
Type
::
Body
::
VOID_TYPE
:
return
DynamicValue
::
Reader
(
reader
.
getDataField
<
Void
>
(
field
.
getOffset
()
*
ELEMENTS
));
#define HANDLE_TYPE(discrim, titleCase, type) \
case schema::Type::Body::discrim##_TYPE: \
return DynamicValue::Reader(reader.getDataField<type>( \
field.getOffset() * ELEMENTS, \
bitCast<typename internal::MaskType<type>::Type>(dval.get##titleCase##Value())));
HANDLE_TYPE
(
BOOL
,
Bool
,
bool
)
HANDLE_TYPE
(
INT8
,
Int8
,
int8_t
)
HANDLE_TYPE
(
INT16
,
Int16
,
int16_t
)
HANDLE_TYPE
(
INT32
,
Int32
,
int32_t
)
HANDLE_TYPE
(
INT64
,
Int64
,
int64_t
)
HANDLE_TYPE
(
UINT8
,
Uint8
,
uint8_t
)
HANDLE_TYPE
(
UINT16
,
Uint16
,
uint16_t
)
HANDLE_TYPE
(
UINT32
,
Uint32
,
uint32_t
)
HANDLE_TYPE
(
UINT64
,
Uint64
,
uint64_t
)
HANDLE_TYPE
(
FLOAT32
,
Float32
,
float
)
HANDLE_TYPE
(
FLOAT64
,
Float64
,
double
)
#undef HANDLE_TYPE
case
schema
:
:
Type
::
Body
::
ENUM_TYPE
:
{
uint16_t
typedDval
;
typedDval
=
dval
.
getEnumValue
();
return
DynamicValue
::
Reader
(
DynamicEnum
(
pool
,
pool
->
getEnum
(
type
.
getEnumType
()),
reader
.
getDataField
<
uint16_t
>
(
field
.
getOffset
()
*
ELEMENTS
,
typedDval
)));
}
case
schema
:
:
Type
::
Body
::
TEXT_TYPE
:
{
Text
::
Reader
typedDval
=
dval
.
getTextValue
();
return
DynamicValue
::
Reader
(
reader
.
getBlobField
<
Text
>
(
field
.
getOffset
()
*
REFERENCES
,
typedDval
.
data
(),
typedDval
.
size
()
*
BYTES
));
}
case
schema
:
:
Type
::
Body
::
DATA_TYPE
:
{
Data
::
Reader
typedDval
=
dval
.
getDataValue
();
return
DynamicValue
::
Reader
(
reader
.
getBlobField
<
Data
>
(
field
.
getOffset
()
*
REFERENCES
,
typedDval
.
data
(),
typedDval
.
size
()
*
BYTES
));
}
case
schema
:
:
Type
::
Body
::
LIST_TYPE
:
{
auto
elementType
=
type
.
getListType
();
return
DynamicValue
::
Reader
(
DynamicList
::
Reader
(
pool
,
elementType
,
reader
.
getListField
(
field
.
getOffset
()
*
REFERENCES
,
elementSizeFor
(
elementType
),
dval
.
getListValue
<
internal
::
TrustedMessage
>
())));
}
case
schema
:
:
Type
::
Body
::
STRUCT_TYPE
:
{
return
DynamicValue
::
Reader
(
DynamicStruct
::
Reader
(
pool
,
pool
->
getStruct
(
type
.
getStructType
()),
reader
.
getStructField
(
field
.
getOffset
()
*
REFERENCES
,
dval
.
getStructValue
<
internal
::
TrustedMessage
>
())));
}
case
schema
:
:
Type
::
Body
::
OBJECT_TYPE
:
{
return
DynamicValue
::
Reader
(
DynamicObject
::
Reader
(
pool
,
reader
.
getObjectField
(
field
.
getOffset
()
*
REFERENCES
,
dval
.
getObjectValue
<
internal
::
TrustedMessage
>
())));
}
case
schema
:
:
Type
::
Body
::
INTERFACE_TYPE
:
FAIL_CHECK
(
"Interfaces not yet implemented."
);
break
;
}
FAIL_CHECK
(
"Can't get here."
);
return
DynamicValue
::
Reader
();
}
DynamicValue
::
Builder
DynamicStruct
::
Builder
::
getFieldImpl
(
const
SchemaPool
*
pool
,
internal
::
StructBuilder
builder
,
schema
::
StructNode
::
Field
::
Reader
field
)
{
auto
type
=
field
.
getType
().
getBody
();
auto
dval
=
field
.
getDefaultValue
().
getBody
();
switch
(
type
.
which
())
{
case
schema
:
:
Type
::
Body
::
VOID_TYPE
:
return
DynamicValue
::
Builder
(
builder
.
getDataField
<
Void
>
(
field
.
getOffset
()
*
ELEMENTS
));
#define HANDLE_TYPE(discrim, titleCase, type) \
case schema::Type::Body::discrim##_TYPE: \
return DynamicValue::Builder(builder.getDataField<type>( \
field.getOffset() * ELEMENTS, \
bitCast<typename internal::MaskType<type>::Type>(dval.get##titleCase##Value())));
HANDLE_TYPE
(
BOOL
,
Bool
,
bool
)
HANDLE_TYPE
(
INT8
,
Int8
,
int8_t
)
HANDLE_TYPE
(
INT16
,
Int16
,
int16_t
)
HANDLE_TYPE
(
INT32
,
Int32
,
int32_t
)
HANDLE_TYPE
(
INT64
,
Int64
,
int64_t
)
HANDLE_TYPE
(
UINT8
,
Uint8
,
uint8_t
)
HANDLE_TYPE
(
UINT16
,
Uint16
,
uint16_t
)
HANDLE_TYPE
(
UINT32
,
Uint32
,
uint32_t
)
HANDLE_TYPE
(
UINT64
,
Uint64
,
uint64_t
)
HANDLE_TYPE
(
FLOAT32
,
Float32
,
float
)
HANDLE_TYPE
(
FLOAT64
,
Float64
,
double
)
#undef HANDLE_TYPE
case
schema
:
:
Type
::
Body
::
ENUM_TYPE
:
{
uint16_t
typedDval
;
typedDval
=
dval
.
getEnumValue
();
return
DynamicValue
::
Builder
(
DynamicEnum
(
pool
,
pool
->
getEnum
(
type
.
getEnumType
()),
builder
.
getDataField
<
uint16_t
>
(
field
.
getOffset
()
*
ELEMENTS
,
typedDval
)));
}
case
schema
:
:
Type
::
Body
::
TEXT_TYPE
:
{
Text
::
Reader
typedDval
=
dval
.
getTextValue
();
return
DynamicValue
::
Builder
(
builder
.
getBlobField
<
Text
>
(
field
.
getOffset
()
*
REFERENCES
,
typedDval
.
data
(),
typedDval
.
size
()
*
BYTES
));
}
case
schema
:
:
Type
::
Body
::
DATA_TYPE
:
{
Data
::
Reader
typedDval
=
dval
.
getDataValue
();
return
DynamicValue
::
Builder
(
builder
.
getBlobField
<
Data
>
(
field
.
getOffset
()
*
REFERENCES
,
typedDval
.
data
(),
typedDval
.
size
()
*
BYTES
));
}
case
schema
:
:
Type
::
Body
::
LIST_TYPE
:
{
auto
elementType
=
type
.
getListType
();
return
DynamicValue
::
Builder
(
DynamicList
::
Builder
(
pool
,
elementType
,
builder
.
getListField
(
field
.
getOffset
()
*
REFERENCES
,
dval
.
getListValue
<
internal
::
TrustedMessage
>
())));
}
case
schema
:
:
Type
::
Body
::
STRUCT_TYPE
:
{
auto
structNode
=
pool
->
getStruct
(
type
.
getStructType
());
auto
structSchema
=
structNode
.
getBody
().
getStructNode
();
return
DynamicValue
::
Builder
(
DynamicStruct
::
Builder
(
pool
,
structNode
,
builder
.
getStructField
(
field
.
getOffset
()
*
REFERENCES
,
internal
::
StructSize
(
structSchema
.
getDataSectionWordSize
()
*
WORDS
,
structSchema
.
getPointerSectionSize
()
*
REFERENCES
,
static_cast
<
internal
::
FieldSize
>
(
structSchema
.
getPreferredListEncoding
())),
dval
.
getStructValue
<
internal
::
TrustedMessage
>
())));
}
case
schema
:
:
Type
::
Body
::
OBJECT_TYPE
:
{
return
DynamicValue
::
Builder
(
DynamicObject
::
Builder
(
pool
,
builder
.
getObjectField
(
field
.
getOffset
()
*
REFERENCES
,
dval
.
getObjectValue
<
internal
::
TrustedMessage
>
())));
}
case
schema
:
:
Type
::
Body
::
INTERFACE_TYPE
:
FAIL_CHECK
(
"Interfaces not yet implemented."
);
break
;
}
FAIL_CHECK
(
"Can't get here."
);
return
DynamicValue
::
Builder
();
}
void
DynamicStruct
::
Builder
::
setFieldImpl
(
const
SchemaPool
*
pool
,
internal
::
StructBuilder
builder
,
schema
::
StructNode
::
Field
::
Reader
field
,
DynamicValue
::
Reader
value
)
{
auto
type
=
field
.
getType
().
getBody
();
auto
dval
=
field
.
getDefaultValue
().
getBody
();
switch
(
type
.
which
())
{
case
schema
:
:
Type
::
Body
::
VOID_TYPE
:
builder
.
setDataField
<
Void
>
(
field
.
getOffset
()
*
ELEMENTS
,
value
.
to
<
Void
>
());
break
;
#define HANDLE_TYPE(discrim, titleCase, type) \
case schema::Type::Body::discrim##_TYPE: \
builder.setDataField<type>( \
field.getOffset() * ELEMENTS, value.to<type>(), \
bitCast<internal::Mask<type> >(dval.get##titleCase##Value()));
break
;
HANDLE_TYPE
(
BOOL
,
Bool
,
bool
)
HANDLE_TYPE
(
INT8
,
Int8
,
int8_t
)
HANDLE_TYPE
(
INT16
,
Int16
,
int16_t
)
HANDLE_TYPE
(
INT32
,
Int32
,
int32_t
)
HANDLE_TYPE
(
INT64
,
Int64
,
int64_t
)
HANDLE_TYPE
(
UINT8
,
Uint8
,
uint8_t
)
HANDLE_TYPE
(
UINT16
,
Uint16
,
uint16_t
)
HANDLE_TYPE
(
UINT32
,
Uint32
,
uint32_t
)
HANDLE_TYPE
(
UINT64
,
Uint64
,
uint64_t
)
HANDLE_TYPE
(
FLOAT32
,
Float32
,
float
)
HANDLE_TYPE
(
FLOAT64
,
Float64
,
double
)
#undef HANDLE_TYPE
case
schema
:
:
Type
::
Body
::
ENUM_TYPE
:
builder
.
setDataField
<
uint16_t
>
(
field
.
getOffset
()
*
ELEMENTS
,
value
.
to
<
DynamicEnum
>
().
getRaw
(),
dval
.
getEnumValue
());
break
;
case
schema
:
:
Type
::
Body
::
TEXT_TYPE
:
builder
.
setBlobField
<
Text
>
(
field
.
getOffset
()
*
REFERENCES
,
value
.
to
<
Text
>
());
break
;
case
schema
:
:
Type
::
Body
::
DATA_TYPE
:
builder
.
setBlobField
<
Data
>
(
field
.
getOffset
()
*
REFERENCES
,
value
.
to
<
Data
>
());
break
;
case
schema
:
:
Type
::
Body
::
LIST_TYPE
:
{
// TODO(soon): We need to do a schemaless copy to avoid losing information if the values are
// larger than what the schema defines.
auto
listValue
=
value
.
to
<
DynamicList
>
();
initListFieldImpl
(
pool
,
builder
,
field
,
listValue
.
size
()).
copyFrom
(
listValue
);
break
;
}
case
schema
:
:
Type
::
Body
::
STRUCT_TYPE
:
{
// TODO(soon): We need to do a schemaless copy to avoid losing information if the values are
// larger than what the schema defines.
initStructFieldImpl
(
pool
,
builder
,
field
).
copyFrom
(
value
.
to
<
DynamicStruct
>
());
break
;
}
case
schema
:
:
Type
::
Body
::
OBJECT_TYPE
:
{
// TODO(soon): Perform schemaless copy.
FAIL_CHECK
(
"TODO"
);
break
;
}
case
schema
:
:
Type
::
Body
::
INTERFACE_TYPE
:
FAIL_CHECK
(
"Interfaces not yet implemented."
);
break
;
}
}
// =======================================================================================
#if 0
#define HANDLE_TYPE(name, discrim, typeName) \
ReaderFor<typeName> DynamicValue::Reader::ToImpl<typeName>::apply(Reader reader) { \
VALIDATE_INPUT(reader.type == schema::Type::Body::discrim##_TYPE, \
"Type mismatch when using DynamicValue::to().") { \
return typeName(); \
} \
return reader.name##Value; \
} \
BuilderFor<typeName> DynamicValue::Builder::ToImpl<typeName>::apply(Builder builder) { \
VALIDATE_INPUT(builder.type == schema::Type::Body::discrim##_TYPE, \
"Type mismatch when using DynamicValue::to().") { \
return typeName(); \
} \
return builder.name##Value; \
}
//HANDLE_TYPE(void, VOID, Void)
HANDLE_TYPE(bool, BOOL, bool)
HANDLE_TYPE(int8, INT8, int8_t)
HANDLE_TYPE(int16, INT16, int16_t)
HANDLE_TYPE(int32, INT32, int32_t)
HANDLE_TYPE(int64, INT64, int64_t)
HANDLE_TYPE(uint8, UINT8, uint8_t)
HANDLE_TYPE(uint16, UINT16, uint16_t)
HANDLE_TYPE(uint32, UINT32, uint32_t)
HANDLE_TYPE(uint64, UINT64, uint64_t)
HANDLE_TYPE(float32, FLOAT32, float)
HANDLE_TYPE(float64, FLOAT64, double)
HANDLE_TYPE(text, TEXT, Text)
HANDLE_TYPE(data, DATA, Data)
HANDLE_TYPE(list, LIST, DynamicList)
HANDLE_TYPE(struct, STRUCT, DynamicStruct)
HANDLE_TYPE(enum, ENUM, DynamicEnum)
HANDLE_TYPE(object, OBJECT, DynamicObject)
#undef HANDLE_TYPE
#endif
// As in the header, HANDLE_TYPE(void, VOID, Void) crashes GCC 4.7.
Void
DynamicValue
::
Reader
::
ToImpl
<
Void
>::
apply
(
Reader
reader
)
{
VALIDATE_INPUT
(
reader
.
type
==
schema
::
Type
::
Body
::
VOID_TYPE
,
"Type mismatch when using DynamicValue::to()."
)
{
return
Void
();
}
return
reader
.
voidValue
;
}
Void
DynamicValue
::
Builder
::
ToImpl
<
Void
>::
apply
(
Builder
builder
)
{
VALIDATE_INPUT
(
builder
.
type
==
schema
::
Type
::
Body
::
VOID_TYPE
,
"Type mismatch when using DynamicValue::to()."
)
{
return
Void
();
}
return
builder
.
voidValue
;
}
}
// namespace capnproto
c++/src/capnproto/dynamic.h
0 → 100644
View file @
18cfa132
// Copyright (c) 2013, Kenton Varda <temporal@gmail.com>
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// This file defines classes that can be used to manipulate messages based on schemas that are not
// known until runtime. This is also useful for writing generic code that uses schemas to handle
// arbitrary types in a generic way.
//
// Each of the classes defined here has a to() template method which converts an instance back to a
// native type. This method will throw an exception if the requested type does not match the
// schema. To convert native types to dynamic, use DynamicFactory.
//
// As always, underlying data is validated lazily, so you have to actually traverse the whole
// message if you want to validate all content.
#ifndef CAPNPROTO_DYNAMIC_H_
#define CAPNPROTO_DYNAMIC_H_
#include "schema.capnp.h"
#include "layout.h"
namespace
capnproto
{
class
MessageReader
;
class
MessageBuilder
;
struct
DynamicValue
{
class
Reader
;
class
Builder
;
};
class
DynamicEnum
;
struct
DynamicObject
{
class
Reader
;
class
Builder
;
};
struct
DynamicUnion
{
class
Reader
;
class
Builder
;
};
struct
DynamicStruct
{
class
Reader
;
class
Builder
;
};
struct
DynamicList
{
class
Reader
;
class
Builder
;
};
class
SchemaPool
{
// Class representing a pool of schema data which is indexed for convenient traversal.
//
// TODO(someday): Allow registration of a callback to look up missing nodes. The callback
// should not return a value, but instead should receive a pointer to the pool to populate.
// This will make it easier to deal with ownership and to batch-add related nodes.
public
:
SchemaPool
()
:
base
(
nullptr
),
impl
(
nullptr
)
{}
// Constructs an empty pool.
explicit
SchemaPool
(
const
SchemaPool
&
base
)
:
base
(
&
base
),
impl
(
nullptr
)
{}
// Constructs a pool that extends the given base pool. The behavior is similar to copying the
// base pool, except that memory is shared. The base pool must outlive the new pool.
//
// The purpose of this is to allow a pool to be shared by multiple threads. The from*() methods
// may add new schema nodes to the pool if they aren't already present, and therefore they are
// not thread-safe. However, if you create a shared pool that contains all the types you need,
// then it is reasonably efficient to create a fresh SchemaPool on the stack extending the shared
// pool each time you need to manipulate a type dynamically. If the shared pool ends up
// containing everything that is needed, then the extension pool won't allocate any memory at all.
~
SchemaPool
();
void
add
(
schema
::
Node
::
Reader
node
);
// Add a schema node. It will be copied and validated, throwing an exception if invalid. If
// another node with the same ID already exists, the nodes will be compared for compatibility
// and the definition determined to be "newer" will be kept. If the nodes are not compatible,
// an exception will be thrown.
template
<
typename
T
>
void
add
();
// Add schema for the given compiled-in type and all of its transitive dependencies, including
// nested nodes, but NOT necessarily including annotation definitions (because those are not
// always compiled in) or parent scopes (because adding parent scopes would necessarily mean
// adding all types in the file and in all transitive imports, which may be much more than you
// want).
bool
has
(
uint64_t
typeId
)
const
;
template
<
typename
T
>
DynamicEnum
fromEnum
(
T
&&
value
);
template
<
typename
T
>
DynamicStruct
::
Reader
fromStructReader
(
T
&&
reader
);
template
<
typename
T
>
DynamicStruct
::
Builder
fromStructBuilder
(
T
&&
builder
);
template
<
typename
T
>
DynamicList
::
Reader
fromListReader
(
T
&&
reader
);
template
<
typename
T
>
DynamicList
::
Builder
fromListBuilder
(
T
&&
builder
);
DynamicStruct
::
Reader
getRoot
(
MessageReader
&
message
,
uint64_t
typeId
)
const
;
DynamicStruct
::
Builder
getRoot
(
MessageBuilder
&
message
,
uint64_t
typeId
)
const
;
private
:
struct
Impl
;
const
SchemaPool
*
base
;
Impl
*
impl
;
SchemaPool
&
operator
=
(
const
SchemaPool
&
)
=
delete
;
void
addNoCopy
(
schema
::
Node
::
Reader
node
);
schema
::
Node
::
Reader
getStruct
(
uint64_t
id
)
const
;
schema
::
Node
::
Reader
getEnum
(
uint64_t
id
)
const
;
schema
::
Node
::
Reader
getInterface
(
uint64_t
id
)
const
;
friend
class
DynamicEnum
;
friend
class
DynamicStruct
;
friend
class
DynamicList
;
friend
class
DynamicObject
;
};
// -------------------------------------------------------------------
namespace
internal
{
struct
ListSchema
{
// Hack for determining/specifying the schema for a List without having to construct a Cap'n Proto
// message.
schema
::
Type
::
Body
::
Which
elementType
;
uint8_t
nestingDepth
;
// 0 for T, 1 for List(T), 2 for List(List(T)), ...
uint64_t
elementTypeId
;
constexpr
ListSchema
(
schema
::
Type
::
Body
::
Which
elementType
)
:
elementType
(
elementType
),
nestingDepth
(
0
),
elementTypeId
(
0
)
{}
constexpr
ListSchema
(
schema
::
Type
::
Body
::
Which
elementType
,
uint64_t
elementTypeId
)
:
elementType
(
elementType
),
nestingDepth
(
0
),
elementTypeId
(
elementTypeId
)
{}
constexpr
ListSchema
(
schema
::
Type
::
Body
::
Which
elementType
,
uint8_t
nestingDepth
,
uint64_t
elementTypeId
)
:
elementType
(
elementType
),
nestingDepth
(
nestingDepth
),
elementTypeId
(
elementTypeId
)
{}
ListSchema
(
schema
::
Type
::
Reader
elementType
);
// Construct from an actual schema.
constexpr
ListSchema
deeper
()
{
return
ListSchema
(
elementType
,
nestingDepth
+
1
,
elementTypeId
);
}
};
template
<
typename
ElementType
,
Kind
kind
=
kind
<
ElementType
>
()
>
struct
ListSchemaFor
;
#define CAPNPROTO_DECLARE_TYPE(discrim, typeName) \
template <> \
struct ListSchemaFor<List<typeName>> { \
static constexpr ListSchema type = ListSchema(schema::Type::Body::discrim##_TYPE); \
};
CAPNPROTO_DECLARE_TYPE
(
VOID
,
Void
)
CAPNPROTO_DECLARE_TYPE
(
BOOL
,
bool
)
CAPNPROTO_DECLARE_TYPE
(
INT8
,
int8_t
)
CAPNPROTO_DECLARE_TYPE
(
INT16
,
int16_t
)
CAPNPROTO_DECLARE_TYPE
(
INT32
,
int32_t
)
CAPNPROTO_DECLARE_TYPE
(
INT64
,
int64_t
)
CAPNPROTO_DECLARE_TYPE
(
UINT8
,
uint8_t
)
CAPNPROTO_DECLARE_TYPE
(
UINT16
,
uint16_t
)
CAPNPROTO_DECLARE_TYPE
(
UINT32
,
uint32_t
)
CAPNPROTO_DECLARE_TYPE
(
UINT64
,
uint64_t
)
CAPNPROTO_DECLARE_TYPE
(
FLOAT32
,
float
)
CAPNPROTO_DECLARE_TYPE
(
FLOAT64
,
double
)
CAPNPROTO_DECLARE_TYPE
(
TEXT
,
Text
)
CAPNPROTO_DECLARE_TYPE
(
DATA
,
Data
)
CAPNPROTO_DECLARE_TYPE
(
LIST
,
DynamicList
)
#undef CAPNPROTO_DECLARE_TYPE
template
<
typename
T
>
struct
ListSchemaFor
<
T
,
Kind
::
ENUM
>
{
static
constexpr
ListSchema
type
=
ListSchema
(
schema
::
Type
::
Body
::
ENUM_TYPE
,
typeId
<
T
>
());
};
template
<
typename
T
>
struct
ListSchemaFor
<
T
,
Kind
::
STRUCT
>
{
static
constexpr
ListSchema
type
=
ListSchema
(
schema
::
Type
::
Body
::
STRUCT_TYPE
,
typeId
<
T
>
());
};
template
<
typename
T
>
struct
ListSchemaFor
<
T
,
Kind
::
INTERFACE
>
{
static
constexpr
ListSchema
type
=
ListSchema
(
schema
::
Type
::
Body
::
INTERFACE_TYPE
,
typeId
<
T
>
());
};
template
<
typename
T
>
struct
ListSchemaFor
<
List
<
T
>
,
Kind
::
LIST
>
{
static
constexpr
ListSchema
type
=
ListSchemaFor
<
T
>::
schema
.
deeper
();
};
}
// namespace internal
// -------------------------------------------------------------------
class
DynamicEnum
{
public
:
DynamicEnum
()
=
default
;
template
<
typename
T
>
inline
T
to
()
{
return
static_cast
<
T
>
(
toImpl
(
typeId
<
T
>
()));
}
// Cast to a native enum type.
schema
::
Node
::
Reader
getSchemaNode
()
{
return
schema
;
}
schema
::
EnumNode
::
Reader
getSchema
();
Maybe
<
schema
::
EnumNode
::
Enumerant
::
Reader
>
getEnumerant
();
// Get which enumerant this enum value represents. Returns nullptr if the numeric value does not
// correspond to any enumerant in the schema -- this can happen if the data was built using a
// newer schema that has more values defined.
Maybe
<
schema
::
EnumNode
::
Enumerant
::
Reader
>
findEnumerantByName
(
Text
::
Reader
name
);
// Search this enum's type for an enumerant with the given name.
inline
uint16_t
getRaw
()
{
return
value
;
}
// Returns the raw underlying enum value.
private
:
const
SchemaPool
*
pool
;
schema
::
Node
::
Reader
schema
;
uint16_t
value
;
inline
DynamicEnum
(
const
SchemaPool
*
pool
,
schema
::
Node
::
Reader
schema
,
uint16_t
value
)
:
pool
(
pool
),
schema
(
schema
),
value
(
value
)
{}
uint16_t
toImpl
(
uint64_t
requestedTypeId
);
friend
struct
DynamicStruct
;
};
// -------------------------------------------------------------------
class
DynamicObject
::
Reader
{
public
:
Reader
()
=
default
;
template
<
typename
T
>
inline
typename
T
::
Reader
to
()
{
return
ToImpl
<
T
>::
apply
(
*
this
);
}
// Convert the object to the given struct, list, or blob type.
DynamicStruct
::
Reader
toStruct
(
schema
::
Node
::
Reader
schema
);
DynamicList
::
Reader
toList
(
schema
::
Type
::
Reader
elementType
);
private
:
const
SchemaPool
*
pool
;
internal
::
ObjectReader
reader
;
inline
Reader
(
const
SchemaPool
*
pool
,
internal
::
ObjectReader
reader
)
:
pool
(
pool
),
reader
(
reader
)
{}
template
<
typename
T
,
Kind
kind
=
kind
<
T
>
()
>
struct
ToImpl
;
// Implementation backing the to() method. Needs to be a struct to allow partial
// specialization. Has a method apply() which does the work.
DynamicStruct
::
Reader
toStruct
(
uint64_t
typeId
);
DynamicList
::
Reader
toList
(
internal
::
ListSchema
schema
);
friend
struct
DynamicStruct
;
};
class
DynamicObject
::
Builder
{
public
:
Builder
()
=
default
;
template
<
typename
T
>
inline
typename
T
::
Builder
to
()
{
return
ToImpl
<
T
>::
apply
(
*
this
);
}
// Convert the object to the given struct, list, or blob type.
DynamicStruct
::
Builder
toStruct
(
schema
::
Node
::
Reader
schema
);
DynamicList
::
Builder
toList
(
schema
::
Type
::
Reader
elementType
);
private
:
const
SchemaPool
*
pool
;
internal
::
ObjectBuilder
builder
;
inline
Builder
(
const
SchemaPool
*
pool
,
internal
::
ObjectBuilder
builder
)
:
pool
(
pool
),
builder
(
builder
)
{}
template
<
typename
T
,
Kind
kind
=
kind
<
T
>
()
>
struct
ToImpl
;
// Implementation backing the to() method. Needs to be a struct to allow partial
// specialization. Has a method apply() which does the work.
DynamicStruct
::
Builder
toStruct
(
uint64_t
typeId
);
DynamicList
::
Builder
toList
(
internal
::
ListSchema
schema
);
friend
struct
DynamicStruct
;
};
// -------------------------------------------------------------------
class
DynamicUnion
::
Reader
{
public
:
Reader
()
=
default
;
schema
::
StructNode
::
Member
::
Reader
getMemberSchema
()
{
return
schema
;
}
schema
::
StructNode
::
Union
::
Reader
getSchema
();
Maybe
<
schema
::
StructNode
::
Member
::
Reader
>
which
();
// Returns which field is set, or nullptr if an unknown field is set (i.e. the schema is old, and
// the underlying data has the union set to a member we don't know about).
DynamicValue
::
Reader
get
();
// Get the value of whichever field of the union is set.
private
:
const
SchemaPool
*
pool
;
schema
::
StructNode
::
Member
::
Reader
schema
;
internal
::
StructReader
reader
;
inline
Reader
(
const
SchemaPool
*
pool
,
schema
::
StructNode
::
Member
::
Reader
schema
,
internal
::
StructReader
reader
)
:
pool
(
pool
),
schema
(
schema
),
reader
(
reader
)
{}
};
class
DynamicUnion
::
Builder
{
public
:
Builder
()
=
default
;
schema
::
StructNode
::
Member
::
Reader
getMemberSchema
()
{
return
schema
;
}
schema
::
StructNode
::
Union
::
Reader
getSchema
();
Maybe
<
schema
::
StructNode
::
Member
::
Reader
>
which
();
// Returns which field is set, or nullptr if an unknown field is set (i.e. the schema is old, and
// the underlying data has the union set to a member we don't know about).
DynamicValue
::
Builder
get
();
void
set
(
schema
::
StructNode
::
Field
::
Reader
field
,
DynamicValue
::
Reader
value
);
DynamicValue
::
Builder
init
(
schema
::
StructNode
::
Field
::
Reader
field
);
private
:
const
SchemaPool
*
pool
;
schema
::
StructNode
::
Member
::
Reader
schema
;
internal
::
StructBuilder
builder
;
inline
Builder
(
const
SchemaPool
*
pool
,
schema
::
StructNode
::
Member
::
Reader
schema
,
internal
::
StructBuilder
builder
)
:
pool
(
pool
),
schema
(
schema
),
builder
(
builder
)
{}
};
// -------------------------------------------------------------------
class
DynamicStruct
::
Reader
{
public
:
Reader
()
=
default
;
template
<
typename
T
>
typename
T
::
Reader
to
();
// Convert the dynamic struct to its compiled-in type.
schema
::
Node
::
Reader
getSchemaNode
();
schema
::
StructNode
::
Reader
getSchema
();
Maybe
<
schema
::
StructNode
::
Member
::
Reader
>
findMemberByName
(
Text
::
Reader
name
);
// Looks up the member with the given name, or returns nullptr if no such member exists.
DynamicValue
::
Reader
getField
(
schema
::
StructNode
::
Field
::
Reader
field
);
// Returns the value of the given field.
DynamicUnion
::
Reader
getUnion
(
schema
::
StructNode
::
Union
::
Reader
un
);
// Returns the value of the given union.
private
:
const
SchemaPool
*
pool
;
schema
::
Node
::
Reader
schema
;
internal
::
StructReader
reader
;
inline
Reader
(
const
SchemaPool
*
pool
,
schema
::
Node
::
Reader
schema
,
internal
::
StructReader
reader
)
:
pool
(
pool
),
schema
(
schema
),
reader
(
reader
)
{}
static
DynamicValue
::
Reader
getFieldImpl
(
const
SchemaPool
*
pool
,
internal
::
StructReader
reader
,
schema
::
StructNode
::
Field
::
Reader
field
);
template
<
typename
T
>
friend
struct
internal
::
PointerHelpers
;
friend
class
DynamicUnion
::
Reader
;
friend
class
DynamicObject
;
};
class
DynamicStruct
::
Builder
{
public
:
Builder
()
=
default
;
template
<
typename
T
>
typename
T
::
Builder
to
();
// Cast to a particular struct type.
schema
::
Node
::
Reader
getSchemaNode
();
schema
::
StructNode
::
Reader
getSchema
();
Maybe
<
schema
::
StructNode
::
Member
::
Reader
>
findMemberByName
(
Text
::
Reader
name
);
// Looks up the member with the given name, or returns nullptr if no such member exists.
DynamicValue
::
Builder
getField
(
schema
::
StructNode
::
Field
::
Reader
field
);
// Returns the value of the given field.
void
setField
(
schema
::
StructNode
::
Field
::
Reader
field
,
DynamicValue
::
Reader
value
);
// Sets the value of the given field.
DynamicStruct
::
Builder
initField
(
schema
::
StructNode
::
Field
::
Reader
field
);
DynamicList
::
Builder
initField
(
schema
::
StructNode
::
Field
::
Reader
field
,
uint
size
);
// Initialize a struct or list field by field schema.
DynamicUnion
::
Builder
getUnion
(
schema
::
StructNode
::
Union
::
Reader
un
);
// Returns the value of the given union.
void
copyFrom
(
Reader
other
);
Reader
asReader
();
private
:
const
SchemaPool
*
pool
;
schema
::
Node
::
Reader
schema
;
internal
::
StructBuilder
builder
;
inline
Builder
(
const
SchemaPool
*
pool
,
schema
::
Node
::
Reader
schema
,
internal
::
StructBuilder
builder
)
:
pool
(
pool
),
schema
(
schema
),
builder
(
builder
)
{}
static
DynamicValue
::
Builder
getFieldImpl
(
const
SchemaPool
*
pool
,
internal
::
StructBuilder
builder
,
schema
::
StructNode
::
Field
::
Reader
field
);
static
void
setFieldImpl
(
const
SchemaPool
*
pool
,
internal
::
StructBuilder
builder
,
schema
::
StructNode
::
Field
::
Reader
field
,
DynamicValue
::
Reader
value
);
static
DynamicList
::
Builder
initListFieldImpl
(
const
SchemaPool
*
pool
,
internal
::
StructBuilder
builder
,
schema
::
StructNode
::
Field
::
Reader
field
,
uint
length
);
static
DynamicStruct
::
Builder
initStructFieldImpl
(
const
SchemaPool
*
pool
,
internal
::
StructBuilder
builder
,
schema
::
StructNode
::
Field
::
Reader
field
);
template
<
typename
T
>
friend
struct
internal
::
PointerHelpers
;
friend
class
DynamicUnion
::
Builder
;
friend
class
DynamicObject
;
};
// -------------------------------------------------------------------
class
DynamicList
::
Reader
{
public
:
Reader
()
=
default
;
inline
explicit
Reader
(
internal
::
ListReader
reader
)
:
reader
(
reader
)
{}
template
<
typename
T
>
typename
T
::
Reader
to
();
// Try to convert to any List<T>, Data, or Text. Throws an exception if the underlying data
// can't possibly represent the requested type.
inline
uint
size
()
{
return
reader
.
size
()
/
ELEMENTS
;
}
DynamicValue
::
Reader
operator
[](
uint
index
);
typedef
internal
::
IndexingIterator
<
Reader
,
DynamicValue
::
Reader
>
iterator
;
inline
iterator
begin
()
{
return
iterator
(
this
,
0
);
}
inline
iterator
end
()
{
return
iterator
(
this
,
size
());
}
private
:
const
SchemaPool
*
pool
;
// We don't encode the element type as schema::Type::Reader because we want to be able to
// construct DynamicList from List<T> without knowing of any particular field that has type
// List<T>, and we don't want to construct a fresh schema object every time this happens.
schema
::
Type
::
Body
::
Which
elementType
;
// cannot be list
uint
depth
;
// Number of types elementType must be wrapped in List() to get the actual element type, e.g.
// List(List(List(Bool))) has depth = 2.
schema
::
Node
::
Body
::
Reader
elementSchema
;
// if elementType is struct/enum/interface
internal
::
ListReader
reader
;
Reader
(
const
SchemaPool
*
pool
,
schema
::
Type
::
Reader
elementType
,
internal
::
ListReader
reader
);
Reader
(
const
SchemaPool
*
pool
,
internal
::
ListSchema
schema
,
internal
::
ListReader
reader
);
friend
class
DynamicStruct
;
friend
class
DynamicObject
;
};
class
DynamicList
::
Builder
{
public
:
Builder
()
=
default
;
inline
explicit
Builder
(
internal
::
ListBuilder
builder
)
:
builder
(
builder
)
{}
template
<
typename
T
>
typename
T
::
Builder
to
();
// Try to convert to any List<T>, Data, or Text. Throws an exception if the underlying data
// can't possibly represent the requested type.
inline
uint
size
()
{
return
builder
.
size
()
/
ELEMENTS
;
}
DynamicStruct
::
Builder
operator
[](
uint
index
);
typedef
internal
::
IndexingIterator
<
Builder
,
DynamicStruct
::
Builder
>
iterator
;
inline
iterator
begin
()
{
return
iterator
(
this
,
0
);
}
inline
iterator
end
()
{
return
iterator
(
this
,
size
());
}
void
copyFrom
(
Reader
other
);
Reader
asReader
();
private
:
const
SchemaPool
*
pool
;
schema
::
Type
::
Body
::
Which
elementType
;
uint
depth
;
schema
::
Node
::
Body
::
Reader
elementSchema
;
internal
::
ListBuilder
builder
;
Builder
(
const
SchemaPool
*
pool
,
schema
::
Type
::
Reader
elementType
,
internal
::
ListBuilder
builder
);
Builder
(
const
SchemaPool
*
pool
,
internal
::
ListSchema
schema
,
internal
::
ListBuilder
builder
);
friend
class
DynamicStruct
;
friend
class
DynamicObject
;
};
// -------------------------------------------------------------------
namespace
internal
{
// Make sure ReaderFor<T> and BuilderFor<T> work for DynamicEnum, DynamicObject, DynamicStruct, and
// DynamicList, so that we can define DynamicValue::to().
template
<>
struct
MaybeReaderBuilder
<
DynamicEnum
,
Kind
::
UNKNOWN
>
{
typedef
DynamicEnum
Reader
;
typedef
DynamicEnum
Builder
;
};
template
<>
struct
MaybeReaderBuilder
<
DynamicObject
,
Kind
::
UNKNOWN
>
{
typedef
DynamicObject
::
Reader
Reader
;
typedef
DynamicObject
::
Builder
Builder
;
};
template
<>
struct
MaybeReaderBuilder
<
DynamicStruct
,
Kind
::
UNKNOWN
>
{
typedef
DynamicStruct
::
Reader
Reader
;
typedef
DynamicStruct
::
Builder
Builder
;
};
template
<>
struct
MaybeReaderBuilder
<
DynamicList
,
Kind
::
UNKNOWN
>
{
typedef
DynamicList
::
Reader
Reader
;
typedef
DynamicList
::
Builder
Builder
;
};
}
// namespace internal
class
DynamicValue
::
Reader
{
public
:
inline
Reader
()
{}
inline
Reader
(
Void
voidValue
);
inline
Reader
(
bool
boolValue
);
inline
Reader
(
int8_t
int8Value
);
inline
Reader
(
int16_t
int16Value
);
inline
Reader
(
int32_t
int32Value
);
inline
Reader
(
int64_t
int64Value
);
inline
Reader
(
uint8_t
uint8Value
);
inline
Reader
(
uint16_t
uint16Value
);
inline
Reader
(
uint32_t
uint32Value
);
inline
Reader
(
uint64_t
uint64Value
);
inline
Reader
(
float
float32Value
);
inline
Reader
(
double
float64Value
);
inline
Reader
(
Text
::
Reader
textValue
);
inline
Reader
(
Data
::
Reader
dataValue
);
inline
Reader
(
DynamicList
::
Reader
listValue
);
inline
Reader
(
DynamicEnum
enumValue
);
inline
Reader
(
DynamicStruct
::
Reader
structValue
);
inline
Reader
(
DynamicObject
::
Reader
objectValue
);
template
<
typename
T
>
inline
ReaderFor
<
T
>
to
()
{
return
ToImpl
<
T
>::
apply
(
*
this
);
}
// Use to interpret the value as some type. Allowed types are:
// - Void, bool, [u]int{8,16,32,64}_t, float, double, any enum: Returns the raw value.
// - Text, Data, any struct type: Returns the corresponding Reader.
// - List<T> for any T listed above: Returns List<T>::Reader.
// - DynamicEnum: Returns DynamicEnum.
// - DynamicStruct, DynamicList, DynamicObject: Returns the corresponding Reader.
// If the requested type does not match the underlying data, the result is unspecified: it may
// throw an exception, it may return a garbage value, or it may return a composite value that
// when traversed throws exceptions or returns garbage values. Under none of these
// circumstances will the program crash.
inline
schema
::
Type
::
Body
::
Which
getType
()
{
return
type
;
}
// Get the type of this value.
private
:
schema
::
Type
::
Body
::
Which
type
;
union
{
Void
voidValue
;
bool
boolValue
;
int8_t
int8Value
;
int16_t
int16Value
;
int32_t
int32Value
;
int64_t
int64Value
;
uint8_t
uint8Value
;
uint16_t
uint16Value
;
uint32_t
uint32Value
;
uint64_t
uint64Value
;
float
float32Value
;
double
float64Value
;
Text
::
Reader
textValue
;
Data
::
Reader
dataValue
;
DynamicList
::
Reader
listValue
;
DynamicEnum
enumValue
;
DynamicStruct
::
Reader
structValue
;
DynamicObject
::
Reader
objectValue
;
};
template
<
typename
T
,
Kind
kind
=
kind
<
T
>
()
>
struct
ToImpl
;
// Implementation backing the to() method. Needs to be a struct to allow partial
// specialization. Has a method apply() which does the work.
};
class
DynamicValue
::
Builder
{
public
:
inline
Builder
()
{}
inline
Builder
(
Void
voidValue
);
inline
Builder
(
bool
boolValue
);
inline
Builder
(
int8_t
int8Value
);
inline
Builder
(
int16_t
int16Value
);
inline
Builder
(
int32_t
int32Value
);
inline
Builder
(
int64_t
int64Value
);
inline
Builder
(
uint8_t
uint8Value
);
inline
Builder
(
uint16_t
uint16Value
);
inline
Builder
(
uint32_t
uint32Value
);
inline
Builder
(
uint64_t
uint64Value
);
inline
Builder
(
float
float32Value
);
inline
Builder
(
double
float64Value
);
inline
Builder
(
Text
::
Builder
textValue
);
inline
Builder
(
Data
::
Builder
dataValue
);
inline
Builder
(
DynamicList
::
Builder
listValue
);
inline
Builder
(
DynamicEnum
enumValue
);
inline
Builder
(
DynamicStruct
::
Builder
structValue
);
inline
Builder
(
DynamicObject
::
Builder
objectValue
);
template
<
typename
T
>
inline
BuilderFor
<
T
>
to
()
{
return
ToImpl
<
T
>::
apply
(
*
this
);
}
// See DynamicValue::Reader::to().
inline
schema
::
Type
::
Body
::
Which
getType
()
{
return
type
;
}
// Get the type of this value.
Reader
asReader
();
private
:
schema
::
Type
::
Body
::
Which
type
;
union
{
Void
voidValue
;
bool
boolValue
;
int8_t
int8Value
;
int16_t
int16Value
;
int32_t
int32Value
;
int64_t
int64Value
;
uint8_t
uint8Value
;
uint16_t
uint16Value
;
uint32_t
uint32Value
;
uint64_t
uint64Value
;
float
float32Value
;
double
float64Value
;
Text
::
Builder
textValue
;
Data
::
Builder
dataValue
;
DynamicList
::
Builder
listValue
;
DynamicEnum
enumValue
;
DynamicStruct
::
Builder
structValue
;
DynamicObject
::
Builder
objectValue
;
};
template
<
typename
T
,
Kind
kind
=
kind
<
T
>
()
>
struct
ToImpl
;
// Implementation backing the to() method. Needs to be a struct to allow partial
// specialization. Has a method apply() which does the work.
};
// =======================================================================================
// Implementation details.
#define CAPNPROTO_DECLARE_TYPE(name, discrim, typeName) \
inline DynamicValue::Reader::Reader(ReaderFor<typeName> name##Value) \
: type(schema::Type::Body::discrim##_TYPE), name##Value(name##Value) {} \
inline DynamicValue::Builder::Builder(BuilderFor<typeName> name##Value) \
: type(schema::Type::Body::discrim##_TYPE), name##Value(name##Value) {} \
template <> \
struct DynamicValue::Reader::ToImpl<typeName> { \
static ReaderFor<typeName> apply(Reader reader); \
}; \
template <> \
struct DynamicValue::Builder::ToImpl<typeName> { \
static BuilderFor<typeName> apply(Builder builder); \
};
//CAPNPROTO_DECLARE_TYPE(void, VOID, Void)
CAPNPROTO_DECLARE_TYPE
(
bool
,
BOOL
,
bool
)
CAPNPROTO_DECLARE_TYPE
(
int8
,
INT8
,
int8_t
)
CAPNPROTO_DECLARE_TYPE
(
int16
,
INT16
,
int16_t
)
CAPNPROTO_DECLARE_TYPE
(
int32
,
INT32
,
int32_t
)
CAPNPROTO_DECLARE_TYPE
(
int64
,
INT64
,
int64_t
)
CAPNPROTO_DECLARE_TYPE
(
uint8
,
UINT8
,
uint8_t
)
CAPNPROTO_DECLARE_TYPE
(
uint16
,
UINT16
,
uint16_t
)
CAPNPROTO_DECLARE_TYPE
(
uint32
,
UINT32
,
uint32_t
)
CAPNPROTO_DECLARE_TYPE
(
uint64
,
UINT64
,
uint64_t
)
CAPNPROTO_DECLARE_TYPE
(
float32
,
FLOAT32
,
float
)
CAPNPROTO_DECLARE_TYPE
(
float64
,
FLOAT64
,
double
)
CAPNPROTO_DECLARE_TYPE
(
text
,
TEXT
,
Text
)
CAPNPROTO_DECLARE_TYPE
(
data
,
DATA
,
Data
)
CAPNPROTO_DECLARE_TYPE
(
list
,
LIST
,
DynamicList
)
CAPNPROTO_DECLARE_TYPE
(
struct
,
STRUCT
,
DynamicStruct
)
CAPNPROTO_DECLARE_TYPE
(
enum
,
ENUM
,
DynamicEnum
)
CAPNPROTO_DECLARE_TYPE
(
object
,
OBJECT
,
DynamicObject
)
#undef CAPNPROTO_DECLARE_TYPE
// CAPNPROTO_DECLARE_TYPE(Void) causes gcc 4.7 to segfault. If I do it manually and remove the
// ReaderFor<> and BuilderFor<> wrappers, it works.
inline
DynamicValue
::
Reader
::
Reader
(
Void
voidValue
)
\
:
type
(
schema
::
Type
::
Body
::
VOID_TYPE
),
voidValue
(
voidValue
)
{}
\
inline
DynamicValue
::
Builder
::
Builder
(
Void
voidValue
)
\
:
type
(
schema
::
Type
::
Body
::
VOID_TYPE
),
voidValue
(
voidValue
)
{}
\
template
<>
struct
DynamicValue
::
Reader
::
ToImpl
<
Void
>
{
static
Void
apply
(
Reader
reader
);
};
template
<>
struct
DynamicValue
::
Builder
::
ToImpl
<
Void
>
{
static
Void
apply
(
Builder
builder
);
};
template
<
typename
T
>
struct
DynamicValue
::
Reader
::
ToImpl
<
T
,
Kind
::
ENUM
>
{
static
T
apply
(
Reader
reader
)
{
return
reader
.
to
<
DynamicEnum
>
().
to
<
T
>
();
}
};
template
<
typename
T
>
struct
DynamicValue
::
Builder
::
ToImpl
<
T
,
Kind
::
ENUM
>
{
static
T
apply
(
Builder
builder
)
{
return
builder
.
to
<
DynamicEnum
>
().
to
<
T
>
();
}
};
template
<
typename
T
>
struct
DynamicValue
::
Reader
::
ToImpl
<
T
,
Kind
::
STRUCT
>
{
static
T
apply
(
Reader
reader
)
{
return
reader
.
to
<
DynamicStruct
>
().
to
<
T
>
();
}
};
template
<
typename
T
>
struct
DynamicValue
::
Builder
::
ToImpl
<
T
,
Kind
::
STRUCT
>
{
static
T
apply
(
Builder
builder
)
{
return
builder
.
to
<
DynamicStruct
>
().
to
<
T
>
();
}
};
template
<
typename
T
>
struct
DynamicValue
::
Reader
::
ToImpl
<
T
,
Kind
::
LIST
>
{
static
T
apply
(
Reader
reader
)
{
return
reader
.
to
<
DynamicList
>
().
to
<
T
>
();
}
};
template
<
typename
T
>
struct
DynamicValue
::
Builder
::
ToImpl
<
T
,
Kind
::
LIST
>
{
static
T
apply
(
Builder
builder
)
{
return
builder
.
to
<
DynamicList
>
().
to
<
T
>
();
}
};
// -------------------------------------------------------------------
template
<
typename
T
>
struct
DynamicObject
::
Reader
::
ToImpl
<
T
,
Kind
::
STRUCT
>
{
static
T
apply
(
Reader
reader
)
{
return
reader
.
toStruct
(
typeId
<
T
>
()).
to
<
T
>
();
}
};
template
<
typename
T
>
struct
DynamicObject
::
Builder
::
ToImpl
<
T
,
Kind
::
STRUCT
>
{
static
T
apply
(
Builder
builder
)
{
return
builder
.
toStruct
(
typeId
<
T
>
()).
to
<
T
>
();
}
};
template
<
typename
T
>
struct
DynamicObject
::
Reader
::
ToImpl
<
List
<
T
>
,
Kind
::
LIST
>
{
static
T
apply
(
Reader
reader
)
{
return
reader
.
toList
(
internal
::
ListSchemaFor
<
T
>::
schema
).
to
<
T
>
();
}
};
template
<
typename
T
>
struct
DynamicObject
::
Builder
::
ToImpl
<
List
<
T
>
,
Kind
::
LIST
>
{
static
T
apply
(
Builder
builder
)
{
return
builder
.
toList
(
internal
::
ListSchemaFor
<
T
>::
schema
).
to
<
T
>
();
}
};
}
// namespace capnproto
#endif // CAPNPROTO_DYNAMIC_H_
c++/src/capnproto/generated-header-support.h
View file @
18cfa132
...
...
@@ -33,6 +33,11 @@ namespace capnproto {
class
DynamicStruct
;
// So that it can be declared a friend.
template
<
typename
T
>
inline
constexpr
uint64_t
typeId
();
// typeId<MyType>() returns the type ID as defined in the schema. Works with structs, enums, and
// interfaces.
namespace
internal
{
template
<
typename
T
>
...
...
@@ -118,18 +123,26 @@ struct PointerHelpers<TrustedMessage> {
#endif
struct
RawSchema
{
const
word
*
encodedNode
;
const
RawSchema
*
dependencies
;
};
template
<
typename
T
>
inline
constexpr
const
RawSchema
&
rawSchema
();
}
// namespace internal
}
// namespace capnproto
#define CAPNPROTO_DECLARE_ENUM(type) \
#define CAPNPROTO_DECLARE_ENUM(type
, id
) \
template <> struct KindOf<type> { static constexpr Kind kind = Kind::ENUM; }
#define CAPNPROTO_DECLARE_STRUCT(type, dataWordSize, pointerCount, preferredElementEncoding) \
#define CAPNPROTO_DECLARE_STRUCT(type,
id,
dataWordSize, pointerCount, preferredElementEncoding) \
template <> struct KindOf<type> { static constexpr Kind kind = Kind::STRUCT; }; \
template <> struct StructSizeFor<type> { \
static constexpr StructSize value = StructSize( \
dataWordSize * WORDS, pointerCount * REFERENCES, FieldSize::preferredElementEncoding); \
}
#define CAPNPROTO_DECLARE_INTERFACE(type) \
#define CAPNPROTO_DECLARE_INTERFACE(type
, id
) \
template <> struct KindOf<type> { static constexpr Kind kind = Kind::INTERFACE; }
#endif // CAPNPROTO_GENERATED_HEADER_SUPPORT_H_
compiler/src/CxxGenerator.hs
View file @
18cfa132
...
...
@@ -265,6 +265,7 @@ enumerantContext parent desc = mkStrContext context where
enumContext
parent
desc
=
mkStrContext
context
where
context
"enumName"
=
MuVariable
$
enumName
desc
context
"enumId"
=
MuVariable
(
printf
"0x%16x"
(
enumId
desc
)
::
String
)
context
"enumerants"
=
MuList
$
map
(
enumerantContext
context
)
$
enumerants
desc
context
s
=
parent
s
...
...
@@ -383,6 +384,7 @@ structContext parent desc = mkStrContext context where
context
"typeFields"
=
context
"structFields"
context
"structName"
=
MuVariable
$
structName
desc
context
"structId"
=
MuVariable
(
printf
"0x%16x"
(
structId
desc
)
::
String
)
context
"structFullName"
=
MuVariable
$
fullName
(
DescStruct
desc
)
context
"structFields"
=
MuList
$
map
(
fieldContext
context
)
$
structFields
desc
context
"structUnions"
=
MuList
$
map
(
unionContext
context
)
$
structUnions
desc
...
...
compiler/src/c++-header.mustache
View file @
18cfa132
...
...
@@ -105,16 +105,18 @@ namespace internal {
{{#
typeStructOrUnion
}}
{{#
typeStruct
}}
CAPNPROTO_DECLARE_STRUCT(
::
{{#
fileNamespaces
}}{{
namespaceName
}}
::
{{/
fileNamespaces
}}{{
typeFullName
}}
,
::
{{#
fileNamespaces
}}{{
namespaceName
}}
::
{{/
fileNamespaces
}}{{
typeFullName
}}
,
{{
structId
}}
,
{{
structDataSize
}}
,
{{
structReferenceCount
}}
,
{{
structPreferredListEncoding
}}
);
{{#
structNestedEnums
}}
CAPNPROTO_DECLARE_ENUM(::
{{#
fileNamespaces
}}{{
namespaceName
}}
::
{{/
fileNamespaces
}}{{
typeFullName
}}
::
{{
enumName
}}
);
CAPNPROTO_DECLARE_ENUM(
::
{{#
fileNamespaces
}}{{
namespaceName
}}
::
{{/
fileNamespaces
}}{{
typeFullName
}}
::
{{
enumName
}}
,
{{
enumId
}}
);
{{/
structNestedEnums
}}
{{/
typeStruct
}}
{{/
typeStructOrUnion
}}
{{/
fileTypes
}}
{{#
fileEnums
}}
CAPNPROTO_DECLARE_ENUM(::
{{#
fileNamespaces
}}{{
namespaceName
}}
::
{{/
fileNamespaces
}}{{
enumName
}}
);
CAPNPROTO_DECLARE_ENUM(
::
{{#
fileNamespaces
}}{{
namespaceName
}}
::
{{/
fileNamespaces
}}{{
enumName
}}
,
{{
enumId
}}
);
{{/
fileEnums
}}
} // namespace capnproto
} // namespace internal
...
...
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