Skip to content

Commit 4e96569

Browse files
committed
imbue builders and readers with cap tables
1 parent 3433572 commit 4e96569

26 files changed

+577
-138
lines changed

runtime/src/main/java/org/capnproto/AnyPointer.java

Lines changed: 41 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -26,30 +26,30 @@ public static final class Factory
2626
implements PointerFactory<Builder, Reader>,
2727
SetPointerBuilder<Builder, Reader>
2828
{
29-
public final Reader fromPointerReader(SegmentReader segment, int pointer, int nestingLimit) {
30-
return new Reader(segment, pointer, nestingLimit);
29+
public final Reader fromPointerReader(SegmentReader segment, CapTableReader capTable, int pointer, int nestingLimit) {
30+
return new Reader(segment, capTable, pointer, nestingLimit);
3131
}
32-
public final Builder fromPointerBuilder(SegmentBuilder segment, int pointer) {
33-
return new Builder(segment, pointer);
32+
public final Builder fromPointerBuilder(SegmentBuilder segment, CapTableBuilder capTable, int pointer) {
33+
return new Builder(segment, capTable, pointer);
3434
}
35-
public final Builder initFromPointerBuilder(SegmentBuilder segment, int pointer, int elementCount) {
36-
Builder result = new Builder(segment, pointer);
35+
public final Builder initFromPointerBuilder(SegmentBuilder segment, CapTableBuilder capTable, int pointer, int elementCount) {
36+
Builder result = new Builder(segment, capTable, pointer);
3737
result.clear();
3838
return result;
3939
}
40-
public void setPointerBuilder(SegmentBuilder segment, int pointer, Reader value) {
40+
public void setPointerBuilder(SegmentBuilder segment, CapTableBuilder capTable, int pointer, Reader value) {
4141
if (value.isNull()) {
42-
WireHelpers.zeroObject(segment, pointer);
42+
WireHelpers.zeroObject(segment, capTable, pointer);
4343
WireHelpers.zeroPointerAndFars(segment, pointer);
4444
}
4545
else {
46-
WireHelpers.copyPointer(segment, pointer, value.segment, value.pointer, value.nestingLimit);
46+
WireHelpers.copyPointer(segment, capTable, pointer, value.segment, value.capTable, value.pointer, value.nestingLimit);
4747
}
4848
}
4949
}
5050
public static final Factory factory = new Factory();
5151

52-
public final static class Reader {
52+
public final static class Reader extends CapTableReader.ReaderContext {
5353
final SegmentReader segment;
5454
final int pointer; // offset in words
5555
final int nestingLimit;
@@ -60,16 +60,29 @@ public Reader(SegmentReader segment, int pointer, int nestingLimit) {
6060
this.nestingLimit = nestingLimit;
6161
}
6262

63+
public Reader(SegmentReader segment, CapTableReader capTable, int pointer, int nestingLimit) {
64+
this.segment = segment;
65+
this.pointer = pointer;
66+
this.nestingLimit = nestingLimit;
67+
this.capTable = capTable;
68+
}
69+
70+
final Reader imbue(CapTableReader capTable) {
71+
Reader result = new Reader(segment, pointer, nestingLimit);
72+
result.capTable = capTable;
73+
return result;
74+
}
75+
6376
public final boolean isNull() {
6477
return WirePointer.isNull(this.segment.buffer.getLong(this.pointer * Constants.BYTES_PER_WORD));
6578
}
6679

6780
public final <T> T getAs(FromPointerReader<T> factory) {
68-
return factory.fromPointerReader(this.segment, this.pointer, this.nestingLimit);
81+
return factory.fromPointerReader(this.segment, this.capTable, this.pointer, this.nestingLimit);
6982
}
7083
}
7184

72-
public static final class Builder {
85+
public static final class Builder extends CapTableBuilder.BuilderContext {
7386
final SegmentBuilder segment;
7487
final int pointer;
7588

@@ -78,34 +91,43 @@ public Builder(SegmentBuilder segment, int pointer) {
7891
this.pointer = pointer;
7992
}
8093

94+
Builder(SegmentBuilder segment, CapTableBuilder capTable, int pointer) {
95+
this.segment = segment;
96+
this.pointer = pointer;
97+
this.capTable = capTable;
98+
}
99+
100+
final Builder imbue(CapTableBuilder capTable) {
101+
return new Builder(segment, capTable, pointer);
102+
}
103+
81104
public final boolean isNull() {
82105
return WirePointer.isNull(this.segment.buffer.getLong(this.pointer * Constants.BYTES_PER_WORD));
83106
}
84107

85108
public final <T> T getAs(FromPointerBuilder<T> factory) {
86-
return factory.fromPointerBuilder(this.segment, this.pointer);
109+
return factory.fromPointerBuilder(this.segment, this.capTable, this.pointer);
87110
}
88111

89112
public final <T> T initAs(FromPointerBuilder<T> factory) {
90-
return factory.initFromPointerBuilder(this.segment, this.pointer, 0);
113+
return factory.initFromPointerBuilder(this.segment, this.capTable, this.pointer, 0);
91114
}
92115

93116
public final <T> T initAs(FromPointerBuilder<T> factory, int elementCount) {
94-
return factory.initFromPointerBuilder(this.segment, this.pointer, elementCount);
117+
return factory.initFromPointerBuilder(this.segment, this.capTable, this.pointer, elementCount);
95118
}
96119

97120
public final <T, U> void setAs(SetPointerBuilder<T, U> factory, U reader) {
98-
factory.setPointerBuilder(this.segment, this.pointer, reader);
121+
factory.setPointerBuilder(this.segment, this.capTable, this.pointer, reader);
99122
}
100123

101124
public final Reader asReader() {
102-
return new Reader(segment, pointer, java.lang.Integer.MAX_VALUE);
125+
return new Reader(segment, this.capTable, pointer, java.lang.Integer.MAX_VALUE);
103126
}
104127

105128
public final void clear() {
106-
WireHelpers.zeroObject(this.segment, this.pointer);
129+
WireHelpers.zeroObject(this.segment, this.capTable, this.pointer);
107130
this.segment.buffer.putLong(this.pointer * 8, 0L);
108131
}
109132
}
110-
111133
}

runtime/src/main/java/org/capnproto/BuilderArena.java

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import java.nio.ByteBuffer;
2525
import java.nio.ByteOrder;
2626
import java.util.ArrayList;
27+
import java.util.List;
2728

2829
public final class BuilderArena implements Arena {
2930
public enum AllocationStrategy {
@@ -38,6 +39,34 @@ public enum AllocationStrategy {
3839
public final ArrayList<SegmentBuilder> segments;
3940
private final Allocator allocator;
4041

42+
private final CapTableBuilder localCapTable = new CapTableBuilder() {
43+
44+
private final List<ClientHook> capTable = new ArrayList<>();
45+
46+
@Override
47+
public int injectCap(ClientHook cap) {
48+
int result = this.capTable.size();
49+
this.capTable.add(cap);
50+
return result;
51+
}
52+
53+
@Override
54+
public void dropCap(int index) {
55+
if (index < this.capTable.size()) {
56+
assert false : "Invalid capability descriptor in message.";
57+
return;
58+
}
59+
this.capTable.set(index, null);
60+
}
61+
62+
@Override
63+
public ClientHook extractCap(int index) {
64+
return index < this.capTable.size()
65+
? this.capTable.get(index)
66+
: null;
67+
}
68+
};
69+
4170
public BuilderArena(int firstSegmentSizeWords, AllocationStrategy allocationStrategy) {
4271
this.segments = new ArrayList<SegmentBuilder>();
4372
{
@@ -64,7 +93,17 @@ public BuilderArena(Allocator allocator, ByteBuffer firstSegment) {
6493
this.allocator = allocator;
6594
}
6695

67-
/**
96+
/**
97+
* Return a CapTableBuilder that merely implements local loopback. That is, you can set
98+
* capabilities, then read the same capabilities back, but there is no intent ever to transmit
99+
* these capabilities. A MessageBuilder that isn't imbued with some other CapTable uses this
100+
* by default.
101+
*/
102+
public CapTableBuilder getLocalCapTable() {
103+
return this.localCapTable;
104+
}
105+
106+
/**
68107
* Constructs a BuilderArena from a ReaderArena and uses the size of the largest segment
69108
* as the next allocation size.
70109
*/
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package org.capnproto;
2+
3+
public interface CapTableBuilder extends CapTableReader {
4+
5+
class BuilderContext {
6+
public CapTableBuilder capTable;
7+
}
8+
9+
int injectCap(ClientHook cap);
10+
11+
void dropCap(int index);
12+
13+
default ClientHook[] getTable() {
14+
return new ClientHook[0];
15+
}
16+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package org.capnproto;
2+
3+
public interface CapTableReader {
4+
5+
class ReaderContext {
6+
public CapTableReader capTable;
7+
}
8+
9+
ClientHook extractCap(int index);
10+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package org.capnproto;
2+
3+
import static org.capnproto.ClientHook.BROKEN_CAPABILITY_BRAND;
4+
import static org.capnproto.ClientHook.NULL_CAPABILITY_BRAND;
5+
6+
public final class Capability {
7+
8+
public static ClientHook newBrokenCap(String reason) {
9+
return newBrokenClient(reason, false, BROKEN_CAPABILITY_BRAND);
10+
}
11+
12+
public static ClientHook newBrokenCap(Throwable exc) {
13+
return newBrokenClient(exc, false, BROKEN_CAPABILITY_BRAND);
14+
}
15+
16+
public static ClientHook newNullCap() {
17+
return newBrokenClient(RpcException.failed("Called null capability"), true, NULL_CAPABILITY_BRAND);
18+
}
19+
20+
private static ClientHook newBrokenClient(String reason, boolean resolved, Object brand) {
21+
return newBrokenClient(RpcException.failed(reason), resolved, brand);
22+
}
23+
24+
private static ClientHook newBrokenClient(Throwable exc, boolean resolved, Object brand) {
25+
return new ClientHook() {
26+
@Override
27+
public Object getBrand() {
28+
return brand;
29+
}
30+
};
31+
}
32+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package org.capnproto;
2+
3+
public interface ClientHook {
4+
5+
static final Object NULL_CAPABILITY_BRAND = new Object();
6+
static final Object BROKEN_CAPABILITY_BRAND = new Object();
7+
8+
/**
9+
Returns an opaque object that identifies who made this client. This can be used by an RPC adapter to
10+
discover when a capability it needs to marshal is one that it created in the first place, and
11+
therefore it can transfer the capability without proxying.
12+
*/
13+
Object getBrand();
14+
15+
/**
16+
* Returns true if the capability was created as a result of assigning a Client to null or by
17+
* reading a null pointer out of a Cap'n Proto message.
18+
*/
19+
default boolean isNull() {
20+
return getBrand() == NULL_CAPABILITY_BRAND;
21+
}
22+
23+
/**
24+
* Returns true if the capability was created by newBrokenCap().
25+
*/
26+
default boolean isError() {
27+
return getBrand() == BROKEN_CAPABILITY_BRAND;
28+
}
29+
}

runtime/src/main/java/org/capnproto/Data.java

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,35 +39,42 @@ public final Reader fromPointerReader(SegmentReader segment, int pointer, int ne
3939
return WireHelpers.readDataPointer(segment, pointer, null, 0, 0);
4040
}
4141

42+
@Override
43+
public final Reader fromPointerReader(SegmentReader segment, CapTableReader capTable, int pointer, int nestingLimit) {
44+
return WireHelpers.readDataPointer(segment, pointer, null, 0, 0);
45+
}
46+
4247
@Override
4348
public final Builder fromPointerBuilderBlobDefault(
4449
SegmentBuilder segment,
50+
CapTableBuilder capTable,
4551
int pointer,
4652
java.nio.ByteBuffer defaultBuffer,
4753
int defaultOffset,
4854
int defaultSize) {
4955
return WireHelpers.getWritableDataPointer(pointer,
5056
segment,
57+
capTable,
5158
defaultBuffer,
5259
defaultOffset,
5360
defaultSize);
5461
}
55-
5662
@Override
57-
public final Builder fromPointerBuilder(SegmentBuilder segment, int pointer) {
63+
public final Builder fromPointerBuilder(SegmentBuilder segment, CapTableBuilder capTable, int pointer) {
5864
return WireHelpers.getWritableDataPointer(pointer,
5965
segment,
66+
capTable,
6067
null, 0, 0);
6168
}
6269

6370
@Override
64-
public final Builder initFromPointerBuilder(SegmentBuilder segment, int pointer, int size) {
65-
return WireHelpers.initDataPointer(pointer, segment, size);
71+
public final Builder initFromPointerBuilder(SegmentBuilder segment, CapTableBuilder capTable, int pointer, int size) {
72+
return WireHelpers.initDataPointer(pointer, segment, capTable, size);
6673
}
6774

6875
@Override
69-
public final void setPointerBuilder(SegmentBuilder segment, int pointer, Reader value) {
70-
WireHelpers.setDataPointer(pointer, segment, value);
76+
public final void setPointerBuilder(SegmentBuilder segment, CapTableBuilder capTable, int pointer, Reader value) {
77+
WireHelpers.setDataPointer(pointer, segment, capTable, value);
7178
}
7279
}
7380
public static final Factory factory = new Factory();

runtime/src/main/java/org/capnproto/FromPointerBuilder.java

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,15 @@
2222
package org.capnproto;
2323

2424
public interface FromPointerBuilder<T> {
25-
T fromPointerBuilder(SegmentBuilder segment, int pointer);
26-
T initFromPointerBuilder(SegmentBuilder segment, int pointer, int elementCount);
25+
default T fromPointerBuilder(SegmentBuilder segment, int pointer) {
26+
return fromPointerBuilder(segment, null, pointer);
27+
}
28+
29+
T fromPointerBuilder(SegmentBuilder segment, CapTableBuilder capTable, int pointer);
30+
31+
default T initFromPointerBuilder(SegmentBuilder segment, int pointer, int elementCount) {
32+
return initFromPointerBuilder(segment, null, pointer, elementCount);
33+
}
34+
35+
T initFromPointerBuilder(SegmentBuilder segment, CapTableBuilder capTable, int pointer, int elementCount);
2736
}

runtime/src/main/java/org/capnproto/FromPointerBuilderBlobDefault.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,11 @@
2222
package org.capnproto;
2323

2424
public interface FromPointerBuilderBlobDefault<T> {
25-
T fromPointerBuilderBlobDefault(SegmentBuilder segment, int pointer,
25+
default T fromPointerBuilderBlobDefault(SegmentBuilder segment, int pointer,
26+
java.nio.ByteBuffer defaultBuffer, int defaultOffset, int defaultSize) {
27+
return fromPointerBuilderBlobDefault(segment, null, pointer, defaultBuffer, defaultOffset, defaultSize);
28+
}
29+
30+
T fromPointerBuilderBlobDefault(SegmentBuilder segment, CapTableBuilder capTable, int pointer,
2631
java.nio.ByteBuffer defaultBuffer, int defaultOffset, int defaultSize);
2732
}

runtime/src/main/java/org/capnproto/FromPointerBuilderRefDefault.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,10 @@
2222
package org.capnproto;
2323

2424
public interface FromPointerBuilderRefDefault<T> {
25-
T fromPointerBuilderRefDefault(SegmentBuilder segment, int pointer, SegmentReader defaultSegment, int defaultOffset);
25+
26+
default T fromPointerBuilderRefDefault(SegmentBuilder segment, int pointer, SegmentReader defaultSegment, int defaultOffset) {
27+
return fromPointerBuilderRefDefault(segment, null, pointer, defaultSegment, defaultOffset);
28+
}
29+
30+
T fromPointerBuilderRefDefault(SegmentBuilder segment, CapTableBuilder capTable, int pointer, SegmentReader defaultSegment, int defaultOffset);
2631
}

0 commit comments

Comments
 (0)