Skip to content

Commit

Permalink
imbue builders and readers with cap tables
Browse files Browse the repository at this point in the history
  • Loading branch information
vaci committed Dec 27, 2022
1 parent 3433572 commit 4e96569
Show file tree
Hide file tree
Showing 26 changed files with 577 additions and 138 deletions.
60 changes: 41 additions & 19 deletions runtime/src/main/java/org/capnproto/AnyPointer.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,30 +26,30 @@ public static final class Factory
implements PointerFactory<Builder, Reader>,
SetPointerBuilder<Builder, Reader>
{
public final Reader fromPointerReader(SegmentReader segment, int pointer, int nestingLimit) {
return new Reader(segment, pointer, nestingLimit);
public final Reader fromPointerReader(SegmentReader segment, CapTableReader capTable, int pointer, int nestingLimit) {
return new Reader(segment, capTable, pointer, nestingLimit);
}
public final Builder fromPointerBuilder(SegmentBuilder segment, int pointer) {
return new Builder(segment, pointer);
public final Builder fromPointerBuilder(SegmentBuilder segment, CapTableBuilder capTable, int pointer) {
return new Builder(segment, capTable, pointer);
}
public final Builder initFromPointerBuilder(SegmentBuilder segment, int pointer, int elementCount) {
Builder result = new Builder(segment, pointer);
public final Builder initFromPointerBuilder(SegmentBuilder segment, CapTableBuilder capTable, int pointer, int elementCount) {
Builder result = new Builder(segment, capTable, pointer);
result.clear();
return result;
}
public void setPointerBuilder(SegmentBuilder segment, int pointer, Reader value) {
public void setPointerBuilder(SegmentBuilder segment, CapTableBuilder capTable, int pointer, Reader value) {
if (value.isNull()) {
WireHelpers.zeroObject(segment, pointer);
WireHelpers.zeroObject(segment, capTable, pointer);
WireHelpers.zeroPointerAndFars(segment, pointer);
}
else {
WireHelpers.copyPointer(segment, pointer, value.segment, value.pointer, value.nestingLimit);
WireHelpers.copyPointer(segment, capTable, pointer, value.segment, value.capTable, value.pointer, value.nestingLimit);
}
}
}
public static final Factory factory = new Factory();

public final static class Reader {
public final static class Reader extends CapTableReader.ReaderContext {
final SegmentReader segment;
final int pointer; // offset in words
final int nestingLimit;
Expand All @@ -60,16 +60,29 @@ public Reader(SegmentReader segment, int pointer, int nestingLimit) {
this.nestingLimit = nestingLimit;
}

public Reader(SegmentReader segment, CapTableReader capTable, int pointer, int nestingLimit) {
this.segment = segment;
this.pointer = pointer;
this.nestingLimit = nestingLimit;
this.capTable = capTable;
}

final Reader imbue(CapTableReader capTable) {
Reader result = new Reader(segment, pointer, nestingLimit);
result.capTable = capTable;
return result;
}

public final boolean isNull() {
return WirePointer.isNull(this.segment.buffer.getLong(this.pointer * Constants.BYTES_PER_WORD));
}

public final <T> T getAs(FromPointerReader<T> factory) {
return factory.fromPointerReader(this.segment, this.pointer, this.nestingLimit);
return factory.fromPointerReader(this.segment, this.capTable, this.pointer, this.nestingLimit);
}
}

public static final class Builder {
public static final class Builder extends CapTableBuilder.BuilderContext {
final SegmentBuilder segment;
final int pointer;

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

Builder(SegmentBuilder segment, CapTableBuilder capTable, int pointer) {
this.segment = segment;
this.pointer = pointer;
this.capTable = capTable;
}

final Builder imbue(CapTableBuilder capTable) {
return new Builder(segment, capTable, pointer);
}

public final boolean isNull() {
return WirePointer.isNull(this.segment.buffer.getLong(this.pointer * Constants.BYTES_PER_WORD));
}

public final <T> T getAs(FromPointerBuilder<T> factory) {
return factory.fromPointerBuilder(this.segment, this.pointer);
return factory.fromPointerBuilder(this.segment, this.capTable, this.pointer);
}

public final <T> T initAs(FromPointerBuilder<T> factory) {
return factory.initFromPointerBuilder(this.segment, this.pointer, 0);
return factory.initFromPointerBuilder(this.segment, this.capTable, this.pointer, 0);
}

public final <T> T initAs(FromPointerBuilder<T> factory, int elementCount) {
return factory.initFromPointerBuilder(this.segment, this.pointer, elementCount);
return factory.initFromPointerBuilder(this.segment, this.capTable, this.pointer, elementCount);
}

public final <T, U> void setAs(SetPointerBuilder<T, U> factory, U reader) {
factory.setPointerBuilder(this.segment, this.pointer, reader);
factory.setPointerBuilder(this.segment, this.capTable, this.pointer, reader);
}

public final Reader asReader() {
return new Reader(segment, pointer, java.lang.Integer.MAX_VALUE);
return new Reader(segment, this.capTable, pointer, java.lang.Integer.MAX_VALUE);
}

public final void clear() {
WireHelpers.zeroObject(this.segment, this.pointer);
WireHelpers.zeroObject(this.segment, this.capTable, this.pointer);
this.segment.buffer.putLong(this.pointer * 8, 0L);
}
}

}
41 changes: 40 additions & 1 deletion runtime/src/main/java/org/capnproto/BuilderArena.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.List;

public final class BuilderArena implements Arena {
public enum AllocationStrategy {
Expand All @@ -38,6 +39,34 @@ public enum AllocationStrategy {
public final ArrayList<SegmentBuilder> segments;
private final Allocator allocator;

private final CapTableBuilder localCapTable = new CapTableBuilder() {

private final List<ClientHook> capTable = new ArrayList<>();

@Override
public int injectCap(ClientHook cap) {
int result = this.capTable.size();
this.capTable.add(cap);
return result;
}

@Override
public void dropCap(int index) {
if (index < this.capTable.size()) {
assert false : "Invalid capability descriptor in message.";
return;
}
this.capTable.set(index, null);
}

@Override
public ClientHook extractCap(int index) {
return index < this.capTable.size()
? this.capTable.get(index)
: null;
}
};

public BuilderArena(int firstSegmentSizeWords, AllocationStrategy allocationStrategy) {
this.segments = new ArrayList<SegmentBuilder>();
{
Expand All @@ -64,7 +93,17 @@ public BuilderArena(Allocator allocator, ByteBuffer firstSegment) {
this.allocator = allocator;
}

/**
/**
* Return a CapTableBuilder that merely implements local loopback. That is, you can set
* capabilities, then read the same capabilities back, but there is no intent ever to transmit
* these capabilities. A MessageBuilder that isn't imbued with some other CapTable uses this
* by default.
*/
public CapTableBuilder getLocalCapTable() {
return this.localCapTable;
}

/**
* Constructs a BuilderArena from a ReaderArena and uses the size of the largest segment
* as the next allocation size.
*/
Expand Down
16 changes: 16 additions & 0 deletions runtime/src/main/java/org/capnproto/CapTableBuilder.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package org.capnproto;

public interface CapTableBuilder extends CapTableReader {

class BuilderContext {
public CapTableBuilder capTable;
}

int injectCap(ClientHook cap);

void dropCap(int index);

default ClientHook[] getTable() {
return new ClientHook[0];
}
}
10 changes: 10 additions & 0 deletions runtime/src/main/java/org/capnproto/CapTableReader.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package org.capnproto;

public interface CapTableReader {

class ReaderContext {
public CapTableReader capTable;
}

ClientHook extractCap(int index);
}
32 changes: 32 additions & 0 deletions runtime/src/main/java/org/capnproto/Capability.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package org.capnproto;

import static org.capnproto.ClientHook.BROKEN_CAPABILITY_BRAND;
import static org.capnproto.ClientHook.NULL_CAPABILITY_BRAND;

public final class Capability {

public static ClientHook newBrokenCap(String reason) {
return newBrokenClient(reason, false, BROKEN_CAPABILITY_BRAND);
}

public static ClientHook newBrokenCap(Throwable exc) {
return newBrokenClient(exc, false, BROKEN_CAPABILITY_BRAND);
}

public static ClientHook newNullCap() {
return newBrokenClient(RpcException.failed("Called null capability"), true, NULL_CAPABILITY_BRAND);
}

private static ClientHook newBrokenClient(String reason, boolean resolved, Object brand) {
return newBrokenClient(RpcException.failed(reason), resolved, brand);
}

private static ClientHook newBrokenClient(Throwable exc, boolean resolved, Object brand) {
return new ClientHook() {
@Override
public Object getBrand() {
return brand;
}
};
}
}
29 changes: 29 additions & 0 deletions runtime/src/main/java/org/capnproto/ClientHook.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package org.capnproto;

public interface ClientHook {

static final Object NULL_CAPABILITY_BRAND = new Object();
static final Object BROKEN_CAPABILITY_BRAND = new Object();

/**
Returns an opaque object 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.
*/
Object getBrand();

/**
* Returns true if the capability was created as a result of assigning a Client to null or by
* reading a null pointer out of a Cap'n Proto message.
*/
default boolean isNull() {
return getBrand() == NULL_CAPABILITY_BRAND;
}

/**
* Returns true if the capability was created by newBrokenCap().
*/
default boolean isError() {
return getBrand() == BROKEN_CAPABILITY_BRAND;
}
}
19 changes: 13 additions & 6 deletions runtime/src/main/java/org/capnproto/Data.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,35 +39,42 @@ public final Reader fromPointerReader(SegmentReader segment, int pointer, int ne
return WireHelpers.readDataPointer(segment, pointer, null, 0, 0);
}

@Override
public final Reader fromPointerReader(SegmentReader segment, CapTableReader capTable, int pointer, int nestingLimit) {
return WireHelpers.readDataPointer(segment, pointer, null, 0, 0);
}

@Override
public final Builder fromPointerBuilderBlobDefault(
SegmentBuilder segment,
CapTableBuilder capTable,
int pointer,
java.nio.ByteBuffer defaultBuffer,
int defaultOffset,
int defaultSize) {
return WireHelpers.getWritableDataPointer(pointer,
segment,
capTable,
defaultBuffer,
defaultOffset,
defaultSize);
}

@Override
public final Builder fromPointerBuilder(SegmentBuilder segment, int pointer) {
public final Builder fromPointerBuilder(SegmentBuilder segment, CapTableBuilder capTable, int pointer) {
return WireHelpers.getWritableDataPointer(pointer,
segment,
capTable,
null, 0, 0);
}

@Override
public final Builder initFromPointerBuilder(SegmentBuilder segment, int pointer, int size) {
return WireHelpers.initDataPointer(pointer, segment, size);
public final Builder initFromPointerBuilder(SegmentBuilder segment, CapTableBuilder capTable, int pointer, int size) {
return WireHelpers.initDataPointer(pointer, segment, capTable, size);
}

@Override
public final void setPointerBuilder(SegmentBuilder segment, int pointer, Reader value) {
WireHelpers.setDataPointer(pointer, segment, value);
public final void setPointerBuilder(SegmentBuilder segment, CapTableBuilder capTable, int pointer, Reader value) {
WireHelpers.setDataPointer(pointer, segment, capTable, value);
}
}
public static final Factory factory = new Factory();
Expand Down
13 changes: 11 additions & 2 deletions runtime/src/main/java/org/capnproto/FromPointerBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,15 @@
package org.capnproto;

public interface FromPointerBuilder<T> {
T fromPointerBuilder(SegmentBuilder segment, int pointer);
T initFromPointerBuilder(SegmentBuilder segment, int pointer, int elementCount);
default T fromPointerBuilder(SegmentBuilder segment, int pointer) {
return fromPointerBuilder(segment, null, pointer);
}

T fromPointerBuilder(SegmentBuilder segment, CapTableBuilder capTable, int pointer);

default T initFromPointerBuilder(SegmentBuilder segment, int pointer, int elementCount) {
return initFromPointerBuilder(segment, null, pointer, elementCount);
}

T initFromPointerBuilder(SegmentBuilder segment, CapTableBuilder capTable, int pointer, int elementCount);
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@
package org.capnproto;

public interface FromPointerBuilderBlobDefault<T> {
T fromPointerBuilderBlobDefault(SegmentBuilder segment, int pointer,
default T fromPointerBuilderBlobDefault(SegmentBuilder segment, int pointer,
java.nio.ByteBuffer defaultBuffer, int defaultOffset, int defaultSize) {
return fromPointerBuilderBlobDefault(segment, null, pointer, defaultBuffer, defaultOffset, defaultSize);
}

T fromPointerBuilderBlobDefault(SegmentBuilder segment, CapTableBuilder capTable, int pointer,
java.nio.ByteBuffer defaultBuffer, int defaultOffset, int defaultSize);
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,10 @@
package org.capnproto;

public interface FromPointerBuilderRefDefault<T> {
T fromPointerBuilderRefDefault(SegmentBuilder segment, int pointer, SegmentReader defaultSegment, int defaultOffset);

default T fromPointerBuilderRefDefault(SegmentBuilder segment, int pointer, SegmentReader defaultSegment, int defaultOffset) {
return fromPointerBuilderRefDefault(segment, null, pointer, defaultSegment, defaultOffset);
}

T fromPointerBuilderRefDefault(SegmentBuilder segment, CapTableBuilder capTable, int pointer, SegmentReader defaultSegment, int defaultOffset);
}
5 changes: 4 additions & 1 deletion runtime/src/main/java/org/capnproto/FromPointerReader.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,8 @@
package org.capnproto;

public interface FromPointerReader<T> {
T fromPointerReader(SegmentReader segment, int pointer, int nestingLimit);
default T fromPointerReader(SegmentReader segment, int pointer, int nestingLimit) {
return fromPointerReader(segment, null, pointer, nestingLimit);
}
T fromPointerReader(SegmentReader segment, CapTableReader capTable, int pointer, int nestingLimit);
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,8 @@
package org.capnproto;

public interface FromPointerReaderRefDefault<T> {
T fromPointerReaderRefDefault(SegmentReader segment, int pointer, SegmentReader defaultSegment, int defaultOffset, int nestingLimit);
default T fromPointerReaderRefDefault(SegmentReader segment, int pointer, SegmentReader defaultSegment, int defaultOffset, int nestingLimit) {
return fromPointerReaderRefDefault(segment, null, pointer, defaultSegment, defaultOffset, nestingLimit);
}
T fromPointerReaderRefDefault(SegmentReader segment, CapTableReader capTable, int pointer, SegmentReader defaultSegment, int defaultOffset, int nestingLimit);
}
Loading

0 comments on commit 4e96569

Please sign in to comment.