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
d07bf3b8
Commit
d07bf3b8
authored
Sep 29, 2013
by
Kenton Varda
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
More capabilities core API WIP.
parent
398dac0d
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
644 additions
and
158 deletions
+644
-158
arena.c++
c++/src/capnp/arena.c++
+60
-6
arena.h
c++/src/capnp/arena.h
+16
-5
capability-context.c++
c++/src/capnp/capability-context.c++
+64
-0
capability-context.h
c++/src/capnp/capability-context.h
+158
-0
capability.c++
c++/src/capnp/capability.c++
+5
-6
capability.h
c++/src/capnp/capability.h
+267
-132
layout.c++
c++/src/capnp/layout.c++
+16
-0
layout.h
c++/src/capnp/layout.h
+19
-4
object.h
c++/src/capnp/object.h
+34
-0
rpc.capnp
c++/src/capnp/rpc.capnp
+5
-5
No files found.
c++/src/capnp/arena.c++
View file @
d07bf3b8
...
...
@@ -24,10 +24,13 @@
#define CAPNP_PRIVATE
#include "arena.h"
#include "message.h"
#include "capability.h"
#include <kj/debug.h>
#include <vector>
#include <string.h>
#include <stdio.h>
#include "capability.h"
#include "capability-context.h"
namespace
capnp
{
namespace
_
{
// private
...
...
@@ -99,10 +102,42 @@ void BasicReaderArena::reportReadLimitReached() {
}
}
namespace
{
class
DummyClientHook
final
:
public
ClientHook
{
public
:
Request
<
ObjectPointer
,
TypelessAnswer
>
newCall
(
uint64_t
interfaceId
,
uint16_t
methodId
)
const
override
{
KJ_FAIL_REQUIRE
(
"Calling capability that was extracted from a message that had no "
"capability context."
);
}
kj
::
Promise
<
void
>
whenResolved
()
const
override
{
return
kj
::
READY_NOW
;
}
kj
::
Own
<
ClientHook
>
addRef
()
const
override
{
return
kj
::
heap
<
DummyClientHook
>
();
}
void
*
getBrand
()
const
override
{
return
nullptr
;
}
};
}
// namespace
kj
::
Own
<
ClientHook
>
BasicReaderArena
::
extractCap
(
const
_
::
StructReader
&
capDescriptor
)
{
KJ_FAIL_REQUIRE
(
"Message contained a capability but is not imbued with a capability context."
)
{
return
kj
::
heap
<
DummyClientHook
>
();
}
}
// =======================================================================================
ImbuedReaderArena
::
ImbuedReaderArena
(
Arena
*
base
)
:
base
(
base
),
segment0
(
nullptr
,
SegmentId
(
0
),
nullptr
,
nullptr
)
{}
ImbuedReaderArena
::
ImbuedReaderArena
(
Arena
*
base
,
CapExtractorBase
*
capExtractor
)
:
base
(
base
),
capExtractor
(
capExtractor
),
segment0
(
nullptr
,
SegmentId
(
0
),
nullptr
,
nullptr
)
{}
ImbuedReaderArena
::~
ImbuedReaderArena
()
noexcept
(
false
)
{}
SegmentReader
*
ImbuedReaderArena
::
imbue
(
SegmentReader
*
baseSegment
)
{
...
...
@@ -139,8 +174,6 @@ SegmentReader* ImbuedReaderArena::imbue(SegmentReader* baseSegment) {
return
result
;
}
// implements Arena ------------------------------------------------
SegmentReader
*
ImbuedReaderArena
::
tryGetSegment
(
SegmentId
id
)
{
return
imbue
(
base
->
tryGetSegment
(
id
));
}
...
...
@@ -149,6 +182,10 @@ void ImbuedReaderArena::reportReadLimitReached() {
return
base
->
reportReadLimitReached
();
}
kj
::
Own
<
ClientHook
>
ImbuedReaderArena
::
extractCap
(
const
_
::
StructReader
&
capDescriptor
)
{
return
capExtractor
->
extractCapInternal
(
capDescriptor
);
}
// =======================================================================================
BasicBuilderArena
::
BasicBuilderArena
(
MessageBuilder
*
message
)
...
...
@@ -288,10 +325,19 @@ void BasicBuilderArena::reportReadLimitReached() {
}
}
kj
::
Own
<
ClientHook
>
BasicBuilderArena
::
extractCap
(
const
_
::
StructReader
&
capDescriptor
)
{
KJ_FAIL_REQUIRE
(
"Message contains no capabilities."
);
}
void
BasicBuilderArena
::
injectCap
(
_
::
PointerBuilder
pointer
,
kj
::
Own
<
ClientHook
>&&
cap
)
{
KJ_FAIL_REQUIRE
(
"Cannot inject capability into a builder that has not been imbued with a "
"capability context."
);
}
// =======================================================================================
ImbuedBuilderArena
::
ImbuedBuilderArena
(
BuilderArena
*
base
)
:
base
(
base
),
segment0
(
nullptr
)
{}
ImbuedBuilderArena
::
ImbuedBuilderArena
(
BuilderArena
*
base
,
CapInjectorBase
*
capInjector
)
:
base
(
base
),
capInjector
(
capInjector
),
segment0
(
nullptr
)
{}
ImbuedBuilderArena
::~
ImbuedBuilderArena
()
noexcept
(
false
)
{}
SegmentBuilder
*
ImbuedBuilderArena
::
imbue
(
SegmentBuilder
*
baseSegment
)
{
...
...
@@ -334,6 +380,10 @@ void ImbuedBuilderArena::reportReadLimitReached() {
base
->
reportReadLimitReached
();
}
kj
::
Own
<
ClientHook
>
ImbuedBuilderArena
::
extractCap
(
const
_
::
StructReader
&
capDescriptor
)
{
return
capInjector
->
getInjectedCapInternal
(
capDescriptor
);
}
SegmentBuilder
*
ImbuedBuilderArena
::
getSegment
(
SegmentId
id
)
{
return
imbue
(
base
->
getSegment
(
id
));
}
...
...
@@ -344,5 +394,9 @@ BuilderArena::AllocateResult ImbuedBuilderArena::allocate(WordCount amount) {
return
result
;
}
void
ImbuedBuilderArena
::
injectCap
(
_
::
PointerBuilder
pointer
,
kj
::
Own
<
ClientHook
>&&
cap
)
{
return
capInjector
->
injectCapInternal
(
pointer
,
kj
::
mv
(
cap
));
}
}
// namespace _ (private)
}
// namespace capnp
c++/src/capnp/arena.h
View file @
d07bf3b8
...
...
@@ -34,10 +34,13 @@
#include <kj/mutex.h>
#include "common.h"
#include "message.h"
#include "layout.h"
namespace
capnp
{
class
TypelessCapability
;
class
CapExtractorBase
;
class
CapInjectorBase
;
class
ClientHook
;
namespace
_
{
// private
...
...
@@ -182,7 +185,7 @@ public:
// the VALIDATE_INPUT() macro which may throw an exception; if it return normally, the caller
// will need to continue with default values.
virtual
kj
::
Own
<
TypelessCapability
>
extractCap
(
const
_
::
StructReader
&
capDescriptor
)
;
virtual
kj
::
Own
<
ClientHook
>
extractCap
(
const
_
::
StructReader
&
capDescriptor
)
=
0
;
// Given a StructReader for a capability descriptor embedded in the message, return the
// corresponding capability.
};
...
...
@@ -196,6 +199,7 @@ public:
// implements Arena ------------------------------------------------
SegmentReader
*
tryGetSegment
(
SegmentId
id
)
override
;
void
reportReadLimitReached
()
override
;
kj
::
Own
<
ClientHook
>
extractCap
(
const
_
::
StructReader
&
capDescriptor
);
private
:
MessageReader
*
message
;
...
...
@@ -210,7 +214,7 @@ private:
class
ImbuedReaderArena
final
:
public
Arena
{
public
:
ImbuedReaderArena
(
Arena
*
base
);
ImbuedReaderArena
(
Arena
*
base
,
CapExtractorBase
*
capExtractor
);
~
ImbuedReaderArena
()
noexcept
(
false
);
KJ_DISALLOW_COPY
(
ImbuedReaderArena
);
...
...
@@ -219,9 +223,11 @@ public:
// implements Arena ------------------------------------------------
SegmentReader
*
tryGetSegment
(
SegmentId
id
)
override
;
void
reportReadLimitReached
()
override
;
kj
::
Own
<
ClientHook
>
extractCap
(
const
_
::
StructReader
&
capDescriptor
);
private
:
Arena
*
base
;
CapExtractorBase
*
capExtractor
;
// Optimize for single-segment messages so that small messages are handled quickly.
SegmentReader
segment0
;
...
...
@@ -248,7 +254,7 @@ public:
// the arena is guaranteed to succeed. Therefore callers should try to allocate from a specific
// segment first if there is one, then fall back to the arena.
virtual
void
injectCap
(
_
::
PointerBuilder
pointer
,
kj
::
Own
<
TypelessCapability
>&&
cap
)
=
0
;
virtual
void
injectCap
(
_
::
PointerBuilder
pointer
,
kj
::
Own
<
ClientHook
>&&
cap
)
=
0
;
// Add the capability to the message and initialize the given pointer as an interface pointer
// pointing to this cap.
};
...
...
@@ -271,10 +277,12 @@ public:
// implements Arena ------------------------------------------------
SegmentReader
*
tryGetSegment
(
SegmentId
id
)
override
;
void
reportReadLimitReached
()
override
;
kj
::
Own
<
ClientHook
>
extractCap
(
const
_
::
StructReader
&
capDescriptor
);
// implements BuilderArena -----------------------------------------
SegmentBuilder
*
getSegment
(
SegmentId
id
)
override
;
AllocateResult
allocate
(
WordCount
amount
)
override
;
void
injectCap
(
_
::
PointerBuilder
pointer
,
kj
::
Own
<
ClientHook
>&&
cap
);
private
:
MessageBuilder
*
message
;
...
...
@@ -294,7 +302,7 @@ class ImbuedBuilderArena final: public BuilderArena {
// A BuilderArena imbued with the ability to inject capabilities.
public
:
ImbuedBuilderArena
(
BuilderArena
*
base
);
ImbuedBuilderArena
(
BuilderArena
*
base
,
CapInjectorBase
*
capInjector
);
~
ImbuedBuilderArena
()
noexcept
(
false
);
KJ_DISALLOW_COPY
(
ImbuedBuilderArena
);
...
...
@@ -304,13 +312,16 @@ public:
// implements Arena ------------------------------------------------
SegmentReader
*
tryGetSegment
(
SegmentId
id
)
override
;
void
reportReadLimitReached
()
override
;
kj
::
Own
<
ClientHook
>
extractCap
(
const
_
::
StructReader
&
capDescriptor
);
// implements BuilderArena -----------------------------------------
SegmentBuilder
*
getSegment
(
SegmentId
id
)
override
;
AllocateResult
allocate
(
WordCount
amount
)
override
;
void
injectCap
(
_
::
PointerBuilder
pointer
,
kj
::
Own
<
ClientHook
>&&
cap
);
private
:
BuilderArena
*
base
;
CapInjectorBase
*
capInjector
;
ImbuedSegmentBuilder
segment0
;
...
...
c++/src/capnp/capability-context.c++
0 → 100644
View file @
d07bf3b8
// 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 CAPNP_PRIVATE
#include "capability-context.h"
#include "arena.h"
#include <kj/debug.h>
namespace
capnp
{
CapReaderContext
::
CapReaderContext
(
CapExtractorBase
&
extractor
)
:
extractor
(
&
extractor
)
{}
CapReaderContext
::~
CapReaderContext
()
noexcept
(
false
)
{
if
(
extractor
==
nullptr
)
{
kj
::
dtor
(
arena
());
}
}
ObjectPointer
::
Reader
CapReaderContext
::
imbue
(
ObjectPointer
::
Reader
base
)
{
KJ_REQUIRE
(
extractor
!=
nullptr
,
"imbue() can only be called once."
);
KJ_IF_MAYBE
(
oldArena
,
base
.
reader
.
getArena
())
{
kj
::
ctor
(
arena
(),
oldArena
,
extractor
);
}
else
{
KJ_FAIL_REQUIRE
(
"Cannot imbue unchecked message."
);
}
extractor
=
nullptr
;
return
ObjectPointer
::
Reader
(
base
.
reader
.
imbue
(
arena
()));
}
CapBuilderContext
::
CapBuilderContext
(
CapInjectorBase
&
injector
)
:
injector
(
&
injector
)
{}
CapBuilderContext
::~
CapBuilderContext
()
noexcept
(
false
)
{
if
(
injector
==
nullptr
)
{
kj
::
dtor
(
arena
());
}
}
ObjectPointer
::
Builder
CapBuilderContext
::
imbue
(
ObjectPointer
::
Builder
base
)
{
KJ_REQUIRE
(
injector
!=
nullptr
,
"imbue() can only be called once."
);
kj
::
ctor
(
arena
(),
&
base
.
builder
.
getArena
(),
injector
);
injector
=
nullptr
;
return
ObjectPointer
::
Builder
(
base
.
builder
.
imbue
(
arena
()));
}
}
// namespace capnp
c++/src/capnp/capability-context.h
0 → 100644
View file @
d07bf3b8
// 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.
// Classes for imbuing message readers/builders with a capability context.
//
// These classes are for use by RPC implementations. Application code need not know about them.
//
// Normally, MessageReader and MessageBuilder do not support interface pointers because they
// are not RPC-aware and so have no idea how to convert between a serialized CapabilityDescriptor
// and a live capability. To fix this, a reader/builder object needs to be "imbued" with a
// capability context. This creates a new reader/builder which points at the same object but has
// the ability to deal with interface fields. Use `CapReaderContext` and `CapBuilderContext` to
// accomplish this.
#ifndef CAPNP_CAPABILITY_CONTEXT_H_
#define CAPNP_CAPABILITY_CONTEXT_H_
#include "layout.h"
#include "object.h"
#include <kj/mutex.h>
namespace
capnp
{
class
ClientHook
;
namespace
_
{
// private
class
ImbuedReaderArena
;
class
ImbuedBuilderArena
;
}
// namespace _ (private)
class
CapExtractorBase
{
// Non-template base class for CapExtractor<T>.
private
:
virtual
kj
::
Own
<
ClientHook
>
extractCapInternal
(
const
_
::
StructReader
&
capDescriptor
)
=
0
;
friend
class
_
::
ImbuedReaderArena
;
};
class
CapInjectorBase
{
// Non-template base class for CapInjector<T>.
private
:
virtual
void
injectCapInternal
(
_
::
PointerBuilder
builder
,
kj
::
Own
<
ClientHook
>&&
cap
)
=
0
;
virtual
kj
::
Own
<
ClientHook
>
getInjectedCapInternal
(
const
_
::
StructReader
&
capDescriptor
)
=
0
;
friend
class
_
::
ImbuedBuilderArena
;
};
template
<
typename
CapDescriptor
>
class
CapExtractor
:
public
CapExtractorBase
{
// Callback used to read a capability from a message, implemented by the RPC system.
// `CapDescriptor` is the struct type which the RPC implementation uses to represent
// capabilities. (On the wire, an interface pointer actually points to a struct of this type.)
public
:
virtual
kj
::
Own
<
ClientHook
>
extractCap
(
typename
CapDescriptor
::
Reader
descriptor
)
=
0
;
// Given the descriptor read off the wire, construct a live capability.
private
:
kj
::
Own
<
ClientHook
>
extractCapInternal
(
const
_
::
StructReader
&
capDescriptor
)
override
final
{
return
extractCap
(
typename
CapDescriptor
::
Reader
(
capDescriptor
));
}
};
template
<
typename
CapDescriptor
>
class
CapInjector
:
public
CapInjectorBase
{
// Callback used to write a capability into a message, implemented by the RPC system.
// `CapDescriptor` is the struct type which the RPC implementation uses to represent
// capabilities. (On the wire, an interface pointer actually points to a struct of this type.)
public
:
virtual
void
injectCap
(
typename
CapDescriptor
::
Builder
descriptor
,
kj
::
Own
<
ClientHook
>&&
cap
)
=
0
;
// Fill in the given descriptor so that it describes the given capability.
virtual
kj
::
Own
<
ClientHook
>
getInjectedCap
(
typename
CapDescriptor
::
Reader
descriptor
)
=
0
;
// Read back a cap that was previously injected with `injectCap`. This should return a new
// reference.
private
:
void
injectCapInternal
(
_
::
PointerBuilder
builder
,
kj
::
Own
<
ClientHook
>&&
cap
)
override
final
{
injectCap
(
typename
CapDescriptor
::
Builder
(
builder
.
initCapDescriptor
(
_
::
structSize
<
CapDescriptor
>
())),
kj
::
mv
(
cap
));
}
kj
::
Own
<
ClientHook
>
getInjectedCapInternal
(
const
_
::
StructReader
&
capDescriptor
)
{
return
getInjectedCap
(
typename
CapDescriptor
::
Reader
(
capDescriptor
));
}
};
// -------------------------------------------------------------------
class
CapReaderContext
{
// Class which can "imbue" reader objects from some other message with a capability context,
// so that interface pointers found in the message can be extracted and called.
//
// `imbue()` can only be called once per context.
public
:
CapReaderContext
(
CapExtractorBase
&
extractor
);
~
CapReaderContext
()
noexcept
(
false
);
ObjectPointer
::
Reader
imbue
(
ObjectPointer
::
Reader
base
);
private
:
CapExtractorBase
*
extractor
;
// becomes null once arena is allocated
void
*
arenaSpace
[
12
+
sizeof
(
kj
::
MutexGuarded
<
void
*>
)
/
sizeof
(
void
*
)];
_
::
ImbuedReaderArena
&
arena
()
{
return
*
reinterpret_cast
<
_
::
ImbuedReaderArena
*>
(
arenaSpace
);
}
friend
class
_
::
ImbuedReaderArena
;
};
class
CapBuilderContext
{
// Class which can "imbue" reader objects from some other message with a capability context,
// so that interface pointers found in the message can be set to point at live capabilities.
//
// `imbue()` can only be called once per context.
public
:
CapBuilderContext
(
CapInjectorBase
&
injector
);
~
CapBuilderContext
()
noexcept
(
false
);
ObjectPointer
::
Builder
imbue
(
ObjectPointer
::
Builder
base
);
private
:
CapInjectorBase
*
injector
;
// becomes null once arena is allocated
void
*
arenaSpace
[
12
+
sizeof
(
kj
::
MutexGuarded
<
void
*>
)
/
sizeof
(
void
*
)];
_
::
ImbuedBuilderArena
&
arena
()
{
return
*
reinterpret_cast
<
_
::
ImbuedBuilderArena
*>
(
arenaSpace
);
}
friend
class
_
::
ImbuedBuilderArena
;
};
}
// namespace capnp
#endif // CAPNP_CAPABILITY_CONTEXT_H_
c++/src/capnp/capability.c++
View file @
d07bf3b8
...
...
@@ -24,19 +24,18 @@
#include "capability.h"
namespace
capnp
{
namespace
_
{
// private
CallResult
::
Pipeline
CallResult
::
Pipeline
::
getPointerField
(
uint16_t
pointerIndex
)
const
{
auto
newOps
=
kj
::
heapArray
<
PipelineManager
::
Op
>
(
ops
.
size
()
+
1
);
TypelessAnswer
::
Pipeline
TypelessAnswer
::
Pipeline
::
getPointerField
(
uint16_t
pointerIndex
)
const
{
auto
newOps
=
kj
::
heapArray
<
PipelineOp
>
(
ops
.
size
()
+
1
);
for
(
auto
i
:
kj
::
indices
(
ops
))
{
newOps
[
i
]
=
ops
[
i
];
}
auto
&
newOp
=
newOps
[
ops
.
size
()];
newOp
.
type
=
Pipeline
Manager
::
Op
::
GET_POINTER_FIELD
;
newOp
.
type
=
PipelineOp
::
GET_POINTER_FIELD
;
newOp
.
pointerIndex
=
pointerIndex
;
return
Pipeline
(
call
->
addRef
(),
kj
::
mv
(
newOps
));
return
Pipeline
(
hook
->
addRef
(),
kj
::
mv
(
newOps
));
}
}
// namespace _ (private)
}
// namespace capnp
c++/src/capnp/capability.h
View file @
d07bf3b8
...
...
@@ -29,221 +29,356 @@
namespace
capnp
{
template
<
typename
Answer
>
class
Response
;
template
<
typename
T
>
class
RemotePromise
:
public
kj
::
Promise
<
kj
::
Own
<
ReaderFor
<
T
>>>
,
public
T
::
Pipeline
{
// A Promise which supports pipelined calls. T is typically a struct type.
class
RemotePromise
:
public
kj
::
Promise
<
Response
<
T
>>
,
public
T
::
Pipeline
{
// A Promise which supports pipelined calls. T is typically a struct type. T must declare
// an inner "mix-in" type "Pipeline" which implements pipelining; RemotePromise simply
// multiply-inherits that type along with Promise<Response<T>>. T::Pipeline must be movable,
// but does not need to be copyable (i.e. just like Promise<T>).
//
// The promise is for an owned pointer so that the RPC system can allocate the MessageReader
// itself.
public
:
inline
RemotePromise
(
kj
::
Promise
<
kj
::
Own
<
ReaderFor
<
T
>>>&&
promise
,
typename
T
::
Pipeline
&&
pipeline
)
:
kj
::
Promise
<
kj
::
Own
<
ReaderFor
<
T
>>>
(
kj
::
mv
(
promise
)),
inline
RemotePromise
(
kj
::
Promise
<
Response
<
T
>>&&
promise
,
typename
T
::
Pipeline
&&
pipeline
)
:
kj
::
Promise
<
Response
<
T
>>
(
kj
::
mv
(
promise
)),
T
::
Pipeline
(
kj
::
mv
(
pipeline
))
{}
inline
RemotePromise
(
decltype
(
nullptr
))
:
kj
::
Promise
<
kj
::
Own
<
ReaderFor
<
T
>
>>
(
nullptr
)
{}
:
kj
::
Promise
<
Response
<
T
>>
(
nullptr
)
{}
KJ_DISALLOW_COPY
(
RemotePromise
);
RemotePromise
(
RemotePromise
&&
other
)
=
default
;
RemotePromise
&
operator
=
(
RemotePromise
&&
other
)
=
default
;
};
struct
Capability
{
// A capability without type-safe methods. Typed capability clients wrap `Client` and typed
// capability servers subclass `Server` to dispatch to the regular, typed methods.
class
Client
;
class
Server
;
};
// =======================================================================================
class
Call
;
struct
CallResult
;
class
RequestHook
;
class
ResponseHook
;
class
PipelineHook
;
class
ClientHook
;
class
TypelessCapability
{
// This is an internal type used to represent a live capability (or a promise for a capability).
// This class should not be used directly by applications; it is intended to be used by the
// generated code wrappers.
template
<
typename
Params
,
typename
Answer
>
class
Request
:
public
Params
::
Builder
{
// A call that hasn't been sent yet. This class extends a Builder for the call's "Params"
// structure with a method send() that actually sends it.
//
// Given a Cap'n Proto method `foo(a :A, b :B): C`, the generated client interface will have
// a method `Request<FooParams, C> startFoo()` (as well as a convenience method
// `RemotePromise<C> foo(A::Reader a, B::Reader b)`).
public
:
virtual
kj
::
Own
<
Call
>
newCall
(
uint64_t
interfaceId
,
uint16_t
methodId
)
const
=
0
;
// Begin a new call to a method of this capability.
inline
Request
(
typename
Params
::
Builder
builder
,
kj
::
Own
<
RequestHook
>&&
hook
)
:
Params
::
Builder
(
builder
),
hook
(
kj
::
mv
(
hook
))
{}
virtual
kj
::
Own
<
TypelessCapability
>
addRef
()
const
=
0
;
// Return a new reference-counted pointer to the same capability. (Reference counting can be
// implemented using a special Disposer, so that the returned pointer actually has the same
// identity as the original.)
RemotePromise
<
Answer
>
send
();
// Send the call and return a promise for the answer.
virtual
kj
::
Promise
<
void
>
whenResolved
()
const
=
0
;
private
:
kj
::
Own
<
RequestHook
>
hook
;
};
template
<
typename
Answer
>
class
Response
:
public
Answer
::
Reader
{
// A completed call. This class extends a Reader for the call's answer structure. The Response
// is move-only -- once it goes out-of-scope, the underlying message will be freed.
public
:
inline
Response
(
typename
Answer
::
Reader
reader
,
kj
::
Own
<
ResponseHook
>&&
hook
)
:
Answer
::
Reader
(
reader
),
hook
(
kj
::
mv
(
hook
))
{}
private
:
kj
::
Own
<
ResponseHook
>
hook
;
template
<
typename
,
typename
>
friend
class
Request
;
};
class
Capability
::
Client
{
// Base type for capability clients.
public
:
explicit
Client
(
kj
::
Own
<
ClientHook
>&&
hook
);
Client
(
const
Client
&
other
);
Client
&
operator
=
(
const
Client
&
other
);
// Copies by reference counting. Warning: Refcounting is slow due to atomic ops. Try to only
// use move instead.
Client
(
Client
&&
)
=
default
;
Client
&
operator
=
(
Client
&&
)
=
default
;
// Move is fast.
kj
::
Promise
<
void
>
whenResolved
()
const
;
// If the capability is actually only a promise, the returned promise resolves once the
// capability itself has resolved to its final destination (or propagates the exception if
// the capability promise is rejected). This is mainly useful for error-checking in the case
// where no calls are being made. There is no reason to wait for this before making calls; if
// the capability does not resolve, the call results will propagate the error.
// TODO(soon): method implementing Join
// TODO(soon): method(s) for Join
private
:
kj
::
Own
<
ClientHook
>
hook
;
};
// =======================================================================================
// Local capabilities
class
CallContextHook
;
template
<
typename
T
>
class
CallContext
:
public
kj
::
DisallowConstCopy
{
// Wrapper around TypelessCallContext with a specific return type.
class
Call
{
public
:
virtual
ObjectPointer
::
Builder
getRequest
()
=
0
;
// Get the request object for this call, to be filled in before sending.
explicit
CallContext
(
kj
::
Own
<
CallContextHook
>
hook
);
typename
T
::
Builder
getAnswer
();
typename
T
::
Builder
initAnswer
();
typename
T
::
Builder
initAnswer
(
uint
size
);
void
setAnswer
(
typename
T
::
Reader
value
);
void
adoptAnswer
(
Orphan
<
T
>&&
value
);
Orphanage
getAnswerOrphanage
();
// Manipulate the answer (return value) payload. The "Return" message (part of the RPC protocol)
// will typically be allocated the first time one of these is called. Some RPC systems may
// allocate these messages in a limited space (such as a shared memory segment), therefore the
// application should delay calling these as long as is convenient to do so (but don't delay
// if doing so would require extra copies later).
void
allowAsyncCancellation
(
bool
allow
=
true
);
// Indicate that it is OK for the RPC system to discard its Promise for this call's result if
// the caller cancels the call, thereby transitively canceling any asynchronous operations the
// call implementation was performing. This is not done by default because it could represent a
// security risk: applications must be carefully written to ensure that they do not end up in
// a bad state if an operation is canceled at an arbitrary point. However, for long-running
// method calls that hold significant resources, prompt cancellation is often useful.
//
// You can also switch back to disallowing cancellation by passing `false` as the argument.
//
// Keep in mind that asynchronous cancellation cannot occur while the method is synchronously
// executing on a local thread. The method must perform an asynchronous operation or call
// `EventLoop::current().runLater()` to yield control.
bool
isCanceled
();
// As an alternative to `allowAsyncCancellation()`, a server can call this to check for
// cancellation.
//
// Keep in mind that if the method is blocking the event loop, the cancel message won't be
// received, so it is necessary to use `EventLoop::current().runLater()` occasionally.
virtual
RemotePromise
<
CallResult
>
send
()
=
0
;
// Send the call and return a promise for the result.
private
:
kj
::
Own
<
CallContextHook
>
hook
;
};
class
CallRunner
{
// Implements pipelined requests for a particular outstanding call.
class
Capability
::
Server
{
// Objects implementing a Cap'n Proto interface must subclass this. Typically, such objects
// will instead subclass a typed Server interface which will take care of implementing
// dispatchCall().
public
:
virtual
kj
::
Own
<
CallRunner
>
addRef
()
const
=
0
;
// Increment this object's reference count.
virtual
kj
::
Promise
<
void
>
dispatchCall
(
uint64_t
interfaceId
,
uint16_t
methodId
,
kj
::
Own
<
ObjectPointer
::
Reader
>
params
,
CallContext
<
ObjectPointer
>
context
)
=
0
;
// Call the given method. `params` is the input struct, and should be released as soon as it
// is no longer needed. `context` may be used to allocate the output struct and deal with
// cancellation.
// TODO(soon): Method which can optionally be overridden to implement Join when the object is
// a proxy.
};
Capability
::
Client
makeLocalClient
(
kj
::
Own
<
Capability
::
Server
>&&
server
);
// Make a client capability that wraps the given server capability.
// =======================================================================================
struct
PipelineOp
{
enum
Type
{
GET_POINTER_FIELD
};
struct
PipelineOp
{
enum
Type
{
GET_POINTER_FIELD
Type
type
;
union
{
uint16_t
pointerIndex
;
};
// There may be other types in the future...
};
virtual
kj
::
Own
<
TypelessCapability
>
getPipelinedCap
(
kj
::
ArrayPtr
<
const
PipelineOp
>
ops
)
const
=
0
;
// Extract a promised Capability from the answer.
Type
type
;
union
{
uint16_t
pointerIndex
;
// for GET_POINTER_FIELD
};
};
struct
CallResult
{
// Result of a call. Designed to be used as RemotePromise<CallResult>.
struct
TypelessAnswer
{
// Result of a call, before it has been type-wrapped. Designed to be used as
// RemotePromise<CallResult>.
typedef
ObjectPointer
::
Reader
Reader
;
// So RemotePromise<CallResult> resolves to Own<ObjectPointer::Reader>.
class
Pipeline
{
public
:
inline
explicit
Pipeline
(
kj
::
Own
<
CallRunner
>&&
runner
)
:
runner
(
kj
::
mv
(
runner
))
{}
inline
explicit
Pipeline
(
kj
::
Own
<
PipelineHook
>&&
hook
)
:
hook
(
kj
::
mv
(
hook
))
{}
Pipeline
getPointerField
(
uint16_t
pointerIndex
)
const
;
// Return a new Promise representing a sub-object of the result. `pointerIndex` is the index
// of the sub-object within the pointer section of the result (the result must be a struct).
//
// TODO(kenton): On GCC 4.8 / Clang 3.3, use rvalue qualifiers to avoid the need for copies.
//
Make `ops` into a Vector so that it can be extended without allocation in this case
.
//
Also make `ops` into a Vector to optimize this
.
inline
kj
::
Own
<
TypelessCapability
>
asCap
()
const
{
return
runner
->
getPipelinedCap
(
ops
);
}
Capability
::
Client
asCap
()
const
;
// Expect that the result is a capability and construct a pipelined version of it now.
private
:
kj
::
Own
<
CallRunner
>
runner
;
kj
::
Array
<
CallRunner
::
PipelineOp
>
ops
;
kj
::
Own
<
PipelineHook
>
hook
;
kj
::
Array
<
PipelineOp
>
ops
;
inline
Pipeline
(
kj
::
Own
<
CallRunner
>&&
runner
,
kj
::
Array
<
CallRunner
::
PipelineOp
>&&
ops
)
:
runner
(
kj
::
mv
(
runner
)),
ops
(
kj
::
mv
(
ops
))
{}
inline
Pipeline
(
kj
::
Own
<
PipelineHook
>&&
hook
,
kj
::
Array
<
PipelineOp
>&&
ops
)
:
hook
(
kj
::
mv
(
hook
)),
ops
(
kj
::
mv
(
ops
))
{}
};
};
// =======================================================================================
// Classes for imbuing message readers/builders with a capability context.
//
// These classes are for use by RPC implementations. Application code need not know about them.
//
// TODO(kenton): Move these to a separate header.
//
// Normally, MessageReader and MessageBuilder do not support interface pointers because they
// are not RPC-aware and so have no idea how to convert between a serialized CapabilityDescriptor
// and a live capability. To fix this, a reader/builder object needs to be "imbued" with a
// capability context. This creates a new reader/builder which points at the same object but has
// the ability to deal with interface fields.
namespace
_
{
// private
class
ImbuedReaderArena
;
class
ImbuedBuilderArena
;
}
// namespace _ (private)
class
CapExtractorBase
{
// Non-template base class for CapExtractor<T>.
// Hook interfaces which must be implemented by the RPC system. Applications never call these
// directly; the RPC system implements them and the types defined earlier in this file wrap them.
private
:
virtual
kj
::
Own
<
TypelessCapability
>
extractCapInternal
(
const
_
::
StructReader
&
capDescriptor
)
=
0
;
friend
class
_
::
ImbuedReaderArena
;
};
class
RequestHook
{
// Hook interface implemented by RPC system representing a request being built.
class
CapInjectorBase
{
// Non-template base class for CapInjector<T>.
public
:
virtual
ObjectPointer
::
Builder
getRequest
()
=
0
;
// Get the request object for this call, to be filled in before sending.
private
:
virtual
void
injectCapInternal
(
_
::
PointerBuilder
builder
,
kj
::
Own
<
TypelessCapability
>&&
cap
)
=
0
;
friend
class
_
::
ImbuedBuilderArena
;
virtual
RemotePromise
<
TypelessAnswer
>
send
()
=
0
;
// Send the call and return a promise for the result.
};
template
<
typename
CapDescriptor
>
class
CapExtractor
:
public
CapExtractorBase
{
//
Callback used to read a capability from a message, implemented by the RPC system.
//
`CapDescriptor` is the struct type which the RPC implementation uses to represent
//
capabilities. (On the wire, an interface pointer actually points to a struct of this type.)
class
ResponseHook
{
// Hook interface implemented by RPC system representing a response.
//
//
At present this class has no methods. It exists only for garbage collection -- when the
//
ResponseHook is destroyed, the answer can be freed.
public
:
virtual
kj
::
Own
<
TypelessCapability
>
extractCap
(
typename
CapDescriptor
::
Reader
descriptor
)
=
0
;
// Given the descriptor read off the wire, construct a live capability.
private
:
kj
::
Own
<
TypelessCapability
>
extractCapInternal
(
const
_
::
StructReader
&
capDescriptor
)
override
final
{
return
extractCap
(
typename
CapDescriptor
::
Reader
(
capDescriptor
));
}
};
template
<
typename
CapDescriptor
>
class
CapInjector
:
public
CapInjectorBase
{
// Callback used to write a capability into a message, implemented by the RPC system.
// `CapDescriptor` is the struct type which the RPC implementation uses to represent
// capabilities. (On the wire, an interface pointer actually points to a struct of this type.)
class
PipelineHook
{
// Represents a currently-running call, and implements pipelined requests on its result.
public
:
virtual
void
injectCap
(
typename
CapDescriptor
::
Builder
descriptor
,
kj
::
Own
<
TypelessCapability
>&&
cap
)
=
0
;
// Fill in the given descriptor so that it describes the given capability.
virtual
kj
::
Own
<
PipelineHook
>
addRef
()
const
=
0
;
// Increment this object's reference count.
private
:
void
injectCapInternal
(
_
::
PointerBuilder
builder
,
kj
::
Own
<
TypelessCapability
>&&
cap
)
override
final
{
injectCap
(
typename
CapDescriptor
::
Builder
(
builder
.
initCapDescriptor
(
_
::
structSize
<
CapDescriptor
>
())),
kj
::
mv
(
cap
));
}
virtual
kj
::
Own
<
ClientHook
>
getPipelinedCap
(
kj
::
ArrayPtr
<
const
PipelineOp
>
ops
)
const
=
0
;
// Extract a promised Capability from the answer.
};
class
CapReaderContext
{
// Class which can "imbue" reader objects from some other message with a capability context,
// so that interface pointers found in the message can be extracted and called.
class
ClientHook
{
public
:
CapReaderContext
(
Orphanage
arena
,
CapExtractorBase
&
extractor
);
~
CapReaderContext
()
noexcept
(
false
);
ObjectPointer
::
Reader
imbue
(
ObjectPointer
::
Reader
base
);
private
:
void
*
arenaSpace
[
15
+
sizeof
(
kj
::
MutexGuarded
<
void
*>
)
/
sizeof
(
void
*
)];
virtual
Request
<
ObjectPointer
,
TypelessAnswer
>
newCall
(
uint64_t
interfaceId
,
uint16_t
methodId
)
const
=
0
;
virtual
kj
::
Promise
<
void
>
whenResolved
()
const
=
0
;
virtual
kj
::
Own
<
TypelessCapability
>
extractCapInternal
(
const
_
::
StructReader
&
capDescriptor
)
=
0
;
virtual
kj
::
Own
<
ClientHook
>
addRef
()
const
=
0
;
// Return a new reference to the same capability.
friend
class
_
::
ImbuedReaderArena
;
virtual
void
*
getBrand
()
const
=
0
;
// Returns a void* that identifies who made this client. This can be used by an RPC adapter to
// discover when a capability it needs to marshal is one that it created in the first place, and
// therefore it can transfer the capability without proxying.
};
class
Ca
pBuilderContext
{
//
Class which can "imbue" reader objects from some other message with a capability context,
//
so that interface pointers found in the message can be set to point at live capabilities
.
class
Ca
llContextHook
{
//
Hook interface implemented by RPC system to manage a call on the server side. See
//
CallContext<T>
.
public
:
CapBuilderContext
(
Orphanage
arena
,
CapInjectorBase
&
injector
);
~
CapBuilderContext
()
noexcept
(
false
);
ObjectPointer
::
Builder
imbue
(
ObjectPointer
::
Builder
base
);
private
:
void
*
arenaSpace
[
15
+
sizeof
(
kj
::
MutexGuarded
<
void
*>
)
/
sizeof
(
void
*
)];
virtual
ObjectPointer
::
Builder
getAnswer
()
=
0
;
virtual
void
allowAsyncCancellation
(
bool
allow
)
=
0
;
virtual
bool
isCanceled
()
=
0
;
};
virtual
void
injectCapInternal
(
_
::
PointerBuilder
builder
,
kj
::
Own
<
TypelessCapability
>&&
cap
)
=
0
;
// =======================================================================================
// Inline implementation details
template
<
typename
Params
,
typename
Answer
>
RemotePromise
<
Answer
>
Request
<
Params
,
Answer
>::
send
()
{
auto
typelessPromise
=
hook
->
send
();
// Convert the Promise to return the correct response type.
// Explicitly upcast to kj::Promise to make clear that calling .then() doesn't invalidate the
// Pipeline part of the RemotePromise.
auto
typedPromise
=
kj
::
implicitCast
<
kj
::
Promise
<
Response
<
TypelessAnswer
>>&>
(
typelessPromise
)
.
then
([](
Response
<
TypelessAnswer
>&&
response
)
->
Response
<
Answer
>
{
return
Response
<
Answer
>
(
response
.
getAs
<
Answer
>
(),
kj
::
mv
(
response
.
hook
));
});
// Wrap the typeless pipeline in a typed wrapper.
typename
Answer
::
Pipeline
typedPipeline
(
kj
::
mv
(
kj
::
implicitCast
<
TypelessAnswer
::
Pipeline
&>
(
typelessPromise
)));
return
RemotePromise
<
Answer
>
(
kj
::
mv
(
typedPromise
),
kj
::
mv
(
typedPipeline
));
}
inline
Capability
::
Client
TypelessAnswer
::
Pipeline
::
asCap
()
const
{
return
Capability
::
Client
(
hook
->
getPipelinedCap
(
ops
));
}
inline
Capability
::
Client
::
Client
(
kj
::
Own
<
ClientHook
>&&
hook
)
:
hook
(
kj
::
mv
(
hook
))
{}
inline
Capability
::
Client
::
Client
(
const
Client
&
other
)
:
hook
(
other
.
hook
->
addRef
())
{}
inline
Capability
::
Client
&
Capability
::
Client
::
operator
=
(
const
Client
&
other
)
{
hook
=
other
.
hook
->
addRef
();
return
*
this
;
}
inline
kj
::
Promise
<
void
>
Capability
::
Client
::
whenResolved
()
const
{
return
hook
->
whenResolved
();
}
friend
class
_
::
ImbuedBuilderArena
;
};
template
<
typename
T
>
inline
CallContext
<
T
>::
CallContext
(
kj
::
Own
<
CallContextHook
>
hook
)
:
hook
(
kj
::
mv
(
hook
))
{}
template
<
typename
T
>
inline
typename
T
::
Builder
CallContext
<
T
>::
getAnswer
()
{
// `template` keyword needed due to: http://llvm.org/bugs/show_bug.cgi?id=17401
return
hook
->
getAnswer
().
template
getAs
<
T
>
();
}
template
<
typename
T
>
inline
typename
T
::
Builder
CallContext
<
T
>::
initAnswer
()
{
// `template` keyword needed due to: http://llvm.org/bugs/show_bug.cgi?id=17401
return
hook
->
getAnswer
().
template
initAs
<
T
>
();
}
template
<
typename
T
>
inline
typename
T
::
Builder
CallContext
<
T
>::
initAnswer
(
uint
size
)
{
// `template` keyword needed due to: http://llvm.org/bugs/show_bug.cgi?id=17401
return
hook
->
getAnswer
().
template
initAs
<
T
>
(
size
);
}
template
<
typename
T
>
inline
void
CallContext
<
T
>::
setAnswer
(
typename
T
::
Reader
value
)
{
hook
->
getAnswer
().
set
(
value
);
}
template
<
typename
T
>
inline
void
CallContext
<
T
>::
adoptAnswer
(
Orphan
<
T
>&&
value
)
{
hook
->
getAnswer
().
adopt
(
kj
::
mv
(
value
));
}
template
<
typename
T
>
inline
Orphanage
CallContext
<
T
>::
getAnswerOrphanage
()
{
return
Orphanage
::
getForMessageContaining
(
hook
->
getAnswer
());
}
template
<
typename
T
>
inline
void
CallContext
<
T
>::
allowAsyncCancellation
(
bool
allow
)
{
hook
->
allowAsyncCancellation
(
allow
);
}
template
<
typename
T
>
inline
bool
CallContext
<
T
>::
isCanceled
()
{
return
hook
->
isCanceled
();
}
}
// namespace capnp
...
...
c++/src/capnp/layout.c++
View file @
d07bf3b8
...
...
@@ -2104,6 +2104,14 @@ PointerReader PointerBuilder::asReader() const {
return
PointerReader
(
segment
,
pointer
,
std
::
numeric_limits
<
int
>::
max
());
}
BuilderArena
&
PointerBuilder
::
getArena
()
const
{
return
*
segment
->
getArena
();
}
PointerBuilder
PointerBuilder
::
imbue
(
ImbuedBuilderArena
&
newArena
)
const
{
return
PointerBuilder
(
newArena
.
imbue
(
segment
),
pointer
);
}
// =======================================================================================
// PointerReader
...
...
@@ -2139,6 +2147,14 @@ bool PointerReader::isNull() const {
return
pointer
==
nullptr
||
pointer
->
isNull
();
}
kj
::
Maybe
<
Arena
&>
PointerReader
::
getArena
()
const
{
return
segment
==
nullptr
?
nullptr
:
segment
->
getArena
();
}
PointerReader
PointerReader
::
imbue
(
ImbuedReaderArena
&
newArena
)
const
{
return
PointerReader
(
newArena
.
imbue
(
segment
),
pointer
,
nestingLimit
);
}
// =======================================================================================
// StructBuilder
...
...
c++/src/capnp/layout.h
View file @
d07bf3b8
...
...
@@ -39,7 +39,7 @@
namespace
capnp
{
class
TypelessCapability
;
class
ClientHook
;
namespace
_
{
// private
...
...
@@ -54,7 +54,10 @@ struct WirePointer;
struct
WireHelpers
;
class
SegmentReader
;
class
SegmentBuilder
;
class
Arena
;
class
BuilderArena
;
class
ImbuedReaderArena
;
class
ImbuedBuilderArena
;
// =============================================================================
...
...
@@ -284,7 +287,7 @@ public:
ListBuilder
getList
(
FieldSize
elementSize
,
const
word
*
defaultValzue
);
ListBuilder
getStructList
(
StructSize
elementSize
,
const
word
*
defaultValue
);
template
<
typename
T
>
typename
T
::
Builder
getBlob
(
const
void
*
defaultValue
,
ByteCount
defaultSize
);
kj
::
Own
<
TypelessCapability
>
getCapability
();
kj
::
Own
<
ClientHook
>
getCapability
();
// Get methods: Get the value. If it is null, initialize it to a copy of the default value.
// The default value is encoded as an "unchecked message" for structs, lists, and objects, or a
// simple byte array for blobs.
...
...
@@ -300,7 +303,7 @@ public:
void
setStruct
(
const
StructReader
&
value
);
void
setList
(
const
ListReader
&
value
);
template
<
typename
T
>
void
setBlob
(
typename
T
::
Reader
value
);
void
setCapability
(
kj
::
Own
<
TypelessCapability
>&&
cap
);
void
setCapability
(
kj
::
Own
<
ClientHook
>&&
cap
);
// Set methods: Initialize the pointer to a newly-allocated copy of the given value, discarding
// the existing object.
...
...
@@ -321,6 +324,12 @@ public:
PointerReader
asReader
()
const
;
BuilderArena
&
getArena
()
const
;
// Get the arena containing this pointer.
PointerBuilder
imbue
(
ImbuedBuilderArena
&
newArena
)
const
;
// Imbue the pointer with a capability context, returning the imbued pointer.
private
:
SegmentBuilder
*
segment
;
// Memory segment in which the pointer resides.
WirePointer
*
pointer
;
// Pointer to the pointer.
...
...
@@ -342,7 +351,7 @@ public:
ListReader
getList
(
FieldSize
expectedElementSize
,
const
word
*
defaultValue
)
const
;
template
<
typename
T
>
typename
T
::
Reader
getBlob
(
const
void
*
defaultValue
,
ByteCount
defaultSize
)
const
;
kj
::
Own
<
TypelessCapability
>
getCapability
();
kj
::
Own
<
ClientHook
>
getCapability
();
// Get methods: Get the value. If it is null, return the default value instead.
// The default value is encoded as an "unchecked message" for structs, lists, and objects, or a
// simple byte array for blobs.
...
...
@@ -352,6 +361,12 @@ public:
// word* can actually be passed to readUnchecked() to read the designated sub-object later. If
// this isn't an unchecked message, throws an exception.
kj
::
Maybe
<
Arena
&>
getArena
()
const
;
// Get the arena containing this pointer.
PointerReader
imbue
(
ImbuedReaderArena
&
newArena
)
const
;
// Imbue the pointer with a capability context, returning the imbued pointer.
private
:
SegmentReader
*
segment
;
// Memory segment in which the pointer resides.
const
WirePointer
*
pointer
;
// Pointer to the pointer. null = treat as null pointer.
...
...
c++/src/capnp/object.h
View file @
d07bf3b8
...
...
@@ -63,6 +63,7 @@ struct ObjectPointer {
_
::
PointerReader
reader
;
friend
struct
ObjectPointer
;
friend
class
Orphanage
;
friend
class
CapReaderContext
;
};
class
Builder
{
...
...
@@ -143,6 +144,7 @@ struct ObjectPointer {
private
:
_
::
PointerBuilder
builder
;
friend
class
CapBuilderContext
;
};
};
...
...
@@ -281,6 +283,38 @@ inline Orphan<T> Orphan<ObjectPointer>::releaseAs() {
return
Orphan
<
T
>
(
kj
::
mv
(
builder
));
}
// Using ObjectPointer as the template type should work...
template
<>
inline
typename
ObjectPointer
::
Reader
ObjectPointer
::
Reader
::
getAs
<
ObjectPointer
>
()
{
return
*
this
;
}
template
<>
inline
typename
ObjectPointer
::
Builder
ObjectPointer
::
Builder
::
getAs
<
ObjectPointer
>
()
{
return
*
this
;
}
template
<>
inline
typename
ObjectPointer
::
Builder
ObjectPointer
::
Builder
::
initAs
<
ObjectPointer
>
()
{
clear
();
return
*
this
;
}
template
<>
inline
void
ObjectPointer
::
Builder
::
setAs
<
ObjectPointer
>
(
ObjectPointer
::
Reader
value
)
{
return
builder
.
copyFrom
(
value
.
reader
);
}
template
<>
inline
void
ObjectPointer
::
Builder
::
adopt
<
ObjectPointer
>
(
Orphan
<
ObjectPointer
>&&
orphan
)
{
builder
.
adopt
(
kj
::
mv
(
orphan
.
builder
));
}
template
<>
inline
Orphan
<
ObjectPointer
>
ObjectPointer
::
Builder
::
disownAs
<
ObjectPointer
>
()
{
return
Orphan
<
ObjectPointer
>
(
builder
.
disown
());
}
template
<>
inline
Orphan
<
ObjectPointer
>
Orphan
<
ObjectPointer
>::
releaseAs
()
{
return
kj
::
mv
(
*
this
);
}
}
// namespace capnp
#endif // CAPNP_OBJECT_H_
c++/src/capnp/rpc.capnp
View file @
d07bf3b8
...
...
@@ -950,7 +950,7 @@ using JoinAnswer = Object;
#
# # Level 4 features -----------------------------------------------
#
# newJoiner(count :UInt32)
:
NewJoinerResponse;
# newJoiner(count :UInt32)
:
NewJoinerResponse;
# # Prepare a new Join operation, which will eventually lead to forming a new direct connection
# # to the host of the joined capability. `count` is the number of capabilities to join.
#
...
...
@@ -973,7 +973,7 @@ using JoinAnswer = Object;
# # message on it with the specified `ProvisionId` in order to receive the final capability.
# }
#
# acceptConnectionFromJoiner(parts
:
List(JoinKeyPart), paths :List(VatPath))
# acceptConnectionFromJoiner(parts
:
List(JoinKeyPart), paths :List(VatPath))
# :ConnectionAndProvisionId;
# # Called on a joined capability's host to receive the connection from the joiner, once all
# # key parts have arrived. The caller should expect to receive an `Accept` message over the
...
...
@@ -1002,17 +1002,17 @@ using JoinAnswer = Object;
# sendToTarget :RecipientId;
# }
#
# connectToIntroduced(capId
:
ThirdPartyCapId) :ConnectionAndProvisionId;
# connectToIntroduced(capId
:
ThirdPartyCapId) :ConnectionAndProvisionId;
# # Given a ThirdPartyCapId received over this connection, connect to the third party. The
# # caller should then send an `Accept` message over the new connection.
#
# acceptIntroducedConnection(recipientId
: RecipientId): Connection
# acceptIntroducedConnection(recipientId
:RecipientId) :Connection;
# # Given a RecipientId received in a `Provide` message on this `Connection`, wait for the
# # recipient to connect, and return the connection formed. Usually, the first message received
# # on the new connection will be an `Accept` message.
# }
#
# st
ur
ct ConnectionAndProvisionId {
# st
ru
ct ConnectionAndProvisionId {
# # **(level 3)**
#
# connection :Connection;
...
...
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