Library cleanup (#1491)

* library cleanup

* remove fastcv

* Fix build step

* bump cereal

* bump cereal

* Install capnp

* bump

* no docker cache

* Update installation instructions

* Needs sudo

* Can we sudo?

* Cache was not the problem

* remove static libraries from boardd install script

* Update setup script

* Remove import

* No capnp install in lgtm

* Fix dockerfile
pull/1499/head
Willem Melching 2020-05-12 18:50:07 -07:00 committed by GitHub
parent 2ae2c40b29
commit 72db8d890d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
858 changed files with 17 additions and 297924 deletions

View File

@ -48,8 +48,8 @@ jobs:
cp -pR panda/ opendbc/ cereal/ $TEST_DIR
# need this to build on x86
cp -pR --parents phonelibs/capnp-cpp phonelibs/zmq phonelibs/libyuv phonelibs/snpe \
external/bin external/capnp selfdrive/modeld/runners $TEST_DIR
cp -pR --parents phonelibs/libyuv phonelibs/snpe \
external/bin selfdrive/modeld/runners $TEST_DIR
# need these so docker copy won't fail
cp Pipfile Pipfile.lock flake8_openpilot.sh pylint_openpilot.sh .pylintrc \
@ -198,4 +198,3 @@ jobs:
run: |
docker commit tmppilot tmppilotci
$CI_RUN "cd /tmp/openpilot && bash <(curl -s https://codecov.io/bash) -Z -F test_car_models"

View File

@ -5,6 +5,8 @@ RUN apt-get update && apt-get install -y \
autoconf \
build-essential \
bzip2 \
capnproto \
libcapnp-dev \
clang \
cmake \
curl \
@ -27,7 +29,8 @@ RUN apt-get update && apt-get install -y \
libsqlite3-dev \
libtool \
libusb-1.0-0-dev \
libzmq5-dev \
libczmq-dev \
libzmq3-dev \
locales \
ocl-icd-libopencl1 \
ocl-icd-opencl-dev \
@ -67,6 +70,7 @@ ENV PATH="/tmp/openpilot/external/bin:${PATH}"
ENV PYTHONPATH /tmp/openpilot:${PYTHONPATH}
RUN mkdir -p /tmp/openpilot
COPY ./flake8_openpilot.sh /tmp/openpilot/
COPY ./pylint_openpilot.sh /tmp/openpilot/
COPY ./.pylintrc /tmp/openpilot/

View File

@ -43,10 +43,9 @@ if arch == "aarch64" or arch == "larch64":
]
if arch == "larch64":
cpppath += ["#phonelibs/capnp-cpp/include"]
libpath += ["#phonelibs/snpe/larch64"]
libpath += ["#phonelibs/libyuv/larch64/lib"]
libpath += ["#external/capnparm/lib", "/usr/lib/aarch64-linux-gnu"]
libpath += ["/usr/lib/aarch64-linux-gnu"]
cflags = ["-DQCOM2", "-mcpu=cortex-a57"]
cxxflags = ["-DQCOM2", "-mcpu=cortex-a57"]
rpath = ["/usr/local/lib"]
@ -62,14 +61,11 @@ else:
"PATH": "#external/bin:" + os.environ['PATH'],
}
cpppath = [
"#phonelibs/capnp-cpp/include",
"#phonelibs/zmq/x64/include",
"#external/tensorflow/include",
]
if arch == "Darwin":
libpath = [
"#phonelibs/capnp-cpp/mac/lib",
"#phonelibs/libyuv/mac/lib",
"#cereal",
"#selfdrive/common",
@ -78,11 +74,8 @@ else:
]
else:
libpath = [
"#phonelibs/capnp-cpp/x64/lib",
"#phonelibs/snpe/x86_64-linux-clang",
"#phonelibs/zmq/x64/lib",
"#phonelibs/libyuv/x64/lib",
"#external/zmq/lib",
"#external/tensorflow/lib",
"#cereal",
"#selfdrive/common",
@ -90,8 +83,7 @@ else:
"/usr/local/lib",
]
rpath = ["phonelibs/capnp-cpp/x64/lib",
"phonelibs/zmq/x64/lib",
rpath = [
"external/tensorflow/lib",
"cereal",
"selfdrive/common"]
@ -189,10 +181,7 @@ def abspath(x):
return x[0].path.rsplit("/", 1)[1][:-3]
# still needed for apks
if arch == 'larch64':
zmq = 'zmq'
else:
zmq = FindFile("libzmq.a", libpath)
zmq = 'zmq'
Export('env', 'arch', 'zmq', 'SHARED', 'webcam')
# cereal and messaging are shared with the system

2
cereal

@ -1 +1 @@
Subproject commit 12aad06e12f249e57abda1664fb0c85e484a0c5d
Subproject commit 775f09de45353773f1fa697048be11c8317324b5

1
external/bin/capnp vendored
View File

@ -1 +0,0 @@
../capnp/bin/capnp

1
external/bin/capnpc vendored
View File

@ -1 +0,0 @@
../capnp/bin/capnpc

View File

@ -1 +0,0 @@
../capnp/bin/capnpc-c

View File

@ -1 +0,0 @@
../capnp/bin/capnpc-c++

View File

@ -1 +0,0 @@
../capnp/bin/capnpc-capnp

View File

@ -1 +0,0 @@
../capnp/bin/capnpc-java

View File

@ -1 +0,0 @@
capnproto-c++-0.6.1*

Binary file not shown.

View File

@ -1 +0,0 @@
capnp

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,32 +0,0 @@
set -e
echo "Installing capnp"
ONE=${HOME}/openpilot
VERSION=0.6.1
wget https://capnproto.org/capnproto-c++-${VERSION}.tar.gz
tar xvf capnproto-c++-${VERSION}.tar.gz
cd capnproto-c++-${VERSION}
CXXFLAGS="-fPIC" ./configure --prefix=${ONE}/external/capnp
make -j9
# manually build binaries statically
g++ -std=gnu++11 -I./src -I./src -DKJ_HEADER_WARNINGS -DCAPNP_HEADER_WARNINGS -DCAPNP_INCLUDE_DIR=\"/usr/local/include\" -pthread -O2 -DNDEBUG -pthread -pthread -o .libs/capnp src/capnp/compiler/module-loader.o src/capnp/compiler/capnp.o ./.libs/libcapnpc.a ./.libs/libcapnp.a ./.libs/libkj.a -lpthread -pthread
g++ -std=gnu++11 -I./src -I./src -DKJ_HEADER_WARNINGS -DCAPNP_HEADER_WARNINGS -DCAPNP_INCLUDE_DIR=\"/usr/local/include\" -pthread -O2 -DNDEBUG -pthread -pthread -o .libs/capnpc-c++ src/capnp/compiler/capnpc-c++.o ./.libs/libcapnp.a ./.libs/libkj.a -lpthread -pthread
g++ -std=gnu++11 -I./src -I./src -DKJ_HEADER_WARNINGS -DCAPNP_HEADER_WARNINGS -DCAPNP_INCLUDE_DIR=\"/usr/local/include\" -pthread -O2 -DNDEBUG -pthread -pthread -o .libs/capnpc-capnp src/capnp/compiler/capnpc-capnp.o ./.libs/libcapnp.a ./.libs/libkj.a -lpthread -pthread
make -j4 install
# --------
echo "Installing java-capnp"
git clone https://github.com/dwrensha/capnproto-java.git
cd capnproto-java
git reset --hard 2c43bd712fb218da0eabdf241a750b9c05903e8e
g++ compiler/src/main/cpp/capnpc-java.c++ -std=c++11 -pthread -I${ONE}/external/capnp/include -L${ONE}/external/capnp/lib -l:libcapnp.a -l:libkj.a -pthread -lpthread -o capnpc-java
cp capnpc-java ${ONE}/external/capnp/bin/
rm -rf capnproto-c++-${VERSION}.tar.gz
rm -rf capnproto-c++-${VERSION}

File diff suppressed because it is too large Load Diff

View File

@ -1,220 +0,0 @@
// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#ifndef CAPNP_BLOB_H_
#define CAPNP_BLOB_H_
#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS)
#pragma GCC system_header
#endif
#include <kj/common.h>
#include <kj/string.h>
#include "common.h"
#include <string.h>
namespace capnp {
struct Data {
Data() = delete;
class Reader;
class Builder;
class Pipeline {};
};
struct Text {
Text() = delete;
class Reader;
class Builder;
class Pipeline {};
};
class Data::Reader: public kj::ArrayPtr<const byte> {
// Points to a blob of bytes. The usual Reader rules apply -- Data::Reader behaves like a simple
// pointer which does not own its target, can be passed by value, etc.
public:
typedef Data Reads;
Reader() = default;
inline Reader(decltype(nullptr)): ArrayPtr<const byte>(nullptr) {}
inline Reader(const byte* value, size_t size): ArrayPtr<const byte>(value, size) {}
inline Reader(const kj::Array<const byte>& value): ArrayPtr<const byte>(value) {}
inline Reader(const ArrayPtr<const byte>& value): ArrayPtr<const byte>(value) {}
inline Reader(const kj::Array<byte>& value): ArrayPtr<const byte>(value) {}
inline Reader(const ArrayPtr<byte>& value): ArrayPtr<const byte>(value) {}
};
class Text::Reader: public kj::StringPtr {
// Like Data::Reader, but points at NUL-terminated UTF-8 text. The NUL terminator is not counted
// in the size but must be present immediately after the last byte.
//
// Text::Reader's interface contract is that its data MUST be NUL-terminated. The producer of
// the Text::Reader must guarantee this, so that the consumer need not check. The data SHOULD
// also be valid UTF-8, but this is NOT guaranteed -- the consumer must verify if it cares.
public:
typedef Text Reads;
Reader() = default;
inline Reader(decltype(nullptr)): StringPtr(nullptr) {}
inline Reader(const char* value): StringPtr(value) {}
inline Reader(const char* value, size_t size): StringPtr(value, size) {}
inline Reader(const kj::String& value): StringPtr(value) {}
inline Reader(const StringPtr& value): StringPtr(value) {}
#if KJ_COMPILER_SUPPORTS_STL_STRING_INTEROP
template <typename T, typename = decltype(kj::instance<T>().c_str())>
inline Reader(const T& t): StringPtr(t) {}
// Allow implicit conversion from any class that has a c_str() method (namely, std::string).
// We use a template trick to detect std::string in order to avoid including the header for
// those who don't want it.
#endif
};
class Data::Builder: public kj::ArrayPtr<byte> {
// Like Data::Reader except the pointers aren't const.
public:
typedef Data Builds;
Builder() = default;
inline Builder(decltype(nullptr)): ArrayPtr<byte>(nullptr) {}
inline Builder(byte* value, size_t size): ArrayPtr<byte>(value, size) {}
inline Builder(kj::Array<byte>& value): ArrayPtr<byte>(value) {}
inline Builder(ArrayPtr<byte> value): ArrayPtr<byte>(value) {}
inline Data::Reader asReader() const { return Data::Reader(*this); }
inline operator Reader() const { return asReader(); }
};
class Text::Builder: public kj::DisallowConstCopy {
// Basically identical to kj::StringPtr, except that the contents are non-const.
public:
inline Builder(): content(nulstr, 1) {}
inline Builder(decltype(nullptr)): content(nulstr, 1) {}
inline Builder(char* value): content(value, strlen(value) + 1) {}
inline Builder(char* value, size_t size): content(value, size + 1) {
KJ_IREQUIRE(value[size] == '\0', "StringPtr must be NUL-terminated.");
}
inline Reader asReader() const { return Reader(content.begin(), content.size() - 1); }
inline operator Reader() const { return asReader(); }
inline operator kj::ArrayPtr<char>();
inline kj::ArrayPtr<char> asArray();
inline operator kj::ArrayPtr<const char>() const;
inline kj::ArrayPtr<const char> asArray() const;
inline kj::ArrayPtr<byte> asBytes() { return asArray().asBytes(); }
inline kj::ArrayPtr<const byte> asBytes() const { return asArray().asBytes(); }
// Result does not include NUL terminator.
inline operator kj::StringPtr() const;
inline kj::StringPtr asString() const;
inline const char* cStr() const { return content.begin(); }
// Returns NUL-terminated string.
inline size_t size() const { return content.size() - 1; }
// Result does not include NUL terminator.
inline char operator[](size_t index) const { return content[index]; }
inline char& operator[](size_t index) { return content[index]; }
inline char* begin() { return content.begin(); }
inline char* end() { return content.end() - 1; }
inline const char* begin() const { return content.begin(); }
inline const char* end() const { return content.end() - 1; }
inline bool operator==(decltype(nullptr)) const { return content.size() <= 1; }
inline bool operator!=(decltype(nullptr)) const { return content.size() > 1; }
inline bool operator==(Builder other) const { return asString() == other.asString(); }
inline bool operator!=(Builder other) const { return asString() != other.asString(); }
inline bool operator< (Builder other) const { return asString() < other.asString(); }
inline bool operator> (Builder other) const { return asString() > other.asString(); }
inline bool operator<=(Builder other) const { return asString() <= other.asString(); }
inline bool operator>=(Builder other) const { return asString() >= other.asString(); }
inline kj::StringPtr slice(size_t start) const;
inline kj::ArrayPtr<const char> slice(size_t start, size_t end) const;
inline Builder slice(size_t start);
inline kj::ArrayPtr<char> slice(size_t start, size_t end);
// A string slice is only NUL-terminated if it is a suffix, so slice() has a one-parameter
// version that assumes end = size().
private:
inline explicit Builder(kj::ArrayPtr<char> content): content(content) {}
kj::ArrayPtr<char> content;
static char nulstr[1];
};
inline kj::StringPtr KJ_STRINGIFY(Text::Builder builder) {
return builder.asString();
}
inline bool operator==(const char* a, const Text::Builder& b) { return a == b.asString(); }
inline bool operator!=(const char* a, const Text::Builder& b) { return a != b.asString(); }
inline Text::Builder::operator kj::StringPtr() const {
return kj::StringPtr(content.begin(), content.size() - 1);
}
inline kj::StringPtr Text::Builder::asString() const {
return kj::StringPtr(content.begin(), content.size() - 1);
}
inline Text::Builder::operator kj::ArrayPtr<char>() {
return content.slice(0, content.size() - 1);
}
inline kj::ArrayPtr<char> Text::Builder::asArray() {
return content.slice(0, content.size() - 1);
}
inline Text::Builder::operator kj::ArrayPtr<const char>() const {
return content.slice(0, content.size() - 1);
}
inline kj::ArrayPtr<const char> Text::Builder::asArray() const {
return content.slice(0, content.size() - 1);
}
inline kj::StringPtr Text::Builder::slice(size_t start) const {
return asReader().slice(start);
}
inline kj::ArrayPtr<const char> Text::Builder::slice(size_t start, size_t end) const {
return content.slice(start, end);
}
inline Text::Builder Text::Builder::slice(size_t start) {
return Text::Builder(content.slice(start, content.size()));
}
inline kj::ArrayPtr<char> Text::Builder::slice(size_t start, size_t end) {
return content.slice(start, end);
}
} // namespace capnp
#endif // CAPNP_BLOB_H_

View File

@ -1,26 +0,0 @@
# Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
# Licensed under the MIT License:
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
@0xbdf87d7bb8304e81;
$namespace("capnp::annotations");
annotation namespace(file): Text;
annotation name(field, enumerant, struct, enum, interface, method, param, group, union): Text;

View File

@ -1,33 +0,0 @@
// Generated by Cap'n Proto compiler, DO NOT EDIT
// source: c++.capnp
#ifndef CAPNP_INCLUDED_bdf87d7bb8304e81_
#define CAPNP_INCLUDED_bdf87d7bb8304e81_
#include <capnp/generated-header-support.h>
#if CAPNP_VERSION != 6001
#error "Version mismatch between generated code and library headers. You must use the same version of the Cap'n Proto compiler and library."
#endif
namespace capnp {
namespace schemas {
CAPNP_DECLARE_SCHEMA(b9c6f99ebf805f2c);
CAPNP_DECLARE_SCHEMA(f264a779fef191ce);
} // namespace schemas
} // namespace capnp
namespace capnp {
namespace annotations {
// =======================================================================================
// =======================================================================================
} // namespace
} // namespace
#endif // CAPNP_INCLUDED_bdf87d7bb8304e81_

View File

@ -1,37 +0,0 @@
# Copyright (c) 2016 NetDEF, Inc. and contributors
# Licensed under the MIT License:
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
@0xc0183dd65ffef0f3;
annotation nameinfix @0x85a8d86d736ba637 (file): Text;
# add an infix (middle insert) for output file names
#
# "make" generally has implicit rules for compiling "foo.c" => "foo". This
# is very annoying with capnp since the rule will be "foo" => "foo.c", leading
# to a loop. $nameinfix (recommended parameter: "-gen") inserts its parameter
# before the ".c", so the filename becomes "foo-gen.c"
#
# ("foo" is really "foo.capnp", so it's foo.capnp-gen.c)
annotation fieldgetset @0xf72bc690355d66de (file): Void;
# generate getter & setter functions for accessing fields
#
# allows grabbing/putting values without de-/encoding the entire struct.

View File

@ -1,884 +0,0 @@
// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#ifndef CAPNP_CAPABILITY_H_
#define CAPNP_CAPABILITY_H_
#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS)
#pragma GCC system_header
#endif
#if CAPNP_LITE
#error "RPC APIs, including this header, are not available in lite mode."
#endif
#include <kj/async.h>
#include <kj/vector.h>
#include "raw-schema.h"
#include "any.h"
#include "pointer-helpers.h"
namespace capnp {
template <typename Results>
class Response;
template <typename T>
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<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<Response<T>>(nullptr),
T::Pipeline(nullptr) {}
KJ_DISALLOW_COPY(RemotePromise);
RemotePromise(RemotePromise&& other) = default;
RemotePromise& operator=(RemotePromise&& other) = default;
};
class LocalClient;
namespace _ { // private
extern const RawSchema NULL_INTERFACE_SCHEMA; // defined in schema.c++
class CapabilityServerSetBase;
} // namespace _ (private)
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;
struct _capnpPrivate {
struct IsInterface;
static constexpr uint64_t typeId = 0x3;
static constexpr Kind kind = Kind::INTERFACE;
static constexpr _::RawSchema const* schema = &_::NULL_INTERFACE_SCHEMA;
static const _::RawBrandedSchema* brand() {
return &_::NULL_INTERFACE_SCHEMA.defaultBrand;
}
};
};
// =======================================================================================
// Capability clients
class RequestHook;
class ResponseHook;
class PipelineHook;
class ClientHook;
template <typename Params, typename Results>
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> fooRequest()` (as well as a convenience method
// `RemotePromise<C> foo(A::Reader a, B::Reader b)`).
public:
inline Request(typename Params::Builder builder, kj::Own<RequestHook>&& hook)
: Params::Builder(builder), hook(kj::mv(hook)) {}
inline Request(decltype(nullptr)): Params::Builder(nullptr) {}
RemotePromise<Results> send() KJ_WARN_UNUSED_RESULT;
// Send the call and return a promise for the results.
private:
kj::Own<RequestHook> hook;
friend class Capability::Client;
friend struct DynamicCapability;
template <typename, typename>
friend class CallContext;
friend class RequestHook;
};
template <typename Results>
class Response: public Results::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 Results::Reader reader, kj::Own<ResponseHook>&& hook)
: Results::Reader(reader), hook(kj::mv(hook)) {}
private:
kj::Own<ResponseHook> hook;
template <typename, typename>
friend class Request;
friend class ResponseHook;
};
class Capability::Client {
// Base type for capability clients.
public:
typedef Capability Reads;
typedef Capability Calls;
Client(decltype(nullptr));
// If you need to declare a Client before you have anything to assign to it (perhaps because
// the assignment is going to occur in an if/else scope), you can start by initializing it to
// `nullptr`. The resulting client is not meant to be called and throws exceptions from all
// methods.
template <typename T, typename = kj::EnableIf<kj::canConvert<T*, Capability::Server*>()>>
Client(kj::Own<T>&& server);
// Make a client capability that wraps the given server capability. The server's methods will
// only be executed in the given EventLoop, regardless of what thread calls the client's methods.
template <typename T, typename = kj::EnableIf<kj::canConvert<T*, Client*>()>>
Client(kj::Promise<T>&& promise);
// Make a client from a promise for a future client. The resulting client queues calls until the
// promise resolves.
Client(kj::Exception&& exception);
// Make a broken client that throws the given exception from all calls.
Client(Client& other);
Client& operator=(Client& other);
// Copies by reference counting. Warning: This refcounting is not thread-safe. All copies of
// the client must remain in one thread.
Client(Client&&) = default;
Client& operator=(Client&&) = default;
// Move constructor avoids reference counting.
explicit Client(kj::Own<ClientHook>&& hook);
// For use by the RPC implementation: Wrap a ClientHook.
template <typename T>
typename T::Client castAs();
// Reinterpret the capability as implementing the given interface. Note that no error will occur
// here if the capability does not actually implement this interface, but later method calls will
// fail. It's up to the application to decide how indicate that additional interfaces are
// supported.
//
// TODO(perf): GCC 4.8 / Clang 3.3: rvalue-qualified version for better performance.
template <typename T>
typename T::Client castAs(InterfaceSchema schema);
// Dynamic version. `T` must be `DynamicCapability`, and you must `#include <capnp/dynamic.h>`.
kj::Promise<void> whenResolved();
// 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.
Request<AnyPointer, AnyPointer> typelessRequest(
uint64_t interfaceId, uint16_t methodId,
kj::Maybe<MessageSize> sizeHint);
// Make a request without knowing the types of the params or results. You specify the type ID
// and method number manually.
// TODO(someday): method(s) for Join
protected:
Client() = default;
template <typename Params, typename Results>
Request<Params, Results> newCall(uint64_t interfaceId, uint16_t methodId,
kj::Maybe<MessageSize> sizeHint);
private:
kj::Own<ClientHook> hook;
static kj::Own<ClientHook> makeLocalClient(kj::Own<Capability::Server>&& server);
template <typename, Kind>
friend struct _::PointerHelpers;
friend struct DynamicCapability;
friend class Orphanage;
friend struct DynamicStruct;
friend struct DynamicList;
template <typename, Kind>
friend struct List;
friend class _::CapabilityServerSetBase;
friend class ClientHook;
};
// =======================================================================================
// Capability servers
class CallContextHook;
template <typename Params, typename Results>
class CallContext: public kj::DisallowConstCopy {
// Wrapper around CallContextHook with a specific return type.
//
// Methods of this class may only be called from within the server's event loop, not from other
// threads.
//
// The CallContext becomes invalid as soon as the call reports completion.
public:
explicit CallContext(CallContextHook& hook);
typename Params::Reader getParams();
// Get the params payload.
void releaseParams();
// Release the params payload. getParams() will throw an exception after this is called.
// Releasing the params may allow the RPC system to free up buffer space to handle other
// requests. Long-running asynchronous methods should try to call this as early as is
// convenient.
typename Results::Builder getResults(kj::Maybe<MessageSize> sizeHint = nullptr);
typename Results::Builder initResults(kj::Maybe<MessageSize> sizeHint = nullptr);
void setResults(typename Results::Reader value);
void adoptResults(Orphan<Results>&& value);
Orphanage getResultsOrphanage(kj::Maybe<MessageSize> sizeHint = nullptr);
// Manipulate the results 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).
//
// `sizeHint` indicates a guess at the message size. This will usually be used to decide how
// much space to allocate for the first message segment (don't worry: only space that is actually
// used will be sent on the wire). If omitted, the system decides. The message root pointer
// should not be included in the size. So, if you are simply going to copy some existing message
// directly into the results, just call `.totalSize()` and pass that in.
template <typename SubParams>
kj::Promise<void> tailCall(Request<SubParams, Results>&& tailRequest);
// Resolve the call by making a tail call. `tailRequest` is a request that has been filled in
// but not yet sent. The context will send the call, then fill in the results with the result
// of the call. If tailCall() is used, {get,init,set,adopt}Results (above) *must not* be called.
//
// The RPC implementation may be able to optimize a tail call to another machine such that the
// results never actually pass through this machine. Even if no such optimization is possible,
// `tailCall()` may allow pipelined calls to be forwarded optimistically to the new call site.
//
// In general, this should be the last thing a method implementation calls, and the promise
// returned from `tailCall()` should then be returned by the method implementation.
void allowCancellation();
// 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.
//
// 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().evalLater()` to yield control.
//
// Note: You might think that we should offer `onCancel()` and/or `isCanceled()` methods that
// provide notification when the caller cancels the request without forcefully killing off the
// promise chain. Unfortunately, this composes poorly with promise forking: the canceled
// path may be just one branch of a fork of the result promise. The other branches still want
// the call to continue. Promise forking is used within the Cap'n Proto implementation -- in
// particular each pipelined call forks the result promise. So, if a caller made a pipelined
// call and then dropped the original object, the call should not be canceled, but it would be
// excessively complicated for the framework to avoid notififying of cancellation as long as
// pipelined calls still exist.
private:
CallContextHook* hook;
friend class Capability::Server;
friend struct DynamicCapability;
};
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:
typedef Capability Serves;
virtual kj::Promise<void> dispatchCall(uint64_t interfaceId, uint16_t methodId,
CallContext<AnyPointer, AnyPointer> 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(someday): Method which can optionally be overridden to implement Join when the object is
// a proxy.
protected:
inline Capability::Client thisCap();
// Get a capability pointing to this object, much like the `this` keyword.
//
// The effect of this method is undefined if:
// - No capability client has been created pointing to this object. (This is always the case in
// the server's constructor.)
// - The capability client pointing at this object has been destroyed. (This is always the case
// in the server's destructor.)
// - Multiple capability clients have been created around the same server (possible if the server
// is refcounted, which is not recommended since the client itself provides refcounting).
template <typename Params, typename Results>
CallContext<Params, Results> internalGetTypedContext(
CallContext<AnyPointer, AnyPointer> typeless);
kj::Promise<void> internalUnimplemented(const char* actualInterfaceName,
uint64_t requestedTypeId);
kj::Promise<void> internalUnimplemented(const char* interfaceName,
uint64_t typeId, uint16_t methodId);
kj::Promise<void> internalUnimplemented(const char* interfaceName, const char* methodName,
uint64_t typeId, uint16_t methodId);
private:
ClientHook* thisHook = nullptr;
friend class LocalClient;
};
// =======================================================================================
class ReaderCapabilityTable: private _::CapTableReader {
// Class which imbues Readers with the ability to read capabilities.
//
// In Cap'n Proto format, the encoding of a capability pointer is simply an integer index into
// an external table. Since these pointers fundamentally point outside the message, a
// MessageReader by default has no idea what they point at, and therefore reading capabilities
// from such a reader will throw exceptions.
//
// In order to be able to read capabilities, you must first attach a capability table, using
// this class. By "imbuing" a Reader, you get a new Reader which will interpret capability
// pointers by treating them as indexes into the ReaderCapabilityTable.
//
// Note that when using Cap'n Proto's RPC system, this is handled automatically.
public:
explicit ReaderCapabilityTable(kj::Array<kj::Maybe<kj::Own<ClientHook>>> table);
KJ_DISALLOW_COPY(ReaderCapabilityTable);
template <typename T>
T imbue(T reader);
// Return a reader equivalent to `reader` except that when reading capability-valued fields,
// the capabilities are looked up in this table.
private:
kj::Array<kj::Maybe<kj::Own<ClientHook>>> table;
kj::Maybe<kj::Own<ClientHook>> extractCap(uint index) override;
};
class BuilderCapabilityTable: private _::CapTableBuilder {
// Class which imbues Builders with the ability to read and write capabilities.
//
// This is much like ReaderCapabilityTable, except for builders. The table starts out empty,
// but capabilities can be added to it over time.
public:
BuilderCapabilityTable();
KJ_DISALLOW_COPY(BuilderCapabilityTable);
inline kj::ArrayPtr<kj::Maybe<kj::Own<ClientHook>>> getTable() { return table; }
template <typename T>
T imbue(T builder);
// Return a builder equivalent to `builder` except that when reading capability-valued fields,
// the capabilities are looked up in this table.
private:
kj::Vector<kj::Maybe<kj::Own<ClientHook>>> table;
kj::Maybe<kj::Own<ClientHook>> extractCap(uint index) override;
uint injectCap(kj::Own<ClientHook>&& cap) override;
void dropCap(uint index) override;
};
// =======================================================================================
namespace _ { // private
class CapabilityServerSetBase {
public:
Capability::Client addInternal(kj::Own<Capability::Server>&& server, void* ptr);
kj::Promise<void*> getLocalServerInternal(Capability::Client& client);
};
} // namespace _ (private)
template <typename T>
class CapabilityServerSet: private _::CapabilityServerSetBase {
// Allows a server to recognize its own capabilities when passed back to it, and obtain the
// underlying Server objects associated with them.
//
// All objects in the set must have the same interface type T. The objects may implement various
// interfaces derived from T (and in fact T can be `capnp::Capability` to accept all objects),
// but note that if you compile with RTTI disabled then you will not be able to down-cast through
// virtual inheritance, and all inheritance between server interfaces is virtual. So, with RTTI
// disabled, you will likely need to set T to be the most-derived Cap'n Proto interface type,
// and you server class will need to be directly derived from that, so that you can use
// static_cast (or kj::downcast) to cast to it after calling getLocalServer(). (If you compile
// with RTTI, then you can freely dynamic_cast and ignore this issue!)
public:
CapabilityServerSet() = default;
KJ_DISALLOW_COPY(CapabilityServerSet);
typename T::Client add(kj::Own<typename T::Server>&& server);
// Create a new capability Client for the given Server and also add this server to the set.
kj::Promise<kj::Maybe<typename T::Server&>> getLocalServer(typename T::Client& client);
// Given a Client pointing to a server previously passed to add(), return the corresponding
// Server. This returns a promise because if the input client is itself a promise, this must
// wait for it to resolve. Keep in mind that the server will be deleted when all clients are
// gone, so the caller should make sure to keep the client alive (hence why this method only
// accepts an lvalue input).
};
// =======================================================================================
// 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.
class RequestHook {
// Hook interface implemented by RPC system representing a request being built.
public:
virtual RemotePromise<AnyPointer> send() = 0;
// Send the call and return a promise for the result.
virtual const void* getBrand() = 0;
// Returns a void* that identifies who made this request. This can be used by an RPC adapter to
// discover when tail call is going to be sent over its own connection and therefore can be
// optimized into a remote tail call.
template <typename T, typename U>
inline static kj::Own<RequestHook> from(Request<T, U>&& request) {
return kj::mv(request.hook);
}
};
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 results can be freed.
public:
virtual ~ResponseHook() noexcept(false);
// Just here to make sure the type is dynamic.
template <typename T>
inline static kj::Own<ResponseHook> from(Response<T>&& response) {
return kj::mv(response.hook);
}
};
// class PipelineHook is declared in any.h because it is needed there.
class ClientHook {
public:
ClientHook();
virtual Request<AnyPointer, AnyPointer> newCall(
uint64_t interfaceId, uint16_t methodId, kj::Maybe<MessageSize> sizeHint) = 0;
// Start a new call, allowing the client to allocate request/response objects as it sees fit.
// This version is used when calls are made from application code in the local process.
struct VoidPromiseAndPipeline {
kj::Promise<void> promise;
kj::Own<PipelineHook> pipeline;
};
virtual VoidPromiseAndPipeline call(uint64_t interfaceId, uint16_t methodId,
kj::Own<CallContextHook>&& context) = 0;
// Call the object, but the caller controls allocation of the request/response objects. If the
// callee insists on allocating these objects itself, it must make a copy. This version is used
// when calls come in over the network via an RPC system. Note that even if the returned
// `Promise<void>` is discarded, the call may continue executing if any pipelined calls are
// waiting for it.
//
// Since the caller of this method chooses the CallContext implementation, it is the caller's
// responsibility to ensure that the returned promise is not canceled unless allowed via
// the context's `allowCancellation()`.
//
// The call must not begin synchronously; the callee must arrange for the call to begin in a
// later turn of the event loop. Otherwise, application code may call back and affect the
// callee's state in an unexpected way.
virtual kj::Maybe<ClientHook&> getResolved() = 0;
// If this ClientHook is a promise that has already resolved, returns the inner, resolved version
// of the capability. The caller may permanently replace this client with the resolved one if
// desired. Returns null if the client isn't a promise or hasn't resolved yet -- use
// `whenMoreResolved()` to distinguish between them.
virtual kj::Maybe<kj::Promise<kj::Own<ClientHook>>> whenMoreResolved() = 0;
// If this client is a settled reference (not a promise), return nullptr. Otherwise, return a
// promise that eventually resolves to a new client that is closer to being the final, settled
// client (i.e. the value eventually returned by `getResolved()`). Calling this repeatedly
// should eventually produce a settled client.
kj::Promise<void> whenResolved();
// Repeatedly calls whenMoreResolved() until it returns nullptr.
virtual kj::Own<ClientHook> addRef() = 0;
// Return a new reference to the same capability.
virtual const void* getBrand() = 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.
static const uint NULL_CAPABILITY_BRAND;
// Value is irrelevant; used for pointer.
inline bool isNull() { return getBrand() == &NULL_CAPABILITY_BRAND; }
// 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.
virtual void* getLocalServer(_::CapabilityServerSetBase& capServerSet);
// If this is a local capability created through `capServerSet`, return the underlying Server.
// Otherwise, return nullptr. Default implementation (which everyone except LocalClient should
// use) always returns nullptr.
static kj::Own<ClientHook> from(Capability::Client client) { return kj::mv(client.hook); }
};
class CallContextHook {
// Hook interface implemented by RPC system to manage a call on the server side. See
// CallContext<T>.
public:
virtual AnyPointer::Reader getParams() = 0;
virtual void releaseParams() = 0;
virtual AnyPointer::Builder getResults(kj::Maybe<MessageSize> sizeHint) = 0;
virtual kj::Promise<void> tailCall(kj::Own<RequestHook>&& request) = 0;
virtual void allowCancellation() = 0;
virtual kj::Promise<AnyPointer::Pipeline> onTailCall() = 0;
// If `tailCall()` is called, resolves to the PipelineHook from the tail call. An
// implementation of `ClientHook::call()` is allowed to call this at most once.
virtual ClientHook::VoidPromiseAndPipeline directTailCall(kj::Own<RequestHook>&& request) = 0;
// Call this when you would otherwise call onTailCall() immediately followed by tailCall().
// Implementations of tailCall() should typically call directTailCall() and then fulfill the
// promise fulfiller for onTailCall() with the returned pipeline.
virtual kj::Own<CallContextHook> addRef() = 0;
};
kj::Own<ClientHook> newLocalPromiseClient(kj::Promise<kj::Own<ClientHook>>&& promise);
// Returns a ClientHook that queues up calls until `promise` resolves, then forwards them to
// the new client. This hook's `getResolved()` and `whenMoreResolved()` methods will reflect the
// redirection to the eventual replacement client.
kj::Own<PipelineHook> newLocalPromisePipeline(kj::Promise<kj::Own<PipelineHook>>&& promise);
// Returns a PipelineHook that queues up calls until `promise` resolves, then forwards them to
// the new pipeline.
kj::Own<ClientHook> newBrokenCap(kj::StringPtr reason);
kj::Own<ClientHook> newBrokenCap(kj::Exception&& reason);
// Helper function that creates a capability which simply throws exceptions when called.
kj::Own<PipelineHook> newBrokenPipeline(kj::Exception&& reason);
// Helper function that creates a pipeline which simply throws exceptions when called.
Request<AnyPointer, AnyPointer> newBrokenRequest(
kj::Exception&& reason, kj::Maybe<MessageSize> sizeHint);
// Helper function that creates a Request object that simply throws exceptions when sent.
// =======================================================================================
// Extend PointerHelpers for interfaces
namespace _ { // private
template <typename T>
struct PointerHelpers<T, Kind::INTERFACE> {
static inline typename T::Client get(PointerReader reader) {
return typename T::Client(reader.getCapability());
}
static inline typename T::Client get(PointerBuilder builder) {
return typename T::Client(builder.getCapability());
}
static inline void set(PointerBuilder builder, typename T::Client&& value) {
builder.setCapability(kj::mv(value.Capability::Client::hook));
}
static inline void set(PointerBuilder builder, typename T::Client& value) {
builder.setCapability(value.Capability::Client::hook->addRef());
}
static inline void adopt(PointerBuilder builder, Orphan<T>&& value) {
builder.adopt(kj::mv(value.builder));
}
static inline Orphan<T> disown(PointerBuilder builder) {
return Orphan<T>(builder.disown());
}
};
} // namespace _ (private)
// =======================================================================================
// Extend List for interfaces
template <typename T>
struct List<T, Kind::INTERFACE> {
List() = delete;
class Reader {
public:
typedef List<T> Reads;
Reader() = default;
inline explicit Reader(_::ListReader reader): reader(reader) {}
inline uint size() const { return unbound(reader.size() / ELEMENTS); }
inline typename T::Client operator[](uint index) const {
KJ_IREQUIRE(index < size());
return typename T::Client(reader.getPointerElement(
bounded(index) * ELEMENTS).getCapability());
}
typedef _::IndexingIterator<const Reader, typename T::Client> Iterator;
inline Iterator begin() const { return Iterator(this, 0); }
inline Iterator end() const { return Iterator(this, size()); }
private:
_::ListReader reader;
template <typename U, Kind K>
friend struct _::PointerHelpers;
template <typename U, Kind K>
friend struct List;
friend class Orphanage;
template <typename U, Kind K>
friend struct ToDynamic_;
};
class Builder {
public:
typedef List<T> Builds;
Builder() = delete;
inline Builder(decltype(nullptr)) {}
inline explicit Builder(_::ListBuilder builder): builder(builder) {}
inline operator Reader() const { return Reader(builder.asReader()); }
inline Reader asReader() const { return Reader(builder.asReader()); }
inline uint size() const { return unbound(builder.size() / ELEMENTS); }
inline typename T::Client operator[](uint index) {
KJ_IREQUIRE(index < size());
return typename T::Client(builder.getPointerElement(
bounded(index) * ELEMENTS).getCapability());
}
inline void set(uint index, typename T::Client value) {
KJ_IREQUIRE(index < size());
builder.getPointerElement(bounded(index) * ELEMENTS).setCapability(kj::mv(value.hook));
}
inline void adopt(uint index, Orphan<T>&& value) {
KJ_IREQUIRE(index < size());
builder.getPointerElement(bounded(index) * ELEMENTS).adopt(kj::mv(value));
}
inline Orphan<T> disown(uint index) {
KJ_IREQUIRE(index < size());
return Orphan<T>(builder.getPointerElement(bounded(index) * ELEMENTS).disown());
}
typedef _::IndexingIterator<Builder, typename T::Client> Iterator;
inline Iterator begin() { return Iterator(this, 0); }
inline Iterator end() { return Iterator(this, size()); }
private:
_::ListBuilder builder;
friend class Orphanage;
template <typename U, Kind K>
friend struct ToDynamic_;
};
private:
inline static _::ListBuilder initPointer(_::PointerBuilder builder, uint size) {
return builder.initList(ElementSize::POINTER, bounded(size) * ELEMENTS);
}
inline static _::ListBuilder getFromPointer(_::PointerBuilder builder, const word* defaultValue) {
return builder.getList(ElementSize::POINTER, defaultValue);
}
inline static _::ListReader getFromPointer(
const _::PointerReader& reader, const word* defaultValue) {
return reader.getList(ElementSize::POINTER, defaultValue);
}
template <typename U, Kind k>
friend struct List;
template <typename U, Kind K>
friend struct _::PointerHelpers;
};
// =======================================================================================
// Inline implementation details
template <typename Params, typename Results>
RemotePromise<Results> Request<Params, Results>::send() {
auto typelessPromise = hook->send();
hook = nullptr; // prevent reuse
// 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<AnyPointer>>&>(typelessPromise)
.then([](Response<AnyPointer>&& response) -> Response<Results> {
return Response<Results>(response.getAs<Results>(), kj::mv(response.hook));
});
// Wrap the typeless pipeline in a typed wrapper.
typename Results::Pipeline typedPipeline(
kj::mv(kj::implicitCast<AnyPointer::Pipeline&>(typelessPromise)));
return RemotePromise<Results>(kj::mv(typedPromise), kj::mv(typedPipeline));
}
inline Capability::Client::Client(kj::Own<ClientHook>&& hook): hook(kj::mv(hook)) {}
template <typename T, typename>
inline Capability::Client::Client(kj::Own<T>&& server)
: hook(makeLocalClient(kj::mv(server))) {}
template <typename T, typename>
inline Capability::Client::Client(kj::Promise<T>&& promise)
: hook(newLocalPromiseClient(promise.then([](T&& t) { return kj::mv(t.hook); }))) {}
inline Capability::Client::Client(Client& other): hook(other.hook->addRef()) {}
inline Capability::Client& Capability::Client::operator=(Client& other) {
hook = other.hook->addRef();
return *this;
}
template <typename T>
inline typename T::Client Capability::Client::castAs() {
return typename T::Client(hook->addRef());
}
inline kj::Promise<void> Capability::Client::whenResolved() {
return hook->whenResolved();
}
inline Request<AnyPointer, AnyPointer> Capability::Client::typelessRequest(
uint64_t interfaceId, uint16_t methodId,
kj::Maybe<MessageSize> sizeHint) {
return newCall<AnyPointer, AnyPointer>(interfaceId, methodId, sizeHint);
}
template <typename Params, typename Results>
inline Request<Params, Results> Capability::Client::newCall(
uint64_t interfaceId, uint16_t methodId, kj::Maybe<MessageSize> sizeHint) {
auto typeless = hook->newCall(interfaceId, methodId, sizeHint);
return Request<Params, Results>(typeless.template getAs<Params>(), kj::mv(typeless.hook));
}
template <typename Params, typename Results>
inline CallContext<Params, Results>::CallContext(CallContextHook& hook): hook(&hook) {}
template <typename Params, typename Results>
inline typename Params::Reader CallContext<Params, Results>::getParams() {
return hook->getParams().template getAs<Params>();
}
template <typename Params, typename Results>
inline void CallContext<Params, Results>::releaseParams() {
hook->releaseParams();
}
template <typename Params, typename Results>
inline typename Results::Builder CallContext<Params, Results>::getResults(
kj::Maybe<MessageSize> sizeHint) {
// `template` keyword needed due to: http://llvm.org/bugs/show_bug.cgi?id=17401
return hook->getResults(sizeHint).template getAs<Results>();
}
template <typename Params, typename Results>
inline typename Results::Builder CallContext<Params, Results>::initResults(
kj::Maybe<MessageSize> sizeHint) {
// `template` keyword needed due to: http://llvm.org/bugs/show_bug.cgi?id=17401
return hook->getResults(sizeHint).template initAs<Results>();
}
template <typename Params, typename Results>
inline void CallContext<Params, Results>::setResults(typename Results::Reader value) {
hook->getResults(value.totalSize()).template setAs<Results>(value);
}
template <typename Params, typename Results>
inline void CallContext<Params, Results>::adoptResults(Orphan<Results>&& value) {
hook->getResults(nullptr).adopt(kj::mv(value));
}
template <typename Params, typename Results>
inline Orphanage CallContext<Params, Results>::getResultsOrphanage(
kj::Maybe<MessageSize> sizeHint) {
return Orphanage::getForMessageContaining(hook->getResults(sizeHint));
}
template <typename Params, typename Results>
template <typename SubParams>
inline kj::Promise<void> CallContext<Params, Results>::tailCall(
Request<SubParams, Results>&& tailRequest) {
return hook->tailCall(kj::mv(tailRequest.hook));
}
template <typename Params, typename Results>
inline void CallContext<Params, Results>::allowCancellation() {
hook->allowCancellation();
}
template <typename Params, typename Results>
CallContext<Params, Results> Capability::Server::internalGetTypedContext(
CallContext<AnyPointer, AnyPointer> typeless) {
return CallContext<Params, Results>(*typeless.hook);
}
Capability::Client Capability::Server::thisCap() {
return Client(thisHook->addRef());
}
template <typename T>
T ReaderCapabilityTable::imbue(T reader) {
return T(_::PointerHelpers<FromReader<T>>::getInternalReader(reader).imbue(this));
}
template <typename T>
T BuilderCapabilityTable::imbue(T builder) {
return T(_::PointerHelpers<FromBuilder<T>>::getInternalBuilder(kj::mv(builder)).imbue(this));
}
template <typename T>
typename T::Client CapabilityServerSet<T>::add(kj::Own<typename T::Server>&& server) {
void* ptr = reinterpret_cast<void*>(server.get());
// Clang insists that `castAs` is a template-dependent member and therefore we need the
// `template` keyword here, but AFAICT this is wrong: addImpl() is not a template.
return addInternal(kj::mv(server), ptr).template castAs<T>();
}
template <typename T>
kj::Promise<kj::Maybe<typename T::Server&>> CapabilityServerSet<T>::getLocalServer(
typename T::Client& client) {
return getLocalServerInternal(client)
.then([](void* server) -> kj::Maybe<typename T::Server&> {
if (server == nullptr) {
return nullptr;
} else {
return *reinterpret_cast<typename T::Server*>(server);
}
});
}
template <typename T>
struct Orphanage::GetInnerReader<T, Kind::INTERFACE> {
static inline kj::Own<ClientHook> apply(typename T::Client t) {
return ClientHook::from(kj::mv(t));
}
};
} // namespace capnp
#endif // CAPNP_CAPABILITY_H_

View File

@ -1,723 +0,0 @@
// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
// This file contains types which are intended to help detect incorrect usage at compile
// time, but should then be optimized down to basic primitives (usually, integers) by the
// compiler.
#ifndef CAPNP_COMMON_H_
#define CAPNP_COMMON_H_
#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS)
#pragma GCC system_header
#endif
#include <inttypes.h>
#include <kj/string.h>
#include <kj/memory.h>
#if CAPNP_DEBUG_TYPES
#include <kj/units.h>
#endif
namespace capnp {
#define CAPNP_VERSION_MAJOR 0
#define CAPNP_VERSION_MINOR 6
#define CAPNP_VERSION_MICRO 1
#define CAPNP_VERSION \
(CAPNP_VERSION_MAJOR * 1000000 + CAPNP_VERSION_MINOR * 1000 + CAPNP_VERSION_MICRO)
#ifndef CAPNP_LITE
#define CAPNP_LITE 0
#endif
typedef unsigned int uint;
struct Void {
// Type used for Void fields. Using C++'s "void" type creates a bunch of issues since it behaves
// differently from other types.
inline constexpr bool operator==(Void other) const { return true; }
inline constexpr bool operator!=(Void other) const { return false; }
};
static constexpr Void VOID = Void();
// Constant value for `Void`, which is an empty struct.
inline kj::StringPtr KJ_STRINGIFY(Void) { return "void"; }
struct Text;
struct Data;
enum class Kind: uint8_t {
PRIMITIVE,
BLOB,
ENUM,
STRUCT,
UNION,
INTERFACE,
LIST,
OTHER
// Some other type which is often a type parameter to Cap'n Proto templates, but which needs
// special handling. This includes types like AnyPointer, Dynamic*, etc.
};
enum class Style: uint8_t {
PRIMITIVE,
POINTER, // other than struct
STRUCT,
CAPABILITY
};
enum class ElementSize: uint8_t {
// Size of a list element.
VOID = 0,
BIT = 1,
BYTE = 2,
TWO_BYTES = 3,
FOUR_BYTES = 4,
EIGHT_BYTES = 5,
POINTER = 6,
INLINE_COMPOSITE = 7
};
enum class PointerType {
// Various wire types a pointer field can take
NULL_,
// Should be NULL, but that's #defined in stddef.h
STRUCT,
LIST,
CAPABILITY
};
namespace schemas {
template <typename T>
struct EnumInfo;
} // namespace schemas
namespace _ { // private
template <typename T, typename = void> struct Kind_;
template <> struct Kind_<Void> { static constexpr Kind kind = Kind::PRIMITIVE; };
template <> struct Kind_<bool> { static constexpr Kind kind = Kind::PRIMITIVE; };
template <> struct Kind_<int8_t> { static constexpr Kind kind = Kind::PRIMITIVE; };
template <> struct Kind_<int16_t> { static constexpr Kind kind = Kind::PRIMITIVE; };
template <> struct Kind_<int32_t> { static constexpr Kind kind = Kind::PRIMITIVE; };
template <> struct Kind_<int64_t> { static constexpr Kind kind = Kind::PRIMITIVE; };
template <> struct Kind_<uint8_t> { static constexpr Kind kind = Kind::PRIMITIVE; };
template <> struct Kind_<uint16_t> { static constexpr Kind kind = Kind::PRIMITIVE; };
template <> struct Kind_<uint32_t> { static constexpr Kind kind = Kind::PRIMITIVE; };
template <> struct Kind_<uint64_t> { static constexpr Kind kind = Kind::PRIMITIVE; };
template <> struct Kind_<float> { static constexpr Kind kind = Kind::PRIMITIVE; };
template <> struct Kind_<double> { static constexpr Kind kind = Kind::PRIMITIVE; };
template <> struct Kind_<Text> { static constexpr Kind kind = Kind::BLOB; };
template <> struct Kind_<Data> { static constexpr Kind kind = Kind::BLOB; };
template <typename T> struct Kind_<T, kj::VoidSfinae<typename T::_capnpPrivate::IsStruct>> {
static constexpr Kind kind = Kind::STRUCT;
};
template <typename T> struct Kind_<T, kj::VoidSfinae<typename T::_capnpPrivate::IsInterface>> {
static constexpr Kind kind = Kind::INTERFACE;
};
template <typename T> struct Kind_<T, kj::VoidSfinae<typename schemas::EnumInfo<T>::IsEnum>> {
static constexpr Kind kind = Kind::ENUM;
};
} // namespace _ (private)
template <typename T, Kind k = _::Kind_<T>::kind>
inline constexpr Kind kind() {
// This overload of kind() matches types which have a Kind_ specialization.
return k;
}
#if _MSC_VER
#define CAPNP_KIND(T) ::capnp::_::Kind_<T>::kind
// Avoid constexpr methods in MSVC (it remains buggy in many situations).
#else // _MSC_VER
#define CAPNP_KIND(T) ::capnp::kind<T>()
// Use this macro rather than kind<T>() in any code which must work in MSVC.
#endif // _MSC_VER, else
#if !CAPNP_LITE
template <typename T, Kind k = kind<T>()>
inline constexpr Style style() {
return k == Kind::PRIMITIVE || k == Kind::ENUM ? Style::PRIMITIVE
: k == Kind::STRUCT ? Style::STRUCT
: k == Kind::INTERFACE ? Style::CAPABILITY : Style::POINTER;
}
#endif // !CAPNP_LITE
template <typename T, Kind k = CAPNP_KIND(T)>
struct List;
#if _MSC_VER
template <typename T, Kind k>
struct List {};
// For some reason, without this declaration, MSVC will error out on some uses of List
// claiming that "T" -- as used in the default initializer for the second template param, "k" --
// is not defined. I do not understand this error, but adding this empty default declaration fixes
// it.
#endif
template <typename T> struct ListElementType_;
template <typename T> struct ListElementType_<List<T>> { typedef T Type; };
template <typename T> using ListElementType = typename ListElementType_<T>::Type;
namespace _ { // private
template <typename T, Kind k> struct Kind_<List<T, k>> {
static constexpr Kind kind = Kind::LIST;
};
} // namespace _ (private)
template <typename T, Kind k = CAPNP_KIND(T)> struct ReaderFor_ { typedef typename T::Reader Type; };
template <typename T> struct ReaderFor_<T, Kind::PRIMITIVE> { typedef T Type; };
template <typename T> struct ReaderFor_<T, Kind::ENUM> { typedef T Type; };
template <typename T> struct ReaderFor_<T, Kind::INTERFACE> { typedef typename T::Client Type; };
template <typename T> using ReaderFor = typename ReaderFor_<T>::Type;
// The type returned by List<T>::Reader::operator[].
template <typename T, Kind k = CAPNP_KIND(T)> struct BuilderFor_ { typedef typename T::Builder Type; };
template <typename T> struct BuilderFor_<T, Kind::PRIMITIVE> { typedef T Type; };
template <typename T> struct BuilderFor_<T, Kind::ENUM> { typedef T Type; };
template <typename T> struct BuilderFor_<T, Kind::INTERFACE> { typedef typename T::Client Type; };
template <typename T> using BuilderFor = typename BuilderFor_<T>::Type;
// The type returned by List<T>::Builder::operator[].
template <typename T, Kind k = CAPNP_KIND(T)> struct PipelineFor_ { typedef typename T::Pipeline Type;};
template <typename T> struct PipelineFor_<T, Kind::INTERFACE> { typedef typename T::Client Type; };
template <typename T> using PipelineFor = typename PipelineFor_<T>::Type;
template <typename T, Kind k = CAPNP_KIND(T)> struct TypeIfEnum_;
template <typename T> struct TypeIfEnum_<T, Kind::ENUM> { typedef T Type; };
template <typename T>
using TypeIfEnum = typename TypeIfEnum_<kj::Decay<T>>::Type;
template <typename T>
using FromReader = typename kj::Decay<T>::Reads;
// FromReader<MyType::Reader> = MyType (for any Cap'n Proto type).
template <typename T>
using FromBuilder = typename kj::Decay<T>::Builds;
// FromBuilder<MyType::Builder> = MyType (for any Cap'n Proto type).
template <typename T>
using FromPipeline = typename kj::Decay<T>::Pipelines;
// FromBuilder<MyType::Pipeline> = MyType (for any Cap'n Proto type).
template <typename T>
using FromClient = typename kj::Decay<T>::Calls;
// FromReader<MyType::Client> = MyType (for any Cap'n Proto interface type).
template <typename T>
using FromServer = typename kj::Decay<T>::Serves;
// FromBuilder<MyType::Server> = MyType (for any Cap'n Proto interface type).
template <typename T, typename = void>
struct FromAny_;
template <typename T>
struct FromAny_<T, kj::VoidSfinae<FromReader<T>>> {
using Type = FromReader<T>;
};
template <typename T>
struct FromAny_<T, kj::VoidSfinae<FromBuilder<T>>> {
using Type = FromBuilder<T>;
};
template <typename T>
struct FromAny_<T, kj::VoidSfinae<FromPipeline<T>>> {
using Type = FromPipeline<T>;
};
// Note that T::Client is covered by FromReader
template <typename T>
struct FromAny_<kj::Own<T>, kj::VoidSfinae<FromServer<T>>> {
using Type = FromServer<T>;
};
template <typename T>
struct FromAny_<T,
kj::EnableIf<_::Kind_<T>::kind == Kind::PRIMITIVE || _::Kind_<T>::kind == Kind::ENUM>> {
// TODO(msvc): Ideally the EnableIf condition would be `style<T>() == Style::PRIMITIVE`, but MSVC
// cannot yet use style<T>() in this constexpr context.
using Type = kj::Decay<T>;
};
template <typename T>
using FromAny = typename FromAny_<T>::Type;
// Given any Cap'n Proto value type as an input, return the Cap'n Proto base type. That is:
//
// Foo::Reader -> Foo
// Foo::Builder -> Foo
// Foo::Pipeline -> Foo
// Foo::Client -> Foo
// Own<Foo::Server> -> Foo
// uint32_t -> uint32_t
namespace _ { // private
template <typename T, Kind k = CAPNP_KIND(T)>
struct PointerHelpers;
#if _MSC_VER
template <typename T, Kind k>
struct PointerHelpers {};
// For some reason, without this declaration, MSVC will error out on some uses of PointerHelpers
// claiming that "T" -- as used in the default initializer for the second template param, "k" --
// is not defined. I do not understand this error, but adding this empty default declaration fixes
// it.
#endif
} // namespace _ (private)
struct MessageSize {
// Size of a message. Every struct type has a method `.totalSize()` that returns this.
uint64_t wordCount;
uint capCount;
};
// =======================================================================================
// Raw memory types and measures
using kj::byte;
class word { uint64_t content KJ_UNUSED_MEMBER; KJ_DISALLOW_COPY(word); public: word() = default; };
// word is an opaque type with size of 64 bits. This type is useful only to make pointer
// arithmetic clearer. Since the contents are private, the only way to access them is to first
// reinterpret_cast to some other pointer type.
//
// Copying is disallowed because you should always use memcpy(). Otherwise, you may run afoul of
// aliasing rules.
//
// A pointer of type word* should always be word-aligned even if won't actually be dereferenced as
// that type.
static_assert(sizeof(byte) == 1, "uint8_t is not one byte?");
static_assert(sizeof(word) == 8, "uint64_t is not 8 bytes?");
#if CAPNP_DEBUG_TYPES
// Set CAPNP_DEBUG_TYPES to 1 to use kj::Quantity for "count" types. Otherwise, plain integers are
// used. All the code should still operate exactly the same, we just lose compile-time checking.
// Note that this will also change symbol names, so it's important that the library and any clients
// be compiled with the same setting here.
//
// We disable this by default to reduce symbol name size and avoid any possibility of the compiler
// failing to fully-optimize the types, but anyone modifying Cap'n Proto itself should enable this
// during development and testing.
namespace _ { class BitLabel; class ElementLabel; struct WirePointer; }
template <uint width, typename T = uint>
using BitCountN = kj::Quantity<kj::Bounded<kj::maxValueForBits<width>(), T>, _::BitLabel>;
template <uint width, typename T = uint>
using ByteCountN = kj::Quantity<kj::Bounded<kj::maxValueForBits<width>(), T>, byte>;
template <uint width, typename T = uint>
using WordCountN = kj::Quantity<kj::Bounded<kj::maxValueForBits<width>(), T>, word>;
template <uint width, typename T = uint>
using ElementCountN = kj::Quantity<kj::Bounded<kj::maxValueForBits<width>(), T>, _::ElementLabel>;
template <uint width, typename T = uint>
using WirePointerCountN = kj::Quantity<kj::Bounded<kj::maxValueForBits<width>(), T>, _::WirePointer>;
typedef BitCountN<8, uint8_t> BitCount8;
typedef BitCountN<16, uint16_t> BitCount16;
typedef BitCountN<32, uint32_t> BitCount32;
typedef BitCountN<64, uint64_t> BitCount64;
typedef BitCountN<sizeof(uint) * 8, uint> BitCount;
typedef ByteCountN<8, uint8_t> ByteCount8;
typedef ByteCountN<16, uint16_t> ByteCount16;
typedef ByteCountN<32, uint32_t> ByteCount32;
typedef ByteCountN<64, uint64_t> ByteCount64;
typedef ByteCountN<sizeof(uint) * 8, uint> ByteCount;
typedef WordCountN<8, uint8_t> WordCount8;
typedef WordCountN<16, uint16_t> WordCount16;
typedef WordCountN<32, uint32_t> WordCount32;
typedef WordCountN<64, uint64_t> WordCount64;
typedef WordCountN<sizeof(uint) * 8, uint> WordCount;
typedef ElementCountN<8, uint8_t> ElementCount8;
typedef ElementCountN<16, uint16_t> ElementCount16;
typedef ElementCountN<32, uint32_t> ElementCount32;
typedef ElementCountN<64, uint64_t> ElementCount64;
typedef ElementCountN<sizeof(uint) * 8, uint> ElementCount;
typedef WirePointerCountN<8, uint8_t> WirePointerCount8;
typedef WirePointerCountN<16, uint16_t> WirePointerCount16;
typedef WirePointerCountN<32, uint32_t> WirePointerCount32;
typedef WirePointerCountN<64, uint64_t> WirePointerCount64;
typedef WirePointerCountN<sizeof(uint) * 8, uint> WirePointerCount;
template <uint width>
using BitsPerElementN = decltype(BitCountN<width>() / ElementCountN<width>());
template <uint width>
using BytesPerElementN = decltype(ByteCountN<width>() / ElementCountN<width>());
template <uint width>
using WordsPerElementN = decltype(WordCountN<width>() / ElementCountN<width>());
template <uint width>
using PointersPerElementN = decltype(WirePointerCountN<width>() / ElementCountN<width>());
using kj::bounded;
using kj::unbound;
using kj::unboundAs;
using kj::unboundMax;
using kj::unboundMaxBits;
using kj::assertMax;
using kj::assertMaxBits;
using kj::upgradeBound;
using kj::ThrowOverflow;
using kj::assumeBits;
using kj::assumeMax;
using kj::subtractChecked;
using kj::trySubtract;
template <typename T, typename U>
inline constexpr U* operator+(U* ptr, kj::Quantity<T, U> offset) {
return ptr + unbound(offset / kj::unit<kj::Quantity<T, U>>());
}
template <typename T, typename U>
inline constexpr const U* operator+(const U* ptr, kj::Quantity<T, U> offset) {
return ptr + unbound(offset / kj::unit<kj::Quantity<T, U>>());
}
template <typename T, typename U>
inline constexpr U* operator+=(U*& ptr, kj::Quantity<T, U> offset) {
return ptr = ptr + unbound(offset / kj::unit<kj::Quantity<T, U>>());
}
template <typename T, typename U>
inline constexpr const U* operator+=(const U*& ptr, kj::Quantity<T, U> offset) {
return ptr = ptr + unbound(offset / kj::unit<kj::Quantity<T, U>>());
}
template <typename T, typename U>
inline constexpr U* operator-(U* ptr, kj::Quantity<T, U> offset) {
return ptr - unbound(offset / kj::unit<kj::Quantity<T, U>>());
}
template <typename T, typename U>
inline constexpr const U* operator-(const U* ptr, kj::Quantity<T, U> offset) {
return ptr - unbound(offset / kj::unit<kj::Quantity<T, U>>());
}
template <typename T, typename U>
inline constexpr U* operator-=(U*& ptr, kj::Quantity<T, U> offset) {
return ptr = ptr - unbound(offset / kj::unit<kj::Quantity<T, U>>());
}
template <typename T, typename U>
inline constexpr const U* operator-=(const U*& ptr, kj::Quantity<T, U> offset) {
return ptr = ptr - unbound(offset / kj::unit<kj::Quantity<T, U>>());
}
constexpr auto BITS = kj::unit<BitCountN<1>>();
constexpr auto BYTES = kj::unit<ByteCountN<1>>();
constexpr auto WORDS = kj::unit<WordCountN<1>>();
constexpr auto ELEMENTS = kj::unit<ElementCountN<1>>();
constexpr auto POINTERS = kj::unit<WirePointerCountN<1>>();
constexpr auto ZERO = kj::bounded<0>();
constexpr auto ONE = kj::bounded<1>();
// GCC 4.7 actually gives unused warnings on these constants in opt mode...
constexpr auto BITS_PER_BYTE KJ_UNUSED = bounded<8>() * BITS / BYTES;
constexpr auto BITS_PER_WORD KJ_UNUSED = bounded<64>() * BITS / WORDS;
constexpr auto BYTES_PER_WORD KJ_UNUSED = bounded<8>() * BYTES / WORDS;
constexpr auto BITS_PER_POINTER KJ_UNUSED = bounded<64>() * BITS / POINTERS;
constexpr auto BYTES_PER_POINTER KJ_UNUSED = bounded<8>() * BYTES / POINTERS;
constexpr auto WORDS_PER_POINTER KJ_UNUSED = ONE * WORDS / POINTERS;
constexpr auto POINTER_SIZE_IN_WORDS = ONE * POINTERS * WORDS_PER_POINTER;
constexpr uint SEGMENT_WORD_COUNT_BITS = 29; // Number of words in a segment.
constexpr uint LIST_ELEMENT_COUNT_BITS = 29; // Number of elements in a list.
constexpr uint STRUCT_DATA_WORD_COUNT_BITS = 16; // Number of words in a Struct data section.
constexpr uint STRUCT_POINTER_COUNT_BITS = 16; // Number of pointers in a Struct pointer section.
constexpr uint BLOB_SIZE_BITS = 29; // Number of bytes in a blob.
typedef WordCountN<SEGMENT_WORD_COUNT_BITS> SegmentWordCount;
typedef ElementCountN<LIST_ELEMENT_COUNT_BITS> ListElementCount;
typedef WordCountN<STRUCT_DATA_WORD_COUNT_BITS, uint16_t> StructDataWordCount;
typedef WirePointerCountN<STRUCT_POINTER_COUNT_BITS, uint16_t> StructPointerCount;
typedef ByteCountN<BLOB_SIZE_BITS> BlobSize;
constexpr auto MAX_SEGMENT_WORDS =
bounded<kj::maxValueForBits<SEGMENT_WORD_COUNT_BITS>()>() * WORDS;
constexpr auto MAX_LIST_ELEMENTS =
bounded<kj::maxValueForBits<LIST_ELEMENT_COUNT_BITS>()>() * ELEMENTS;
constexpr auto MAX_STUCT_DATA_WORDS =
bounded<kj::maxValueForBits<STRUCT_DATA_WORD_COUNT_BITS>()>() * WORDS;
constexpr auto MAX_STRUCT_POINTER_COUNT =
bounded<kj::maxValueForBits<STRUCT_POINTER_COUNT_BITS>()>() * POINTERS;
using StructDataBitCount = decltype(WordCountN<STRUCT_POINTER_COUNT_BITS>() * BITS_PER_WORD);
// Number of bits in a Struct data segment (should come out to BitCountN<22>).
using StructDataOffset = decltype(StructDataBitCount() * (ONE * ELEMENTS / BITS));
using StructPointerOffset = StructPointerCount;
// Type of a field offset.
inline StructDataOffset assumeDataOffset(uint32_t offset) {
return assumeMax(MAX_STUCT_DATA_WORDS * BITS_PER_WORD * (ONE * ELEMENTS / BITS),
bounded(offset) * ELEMENTS);
}
inline StructPointerOffset assumePointerOffset(uint32_t offset) {
return assumeMax(MAX_STRUCT_POINTER_COUNT, bounded(offset) * POINTERS);
}
constexpr uint MAX_TEXT_SIZE = kj::maxValueForBits<BLOB_SIZE_BITS>() - 1;
typedef kj::Quantity<kj::Bounded<MAX_TEXT_SIZE, uint>, byte> TextSize;
// Not including NUL terminator.
template <typename T>
inline KJ_CONSTEXPR() decltype(bounded<sizeof(T)>() * BYTES / ELEMENTS) bytesPerElement() {
return bounded<sizeof(T)>() * BYTES / ELEMENTS;
}
template <typename T>
inline KJ_CONSTEXPR() decltype(bounded<sizeof(T) * 8>() * BITS / ELEMENTS) bitsPerElement() {
return bounded<sizeof(T) * 8>() * BITS / ELEMENTS;
}
template <typename T, uint maxN>
inline constexpr kj::Quantity<kj::Bounded<maxN, size_t>, T>
intervalLength(const T* a, const T* b, kj::Quantity<kj::BoundedConst<maxN>, T>) {
return kj::assumeMax<maxN>(b - a) * kj::unit<kj::Quantity<kj::BoundedConst<1u>, T>>();
}
template <typename T, typename U>
inline constexpr kj::ArrayPtr<const U> arrayPtr(const U* ptr, kj::Quantity<T, U> size) {
return kj::ArrayPtr<const U>(ptr, unbound(size / kj::unit<kj::Quantity<T, U>>()));
}
template <typename T, typename U>
inline constexpr kj::ArrayPtr<U> arrayPtr(U* ptr, kj::Quantity<T, U> size) {
return kj::ArrayPtr<U>(ptr, unbound(size / kj::unit<kj::Quantity<T, U>>()));
}
#else
template <uint width, typename T = uint>
using BitCountN = T;
template <uint width, typename T = uint>
using ByteCountN = T;
template <uint width, typename T = uint>
using WordCountN = T;
template <uint width, typename T = uint>
using ElementCountN = T;
template <uint width, typename T = uint>
using WirePointerCountN = T;
// XXX
typedef BitCountN<8, uint8_t> BitCount8;
typedef BitCountN<16, uint16_t> BitCount16;
typedef BitCountN<32, uint32_t> BitCount32;
typedef BitCountN<64, uint64_t> BitCount64;
typedef BitCountN<sizeof(uint) * 8, uint> BitCount;
typedef ByteCountN<8, uint8_t> ByteCount8;
typedef ByteCountN<16, uint16_t> ByteCount16;
typedef ByteCountN<32, uint32_t> ByteCount32;
typedef ByteCountN<64, uint64_t> ByteCount64;
typedef ByteCountN<sizeof(uint) * 8, uint> ByteCount;
typedef WordCountN<8, uint8_t> WordCount8;
typedef WordCountN<16, uint16_t> WordCount16;
typedef WordCountN<32, uint32_t> WordCount32;
typedef WordCountN<64, uint64_t> WordCount64;
typedef WordCountN<sizeof(uint) * 8, uint> WordCount;
typedef ElementCountN<8, uint8_t> ElementCount8;
typedef ElementCountN<16, uint16_t> ElementCount16;
typedef ElementCountN<32, uint32_t> ElementCount32;
typedef ElementCountN<64, uint64_t> ElementCount64;
typedef ElementCountN<sizeof(uint) * 8, uint> ElementCount;
typedef WirePointerCountN<8, uint8_t> WirePointerCount8;
typedef WirePointerCountN<16, uint16_t> WirePointerCount16;
typedef WirePointerCountN<32, uint32_t> WirePointerCount32;
typedef WirePointerCountN<64, uint64_t> WirePointerCount64;
typedef WirePointerCountN<sizeof(uint) * 8, uint> WirePointerCount;
template <uint width>
using BitsPerElementN = decltype(BitCountN<width>() / ElementCountN<width>());
template <uint width>
using BytesPerElementN = decltype(ByteCountN<width>() / ElementCountN<width>());
template <uint width>
using WordsPerElementN = decltype(WordCountN<width>() / ElementCountN<width>());
template <uint width>
using PointersPerElementN = decltype(WirePointerCountN<width>() / ElementCountN<width>());
using kj::ThrowOverflow;
// YYY
template <uint i> inline constexpr uint bounded() { return i; }
template <typename T> inline constexpr T bounded(T i) { return i; }
template <typename T> inline constexpr T unbound(T i) { return i; }
template <typename T, typename U> inline constexpr T unboundAs(U i) { return i; }
template <uint64_t requestedMax, typename T> inline constexpr uint unboundMax(T i) { return i; }
template <uint bits, typename T> inline constexpr uint unboundMaxBits(T i) { return i; }
template <uint newMax, typename T, typename ErrorFunc>
inline T assertMax(T value, ErrorFunc&& func) {
if (KJ_UNLIKELY(value > newMax)) func();
return value;
}
template <typename T, typename ErrorFunc>
inline T assertMax(uint newMax, T value, ErrorFunc&& func) {
if (KJ_UNLIKELY(value > newMax)) func();
return value;
}
template <uint bits, typename T, typename ErrorFunc = ThrowOverflow>
inline T assertMaxBits(T value, ErrorFunc&& func = ErrorFunc()) {
if (KJ_UNLIKELY(value > kj::maxValueForBits<bits>())) func();
return value;
}
template <typename T, typename ErrorFunc = ThrowOverflow>
inline T assertMaxBits(uint bits, T value, ErrorFunc&& func = ErrorFunc()) {
if (KJ_UNLIKELY(value > (1ull << bits) - 1)) func();
return value;
}
template <typename T, typename U> inline constexpr T upgradeBound(U i) { return i; }
template <uint bits, typename T> inline constexpr T assumeBits(T i) { return i; }
template <uint64_t max, typename T> inline constexpr T assumeMax(T i) { return i; }
template <typename T, typename U, typename ErrorFunc = ThrowOverflow>
inline auto subtractChecked(T a, U b, ErrorFunc&& errorFunc = ErrorFunc())
-> decltype(a - b) {
if (b > a) errorFunc();
return a - b;
}
template <typename T, typename U>
inline auto trySubtract(T a, U b) -> kj::Maybe<decltype(a - b)> {
if (b > a) {
return nullptr;
} else {
return a - b;
}
}
constexpr uint BITS = 1;
constexpr uint BYTES = 1;
constexpr uint WORDS = 1;
constexpr uint ELEMENTS = 1;
constexpr uint POINTERS = 1;
constexpr uint ZERO = 0;
constexpr uint ONE = 1;
// GCC 4.7 actually gives unused warnings on these constants in opt mode...
constexpr uint BITS_PER_BYTE KJ_UNUSED = 8;
constexpr uint BITS_PER_WORD KJ_UNUSED = 64;
constexpr uint BYTES_PER_WORD KJ_UNUSED = 8;
constexpr uint BITS_PER_POINTER KJ_UNUSED = 64;
constexpr uint BYTES_PER_POINTER KJ_UNUSED = 8;
constexpr uint WORDS_PER_POINTER KJ_UNUSED = 1;
// XXX
constexpr uint POINTER_SIZE_IN_WORDS = ONE * POINTERS * WORDS_PER_POINTER;
constexpr uint SEGMENT_WORD_COUNT_BITS = 29; // Number of words in a segment.
constexpr uint LIST_ELEMENT_COUNT_BITS = 29; // Number of elements in a list.
constexpr uint STRUCT_DATA_WORD_COUNT_BITS = 16; // Number of words in a Struct data section.
constexpr uint STRUCT_POINTER_COUNT_BITS = 16; // Number of pointers in a Struct pointer section.
constexpr uint BLOB_SIZE_BITS = 29; // Number of bytes in a blob.
typedef WordCountN<SEGMENT_WORD_COUNT_BITS> SegmentWordCount;
typedef ElementCountN<LIST_ELEMENT_COUNT_BITS> ListElementCount;
typedef WordCountN<STRUCT_DATA_WORD_COUNT_BITS, uint16_t> StructDataWordCount;
typedef WirePointerCountN<STRUCT_POINTER_COUNT_BITS, uint16_t> StructPointerCount;
typedef ByteCountN<BLOB_SIZE_BITS> BlobSize;
// YYY
constexpr auto MAX_SEGMENT_WORDS = kj::maxValueForBits<SEGMENT_WORD_COUNT_BITS>();
constexpr auto MAX_LIST_ELEMENTS = kj::maxValueForBits<LIST_ELEMENT_COUNT_BITS>();
constexpr auto MAX_STUCT_DATA_WORDS = kj::maxValueForBits<STRUCT_DATA_WORD_COUNT_BITS>();
constexpr auto MAX_STRUCT_POINTER_COUNT = kj::maxValueForBits<STRUCT_POINTER_COUNT_BITS>();
typedef uint StructDataBitCount;
typedef uint StructDataOffset;
typedef uint StructPointerOffset;
inline StructDataOffset assumeDataOffset(uint32_t offset) { return offset; }
inline StructPointerOffset assumePointerOffset(uint32_t offset) { return offset; }
constexpr uint MAX_TEXT_SIZE = kj::maxValueForBits<BLOB_SIZE_BITS>() - 1;
typedef uint TextSize;
template <typename T>
inline KJ_CONSTEXPR() size_t bytesPerElement() { return sizeof(T); }
template <typename T>
inline KJ_CONSTEXPR() size_t bitsPerElement() { return sizeof(T) * 8; }
template <typename T>
inline constexpr ptrdiff_t intervalLength(const T* a, const T* b, uint) {
return b - a;
}
template <typename T, typename U>
inline constexpr kj::ArrayPtr<const U> arrayPtr(const U* ptr, T size) {
return kj::arrayPtr(ptr, size);
}
template <typename T, typename U>
inline constexpr kj::ArrayPtr<U> arrayPtr(U* ptr, T size) {
return kj::arrayPtr(ptr, size);
}
#endif
} // namespace capnp
#endif // CAPNP_COMMON_H_

View File

@ -1,860 +0,0 @@
// Generated by Cap'n Proto compiler, DO NOT EDIT
// source: json.capnp
#ifndef CAPNP_INCLUDED_8ef99297a43a5e34_
#define CAPNP_INCLUDED_8ef99297a43a5e34_
#include <capnp/generated-header-support.h>
#if !CAPNP_LITE
#include <capnp/capability.h>
#endif // !CAPNP_LITE
#if CAPNP_VERSION != 6001
#error "Version mismatch between generated code and library headers. You must use the same version of the Cap'n Proto compiler and library."
#endif
namespace capnp {
namespace schemas {
CAPNP_DECLARE_SCHEMA(8825ffaa852cda72);
CAPNP_DECLARE_SCHEMA(c27855d853a937cc);
CAPNP_DECLARE_SCHEMA(9bbf84153dd4bb60);
} // namespace schemas
} // namespace capnp
namespace capnp {
struct JsonValue {
JsonValue() = delete;
class Reader;
class Builder;
class Pipeline;
enum Which: uint16_t {
NULL_,
BOOLEAN,
NUMBER,
STRING,
ARRAY,
OBJECT,
CALL,
};
struct Field;
struct Call;
struct _capnpPrivate {
CAPNP_DECLARE_STRUCT_HEADER(8825ffaa852cda72, 2, 1)
#if !CAPNP_LITE
static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; }
#endif // !CAPNP_LITE
};
};
struct JsonValue::Field {
Field() = delete;
class Reader;
class Builder;
class Pipeline;
struct _capnpPrivate {
CAPNP_DECLARE_STRUCT_HEADER(c27855d853a937cc, 0, 2)
#if !CAPNP_LITE
static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; }
#endif // !CAPNP_LITE
};
};
struct JsonValue::Call {
Call() = delete;
class Reader;
class Builder;
class Pipeline;
struct _capnpPrivate {
CAPNP_DECLARE_STRUCT_HEADER(9bbf84153dd4bb60, 0, 2)
#if !CAPNP_LITE
static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; }
#endif // !CAPNP_LITE
};
};
// =======================================================================================
class JsonValue::Reader {
public:
typedef JsonValue Reads;
Reader() = default;
inline explicit Reader(::capnp::_::StructReader base): _reader(base) {}
inline ::capnp::MessageSize totalSize() const {
return _reader.totalSize().asPublic();
}
#if !CAPNP_LITE
inline ::kj::StringTree toString() const {
return ::capnp::_::structString(_reader, *_capnpPrivate::brand());
}
#endif // !CAPNP_LITE
inline Which which() const;
inline bool isNull() const;
inline ::capnp::Void getNull() const;
inline bool isBoolean() const;
inline bool getBoolean() const;
inline bool isNumber() const;
inline double getNumber() const;
inline bool isString() const;
inline bool hasString() const;
inline ::capnp::Text::Reader getString() const;
inline bool isArray() const;
inline bool hasArray() const;
inline ::capnp::List< ::capnp::JsonValue>::Reader getArray() const;
inline bool isObject() const;
inline bool hasObject() const;
inline ::capnp::List< ::capnp::JsonValue::Field>::Reader getObject() const;
inline bool isCall() const;
inline bool hasCall() const;
inline ::capnp::JsonValue::Call::Reader getCall() const;
private:
::capnp::_::StructReader _reader;
template <typename, ::capnp::Kind>
friend struct ::capnp::ToDynamic_;
template <typename, ::capnp::Kind>
friend struct ::capnp::_::PointerHelpers;
template <typename, ::capnp::Kind>
friend struct ::capnp::List;
friend class ::capnp::MessageBuilder;
friend class ::capnp::Orphanage;
};
class JsonValue::Builder {
public:
typedef JsonValue Builds;
Builder() = delete; // Deleted to discourage incorrect usage.
// You can explicitly initialize to nullptr instead.
inline Builder(decltype(nullptr)) {}
inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {}
inline operator Reader() const { return Reader(_builder.asReader()); }
inline Reader asReader() const { return *this; }
inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); }
#if !CAPNP_LITE
inline ::kj::StringTree toString() const { return asReader().toString(); }
#endif // !CAPNP_LITE
inline Which which();
inline bool isNull();
inline ::capnp::Void getNull();
inline void setNull( ::capnp::Void value = ::capnp::VOID);
inline bool isBoolean();
inline bool getBoolean();
inline void setBoolean(bool value);
inline bool isNumber();
inline double getNumber();
inline void setNumber(double value);
inline bool isString();
inline bool hasString();
inline ::capnp::Text::Builder getString();
inline void setString( ::capnp::Text::Reader value);
inline ::capnp::Text::Builder initString(unsigned int size);
inline void adoptString(::capnp::Orphan< ::capnp::Text>&& value);
inline ::capnp::Orphan< ::capnp::Text> disownString();
inline bool isArray();
inline bool hasArray();
inline ::capnp::List< ::capnp::JsonValue>::Builder getArray();
inline void setArray( ::capnp::List< ::capnp::JsonValue>::Reader value);
inline ::capnp::List< ::capnp::JsonValue>::Builder initArray(unsigned int size);
inline void adoptArray(::capnp::Orphan< ::capnp::List< ::capnp::JsonValue>>&& value);
inline ::capnp::Orphan< ::capnp::List< ::capnp::JsonValue>> disownArray();
inline bool isObject();
inline bool hasObject();
inline ::capnp::List< ::capnp::JsonValue::Field>::Builder getObject();
inline void setObject( ::capnp::List< ::capnp::JsonValue::Field>::Reader value);
inline ::capnp::List< ::capnp::JsonValue::Field>::Builder initObject(unsigned int size);
inline void adoptObject(::capnp::Orphan< ::capnp::List< ::capnp::JsonValue::Field>>&& value);
inline ::capnp::Orphan< ::capnp::List< ::capnp::JsonValue::Field>> disownObject();
inline bool isCall();
inline bool hasCall();
inline ::capnp::JsonValue::Call::Builder getCall();
inline void setCall( ::capnp::JsonValue::Call::Reader value);
inline ::capnp::JsonValue::Call::Builder initCall();
inline void adoptCall(::capnp::Orphan< ::capnp::JsonValue::Call>&& value);
inline ::capnp::Orphan< ::capnp::JsonValue::Call> disownCall();
private:
::capnp::_::StructBuilder _builder;
template <typename, ::capnp::Kind>
friend struct ::capnp::ToDynamic_;
friend class ::capnp::Orphanage;
template <typename, ::capnp::Kind>
friend struct ::capnp::_::PointerHelpers;
};
#if !CAPNP_LITE
class JsonValue::Pipeline {
public:
typedef JsonValue Pipelines;
inline Pipeline(decltype(nullptr)): _typeless(nullptr) {}
inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless)
: _typeless(kj::mv(typeless)) {}
private:
::capnp::AnyPointer::Pipeline _typeless;
friend class ::capnp::PipelineHook;
template <typename, ::capnp::Kind>
friend struct ::capnp::ToDynamic_;
};
#endif // !CAPNP_LITE
class JsonValue::Field::Reader {
public:
typedef Field Reads;
Reader() = default;
inline explicit Reader(::capnp::_::StructReader base): _reader(base) {}
inline ::capnp::MessageSize totalSize() const {
return _reader.totalSize().asPublic();
}
#if !CAPNP_LITE
inline ::kj::StringTree toString() const {
return ::capnp::_::structString(_reader, *_capnpPrivate::brand());
}
#endif // !CAPNP_LITE
inline bool hasName() const;
inline ::capnp::Text::Reader getName() const;
inline bool hasValue() const;
inline ::capnp::JsonValue::Reader getValue() const;
private:
::capnp::_::StructReader _reader;
template <typename, ::capnp::Kind>
friend struct ::capnp::ToDynamic_;
template <typename, ::capnp::Kind>
friend struct ::capnp::_::PointerHelpers;
template <typename, ::capnp::Kind>
friend struct ::capnp::List;
friend class ::capnp::MessageBuilder;
friend class ::capnp::Orphanage;
};
class JsonValue::Field::Builder {
public:
typedef Field Builds;
Builder() = delete; // Deleted to discourage incorrect usage.
// You can explicitly initialize to nullptr instead.
inline Builder(decltype(nullptr)) {}
inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {}
inline operator Reader() const { return Reader(_builder.asReader()); }
inline Reader asReader() const { return *this; }
inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); }
#if !CAPNP_LITE
inline ::kj::StringTree toString() const { return asReader().toString(); }
#endif // !CAPNP_LITE
inline bool hasName();
inline ::capnp::Text::Builder getName();
inline void setName( ::capnp::Text::Reader value);
inline ::capnp::Text::Builder initName(unsigned int size);
inline void adoptName(::capnp::Orphan< ::capnp::Text>&& value);
inline ::capnp::Orphan< ::capnp::Text> disownName();
inline bool hasValue();
inline ::capnp::JsonValue::Builder getValue();
inline void setValue( ::capnp::JsonValue::Reader value);
inline ::capnp::JsonValue::Builder initValue();
inline void adoptValue(::capnp::Orphan< ::capnp::JsonValue>&& value);
inline ::capnp::Orphan< ::capnp::JsonValue> disownValue();
private:
::capnp::_::StructBuilder _builder;
template <typename, ::capnp::Kind>
friend struct ::capnp::ToDynamic_;
friend class ::capnp::Orphanage;
template <typename, ::capnp::Kind>
friend struct ::capnp::_::PointerHelpers;
};
#if !CAPNP_LITE
class JsonValue::Field::Pipeline {
public:
typedef Field Pipelines;
inline Pipeline(decltype(nullptr)): _typeless(nullptr) {}
inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless)
: _typeless(kj::mv(typeless)) {}
inline ::capnp::JsonValue::Pipeline getValue();
private:
::capnp::AnyPointer::Pipeline _typeless;
friend class ::capnp::PipelineHook;
template <typename, ::capnp::Kind>
friend struct ::capnp::ToDynamic_;
};
#endif // !CAPNP_LITE
class JsonValue::Call::Reader {
public:
typedef Call Reads;
Reader() = default;
inline explicit Reader(::capnp::_::StructReader base): _reader(base) {}
inline ::capnp::MessageSize totalSize() const {
return _reader.totalSize().asPublic();
}
#if !CAPNP_LITE
inline ::kj::StringTree toString() const {
return ::capnp::_::structString(_reader, *_capnpPrivate::brand());
}
#endif // !CAPNP_LITE
inline bool hasFunction() const;
inline ::capnp::Text::Reader getFunction() const;
inline bool hasParams() const;
inline ::capnp::List< ::capnp::JsonValue>::Reader getParams() const;
private:
::capnp::_::StructReader _reader;
template <typename, ::capnp::Kind>
friend struct ::capnp::ToDynamic_;
template <typename, ::capnp::Kind>
friend struct ::capnp::_::PointerHelpers;
template <typename, ::capnp::Kind>
friend struct ::capnp::List;
friend class ::capnp::MessageBuilder;
friend class ::capnp::Orphanage;
};
class JsonValue::Call::Builder {
public:
typedef Call Builds;
Builder() = delete; // Deleted to discourage incorrect usage.
// You can explicitly initialize to nullptr instead.
inline Builder(decltype(nullptr)) {}
inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {}
inline operator Reader() const { return Reader(_builder.asReader()); }
inline Reader asReader() const { return *this; }
inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); }
#if !CAPNP_LITE
inline ::kj::StringTree toString() const { return asReader().toString(); }
#endif // !CAPNP_LITE
inline bool hasFunction();
inline ::capnp::Text::Builder getFunction();
inline void setFunction( ::capnp::Text::Reader value);
inline ::capnp::Text::Builder initFunction(unsigned int size);
inline void adoptFunction(::capnp::Orphan< ::capnp::Text>&& value);
inline ::capnp::Orphan< ::capnp::Text> disownFunction();
inline bool hasParams();
inline ::capnp::List< ::capnp::JsonValue>::Builder getParams();
inline void setParams( ::capnp::List< ::capnp::JsonValue>::Reader value);
inline ::capnp::List< ::capnp::JsonValue>::Builder initParams(unsigned int size);
inline void adoptParams(::capnp::Orphan< ::capnp::List< ::capnp::JsonValue>>&& value);
inline ::capnp::Orphan< ::capnp::List< ::capnp::JsonValue>> disownParams();
private:
::capnp::_::StructBuilder _builder;
template <typename, ::capnp::Kind>
friend struct ::capnp::ToDynamic_;
friend class ::capnp::Orphanage;
template <typename, ::capnp::Kind>
friend struct ::capnp::_::PointerHelpers;
};
#if !CAPNP_LITE
class JsonValue::Call::Pipeline {
public:
typedef Call Pipelines;
inline Pipeline(decltype(nullptr)): _typeless(nullptr) {}
inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless)
: _typeless(kj::mv(typeless)) {}
private:
::capnp::AnyPointer::Pipeline _typeless;
friend class ::capnp::PipelineHook;
template <typename, ::capnp::Kind>
friend struct ::capnp::ToDynamic_;
};
#endif // !CAPNP_LITE
// =======================================================================================
inline ::capnp::JsonValue::Which JsonValue::Reader::which() const {
return _reader.getDataField<Which>(
::capnp::bounded<0>() * ::capnp::ELEMENTS);
}
inline ::capnp::JsonValue::Which JsonValue::Builder::which() {
return _builder.getDataField<Which>(
::capnp::bounded<0>() * ::capnp::ELEMENTS);
}
inline bool JsonValue::Reader::isNull() const {
return which() == JsonValue::NULL_;
}
inline bool JsonValue::Builder::isNull() {
return which() == JsonValue::NULL_;
}
inline ::capnp::Void JsonValue::Reader::getNull() const {
KJ_IREQUIRE((which() == JsonValue::NULL_),
"Must check which() before get()ing a union member.");
return _reader.getDataField< ::capnp::Void>(
::capnp::bounded<0>() * ::capnp::ELEMENTS);
}
inline ::capnp::Void JsonValue::Builder::getNull() {
KJ_IREQUIRE((which() == JsonValue::NULL_),
"Must check which() before get()ing a union member.");
return _builder.getDataField< ::capnp::Void>(
::capnp::bounded<0>() * ::capnp::ELEMENTS);
}
inline void JsonValue::Builder::setNull( ::capnp::Void value) {
_builder.setDataField<JsonValue::Which>(
::capnp::bounded<0>() * ::capnp::ELEMENTS, JsonValue::NULL_);
_builder.setDataField< ::capnp::Void>(
::capnp::bounded<0>() * ::capnp::ELEMENTS, value);
}
inline bool JsonValue::Reader::isBoolean() const {
return which() == JsonValue::BOOLEAN;
}
inline bool JsonValue::Builder::isBoolean() {
return which() == JsonValue::BOOLEAN;
}
inline bool JsonValue::Reader::getBoolean() const {
KJ_IREQUIRE((which() == JsonValue::BOOLEAN),
"Must check which() before get()ing a union member.");
return _reader.getDataField<bool>(
::capnp::bounded<16>() * ::capnp::ELEMENTS);
}
inline bool JsonValue::Builder::getBoolean() {
KJ_IREQUIRE((which() == JsonValue::BOOLEAN),
"Must check which() before get()ing a union member.");
return _builder.getDataField<bool>(
::capnp::bounded<16>() * ::capnp::ELEMENTS);
}
inline void JsonValue::Builder::setBoolean(bool value) {
_builder.setDataField<JsonValue::Which>(
::capnp::bounded<0>() * ::capnp::ELEMENTS, JsonValue::BOOLEAN);
_builder.setDataField<bool>(
::capnp::bounded<16>() * ::capnp::ELEMENTS, value);
}
inline bool JsonValue::Reader::isNumber() const {
return which() == JsonValue::NUMBER;
}
inline bool JsonValue::Builder::isNumber() {
return which() == JsonValue::NUMBER;
}
inline double JsonValue::Reader::getNumber() const {
KJ_IREQUIRE((which() == JsonValue::NUMBER),
"Must check which() before get()ing a union member.");
return _reader.getDataField<double>(
::capnp::bounded<1>() * ::capnp::ELEMENTS);
}
inline double JsonValue::Builder::getNumber() {
KJ_IREQUIRE((which() == JsonValue::NUMBER),
"Must check which() before get()ing a union member.");
return _builder.getDataField<double>(
::capnp::bounded<1>() * ::capnp::ELEMENTS);
}
inline void JsonValue::Builder::setNumber(double value) {
_builder.setDataField<JsonValue::Which>(
::capnp::bounded<0>() * ::capnp::ELEMENTS, JsonValue::NUMBER);
_builder.setDataField<double>(
::capnp::bounded<1>() * ::capnp::ELEMENTS, value);
}
inline bool JsonValue::Reader::isString() const {
return which() == JsonValue::STRING;
}
inline bool JsonValue::Builder::isString() {
return which() == JsonValue::STRING;
}
inline bool JsonValue::Reader::hasString() const {
if (which() != JsonValue::STRING) return false;
return !_reader.getPointerField(
::capnp::bounded<0>() * ::capnp::POINTERS).isNull();
}
inline bool JsonValue::Builder::hasString() {
if (which() != JsonValue::STRING) return false;
return !_builder.getPointerField(
::capnp::bounded<0>() * ::capnp::POINTERS).isNull();
}
inline ::capnp::Text::Reader JsonValue::Reader::getString() const {
KJ_IREQUIRE((which() == JsonValue::STRING),
"Must check which() before get()ing a union member.");
return ::capnp::_::PointerHelpers< ::capnp::Text>::get(_reader.getPointerField(
::capnp::bounded<0>() * ::capnp::POINTERS));
}
inline ::capnp::Text::Builder JsonValue::Builder::getString() {
KJ_IREQUIRE((which() == JsonValue::STRING),
"Must check which() before get()ing a union member.");
return ::capnp::_::PointerHelpers< ::capnp::Text>::get(_builder.getPointerField(
::capnp::bounded<0>() * ::capnp::POINTERS));
}
inline void JsonValue::Builder::setString( ::capnp::Text::Reader value) {
_builder.setDataField<JsonValue::Which>(
::capnp::bounded<0>() * ::capnp::ELEMENTS, JsonValue::STRING);
::capnp::_::PointerHelpers< ::capnp::Text>::set(_builder.getPointerField(
::capnp::bounded<0>() * ::capnp::POINTERS), value);
}
inline ::capnp::Text::Builder JsonValue::Builder::initString(unsigned int size) {
_builder.setDataField<JsonValue::Which>(
::capnp::bounded<0>() * ::capnp::ELEMENTS, JsonValue::STRING);
return ::capnp::_::PointerHelpers< ::capnp::Text>::init(_builder.getPointerField(
::capnp::bounded<0>() * ::capnp::POINTERS), size);
}
inline void JsonValue::Builder::adoptString(
::capnp::Orphan< ::capnp::Text>&& value) {
_builder.setDataField<JsonValue::Which>(
::capnp::bounded<0>() * ::capnp::ELEMENTS, JsonValue::STRING);
::capnp::_::PointerHelpers< ::capnp::Text>::adopt(_builder.getPointerField(
::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value));
}
inline ::capnp::Orphan< ::capnp::Text> JsonValue::Builder::disownString() {
KJ_IREQUIRE((which() == JsonValue::STRING),
"Must check which() before get()ing a union member.");
return ::capnp::_::PointerHelpers< ::capnp::Text>::disown(_builder.getPointerField(
::capnp::bounded<0>() * ::capnp::POINTERS));
}
inline bool JsonValue::Reader::isArray() const {
return which() == JsonValue::ARRAY;
}
inline bool JsonValue::Builder::isArray() {
return which() == JsonValue::ARRAY;
}
inline bool JsonValue::Reader::hasArray() const {
if (which() != JsonValue::ARRAY) return false;
return !_reader.getPointerField(
::capnp::bounded<0>() * ::capnp::POINTERS).isNull();
}
inline bool JsonValue::Builder::hasArray() {
if (which() != JsonValue::ARRAY) return false;
return !_builder.getPointerField(
::capnp::bounded<0>() * ::capnp::POINTERS).isNull();
}
inline ::capnp::List< ::capnp::JsonValue>::Reader JsonValue::Reader::getArray() const {
KJ_IREQUIRE((which() == JsonValue::ARRAY),
"Must check which() before get()ing a union member.");
return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::JsonValue>>::get(_reader.getPointerField(
::capnp::bounded<0>() * ::capnp::POINTERS));
}
inline ::capnp::List< ::capnp::JsonValue>::Builder JsonValue::Builder::getArray() {
KJ_IREQUIRE((which() == JsonValue::ARRAY),
"Must check which() before get()ing a union member.");
return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::JsonValue>>::get(_builder.getPointerField(
::capnp::bounded<0>() * ::capnp::POINTERS));
}
inline void JsonValue::Builder::setArray( ::capnp::List< ::capnp::JsonValue>::Reader value) {
_builder.setDataField<JsonValue::Which>(
::capnp::bounded<0>() * ::capnp::ELEMENTS, JsonValue::ARRAY);
::capnp::_::PointerHelpers< ::capnp::List< ::capnp::JsonValue>>::set(_builder.getPointerField(
::capnp::bounded<0>() * ::capnp::POINTERS), value);
}
inline ::capnp::List< ::capnp::JsonValue>::Builder JsonValue::Builder::initArray(unsigned int size) {
_builder.setDataField<JsonValue::Which>(
::capnp::bounded<0>() * ::capnp::ELEMENTS, JsonValue::ARRAY);
return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::JsonValue>>::init(_builder.getPointerField(
::capnp::bounded<0>() * ::capnp::POINTERS), size);
}
inline void JsonValue::Builder::adoptArray(
::capnp::Orphan< ::capnp::List< ::capnp::JsonValue>>&& value) {
_builder.setDataField<JsonValue::Which>(
::capnp::bounded<0>() * ::capnp::ELEMENTS, JsonValue::ARRAY);
::capnp::_::PointerHelpers< ::capnp::List< ::capnp::JsonValue>>::adopt(_builder.getPointerField(
::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value));
}
inline ::capnp::Orphan< ::capnp::List< ::capnp::JsonValue>> JsonValue::Builder::disownArray() {
KJ_IREQUIRE((which() == JsonValue::ARRAY),
"Must check which() before get()ing a union member.");
return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::JsonValue>>::disown(_builder.getPointerField(
::capnp::bounded<0>() * ::capnp::POINTERS));
}
inline bool JsonValue::Reader::isObject() const {
return which() == JsonValue::OBJECT;
}
inline bool JsonValue::Builder::isObject() {
return which() == JsonValue::OBJECT;
}
inline bool JsonValue::Reader::hasObject() const {
if (which() != JsonValue::OBJECT) return false;
return !_reader.getPointerField(
::capnp::bounded<0>() * ::capnp::POINTERS).isNull();
}
inline bool JsonValue::Builder::hasObject() {
if (which() != JsonValue::OBJECT) return false;
return !_builder.getPointerField(
::capnp::bounded<0>() * ::capnp::POINTERS).isNull();
}
inline ::capnp::List< ::capnp::JsonValue::Field>::Reader JsonValue::Reader::getObject() const {
KJ_IREQUIRE((which() == JsonValue::OBJECT),
"Must check which() before get()ing a union member.");
return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::JsonValue::Field>>::get(_reader.getPointerField(
::capnp::bounded<0>() * ::capnp::POINTERS));
}
inline ::capnp::List< ::capnp::JsonValue::Field>::Builder JsonValue::Builder::getObject() {
KJ_IREQUIRE((which() == JsonValue::OBJECT),
"Must check which() before get()ing a union member.");
return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::JsonValue::Field>>::get(_builder.getPointerField(
::capnp::bounded<0>() * ::capnp::POINTERS));
}
inline void JsonValue::Builder::setObject( ::capnp::List< ::capnp::JsonValue::Field>::Reader value) {
_builder.setDataField<JsonValue::Which>(
::capnp::bounded<0>() * ::capnp::ELEMENTS, JsonValue::OBJECT);
::capnp::_::PointerHelpers< ::capnp::List< ::capnp::JsonValue::Field>>::set(_builder.getPointerField(
::capnp::bounded<0>() * ::capnp::POINTERS), value);
}
inline ::capnp::List< ::capnp::JsonValue::Field>::Builder JsonValue::Builder::initObject(unsigned int size) {
_builder.setDataField<JsonValue::Which>(
::capnp::bounded<0>() * ::capnp::ELEMENTS, JsonValue::OBJECT);
return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::JsonValue::Field>>::init(_builder.getPointerField(
::capnp::bounded<0>() * ::capnp::POINTERS), size);
}
inline void JsonValue::Builder::adoptObject(
::capnp::Orphan< ::capnp::List< ::capnp::JsonValue::Field>>&& value) {
_builder.setDataField<JsonValue::Which>(
::capnp::bounded<0>() * ::capnp::ELEMENTS, JsonValue::OBJECT);
::capnp::_::PointerHelpers< ::capnp::List< ::capnp::JsonValue::Field>>::adopt(_builder.getPointerField(
::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value));
}
inline ::capnp::Orphan< ::capnp::List< ::capnp::JsonValue::Field>> JsonValue::Builder::disownObject() {
KJ_IREQUIRE((which() == JsonValue::OBJECT),
"Must check which() before get()ing a union member.");
return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::JsonValue::Field>>::disown(_builder.getPointerField(
::capnp::bounded<0>() * ::capnp::POINTERS));
}
inline bool JsonValue::Reader::isCall() const {
return which() == JsonValue::CALL;
}
inline bool JsonValue::Builder::isCall() {
return which() == JsonValue::CALL;
}
inline bool JsonValue::Reader::hasCall() const {
if (which() != JsonValue::CALL) return false;
return !_reader.getPointerField(
::capnp::bounded<0>() * ::capnp::POINTERS).isNull();
}
inline bool JsonValue::Builder::hasCall() {
if (which() != JsonValue::CALL) return false;
return !_builder.getPointerField(
::capnp::bounded<0>() * ::capnp::POINTERS).isNull();
}
inline ::capnp::JsonValue::Call::Reader JsonValue::Reader::getCall() const {
KJ_IREQUIRE((which() == JsonValue::CALL),
"Must check which() before get()ing a union member.");
return ::capnp::_::PointerHelpers< ::capnp::JsonValue::Call>::get(_reader.getPointerField(
::capnp::bounded<0>() * ::capnp::POINTERS));
}
inline ::capnp::JsonValue::Call::Builder JsonValue::Builder::getCall() {
KJ_IREQUIRE((which() == JsonValue::CALL),
"Must check which() before get()ing a union member.");
return ::capnp::_::PointerHelpers< ::capnp::JsonValue::Call>::get(_builder.getPointerField(
::capnp::bounded<0>() * ::capnp::POINTERS));
}
inline void JsonValue::Builder::setCall( ::capnp::JsonValue::Call::Reader value) {
_builder.setDataField<JsonValue::Which>(
::capnp::bounded<0>() * ::capnp::ELEMENTS, JsonValue::CALL);
::capnp::_::PointerHelpers< ::capnp::JsonValue::Call>::set(_builder.getPointerField(
::capnp::bounded<0>() * ::capnp::POINTERS), value);
}
inline ::capnp::JsonValue::Call::Builder JsonValue::Builder::initCall() {
_builder.setDataField<JsonValue::Which>(
::capnp::bounded<0>() * ::capnp::ELEMENTS, JsonValue::CALL);
return ::capnp::_::PointerHelpers< ::capnp::JsonValue::Call>::init(_builder.getPointerField(
::capnp::bounded<0>() * ::capnp::POINTERS));
}
inline void JsonValue::Builder::adoptCall(
::capnp::Orphan< ::capnp::JsonValue::Call>&& value) {
_builder.setDataField<JsonValue::Which>(
::capnp::bounded<0>() * ::capnp::ELEMENTS, JsonValue::CALL);
::capnp::_::PointerHelpers< ::capnp::JsonValue::Call>::adopt(_builder.getPointerField(
::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value));
}
inline ::capnp::Orphan< ::capnp::JsonValue::Call> JsonValue::Builder::disownCall() {
KJ_IREQUIRE((which() == JsonValue::CALL),
"Must check which() before get()ing a union member.");
return ::capnp::_::PointerHelpers< ::capnp::JsonValue::Call>::disown(_builder.getPointerField(
::capnp::bounded<0>() * ::capnp::POINTERS));
}
inline bool JsonValue::Field::Reader::hasName() const {
return !_reader.getPointerField(
::capnp::bounded<0>() * ::capnp::POINTERS).isNull();
}
inline bool JsonValue::Field::Builder::hasName() {
return !_builder.getPointerField(
::capnp::bounded<0>() * ::capnp::POINTERS).isNull();
}
inline ::capnp::Text::Reader JsonValue::Field::Reader::getName() const {
return ::capnp::_::PointerHelpers< ::capnp::Text>::get(_reader.getPointerField(
::capnp::bounded<0>() * ::capnp::POINTERS));
}
inline ::capnp::Text::Builder JsonValue::Field::Builder::getName() {
return ::capnp::_::PointerHelpers< ::capnp::Text>::get(_builder.getPointerField(
::capnp::bounded<0>() * ::capnp::POINTERS));
}
inline void JsonValue::Field::Builder::setName( ::capnp::Text::Reader value) {
::capnp::_::PointerHelpers< ::capnp::Text>::set(_builder.getPointerField(
::capnp::bounded<0>() * ::capnp::POINTERS), value);
}
inline ::capnp::Text::Builder JsonValue::Field::Builder::initName(unsigned int size) {
return ::capnp::_::PointerHelpers< ::capnp::Text>::init(_builder.getPointerField(
::capnp::bounded<0>() * ::capnp::POINTERS), size);
}
inline void JsonValue::Field::Builder::adoptName(
::capnp::Orphan< ::capnp::Text>&& value) {
::capnp::_::PointerHelpers< ::capnp::Text>::adopt(_builder.getPointerField(
::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value));
}
inline ::capnp::Orphan< ::capnp::Text> JsonValue::Field::Builder::disownName() {
return ::capnp::_::PointerHelpers< ::capnp::Text>::disown(_builder.getPointerField(
::capnp::bounded<0>() * ::capnp::POINTERS));
}
inline bool JsonValue::Field::Reader::hasValue() const {
return !_reader.getPointerField(
::capnp::bounded<1>() * ::capnp::POINTERS).isNull();
}
inline bool JsonValue::Field::Builder::hasValue() {
return !_builder.getPointerField(
::capnp::bounded<1>() * ::capnp::POINTERS).isNull();
}
inline ::capnp::JsonValue::Reader JsonValue::Field::Reader::getValue() const {
return ::capnp::_::PointerHelpers< ::capnp::JsonValue>::get(_reader.getPointerField(
::capnp::bounded<1>() * ::capnp::POINTERS));
}
inline ::capnp::JsonValue::Builder JsonValue::Field::Builder::getValue() {
return ::capnp::_::PointerHelpers< ::capnp::JsonValue>::get(_builder.getPointerField(
::capnp::bounded<1>() * ::capnp::POINTERS));
}
#if !CAPNP_LITE
inline ::capnp::JsonValue::Pipeline JsonValue::Field::Pipeline::getValue() {
return ::capnp::JsonValue::Pipeline(_typeless.getPointerField(1));
}
#endif // !CAPNP_LITE
inline void JsonValue::Field::Builder::setValue( ::capnp::JsonValue::Reader value) {
::capnp::_::PointerHelpers< ::capnp::JsonValue>::set(_builder.getPointerField(
::capnp::bounded<1>() * ::capnp::POINTERS), value);
}
inline ::capnp::JsonValue::Builder JsonValue::Field::Builder::initValue() {
return ::capnp::_::PointerHelpers< ::capnp::JsonValue>::init(_builder.getPointerField(
::capnp::bounded<1>() * ::capnp::POINTERS));
}
inline void JsonValue::Field::Builder::adoptValue(
::capnp::Orphan< ::capnp::JsonValue>&& value) {
::capnp::_::PointerHelpers< ::capnp::JsonValue>::adopt(_builder.getPointerField(
::capnp::bounded<1>() * ::capnp::POINTERS), kj::mv(value));
}
inline ::capnp::Orphan< ::capnp::JsonValue> JsonValue::Field::Builder::disownValue() {
return ::capnp::_::PointerHelpers< ::capnp::JsonValue>::disown(_builder.getPointerField(
::capnp::bounded<1>() * ::capnp::POINTERS));
}
inline bool JsonValue::Call::Reader::hasFunction() const {
return !_reader.getPointerField(
::capnp::bounded<0>() * ::capnp::POINTERS).isNull();
}
inline bool JsonValue::Call::Builder::hasFunction() {
return !_builder.getPointerField(
::capnp::bounded<0>() * ::capnp::POINTERS).isNull();
}
inline ::capnp::Text::Reader JsonValue::Call::Reader::getFunction() const {
return ::capnp::_::PointerHelpers< ::capnp::Text>::get(_reader.getPointerField(
::capnp::bounded<0>() * ::capnp::POINTERS));
}
inline ::capnp::Text::Builder JsonValue::Call::Builder::getFunction() {
return ::capnp::_::PointerHelpers< ::capnp::Text>::get(_builder.getPointerField(
::capnp::bounded<0>() * ::capnp::POINTERS));
}
inline void JsonValue::Call::Builder::setFunction( ::capnp::Text::Reader value) {
::capnp::_::PointerHelpers< ::capnp::Text>::set(_builder.getPointerField(
::capnp::bounded<0>() * ::capnp::POINTERS), value);
}
inline ::capnp::Text::Builder JsonValue::Call::Builder::initFunction(unsigned int size) {
return ::capnp::_::PointerHelpers< ::capnp::Text>::init(_builder.getPointerField(
::capnp::bounded<0>() * ::capnp::POINTERS), size);
}
inline void JsonValue::Call::Builder::adoptFunction(
::capnp::Orphan< ::capnp::Text>&& value) {
::capnp::_::PointerHelpers< ::capnp::Text>::adopt(_builder.getPointerField(
::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value));
}
inline ::capnp::Orphan< ::capnp::Text> JsonValue::Call::Builder::disownFunction() {
return ::capnp::_::PointerHelpers< ::capnp::Text>::disown(_builder.getPointerField(
::capnp::bounded<0>() * ::capnp::POINTERS));
}
inline bool JsonValue::Call::Reader::hasParams() const {
return !_reader.getPointerField(
::capnp::bounded<1>() * ::capnp::POINTERS).isNull();
}
inline bool JsonValue::Call::Builder::hasParams() {
return !_builder.getPointerField(
::capnp::bounded<1>() * ::capnp::POINTERS).isNull();
}
inline ::capnp::List< ::capnp::JsonValue>::Reader JsonValue::Call::Reader::getParams() const {
return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::JsonValue>>::get(_reader.getPointerField(
::capnp::bounded<1>() * ::capnp::POINTERS));
}
inline ::capnp::List< ::capnp::JsonValue>::Builder JsonValue::Call::Builder::getParams() {
return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::JsonValue>>::get(_builder.getPointerField(
::capnp::bounded<1>() * ::capnp::POINTERS));
}
inline void JsonValue::Call::Builder::setParams( ::capnp::List< ::capnp::JsonValue>::Reader value) {
::capnp::_::PointerHelpers< ::capnp::List< ::capnp::JsonValue>>::set(_builder.getPointerField(
::capnp::bounded<1>() * ::capnp::POINTERS), value);
}
inline ::capnp::List< ::capnp::JsonValue>::Builder JsonValue::Call::Builder::initParams(unsigned int size) {
return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::JsonValue>>::init(_builder.getPointerField(
::capnp::bounded<1>() * ::capnp::POINTERS), size);
}
inline void JsonValue::Call::Builder::adoptParams(
::capnp::Orphan< ::capnp::List< ::capnp::JsonValue>>&& value) {
::capnp::_::PointerHelpers< ::capnp::List< ::capnp::JsonValue>>::adopt(_builder.getPointerField(
::capnp::bounded<1>() * ::capnp::POINTERS), kj::mv(value));
}
inline ::capnp::Orphan< ::capnp::List< ::capnp::JsonValue>> JsonValue::Call::Builder::disownParams() {
return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::JsonValue>>::disown(_builder.getPointerField(
::capnp::bounded<1>() * ::capnp::POINTERS));
}
} // namespace
#endif // CAPNP_INCLUDED_8ef99297a43a5e34_

View File

@ -1,462 +0,0 @@
// Copyright (c) 2015 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#ifndef CAPNP_COMPAT_JSON_H_
#define CAPNP_COMPAT_JSON_H_
#include <capnp/schema.h>
#include <capnp/dynamic.h>
#include <capnp/compat/json.capnp.h>
namespace capnp {
class JsonCodec {
// Flexible class for encoding Cap'n Proto types as JSON, and decoding JSON back to Cap'n Proto.
//
// Typical usage:
//
// JsonCodec json;
//
// // encode
// kj::String encoded = json.encode(someStructReader);
//
// // decode
// json.decode(encoded, someStructBuilder);
//
// Advanced users can do fancy things like override the way certain types or fields are
// represented in JSON by registering handlers. See the unit test for an example.
//
// Notes:
// - When encoding, all primitive fields are always encoded, even if default-valued. Pointer
// fields are only encoded if they are non-null.
// - 64-bit integers are encoded as strings, since JSON "numbers" are double-precision floating
// points which cannot store a 64-bit integer without losing data.
// - NaNs and infinite floating point numbers are not allowed by the JSON spec, and so are encoded
// as null. This matches the behavior of `JSON.stringify` in at least Firefox and Chrome.
// - Data is encoded as an array of numbers in the range [0,255]. You probably want to register
// a handler that does something better, like maybe base64 encoding, but there are a zillion
// different ways people do this.
// - Encoding/decoding capabilities and AnyPointers requires registering a Handler, since there's
// no obvious default behavior.
// - When decoding, unrecognized field names are ignored. Note: This means that JSON is NOT a
// good format for receiving input from a human. Consider `capnp eval` or the SchemaParser
// library for human input.
public:
JsonCodec();
~JsonCodec() noexcept(false);
// ---------------------------------------------------------------------------
// standard API
void setPrettyPrint(bool enabled);
// Enable to insert newlines, indentation, and other extra spacing into the output. The default
// is to use minimal whitespace.
void setMaxNestingDepth(size_t maxNestingDepth);
// Set maximum nesting depth when decoding JSON to prevent highly nested input from overflowing
// the call stack. The default is 64.
template <typename T>
kj::String encode(T&& value);
// Encode any Cap'n Proto value to JSON, including primitives and
// Dynamic{Enum,Struct,List,Capability}, but not DynamicValue (see below).
kj::String encode(DynamicValue::Reader value, Type type) const;
// Encode a DynamicValue to JSON. `type` is needed because `DynamicValue` itself does
// not distinguish between e.g. int32 and int64, which in JSON are handled differently. Most
// of the time, though, you can use the single-argument templated version of `encode()` instead.
void decode(kj::ArrayPtr<const char> input, DynamicStruct::Builder output) const;
// Decode JSON text directly into a struct builder. This only works for structs since lists
// need to be allocated with the correct size in advance.
//
// (Remember that any Cap'n Proto struct reader type can be implicitly cast to
// DynamicStruct::Reader.)
template <typename T>
Orphan<T> decode(kj::ArrayPtr<const char> input, Orphanage orphanage) const;
// Decode JSON text to any Cap'n Proto object (pointer value), allocated using the given
// orphanage. T must be specified explicitly and cannot be dynamic, e.g.:
//
// Orphan<MyType> orphan = json.decode<MyType>(text, orphanage);
template <typename T>
ReaderFor<T> decode(kj::ArrayPtr<const char> input) const;
// Decode JSON text into a primitive or capability value. T must be specified explicitly and
// cannot be dynamic, e.g.:
//
// uint32_t n = json.decode<uint32_t>(text);
Orphan<DynamicValue> decode(kj::ArrayPtr<const char> input, Type type, Orphanage orphanage) const;
Orphan<DynamicList> decode(
kj::ArrayPtr<const char> input, ListSchema type, Orphanage orphanage) const;
Orphan<DynamicStruct> decode(
kj::ArrayPtr<const char> input, StructSchema type, Orphanage orphanage) const;
DynamicCapability::Client decode(kj::ArrayPtr<const char> input, InterfaceSchema type) const;
DynamicEnum decode(kj::ArrayPtr<const char> input, EnumSchema type) const;
// Decode to a dynamic value, specifying the type schema.
// ---------------------------------------------------------------------------
// layered API
//
// You can separate text <-> JsonValue from JsonValue <-> T. These are particularly useful
// for calling from Handler implementations.
kj::String encodeRaw(JsonValue::Reader value) const;
void decodeRaw(kj::ArrayPtr<const char> input, JsonValue::Builder output) const;
// Translate JsonValue <-> text.
template <typename T>
void encode(T&& value, JsonValue::Builder output);
void encode(DynamicValue::Reader input, Type type, JsonValue::Builder output) const;
void decode(JsonValue::Reader input, DynamicStruct::Builder output) const;
template <typename T>
Orphan<T> decode(JsonValue::Reader input, Orphanage orphanage) const;
template <typename T>
ReaderFor<T> decode(JsonValue::Reader input) const;
Orphan<DynamicValue> decode(JsonValue::Reader input, Type type, Orphanage orphanage) const;
Orphan<DynamicList> decode(JsonValue::Reader input, ListSchema type, Orphanage orphanage) const;
Orphan<DynamicStruct> decode(
JsonValue::Reader input, StructSchema type, Orphanage orphanage) const;
DynamicCapability::Client decode(JsonValue::Reader input, InterfaceSchema type) const;
DynamicEnum decode(JsonValue::Reader input, EnumSchema type) const;
// ---------------------------------------------------------------------------
// specializing particular types
template <typename T, Style s = style<T>()>
class Handler;
// Implement this interface to specify a special encoding for a particular type or field.
//
// The templates are a bit ugly, but subclasses of this type essentially implement two methods,
// one to encode values of this type and one to decode values of this type. `encode()` is simple:
//
// void encode(const JsonCodec& codec, ReaderFor<T> input, JsonValue::Builder output) const;
//
// `decode()` is a bit trickier. When T is a struct (including DynamicStruct), it is:
//
// void decode(const JsonCodec& codec, JsonValue::Reader input, BuilderFor<T> output) const;
//
// However, when T is a primitive, decode() is:
//
// T decode(const JsonCodec& codec, JsonValue::Reader input) const;
//
// Or when T is any non-struct object (list, blob), decode() is:
//
// Orphan<T> decode(const JsonCodec& codec, JsonValue::Reader input, Orphanage orphanage) const;
//
// Or when T is an interface:
//
// T::Client decode(const JsonCodec& codec, JsonValue::Reader input) const;
//
// Additionally, when T is a struct you can *optionally* also implement the orphan-returning form
// of decode(), but it will only be called when the struct would be allocated as an individual
// object, not as part of a list. This allows you to return "nullptr" in these cases to say that
// the pointer value should be null. This does not apply to list elements because struct list
// elements cannot ever be null (since Cap'n Proto encodes struct lists as a flat list rather
// than list-of-pointers).
template <typename T>
void addTypeHandler(Handler<T>& handler);
void addTypeHandler(Type type, Handler<DynamicValue>& handler);
void addTypeHandler(EnumSchema type, Handler<DynamicEnum>& handler);
void addTypeHandler(StructSchema type, Handler<DynamicStruct>& handler);
void addTypeHandler(ListSchema type, Handler<DynamicList>& handler);
void addTypeHandler(InterfaceSchema type, Handler<DynamicCapability>& handler);
// Arrange that whenever the type T appears in the message, your handler will be used to
// encode/decode it.
//
// Note that if you register a handler for a capability type, it will also apply to subtypes.
// Thus Handler<Capability> handles all capabilities.
template <typename T>
void addFieldHandler(StructSchema::Field field, Handler<T>& handler);
// Matches only the specific field. T can be a dynamic type. T must match the field's type.
private:
class HandlerBase;
struct Impl;
kj::Own<Impl> impl;
void encodeField(StructSchema::Field field, DynamicValue::Reader input,
JsonValue::Builder output) const;
void decodeArray(List<JsonValue>::Reader input, DynamicList::Builder output) const;
void decodeObject(List<JsonValue::Field>::Reader input, DynamicStruct::Builder output) const;
void addTypeHandlerImpl(Type type, HandlerBase& handler);
void addFieldHandlerImpl(StructSchema::Field field, Type type, HandlerBase& handler);
};
// =======================================================================================
// inline implementation details
template <typename T>
kj::String JsonCodec::encode(T&& value) {
typedef FromAny<kj::Decay<T>> Base;
return encode(DynamicValue::Reader(ReaderFor<Base>(kj::fwd<T>(value))), Type::from<Base>());
}
template <typename T>
inline Orphan<T> JsonCodec::decode(kj::ArrayPtr<const char> input, Orphanage orphanage) const {
return decode(input, Type::from<T>(), orphanage).template releaseAs<T>();
}
template <typename T>
inline ReaderFor<T> JsonCodec::decode(kj::ArrayPtr<const char> input) const {
static_assert(style<T>() == Style::PRIMITIVE || style<T>() == Style::CAPABILITY,
"must specify an orphanage to decode an object type");
return decode(input, Type::from<T>(), Orphanage()).getReader().template as<T>();
}
inline Orphan<DynamicList> JsonCodec::decode(
kj::ArrayPtr<const char> input, ListSchema type, Orphanage orphanage) const {
return decode(input, Type(type), orphanage).releaseAs<DynamicList>();
}
inline Orphan<DynamicStruct> JsonCodec::decode(
kj::ArrayPtr<const char> input, StructSchema type, Orphanage orphanage) const {
return decode(input, Type(type), orphanage).releaseAs<DynamicStruct>();
}
inline DynamicCapability::Client JsonCodec::decode(
kj::ArrayPtr<const char> input, InterfaceSchema type) const {
return decode(input, Type(type), Orphanage()).getReader().as<DynamicCapability>();
}
inline DynamicEnum JsonCodec::decode(kj::ArrayPtr<const char> input, EnumSchema type) const {
return decode(input, Type(type), Orphanage()).getReader().as<DynamicEnum>();
}
// -----------------------------------------------------------------------------
template <typename T>
void JsonCodec::encode(T&& value, JsonValue::Builder output) {
typedef FromAny<kj::Decay<T>> Base;
encode(DynamicValue::Reader(ReaderFor<Base>(kj::fwd<T>(value))), Type::from<Base>(), output);
}
template <typename T>
inline Orphan<T> JsonCodec::decode(JsonValue::Reader input, Orphanage orphanage) const {
return decode(input, Type::from<T>(), orphanage).template releaseAs<T>();
}
template <typename T>
inline ReaderFor<T> JsonCodec::decode(JsonValue::Reader input) const {
static_assert(style<T>() == Style::PRIMITIVE || style<T>() == Style::CAPABILITY,
"must specify an orphanage to decode an object type");
return decode(input, Type::from<T>(), Orphanage()).getReader().template as<T>();
}
inline Orphan<DynamicList> JsonCodec::decode(
JsonValue::Reader input, ListSchema type, Orphanage orphanage) const {
return decode(input, Type(type), orphanage).releaseAs<DynamicList>();
}
inline Orphan<DynamicStruct> JsonCodec::decode(
JsonValue::Reader input, StructSchema type, Orphanage orphanage) const {
return decode(input, Type(type), orphanage).releaseAs<DynamicStruct>();
}
inline DynamicCapability::Client JsonCodec::decode(
JsonValue::Reader input, InterfaceSchema type) const {
return decode(input, Type(type), Orphanage()).getReader().as<DynamicCapability>();
}
inline DynamicEnum JsonCodec::decode(JsonValue::Reader input, EnumSchema type) const {
return decode(input, Type(type), Orphanage()).getReader().as<DynamicEnum>();
}
// -----------------------------------------------------------------------------
class JsonCodec::HandlerBase {
// Internal helper; ignore.
public:
virtual void encodeBase(const JsonCodec& codec, DynamicValue::Reader input,
JsonValue::Builder output) const = 0;
virtual Orphan<DynamicValue> decodeBase(const JsonCodec& codec, JsonValue::Reader input,
Type type, Orphanage orphanage) const;
virtual void decodeStructBase(const JsonCodec& codec, JsonValue::Reader input,
DynamicStruct::Builder output) const;
};
template <typename T>
class JsonCodec::Handler<T, Style::POINTER>: private JsonCodec::HandlerBase {
public:
virtual void encode(const JsonCodec& codec, ReaderFor<T> input,
JsonValue::Builder output) const = 0;
virtual Orphan<T> decode(const JsonCodec& codec, JsonValue::Reader input,
Orphanage orphanage) const = 0;
private:
void encodeBase(const JsonCodec& codec, DynamicValue::Reader input,
JsonValue::Builder output) const override final {
encode(codec, input.as<T>(), output);
}
Orphan<DynamicValue> decodeBase(const JsonCodec& codec, JsonValue::Reader input,
Type type, Orphanage orphanage) const override final {
return decode(codec, input, orphanage);
}
friend class JsonCodec;
};
template <typename T>
class JsonCodec::Handler<T, Style::STRUCT>: private JsonCodec::HandlerBase {
public:
virtual void encode(const JsonCodec& codec, ReaderFor<T> input,
JsonValue::Builder output) const = 0;
virtual void decode(const JsonCodec& codec, JsonValue::Reader input,
BuilderFor<T> output) const = 0;
virtual Orphan<T> decode(const JsonCodec& codec, JsonValue::Reader input,
Orphanage orphanage) const {
// If subclass does not override, fall back to regular version.
auto result = orphanage.newOrphan<T>();
decode(codec, input, result.get());
return result;
}
private:
void encodeBase(const JsonCodec& codec, DynamicValue::Reader input,
JsonValue::Builder output) const override final {
encode(codec, input.as<T>(), output);
}
Orphan<DynamicValue> decodeBase(const JsonCodec& codec, JsonValue::Reader input,
Type type, Orphanage orphanage) const override final {
return decode(codec, input, orphanage);
}
void decodeStructBase(const JsonCodec& codec, JsonValue::Reader input,
DynamicStruct::Builder output) const override final {
decode(codec, input, output.as<T>());
}
friend class JsonCodec;
};
template <>
class JsonCodec::Handler<DynamicStruct>: private JsonCodec::HandlerBase {
// Almost identical to Style::STRUCT except that we pass the struct type to decode().
public:
virtual void encode(const JsonCodec& codec, DynamicStruct::Reader input,
JsonValue::Builder output) const = 0;
virtual void decode(const JsonCodec& codec, JsonValue::Reader input,
DynamicStruct::Builder output) const = 0;
virtual Orphan<DynamicStruct> decode(const JsonCodec& codec, JsonValue::Reader input,
StructSchema type, Orphanage orphanage) const {
// If subclass does not override, fall back to regular version.
auto result = orphanage.newOrphan(type);
decode(codec, input, result.get());
return result;
}
private:
void encodeBase(const JsonCodec& codec, DynamicValue::Reader input,
JsonValue::Builder output) const override final {
encode(codec, input.as<DynamicStruct>(), output);
}
Orphan<DynamicValue> decodeBase(const JsonCodec& codec, JsonValue::Reader input,
Type type, Orphanage orphanage) const override final {
return decode(codec, input, type.asStruct(), orphanage);
}
void decodeStructBase(const JsonCodec& codec, JsonValue::Reader input,
DynamicStruct::Builder output) const override final {
decode(codec, input, output.as<DynamicStruct>());
}
friend class JsonCodec;
};
template <typename T>
class JsonCodec::Handler<T, Style::PRIMITIVE>: private JsonCodec::HandlerBase {
public:
virtual void encode(const JsonCodec& codec, T input, JsonValue::Builder output) const = 0;
virtual T decode(const JsonCodec& codec, JsonValue::Reader input) const = 0;
private:
void encodeBase(const JsonCodec& codec, DynamicValue::Reader input,
JsonValue::Builder output) const override final {
encode(codec, input.as<T>(), output);
}
Orphan<DynamicValue> decodeBase(const JsonCodec& codec, JsonValue::Reader input,
Type type, Orphanage orphanage) const override final {
return decode(codec, input);
}
friend class JsonCodec;
};
template <typename T>
class JsonCodec::Handler<T, Style::CAPABILITY>: private JsonCodec::HandlerBase {
public:
virtual void encode(const JsonCodec& codec, typename T::Client input,
JsonValue::Builder output) const = 0;
virtual typename T::Client decode(const JsonCodec& codec, JsonValue::Reader input) const = 0;
private:
void encodeBase(const JsonCodec& codec, DynamicValue::Reader input,
JsonValue::Builder output) const override final {
encode(codec, input.as<T>(), output);
}
Orphan<DynamicValue> decodeBase(const JsonCodec& codec, JsonValue::Reader input,
Type type, Orphanage orphanage) const override final {
return orphanage.newOrphanCopy(decode(codec, input));
}
friend class JsonCodec;
};
template <typename T>
inline void JsonCodec::addTypeHandler(Handler<T>& handler) {
addTypeHandlerImpl(Type::from<T>(), handler);
}
inline void JsonCodec::addTypeHandler(Type type, Handler<DynamicValue>& handler) {
addTypeHandlerImpl(type, handler);
}
inline void JsonCodec::addTypeHandler(EnumSchema type, Handler<DynamicEnum>& handler) {
addTypeHandlerImpl(type, handler);
}
inline void JsonCodec::addTypeHandler(StructSchema type, Handler<DynamicStruct>& handler) {
addTypeHandlerImpl(type, handler);
}
inline void JsonCodec::addTypeHandler(ListSchema type, Handler<DynamicList>& handler) {
addTypeHandlerImpl(type, handler);
}
inline void JsonCodec::addTypeHandler(InterfaceSchema type, Handler<DynamicCapability>& handler) {
addTypeHandlerImpl(type, handler);
}
template <typename T>
inline void JsonCodec::addFieldHandler(StructSchema::Field field, Handler<T>& handler) {
addFieldHandlerImpl(field, Type::from<T>(), handler);
}
template <> void JsonCodec::addTypeHandler(Handler<DynamicValue>& handler)
KJ_UNAVAILABLE("JSON handlers for type sets (e.g. all structs, all lists) not implemented; "
"try specifying a specific type schema as the first parameter");
template <> void JsonCodec::addTypeHandler(Handler<DynamicEnum>& handler)
KJ_UNAVAILABLE("JSON handlers for type sets (e.g. all structs, all lists) not implemented; "
"try specifying a specific type schema as the first parameter");
template <> void JsonCodec::addTypeHandler(Handler<DynamicStruct>& handler)
KJ_UNAVAILABLE("JSON handlers for type sets (e.g. all structs, all lists) not implemented; "
"try specifying a specific type schema as the first parameter");
template <> void JsonCodec::addTypeHandler(Handler<DynamicList>& handler)
KJ_UNAVAILABLE("JSON handlers for type sets (e.g. all structs, all lists) not implemented; "
"try specifying a specific type schema as the first parameter");
template <> void JsonCodec::addTypeHandler(Handler<DynamicCapability>& handler)
KJ_UNAVAILABLE("JSON handlers for type sets (e.g. all structs, all lists) not implemented; "
"try specifying a specific type schema as the first parameter");
// TODO(someday): Implement support for registering handlers that cover thinsg like "all structs"
// or "all lists". Currently you can only target a specific struct or list type.
} // namespace capnp
#endif // CAPNP_COMPAT_JSON_H_

File diff suppressed because it is too large Load Diff

View File

@ -1,309 +0,0 @@
// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#ifndef CAPNP_ENDIAN_H_
#define CAPNP_ENDIAN_H_
#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS)
#pragma GCC system_header
#endif
#include "common.h"
#include <inttypes.h>
#include <string.h> // memcpy
namespace capnp {
namespace _ { // private
// WireValue
//
// Wraps a primitive value as it appears on the wire. Namely, values are little-endian on the
// wire, because little-endian is the most common endianness in modern CPUs.
//
// Note: In general, code that depends cares about byte ordering is bad. See:
// http://commandcenter.blogspot.com/2012/04/byte-order-fallacy.html
// Cap'n Proto is special because it is essentially doing compiler-like things, fussing over
// allocation and layout of memory, in order to squeeze out every last drop of performance.
#if _MSC_VER
// Assume Windows is little-endian.
//
// TODO(msvc): This is ugly. Maybe refactor later checks to be based on CAPNP_BYTE_ORDER or
// CAPNP_SWAP_BYTES or something, and define that in turn based on _MSC_VER or the GCC
// intrinsics.
#ifndef __ORDER_BIG_ENDIAN__
#define __ORDER_BIG_ENDIAN__ 4321
#endif
#ifndef __ORDER_LITTLE_ENDIAN__
#define __ORDER_LITTLE_ENDIAN__ 1234
#endif
#ifndef __BYTE_ORDER__
#define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__
#endif
#endif
#if CAPNP_REVERSE_ENDIAN
#define CAPNP_WIRE_BYTE_ORDER __ORDER_BIG_ENDIAN__
#define CAPNP_OPPOSITE_OF_WIRE_BYTE_ORDER __ORDER_LITTLE_ENDIAN__
#else
#define CAPNP_WIRE_BYTE_ORDER __ORDER_LITTLE_ENDIAN__
#define CAPNP_OPPOSITE_OF_WIRE_BYTE_ORDER __ORDER_BIG_ENDIAN__
#endif
#if defined(__BYTE_ORDER__) && \
__BYTE_ORDER__ == CAPNP_WIRE_BYTE_ORDER && \
!CAPNP_DISABLE_ENDIAN_DETECTION
// CPU is little-endian. We can just read/write the memory directly.
template <typename T>
class DirectWireValue {
public:
KJ_ALWAYS_INLINE(T get() const) { return value; }
KJ_ALWAYS_INLINE(void set(T newValue)) { value = newValue; }
private:
T value;
};
template <typename T>
using WireValue = DirectWireValue<T>;
// To prevent ODR problems when endian-test, endian-reverse-test, and endian-fallback-test are
// linked together, we define each implementation with a different name and define an alias to the
// one we want to use.
#elif defined(__BYTE_ORDER__) && \
__BYTE_ORDER__ == CAPNP_OPPOSITE_OF_WIRE_BYTE_ORDER && \
defined(__GNUC__) && !CAPNP_DISABLE_ENDIAN_DETECTION
// Big-endian, but GCC's __builtin_bswap() is available.
// TODO(perf): Use dedicated instructions to read little-endian data on big-endian CPUs that have
// them.
// TODO(perf): Verify that this code optimizes reasonably. In particular, ensure that the
// compiler optimizes away the memcpy()s and keeps everything in registers.
template <typename T, size_t size = sizeof(T)>
class SwappingWireValue;
template <typename T>
class SwappingWireValue<T, 1> {
public:
KJ_ALWAYS_INLINE(T get() const) { return value; }
KJ_ALWAYS_INLINE(void set(T newValue)) { value = newValue; }
private:
T value;
};
template <typename T>
class SwappingWireValue<T, 2> {
public:
KJ_ALWAYS_INLINE(T get() const) {
// Not all platforms have __builtin_bswap16() for some reason. In particular, it is missing
// on gcc-4.7.3-cygwin32 (but present on gcc-4.8.1-cygwin64).
uint16_t swapped = (value << 8) | (value >> 8);
T result;
memcpy(&result, &swapped, sizeof(T));
return result;
}
KJ_ALWAYS_INLINE(void set(T newValue)) {
uint16_t raw;
memcpy(&raw, &newValue, sizeof(T));
// Not all platforms have __builtin_bswap16() for some reason. In particular, it is missing
// on gcc-4.7.3-cygwin32 (but present on gcc-4.8.1-cygwin64).
value = (raw << 8) | (raw >> 8);
}
private:
uint16_t value;
};
template <typename T>
class SwappingWireValue<T, 4> {
public:
KJ_ALWAYS_INLINE(T get() const) {
uint32_t swapped = __builtin_bswap32(value);
T result;
memcpy(&result, &swapped, sizeof(T));
return result;
}
KJ_ALWAYS_INLINE(void set(T newValue)) {
uint32_t raw;
memcpy(&raw, &newValue, sizeof(T));
value = __builtin_bswap32(raw);
}
private:
uint32_t value;
};
template <typename T>
class SwappingWireValue<T, 8> {
public:
KJ_ALWAYS_INLINE(T get() const) {
uint64_t swapped = __builtin_bswap64(value);
T result;
memcpy(&result, &swapped, sizeof(T));
return result;
}
KJ_ALWAYS_INLINE(void set(T newValue)) {
uint64_t raw;
memcpy(&raw, &newValue, sizeof(T));
value = __builtin_bswap64(raw);
}
private:
uint64_t value;
};
template <typename T>
using WireValue = SwappingWireValue<T>;
// To prevent ODR problems when endian-test, endian-reverse-test, and endian-fallback-test are
// linked together, we define each implementation with a different name and define an alias to the
// one we want to use.
#else
// Unknown endianness. Fall back to bit shifts.
#if !CAPNP_DISABLE_ENDIAN_DETECTION
#if _MSC_VER
#pragma message("Couldn't detect endianness of your platform. Using unoptimized fallback implementation.")
#pragma message("Consider changing this code to detect your platform and send us a patch!")
#else
#warning "Couldn't detect endianness of your platform. Using unoptimized fallback implementation."
#warning "Consider changing this code to detect your platform and send us a patch!"
#endif
#endif // !CAPNP_DISABLE_ENDIAN_DETECTION
template <typename T, size_t size = sizeof(T)>
class ShiftingWireValue;
template <typename T>
class ShiftingWireValue<T, 1> {
public:
KJ_ALWAYS_INLINE(T get() const) { return value; }
KJ_ALWAYS_INLINE(void set(T newValue)) { value = newValue; }
private:
T value;
};
template <typename T>
class ShiftingWireValue<T, 2> {
public:
KJ_ALWAYS_INLINE(T get() const) {
uint16_t raw = (static_cast<uint16_t>(bytes[0]) ) |
(static_cast<uint16_t>(bytes[1]) << 8);
T result;
memcpy(&result, &raw, sizeof(T));
return result;
}
KJ_ALWAYS_INLINE(void set(T newValue)) {
uint16_t raw;
memcpy(&raw, &newValue, sizeof(T));
bytes[0] = raw;
bytes[1] = raw >> 8;
}
private:
union {
byte bytes[2];
uint16_t align;
};
};
template <typename T>
class ShiftingWireValue<T, 4> {
public:
KJ_ALWAYS_INLINE(T get() const) {
uint32_t raw = (static_cast<uint32_t>(bytes[0]) ) |
(static_cast<uint32_t>(bytes[1]) << 8) |
(static_cast<uint32_t>(bytes[2]) << 16) |
(static_cast<uint32_t>(bytes[3]) << 24);
T result;
memcpy(&result, &raw, sizeof(T));
return result;
}
KJ_ALWAYS_INLINE(void set(T newValue)) {
uint32_t raw;
memcpy(&raw, &newValue, sizeof(T));
bytes[0] = raw;
bytes[1] = raw >> 8;
bytes[2] = raw >> 16;
bytes[3] = raw >> 24;
}
private:
union {
byte bytes[4];
uint32_t align;
};
};
template <typename T>
class ShiftingWireValue<T, 8> {
public:
KJ_ALWAYS_INLINE(T get() const) {
uint64_t raw = (static_cast<uint64_t>(bytes[0]) ) |
(static_cast<uint64_t>(bytes[1]) << 8) |
(static_cast<uint64_t>(bytes[2]) << 16) |
(static_cast<uint64_t>(bytes[3]) << 24) |
(static_cast<uint64_t>(bytes[4]) << 32) |
(static_cast<uint64_t>(bytes[5]) << 40) |
(static_cast<uint64_t>(bytes[6]) << 48) |
(static_cast<uint64_t>(bytes[7]) << 56);
T result;
memcpy(&result, &raw, sizeof(T));
return result;
}
KJ_ALWAYS_INLINE(void set(T newValue)) {
uint64_t raw;
memcpy(&raw, &newValue, sizeof(T));
bytes[0] = raw;
bytes[1] = raw >> 8;
bytes[2] = raw >> 16;
bytes[3] = raw >> 24;
bytes[4] = raw >> 32;
bytes[5] = raw >> 40;
bytes[6] = raw >> 48;
bytes[7] = raw >> 56;
}
private:
union {
byte bytes[8];
uint64_t align;
};
};
template <typename T>
using WireValue = ShiftingWireValue<T>;
// To prevent ODR problems when endian-test, endian-reverse-test, and endian-fallback-test are
// linked together, we define each implementation with a different name and define an alias to the
// one we want to use.
#endif
} // namespace _ (private)
} // namespace capnp
#endif // CAPNP_ENDIAN_H_

View File

@ -1,254 +0,0 @@
// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#ifndef CAPNP_EZ_RPC_H_
#define CAPNP_EZ_RPC_H_
#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS)
#pragma GCC system_header
#endif
#include "rpc.h"
#include "message.h"
struct sockaddr;
namespace kj { class AsyncIoProvider; class LowLevelAsyncIoProvider; }
namespace capnp {
class EzRpcContext;
class EzRpcClient {
// Super-simple interface for setting up a Cap'n Proto RPC client. Example:
//
// # Cap'n Proto schema
// interface Adder {
// add @0 (left :Int32, right :Int32) -> (value :Int32);
// }
//
// // C++ client
// int main() {
// capnp::EzRpcClient client("localhost:3456");
// Adder::Client adder = client.getMain<Adder>();
// auto request = adder.addRequest();
// request.setLeft(12);
// request.setRight(34);
// auto response = request.send().wait(client.getWaitScope());
// assert(response.getValue() == 46);
// return 0;
// }
//
// // C++ server
// class AdderImpl final: public Adder::Server {
// public:
// kj::Promise<void> add(AddContext context) override {
// auto params = context.getParams();
// context.getResults().setValue(params.getLeft() + params.getRight());
// return kj::READY_NOW;
// }
// };
//
// int main() {
// capnp::EzRpcServer server(kj::heap<AdderImpl>(), "*:3456");
// kj::NEVER_DONE.wait(server.getWaitScope());
// }
//
// This interface is easy, but it hides a lot of useful features available from the lower-level
// classes:
// - The server can only export a small set of public, singleton capabilities under well-known
// string names. This is fine for transient services where no state needs to be kept between
// connections, but hides the power of Cap'n Proto when it comes to long-lived resources.
// - EzRpcClient/EzRpcServer automatically set up a `kj::EventLoop` and make it current for the
// thread. Only one `kj::EventLoop` can exist per thread, so you cannot use these interfaces
// if you wish to set up your own event loop. (However, you can safely create multiple
// EzRpcClient / EzRpcServer objects in a single thread; they will make sure to make no more
// than one EventLoop.)
// - These classes only support simple two-party connections, not multilateral VatNetworks.
// - These classes only support communication over a raw, unencrypted socket. If you want to
// build on an abstract stream (perhaps one which supports encryption), you must use the
// lower-level interfaces.
//
// Some of these restrictions will probably be lifted in future versions, but some things will
// always require using the low-level interfaces directly. If you are interested in working
// at a lower level, start by looking at these interfaces:
// - `kj::setupAsyncIo()` in `kj/async-io.h`.
// - `RpcSystem` in `capnp/rpc.h`.
// - `TwoPartyVatNetwork` in `capnp/rpc-twoparty.h`.
public:
explicit EzRpcClient(kj::StringPtr serverAddress, uint defaultPort = 0,
ReaderOptions readerOpts = ReaderOptions());
// Construct a new EzRpcClient and connect to the given address. The connection is formed in
// the background -- if it fails, calls to capabilities returned by importCap() will fail with an
// appropriate exception.
//
// `defaultPort` is the IP port number to use if `serverAddress` does not include it explicitly.
// If unspecified, the port is required in `serverAddress`.
//
// The address is parsed by `kj::Network` in `kj/async-io.h`. See that interface for more info
// on the address format, but basically it's what you'd expect.
//
// `readerOpts` is the ReaderOptions structure used to read each incoming message on the
// connection. Setting this may be necessary if you need to receive very large individual
// messages or messages. However, it is recommended that you instead think about how to change
// your protocol to send large data blobs in multiple small chunks -- this is much better for
// both security and performance. See `ReaderOptions` in `message.h` for more details.
EzRpcClient(const struct sockaddr* serverAddress, uint addrSize,
ReaderOptions readerOpts = ReaderOptions());
// Like the above constructor, but connects to an already-resolved socket address. Any address
// format supported by `kj::Network` in `kj/async-io.h` is accepted.
explicit EzRpcClient(int socketFd, ReaderOptions readerOpts = ReaderOptions());
// Create a client on top of an already-connected socket.
// `readerOpts` acts as in the first constructor.
~EzRpcClient() noexcept(false);
template <typename Type>
typename Type::Client getMain();
Capability::Client getMain();
// Get the server's main (aka "bootstrap") interface.
template <typename Type>
typename Type::Client importCap(kj::StringPtr name)
KJ_DEPRECATED("Change your server to export a main interface, then use getMain() instead.");
Capability::Client importCap(kj::StringPtr name)
KJ_DEPRECATED("Change your server to export a main interface, then use getMain() instead.");
// ** DEPRECATED **
//
// Ask the sever for the capability with the given name. You may specify a type to automatically
// down-cast to that type. It is up to you to specify the correct expected type.
//
// Named interfaces are deprecated. The new preferred usage pattern is for the server to export
// a "main" interface which itself has methods for getting any other interfaces.
kj::WaitScope& getWaitScope();
// Get the `WaitScope` for the client's `EventLoop`, which allows you to synchronously wait on
// promises.
kj::AsyncIoProvider& getIoProvider();
// Get the underlying AsyncIoProvider set up by the RPC system. This is useful if you want
// to do some non-RPC I/O in asynchronous fashion.
kj::LowLevelAsyncIoProvider& getLowLevelIoProvider();
// Get the underlying LowLevelAsyncIoProvider set up by the RPC system. This is useful if you
// want to do some non-RPC I/O in asynchronous fashion.
private:
struct Impl;
kj::Own<Impl> impl;
};
class EzRpcServer {
// The server counterpart to `EzRpcClient`. See `EzRpcClient` for an example.
public:
explicit EzRpcServer(Capability::Client mainInterface, kj::StringPtr bindAddress,
uint defaultPort = 0, ReaderOptions readerOpts = ReaderOptions());
// Construct a new `EzRpcServer` that binds to the given address. An address of "*" means to
// bind to all local addresses.
//
// `defaultPort` is the IP port number to use if `serverAddress` does not include it explicitly.
// If unspecified, a port is chosen automatically, and you must call getPort() to find out what
// it is.
//
// The address is parsed by `kj::Network` in `kj/async-io.h`. See that interface for more info
// on the address format, but basically it's what you'd expect.
//
// The server might not begin listening immediately, especially if `bindAddress` needs to be
// resolved. If you need to wait until the server is definitely up, wait on the promise returned
// by `getPort()`.
//
// `readerOpts` is the ReaderOptions structure used to read each incoming message on the
// connection. Setting this may be necessary if you need to receive very large individual
// messages or messages. However, it is recommended that you instead think about how to change
// your protocol to send large data blobs in multiple small chunks -- this is much better for
// both security and performance. See `ReaderOptions` in `message.h` for more details.
EzRpcServer(Capability::Client mainInterface, struct sockaddr* bindAddress, uint addrSize,
ReaderOptions readerOpts = ReaderOptions());
// Like the above constructor, but binds to an already-resolved socket address. Any address
// format supported by `kj::Network` in `kj/async-io.h` is accepted.
EzRpcServer(Capability::Client mainInterface, int socketFd, uint port,
ReaderOptions readerOpts = ReaderOptions());
// Create a server on top of an already-listening socket (i.e. one on which accept() may be
// called). `port` is returned by `getPort()` -- it serves no other purpose.
// `readerOpts` acts as in the other two above constructors.
explicit EzRpcServer(kj::StringPtr bindAddress, uint defaultPort = 0,
ReaderOptions readerOpts = ReaderOptions())
KJ_DEPRECATED("Please specify a main interface for your server.");
EzRpcServer(struct sockaddr* bindAddress, uint addrSize,
ReaderOptions readerOpts = ReaderOptions())
KJ_DEPRECATED("Please specify a main interface for your server.");
EzRpcServer(int socketFd, uint port, ReaderOptions readerOpts = ReaderOptions())
KJ_DEPRECATED("Please specify a main interface for your server.");
~EzRpcServer() noexcept(false);
void exportCap(kj::StringPtr name, Capability::Client cap);
// Export a capability publicly under the given name, so that clients can import it.
//
// Keep in mind that you can implicitly convert `kj::Own<MyType::Server>&&` to
// `Capability::Client`, so it's typical to pass something like
// `kj::heap<MyImplementation>(<constructor params>)` as the second parameter.
kj::Promise<uint> getPort();
// Get the IP port number on which this server is listening. This promise won't resolve until
// the server is actually listening. If the address was not an IP address (e.g. it was a Unix
// domain socket) then getPort() resolves to zero.
kj::WaitScope& getWaitScope();
// Get the `WaitScope` for the client's `EventLoop`, which allows you to synchronously wait on
// promises.
kj::AsyncIoProvider& getIoProvider();
// Get the underlying AsyncIoProvider set up by the RPC system. This is useful if you want
// to do some non-RPC I/O in asynchronous fashion.
kj::LowLevelAsyncIoProvider& getLowLevelIoProvider();
// Get the underlying LowLevelAsyncIoProvider set up by the RPC system. This is useful if you
// want to do some non-RPC I/O in asynchronous fashion.
private:
struct Impl;
kj::Own<Impl> impl;
};
// =======================================================================================
// inline implementation details
template <typename Type>
inline typename Type::Client EzRpcClient::getMain() {
return getMain().castAs<Type>();
}
template <typename Type>
inline typename Type::Client EzRpcClient::importCap(kj::StringPtr name) {
return importCap(name).castAs<Type>();
}
} // namespace capnp
#endif // CAPNP_EZ_RPC_H_

View File

@ -1,407 +0,0 @@
// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
// This file is included from all generated headers.
#ifndef CAPNP_GENERATED_HEADER_SUPPORT_H_
#define CAPNP_GENERATED_HEADER_SUPPORT_H_
#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS)
#pragma GCC system_header
#endif
#include "raw-schema.h"
#include "layout.h"
#include "list.h"
#include "orphan.h"
#include "pointer-helpers.h"
#include "any.h"
#include <kj/string.h>
#include <kj/string-tree.h>
namespace capnp {
class MessageBuilder; // So that it can be declared a friend.
template <typename T, Kind k = CAPNP_KIND(T)>
struct ToDynamic_; // Defined in dynamic.h, needs to be declared as everyone's friend.
struct DynamicStruct; // So that it can be declared a friend.
struct Capability; // To declare brandBindingFor<Capability>()
namespace _ { // private
#if !CAPNP_LITE
template <typename T, typename CapnpPrivate = typename T::_capnpPrivate, bool = false>
inline const RawSchema& rawSchema() {
return *CapnpPrivate::schema;
}
template <typename T, uint64_t id = schemas::EnumInfo<T>::typeId>
inline const RawSchema& rawSchema() {
return *schemas::EnumInfo<T>::schema;
}
template <typename T, typename CapnpPrivate = typename T::_capnpPrivate>
inline const RawBrandedSchema& rawBrandedSchema() {
return *CapnpPrivate::brand();
}
template <typename T, uint64_t id = schemas::EnumInfo<T>::typeId>
inline const RawBrandedSchema& rawBrandedSchema() {
return schemas::EnumInfo<T>::schema->defaultBrand;
}
template <typename TypeTag, typename... Params>
struct ChooseBrand;
// If all of `Params` are `AnyPointer`, return the type's default brand. Otherwise, return a
// specific brand instance. TypeTag is the _capnpPrivate struct for the type in question.
template <typename TypeTag>
struct ChooseBrand<TypeTag> {
// All params were AnyPointer. No specific brand needed.
static constexpr _::RawBrandedSchema const* brand() { return &TypeTag::schema->defaultBrand; }
};
template <typename TypeTag, typename... Rest>
struct ChooseBrand<TypeTag, AnyPointer, Rest...>: public ChooseBrand<TypeTag, Rest...> {};
// The first parameter is AnyPointer, so recurse to check the rest.
template <typename TypeTag, typename First, typename... Rest>
struct ChooseBrand<TypeTag, First, Rest...> {
// At least one parameter is not AnyPointer, so use the specificBrand constant.
static constexpr _::RawBrandedSchema const* brand() { return &TypeTag::specificBrand; }
};
template <typename T, Kind k = kind<T>()>
struct BrandBindingFor_;
#define HANDLE_TYPE(Type, which) \
template <> \
struct BrandBindingFor_<Type, Kind::PRIMITIVE> { \
static constexpr RawBrandedSchema::Binding get(uint16_t listDepth) { \
return { which, listDepth, nullptr }; \
} \
}
HANDLE_TYPE(Void, 0);
HANDLE_TYPE(bool, 1);
HANDLE_TYPE(int8_t, 2);
HANDLE_TYPE(int16_t, 3);
HANDLE_TYPE(int32_t, 4);
HANDLE_TYPE(int64_t, 5);
HANDLE_TYPE(uint8_t, 6);
HANDLE_TYPE(uint16_t, 7);
HANDLE_TYPE(uint32_t, 8);
HANDLE_TYPE(uint64_t, 9);
HANDLE_TYPE(float, 10);
HANDLE_TYPE(double, 11);
#undef HANDLE_TYPE
template <>
struct BrandBindingFor_<Text, Kind::BLOB> {
static constexpr RawBrandedSchema::Binding get(uint16_t listDepth) {
return { 12, listDepth, nullptr };
}
};
template <>
struct BrandBindingFor_<Data, Kind::BLOB> {
static constexpr RawBrandedSchema::Binding get(uint16_t listDepth) {
return { 13, listDepth, nullptr };
}
};
template <typename T>
struct BrandBindingFor_<List<T>, Kind::LIST> {
static constexpr RawBrandedSchema::Binding get(uint16_t listDepth) {
return BrandBindingFor_<T>::get(listDepth + 1);
}
};
template <typename T>
struct BrandBindingFor_<T, Kind::ENUM> {
static constexpr RawBrandedSchema::Binding get(uint16_t listDepth) {
return { 15, listDepth, nullptr };
}
};
template <typename T>
struct BrandBindingFor_<T, Kind::STRUCT> {
static constexpr RawBrandedSchema::Binding get(uint16_t listDepth) {
return { 16, listDepth, T::_capnpPrivate::brand() };
}
};
template <typename T>
struct BrandBindingFor_<T, Kind::INTERFACE> {
static constexpr RawBrandedSchema::Binding get(uint16_t listDepth) {
return { 17, listDepth, T::_capnpPrivate::brand() };
}
};
template <>
struct BrandBindingFor_<AnyPointer, Kind::OTHER> {
static constexpr RawBrandedSchema::Binding get(uint16_t listDepth) {
return { 18, listDepth, 0, 0 };
}
};
template <>
struct BrandBindingFor_<AnyStruct, Kind::OTHER> {
static constexpr RawBrandedSchema::Binding get(uint16_t listDepth) {
return { 18, listDepth, 0, 1 };
}
};
template <>
struct BrandBindingFor_<AnyList, Kind::OTHER> {
static constexpr RawBrandedSchema::Binding get(uint16_t listDepth) {
return { 18, listDepth, 0, 2 };
}
};
template <>
struct BrandBindingFor_<Capability, Kind::OTHER> {
static constexpr RawBrandedSchema::Binding get(uint16_t listDepth) {
return { 18, listDepth, 0, 3 };
}
};
template <typename T>
constexpr RawBrandedSchema::Binding brandBindingFor() {
return BrandBindingFor_<T>::get(0);
}
kj::StringTree structString(StructReader reader, const RawBrandedSchema& schema);
kj::String enumString(uint16_t value, const RawBrandedSchema& schema);
// Declared here so that we can declare inline stringify methods on generated types.
// Defined in stringify.c++, which depends on dynamic.c++, which is allowed not to be linked in.
template <typename T>
inline kj::StringTree structString(StructReader reader) {
return structString(reader, rawBrandedSchema<T>());
}
template <typename T>
inline kj::String enumString(T value) {
return enumString(static_cast<uint16_t>(value), rawBrandedSchema<T>());
}
#endif // !CAPNP_LITE
// TODO(cleanup): Unify ConstStruct and ConstList.
template <typename T>
class ConstStruct {
public:
ConstStruct() = delete;
KJ_DISALLOW_COPY(ConstStruct);
inline explicit constexpr ConstStruct(const word* ptr): ptr(ptr) {}
inline typename T::Reader get() const {
return AnyPointer::Reader(PointerReader::getRootUnchecked(ptr)).getAs<T>();
}
inline operator typename T::Reader() const { return get(); }
inline typename T::Reader operator*() const { return get(); }
inline TemporaryPointer<typename T::Reader> operator->() const { return get(); }
private:
const word* ptr;
};
template <typename T>
class ConstList {
public:
ConstList() = delete;
KJ_DISALLOW_COPY(ConstList);
inline explicit constexpr ConstList(const word* ptr): ptr(ptr) {}
inline typename List<T>::Reader get() const {
return AnyPointer::Reader(PointerReader::getRootUnchecked(ptr)).getAs<List<T>>();
}
inline operator typename List<T>::Reader() const { return get(); }
inline typename List<T>::Reader operator*() const { return get(); }
inline TemporaryPointer<typename List<T>::Reader> operator->() const { return get(); }
private:
const word* ptr;
};
template <size_t size>
class ConstText {
public:
ConstText() = delete;
KJ_DISALLOW_COPY(ConstText);
inline explicit constexpr ConstText(const word* ptr): ptr(ptr) {}
inline Text::Reader get() const {
return Text::Reader(reinterpret_cast<const char*>(ptr), size);
}
inline operator Text::Reader() const { return get(); }
inline Text::Reader operator*() const { return get(); }
inline TemporaryPointer<Text::Reader> operator->() const { return get(); }
inline kj::StringPtr toString() const {
return get();
}
private:
const word* ptr;
};
template <size_t size>
inline kj::StringPtr KJ_STRINGIFY(const ConstText<size>& s) {
return s.get();
}
template <size_t size>
class ConstData {
public:
ConstData() = delete;
KJ_DISALLOW_COPY(ConstData);
inline explicit constexpr ConstData(const word* ptr): ptr(ptr) {}
inline Data::Reader get() const {
return Data::Reader(reinterpret_cast<const byte*>(ptr), size);
}
inline operator Data::Reader() const { return get(); }
inline Data::Reader operator*() const { return get(); }
inline TemporaryPointer<Data::Reader> operator->() const { return get(); }
private:
const word* ptr;
};
template <size_t size>
inline auto KJ_STRINGIFY(const ConstData<size>& s) -> decltype(kj::toCharSequence(s.get())) {
return kj::toCharSequence(s.get());
}
} // namespace _ (private)
template <typename T, typename CapnpPrivate = typename T::_capnpPrivate>
inline constexpr uint64_t typeId() { return CapnpPrivate::typeId; }
template <typename T, uint64_t id = schemas::EnumInfo<T>::typeId>
inline constexpr uint64_t typeId() { return id; }
// typeId<MyType>() returns the type ID as defined in the schema. Works with structs, enums, and
// interfaces.
template <typename T>
inline constexpr uint sizeInWords() {
// Return the size, in words, of a Struct type, if allocated free-standing (not in a list).
// May be useful for pre-computing space needed in order to precisely allocate messages.
return unbound((upgradeBound<uint>(_::structSize<T>().data) +
_::structSize<T>().pointers * WORDS_PER_POINTER) / WORDS);
}
} // namespace capnp
#if _MSC_VER
// MSVC doesn't understand floating-point constexpr yet.
//
// TODO(msvc): Remove this hack when MSVC is fixed.
#define CAPNP_NON_INT_CONSTEXPR_DECL_INIT(value)
#define CAPNP_NON_INT_CONSTEXPR_DEF_INIT(value) = value
#else
#define CAPNP_NON_INT_CONSTEXPR_DECL_INIT(value) = value
#define CAPNP_NON_INT_CONSTEXPR_DEF_INIT(value)
#endif
#if _MSC_VER
// TODO(msvc): A little hack to allow MSVC to use C++14 return type deduction in cases where the
// explicit type exposes bugs in the compiler.
#define CAPNP_AUTO_IF_MSVC(...) auto
#else
#define CAPNP_AUTO_IF_MSVC(...) __VA_ARGS__
#endif
#if CAPNP_LITE
#define CAPNP_DECLARE_SCHEMA(id) \
extern ::capnp::word const* const bp_##id
#define CAPNP_DECLARE_ENUM(type, id) \
inline ::kj::String KJ_STRINGIFY(type##_##id value) { \
return ::kj::str(static_cast<uint16_t>(value)); \
} \
template <> struct EnumInfo<type##_##id> { \
struct IsEnum; \
static constexpr uint64_t typeId = 0x##id; \
static inline ::capnp::word const* encodedSchema() { return bp_##id; } \
}
#if _MSC_VER
// TODO(msvc): MSVC dosen't expect constexprs to have definitions.
#define CAPNP_DEFINE_ENUM(type, id)
#else
#define CAPNP_DEFINE_ENUM(type, id) \
constexpr uint64_t EnumInfo<type>::typeId
#endif
#define CAPNP_DECLARE_STRUCT_HEADER(id, dataWordSize_, pointerCount_) \
struct IsStruct; \
static constexpr uint64_t typeId = 0x##id; \
static constexpr uint16_t dataWordSize = dataWordSize_; \
static constexpr uint16_t pointerCount = pointerCount_; \
static inline ::capnp::word const* encodedSchema() { return ::capnp::schemas::bp_##id; }
#else // CAPNP_LITE
#define CAPNP_DECLARE_SCHEMA(id) \
extern ::capnp::word const* const bp_##id; \
extern const ::capnp::_::RawSchema s_##id
#define CAPNP_DECLARE_ENUM(type, id) \
inline ::kj::String KJ_STRINGIFY(type##_##id value) { \
return ::capnp::_::enumString(value); \
} \
template <> struct EnumInfo<type##_##id> { \
struct IsEnum; \
static constexpr uint64_t typeId = 0x##id; \
static inline ::capnp::word const* encodedSchema() { return bp_##id; } \
static constexpr ::capnp::_::RawSchema const* schema = &s_##id; \
}
#define CAPNP_DEFINE_ENUM(type, id) \
constexpr uint64_t EnumInfo<type>::typeId; \
constexpr ::capnp::_::RawSchema const* EnumInfo<type>::schema
#define CAPNP_DECLARE_STRUCT_HEADER(id, dataWordSize_, pointerCount_) \
struct IsStruct; \
static constexpr uint64_t typeId = 0x##id; \
static constexpr ::capnp::Kind kind = ::capnp::Kind::STRUCT; \
static constexpr uint16_t dataWordSize = dataWordSize_; \
static constexpr uint16_t pointerCount = pointerCount_; \
static inline ::capnp::word const* encodedSchema() { return ::capnp::schemas::bp_##id; } \
static constexpr ::capnp::_::RawSchema const* schema = &::capnp::schemas::s_##id;
#define CAPNP_DECLARE_INTERFACE_HEADER(id) \
struct IsInterface; \
static constexpr uint64_t typeId = 0x##id; \
static constexpr ::capnp::Kind kind = ::capnp::Kind::INTERFACE; \
static inline ::capnp::word const* encodedSchema() { return ::capnp::schemas::bp_##id; } \
static constexpr ::capnp::_::RawSchema const* schema = &::capnp::schemas::s_##id;
#endif // CAPNP_LITE, else
#endif // CAPNP_GENERATED_HEADER_SUPPORT_H_

View File

@ -1,58 +0,0 @@
# Copyright (c) 2015 Sandstorm Development Group, Inc. and contributors
# Licensed under the MIT License:
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
@0x8ef99297a43a5e34;
$import "/capnp/c++.capnp".namespace("capnp");
struct JsonValue {
union {
null @0 :Void;
boolean @1 :Bool;
number @2 :Float64;
string @3 :Text;
array @4 :List(JsonValue);
object @5 :List(Field);
# Standard JSON values.
call @6 :Call;
# Non-standard: A "function call", applying a named function (named by a single identifier)
# to a parameter list. Examples:
#
# BinData(0, "Zm9vCg==")
# ISODate("2015-04-15T08:44:50.218Z")
#
# Mongo DB users will recognize the above as exactly the syntax Mongo uses to represent BSON
# "binary" and "date" types in text, since JSON has no analog of these. This is basically the
# reason this extension exists. We do NOT recommend using `call` unless you specifically need
# to be compatible with some silly format that uses this syntax.
}
struct Field {
name @0 :Text;
value @1 :JsonValue;
}
struct Call {
function @0 :Text;
params @1 :List(JsonValue);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,546 +0,0 @@
// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#ifndef CAPNP_LIST_H_
#define CAPNP_LIST_H_
#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS)
#pragma GCC system_header
#endif
#include "layout.h"
#include "orphan.h"
#include <initializer_list>
#ifdef KJ_STD_COMPAT
#include <iterator>
#endif // KJ_STD_COMPAT
namespace capnp {
namespace _ { // private
template <typename T>
class TemporaryPointer {
// This class is a little hack which lets us define operator->() in cases where it needs to
// return a pointer to a temporary value. We instead construct a TemporaryPointer and return that
// (by value). The compiler then invokes operator->() on the TemporaryPointer, which itself is
// able to return a real pointer to its member.
public:
TemporaryPointer(T&& value): value(kj::mv(value)) {}
TemporaryPointer(const T& value): value(value) {}
inline T* operator->() { return &value; }
private:
T value;
};
template <typename Container, typename Element>
class IndexingIterator {
public:
IndexingIterator() = default;
inline Element operator*() const { return (*container)[index]; }
inline TemporaryPointer<Element> operator->() const {
return TemporaryPointer<Element>((*container)[index]);
}
inline Element operator[]( int off) const { return (*container)[index]; }
inline Element operator[](uint off) const { return (*container)[index]; }
inline IndexingIterator& operator++() { ++index; return *this; }
inline IndexingIterator operator++(int) { IndexingIterator other = *this; ++index; return other; }
inline IndexingIterator& operator--() { --index; return *this; }
inline IndexingIterator operator--(int) { IndexingIterator other = *this; --index; return other; }
inline IndexingIterator operator+(uint amount) const { return IndexingIterator(container, index + amount); }
inline IndexingIterator operator-(uint amount) const { return IndexingIterator(container, index - amount); }
inline IndexingIterator operator+( int amount) const { return IndexingIterator(container, index + amount); }
inline IndexingIterator operator-( int amount) const { return IndexingIterator(container, index - amount); }
inline int operator-(const IndexingIterator& other) const { return index - other.index; }
inline IndexingIterator& operator+=(uint amount) { index += amount; return *this; }
inline IndexingIterator& operator-=(uint amount) { index -= amount; return *this; }
inline IndexingIterator& operator+=( int amount) { index += amount; return *this; }
inline IndexingIterator& operator-=( int amount) { index -= amount; return *this; }
// STL says comparing iterators of different containers is not allowed, so we only compare
// indices here.
inline bool operator==(const IndexingIterator& other) const { return index == other.index; }
inline bool operator!=(const IndexingIterator& other) const { return index != other.index; }
inline bool operator<=(const IndexingIterator& other) const { return index <= other.index; }
inline bool operator>=(const IndexingIterator& other) const { return index >= other.index; }
inline bool operator< (const IndexingIterator& other) const { return index < other.index; }
inline bool operator> (const IndexingIterator& other) const { return index > other.index; }
private:
Container* container;
uint index;
friend Container;
inline IndexingIterator(Container* container, uint index)
: container(container), index(index) {}
};
} // namespace _ (private)
template <typename T>
struct List<T, Kind::PRIMITIVE> {
// List of primitives.
List() = delete;
class Reader {
public:
typedef List<T> Reads;
inline Reader(): reader(_::elementSizeForType<T>()) {}
inline explicit Reader(_::ListReader reader): reader(reader) {}
inline uint size() const { return unbound(reader.size() / ELEMENTS); }
inline T operator[](uint index) const {
KJ_IREQUIRE(index < size());
return reader.template getDataElement<T>(bounded(index) * ELEMENTS);
}
typedef _::IndexingIterator<const Reader, T> Iterator;
inline Iterator begin() const { return Iterator(this, 0); }
inline Iterator end() const { return Iterator(this, size()); }
private:
_::ListReader reader;
template <typename U, Kind K>
friend struct _::PointerHelpers;
template <typename U, Kind K>
friend struct List;
friend class Orphanage;
template <typename U, Kind K>
friend struct ToDynamic_;
};
class Builder {
public:
typedef List<T> Builds;
inline Builder(): builder(_::elementSizeForType<T>()) {}
inline Builder(decltype(nullptr)): Builder() {}
inline explicit Builder(_::ListBuilder builder): builder(builder) {}
inline operator Reader() const { return Reader(builder.asReader()); }
inline Reader asReader() const { return Reader(builder.asReader()); }
inline uint size() const { return unbound(builder.size() / ELEMENTS); }
inline T operator[](uint index) {
KJ_IREQUIRE(index < size());
return builder.template getDataElement<T>(bounded(index) * ELEMENTS);
}
inline void set(uint index, T value) {
// Alas, it is not possible to make operator[] return a reference to which you can assign,
// since the encoded representation does not necessarily match the compiler's representation
// of the type. We can't even return a clever class that implements operator T() and
// operator=() because it will lead to surprising behavior when using type inference (e.g.
// calling a template function with inferred argument types, or using "auto" or "decltype").
builder.template setDataElement<T>(bounded(index) * ELEMENTS, value);
}
typedef _::IndexingIterator<Builder, T> Iterator;
inline Iterator begin() { return Iterator(this, 0); }
inline Iterator end() { return Iterator(this, size()); }
private:
_::ListBuilder builder;
template <typename U, Kind K>
friend struct _::PointerHelpers;
friend class Orphanage;
template <typename U, Kind K>
friend struct ToDynamic_;
};
class Pipeline {};
private:
inline static _::ListBuilder initPointer(_::PointerBuilder builder, uint size) {
return builder.initList(_::elementSizeForType<T>(), bounded(size) * ELEMENTS);
}
inline static _::ListBuilder getFromPointer(_::PointerBuilder builder, const word* defaultValue) {
return builder.getList(_::elementSizeForType<T>(), defaultValue);
}
inline static _::ListReader getFromPointer(
const _::PointerReader& reader, const word* defaultValue) {
return reader.getList(_::elementSizeForType<T>(), defaultValue);
}
template <typename U, Kind k>
friend struct List;
template <typename U, Kind K>
friend struct _::PointerHelpers;
};
template <typename T>
struct List<T, Kind::ENUM>: public List<T, Kind::PRIMITIVE> {};
template <typename T>
struct List<T, Kind::STRUCT> {
// List of structs.
List() = delete;
class Reader {
public:
typedef List<T> Reads;
inline Reader(): reader(ElementSize::INLINE_COMPOSITE) {}
inline explicit Reader(_::ListReader reader): reader(reader) {}
inline uint size() const { return unbound(reader.size() / ELEMENTS); }
inline typename T::Reader operator[](uint index) const {
KJ_IREQUIRE(index < size());
return typename T::Reader(reader.getStructElement(bounded(index) * ELEMENTS));
}
typedef _::IndexingIterator<const Reader, typename T::Reader> Iterator;
inline Iterator begin() const { return Iterator(this, 0); }
inline Iterator end() const { return Iterator(this, size()); }
private:
_::ListReader reader;
template <typename U, Kind K>
friend struct _::PointerHelpers;
template <typename U, Kind K>
friend struct List;
friend class Orphanage;
template <typename U, Kind K>
friend struct ToDynamic_;
};
class Builder {
public:
typedef List<T> Builds;
inline Builder(): builder(ElementSize::INLINE_COMPOSITE) {}
inline Builder(decltype(nullptr)): Builder() {}
inline explicit Builder(_::ListBuilder builder): builder(builder) {}
inline operator Reader() const { return Reader(builder.asReader()); }
inline Reader asReader() const { return Reader(builder.asReader()); }
inline uint size() const { return unbound(builder.size() / ELEMENTS); }
inline typename T::Builder operator[](uint index) {
KJ_IREQUIRE(index < size());
return typename T::Builder(builder.getStructElement(bounded(index) * ELEMENTS));
}
inline void adoptWithCaveats(uint index, Orphan<T>&& orphan) {
// Mostly behaves like you'd expect `adopt` to behave, but with two caveats originating from
// the fact that structs in a struct list are allocated inline rather than by pointer:
// * This actually performs a shallow copy, effectively adopting each of the orphan's
// children rather than adopting the orphan itself. The orphan ends up being discarded,
// possibly wasting space in the message object.
// * If the orphan is larger than the target struct -- say, because the orphan was built
// using a newer version of the schema that has additional fields -- it will be truncated,
// losing data.
KJ_IREQUIRE(index < size());
// We pass a zero-valued StructSize to asStruct() because we do not want the struct to be
// expanded under any circumstances. We're just going to throw it away anyway, and
// transferContentFrom() already carefully compares the struct sizes before transferring.
builder.getStructElement(bounded(index) * ELEMENTS).transferContentFrom(
orphan.builder.asStruct(_::StructSize(ZERO * WORDS, ZERO * POINTERS)));
}
inline void setWithCaveats(uint index, const typename T::Reader& reader) {
// Mostly behaves like you'd expect `set` to behave, but with a caveat originating from
// the fact that structs in a struct list are allocated inline rather than by pointer:
// If the source struct is larger than the target struct -- say, because the source was built
// using a newer version of the schema that has additional fields -- it will be truncated,
// losing data.
//
// Note: If you are trying to concatenate some lists, use Orphanage::newOrphanConcat() to
// do it without losing any data in case the source lists come from a newer version of the
// protocol. (Plus, it's easier to use anyhow.)
KJ_IREQUIRE(index < size());
builder.getStructElement(bounded(index) * ELEMENTS).copyContentFrom(reader._reader);
}
// There are no init(), set(), adopt(), or disown() methods for lists of structs because the
// elements of the list are inlined and are initialized when the list is initialized. This
// means that init() would be redundant, and set() would risk data loss if the input struct
// were from a newer version of the protocol.
typedef _::IndexingIterator<Builder, typename T::Builder> Iterator;
inline Iterator begin() { return Iterator(this, 0); }
inline Iterator end() { return Iterator(this, size()); }
private:
_::ListBuilder builder;
template <typename U, Kind K>
friend struct _::PointerHelpers;
friend class Orphanage;
template <typename U, Kind K>
friend struct ToDynamic_;
};
class Pipeline {};
private:
inline static _::ListBuilder initPointer(_::PointerBuilder builder, uint size) {
return builder.initStructList(bounded(size) * ELEMENTS, _::structSize<T>());
}
inline static _::ListBuilder getFromPointer(_::PointerBuilder builder, const word* defaultValue) {
return builder.getStructList(_::structSize<T>(), defaultValue);
}
inline static _::ListReader getFromPointer(
const _::PointerReader& reader, const word* defaultValue) {
return reader.getList(ElementSize::INLINE_COMPOSITE, defaultValue);
}
template <typename U, Kind k>
friend struct List;
template <typename U, Kind K>
friend struct _::PointerHelpers;
};
template <typename T>
struct List<List<T>, Kind::LIST> {
// List of lists.
List() = delete;
class Reader {
public:
typedef List<List<T>> Reads;
inline Reader(): reader(ElementSize::POINTER) {}
inline explicit Reader(_::ListReader reader): reader(reader) {}
inline uint size() const { return unbound(reader.size() / ELEMENTS); }
inline typename List<T>::Reader operator[](uint index) const {
KJ_IREQUIRE(index < size());
return typename List<T>::Reader(_::PointerHelpers<List<T>>::get(
reader.getPointerElement(bounded(index) * ELEMENTS)));
}
typedef _::IndexingIterator<const Reader, typename List<T>::Reader> Iterator;
inline Iterator begin() const { return Iterator(this, 0); }
inline Iterator end() const { return Iterator(this, size()); }
private:
_::ListReader reader;
template <typename U, Kind K>
friend struct _::PointerHelpers;
template <typename U, Kind K>
friend struct List;
friend class Orphanage;
template <typename U, Kind K>
friend struct ToDynamic_;
};
class Builder {
public:
typedef List<List<T>> Builds;
inline Builder(): builder(ElementSize::POINTER) {}
inline Builder(decltype(nullptr)): Builder() {}
inline explicit Builder(_::ListBuilder builder): builder(builder) {}
inline operator Reader() const { return Reader(builder.asReader()); }
inline Reader asReader() const { return Reader(builder.asReader()); }
inline uint size() const { return unbound(builder.size() / ELEMENTS); }
inline typename List<T>::Builder operator[](uint index) {
KJ_IREQUIRE(index < size());
return typename List<T>::Builder(_::PointerHelpers<List<T>>::get(
builder.getPointerElement(bounded(index) * ELEMENTS)));
}
inline typename List<T>::Builder init(uint index, uint size) {
KJ_IREQUIRE(index < this->size());
return typename List<T>::Builder(_::PointerHelpers<List<T>>::init(
builder.getPointerElement(bounded(index) * ELEMENTS), size));
}
inline void set(uint index, typename List<T>::Reader value) {
KJ_IREQUIRE(index < size());
builder.getPointerElement(bounded(index) * ELEMENTS).setList(value.reader);
}
void set(uint index, std::initializer_list<ReaderFor<T>> value) {
KJ_IREQUIRE(index < size());
auto l = init(index, value.size());
uint i = 0;
for (auto& element: value) {
l.set(i++, element);
}
}
inline void adopt(uint index, Orphan<T>&& value) {
KJ_IREQUIRE(index < size());
builder.getPointerElement(bounded(index) * ELEMENTS).adopt(kj::mv(value.builder));
}
inline Orphan<T> disown(uint index) {
KJ_IREQUIRE(index < size());
return Orphan<T>(builder.getPointerElement(bounded(index) * ELEMENTS).disown());
}
typedef _::IndexingIterator<Builder, typename List<T>::Builder> Iterator;
inline Iterator begin() { return Iterator(this, 0); }
inline Iterator end() { return Iterator(this, size()); }
private:
_::ListBuilder builder;
template <typename U, Kind K>
friend struct _::PointerHelpers;
friend class Orphanage;
template <typename U, Kind K>
friend struct ToDynamic_;
};
class Pipeline {};
private:
inline static _::ListBuilder initPointer(_::PointerBuilder builder, uint size) {
return builder.initList(ElementSize::POINTER, bounded(size) * ELEMENTS);
}
inline static _::ListBuilder getFromPointer(_::PointerBuilder builder, const word* defaultValue) {
return builder.getList(ElementSize::POINTER, defaultValue);
}
inline static _::ListReader getFromPointer(
const _::PointerReader& reader, const word* defaultValue) {
return reader.getList(ElementSize::POINTER, defaultValue);
}
template <typename U, Kind k>
friend struct List;
template <typename U, Kind K>
friend struct _::PointerHelpers;
};
template <typename T>
struct List<T, Kind::BLOB> {
List() = delete;
class Reader {
public:
typedef List<T> Reads;
inline Reader(): reader(ElementSize::POINTER) {}
inline explicit Reader(_::ListReader reader): reader(reader) {}
inline uint size() const { return unbound(reader.size() / ELEMENTS); }
inline typename T::Reader operator[](uint index) const {
KJ_IREQUIRE(index < size());
return reader.getPointerElement(bounded(index) * ELEMENTS)
.template getBlob<T>(nullptr, ZERO * BYTES);
}
typedef _::IndexingIterator<const Reader, typename T::Reader> Iterator;
inline Iterator begin() const { return Iterator(this, 0); }
inline Iterator end() const { return Iterator(this, size()); }
private:
_::ListReader reader;
template <typename U, Kind K>
friend struct _::PointerHelpers;
template <typename U, Kind K>
friend struct List;
friend class Orphanage;
template <typename U, Kind K>
friend struct ToDynamic_;
};
class Builder {
public:
typedef List<T> Builds;
inline Builder(): builder(ElementSize::POINTER) {}
inline Builder(decltype(nullptr)): Builder() {}
inline explicit Builder(_::ListBuilder builder): builder(builder) {}
inline operator Reader() const { return Reader(builder.asReader()); }
inline Reader asReader() const { return Reader(builder.asReader()); }
inline uint size() const { return unbound(builder.size() / ELEMENTS); }
inline typename T::Builder operator[](uint index) {
KJ_IREQUIRE(index < size());
return builder.getPointerElement(bounded(index) * ELEMENTS)
.template getBlob<T>(nullptr, ZERO * BYTES);
}
inline void set(uint index, typename T::Reader value) {
KJ_IREQUIRE(index < size());
builder.getPointerElement(bounded(index) * ELEMENTS).template setBlob<T>(value);
}
inline typename T::Builder init(uint index, uint size) {
KJ_IREQUIRE(index < this->size());
return builder.getPointerElement(bounded(index) * ELEMENTS)
.template initBlob<T>(bounded(size) * BYTES);
}
inline void adopt(uint index, Orphan<T>&& value) {
KJ_IREQUIRE(index < size());
builder.getPointerElement(bounded(index) * ELEMENTS).adopt(kj::mv(value.builder));
}
inline Orphan<T> disown(uint index) {
KJ_IREQUIRE(index < size());
return Orphan<T>(builder.getPointerElement(bounded(index) * ELEMENTS).disown());
}
typedef _::IndexingIterator<Builder, typename T::Builder> Iterator;
inline Iterator begin() { return Iterator(this, 0); }
inline Iterator end() { return Iterator(this, size()); }
private:
_::ListBuilder builder;
template <typename U, Kind K>
friend struct _::PointerHelpers;
friend class Orphanage;
template <typename U, Kind K>
friend struct ToDynamic_;
};
class Pipeline {};
private:
inline static _::ListBuilder initPointer(_::PointerBuilder builder, uint size) {
return builder.initList(ElementSize::POINTER, bounded(size) * ELEMENTS);
}
inline static _::ListBuilder getFromPointer(_::PointerBuilder builder, const word* defaultValue) {
return builder.getList(ElementSize::POINTER, defaultValue);
}
inline static _::ListReader getFromPointer(
const _::PointerReader& reader, const word* defaultValue) {
return reader.getList(ElementSize::POINTER, defaultValue);
}
template <typename U, Kind k>
friend struct List;
template <typename U, Kind K>
friend struct _::PointerHelpers;
};
} // namespace capnp
#ifdef KJ_STD_COMPAT
namespace std {
template <typename Container, typename Element>
struct iterator_traits<capnp::_::IndexingIterator<Container, Element>>
: public std::iterator<std::random_access_iterator_tag, Element, int> {};
} // namespace std
#endif // KJ_STD_COMPAT
#endif // CAPNP_LIST_H_

View File

@ -1,202 +0,0 @@
// Copyright (c) 2015 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#ifndef CAPNP_MEMBRANE_H_
#define CAPNP_MEMBRANE_H_
// In capability theory, a "membrane" is a wrapper around a capability which (usually) forwards
// calls but recursively wraps capabilities in those calls in the same membrane. The purpose of a
// membrane is to enforce a barrier between two capabilities that cannot be bypassed by merely
// introducing new objects.
//
// The most common use case for a membrane is revocation: Say Alice wants to give Bob a capability
// to access Carol, but wants to be able to revoke this capability later. Alice can accomplish this
// by wrapping Carol in a revokable wrapper which passes through calls until such a time as Alice
// indicates it should be revoked, after which all calls through the wrapper will throw exceptions.
// However, a naive wrapper approach has a problem: if Bob makes a call to Carol and sends a new
// capability in that call, or if Carol returns a capability to Bob in the response to a call, then
// the two are now able to communicate using this new capability, which Alice cannot revoke. In
// order to avoid this problem, Alice must use not just a wrapper but a "membrane", which
// recursively wraps all objects that pass through it in either direction. Thus, all connections
// formed between Bob and Carol (originating from Alice's original introduction) can be revoked
// together by revoking the membrane.
//
// Note that when a capability is passed into a membrane and then passed back out, the result is
// the original capability, not a double-membraned capability. This means that in our revocation
// example, if Bob uses his capability to Carol to obtain another capability from her, then send
// it back to her, the capability Carol receives back will NOT be revoked when Bob's access to
// Carol is revoked. Thus Bob can create long-term irrevocable connections. In most practical use
// cases, this is what you want. APIs commonly rely on the fact that a capability obtained and then
// passed back can be recognized as the original capability.
//
// Mark Miller on membranes: http://www.eros-os.org/pipermail/e-lang/2003-January/008434.html
#include "capability.h"
namespace capnp {
class MembranePolicy {
// Applications may implement this interface to define a membrane policy, which allows some
// calls crossing the membrane to be blocked or redirected.
public:
virtual kj::Maybe<Capability::Client> inboundCall(
uint64_t interfaceId, uint16_t methodId, Capability::Client target) = 0;
// Given an inbound call (a call originating "outside" the membrane destined for an object
// "inside" the membrane), decides what to do with it. The policy may:
//
// - Return null to indicate that the call should proceed to the destination. All capabilities
// in the parameters or result will be properly wrapped in the same membrane.
// - Return a capability to have the call redirected to that capability. Note that the redirect
// capability will be treated as outside the membrane, so the params and results will not be
// auto-wrapped; however, the callee can easily wrap the returned capability in the membrane
// itself before returning to achieve this effect.
// - Throw an exception to cause the call to fail with that exception.
//
// `target` is the underlying capability (*inside* the membrane) for which the call is destined.
// Generally, the only way you should use `target` is to wrap it in some capability which you
// return as a redirect. The redirect capability may modify the call in some way and send it to
// `target`. Be careful to use `copyIntoMembrane()` and `copyOutOfMembrane()` as appropriate when
// copying parameters or results across the membrane.
//
// Note that since `target` is inside the capability, if you were to directly return it (rather
// than return null), the effect would be that the membrane would be broken: the call would
// proceed directly and any new capabilities introduced through it would not be membraned. You
// generally should not do that.
virtual kj::Maybe<Capability::Client> outboundCall(
uint64_t interfaceId, uint16_t methodId, Capability::Client target) = 0;
// Like `inboundCall()`, but applies to calls originating *inside* the membrane and terminating
// outside.
//
// Note: It is strongly recommended that `outboundCall()` returns null in exactly the same cases
// that `inboundCall()` return null. Conversely, for any case where `inboundCall()` would
// redirect or throw, `outboundCall()` should also redirect or throw. Otherwise, you can run
// into inconsistent behavion when a promise is returned across a membrane, and that promise
// later resolves to a capability on the other side of the membrane: calls on the promise
// will enter and then exit the membrane, but calls on the eventual resolution will not cross
// the membrane at all, so it is important that these two cases behave the same.
virtual kj::Own<MembranePolicy> addRef() = 0;
// Return a new owned pointer to the same policy.
//
// Typically an implementation of MembranePolicy should also inherit kj::Refcounted and implement
// `addRef()` as `return kj::addRef(*this);`.
//
// Note that the membraning system considers two membranes created with the same MembranePolicy
// object actually to be the *same* membrane. This is relevant when an object passes into the
// membrane and then back out (or out and then back in): instead of double-wrapping the object,
// the wrapping will be removed.
};
Capability::Client membrane(Capability::Client inner, kj::Own<MembranePolicy> policy);
// Wrap `inner` in a membrane specified by `policy`. `inner` is considered "inside" the membrane,
// while the returned capability should only be called from outside the membrane.
Capability::Client reverseMembrane(Capability::Client outer, kj::Own<MembranePolicy> policy);
// Like `membrane` but treat the input capability as "outside" the membrane, and return a
// capability appropriate for use inside.
//
// Applications typically won't use this directly; the membraning code automatically sets up
// reverse membranes where needed.
template <typename ClientType>
ClientType membrane(ClientType inner, kj::Own<MembranePolicy> policy);
template <typename ClientType>
ClientType reverseMembrane(ClientType inner, kj::Own<MembranePolicy> policy);
// Convenience templates which return the same interface type as the input.
template <typename ServerType>
typename ServerType::Serves::Client membrane(
kj::Own<ServerType> inner, kj::Own<MembranePolicy> policy);
template <typename ServerType>
typename ServerType::Serves::Client reverseMembrane(
kj::Own<ServerType> inner, kj::Own<MembranePolicy> policy);
// Convenience templates which input a capability server type and return the appropriate client
// type.
template <typename Reader>
Orphan<typename kj::Decay<Reader>::Reads> copyIntoMembrane(
Reader&& from, Orphanage to, kj::Own<MembranePolicy> policy);
// Copy a Cap'n Proto object (e.g. struct or list), adding the given membrane to any capabilities
// found within it. `from` is interpreted as "outside" the membrane while `to` is "inside".
template <typename Reader>
Orphan<typename kj::Decay<Reader>::Reads> copyOutOfMembrane(
Reader&& from, Orphanage to, kj::Own<MembranePolicy> policy);
// Like copyIntoMembrane() except that `from` is "inside" the membrane and `to` is "outside".
// =======================================================================================
// inline implementation details
template <typename ClientType>
ClientType membrane(ClientType inner, kj::Own<MembranePolicy> policy) {
return membrane(Capability::Client(kj::mv(inner)), kj::mv(policy))
.castAs<typename ClientType::Calls>();
}
template <typename ClientType>
ClientType reverseMembrane(ClientType inner, kj::Own<MembranePolicy> policy) {
return reverseMembrane(Capability::Client(kj::mv(inner)), kj::mv(policy))
.castAs<typename ClientType::Calls>();
}
template <typename ServerType>
typename ServerType::Serves::Client membrane(
kj::Own<ServerType> inner, kj::Own<MembranePolicy> policy) {
return membrane(Capability::Client(kj::mv(inner)), kj::mv(policy))
.castAs<typename ServerType::Serves>();
}
template <typename ServerType>
typename ServerType::Serves::Client reverseMembrane(
kj::Own<ServerType> inner, kj::Own<MembranePolicy> policy) {
return reverseMembrane(Capability::Client(kj::mv(inner)), kj::mv(policy))
.castAs<typename ServerType::Serves>();
}
namespace _ { // private
OrphanBuilder copyOutOfMembrane(PointerReader from, Orphanage to,
kj::Own<MembranePolicy> policy, bool reverse);
OrphanBuilder copyOutOfMembrane(StructReader from, Orphanage to,
kj::Own<MembranePolicy> policy, bool reverse);
OrphanBuilder copyOutOfMembrane(ListReader from, Orphanage to,
kj::Own<MembranePolicy> policy, bool reverse);
} // namespace _ (private)
template <typename Reader>
Orphan<typename kj::Decay<Reader>::Reads> copyIntoMembrane(
Reader&& from, Orphanage to, kj::Own<MembranePolicy> policy) {
return _::copyOutOfMembrane(
_::PointerHelpers<typename kj::Decay<Reader>::Reads>::getInternalReader(from),
to, kj::mv(policy), true);
}
template <typename Reader>
Orphan<typename kj::Decay<Reader>::Reads> copyOutOfMembrane(
Reader&& from, Orphanage to, kj::Own<MembranePolicy> policy) {
return _::copyOutOfMembrane(
_::PointerHelpers<typename kj::Decay<Reader>::Reads>::getInternalReader(from),
to, kj::mv(policy), false);
}
} // namespace capnp
#endif // CAPNP_MEMBRANE_H_

View File

@ -1,508 +0,0 @@
// Copyright (c) 2013-2016 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include <kj/common.h>
#include <kj/memory.h>
#include <kj/mutex.h>
#include <kj/debug.h>
#include "common.h"
#include "layout.h"
#include "any.h"
#ifndef CAPNP_MESSAGE_H_
#define CAPNP_MESSAGE_H_
#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS)
#pragma GCC system_header
#endif
namespace capnp {
namespace _ { // private
class ReaderArena;
class BuilderArena;
}
class StructSchema;
class Orphanage;
template <typename T>
class Orphan;
// =======================================================================================
struct ReaderOptions {
// Options controlling how data is read.
uint64_t traversalLimitInWords = 8 * 1024 * 1024;
// Limits how many total words of data are allowed to be traversed. Traversal is counted when
// a new struct or list builder is obtained, e.g. from a get() accessor. This means that calling
// the getter for the same sub-struct multiple times will cause it to be double-counted. Once
// the traversal limit is reached, an error will be reported.
//
// This limit exists for security reasons. It is possible for an attacker to construct a message
// in which multiple pointers point at the same location. This is technically invalid, but hard
// to detect. Using such a message, an attacker could cause a message which is small on the wire
// to appear much larger when actually traversed, possibly exhausting server resources leading to
// denial-of-service.
//
// It makes sense to set a traversal limit that is much larger than the underlying message.
// Together with sensible coding practices (e.g. trying to avoid calling sub-object getters
// multiple times, which is expensive anyway), this should provide adequate protection without
// inconvenience.
//
// The default limit is 64 MiB. This may or may not be a sensible number for any given use case,
// but probably at least prevents easy exploitation while also avoiding causing problems in most
// typical cases.
int nestingLimit = 64;
// Limits how deeply-nested a message structure can be, e.g. structs containing other structs or
// lists of structs.
//
// Like the traversal limit, this limit exists for security reasons. Since it is common to use
// recursive code to traverse recursive data structures, an attacker could easily cause a stack
// overflow by sending a very-deeply-nested (or even cyclic) message, without the message even
// being very large. The default limit of 64 is probably low enough to prevent any chance of
// stack overflow, yet high enough that it is never a problem in practice.
};
class MessageReader {
// Abstract interface for an object used to read a Cap'n Proto message. Subclasses of
// MessageReader are responsible for reading the raw, flat message content. Callers should
// usually call `messageReader.getRoot<MyStructType>()` to get a `MyStructType::Reader`
// representing the root of the message, then use that to traverse the message content.
//
// Some common subclasses of `MessageReader` include `SegmentArrayMessageReader`, whose
// constructor accepts pointers to the raw data, and `StreamFdMessageReader` (from
// `serialize.h`), which reads the message from a file descriptor. One might implement other
// subclasses to handle things like reading from shared memory segments, mmap()ed files, etc.
public:
MessageReader(ReaderOptions options);
// It is suggested that subclasses take ReaderOptions as a constructor parameter, but give it a
// default value of "ReaderOptions()". The base class constructor doesn't have a default value
// in order to remind subclasses that they really need to give the user a way to provide this.
virtual ~MessageReader() noexcept(false);
virtual kj::ArrayPtr<const word> getSegment(uint id) = 0;
// Gets the segment with the given ID, or returns null if no such segment exists. This method
// will be called at most once for each segment ID.
inline const ReaderOptions& getOptions();
// Get the options passed to the constructor.
template <typename RootType>
typename RootType::Reader getRoot();
// Get the root struct of the message, interpreting it as the given struct type.
template <typename RootType, typename SchemaType>
typename RootType::Reader getRoot(SchemaType schema);
// Dynamically interpret the root struct of the message using the given schema (a StructSchema).
// RootType in this case must be DynamicStruct, and you must #include <capnp/dynamic.h> to
// use this.
bool isCanonical();
// Returns whether the message encoded in the reader is in canonical form.
private:
ReaderOptions options;
// Space in which we can construct a ReaderArena. We don't use ReaderArena directly here
// because we don't want clients to have to #include arena.h, which itself includes a bunch of
// big STL headers. We don't use a pointer to a ReaderArena because that would require an
// extra malloc on every message which could be expensive when processing small messages.
void* arenaSpace[15 + sizeof(kj::MutexGuarded<void*>) / sizeof(void*)];
bool allocatedArena;
_::ReaderArena* arena() { return reinterpret_cast<_::ReaderArena*>(arenaSpace); }
AnyPointer::Reader getRootInternal();
};
class MessageBuilder {
// Abstract interface for an object used to allocate and build a message. Subclasses of
// MessageBuilder are responsible for allocating the space in which the message will be written.
// The most common subclass is `MallocMessageBuilder`, but other subclasses may be used to do
// tricky things like allocate messages in shared memory or mmap()ed files.
//
// Creating a new message ususually means allocating a new MessageBuilder (ideally on the stack)
// and then calling `messageBuilder.initRoot<MyStructType>()` to get a `MyStructType::Builder`.
// That, in turn, can be used to fill in the message content. When done, you can call
// `messageBuilder.getSegmentsForOutput()` to get a list of flat data arrays containing the
// message.
public:
MessageBuilder();
virtual ~MessageBuilder() noexcept(false);
KJ_DISALLOW_COPY(MessageBuilder);
struct SegmentInit {
kj::ArrayPtr<word> space;
size_t wordsUsed;
// Number of words in `space` which are used; the rest are free space in which additional
// objects may be allocated.
};
explicit MessageBuilder(kj::ArrayPtr<SegmentInit> segments);
// Create a MessageBuilder backed by existing memory. This is an advanced interface that most
// people should not use. THIS METHOD IS INSECURE; see below.
//
// This allows a MessageBuilder to be constructed to modify an in-memory message without first
// making a copy of the content. This is especially useful in conjunction with mmap().
//
// The contents of each segment must outlive the MessageBuilder, but the SegmentInit array itself
// only need outlive the constructor.
//
// SECURITY: Do not use this in conjunction with untrusted data. This constructor assumes that
// the input message is valid. This constructor is designed to be used with data you control,
// e.g. an mmap'd file which is owned and accessed by only one program. When reading data you
// do not trust, you *must* load it into a Reader and then copy into a Builder as a means of
// validating the content.
//
// WARNING: It is NOT safe to initialize a MessageBuilder in this way from memory that is
// currently in use by another MessageBuilder or MessageReader. Other readers/builders will
// not observe changes to the segment sizes nor newly-allocated segments caused by allocating
// new objects in this message.
virtual kj::ArrayPtr<word> allocateSegment(uint minimumSize) = 0;
// Allocates an array of at least the given number of words, throwing an exception or crashing if
// this is not possible. It is expected that this method will usually return more space than
// requested, and the caller should use that extra space as much as possible before allocating
// more. The returned space remains valid at least until the MessageBuilder is destroyed.
//
// Cap'n Proto will only call this once at a time, so the subclass need not worry about
// thread-safety.
template <typename RootType>
typename RootType::Builder initRoot();
// Initialize the root struct of the message as the given struct type.
template <typename Reader>
void setRoot(Reader&& value);
// Set the root struct to a deep copy of the given struct.
template <typename RootType>
typename RootType::Builder getRoot();
// Get the root struct of the message, interpreting it as the given struct type.
template <typename RootType, typename SchemaType>
typename RootType::Builder getRoot(SchemaType schema);
// Dynamically interpret the root struct of the message using the given schema (a StructSchema).
// RootType in this case must be DynamicStruct, and you must #include <capnp/dynamic.h> to
// use this.
template <typename RootType, typename SchemaType>
typename RootType::Builder initRoot(SchemaType schema);
// Dynamically init the root struct of the message using the given schema (a StructSchema).
// RootType in this case must be DynamicStruct, and you must #include <capnp/dynamic.h> to
// use this.
template <typename T>
void adoptRoot(Orphan<T>&& orphan);
// Like setRoot() but adopts the orphan without copying.
kj::ArrayPtr<const kj::ArrayPtr<const word>> getSegmentsForOutput();
// Get the raw data that makes up the message.
Orphanage getOrphanage();
bool isCanonical();
// Check whether the message builder is in canonical form
private:
void* arenaSpace[22];
// Space in which we can construct a BuilderArena. We don't use BuilderArena directly here
// because we don't want clients to have to #include arena.h, which itself includes a bunch of
// big STL headers. We don't use a pointer to a BuilderArena because that would require an
// extra malloc on every message which could be expensive when processing small messages.
bool allocatedArena = false;
// We have to initialize the arena lazily because when we do so we want to allocate the root
// pointer immediately, and this will allocate a segment, which requires a virtual function
// call on the MessageBuilder. We can't do such a call in the constructor since the subclass
// isn't constructed yet. This is kind of annoying because it means that getOrphanage() is
// not thread-safe, but that shouldn't be a huge deal...
_::BuilderArena* arena() { return reinterpret_cast<_::BuilderArena*>(arenaSpace); }
_::SegmentBuilder* getRootSegment();
AnyPointer::Builder getRootInternal();
};
template <typename RootType>
typename RootType::Reader readMessageUnchecked(const word* data);
// IF THE INPUT IS INVALID, THIS MAY CRASH, CORRUPT MEMORY, CREATE A SECURITY HOLE IN YOUR APP,
// MURDER YOUR FIRST-BORN CHILD, AND/OR BRING ABOUT ETERNAL DAMNATION ON ALL OF HUMANITY. DO NOT
// USE UNLESS YOU UNDERSTAND THE CONSEQUENCES.
//
// Given a pointer to a known-valid message located in a single contiguous memory segment,
// returns a reader for that message. No bounds-checking will be done while traversing this
// message. Use this only if you have already verified that all pointers are valid and in-bounds,
// and there are no far pointers in the message.
//
// To create a message that can be passed to this function, build a message using a MallocAllocator
// whose preferred segment size is larger than the message size. This guarantees that the message
// will be allocated as a single segment, meaning getSegmentsForOutput() returns a single word
// array. That word array is your message; you may pass a pointer to its first word into
// readMessageUnchecked() to read the message.
//
// This can be particularly handy for embedding messages in generated code: you can
// embed the raw bytes (using AlignedData) then make a Reader for it using this. This is the way
// default values are embedded in code generated by the Cap'n Proto compiler. E.g., if you have
// a message MyMessage, you can read its default value like so:
// MyMessage::Reader reader = Message<MyMessage>::readMessageUnchecked(MyMessage::DEFAULT.words);
//
// To sanitize a message from an untrusted source such that it can be safely passed to
// readMessageUnchecked(), use copyToUnchecked().
template <typename Reader>
void copyToUnchecked(Reader&& reader, kj::ArrayPtr<word> uncheckedBuffer);
// Copy the content of the given reader into the given buffer, such that it can safely be passed to
// readMessageUnchecked(). The buffer's size must be exactly reader.totalSizeInWords() + 1,
// otherwise an exception will be thrown. The buffer must be zero'd before calling.
template <typename RootType>
typename RootType::Reader readDataStruct(kj::ArrayPtr<const word> data);
// Interprets the given data as a single, data-only struct. Only primitive fields (booleans,
// numbers, and enums) will be readable; all pointers will be null. This is useful if you want
// to use Cap'n Proto as a language/platform-neutral way to pack some bits.
//
// The input is a word array rather than a byte array to enforce alignment. If you have a byte
// array which you know is word-aligned (or if your platform supports unaligned reads and you don't
// mind the performance penalty), then you can use `reinterpret_cast` to convert a byte array into
// a word array:
//
// kj::arrayPtr(reinterpret_cast<const word*>(bytes.begin()),
// reinterpret_cast<const word*>(bytes.end()))
template <typename BuilderType>
typename kj::ArrayPtr<const word> writeDataStruct(BuilderType builder);
// Given a struct builder, get the underlying data section as a word array, suitable for passing
// to `readDataStruct()`.
//
// Note that you may call `.toBytes()` on the returned value to convert to `ArrayPtr<const byte>`.
template <typename Type>
static typename Type::Reader defaultValue();
// Get a default instance of the given struct or list type.
//
// TODO(cleanup): Find a better home for this function?
// =======================================================================================
class SegmentArrayMessageReader: public MessageReader {
// A simple MessageReader that reads from an array of word arrays representing all segments.
// In particular you can read directly from the output of MessageBuilder::getSegmentsForOutput()
// (although it would probably make more sense to call builder.getRoot().asReader() in that case).
public:
SegmentArrayMessageReader(kj::ArrayPtr<const kj::ArrayPtr<const word>> segments,
ReaderOptions options = ReaderOptions());
// Creates a message pointing at the given segment array, without taking ownership of the
// segments. All arrays passed in must remain valid until the MessageReader is destroyed.
KJ_DISALLOW_COPY(SegmentArrayMessageReader);
~SegmentArrayMessageReader() noexcept(false);
virtual kj::ArrayPtr<const word> getSegment(uint id) override;
private:
kj::ArrayPtr<const kj::ArrayPtr<const word>> segments;
};
enum class AllocationStrategy: uint8_t {
FIXED_SIZE,
// The builder will prefer to allocate the same amount of space for each segment with no
// heuristic growth. It will still allocate larger segments when the preferred size is too small
// for some single object. This mode is generally not recommended, but can be particularly useful
// for testing in order to force a message to allocate a predictable number of segments. Note
// that you can force every single object in the message to be located in a separate segment by
// using this mode with firstSegmentWords = 0.
GROW_HEURISTICALLY
// The builder will heuristically decide how much space to allocate for each segment. Each
// allocated segment will be progressively larger than the previous segments on the assumption
// that message sizes are exponentially distributed. The total number of segments that will be
// allocated for a message of size n is O(log n).
};
constexpr uint SUGGESTED_FIRST_SEGMENT_WORDS = 1024;
constexpr AllocationStrategy SUGGESTED_ALLOCATION_STRATEGY = AllocationStrategy::GROW_HEURISTICALLY;
class MallocMessageBuilder: public MessageBuilder {
// A simple MessageBuilder that uses malloc() (actually, calloc()) to allocate segments. This
// implementation should be reasonable for any case that doesn't require writing the message to
// a specific location in memory.
public:
explicit MallocMessageBuilder(uint firstSegmentWords = SUGGESTED_FIRST_SEGMENT_WORDS,
AllocationStrategy allocationStrategy = SUGGESTED_ALLOCATION_STRATEGY);
// Creates a BuilderContext which allocates at least the given number of words for the first
// segment, and then uses the given strategy to decide how much to allocate for subsequent
// segments. When choosing a value for firstSegmentWords, consider that:
// 1) Reading and writing messages gets slower when multiple segments are involved, so it's good
// if most messages fit in a single segment.
// 2) Unused bytes will not be written to the wire, so generally it is not a big deal to allocate
// more space than you need. It only becomes problematic if you are allocating many messages
// in parallel and thus use lots of memory, or if you allocate so much extra space that just
// zeroing it out becomes a bottleneck.
// The defaults have been chosen to be reasonable for most people, so don't change them unless you
// have reason to believe you need to.
explicit MallocMessageBuilder(kj::ArrayPtr<word> firstSegment,
AllocationStrategy allocationStrategy = SUGGESTED_ALLOCATION_STRATEGY);
// This version always returns the given array for the first segment, and then proceeds with the
// allocation strategy. This is useful for optimization when building lots of small messages in
// a tight loop: you can reuse the space for the first segment.
//
// firstSegment MUST be zero-initialized. MallocMessageBuilder's destructor will write new zeros
// over any space that was used so that it can be reused.
KJ_DISALLOW_COPY(MallocMessageBuilder);
virtual ~MallocMessageBuilder() noexcept(false);
virtual kj::ArrayPtr<word> allocateSegment(uint minimumSize) override;
private:
uint nextSize;
AllocationStrategy allocationStrategy;
bool ownFirstSegment;
bool returnedFirstSegment;
void* firstSegment;
struct MoreSegments;
kj::Maybe<kj::Own<MoreSegments>> moreSegments;
};
class FlatMessageBuilder: public MessageBuilder {
// THIS IS NOT THE CLASS YOU'RE LOOKING FOR.
//
// If you want to write a message into already-existing scratch space, use `MallocMessageBuilder`
// and pass the scratch space to its constructor. It will then only fall back to malloc() if
// the scratch space is not large enough.
//
// Do NOT use this class unless you really know what you're doing. This class is problematic
// because it requires advance knowledge of the size of your message, which is usually impossible
// to determine without actually building the message. The class was created primarily to
// implement `copyToUnchecked()`, which itself exists only to support other internal parts of
// the Cap'n Proto implementation.
public:
explicit FlatMessageBuilder(kj::ArrayPtr<word> array);
KJ_DISALLOW_COPY(FlatMessageBuilder);
virtual ~FlatMessageBuilder() noexcept(false);
void requireFilled();
// Throws an exception if the flat array is not exactly full.
virtual kj::ArrayPtr<word> allocateSegment(uint minimumSize) override;
private:
kj::ArrayPtr<word> array;
bool allocated;
};
// =======================================================================================
// implementation details
inline const ReaderOptions& MessageReader::getOptions() {
return options;
}
template <typename RootType>
inline typename RootType::Reader MessageReader::getRoot() {
return getRootInternal().getAs<RootType>();
}
template <typename RootType>
inline typename RootType::Builder MessageBuilder::initRoot() {
return getRootInternal().initAs<RootType>();
}
template <typename Reader>
inline void MessageBuilder::setRoot(Reader&& value) {
getRootInternal().setAs<FromReader<Reader>>(value);
}
template <typename RootType>
inline typename RootType::Builder MessageBuilder::getRoot() {
return getRootInternal().getAs<RootType>();
}
template <typename T>
void MessageBuilder::adoptRoot(Orphan<T>&& orphan) {
return getRootInternal().adopt(kj::mv(orphan));
}
template <typename RootType, typename SchemaType>
typename RootType::Reader MessageReader::getRoot(SchemaType schema) {
return getRootInternal().getAs<RootType>(schema);
}
template <typename RootType, typename SchemaType>
typename RootType::Builder MessageBuilder::getRoot(SchemaType schema) {
return getRootInternal().getAs<RootType>(schema);
}
template <typename RootType, typename SchemaType>
typename RootType::Builder MessageBuilder::initRoot(SchemaType schema) {
return getRootInternal().initAs<RootType>(schema);
}
template <typename RootType>
typename RootType::Reader readMessageUnchecked(const word* data) {
return AnyPointer::Reader(_::PointerReader::getRootUnchecked(data)).getAs<RootType>();
}
template <typename Reader>
void copyToUnchecked(Reader&& reader, kj::ArrayPtr<word> uncheckedBuffer) {
FlatMessageBuilder builder(uncheckedBuffer);
builder.setRoot(kj::fwd<Reader>(reader));
builder.requireFilled();
}
template <typename RootType>
typename RootType::Reader readDataStruct(kj::ArrayPtr<const word> data) {
return typename RootType::Reader(_::StructReader(data));
}
template <typename BuilderType>
typename kj::ArrayPtr<const word> writeDataStruct(BuilderType builder) {
auto bytes = _::PointerHelpers<FromBuilder<BuilderType>>::getInternalBuilder(kj::mv(builder))
.getDataSectionAsBlob();
return kj::arrayPtr(reinterpret_cast<word*>(bytes.begin()),
reinterpret_cast<word*>(bytes.end()));
}
template <typename Type>
static typename Type::Reader defaultValue() {
return typename Type::Reader(_::StructReader());
}
template <typename T>
kj::Array<word> canonicalize(T&& reader) {
return _::PointerHelpers<FromReader<T>>::getInternalReader(reader).canonicalize();
}
} // namespace capnp
#endif // CAPNP_MESSAGE_H_

View File

@ -1,440 +0,0 @@
// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#ifndef CAPNP_ORPHAN_H_
#define CAPNP_ORPHAN_H_
#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS)
#pragma GCC system_header
#endif
#include "layout.h"
namespace capnp {
class StructSchema;
class ListSchema;
struct DynamicStruct;
struct DynamicList;
namespace _ { struct OrphanageInternal; }
template <typename T>
class Orphan {
// Represents an object which is allocated within some message builder but has no pointers
// pointing at it. An Orphan can later be "adopted" by some other object as one of that object's
// fields, without having to copy the orphan. For a field `foo` of pointer type, the generated
// code will define builder methods `void adoptFoo(Orphan<T>)` and `Orphan<T> disownFoo()`.
// Orphans can also be created independently of any parent using an Orphanage.
//
// `Orphan<T>` can be moved but not copied, like `Own<T>`, so that it is impossible for one
// orphan to be adopted multiple times. If an orphan is destroyed without being adopted, its
// contents are zero'd out (and possibly reused, if we ever implement the ability to reuse space
// in a message arena).
public:
Orphan() = default;
KJ_DISALLOW_COPY(Orphan);
Orphan(Orphan&&) = default;
Orphan& operator=(Orphan&&) = default;
inline Orphan(_::OrphanBuilder&& builder): builder(kj::mv(builder)) {}
inline BuilderFor<T> get();
// Get the underlying builder. If the orphan is null, this will allocate and return a default
// object rather than crash. This is done for security -- otherwise, you might enable a DoS
// attack any time you disown a field and fail to check if it is null. In the case of structs,
// this means that the orphan is no longer null after get() returns. In the case of lists,
// no actual object is allocated since a simple empty ListBuilder can be returned.
inline ReaderFor<T> getReader() const;
inline bool operator==(decltype(nullptr)) const { return builder == nullptr; }
inline bool operator!=(decltype(nullptr)) const { return builder != nullptr; }
inline void truncate(uint size);
// Resize an object (which must be a list or a blob) to the given size.
//
// If the new size is less than the original, the remaining elements will be discarded. The
// list is never moved in this case. If the list happens to be located at the end of its segment
// (which is always true if the list was the last thing allocated), the removed memory will be
// reclaimed (reducing the messag size), otherwise it is simply zeroed. The reclaiming behavior
// is particularly useful for allocating buffer space when you aren't sure how much space you
// actually need: you can pre-allocate, say, a 4k byte array, read() from a file into it, and
// then truncate it back to the amount of space actually used.
//
// If the new size is greater than the original, the list is extended with default values. If
// the list is the last object in its segment *and* there is enough space left in the segment to
// extend it to cover the new values, then the list is extended in-place. Otherwise, it must be
// moved to a new location, leaving a zero'd hole in the previous space that won't be filled.
// This copy is shallow; sub-objects will simply be reparented, not copied.
//
// Any existing readers or builders pointing at the object are invalidated by this call (even if
// it doesn't move). You must call `get()` or `getReader()` again to get the new, valid pointer.
private:
_::OrphanBuilder builder;
template <typename, Kind>
friend struct _::PointerHelpers;
template <typename, Kind>
friend struct List;
template <typename U>
friend class Orphan;
friend class Orphanage;
friend class MessageBuilder;
};
class Orphanage: private kj::DisallowConstCopy {
// Use to directly allocate Orphan objects, without having a parent object allocate and then
// disown the object.
public:
inline Orphanage(): arena(nullptr) {}
template <typename BuilderType>
static Orphanage getForMessageContaining(BuilderType builder);
// Construct an Orphanage that allocates within the message containing the given Builder. This
// allows the constructed Orphans to be adopted by objects within said message.
//
// This constructor takes the builder rather than having the builder have a getOrphanage() method
// because this is an advanced feature and we don't want to pollute the builder APIs with it.
//
// Note that if you have a direct pointer to the `MessageBuilder`, you can simply call its
// `getOrphanage()` method.
template <typename RootType>
Orphan<RootType> newOrphan() const;
// Allocate a new orphaned struct.
template <typename RootType>
Orphan<RootType> newOrphan(uint size) const;
// Allocate a new orphaned list or blob.
Orphan<DynamicStruct> newOrphan(StructSchema schema) const;
// Dynamically create an orphan struct with the given schema. You must
// #include <capnp/dynamic.h> to use this.
Orphan<DynamicList> newOrphan(ListSchema schema, uint size) const;
// Dynamically create an orphan list with the given schema. You must #include <capnp/dynamic.h>
// to use this.
template <typename Reader>
Orphan<FromReader<Reader>> newOrphanCopy(Reader copyFrom) const;
// Allocate a new orphaned object (struct, list, or blob) and initialize it as a copy of the
// given object.
template <typename T>
Orphan<List<ListElementType<FromReader<T>>>> newOrphanConcat(kj::ArrayPtr<T> lists) const;
template <typename T>
Orphan<List<ListElementType<FromReader<T>>>> newOrphanConcat(kj::ArrayPtr<const T> lists) const;
// Given an array of List readers, copy and concatenate the lists, creating a new Orphan.
//
// Note that compared to allocating the list yourself and using `setWithCaveats()` to set each
// item, this method avoids the "caveats": the new list will be allocated with the element size
// being the maximum of that from all the input lists. This is particularly important when
// concatenating struct lists: if the lists were created using a newer version of the protocol
// in which some new fields had been added to the struct, using `setWithCaveats()` would
// truncate off those new fields.
Orphan<Data> referenceExternalData(Data::Reader data) const;
// Creates an Orphan<Data> that points at an existing region of memory (e.g. from another message)
// without copying it. There are some SEVERE restrictions on how this can be used:
// - The memory must remain valid until the `MessageBuilder` is destroyed (even if the orphan is
// abandoned).
// - Because the data is const, you will not be allowed to obtain a `Data::Builder`
// for this blob. Any call which would return such a builder will throw an exception. You
// can, however, obtain a Reader, e.g. via orphan.getReader() or from a parent Reader (once
// the orphan is adopted). It is your responsibility to make sure your code can deal with
// these problems when using this optimization; if you can't, allocate a copy instead.
// - `data.begin()` must be aligned to a machine word boundary (32-bit or 64-bit depending on
// the CPU). Any pointer returned by malloc() as well as any data blob obtained from another
// Cap'n Proto message satisfies this.
// - If `data.size()` is not a multiple of 8, extra bytes past data.end() up until the next 8-byte
// boundary will be visible in the raw message when it is written out. Thus, there must be no
// secrets in these bytes. Data blobs obtained from other Cap'n Proto messages should be safe
// as these bytes should be zero (unless the sender had the same problem).
//
// The array will actually become one of the message's segments. The data can thus be adopted
// into the message tree without copying it. This is particularly useful when referencing very
// large blobs, such as whole mmap'd files.
private:
_::BuilderArena* arena;
_::CapTableBuilder* capTable;
inline explicit Orphanage(_::BuilderArena* arena, _::CapTableBuilder* capTable)
: arena(arena), capTable(capTable) {}
template <typename T, Kind = CAPNP_KIND(T)>
struct GetInnerBuilder;
template <typename T, Kind = CAPNP_KIND(T)>
struct GetInnerReader;
template <typename T>
struct NewOrphanListImpl;
friend class MessageBuilder;
friend struct _::OrphanageInternal;
};
// =======================================================================================
// Inline implementation details.
namespace _ { // private
template <typename T, Kind = CAPNP_KIND(T)>
struct OrphanGetImpl;
template <typename T>
struct OrphanGetImpl<T, Kind::PRIMITIVE> {
static inline void truncateListOf(_::OrphanBuilder& builder, ElementCount size) {
builder.truncate(size, _::elementSizeForType<T>());
}
};
template <typename T>
struct OrphanGetImpl<T, Kind::STRUCT> {
static inline typename T::Builder apply(_::OrphanBuilder& builder) {
return typename T::Builder(builder.asStruct(_::structSize<T>()));
}
static inline typename T::Reader applyReader(const _::OrphanBuilder& builder) {
return typename T::Reader(builder.asStructReader(_::structSize<T>()));
}
static inline void truncateListOf(_::OrphanBuilder& builder, ElementCount size) {
builder.truncate(size, _::structSize<T>());
}
};
#if !CAPNP_LITE
template <typename T>
struct OrphanGetImpl<T, Kind::INTERFACE> {
static inline typename T::Client apply(_::OrphanBuilder& builder) {
return typename T::Client(builder.asCapability());
}
static inline typename T::Client applyReader(const _::OrphanBuilder& builder) {
return typename T::Client(builder.asCapability());
}
static inline void truncateListOf(_::OrphanBuilder& builder, ElementCount size) {
builder.truncate(size, ElementSize::POINTER);
}
};
#endif // !CAPNP_LITE
template <typename T, Kind k>
struct OrphanGetImpl<List<T, k>, Kind::LIST> {
static inline typename List<T>::Builder apply(_::OrphanBuilder& builder) {
return typename List<T>::Builder(builder.asList(_::ElementSizeForType<T>::value));
}
static inline typename List<T>::Reader applyReader(const _::OrphanBuilder& builder) {
return typename List<T>::Reader(builder.asListReader(_::ElementSizeForType<T>::value));
}
static inline void truncateListOf(_::OrphanBuilder& builder, ElementCount size) {
builder.truncate(size, ElementSize::POINTER);
}
};
template <typename T>
struct OrphanGetImpl<List<T, Kind::STRUCT>, Kind::LIST> {
static inline typename List<T>::Builder apply(_::OrphanBuilder& builder) {
return typename List<T>::Builder(builder.asStructList(_::structSize<T>()));
}
static inline typename List<T>::Reader applyReader(const _::OrphanBuilder& builder) {
return typename List<T>::Reader(builder.asListReader(_::ElementSizeForType<T>::value));
}
static inline void truncateListOf(_::OrphanBuilder& builder, ElementCount size) {
builder.truncate(size, ElementSize::POINTER);
}
};
template <>
struct OrphanGetImpl<Text, Kind::BLOB> {
static inline Text::Builder apply(_::OrphanBuilder& builder) {
return Text::Builder(builder.asText());
}
static inline Text::Reader applyReader(const _::OrphanBuilder& builder) {
return Text::Reader(builder.asTextReader());
}
static inline void truncateListOf(_::OrphanBuilder& builder, ElementCount size) {
builder.truncate(size, ElementSize::POINTER);
}
};
template <>
struct OrphanGetImpl<Data, Kind::BLOB> {
static inline Data::Builder apply(_::OrphanBuilder& builder) {
return Data::Builder(builder.asData());
}
static inline Data::Reader applyReader(const _::OrphanBuilder& builder) {
return Data::Reader(builder.asDataReader());
}
static inline void truncateListOf(_::OrphanBuilder& builder, ElementCount size) {
builder.truncate(size, ElementSize::POINTER);
}
};
struct OrphanageInternal {
static inline _::BuilderArena* getArena(Orphanage orphanage) { return orphanage.arena; }
static inline _::CapTableBuilder* getCapTable(Orphanage orphanage) { return orphanage.capTable; }
};
} // namespace _ (private)
template <typename T>
inline BuilderFor<T> Orphan<T>::get() {
return _::OrphanGetImpl<T>::apply(builder);
}
template <typename T>
inline ReaderFor<T> Orphan<T>::getReader() const {
return _::OrphanGetImpl<T>::applyReader(builder);
}
template <typename T>
inline void Orphan<T>::truncate(uint size) {
_::OrphanGetImpl<ListElementType<T>>::truncateListOf(builder, bounded(size) * ELEMENTS);
}
template <>
inline void Orphan<Text>::truncate(uint size) {
builder.truncateText(bounded(size) * ELEMENTS);
}
template <>
inline void Orphan<Data>::truncate(uint size) {
builder.truncate(bounded(size) * ELEMENTS, ElementSize::BYTE);
}
template <typename T>
struct Orphanage::GetInnerBuilder<T, Kind::STRUCT> {
static inline _::StructBuilder apply(typename T::Builder& t) {
return t._builder;
}
};
template <typename T>
struct Orphanage::GetInnerBuilder<T, Kind::LIST> {
static inline _::ListBuilder apply(typename T::Builder& t) {
return t.builder;
}
};
template <typename BuilderType>
Orphanage Orphanage::getForMessageContaining(BuilderType builder) {
auto inner = GetInnerBuilder<FromBuilder<BuilderType>>::apply(builder);
return Orphanage(inner.getArena(), inner.getCapTable());
}
template <typename RootType>
Orphan<RootType> Orphanage::newOrphan() const {
return Orphan<RootType>(_::OrphanBuilder::initStruct(arena, capTable, _::structSize<RootType>()));
}
template <typename T, Kind k>
struct Orphanage::NewOrphanListImpl<List<T, k>> {
static inline _::OrphanBuilder apply(
_::BuilderArena* arena, _::CapTableBuilder* capTable, uint size) {
return _::OrphanBuilder::initList(
arena, capTable, bounded(size) * ELEMENTS, _::ElementSizeForType<T>::value);
}
};
template <typename T>
struct Orphanage::NewOrphanListImpl<List<T, Kind::STRUCT>> {
static inline _::OrphanBuilder apply(
_::BuilderArena* arena, _::CapTableBuilder* capTable, uint size) {
return _::OrphanBuilder::initStructList(
arena, capTable, bounded(size) * ELEMENTS, _::structSize<T>());
}
};
template <>
struct Orphanage::NewOrphanListImpl<Text> {
static inline _::OrphanBuilder apply(
_::BuilderArena* arena, _::CapTableBuilder* capTable, uint size) {
return _::OrphanBuilder::initText(arena, capTable, bounded(size) * BYTES);
}
};
template <>
struct Orphanage::NewOrphanListImpl<Data> {
static inline _::OrphanBuilder apply(
_::BuilderArena* arena, _::CapTableBuilder* capTable, uint size) {
return _::OrphanBuilder::initData(arena, capTable, bounded(size) * BYTES);
}
};
template <typename RootType>
Orphan<RootType> Orphanage::newOrphan(uint size) const {
return Orphan<RootType>(NewOrphanListImpl<RootType>::apply(arena, capTable, size));
}
template <typename T>
struct Orphanage::GetInnerReader<T, Kind::STRUCT> {
static inline _::StructReader apply(const typename T::Reader& t) {
return t._reader;
}
};
template <typename T>
struct Orphanage::GetInnerReader<T, Kind::LIST> {
static inline _::ListReader apply(const typename T::Reader& t) {
return t.reader;
}
};
template <typename T>
struct Orphanage::GetInnerReader<T, Kind::BLOB> {
static inline const typename T::Reader& apply(const typename T::Reader& t) {
return t;
}
};
template <typename Reader>
inline Orphan<FromReader<Reader>> Orphanage::newOrphanCopy(Reader copyFrom) const {
return Orphan<FromReader<Reader>>(_::OrphanBuilder::copy(
arena, capTable, GetInnerReader<FromReader<Reader>>::apply(copyFrom)));
}
template <typename T>
inline Orphan<List<ListElementType<FromReader<T>>>>
Orphanage::newOrphanConcat(kj::ArrayPtr<T> lists) const {
return newOrphanConcat(kj::implicitCast<kj::ArrayPtr<const T>>(lists));
}
template <typename T>
inline Orphan<List<ListElementType<FromReader<T>>>>
Orphanage::newOrphanConcat(kj::ArrayPtr<const T> lists) const {
// Optimization / simplification: Rely on List<T>::Reader containing nothing except a
// _::ListReader.
static_assert(sizeof(T) == sizeof(_::ListReader), "lists are not bare readers?");
kj::ArrayPtr<const _::ListReader> raw(
reinterpret_cast<const _::ListReader*>(lists.begin()), lists.size());
typedef ListElementType<FromReader<T>> Element;
return Orphan<List<Element>>(
_::OrphanBuilder::concat(arena, capTable,
_::elementSizeForType<Element>(),
_::minStructSizeForElement<Element>(), raw));
}
inline Orphan<Data> Orphanage::referenceExternalData(Data::Reader data) const {
return Orphan<Data>(_::OrphanBuilder::referenceExternalData(arena, data));
}
} // namespace capnp
#endif // CAPNP_ORPHAN_H_

View File

@ -1,139 +0,0 @@
# Copyright (c) 2014 Sandstorm Development Group, Inc. and contributors
# Licensed under the MIT License:
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
@0xb8630836983feed7;
$import "/capnp/c++.capnp".namespace("capnp");
interface Persistent@0xc8cb212fcd9f5691(SturdyRef, Owner) {
# Interface implemented by capabilities that outlive a single connection. A client may save()
# the capability, producing a SturdyRef. The SturdyRef can be stored to disk, then later used to
# obtain a new reference to the capability on a future connection.
#
# The exact format of SturdyRef depends on the "realm" in which the SturdyRef appears. A "realm"
# is an abstract space in which all SturdyRefs have the same format and refer to the same set of
# resources. Every vat is in exactly one realm. All capability clients within that vat must
# produce SturdyRefs of the format appropriate for the realm.
#
# Similarly, every VatNetwork also resides in a particular realm. Usually, a vat's "realm"
# corresponds to the realm of its main VatNetwork. However, a Vat can in fact communicate over
# a VatNetwork in a different realm -- in this case, all SturdyRefs need to be transformed when
# coming or going through said VatNetwork. The RPC system has hooks for registering
# transformation callbacks for this purpose.
#
# Since the format of SturdyRef is realm-dependent, it is not defined here. An application should
# choose an appropriate realm for itself as part of its design. Note that under Sandstorm, every
# application exists in its own realm and is therefore free to define its own SturdyRef format;
# the Sandstorm platform handles translating between realms.
#
# Note that whether a capability is persistent is often orthogonal to its type. In these cases,
# the capability's interface should NOT inherit `Persistent`; instead, just perform a cast at
# runtime. It's not type-safe, but trying to be type-safe in these cases will likely lead to
# tears. In cases where a particular interface only makes sense on persistent capabilities, it
# still should not explicitly inherit Persistent because the `SturdyRef` and `Owner` types will
# vary between realms (they may even be different at the call site than they are on the
# implementation). Instead, mark persistent interfaces with the $persistent annotation (defined
# below).
#
# Sealing
# -------
#
# As an added security measure, SturdyRefs may be "sealed" to a particular owner, such that
# if the SturdyRef itself leaks to a third party, that party cannot actually restore it because
# they are not the owner. To restore a sealed capability, you must first prove to its host that
# you are the rightful owner. The precise mechanism for this authentication is defined by the
# realm.
#
# Sealing is a defense-in-depth mechanism meant to mitigate damage in the case of catastrophic
# attacks. For example, say an attacker temporarily gains read access to a database full of
# SturdyRefs: it would be unfortunate if it were then necessary to revoke every single reference
# in the database to prevent the attacker from using them.
#
# In general, an "owner" is a course-grained identity. Because capability-based security is still
# the primary mechanism of security, it is not necessary nor desirable to have a separate "owner"
# identity for every single process or object; that is exactly what capabilities are supposed to
# avoid! Instead, it makes sense for an "owner" to literally identify the owner of the machines
# where the capability is stored. If untrusted third parties are able to run arbitrary code on
# said machines, then the sandbox for that code should be designed using Distributed Confinement
# such that the third-party code never sees the bits of the SturdyRefs and cannot directly
# exercise the owner's power to restore refs. See:
#
# http://www.erights.org/elib/capability/dist-confine.html
#
# Resist the urge to represent an Owner as a simple public key. The whole point of sealing is to
# defend against leaked-storage attacks. Such attacks can easily result in the owner's private
# key being stolen as well. A better solution is for `Owner` to contain a simple globally unique
# identifier for the owner, and for everyone to separately maintain a mapping of owner IDs to
# public keys. If an owner's private key is compromised, then humans will need to communicate
# and agree on a replacement public key, then update the mapping.
#
# As a concrete example, an `Owner` could simply contain a domain name, and restoring a SturdyRef
# would require signing a request using the domain's private key. Authenticating this key could
# be accomplished through certificate authorities or web-of-trust techniques.
save @0 SaveParams -> SaveResults;
# Save a capability persistently so that it can be restored by a future connection. Not all
# capabilities can be saved -- application interfaces should define which capabilities support
# this and which do not.
struct SaveParams {
sealFor @0 :Owner;
# Seal the SturdyRef so that it can only be restored by the specified Owner. This is meant
# to mitigate damage when a SturdyRef is leaked. See comments above.
#
# Leaving this value null may or may not be allowed; it is up to the realm to decide. If a
# realm does allow a null owner, this should indicate that anyone is allowed to restore the
# ref.
}
struct SaveResults {
sturdyRef @0 :SturdyRef;
}
}
interface RealmGateway(InternalRef, ExternalRef, InternalOwner, ExternalOwner) {
# Interface invoked when a SturdyRef is about to cross realms. The RPC system supports providing
# a RealmGateway as a callback hook when setting up RPC over some VatNetwork.
import @0 (cap :Persistent(ExternalRef, ExternalOwner),
params :Persistent(InternalRef, InternalOwner).SaveParams)
-> Persistent(InternalRef, InternalOwner).SaveResults;
# Given an external capability, save it and return an internal reference. Used when someone
# inside the realm tries to save a capability from outside the realm.
export @1 (cap :Persistent(InternalRef, InternalOwner),
params :Persistent(ExternalRef, ExternalOwner).SaveParams)
-> Persistent(ExternalRef, ExternalOwner).SaveResults;
# Given an internal capability, save it and return an external reference. Used when someone
# outside the realm tries to save a capability from inside the realm.
}
annotation persistent(interface, field) :Void;
# Apply this annotation to interfaces for objects that will always be persistent, instead of
# extending the Persistent capability, since the correct type parameters to Persistent depend on
# the realm, which is orthogonal to the interface type and therefore should not be defined
# along-side it.
#
# You may also apply this annotation to a capability-typed field which will always contain a
# persistent capability, but where the capability's interface itself is not already marked
# persistent.
#
# Note that absence of the $persistent annotation doesn't mean a capability of that type isn't
# persistent; it just means not *all* such capabilities are persistent.

File diff suppressed because it is too large Load Diff

View File

@ -1,160 +0,0 @@
// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#ifndef CAPNP_POINTER_HELPERS_H_
#define CAPNP_POINTER_HELPERS_H_
#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS)
#pragma GCC system_header
#endif
#include "layout.h"
#include "list.h"
namespace capnp {
namespace _ { // private
// PointerHelpers is a template class that assists in wrapping/unwrapping the low-level types in
// layout.h with the high-level public API and generated types. This way, the code generator
// and other templates do not have to specialize on each kind of pointer.
template <typename T>
struct PointerHelpers<T, Kind::STRUCT> {
static inline typename T::Reader get(PointerReader reader, const word* defaultValue = nullptr) {
return typename T::Reader(reader.getStruct(defaultValue));
}
static inline typename T::Builder get(PointerBuilder builder,
const word* defaultValue = nullptr) {
return typename T::Builder(builder.getStruct(structSize<T>(), defaultValue));
}
static inline void set(PointerBuilder builder, typename T::Reader value) {
builder.setStruct(value._reader);
}
static inline void setCanonical(PointerBuilder builder, typename T::Reader value) {
builder.setStruct(value._reader, true);
}
static inline typename T::Builder init(PointerBuilder builder) {
return typename T::Builder(builder.initStruct(structSize<T>()));
}
static inline void adopt(PointerBuilder builder, Orphan<T>&& value) {
builder.adopt(kj::mv(value.builder));
}
static inline Orphan<T> disown(PointerBuilder builder) {
return Orphan<T>(builder.disown());
}
static inline _::StructReader getInternalReader(const typename T::Reader& reader) {
return reader._reader;
}
static inline _::StructBuilder getInternalBuilder(typename T::Builder&& builder) {
return builder._builder;
}
};
template <typename T>
struct PointerHelpers<List<T>, Kind::LIST> {
static inline typename List<T>::Reader get(PointerReader reader,
const word* defaultValue = nullptr) {
return typename List<T>::Reader(List<T>::getFromPointer(reader, defaultValue));
}
static inline typename List<T>::Builder get(PointerBuilder builder,
const word* defaultValue = nullptr) {
return typename List<T>::Builder(List<T>::getFromPointer(builder, defaultValue));
}
static inline void set(PointerBuilder builder, typename List<T>::Reader value) {
builder.setList(value.reader);
}
static inline void setCanonical(PointerBuilder builder, typename List<T>::Reader value) {
builder.setList(value.reader, true);
}
static void set(PointerBuilder builder, kj::ArrayPtr<const ReaderFor<T>> value) {
auto l = init(builder, value.size());
uint i = 0;
for (auto& element: value) {
l.set(i++, element);
}
}
static inline typename List<T>::Builder init(PointerBuilder builder, uint size) {
return typename List<T>::Builder(List<T>::initPointer(builder, size));
}
static inline void adopt(PointerBuilder builder, Orphan<List<T>>&& value) {
builder.adopt(kj::mv(value.builder));
}
static inline Orphan<List<T>> disown(PointerBuilder builder) {
return Orphan<List<T>>(builder.disown());
}
static inline _::ListReader getInternalReader(const typename List<T>::Reader& reader) {
return reader.reader;
}
static inline _::ListBuilder getInternalBuilder(typename List<T>::Builder&& builder) {
return builder.builder;
}
};
template <typename T>
struct PointerHelpers<T, Kind::BLOB> {
static inline typename T::Reader get(PointerReader reader,
const void* defaultValue = nullptr,
uint defaultBytes = 0) {
return reader.getBlob<T>(defaultValue, bounded(defaultBytes) * BYTES);
}
static inline typename T::Builder get(PointerBuilder builder,
const void* defaultValue = nullptr,
uint defaultBytes = 0) {
return builder.getBlob<T>(defaultValue, bounded(defaultBytes) * BYTES);
}
static inline void set(PointerBuilder builder, typename T::Reader value) {
builder.setBlob<T>(value);
}
static inline void setCanonical(PointerBuilder builder, typename T::Reader value) {
builder.setBlob<T>(value);
}
static inline typename T::Builder init(PointerBuilder builder, uint size) {
return builder.initBlob<T>(bounded(size) * BYTES);
}
static inline void adopt(PointerBuilder builder, Orphan<T>&& value) {
builder.adopt(kj::mv(value.builder));
}
static inline Orphan<T> disown(PointerBuilder builder) {
return Orphan<T>(builder.disown());
}
};
struct UncheckedMessage {
typedef const word* Reader;
};
template <> struct Kind_<UncheckedMessage> { static constexpr Kind kind = Kind::OTHER; };
template <>
struct PointerHelpers<UncheckedMessage> {
// Reads an AnyPointer field as an unchecked message pointer. Requires that the containing
// message is itself unchecked. This hack is currently private. It is used to locate default
// values within encoded schemas.
static inline const word* get(PointerReader reader) {
return reader.getUnchecked();
}
};
} // namespace _ (private)
} // namespace capnp
#endif // CAPNP_POINTER_HELPERS_H_

View File

@ -1,47 +0,0 @@
// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#ifndef CAPNP_PRETTY_PRINT_H_
#define CAPNP_PRETTY_PRINT_H_
#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS)
#pragma GCC system_header
#endif
#include "dynamic.h"
#include <kj/string-tree.h>
namespace capnp {
kj::StringTree prettyPrint(DynamicStruct::Reader value);
kj::StringTree prettyPrint(DynamicStruct::Builder value);
kj::StringTree prettyPrint(DynamicList::Reader value);
kj::StringTree prettyPrint(DynamicList::Builder value);
// Print the given Cap'n Proto struct or list with nice indentation. Note that you can pass any
// struct or list reader or builder type to this method, since they can be implicitly converted
// to one of the dynamic types.
//
// If you don't want indentation, just use the value's KJ stringifier (e.g. pass it to kj::str(),
// any of the KJ debug macros, etc.).
} // namespace capnp
#endif // PRETTY_PRINT_H_

View File

@ -1,242 +0,0 @@
// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#ifndef CAPNP_RAW_SCHEMA_H_
#define CAPNP_RAW_SCHEMA_H_
#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS)
#pragma GCC system_header
#endif
#include "common.h" // for uint and friends
#if _MSC_VER
#include <atomic>
#endif
namespace capnp {
namespace _ { // private
struct RawSchema;
struct RawBrandedSchema {
// Represents a combination of a schema and bindings for its generic parameters.
//
// Note that while we generate one `RawSchema` per type, we generate a `RawBrandedSchema` for
// every _instance_ of a generic type -- or, at least, every instance that is actually used. For
// generated-code types, we use template magic to initialize these.
const RawSchema* generic;
// Generic type which we're branding.
struct Binding {
uint8_t which; // Numeric value of one of schema::Type::Which.
bool isImplicitParameter;
// For AnyPointer, true if it's an implicit method parameter.
uint16_t listDepth; // Number of times to wrap the base type in List().
uint16_t paramIndex;
// For AnyPointer. If it's a type parameter (scopeId is non-zero) or it's an implicit parameter
// (isImplicitParameter is true), then this is the parameter index. Otherwise this is a numeric
// value of one of schema::Type::AnyPointer::Unconstrained::Which.
union {
const RawBrandedSchema* schema; // for struct, enum, interface
uint64_t scopeId; // for AnyPointer, if it's a type parameter
};
Binding() = default;
inline constexpr Binding(uint8_t which, uint16_t listDepth, const RawBrandedSchema* schema)
: which(which), isImplicitParameter(false), listDepth(listDepth), paramIndex(0),
schema(schema) {}
inline constexpr Binding(uint8_t which, uint16_t listDepth,
uint64_t scopeId, uint16_t paramIndex)
: which(which), isImplicitParameter(false), listDepth(listDepth), paramIndex(paramIndex),
scopeId(scopeId) {}
inline constexpr Binding(uint8_t which, uint16_t listDepth, uint16_t implicitParamIndex)
: which(which), isImplicitParameter(true), listDepth(listDepth),
paramIndex(implicitParamIndex), scopeId(0) {}
};
struct Scope {
uint64_t typeId;
// Type ID whose parameters are being bound.
const Binding* bindings;
uint bindingCount;
// Bindings for those parameters.
bool isUnbound;
// This scope is unbound, in the sense of SchemaLoader::getUnbound().
};
const Scope* scopes;
// Array of enclosing scopes for which generic variables have been bound, sorted by type ID.
struct Dependency {
uint location;
const RawBrandedSchema* schema;
};
const Dependency* dependencies;
// Map of branded schemas for dependencies of this type, given our brand. Only dependencies that
// are branded are included in this map; if a dependency is missing, use its `defaultBrand`.
uint32_t scopeCount;
uint32_t dependencyCount;
enum class DepKind {
// Component of a Dependency::location. Specifies what sort of dependency this is.
INVALID,
// Mostly defined to ensure that zero is not a valid location.
FIELD,
// Binding needed for a field's type. The index is the field index (NOT ordinal!).
METHOD_PARAMS,
// Bindings needed for a method's params type. The index is the method number.
METHOD_RESULTS,
// Bindings needed for a method's results type. The index is the method ordinal.
SUPERCLASS,
// Bindings needed for a superclass type. The index is the superclass's index in the
// "extends" list.
CONST_TYPE
// Bindings needed for the type of a constant. The index is zero.
};
static inline uint makeDepLocation(DepKind kind, uint index) {
// Make a number representing the location of a particular dependency within its parent
// schema.
return (static_cast<uint>(kind) << 24) | index;
}
class Initializer {
public:
virtual void init(const RawBrandedSchema* generic) const = 0;
};
const Initializer* lazyInitializer;
// Lazy initializer, invoked by ensureInitialized().
inline void ensureInitialized() const {
// Lazy initialization support. Invoke to ensure that initialization has taken place. This
// is required in particular when traversing the dependency list. RawSchemas for compiled-in
// types are always initialized; only dynamically-loaded schemas may be lazy.
#if __GNUC__
const Initializer* i = __atomic_load_n(&lazyInitializer, __ATOMIC_ACQUIRE);
#elif _MSC_VER
const Initializer* i = *static_cast<Initializer const* const volatile*>(&lazyInitializer);
std::atomic_thread_fence(std::memory_order_acquire);
#else
#error "Platform not supported"
#endif
if (i != nullptr) i->init(this);
}
inline bool isUnbound() const;
// Checks if this schema is the result of calling SchemaLoader::getUnbound(), in which case
// binding lookups need to be handled specially.
};
struct RawSchema {
// The generated code defines a constant RawSchema for every compiled declaration.
//
// This is an internal structure which could change in the future.
uint64_t id;
const word* encodedNode;
// Encoded SchemaNode, readable via readMessageUnchecked<schema::Node>(encodedNode).
uint32_t encodedSize;
// Size of encodedNode, in words.
const RawSchema* const* dependencies;
// Pointers to other types on which this one depends, sorted by ID. The schemas in this table
// may be uninitialized -- you must call ensureInitialized() on the one you wish to use before
// using it.
//
// TODO(someday): Make this a hashtable.
const uint16_t* membersByName;
// Indexes of members sorted by name. Used to implement name lookup.
// TODO(someday): Make this a hashtable.
uint32_t dependencyCount;
uint32_t memberCount;
// Sizes of above tables.
const uint16_t* membersByDiscriminant;
// List of all member indexes ordered by discriminant value. Those which don't have a
// discriminant value are listed at the end, in order by ordinal.
const RawSchema* canCastTo;
// Points to the RawSchema of a compiled-in type to which it is safe to cast any DynamicValue
// with this schema. This is null for all compiled-in types; it is only set by SchemaLoader on
// dynamically-loaded types.
class Initializer {
public:
virtual void init(const RawSchema* schema) const = 0;
};
const Initializer* lazyInitializer;
// Lazy initializer, invoked by ensureInitialized().
inline void ensureInitialized() const {
// Lazy initialization support. Invoke to ensure that initialization has taken place. This
// is required in particular when traversing the dependency list. RawSchemas for compiled-in
// types are always initialized; only dynamically-loaded schemas may be lazy.
#if __GNUC__
const Initializer* i = __atomic_load_n(&lazyInitializer, __ATOMIC_ACQUIRE);
#elif _MSC_VER
const Initializer* i = *static_cast<Initializer const* const volatile*>(&lazyInitializer);
std::atomic_thread_fence(std::memory_order_acquire);
#else
#error "Platform not supported"
#endif
if (i != nullptr) i->init(this);
}
RawBrandedSchema defaultBrand;
// Specifies the brand to use for this schema if no generic parameters have been bound to
// anything. Generally, in the default brand, all generic parameters are treated as if they were
// bound to `AnyPointer`.
};
inline bool RawBrandedSchema::isUnbound() const {
// The unbound schema is the only one that has no scopes but is not the default schema.
return scopeCount == 0 && this != &generic->defaultBrand;
}
} // namespace _ (private)
} // namespace capnp
#endif // CAPNP_RAW_SCHEMA_H_

View File

@ -1,130 +0,0 @@
// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
// This file contains a bunch of internal declarations that must appear before rpc.h can start.
// We don't define these directly in rpc.h because it makes the file hard to read.
#ifndef CAPNP_RPC_PRELUDE_H_
#define CAPNP_RPC_PRELUDE_H_
#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS)
#pragma GCC system_header
#endif
#include "capability.h"
#include "persistent.capnp.h"
namespace capnp {
class OutgoingRpcMessage;
class IncomingRpcMessage;
template <typename SturdyRefHostId>
class RpcSystem;
namespace _ { // private
class VatNetworkBase {
// Non-template version of VatNetwork. Ignore this class; see VatNetwork in rpc.h.
public:
class Connection;
struct ConnectionAndProvisionId {
kj::Own<Connection> connection;
kj::Own<OutgoingRpcMessage> firstMessage;
Orphan<AnyPointer> provisionId;
};
class Connection {
public:
virtual kj::Own<OutgoingRpcMessage> newOutgoingMessage(uint firstSegmentWordSize) = 0;
virtual kj::Promise<kj::Maybe<kj::Own<IncomingRpcMessage>>> receiveIncomingMessage() = 0;
virtual kj::Promise<void> shutdown() = 0;
virtual AnyStruct::Reader baseGetPeerVatId() = 0;
};
virtual kj::Maybe<kj::Own<Connection>> baseConnect(AnyStruct::Reader vatId) = 0;
virtual kj::Promise<kj::Own<Connection>> baseAccept() = 0;
};
class SturdyRefRestorerBase {
public:
virtual Capability::Client baseRestore(AnyPointer::Reader ref) = 0;
};
class BootstrapFactoryBase {
// Non-template version of BootstrapFactory. Ignore this class; see BootstrapFactory in rpc.h.
public:
virtual Capability::Client baseCreateFor(AnyStruct::Reader clientId) = 0;
};
class RpcSystemBase {
// Non-template version of RpcSystem. Ignore this class; see RpcSystem in rpc.h.
public:
RpcSystemBase(VatNetworkBase& network, kj::Maybe<Capability::Client> bootstrapInterface,
kj::Maybe<RealmGateway<>::Client> gateway);
RpcSystemBase(VatNetworkBase& network, BootstrapFactoryBase& bootstrapFactory,
kj::Maybe<RealmGateway<>::Client> gateway);
RpcSystemBase(VatNetworkBase& network, SturdyRefRestorerBase& restorer);
RpcSystemBase(RpcSystemBase&& other) noexcept;
~RpcSystemBase() noexcept(false);
private:
class Impl;
kj::Own<Impl> impl;
Capability::Client baseBootstrap(AnyStruct::Reader vatId);
Capability::Client baseRestore(AnyStruct::Reader vatId, AnyPointer::Reader objectId);
void baseSetFlowLimit(size_t words);
template <typename>
friend class capnp::RpcSystem;
};
template <typename T> struct InternalRefFromRealmGateway_;
template <typename InternalRef, typename ExternalRef, typename InternalOwner,
typename ExternalOwner>
struct InternalRefFromRealmGateway_<RealmGateway<InternalRef, ExternalRef, InternalOwner,
ExternalOwner>> {
typedef InternalRef Type;
};
template <typename T>
using InternalRefFromRealmGateway = typename InternalRefFromRealmGateway_<T>::Type;
template <typename T>
using InternalRefFromRealmGatewayClient = InternalRefFromRealmGateway<typename T::Calls>;
template <typename T> struct ExternalRefFromRealmGateway_;
template <typename InternalRef, typename ExternalRef, typename InternalOwner,
typename ExternalOwner>
struct ExternalRefFromRealmGateway_<RealmGateway<InternalRef, ExternalRef, InternalOwner,
ExternalOwner>> {
typedef ExternalRef Type;
};
template <typename T>
using ExternalRefFromRealmGateway = typename ExternalRefFromRealmGateway_<T>::Type;
template <typename T>
using ExternalRefFromRealmGatewayClient = ExternalRefFromRealmGateway<typename T::Calls>;
} // namespace _ (private)
} // namespace capnp
#endif // CAPNP_RPC_PRELUDE_H_

View File

@ -1,169 +0,0 @@
# Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
# Licensed under the MIT License:
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
@0xa184c7885cdaf2a1;
# This file defines the "network-specific parameters" in rpc.capnp to support a network consisting
# of two vats. Each of these vats may in fact be in communication with other vats, but any
# capabilities they forward must be proxied. Thus, to each end of the connection, all capabilities
# received from the other end appear to live in a single vat.
#
# Two notable use cases for this model include:
# - Regular client-server communications, where a remote client machine (perhaps living on an end
# user's personal device) connects to a server. The server may be part of a cluster, and may
# call on other servers in the cluster to help service the user's request. It may even obtain
# capabilities from these other servers which it passes on to the user. To simplify network
# common traversal problems (e.g. if the user is behind a firewall), it is probably desirable to
# multiplex all communications between the server cluster and the client over the original
# connection rather than form new ones. This connection should use the two-party protocol, as
# the client has no interest in knowing about additional servers.
# - Applications running in a sandbox. A supervisor process may execute a confined application
# such that all of the confined app's communications with the outside world must pass through
# the supervisor. In this case, the connection between the confined app and the supervisor might
# as well use the two-party protocol, because the confined app is intentionally prevented from
# talking to any other vat anyway. Any external resources will be proxied through the supervisor,
# and so to the contained app will appear as if they were hosted by the supervisor itself.
#
# Since there are only two vats in this network, there is never a need for three-way introductions,
# so level 3 is free. Moreover, because it is never necessary to form new connections, the
# two-party protocol can be used easily anywhere where a two-way byte stream exists, without regard
# to where that byte stream goes or how it was initiated. This makes the two-party runtime library
# highly reusable.
#
# Joins (level 4) _could_ be needed in cases where one or both vats are participating in other
# networks that use joins. For instance, if Alice and Bob are speaking through the two-party
# protocol, and Bob is also participating on another network, Bob may send Alice two or more
# proxied capabilities which, unbeknownst to Bob at the time, are in fact pointing at the same
# remote object. Alice may then request to join these capabilities, at which point Bob will have
# to forward the join to the other network. Note, however, that if Alice is _not_ participating on
# any other network, then Alice will never need to _receive_ a Join, because Alice would always
# know when two locally-hosted capabilities are the same and would never export a redundant alias
# to Bob. So, Alice can respond to all incoming joins with an error, and only needs to implement
# outgoing joins if she herself desires to use this feature. Also, outgoing joins are relatively
# easy to implement in this scenario.
#
# What all this means is that a level 4 implementation of the confined network is barely more
# complicated than a level 2 implementation. However, such an implementation allows the "client"
# or "confined" app to access the server's/supervisor's network with equal functionality to any
# native participant. In other words, an application which implements only the two-party protocol
# can be paired with a proxy app in order to participate in any network.
#
# So, when implementing Cap'n Proto in a new language, it makes sense to implement only the
# two-party protocol initially, and then pair applications with an appropriate proxy written in
# C++, rather than implement other parameterizations of the RPC protocol directly.
using Cxx = import "/capnp/c++.capnp";
$Cxx.namespace("capnp::rpc::twoparty");
# Note: SturdyRef is not specified here. It is up to the application to define semantics of
# SturdyRefs if desired.
enum Side {
server @0;
# The object lives on the "server" or "supervisor" end of the connection. Only the
# server/supervisor knows how to interpret the ref; to the client, it is opaque.
#
# Note that containers intending to implement strong confinement should rewrite SturdyRefs
# received from the external network before passing them on to the confined app. The confined
# app thus does not ever receive the raw bits of the SturdyRef (which it could perhaps
# maliciously leak), but instead receives only a thing that it can pass back to the container
# later to restore the ref. See:
# http://www.erights.org/elib/capability/dist-confine.html
client @1;
# The object lives on the "client" or "confined app" end of the connection. Only the client
# knows how to interpret the ref; to the server/supervisor, it is opaque. Most clients do not
# actually know how to persist capabilities at all, so use of this is unusual.
}
struct VatId {
side @0 :Side;
}
struct ProvisionId {
# Only used for joins, since three-way introductions never happen on a two-party network.
joinId @0 :UInt32;
# The ID from `JoinKeyPart`.
}
struct RecipientId {}
# Never used, because there are only two parties.
struct ThirdPartyCapId {}
# Never used, because there is no third party.
struct JoinKeyPart {
# Joins in the two-party case are simplified by a few observations.
#
# First, on a two-party network, a Join only ever makes sense if the receiving end is also
# connected to other networks. A vat which is not connected to any other network can safely
# reject all joins.
#
# Second, since a two-party connection bisects the network -- there can be no other connections
# between the networks at either end of the connection -- if one part of a join crosses the
# connection, then _all_ parts must cross it. Therefore, a vat which is receiving a Join request
# off some other network which needs to be forwarded across the two-party connection can
# collect all the parts on its end and only forward them across the two-party connection when all
# have been received.
#
# For example, imagine that Alice and Bob are vats connected over a two-party connection, and
# each is also connected to other networks. At some point, Alice receives one part of a Join
# request off her network. The request is addressed to a capability that Alice received from
# Bob and is proxying to her other network. Alice goes ahead and responds to the Join part as
# if she hosted the capability locally (this is important so that if not all the Join parts end
# up at Alice, the original sender can detect the failed Join without hanging). As other parts
# trickle in, Alice verifies that each part is addressed to a capability from Bob and continues
# to respond to each one. Once the complete set of join parts is received, Alice checks if they
# were all for the exact same capability. If so, she doesn't need to send anything to Bob at
# all. Otherwise, she collects the set of capabilities (from Bob) to which the join parts were
# addressed and essentially initiates a _new_ Join request on those capabilities to Bob. Alice
# does not forward the Join parts she received herself, but essentially forwards the Join as a
# whole.
#
# On Bob's end, since he knows that Alice will always send all parts of a Join together, he
# simply waits until he's received them all, then performs a join on the respective capabilities
# as if it had been requested locally.
joinId @0 :UInt32;
# A number identifying this join, chosen by the sender. May be reused once `Finish` messages are
# sent corresponding to all of the `Join` messages.
partCount @1 :UInt16;
# The number of capabilities to be joined.
partNum @2 :UInt16;
# Which part this request targets -- a number in the range [0, partCount).
}
struct JoinResult {
joinId @0 :UInt32;
# Matches `JoinKeyPart`.
succeeded @1 :Bool;
# All JoinResults in the set will have the same value for `succeeded`. The receiver actually
# implements the join by waiting for all the `JoinKeyParts` and then performing its own join on
# them, then going back and answering all the join requests afterwards.
cap @2 :AnyPointer;
# One of the JoinResults will have a non-null `cap` which is the joined capability.
#
# TODO(cleanup): Change `AnyPointer` to `Capability` when that is supported.
}

View File

@ -1,726 +0,0 @@
// Generated by Cap'n Proto compiler, DO NOT EDIT
// source: rpc-twoparty.capnp
#ifndef CAPNP_INCLUDED_a184c7885cdaf2a1_
#define CAPNP_INCLUDED_a184c7885cdaf2a1_
#include <capnp/generated-header-support.h>
#if CAPNP_VERSION != 6001
#error "Version mismatch between generated code and library headers. You must use the same version of the Cap'n Proto compiler and library."
#endif
namespace capnp {
namespace schemas {
CAPNP_DECLARE_SCHEMA(9fd69ebc87b9719c);
enum class Side_9fd69ebc87b9719c: uint16_t {
SERVER,
CLIENT,
};
CAPNP_DECLARE_ENUM(Side, 9fd69ebc87b9719c);
CAPNP_DECLARE_SCHEMA(d20b909fee733a8e);
CAPNP_DECLARE_SCHEMA(b88d09a9c5f39817);
CAPNP_DECLARE_SCHEMA(89f389b6fd4082c1);
CAPNP_DECLARE_SCHEMA(b47f4979672cb59d);
CAPNP_DECLARE_SCHEMA(95b29059097fca83);
CAPNP_DECLARE_SCHEMA(9d263a3630b7ebee);
} // namespace schemas
} // namespace capnp
namespace capnp {
namespace rpc {
namespace twoparty {
typedef ::capnp::schemas::Side_9fd69ebc87b9719c Side;
struct VatId {
VatId() = delete;
class Reader;
class Builder;
class Pipeline;
struct _capnpPrivate {
CAPNP_DECLARE_STRUCT_HEADER(d20b909fee733a8e, 1, 0)
#if !CAPNP_LITE
static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; }
#endif // !CAPNP_LITE
};
};
struct ProvisionId {
ProvisionId() = delete;
class Reader;
class Builder;
class Pipeline;
struct _capnpPrivate {
CAPNP_DECLARE_STRUCT_HEADER(b88d09a9c5f39817, 1, 0)
#if !CAPNP_LITE
static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; }
#endif // !CAPNP_LITE
};
};
struct RecipientId {
RecipientId() = delete;
class Reader;
class Builder;
class Pipeline;
struct _capnpPrivate {
CAPNP_DECLARE_STRUCT_HEADER(89f389b6fd4082c1, 0, 0)
#if !CAPNP_LITE
static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; }
#endif // !CAPNP_LITE
};
};
struct ThirdPartyCapId {
ThirdPartyCapId() = delete;
class Reader;
class Builder;
class Pipeline;
struct _capnpPrivate {
CAPNP_DECLARE_STRUCT_HEADER(b47f4979672cb59d, 0, 0)
#if !CAPNP_LITE
static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; }
#endif // !CAPNP_LITE
};
};
struct JoinKeyPart {
JoinKeyPart() = delete;
class Reader;
class Builder;
class Pipeline;
struct _capnpPrivate {
CAPNP_DECLARE_STRUCT_HEADER(95b29059097fca83, 1, 0)
#if !CAPNP_LITE
static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; }
#endif // !CAPNP_LITE
};
};
struct JoinResult {
JoinResult() = delete;
class Reader;
class Builder;
class Pipeline;
struct _capnpPrivate {
CAPNP_DECLARE_STRUCT_HEADER(9d263a3630b7ebee, 1, 1)
#if !CAPNP_LITE
static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; }
#endif // !CAPNP_LITE
};
};
// =======================================================================================
class VatId::Reader {
public:
typedef VatId Reads;
Reader() = default;
inline explicit Reader(::capnp::_::StructReader base): _reader(base) {}
inline ::capnp::MessageSize totalSize() const {
return _reader.totalSize().asPublic();
}
#if !CAPNP_LITE
inline ::kj::StringTree toString() const {
return ::capnp::_::structString(_reader, *_capnpPrivate::brand());
}
#endif // !CAPNP_LITE
inline ::capnp::rpc::twoparty::Side getSide() const;
private:
::capnp::_::StructReader _reader;
template <typename, ::capnp::Kind>
friend struct ::capnp::ToDynamic_;
template <typename, ::capnp::Kind>
friend struct ::capnp::_::PointerHelpers;
template <typename, ::capnp::Kind>
friend struct ::capnp::List;
friend class ::capnp::MessageBuilder;
friend class ::capnp::Orphanage;
};
class VatId::Builder {
public:
typedef VatId Builds;
Builder() = delete; // Deleted to discourage incorrect usage.
// You can explicitly initialize to nullptr instead.
inline Builder(decltype(nullptr)) {}
inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {}
inline operator Reader() const { return Reader(_builder.asReader()); }
inline Reader asReader() const { return *this; }
inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); }
#if !CAPNP_LITE
inline ::kj::StringTree toString() const { return asReader().toString(); }
#endif // !CAPNP_LITE
inline ::capnp::rpc::twoparty::Side getSide();
inline void setSide( ::capnp::rpc::twoparty::Side value);
private:
::capnp::_::StructBuilder _builder;
template <typename, ::capnp::Kind>
friend struct ::capnp::ToDynamic_;
friend class ::capnp::Orphanage;
template <typename, ::capnp::Kind>
friend struct ::capnp::_::PointerHelpers;
};
#if !CAPNP_LITE
class VatId::Pipeline {
public:
typedef VatId Pipelines;
inline Pipeline(decltype(nullptr)): _typeless(nullptr) {}
inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless)
: _typeless(kj::mv(typeless)) {}
private:
::capnp::AnyPointer::Pipeline _typeless;
friend class ::capnp::PipelineHook;
template <typename, ::capnp::Kind>
friend struct ::capnp::ToDynamic_;
};
#endif // !CAPNP_LITE
class ProvisionId::Reader {
public:
typedef ProvisionId Reads;
Reader() = default;
inline explicit Reader(::capnp::_::StructReader base): _reader(base) {}
inline ::capnp::MessageSize totalSize() const {
return _reader.totalSize().asPublic();
}
#if !CAPNP_LITE
inline ::kj::StringTree toString() const {
return ::capnp::_::structString(_reader, *_capnpPrivate::brand());
}
#endif // !CAPNP_LITE
inline ::uint32_t getJoinId() const;
private:
::capnp::_::StructReader _reader;
template <typename, ::capnp::Kind>
friend struct ::capnp::ToDynamic_;
template <typename, ::capnp::Kind>
friend struct ::capnp::_::PointerHelpers;
template <typename, ::capnp::Kind>
friend struct ::capnp::List;
friend class ::capnp::MessageBuilder;
friend class ::capnp::Orphanage;
};
class ProvisionId::Builder {
public:
typedef ProvisionId Builds;
Builder() = delete; // Deleted to discourage incorrect usage.
// You can explicitly initialize to nullptr instead.
inline Builder(decltype(nullptr)) {}
inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {}
inline operator Reader() const { return Reader(_builder.asReader()); }
inline Reader asReader() const { return *this; }
inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); }
#if !CAPNP_LITE
inline ::kj::StringTree toString() const { return asReader().toString(); }
#endif // !CAPNP_LITE
inline ::uint32_t getJoinId();
inline void setJoinId( ::uint32_t value);
private:
::capnp::_::StructBuilder _builder;
template <typename, ::capnp::Kind>
friend struct ::capnp::ToDynamic_;
friend class ::capnp::Orphanage;
template <typename, ::capnp::Kind>
friend struct ::capnp::_::PointerHelpers;
};
#if !CAPNP_LITE
class ProvisionId::Pipeline {
public:
typedef ProvisionId Pipelines;
inline Pipeline(decltype(nullptr)): _typeless(nullptr) {}
inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless)
: _typeless(kj::mv(typeless)) {}
private:
::capnp::AnyPointer::Pipeline _typeless;
friend class ::capnp::PipelineHook;
template <typename, ::capnp::Kind>
friend struct ::capnp::ToDynamic_;
};
#endif // !CAPNP_LITE
class RecipientId::Reader {
public:
typedef RecipientId Reads;
Reader() = default;
inline explicit Reader(::capnp::_::StructReader base): _reader(base) {}
inline ::capnp::MessageSize totalSize() const {
return _reader.totalSize().asPublic();
}
#if !CAPNP_LITE
inline ::kj::StringTree toString() const {
return ::capnp::_::structString(_reader, *_capnpPrivate::brand());
}
#endif // !CAPNP_LITE
private:
::capnp::_::StructReader _reader;
template <typename, ::capnp::Kind>
friend struct ::capnp::ToDynamic_;
template <typename, ::capnp::Kind>
friend struct ::capnp::_::PointerHelpers;
template <typename, ::capnp::Kind>
friend struct ::capnp::List;
friend class ::capnp::MessageBuilder;
friend class ::capnp::Orphanage;
};
class RecipientId::Builder {
public:
typedef RecipientId Builds;
Builder() = delete; // Deleted to discourage incorrect usage.
// You can explicitly initialize to nullptr instead.
inline Builder(decltype(nullptr)) {}
inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {}
inline operator Reader() const { return Reader(_builder.asReader()); }
inline Reader asReader() const { return *this; }
inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); }
#if !CAPNP_LITE
inline ::kj::StringTree toString() const { return asReader().toString(); }
#endif // !CAPNP_LITE
private:
::capnp::_::StructBuilder _builder;
template <typename, ::capnp::Kind>
friend struct ::capnp::ToDynamic_;
friend class ::capnp::Orphanage;
template <typename, ::capnp::Kind>
friend struct ::capnp::_::PointerHelpers;
};
#if !CAPNP_LITE
class RecipientId::Pipeline {
public:
typedef RecipientId Pipelines;
inline Pipeline(decltype(nullptr)): _typeless(nullptr) {}
inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless)
: _typeless(kj::mv(typeless)) {}
private:
::capnp::AnyPointer::Pipeline _typeless;
friend class ::capnp::PipelineHook;
template <typename, ::capnp::Kind>
friend struct ::capnp::ToDynamic_;
};
#endif // !CAPNP_LITE
class ThirdPartyCapId::Reader {
public:
typedef ThirdPartyCapId Reads;
Reader() = default;
inline explicit Reader(::capnp::_::StructReader base): _reader(base) {}
inline ::capnp::MessageSize totalSize() const {
return _reader.totalSize().asPublic();
}
#if !CAPNP_LITE
inline ::kj::StringTree toString() const {
return ::capnp::_::structString(_reader, *_capnpPrivate::brand());
}
#endif // !CAPNP_LITE
private:
::capnp::_::StructReader _reader;
template <typename, ::capnp::Kind>
friend struct ::capnp::ToDynamic_;
template <typename, ::capnp::Kind>
friend struct ::capnp::_::PointerHelpers;
template <typename, ::capnp::Kind>
friend struct ::capnp::List;
friend class ::capnp::MessageBuilder;
friend class ::capnp::Orphanage;
};
class ThirdPartyCapId::Builder {
public:
typedef ThirdPartyCapId Builds;
Builder() = delete; // Deleted to discourage incorrect usage.
// You can explicitly initialize to nullptr instead.
inline Builder(decltype(nullptr)) {}
inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {}
inline operator Reader() const { return Reader(_builder.asReader()); }
inline Reader asReader() const { return *this; }
inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); }
#if !CAPNP_LITE
inline ::kj::StringTree toString() const { return asReader().toString(); }
#endif // !CAPNP_LITE
private:
::capnp::_::StructBuilder _builder;
template <typename, ::capnp::Kind>
friend struct ::capnp::ToDynamic_;
friend class ::capnp::Orphanage;
template <typename, ::capnp::Kind>
friend struct ::capnp::_::PointerHelpers;
};
#if !CAPNP_LITE
class ThirdPartyCapId::Pipeline {
public:
typedef ThirdPartyCapId Pipelines;
inline Pipeline(decltype(nullptr)): _typeless(nullptr) {}
inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless)
: _typeless(kj::mv(typeless)) {}
private:
::capnp::AnyPointer::Pipeline _typeless;
friend class ::capnp::PipelineHook;
template <typename, ::capnp::Kind>
friend struct ::capnp::ToDynamic_;
};
#endif // !CAPNP_LITE
class JoinKeyPart::Reader {
public:
typedef JoinKeyPart Reads;
Reader() = default;
inline explicit Reader(::capnp::_::StructReader base): _reader(base) {}
inline ::capnp::MessageSize totalSize() const {
return _reader.totalSize().asPublic();
}
#if !CAPNP_LITE
inline ::kj::StringTree toString() const {
return ::capnp::_::structString(_reader, *_capnpPrivate::brand());
}
#endif // !CAPNP_LITE
inline ::uint32_t getJoinId() const;
inline ::uint16_t getPartCount() const;
inline ::uint16_t getPartNum() const;
private:
::capnp::_::StructReader _reader;
template <typename, ::capnp::Kind>
friend struct ::capnp::ToDynamic_;
template <typename, ::capnp::Kind>
friend struct ::capnp::_::PointerHelpers;
template <typename, ::capnp::Kind>
friend struct ::capnp::List;
friend class ::capnp::MessageBuilder;
friend class ::capnp::Orphanage;
};
class JoinKeyPart::Builder {
public:
typedef JoinKeyPart Builds;
Builder() = delete; // Deleted to discourage incorrect usage.
// You can explicitly initialize to nullptr instead.
inline Builder(decltype(nullptr)) {}
inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {}
inline operator Reader() const { return Reader(_builder.asReader()); }
inline Reader asReader() const { return *this; }
inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); }
#if !CAPNP_LITE
inline ::kj::StringTree toString() const { return asReader().toString(); }
#endif // !CAPNP_LITE
inline ::uint32_t getJoinId();
inline void setJoinId( ::uint32_t value);
inline ::uint16_t getPartCount();
inline void setPartCount( ::uint16_t value);
inline ::uint16_t getPartNum();
inline void setPartNum( ::uint16_t value);
private:
::capnp::_::StructBuilder _builder;
template <typename, ::capnp::Kind>
friend struct ::capnp::ToDynamic_;
friend class ::capnp::Orphanage;
template <typename, ::capnp::Kind>
friend struct ::capnp::_::PointerHelpers;
};
#if !CAPNP_LITE
class JoinKeyPart::Pipeline {
public:
typedef JoinKeyPart Pipelines;
inline Pipeline(decltype(nullptr)): _typeless(nullptr) {}
inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless)
: _typeless(kj::mv(typeless)) {}
private:
::capnp::AnyPointer::Pipeline _typeless;
friend class ::capnp::PipelineHook;
template <typename, ::capnp::Kind>
friend struct ::capnp::ToDynamic_;
};
#endif // !CAPNP_LITE
class JoinResult::Reader {
public:
typedef JoinResult Reads;
Reader() = default;
inline explicit Reader(::capnp::_::StructReader base): _reader(base) {}
inline ::capnp::MessageSize totalSize() const {
return _reader.totalSize().asPublic();
}
#if !CAPNP_LITE
inline ::kj::StringTree toString() const {
return ::capnp::_::structString(_reader, *_capnpPrivate::brand());
}
#endif // !CAPNP_LITE
inline ::uint32_t getJoinId() const;
inline bool getSucceeded() const;
inline bool hasCap() const;
inline ::capnp::AnyPointer::Reader getCap() const;
private:
::capnp::_::StructReader _reader;
template <typename, ::capnp::Kind>
friend struct ::capnp::ToDynamic_;
template <typename, ::capnp::Kind>
friend struct ::capnp::_::PointerHelpers;
template <typename, ::capnp::Kind>
friend struct ::capnp::List;
friend class ::capnp::MessageBuilder;
friend class ::capnp::Orphanage;
};
class JoinResult::Builder {
public:
typedef JoinResult Builds;
Builder() = delete; // Deleted to discourage incorrect usage.
// You can explicitly initialize to nullptr instead.
inline Builder(decltype(nullptr)) {}
inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {}
inline operator Reader() const { return Reader(_builder.asReader()); }
inline Reader asReader() const { return *this; }
inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); }
#if !CAPNP_LITE
inline ::kj::StringTree toString() const { return asReader().toString(); }
#endif // !CAPNP_LITE
inline ::uint32_t getJoinId();
inline void setJoinId( ::uint32_t value);
inline bool getSucceeded();
inline void setSucceeded(bool value);
inline bool hasCap();
inline ::capnp::AnyPointer::Builder getCap();
inline ::capnp::AnyPointer::Builder initCap();
private:
::capnp::_::StructBuilder _builder;
template <typename, ::capnp::Kind>
friend struct ::capnp::ToDynamic_;
friend class ::capnp::Orphanage;
template <typename, ::capnp::Kind>
friend struct ::capnp::_::PointerHelpers;
};
#if !CAPNP_LITE
class JoinResult::Pipeline {
public:
typedef JoinResult Pipelines;
inline Pipeline(decltype(nullptr)): _typeless(nullptr) {}
inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless)
: _typeless(kj::mv(typeless)) {}
private:
::capnp::AnyPointer::Pipeline _typeless;
friend class ::capnp::PipelineHook;
template <typename, ::capnp::Kind>
friend struct ::capnp::ToDynamic_;
};
#endif // !CAPNP_LITE
// =======================================================================================
inline ::capnp::rpc::twoparty::Side VatId::Reader::getSide() const {
return _reader.getDataField< ::capnp::rpc::twoparty::Side>(
::capnp::bounded<0>() * ::capnp::ELEMENTS);
}
inline ::capnp::rpc::twoparty::Side VatId::Builder::getSide() {
return _builder.getDataField< ::capnp::rpc::twoparty::Side>(
::capnp::bounded<0>() * ::capnp::ELEMENTS);
}
inline void VatId::Builder::setSide( ::capnp::rpc::twoparty::Side value) {
_builder.setDataField< ::capnp::rpc::twoparty::Side>(
::capnp::bounded<0>() * ::capnp::ELEMENTS, value);
}
inline ::uint32_t ProvisionId::Reader::getJoinId() const {
return _reader.getDataField< ::uint32_t>(
::capnp::bounded<0>() * ::capnp::ELEMENTS);
}
inline ::uint32_t ProvisionId::Builder::getJoinId() {
return _builder.getDataField< ::uint32_t>(
::capnp::bounded<0>() * ::capnp::ELEMENTS);
}
inline void ProvisionId::Builder::setJoinId( ::uint32_t value) {
_builder.setDataField< ::uint32_t>(
::capnp::bounded<0>() * ::capnp::ELEMENTS, value);
}
inline ::uint32_t JoinKeyPart::Reader::getJoinId() const {
return _reader.getDataField< ::uint32_t>(
::capnp::bounded<0>() * ::capnp::ELEMENTS);
}
inline ::uint32_t JoinKeyPart::Builder::getJoinId() {
return _builder.getDataField< ::uint32_t>(
::capnp::bounded<0>() * ::capnp::ELEMENTS);
}
inline void JoinKeyPart::Builder::setJoinId( ::uint32_t value) {
_builder.setDataField< ::uint32_t>(
::capnp::bounded<0>() * ::capnp::ELEMENTS, value);
}
inline ::uint16_t JoinKeyPart::Reader::getPartCount() const {
return _reader.getDataField< ::uint16_t>(
::capnp::bounded<2>() * ::capnp::ELEMENTS);
}
inline ::uint16_t JoinKeyPart::Builder::getPartCount() {
return _builder.getDataField< ::uint16_t>(
::capnp::bounded<2>() * ::capnp::ELEMENTS);
}
inline void JoinKeyPart::Builder::setPartCount( ::uint16_t value) {
_builder.setDataField< ::uint16_t>(
::capnp::bounded<2>() * ::capnp::ELEMENTS, value);
}
inline ::uint16_t JoinKeyPart::Reader::getPartNum() const {
return _reader.getDataField< ::uint16_t>(
::capnp::bounded<3>() * ::capnp::ELEMENTS);
}
inline ::uint16_t JoinKeyPart::Builder::getPartNum() {
return _builder.getDataField< ::uint16_t>(
::capnp::bounded<3>() * ::capnp::ELEMENTS);
}
inline void JoinKeyPart::Builder::setPartNum( ::uint16_t value) {
_builder.setDataField< ::uint16_t>(
::capnp::bounded<3>() * ::capnp::ELEMENTS, value);
}
inline ::uint32_t JoinResult::Reader::getJoinId() const {
return _reader.getDataField< ::uint32_t>(
::capnp::bounded<0>() * ::capnp::ELEMENTS);
}
inline ::uint32_t JoinResult::Builder::getJoinId() {
return _builder.getDataField< ::uint32_t>(
::capnp::bounded<0>() * ::capnp::ELEMENTS);
}
inline void JoinResult::Builder::setJoinId( ::uint32_t value) {
_builder.setDataField< ::uint32_t>(
::capnp::bounded<0>() * ::capnp::ELEMENTS, value);
}
inline bool JoinResult::Reader::getSucceeded() const {
return _reader.getDataField<bool>(
::capnp::bounded<32>() * ::capnp::ELEMENTS);
}
inline bool JoinResult::Builder::getSucceeded() {
return _builder.getDataField<bool>(
::capnp::bounded<32>() * ::capnp::ELEMENTS);
}
inline void JoinResult::Builder::setSucceeded(bool value) {
_builder.setDataField<bool>(
::capnp::bounded<32>() * ::capnp::ELEMENTS, value);
}
inline bool JoinResult::Reader::hasCap() const {
return !_reader.getPointerField(
::capnp::bounded<0>() * ::capnp::POINTERS).isNull();
}
inline bool JoinResult::Builder::hasCap() {
return !_builder.getPointerField(
::capnp::bounded<0>() * ::capnp::POINTERS).isNull();
}
inline ::capnp::AnyPointer::Reader JoinResult::Reader::getCap() const {
return ::capnp::AnyPointer::Reader(_reader.getPointerField(
::capnp::bounded<0>() * ::capnp::POINTERS));
}
inline ::capnp::AnyPointer::Builder JoinResult::Builder::getCap() {
return ::capnp::AnyPointer::Builder(_builder.getPointerField(
::capnp::bounded<0>() * ::capnp::POINTERS));
}
inline ::capnp::AnyPointer::Builder JoinResult::Builder::initCap() {
auto result = ::capnp::AnyPointer::Builder(_builder.getPointerField(
::capnp::bounded<0>() * ::capnp::POINTERS));
result.clear();
return result;
}
} // namespace
} // namespace
} // namespace
#endif // CAPNP_INCLUDED_a184c7885cdaf2a1_

View File

@ -1,160 +0,0 @@
// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#ifndef CAPNP_RPC_TWOPARTY_H_
#define CAPNP_RPC_TWOPARTY_H_
#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS)
#pragma GCC system_header
#endif
#include "rpc.h"
#include "message.h"
#include <kj/async-io.h>
#include <capnp/rpc-twoparty.capnp.h>
namespace capnp {
namespace rpc {
namespace twoparty {
typedef VatId SturdyRefHostId; // For backwards-compatibility with version 0.4.
}
}
typedef VatNetwork<rpc::twoparty::VatId, rpc::twoparty::ProvisionId,
rpc::twoparty::RecipientId, rpc::twoparty::ThirdPartyCapId, rpc::twoparty::JoinResult>
TwoPartyVatNetworkBase;
class TwoPartyVatNetwork: public TwoPartyVatNetworkBase,
private TwoPartyVatNetworkBase::Connection {
// A `VatNetwork` that consists of exactly two parties communicating over an arbitrary byte
// stream. This is used to implement the common case of a client/server network.
//
// See `ez-rpc.h` for a simple interface for setting up two-party clients and servers.
// Use `TwoPartyVatNetwork` only if you need the advanced features.
public:
TwoPartyVatNetwork(kj::AsyncIoStream& stream, rpc::twoparty::Side side,
ReaderOptions receiveOptions = ReaderOptions());
KJ_DISALLOW_COPY(TwoPartyVatNetwork);
kj::Promise<void> onDisconnect() { return disconnectPromise.addBranch(); }
// Returns a promise that resolves when the peer disconnects.
rpc::twoparty::Side getSide() { return side; }
// implements VatNetwork -----------------------------------------------------
kj::Maybe<kj::Own<TwoPartyVatNetworkBase::Connection>> connect(
rpc::twoparty::VatId::Reader ref) override;
kj::Promise<kj::Own<TwoPartyVatNetworkBase::Connection>> accept() override;
private:
class OutgoingMessageImpl;
class IncomingMessageImpl;
kj::AsyncIoStream& stream;
rpc::twoparty::Side side;
MallocMessageBuilder peerVatId;
ReaderOptions receiveOptions;
bool accepted = false;
kj::Maybe<kj::Promise<void>> previousWrite;
// Resolves when the previous write completes. This effectively serves as the write queue.
// Becomes null when shutdown() is called.
kj::Own<kj::PromiseFulfiller<kj::Own<TwoPartyVatNetworkBase::Connection>>> acceptFulfiller;
// Fulfiller for the promise returned by acceptConnectionAsRefHost() on the client side, or the
// second call on the server side. Never fulfilled, because there is only one connection.
kj::ForkedPromise<void> disconnectPromise = nullptr;
class FulfillerDisposer: public kj::Disposer {
// Hack: TwoPartyVatNetwork is both a VatNetwork and a VatNetwork::Connection. When the RPC
// system detects (or initiates) a disconnection, it drops its reference to the Connection.
// When all references have been dropped, then we want disconnectPromise to be fulfilled.
// So we hand out Own<Connection>s with this disposer attached, so that we can detect when
// they are dropped.
public:
mutable kj::Own<kj::PromiseFulfiller<void>> fulfiller;
mutable uint refcount = 0;
void disposeImpl(void* pointer) const override;
};
FulfillerDisposer disconnectFulfiller;
kj::Own<TwoPartyVatNetworkBase::Connection> asConnection();
// Returns a pointer to this with the disposer set to disconnectFulfiller.
// implements Connection -----------------------------------------------------
rpc::twoparty::VatId::Reader getPeerVatId() override;
kj::Own<OutgoingRpcMessage> newOutgoingMessage(uint firstSegmentWordSize) override;
kj::Promise<kj::Maybe<kj::Own<IncomingRpcMessage>>> receiveIncomingMessage() override;
kj::Promise<void> shutdown() override;
};
class TwoPartyServer: private kj::TaskSet::ErrorHandler {
// Convenience class which implements a simple server which accepts connections on a listener
// socket and serices them as two-party connections.
public:
explicit TwoPartyServer(Capability::Client bootstrapInterface);
void accept(kj::Own<kj::AsyncIoStream>&& connection);
// Accepts the connection for servicing.
kj::Promise<void> listen(kj::ConnectionReceiver& listener);
// Listens for connections on the given listener. The returned promise never resolves unless an
// exception is thrown while trying to accept. You may discard the returned promise to cancel
// listening.
private:
Capability::Client bootstrapInterface;
kj::TaskSet tasks;
struct AcceptedConnection;
void taskFailed(kj::Exception&& exception) override;
};
class TwoPartyClient {
// Convenience class which implements a simple client.
public:
explicit TwoPartyClient(kj::AsyncIoStream& connection);
TwoPartyClient(kj::AsyncIoStream& connection, Capability::Client bootstrapInterface,
rpc::twoparty::Side side = rpc::twoparty::Side::CLIENT);
Capability::Client bootstrap();
// Get the server's bootstrap interface.
inline kj::Promise<void> onDisconnect() { return network.onDisconnect(); }
private:
TwoPartyVatNetwork network;
RpcSystem<rpc::twoparty::VatId> rpcSystem;
};
} // namespace capnp
#endif // CAPNP_RPC_TWOPARTY_H_

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,537 +0,0 @@
// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#ifndef CAPNP_RPC_H_
#define CAPNP_RPC_H_
#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS)
#pragma GCC system_header
#endif
#include "capability.h"
#include "rpc-prelude.h"
namespace capnp {
template <typename VatId, typename ProvisionId, typename RecipientId,
typename ThirdPartyCapId, typename JoinResult>
class VatNetwork;
template <typename SturdyRefObjectId>
class SturdyRefRestorer;
template <typename VatId>
class BootstrapFactory: public _::BootstrapFactoryBase {
// Interface that constructs per-client bootstrap interfaces. Use this if you want each client
// who connects to see a different bootstrap interface based on their (authenticated) VatId.
// This allows an application to bootstrap off of the authentication performed at the VatNetwork
// level. (Typically VatId is some sort of public key.)
//
// This is only useful for multi-party networks. For TwoPartyVatNetwork, there's no reason to
// use a BootstrapFactory; just specify a single bootstrap capability in this case.
public:
virtual Capability::Client createFor(typename VatId::Reader clientId) = 0;
// Create a bootstrap capability appropriate for exposing to the given client. VatNetwork will
// have authenticated the client VatId before this is called.
private:
Capability::Client baseCreateFor(AnyStruct::Reader clientId) override;
};
template <typename VatId>
class RpcSystem: public _::RpcSystemBase {
// Represents the RPC system, which is the portal to objects available on the network.
//
// The RPC implementation sits on top of an implementation of `VatNetwork`. The `VatNetwork`
// determines how to form connections between vats -- specifically, two-way, private, reliable,
// sequenced datagram connections. The RPC implementation determines how to use such connections
// to manage object references and make method calls.
//
// See `makeRpcServer()` and `makeRpcClient()` below for convenient syntax for setting up an
// `RpcSystem` given a `VatNetwork`.
//
// See `ez-rpc.h` for an even simpler interface for setting up RPC in a typical two-party
// client/server scenario.
public:
template <typename ProvisionId, typename RecipientId,
typename ThirdPartyCapId, typename JoinResult>
RpcSystem(
VatNetwork<VatId, ProvisionId, RecipientId, ThirdPartyCapId, JoinResult>& network,
kj::Maybe<Capability::Client> bootstrapInterface,
kj::Maybe<RealmGateway<>::Client> gateway = nullptr);
template <typename ProvisionId, typename RecipientId,
typename ThirdPartyCapId, typename JoinResult>
RpcSystem(
VatNetwork<VatId, ProvisionId, RecipientId, ThirdPartyCapId, JoinResult>& network,
BootstrapFactory<VatId>& bootstrapFactory,
kj::Maybe<RealmGateway<>::Client> gateway = nullptr);
template <typename ProvisionId, typename RecipientId,
typename ThirdPartyCapId, typename JoinResult,
typename LocalSturdyRefObjectId>
RpcSystem(
VatNetwork<VatId, ProvisionId, RecipientId, ThirdPartyCapId, JoinResult>& network,
SturdyRefRestorer<LocalSturdyRefObjectId>& restorer);
RpcSystem(RpcSystem&& other) = default;
Capability::Client bootstrap(typename VatId::Reader vatId);
// Connect to the given vat and return its bootstrap interface.
Capability::Client restore(typename VatId::Reader hostId, AnyPointer::Reader objectId)
KJ_DEPRECATED("Please transition to using a bootstrap interface instead.");
// ** DEPRECATED **
//
// Restores the given SturdyRef from the network and return the capability representing it.
//
// `hostId` identifies the host from which to request the ref, in the format specified by the
// `VatNetwork` in use. `objectId` is the object ID in whatever format is expected by said host.
//
// This method will be removed in a future version of Cap'n Proto. Instead, please transition
// to using bootstrap(), which is equivalent to calling restore() with a null `objectId`.
// You may emulate the old concept of object IDs by exporting a bootstrap interface which has
// methods that can be used to obtain other capabilities by ID.
void setFlowLimit(size_t words);
// Sets the incoming call flow limit. If more than `words` worth of call messages have not yet
// received responses, the RpcSystem will not read further messages from the stream. This can be
// used as a crude way to prevent a resource exhaustion attack (or bug) in which a peer makes an
// excessive number of simultaneous calls that consume the receiver's RAM.
//
// There are some caveats. When over the flow limit, all messages are blocked, including returns.
// If the outstanding calls are themselves waiting on calls going in the opposite direction, the
// flow limit may prevent those calls from completing, leading to deadlock. However, a
// sufficiently high limit should make this unlikely.
//
// Note that a call's parameter size counts against the flow limit until the call returns, even
// if the recipient calls releaseParams() to free the parameter memory early. This is because
// releaseParams() may simply indicate that the parameters have been forwarded to another
// machine, but are still in-memory there. For illustration, say that Alice made a call to Bob
// who forwarded the call to Carol. Bob has imposed a flow limit on Alice. Alice's calls are
// being forwarded to Carol, so Bob never keeps the parameters in-memory for more than a brief
// period. However, the flow limit counts all calls that haven't returned, even if Bob has
// already freed the memory they consumed. You might argue that the right solution here is
// instead for Carol to impose her own flow limit on Bob. This has a serious problem, though:
// Bob might be forwarding requests to Carol on behalf of many different parties, not just Alice.
// If Alice can pump enough data to hit the Bob -> Carol flow limit, then those other parties
// will be disrupted. Thus, we can only really impose the limit on the Alice -> Bob link, which
// only affects Alice. We need that one flow limit to limit Alice's impact on the whole system,
// so it has to count all in-flight calls.
//
// In Sandstorm, flow limits are imposed by the supervisor on calls coming out of a grain, in
// order to prevent a grain from inundating the system with in-flight calls. In practice, the
// main time this happens is when a grain is pushing a large file download and doesn't implement
// proper cooperative flow control.
};
template <typename VatId, typename ProvisionId, typename RecipientId,
typename ThirdPartyCapId, typename JoinResult>
RpcSystem<VatId> makeRpcServer(
VatNetwork<VatId, ProvisionId, RecipientId, ThirdPartyCapId, JoinResult>& network,
Capability::Client bootstrapInterface);
// Make an RPC server. Typical usage (e.g. in a main() function):
//
// MyEventLoop eventLoop;
// kj::WaitScope waitScope(eventLoop);
// MyNetwork network;
// MyMainInterface::Client bootstrap = makeMain();
// auto server = makeRpcServer(network, bootstrap);
// kj::NEVER_DONE.wait(waitScope); // run forever
//
// See also ez-rpc.h, which has simpler instructions for the common case of a two-party
// client-server RPC connection.
template <typename VatId, typename ProvisionId, typename RecipientId,
typename ThirdPartyCapId, typename JoinResult, typename RealmGatewayClient,
typename InternalRef = _::InternalRefFromRealmGatewayClient<RealmGatewayClient>,
typename ExternalRef = _::ExternalRefFromRealmGatewayClient<RealmGatewayClient>>
RpcSystem<VatId> makeRpcServer(
VatNetwork<VatId, ProvisionId, RecipientId, ThirdPartyCapId, JoinResult>& network,
Capability::Client bootstrapInterface, RealmGatewayClient gateway);
// Make an RPC server for a VatNetwork that resides in a different realm from the application.
// The given RealmGateway is used to translate SturdyRefs between the app's ("internal") format
// and the network's ("external") format.
template <typename VatId, typename ProvisionId, typename RecipientId,
typename ThirdPartyCapId, typename JoinResult>
RpcSystem<VatId> makeRpcServer(
VatNetwork<VatId, ProvisionId, RecipientId, ThirdPartyCapId, JoinResult>& network,
BootstrapFactory<VatId>& bootstrapFactory);
// Make an RPC server that can serve different bootstrap interfaces to different clients via a
// BootstrapInterface.
template <typename VatId, typename ProvisionId, typename RecipientId,
typename ThirdPartyCapId, typename JoinResult, typename RealmGatewayClient,
typename InternalRef = _::InternalRefFromRealmGatewayClient<RealmGatewayClient>,
typename ExternalRef = _::ExternalRefFromRealmGatewayClient<RealmGatewayClient>>
RpcSystem<VatId> makeRpcServer(
VatNetwork<VatId, ProvisionId, RecipientId, ThirdPartyCapId, JoinResult>& network,
BootstrapFactory<VatId>& bootstrapFactory, RealmGatewayClient gateway);
// Make an RPC server that can serve different bootstrap interfaces to different clients via a
// BootstrapInterface and communicates with a different realm than the application is in via a
// RealmGateway.
template <typename VatId, typename LocalSturdyRefObjectId,
typename ProvisionId, typename RecipientId, typename ThirdPartyCapId, typename JoinResult>
RpcSystem<VatId> makeRpcServer(
VatNetwork<VatId, ProvisionId, RecipientId, ThirdPartyCapId, JoinResult>& network,
SturdyRefRestorer<LocalSturdyRefObjectId>& restorer)
KJ_DEPRECATED("Please transition to using a bootstrap interface instead.");
// ** DEPRECATED **
//
// Create an RPC server which exports multiple main interfaces by object ID. The `restorer` object
// can be used to look up objects by ID.
//
// Please transition to exporting only one interface, which is known as the "bootstrap" interface.
// For backwards-compatibility with old clients, continue to implement SturdyRefRestorer, but
// return the new bootstrap interface when the request object ID is null. When new clients connect
// and request the bootstrap interface, they will get that interface. Eventually, once all clients
// are updated to request only the bootstrap interface, stop implementing SturdyRefRestorer and
// switch to passing the bootstrap capability itself as the second parameter to `makeRpcServer()`.
template <typename VatId, typename ProvisionId,
typename RecipientId, typename ThirdPartyCapId, typename JoinResult>
RpcSystem<VatId> makeRpcClient(
VatNetwork<VatId, ProvisionId, RecipientId, ThirdPartyCapId, JoinResult>& network);
// Make an RPC client. Typical usage (e.g. in a main() function):
//
// MyEventLoop eventLoop;
// kj::WaitScope waitScope(eventLoop);
// MyNetwork network;
// auto client = makeRpcClient(network);
// MyCapability::Client cap = client.restore(hostId, objId).castAs<MyCapability>();
// auto response = cap.fooRequest().send().wait(waitScope);
// handleMyResponse(response);
//
// See also ez-rpc.h, which has simpler instructions for the common case of a two-party
// client-server RPC connection.
template <typename VatId, typename ProvisionId, typename RecipientId,
typename ThirdPartyCapId, typename JoinResult, typename RealmGatewayClient,
typename InternalRef = _::InternalRefFromRealmGatewayClient<RealmGatewayClient>,
typename ExternalRef = _::ExternalRefFromRealmGatewayClient<RealmGatewayClient>>
RpcSystem<VatId> makeRpcClient(
VatNetwork<VatId, ProvisionId, RecipientId, ThirdPartyCapId, JoinResult>& network,
RealmGatewayClient gateway);
// Make an RPC client for a VatNetwork that resides in a different realm from the application.
// The given RealmGateway is used to translate SturdyRefs between the app's ("internal") format
// and the network's ("external") format.
template <typename SturdyRefObjectId>
class SturdyRefRestorer: public _::SturdyRefRestorerBase {
// ** DEPRECATED **
//
// In Cap'n Proto 0.4.x, applications could export multiple main interfaces identified by
// object IDs. The callback used to map object IDs to objects was `SturdyRefRestorer`, as we
// imagined this would eventually be used for restoring SturdyRefs as well. In practice, it was
// never used for real SturdyRefs, only for exporting singleton objects under well-known names.
//
// The new preferred strategy is to export only a _single_ such interface, called the
// "bootstrap interface". That interface can itself have methods for obtaining other objects, of
// course, but that is up to the app. `SturdyRefRestorer` exists for backwards-compatibility.
//
// Hint: Use SturdyRefRestorer<capnp::Text> to define a server that exports services under
// string names.
public:
virtual Capability::Client restore(typename SturdyRefObjectId::Reader ref)
KJ_DEPRECATED(
"Please transition to using bootstrap interfaces instead of SturdyRefRestorer.") = 0;
// Restore the given object, returning a capability representing it.
private:
Capability::Client baseRestore(AnyPointer::Reader ref) override final;
};
// =======================================================================================
// VatNetwork
class OutgoingRpcMessage {
// A message to be sent by a `VatNetwork`.
public:
virtual AnyPointer::Builder getBody() = 0;
// Get the message body, which the caller may fill in any way it wants. (The standard RPC
// implementation initializes it as a Message as defined in rpc.capnp.)
virtual void send() = 0;
// Send the message, or at least put it in a queue to be sent later. Note that the builder
// returned by `getBody()` remains valid at least until the `OutgoingRpcMessage` is destroyed.
};
class IncomingRpcMessage {
// A message received from a `VatNetwork`.
public:
virtual AnyPointer::Reader getBody() = 0;
// Get the message body, to be interpreted by the caller. (The standard RPC implementation
// interprets it as a Message as defined in rpc.capnp.)
};
template <typename VatId, typename ProvisionId, typename RecipientId,
typename ThirdPartyCapId, typename JoinResult>
class VatNetwork: public _::VatNetworkBase {
// Cap'n Proto RPC operates between vats, where a "vat" is some sort of host of objects.
// Typically one Cap'n Proto process (in the Unix sense) is one vat. The RPC system is what
// allows calls between objects hosted in different vats.
//
// The RPC implementation sits on top of an implementation of `VatNetwork`. The `VatNetwork`
// determines how to form connections between vats -- specifically, two-way, private, reliable,
// sequenced datagram connections. The RPC implementation determines how to use such connections
// to manage object references and make method calls.
//
// The most common implementation of VatNetwork is TwoPartyVatNetwork (rpc-twoparty.h). Most
// simple client-server apps will want to use it. (You may even want to use the EZ RPC
// interfaces in `ez-rpc.h` and avoid all of this.)
//
// TODO(someday): Provide a standard implementation for the public internet.
public:
class Connection;
struct ConnectionAndProvisionId {
// Result of connecting to a vat introduced by another vat.
kj::Own<Connection> connection;
// Connection to the new vat.
kj::Own<OutgoingRpcMessage> firstMessage;
// An already-allocated `OutgoingRpcMessage` associated with `connection`. The RPC system will
// construct this as an `Accept` message and send it.
Orphan<ProvisionId> provisionId;
// A `ProvisionId` already allocated inside `firstMessage`, which the RPC system will use to
// build the `Accept` message.
};
class Connection: public _::VatNetworkBase::Connection {
// A two-way RPC connection.
//
// This object may represent a connection that doesn't exist yet, but is expected to exist
// in the future. In this case, sent messages will automatically be queued and sent once the
// connection is ready, so that the caller doesn't need to know the difference.
public:
// Level 0 features ----------------------------------------------
virtual typename VatId::Reader getPeerVatId() = 0;
// Returns the connected vat's authenticated VatId. It is the VatNetwork's responsibility to
// authenticate this, so that the caller can be assured that they are really talking to the
// identified vat and not an imposter.
virtual kj::Own<OutgoingRpcMessage> newOutgoingMessage(uint firstSegmentWordSize) override = 0;
// Allocate a new message to be sent on this connection.
//
// If `firstSegmentWordSize` is non-zero, it should be treated as a hint suggesting how large
// to make the first segment. This is entirely a hint and the connection may adjust it up or
// down. If it is zero, the connection should choose the size itself.
virtual kj::Promise<kj::Maybe<kj::Own<IncomingRpcMessage>>> receiveIncomingMessage() override = 0;
// Wait for a message to be received and return it. If the read stream cleanly terminates,
// return null. If any other problem occurs, throw an exception.
virtual kj::Promise<void> shutdown() override KJ_WARN_UNUSED_RESULT = 0;
// Waits until all outgoing messages have been sent, then shuts down the outgoing stream. The
// returned promise resolves after shutdown is complete.
private:
AnyStruct::Reader baseGetPeerVatId() override;
};
// Level 0 features ------------------------------------------------
virtual kj::Maybe<kj::Own<Connection>> connect(typename VatId::Reader hostId) = 0;
// Connect to a VatId. Note that this method immediately returns a `Connection`, even
// if the network connection has not yet been established. Messages can be queued to this
// connection and will be delivered once it is open. The caller must attempt to read from the
// connection to verify that it actually succeeded; the read will fail if the connection
// couldn't be opened. Some network implementations may actually start sending messages before
// hearing back from the server at all, to avoid a round trip.
//
// Returns nullptr if `hostId` refers to the local host.
virtual kj::Promise<kj::Own<Connection>> accept() = 0;
// Wait for the next incoming connection and return it.
// Level 4 features ------------------------------------------------
// TODO(someday)
private:
kj::Maybe<kj::Own<_::VatNetworkBase::Connection>>
baseConnect(AnyStruct::Reader hostId) override final;
kj::Promise<kj::Own<_::VatNetworkBase::Connection>> baseAccept() override final;
};
// =======================================================================================
// ***************************************************************************************
// Inline implementation details start here
// ***************************************************************************************
// =======================================================================================
template <typename VatId>
Capability::Client BootstrapFactory<VatId>::baseCreateFor(AnyStruct::Reader clientId) {
return createFor(clientId.as<VatId>());
}
template <typename SturdyRef, typename ProvisionId, typename RecipientId,
typename ThirdPartyCapId, typename JoinResult>
kj::Maybe<kj::Own<_::VatNetworkBase::Connection>>
VatNetwork<SturdyRef, ProvisionId, RecipientId, ThirdPartyCapId, JoinResult>::
baseConnect(AnyStruct::Reader ref) {
auto maybe = connect(ref.as<SturdyRef>());
return maybe.map([](kj::Own<Connection>& conn) -> kj::Own<_::VatNetworkBase::Connection> {
return kj::mv(conn);
});
}
template <typename SturdyRef, typename ProvisionId, typename RecipientId,
typename ThirdPartyCapId, typename JoinResult>
kj::Promise<kj::Own<_::VatNetworkBase::Connection>>
VatNetwork<SturdyRef, ProvisionId, RecipientId, ThirdPartyCapId, JoinResult>::baseAccept() {
return accept().then(
[](kj::Own<Connection>&& connection) -> kj::Own<_::VatNetworkBase::Connection> {
return kj::mv(connection);
});
}
template <typename SturdyRef, typename ProvisionId, typename RecipientId,
typename ThirdPartyCapId, typename JoinResult>
AnyStruct::Reader VatNetwork<
SturdyRef, ProvisionId, RecipientId, ThirdPartyCapId, JoinResult>::
Connection::baseGetPeerVatId() {
return getPeerVatId();
}
template <typename SturdyRef>
Capability::Client SturdyRefRestorer<SturdyRef>::baseRestore(AnyPointer::Reader ref) {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
return restore(ref.getAs<SturdyRef>());
#pragma GCC diagnostic pop
}
template <typename VatId>
template <typename ProvisionId, typename RecipientId,
typename ThirdPartyCapId, typename JoinResult>
RpcSystem<VatId>::RpcSystem(
VatNetwork<VatId, ProvisionId, RecipientId, ThirdPartyCapId, JoinResult>& network,
kj::Maybe<Capability::Client> bootstrap,
kj::Maybe<RealmGateway<>::Client> gateway)
: _::RpcSystemBase(network, kj::mv(bootstrap), kj::mv(gateway)) {}
template <typename VatId>
template <typename ProvisionId, typename RecipientId,
typename ThirdPartyCapId, typename JoinResult>
RpcSystem<VatId>::RpcSystem(
VatNetwork<VatId, ProvisionId, RecipientId, ThirdPartyCapId, JoinResult>& network,
BootstrapFactory<VatId>& bootstrapFactory,
kj::Maybe<RealmGateway<>::Client> gateway)
: _::RpcSystemBase(network, bootstrapFactory, kj::mv(gateway)) {}
template <typename VatId>
template <typename ProvisionId, typename RecipientId,
typename ThirdPartyCapId, typename JoinResult,
typename LocalSturdyRefObjectId>
RpcSystem<VatId>::RpcSystem(
VatNetwork<VatId, ProvisionId, RecipientId, ThirdPartyCapId, JoinResult>& network,
SturdyRefRestorer<LocalSturdyRefObjectId>& restorer)
: _::RpcSystemBase(network, restorer) {}
template <typename VatId>
Capability::Client RpcSystem<VatId>::bootstrap(typename VatId::Reader vatId) {
return baseBootstrap(_::PointerHelpers<VatId>::getInternalReader(vatId));
}
template <typename VatId>
Capability::Client RpcSystem<VatId>::restore(
typename VatId::Reader hostId, AnyPointer::Reader objectId) {
return baseRestore(_::PointerHelpers<VatId>::getInternalReader(hostId), objectId);
}
template <typename VatId>
inline void RpcSystem<VatId>::setFlowLimit(size_t words) {
baseSetFlowLimit(words);
}
template <typename VatId, typename ProvisionId, typename RecipientId,
typename ThirdPartyCapId, typename JoinResult>
RpcSystem<VatId> makeRpcServer(
VatNetwork<VatId, ProvisionId, RecipientId, ThirdPartyCapId, JoinResult>& network,
Capability::Client bootstrapInterface) {
return RpcSystem<VatId>(network, kj::mv(bootstrapInterface));
}
template <typename VatId, typename ProvisionId, typename RecipientId,
typename ThirdPartyCapId, typename JoinResult,
typename RealmGatewayClient, typename InternalRef, typename ExternalRef>
RpcSystem<VatId> makeRpcServer(
VatNetwork<VatId, ProvisionId, RecipientId, ThirdPartyCapId, JoinResult>& network,
Capability::Client bootstrapInterface, RealmGatewayClient gateway) {
return RpcSystem<VatId>(network, kj::mv(bootstrapInterface),
gateway.template castAs<RealmGateway<>>());
}
template <typename VatId, typename ProvisionId, typename RecipientId,
typename ThirdPartyCapId, typename JoinResult>
RpcSystem<VatId> makeRpcServer(
VatNetwork<VatId, ProvisionId, RecipientId, ThirdPartyCapId, JoinResult>& network,
BootstrapFactory<VatId>& bootstrapFactory) {
return RpcSystem<VatId>(network, bootstrapFactory);
}
template <typename VatId, typename ProvisionId, typename RecipientId,
typename ThirdPartyCapId, typename JoinResult,
typename RealmGatewayClient, typename InternalRef, typename ExternalRef>
RpcSystem<VatId> makeRpcServer(
VatNetwork<VatId, ProvisionId, RecipientId, ThirdPartyCapId, JoinResult>& network,
BootstrapFactory<VatId>& bootstrapFactory, RealmGatewayClient gateway) {
return RpcSystem<VatId>(network, bootstrapFactory, gateway.template castAs<RealmGateway<>>());
}
template <typename VatId, typename LocalSturdyRefObjectId,
typename ProvisionId, typename RecipientId, typename ThirdPartyCapId, typename JoinResult>
RpcSystem<VatId> makeRpcServer(
VatNetwork<VatId, ProvisionId, RecipientId, ThirdPartyCapId, JoinResult>& network,
SturdyRefRestorer<LocalSturdyRefObjectId>& restorer) {
return RpcSystem<VatId>(network, restorer);
}
template <typename VatId, typename ProvisionId,
typename RecipientId, typename ThirdPartyCapId, typename JoinResult>
RpcSystem<VatId> makeRpcClient(
VatNetwork<VatId, ProvisionId, RecipientId, ThirdPartyCapId, JoinResult>& network) {
return RpcSystem<VatId>(network, nullptr);
}
template <typename VatId, typename ProvisionId,
typename RecipientId, typename ThirdPartyCapId, typename JoinResult,
typename RealmGatewayClient, typename InternalRef, typename ExternalRef>
RpcSystem<VatId> makeRpcClient(
VatNetwork<VatId, ProvisionId, RecipientId, ThirdPartyCapId, JoinResult>& network,
RealmGatewayClient gateway) {
return RpcSystem<VatId>(network, nullptr, gateway.template castAs<RealmGateway<>>());
}
} // namespace capnp
#endif // CAPNP_RPC_H_

View File

@ -1,48 +0,0 @@
// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#ifndef CAPNP_SCHEMA_LITE_H_
#define CAPNP_SCHEMA_LITE_H_
#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS)
#pragma GCC system_header
#endif
#include <capnp/schema.capnp.h>
#include "message.h"
namespace capnp {
template <typename T, typename CapnpPrivate = typename T::_capnpPrivate>
inline schema::Node::Reader schemaProto() {
// Get the schema::Node for this type's schema. This function works even in lite mode.
return readMessageUnchecked<schema::Node>(CapnpPrivate::encodedSchema());
}
template <typename T, uint64_t id = schemas::EnumInfo<T>::typeId>
inline schema::Node::Reader schemaProto() {
// Get the schema::Node for this type's schema. This function works even in lite mode.
return readMessageUnchecked<schema::Node>(schemas::EnumInfo<T>::encodedSchema());
}
} // namespace capnp
#endif // CAPNP_SCHEMA_LITE_H_

View File

@ -1,173 +0,0 @@
// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#ifndef CAPNP_SCHEMA_LOADER_H_
#define CAPNP_SCHEMA_LOADER_H_
#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS)
#pragma GCC system_header
#endif
#include "schema.h"
#include <kj/memory.h>
#include <kj/mutex.h>
namespace capnp {
class SchemaLoader {
// Class which can be used to construct Schema objects from schema::Nodes as defined in
// schema.capnp.
//
// It is a bad idea to use this class on untrusted input with exceptions disabled -- you may
// be exposing yourself to denial-of-service attacks, as attackers can easily construct schemas
// that are subtly inconsistent in a way that causes exceptions to be thrown either by
// SchemaLoader or by the dynamic API when the schemas are subsequently used. If you enable and
// properly catch exceptions, you should be OK -- assuming no bugs in the Cap'n Proto
// implementation, of course.
public:
class LazyLoadCallback {
public:
virtual void load(const SchemaLoader& loader, uint64_t id) const = 0;
// Request that the schema node with the given ID be loaded into the given SchemaLoader. If
// the callback is able to find a schema for this ID, it should invoke `loadOnce()` on
// `loader` to load it. If no such node exists, it should simply do nothing and return.
//
// The callback is allowed to load schema nodes other than the one requested, e.g. because it
// expects they will be needed soon.
//
// If the `SchemaLoader` is used from multiple threads, the callback must be thread-safe.
// In particular, it's possible for multiple threads to invoke `load()` with the same ID.
// If the callback performs a large amount of work to look up IDs, it should be sure to
// de-dup these requests.
};
SchemaLoader();
SchemaLoader(const LazyLoadCallback& callback);
// Construct a SchemaLoader which will invoke the given callback when a schema node is requested
// that isn't already loaded.
~SchemaLoader() noexcept(false);
KJ_DISALLOW_COPY(SchemaLoader);
Schema get(uint64_t id, schema::Brand::Reader brand = schema::Brand::Reader(),
Schema scope = Schema()) const;
// Gets the schema for the given ID, throwing an exception if it isn't present.
//
// The returned schema may be invalidated if load() is called with a new schema for the same ID.
// In general, you should not call load() while a schema from this loader is in-use.
//
// `brand` and `scope` are used to determine brand bindings where relevant. `brand` gives
// parameter bindings for the target type's brand parameters that were specified at the reference
// site. `scope` specifies the scope in which the type ID appeared -- if `brand` itself contains
// parameter references or indicates that some parameters will be inherited, these will be
// interpreted within / inherited from `scope`.
kj::Maybe<Schema> tryGet(uint64_t id, schema::Brand::Reader bindings = schema::Brand::Reader(),
Schema scope = Schema()) const;
// Like get() but doesn't throw.
Schema getUnbound(uint64_t id) const;
// Gets a special version of the schema in which all brand parameters are "unbound". This means
// that if you look up a type via the Schema API, and it resolves to a brand parameter, the
// returned Type's getBrandParameter() method will return info about that parameter. Otherwise,
// normally, all brand parameters that aren't otherwise bound are assumed to simply be
// "AnyPointer".
Type getType(schema::Type::Reader type, Schema scope = Schema()) const;
// Convenience method which interprets a schema::Type to produce a Type object. Implemented in
// terms of get().
Schema load(const schema::Node::Reader& reader);
// Loads the given schema node. Validates the node and throws an exception if invalid. This
// makes a copy of the schema, so the object passed in can be destroyed after this returns.
//
// If the node has any dependencies which are not already loaded, they will be initialized as
// stubs -- empty schemas of whichever kind is expected.
//
// If another schema for the given reader has already been seen, the loader will inspect both
// schemas to determine which one is newer, and use that that one. If the two versions are
// found to be incompatible, an exception is thrown. If the two versions differ but are
// compatible and the loader cannot determine which is newer (e.g., the only changes are renames),
// the existing schema will be preferred. Note that in any case, the loader will end up keeping
// around copies of both schemas, so you shouldn't repeatedly reload schemas into the same loader.
//
// The following properties of the schema node are validated:
// - Struct size and preferred list encoding are valid and consistent.
// - Struct members are fields or unions.
// - Union members are fields.
// - Field offsets are in-bounds.
// - Ordinals and codeOrders are sequential starting from zero.
// - Values are of the right union case to match their types.
//
// You should assume anything not listed above is NOT validated. In particular, things that are
// not validated now, but could be in the future, include but are not limited to:
// - Names.
// - Annotation values. (This is hard because the annotation declaration is not always
// available.)
// - Content of default/constant values of pointer type. (Validating these would require knowing
// their schema, but even if the schemas are available at validation time, they could be
// updated by a subsequent load(), invalidating existing values. Instead, these values are
// validated at the time they are used, as usual for Cap'n Proto objects.)
//
// Also note that unknown types are not considered invalid. Instead, the dynamic API returns
// a DynamicValue with type UNKNOWN for these.
Schema loadOnce(const schema::Node::Reader& reader) const;
// Like `load()` but does nothing if a schema with the same ID is already loaded. In contrast,
// `load()` would attempt to compare the schemas and take the newer one. `loadOnce()` is safe
// to call even while concurrently using schemas from this loader. It should be considered an
// error to call `loadOnce()` with two non-identical schemas that share the same ID, although
// this error may or may not actually be detected by the implementation.
template <typename T>
void loadCompiledTypeAndDependencies();
// Load the schema for the given compiled-in type and all of its dependencies.
//
// If you want to be able to cast a DynamicValue built from this SchemaLoader to the compiled-in
// type using as<T>(), you must call this method before constructing the DynamicValue. Otherwise,
// as<T>() will throw an exception complaining about type mismatch.
kj::Array<Schema> getAllLoaded() const;
// Get a complete list of all loaded schema nodes. It is particularly useful to call this after
// loadCompiledTypeAndDependencies<T>() in order to get a flat list of all of T's transitive
// dependencies.
private:
class Validator;
class CompatibilityChecker;
class Impl;
class InitializerImpl;
class BrandedInitializerImpl;
kj::MutexGuarded<kj::Own<Impl>> impl;
void loadNative(const _::RawSchema* nativeSchema);
};
template <typename T>
inline void SchemaLoader::loadCompiledTypeAndDependencies() {
loadNative(&_::rawSchema<T>());
}
} // namespace capnp
#endif // CAPNP_SCHEMA_LOADER_H_

View File

@ -1,207 +0,0 @@
// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#ifndef CAPNP_SCHEMA_PARSER_H_
#define CAPNP_SCHEMA_PARSER_H_
#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS)
#pragma GCC system_header
#endif
#include "schema-loader.h"
#include <kj/string.h>
namespace capnp {
class ParsedSchema;
class SchemaFile;
class SchemaParser {
// Parses `.capnp` files to produce `Schema` objects.
//
// This class is thread-safe, hence all its methods are const.
public:
SchemaParser();
~SchemaParser() noexcept(false);
ParsedSchema parseDiskFile(kj::StringPtr displayName, kj::StringPtr diskPath,
kj::ArrayPtr<const kj::StringPtr> importPath) const;
// Parse a file located on disk. Throws an exception if the file dosen't exist.
//
// Parameters:
// * `displayName`: The name that will appear in the file's schema node. (If the file has
// already been parsed, this will be ignored and the display name from the first time it was
// parsed will be kept.)
// * `diskPath`: The path to the file on disk.
// * `importPath`: Directories to search when resolving absolute imports within this file
// (imports that start with a `/`). Must remain valid until the SchemaParser is destroyed.
// (If the file has already been parsed, this will be ignored and the import path from the
// first time it was parsed will be kept.)
//
// This method is a shortcut, equivalent to:
// parser.parseFile(SchemaFile::newDiskFile(displayName, diskPath, importPath))`;
//
// This method throws an exception if any errors are encountered in the file or in anything the
// file depends on. Note that merely importing another file does not count as a dependency on
// anything in the imported file -- only the imported types which are actually used are
// "dependencies".
ParsedSchema parseFile(kj::Own<SchemaFile>&& file) const;
// Advanced interface for parsing a file that may or may not be located in any global namespace.
// Most users will prefer `parseDiskFile()`.
//
// If the file has already been parsed (that is, a SchemaFile that compares equal to this one
// was parsed previously), the existing schema will be returned again.
//
// This method reports errors by calling SchemaFile::reportError() on the file where the error
// is located. If that call does not throw an exception, `parseFile()` may in fact return
// normally. In this case, the result is a best-effort attempt to compile the schema, but it
// may be invalid or corrupt, and using it for anything may cause exceptions to be thrown.
template <typename T>
inline void loadCompiledTypeAndDependencies() {
// See SchemaLoader::loadCompiledTypeAndDependencies().
getLoader().loadCompiledTypeAndDependencies<T>();
}
private:
struct Impl;
class ModuleImpl;
kj::Own<Impl> impl;
mutable bool hadErrors = false;
ModuleImpl& getModuleImpl(kj::Own<SchemaFile>&& file) const;
SchemaLoader& getLoader();
friend class ParsedSchema;
};
class ParsedSchema: public Schema {
// ParsedSchema is an extension of Schema which also has the ability to look up nested nodes
// by name. See `SchemaParser`.
public:
inline ParsedSchema(): parser(nullptr) {}
kj::Maybe<ParsedSchema> findNested(kj::StringPtr name) const;
// Gets the nested node with the given name, or returns null if there is no such nested
// declaration.
ParsedSchema getNested(kj::StringPtr name) const;
// Gets the nested node with the given name, or throws an exception if there is no such nested
// declaration.
private:
inline ParsedSchema(Schema inner, const SchemaParser& parser): Schema(inner), parser(&parser) {}
const SchemaParser* parser;
friend class SchemaParser;
};
// =======================================================================================
// Advanced API
class SchemaFile {
// Abstract interface representing a schema file. You can implement this yourself in order to
// gain more control over how the compiler resolves imports and reads files. For the
// common case of files on disk or other global filesystem-like namespaces, use
// `SchemaFile::newDiskFile()`.
public:
class FileReader {
public:
virtual bool exists(kj::StringPtr path) const = 0;
virtual kj::Array<const char> read(kj::StringPtr path) const = 0;
};
class DiskFileReader final: public FileReader {
// Implementation of FileReader that uses the local disk. Files are read using mmap() if
// possible.
public:
static const DiskFileReader instance;
bool exists(kj::StringPtr path) const override;
kj::Array<const char> read(kj::StringPtr path) const override;
};
static kj::Own<SchemaFile> newDiskFile(
kj::StringPtr displayName, kj::StringPtr diskPath,
kj::ArrayPtr<const kj::StringPtr> importPath,
const FileReader& fileReader = DiskFileReader::instance);
// Construct a SchemaFile representing a file on disk (or located in the filesystem-like
// namespace represented by `fileReader`).
//
// Parameters:
// * `displayName`: The name that will appear in the file's schema node.
// * `diskPath`: The path to the file on disk.
// * `importPath`: Directories to search when resolving absolute imports within this file
// (imports that start with a `/`). The array content must remain valid as long as the
// SchemaFile exists (which is at least as long as the SchemaParser that parses it exists).
// * `fileReader`: Allows you to use a filesystem other than the actual local disk. Although,
// if you find yourself using this, it may make more sense for you to implement SchemaFile
// yourself.
//
// The SchemaFile compares equal to any other SchemaFile that has exactly the same disk path,
// after canonicalization.
//
// The SchemaFile will throw an exception if any errors are reported.
// -----------------------------------------------------------------
// For more control, you can implement this interface.
virtual kj::StringPtr getDisplayName() const = 0;
// Get the file's name, as it should appear in the schema.
virtual kj::Array<const char> readContent() const = 0;
// Read the file's entire content and return it as a byte array.
virtual kj::Maybe<kj::Own<SchemaFile>> import(kj::StringPtr path) const = 0;
// Resolve an import, relative to this file.
//
// `path` is exactly what appears between quotes after the `import` keyword in the source code.
// It is entirely up to the `SchemaFile` to decide how to map this to another file. Typically,
// a leading '/' means that the file is an "absolute" path and is searched for in some list of
// schema file repositories. On the other hand, a path that doesn't start with '/' is relative
// to the importing file.
virtual bool operator==(const SchemaFile& other) const = 0;
virtual bool operator!=(const SchemaFile& other) const = 0;
virtual size_t hashCode() const = 0;
// Compare two SchemaFiles to see if they refer to the same underlying file. This is an
// optimization used to avoid the need to re-parse a file to check its ID.
struct SourcePos {
uint byte;
uint line;
uint column;
};
virtual void reportError(SourcePos start, SourcePos end, kj::StringPtr message) const = 0;
// Report that the file contains an error at the given interval.
private:
class DiskSchemaFile;
};
} // namespace capnp
#endif // CAPNP_SCHEMA_PARSER_H_

View File

@ -1,498 +0,0 @@
# Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
# Licensed under the MIT License:
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
using Cxx = import "/capnp/c++.capnp";
@0xa93fc509624c72d9;
$Cxx.namespace("capnp::schema");
using Id = UInt64;
# The globally-unique ID of a file, type, or annotation.
struct Node {
id @0 :Id;
displayName @1 :Text;
# Name to present to humans to identify this Node. You should not attempt to parse this. Its
# format could change. It is not guaranteed to be unique.
#
# (On Zooko's triangle, this is the node's nickname.)
displayNamePrefixLength @2 :UInt32;
# If you want a shorter version of `displayName` (just naming this node, without its surrounding
# scope), chop off this many characters from the beginning of `displayName`.
scopeId @3 :Id;
# ID of the lexical parent node. Typically, the scope node will have a NestedNode pointing back
# at this node, but robust code should avoid relying on this (and, in fact, group nodes are not
# listed in the outer struct's nestedNodes, since they are listed in the fields). `scopeId` is
# zero if the node has no parent, which is normally only the case with files, but should be
# allowed for any kind of node (in order to make runtime type generation easier).
parameters @32 :List(Parameter);
# If this node is parameterized (generic), the list of parameters. Empty for non-generic types.
isGeneric @33 :Bool;
# True if this node is generic, meaning that it or one of its parent scopes has a non-empty
# `parameters`.
struct Parameter {
# Information about one of the node's parameters.
name @0 :Text;
}
nestedNodes @4 :List(NestedNode);
# List of nodes nested within this node, along with the names under which they were declared.
struct NestedNode {
name @0 :Text;
# Unqualified symbol name. Unlike Node.displayName, this *can* be used programmatically.
#
# (On Zooko's triangle, this is the node's petname according to its parent scope.)
id @1 :Id;
# ID of the nested node. Typically, the target node's scopeId points back to this node, but
# robust code should avoid relying on this.
}
annotations @5 :List(Annotation);
# Annotations applied to this node.
union {
# Info specific to each kind of node.
file @6 :Void;
struct :group {
dataWordCount @7 :UInt16;
# Size of the data section, in words.
pointerCount @8 :UInt16;
# Size of the pointer section, in pointers (which are one word each).
preferredListEncoding @9 :ElementSize;
# The preferred element size to use when encoding a list of this struct. If this is anything
# other than `inlineComposite` then the struct is one word or less in size and is a candidate
# for list packing optimization.
isGroup @10 :Bool;
# If true, then this "struct" node is actually not an independent node, but merely represents
# some named union or group within a particular parent struct. This node's scopeId refers
# to the parent struct, which may itself be a union/group in yet another struct.
#
# All group nodes share the same dataWordCount and pointerCount as the top-level
# struct, and their fields live in the same ordinal and offset spaces as all other fields in
# the struct.
#
# Note that a named union is considered a special kind of group -- in fact, a named union
# is exactly equivalent to a group that contains nothing but an unnamed union.
discriminantCount @11 :UInt16;
# Number of fields in this struct which are members of an anonymous union, and thus may
# overlap. If this is non-zero, then a 16-bit discriminant is present indicating which
# of the overlapping fields is active. This can never be 1 -- if it is non-zero, it must be
# two or more.
#
# Note that the fields of an unnamed union are considered fields of the scope containing the
# union -- an unnamed union is not its own group. So, a top-level struct may contain a
# non-zero discriminant count. Named unions, on the other hand, are equivalent to groups
# containing unnamed unions. So, a named union has its own independent schema node, with
# `isGroup` = true.
discriminantOffset @12 :UInt32;
# If `discriminantCount` is non-zero, this is the offset of the union discriminant, in
# multiples of 16 bits.
fields @13 :List(Field);
# Fields defined within this scope (either the struct's top-level fields, or the fields of
# a particular group; see `isGroup`).
#
# The fields are sorted by ordinal number, but note that because groups share the same
# ordinal space, the field's index in this list is not necessarily exactly its ordinal.
# On the other hand, the field's position in this list does remain the same even as the
# protocol evolves, since it is not possible to insert or remove an earlier ordinal.
# Therefore, for most use cases, if you want to identify a field by number, it may make the
# most sense to use the field's index in this list rather than its ordinal.
}
enum :group {
enumerants@14 :List(Enumerant);
# Enumerants ordered by numeric value (ordinal).
}
interface :group {
methods @15 :List(Method);
# Methods ordered by ordinal.
superclasses @31 :List(Superclass);
# Superclasses of this interface.
}
const :group {
type @16 :Type;
value @17 :Value;
}
annotation :group {
type @18 :Type;
targetsFile @19 :Bool;
targetsConst @20 :Bool;
targetsEnum @21 :Bool;
targetsEnumerant @22 :Bool;
targetsStruct @23 :Bool;
targetsField @24 :Bool;
targetsUnion @25 :Bool;
targetsGroup @26 :Bool;
targetsInterface @27 :Bool;
targetsMethod @28 :Bool;
targetsParam @29 :Bool;
targetsAnnotation @30 :Bool;
}
}
}
struct Field {
# Schema for a field of a struct.
name @0 :Text;
codeOrder @1 :UInt16;
# Indicates where this member appeared in the code, relative to other members.
# Code ordering may have semantic relevance -- programmers tend to place related fields
# together. So, using code ordering makes sense in human-readable formats where ordering is
# otherwise irrelevant, like JSON. The values of codeOrder are tightly-packed, so the maximum
# value is count(members) - 1. Fields that are members of a union are only ordered relative to
# the other members of that union, so the maximum value there is count(union.members).
annotations @2 :List(Annotation);
const noDiscriminant :UInt16 = 0xffff;
discriminantValue @3 :UInt16 = Field.noDiscriminant;
# If the field is in a union, this is the value which the union's discriminant should take when
# the field is active. If the field is not in a union, this is 0xffff.
union {
slot :group {
# A regular, non-group, non-fixed-list field.
offset @4 :UInt32;
# Offset, in units of the field's size, from the beginning of the section in which the field
# resides. E.g. for a UInt32 field, multiply this by 4 to get the byte offset from the
# beginning of the data section.
type @5 :Type;
defaultValue @6 :Value;
hadExplicitDefault @10 :Bool;
# Whether the default value was specified explicitly. Non-explicit default values are always
# zero or empty values. Usually, whether the default value was explicit shouldn't matter.
# The main use case for this flag is for structs representing method parameters:
# explicitly-defaulted parameters may be allowed to be omitted when calling the method.
}
group :group {
# A group.
typeId @7 :Id;
# The ID of the group's node.
}
}
ordinal :union {
implicit @8 :Void;
explicit @9 :UInt16;
# The original ordinal number given to the field. You probably should NOT use this; if you need
# a numeric identifier for a field, use its position within the field array for its scope.
# The ordinal is given here mainly just so that the original schema text can be reproduced given
# the compiled version -- i.e. so that `capnp compile -ocapnp` can do its job.
}
}
struct Enumerant {
# Schema for member of an enum.
name @0 :Text;
codeOrder @1 :UInt16;
# Specifies order in which the enumerants were declared in the code.
# Like Struct.Field.codeOrder.
annotations @2 :List(Annotation);
}
struct Superclass {
id @0 :Id;
brand @1 :Brand;
}
struct Method {
# Schema for method of an interface.
name @0 :Text;
codeOrder @1 :UInt16;
# Specifies order in which the methods were declared in the code.
# Like Struct.Field.codeOrder.
implicitParameters @7 :List(Node.Parameter);
# The parameters listed in [] (typically, type / generic parameters), whose bindings are intended
# to be inferred rather than specified explicitly, although not all languages support this.
paramStructType @2 :Id;
# ID of the parameter struct type. If a named parameter list was specified in the method
# declaration (rather than a single struct parameter type) then a corresponding struct type is
# auto-generated. Such an auto-generated type will not be listed in the interface's
# `nestedNodes` and its `scopeId` will be zero -- it is completely detached from the namespace.
# (Awkwardly, it does of course inherit generic parameters from the method's scope, which makes
# this a situation where you can't just climb the scope chain to find where a particular
# generic parameter was introduced. Making the `scopeId` zero was a mistake.)
paramBrand @5 :Brand;
# Brand of param struct type.
resultStructType @3 :Id;
# ID of the return struct type; similar to `paramStructType`.
resultBrand @6 :Brand;
# Brand of result struct type.
annotations @4 :List(Annotation);
}
struct Type {
# Represents a type expression.
union {
# The ordinals intentionally match those of Value.
void @0 :Void;
bool @1 :Void;
int8 @2 :Void;
int16 @3 :Void;
int32 @4 :Void;
int64 @5 :Void;
uint8 @6 :Void;
uint16 @7 :Void;
uint32 @8 :Void;
uint64 @9 :Void;
float32 @10 :Void;
float64 @11 :Void;
text @12 :Void;
data @13 :Void;
list :group {
elementType @14 :Type;
}
enum :group {
typeId @15 :Id;
brand @21 :Brand;
}
struct :group {
typeId @16 :Id;
brand @22 :Brand;
}
interface :group {
typeId @17 :Id;
brand @23 :Brand;
}
anyPointer :union {
unconstrained :union {
# A regular AnyPointer.
#
# The name "unconstrained" means as opposed to constraining it to match a type parameter.
# In retrospect this name is probably a poor choice given that it may still be constrained
# to be a struct, list, or capability.
anyKind @18 :Void; # truly AnyPointer
struct @25 :Void; # AnyStruct
list @26 :Void; # AnyList
capability @27 :Void; # Capability
}
parameter :group {
# This is actually a reference to a type parameter defined within this scope.
scopeId @19 :Id;
# ID of the generic type whose parameter we're referencing. This should be a parent of the
# current scope.
parameterIndex @20 :UInt16;
# Index of the parameter within the generic type's parameter list.
}
implicitMethodParameter :group {
# This is actually a reference to an implicit (generic) parameter of a method. The only
# legal context for this type to appear is inside Method.paramBrand or Method.resultBrand.
parameterIndex @24 :UInt16;
}
}
}
}
struct Brand {
# Specifies bindings for parameters of generics. Since these bindings turn a generic into a
# non-generic, we call it the "brand".
scopes @0 :List(Scope);
# For each of the target type and each of its parent scopes, a parameterization may be included
# in this list. If no parameterization is included for a particular relevant scope, then either
# that scope has no parameters or all parameters should be considered to be `AnyPointer`.
struct Scope {
scopeId @0 :Id;
# ID of the scope to which these params apply.
union {
bind @1 :List(Binding);
# List of parameter bindings.
inherit @2 :Void;
# The place where this Brand appears is actually within this scope or a sub-scope,
# and the bindings for this scope should be inherited from the reference point.
}
}
struct Binding {
union {
unbound @0 :Void;
type @1 :Type;
# TODO(someday): Allow non-type parameters? Unsure if useful.
}
}
}
struct Value {
# Represents a value, e.g. a field default value, constant value, or annotation value.
union {
# The ordinals intentionally match those of Type.
void @0 :Void;
bool @1 :Bool;
int8 @2 :Int8;
int16 @3 :Int16;
int32 @4 :Int32;
int64 @5 :Int64;
uint8 @6 :UInt8;
uint16 @7 :UInt16;
uint32 @8 :UInt32;
uint64 @9 :UInt64;
float32 @10 :Float32;
float64 @11 :Float64;
text @12 :Text;
data @13 :Data;
list @14 :AnyPointer;
enum @15 :UInt16;
struct @16 :AnyPointer;
interface @17 :Void;
# The only interface value that can be represented statically is "null", whose methods always
# throw exceptions.
anyPointer @18 :AnyPointer;
}
}
struct Annotation {
# Describes an annotation applied to a declaration. Note AnnotationNode describes the
# annotation's declaration, while this describes a use of the annotation.
id @0 :Id;
# ID of the annotation node.
brand @2 :Brand;
# Brand of the annotation.
#
# Note that the annotation itself is not allowed to be parameterized, but its scope might be.
value @1 :Value;
}
enum ElementSize {
# Possible element sizes for encoded lists. These correspond exactly to the possible values of
# the 3-bit element size component of a list pointer.
empty @0; # aka "void", but that's a keyword.
bit @1;
byte @2;
twoBytes @3;
fourBytes @4;
eightBytes @5;
pointer @6;
inlineComposite @7;
}
struct CapnpVersion {
major @0 :UInt16;
minor @1 :UInt8;
micro @2 :UInt8;
}
struct CodeGeneratorRequest {
capnpVersion @2 :CapnpVersion;
# Version of the `capnp` executable. Generally, code generators should ignore this, but the code
# generators that ship with `capnp` itself will print a warning if this mismatches since that
# probably indicates something is misconfigured.
#
# The first version of 'capnp' to set this was 0.6.0. So, if it's missing, the compiler version
# is older than that.
nodes @0 :List(Node);
# All nodes parsed by the compiler, including for the files on the command line and their
# imports.
requestedFiles @1 :List(RequestedFile);
# Files which were listed on the command line.
struct RequestedFile {
id @0 :Id;
# ID of the file.
filename @1 :Text;
# Name of the file as it appeared on the command-line (minus the src-prefix). You may use
# this to decide where to write the output.
imports @2 :List(Import);
# List of all imported paths seen in this file.
struct Import {
id @0 :Id;
# ID of the imported file.
name @1 :Text;
# Name which *this* file used to refer to the foreign file. This may be a relative name.
# This information is provided because it might be useful for code generation, e.g. to
# generate #include directives in C++. We don't put this in Node.file because this
# information is only meaningful at compile time anyway.
#
# (On Zooko's triangle, this is the import's petname according to the importing file.)
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,934 +0,0 @@
// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#ifndef CAPNP_SCHEMA_H_
#define CAPNP_SCHEMA_H_
#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS)
#pragma GCC system_header
#endif
#if CAPNP_LITE
#error "Reflection APIs, including this header, are not available in lite mode."
#endif
#include <capnp/schema.capnp.h>
namespace capnp {
class Schema;
class StructSchema;
class EnumSchema;
class InterfaceSchema;
class ConstSchema;
class ListSchema;
class Type;
template <typename T, Kind k = kind<T>()> struct SchemaType_ { typedef Schema Type; };
template <typename T> struct SchemaType_<T, Kind::PRIMITIVE> { typedef schema::Type::Which Type; };
template <typename T> struct SchemaType_<T, Kind::BLOB> { typedef schema::Type::Which Type; };
template <typename T> struct SchemaType_<T, Kind::ENUM> { typedef EnumSchema Type; };
template <typename T> struct SchemaType_<T, Kind::STRUCT> { typedef StructSchema Type; };
template <typename T> struct SchemaType_<T, Kind::INTERFACE> { typedef InterfaceSchema Type; };
template <typename T> struct SchemaType_<T, Kind::LIST> { typedef ListSchema Type; };
template <typename T>
using SchemaType = typename SchemaType_<T>::Type;
// SchemaType<T> is the type of T's schema, e.g. StructSchema if T is a struct.
namespace _ { // private
extern const RawSchema NULL_SCHEMA;
extern const RawSchema NULL_STRUCT_SCHEMA;
extern const RawSchema NULL_ENUM_SCHEMA;
extern const RawSchema NULL_INTERFACE_SCHEMA;
extern const RawSchema NULL_CONST_SCHEMA;
// The schema types default to these null (empty) schemas in case of error, especially when
// exceptions are disabled.
} // namespace _ (private)
class Schema {
// Convenience wrapper around capnp::schema::Node.
public:
inline Schema(): raw(&_::NULL_SCHEMA.defaultBrand) {}
template <typename T>
static inline SchemaType<T> from() { return SchemaType<T>::template fromImpl<T>(); }
// Get the Schema for a particular compiled-in type.
schema::Node::Reader getProto() const;
// Get the underlying Cap'n Proto representation of the schema node. (Note that this accessor
// has performance comparable to accessors of struct-typed fields on Reader classes.)
kj::ArrayPtr<const word> asUncheckedMessage() const;
// Get the encoded schema node content as a single message segment. It is safe to read as an
// unchecked message.
Schema getDependency(uint64_t id) const KJ_DEPRECATED("Does not handle generics correctly.");
// DEPRECATED: This method cannot correctly account for generic type parameter bindings that
// may apply to the dependency. Instead of using this method, use a method of the Schema API
// that corresponds to the exact kind of dependency. For example, to get a field type, use
// StructSchema::Field::getType().
//
// Gets the Schema for one of this Schema's dependencies. For example, if this Schema is for a
// struct, you could look up the schema for one of its fields' types. Throws an exception if this
// schema doesn't actually depend on the given id.
//
// Note that not all type IDs found in the schema node are considered "dependencies" -- only the
// ones that are needed to implement the dynamic API are. That includes:
// - Field types.
// - Group types.
// - scopeId for group nodes, but NOT otherwise.
// - Method parameter and return types.
//
// The following are NOT considered dependencies:
// - Nested nodes.
// - scopeId for a non-group node.
// - Annotations.
//
// To obtain schemas for those, you would need a SchemaLoader.
bool isBranded() const;
// Returns true if this schema represents a non-default parameterization of this type.
Schema getGeneric() const;
// Get the version of this schema with any brands removed.
class BrandArgumentList;
BrandArgumentList getBrandArgumentsAtScope(uint64_t scopeId) const;
// Gets the values bound to the brand parameters at the given scope.
StructSchema asStruct() const;
EnumSchema asEnum() const;
InterfaceSchema asInterface() const;
ConstSchema asConst() const;
// Cast the Schema to a specific type. Throws an exception if the type doesn't match. Use
// getProto() to determine type, e.g. getProto().isStruct().
inline bool operator==(const Schema& other) const { return raw == other.raw; }
inline bool operator!=(const Schema& other) const { return raw != other.raw; }
// Determine whether two Schemas are wrapping the exact same underlying data, by identity. If
// you want to check if two Schemas represent the same type (but possibly different versions of
// it), compare their IDs instead.
template <typename T>
void requireUsableAs() const;
// Throws an exception if a value with this Schema cannot safely be cast to a native value of
// the given type. This passes if either:
// - *this == from<T>()
// - This schema was loaded with SchemaLoader, the type ID matches typeId<T>(), and
// loadCompiledTypeAndDependencies<T>() was called on the SchemaLoader.
kj::StringPtr getShortDisplayName() const;
// Get the short version of the node's display name.
private:
const _::RawBrandedSchema* raw;
inline explicit Schema(const _::RawBrandedSchema* raw): raw(raw) {
KJ_IREQUIRE(raw->lazyInitializer == nullptr,
"Must call ensureInitialized() on RawSchema before constructing Schema.");
}
template <typename T> static inline Schema fromImpl() {
return Schema(&_::rawSchema<T>());
}
void requireUsableAs(const _::RawSchema* expected) const;
uint32_t getSchemaOffset(const schema::Value::Reader& value) const;
Type getBrandBinding(uint64_t scopeId, uint index) const;
// Look up the binding for a brand parameter used by this Schema. Returns `AnyPointer` if the
// parameter is not bound.
//
// TODO(someday): Public interface for iterating over all bindings?
Schema getDependency(uint64_t id, uint location) const;
// Look up schema for a particular dependency of this schema. `location` is the dependency
// location number as defined in _::RawBrandedSchema.
Type interpretType(schema::Type::Reader proto, uint location) const;
// Interpret a schema::Type in the given location within the schema, compiling it into a
// Type object.
friend class StructSchema;
friend class EnumSchema;
friend class InterfaceSchema;
friend class ConstSchema;
friend class ListSchema;
friend class SchemaLoader;
friend class Type;
friend kj::StringTree _::structString(
_::StructReader reader, const _::RawBrandedSchema& schema);
friend kj::String _::enumString(uint16_t value, const _::RawBrandedSchema& schema);
};
kj::StringPtr KJ_STRINGIFY(const Schema& schema);
class Schema::BrandArgumentList {
// A list of generic parameter bindings for parameters of some particular type. Note that since
// parameters on an outer type apply to all inner types as well, a deeply-nested type can have
// multiple BrandArgumentLists that apply to it.
//
// A BrandArgumentList only represents the arguments that the client of the type specified. Since
// new parameters can be added over time, this list may not cover all defined parameters for the
// type. Missing parameters should be treated as AnyPointer. This class's implementation of
// operator[] already does this for you; out-of-bounds access will safely return AnyPointer.
public:
inline BrandArgumentList(): scopeId(0), size_(0), bindings(nullptr) {}
inline uint size() const { return size_; }
Type operator[](uint index) const;
typedef _::IndexingIterator<const BrandArgumentList, Type> Iterator;
inline Iterator begin() const { return Iterator(this, 0); }
inline Iterator end() const { return Iterator(this, size()); }
private:
uint64_t scopeId;
uint size_;
bool isUnbound;
const _::RawBrandedSchema::Binding* bindings;
inline BrandArgumentList(uint64_t scopeId, bool isUnbound)
: scopeId(scopeId), size_(0), isUnbound(isUnbound), bindings(nullptr) {}
inline BrandArgumentList(uint64_t scopeId, uint size,
const _::RawBrandedSchema::Binding* bindings)
: scopeId(scopeId), size_(size), isUnbound(false), bindings(bindings) {}
friend class Schema;
};
// -------------------------------------------------------------------
class StructSchema: public Schema {
public:
inline StructSchema(): Schema(&_::NULL_STRUCT_SCHEMA.defaultBrand) {}
class Field;
class FieldList;
class FieldSubset;
FieldList getFields() const;
// List top-level fields of this struct. This list will contain top-level groups (including
// named unions) but not the members of those groups. The list does, however, contain the
// members of the unnamed union, if there is one.
FieldSubset getUnionFields() const;
// If the field contains an unnamed union, get a list of fields in the union, ordered by
// ordinal. Since discriminant values are assigned sequentially by ordinal, you may index this
// list by discriminant value.
FieldSubset getNonUnionFields() const;
// Get the fields of this struct which are not in an unnamed union, ordered by ordinal.
kj::Maybe<Field> findFieldByName(kj::StringPtr name) const;
// Find the field with the given name, or return null if there is no such field. If the struct
// contains an unnamed union, then this will find fields of that union in addition to fields
// of the outer struct, since they exist in the same namespace. It will not, however, find
// members of groups (including named unions) -- you must first look up the group itself,
// then dig into its type.
Field getFieldByName(kj::StringPtr name) const;
// Like findFieldByName() but throws an exception on failure.
kj::Maybe<Field> getFieldByDiscriminant(uint16_t discriminant) const;
// Finds the field whose `discriminantValue` is equal to the given value, or returns null if
// there is no such field. (If the schema does not represent a union or a struct containing
// an unnamed union, then this always returns null.)
private:
StructSchema(Schema base): Schema(base) {}
template <typename T> static inline StructSchema fromImpl() {
return StructSchema(Schema(&_::rawBrandedSchema<T>()));
}
friend class Schema;
friend class Type;
};
class StructSchema::Field {
public:
Field() = default;
inline schema::Field::Reader getProto() const { return proto; }
inline StructSchema getContainingStruct() const { return parent; }
inline uint getIndex() const { return index; }
// Get the index of this field within the containing struct or union.
Type getType() const;
// Get the type of this field. Note that this is preferred over getProto().getType() as this
// method will apply generics.
uint32_t getDefaultValueSchemaOffset() const;
// For struct, list, and object fields, returns the offset, in words, within the first segment of
// the struct's schema, where this field's default value pointer is located. The schema is
// always stored as a single-segment unchecked message, which in turn means that the default
// value pointer itself can be treated as the root of an unchecked message -- if you know where
// to find it, which is what this method helps you with.
//
// For blobs, returns the offset of the beginning of the blob's content within the first segment
// of the struct's schema.
//
// This is primarily useful for code generators. The C++ code generator, for example, embeds
// the entire schema as a raw word array within the generated code. Of course, to implement
// field accessors, it needs access to those fields' default values. Embedding separate copies
// of those default values would be redundant since they are already included in the schema, but
// seeking through the schema at runtime to find the default values would be ugly. Instead,
// the code generator can use getDefaultValueSchemaOffset() to find the offset of the default
// value within the schema, and can simply apply that offset at runtime.
//
// If the above does not make sense, you probably don't need this method.
inline bool operator==(const Field& other) const;
inline bool operator!=(const Field& other) const { return !(*this == other); }
private:
StructSchema parent;
uint index;
schema::Field::Reader proto;
inline Field(StructSchema parent, uint index, schema::Field::Reader proto)
: parent(parent), index(index), proto(proto) {}
friend class StructSchema;
};
kj::StringPtr KJ_STRINGIFY(const StructSchema::Field& field);
class StructSchema::FieldList {
public:
FieldList() = default; // empty list
inline uint size() const { return list.size(); }
inline Field operator[](uint index) const { return Field(parent, index, list[index]); }
typedef _::IndexingIterator<const FieldList, Field> Iterator;
inline Iterator begin() const { return Iterator(this, 0); }
inline Iterator end() const { return Iterator(this, size()); }
private:
StructSchema parent;
List<schema::Field>::Reader list;
inline FieldList(StructSchema parent, List<schema::Field>::Reader list)
: parent(parent), list(list) {}
friend class StructSchema;
};
class StructSchema::FieldSubset {
public:
FieldSubset() = default; // empty list
inline uint size() const { return size_; }
inline Field operator[](uint index) const {
return Field(parent, indices[index], list[indices[index]]);
}
typedef _::IndexingIterator<const FieldSubset, Field> Iterator;
inline Iterator begin() const { return Iterator(this, 0); }
inline Iterator end() const { return Iterator(this, size()); }
private:
StructSchema parent;
List<schema::Field>::Reader list;
const uint16_t* indices;
uint size_;
inline FieldSubset(StructSchema parent, List<schema::Field>::Reader list,
const uint16_t* indices, uint size)
: parent(parent), list(list), indices(indices), size_(size) {}
friend class StructSchema;
};
// -------------------------------------------------------------------
class EnumSchema: public Schema {
public:
inline EnumSchema(): Schema(&_::NULL_ENUM_SCHEMA.defaultBrand) {}
class Enumerant;
class EnumerantList;
EnumerantList getEnumerants() const;
kj::Maybe<Enumerant> findEnumerantByName(kj::StringPtr name) const;
Enumerant getEnumerantByName(kj::StringPtr name) const;
// Like findEnumerantByName() but throws an exception on failure.
private:
EnumSchema(Schema base): Schema(base) {}
template <typename T> static inline EnumSchema fromImpl() {
return EnumSchema(Schema(&_::rawBrandedSchema<T>()));
}
friend class Schema;
friend class Type;
};
class EnumSchema::Enumerant {
public:
Enumerant() = default;
inline schema::Enumerant::Reader getProto() const { return proto; }
inline EnumSchema getContainingEnum() const { return parent; }
inline uint16_t getOrdinal() const { return ordinal; }
inline uint getIndex() const { return ordinal; }
inline bool operator==(const Enumerant& other) const;
inline bool operator!=(const Enumerant& other) const { return !(*this == other); }
private:
EnumSchema parent;
uint16_t ordinal;
schema::Enumerant::Reader proto;
inline Enumerant(EnumSchema parent, uint16_t ordinal, schema::Enumerant::Reader proto)
: parent(parent), ordinal(ordinal), proto(proto) {}
friend class EnumSchema;
};
class EnumSchema::EnumerantList {
public:
EnumerantList() = default; // empty list
inline uint size() const { return list.size(); }
inline Enumerant operator[](uint index) const { return Enumerant(parent, index, list[index]); }
typedef _::IndexingIterator<const EnumerantList, Enumerant> Iterator;
inline Iterator begin() const { return Iterator(this, 0); }
inline Iterator end() const { return Iterator(this, size()); }
private:
EnumSchema parent;
List<schema::Enumerant>::Reader list;
inline EnumerantList(EnumSchema parent, List<schema::Enumerant>::Reader list)
: parent(parent), list(list) {}
friend class EnumSchema;
};
// -------------------------------------------------------------------
class InterfaceSchema: public Schema {
public:
inline InterfaceSchema(): Schema(&_::NULL_INTERFACE_SCHEMA.defaultBrand) {}
class Method;
class MethodList;
MethodList getMethods() const;
kj::Maybe<Method> findMethodByName(kj::StringPtr name) const;
Method getMethodByName(kj::StringPtr name) const;
// Like findMethodByName() but throws an exception on failure.
class SuperclassList;
SuperclassList getSuperclasses() const;
// Get the immediate superclasses of this type, after applying generics.
bool extends(InterfaceSchema other) const;
// Returns true if `other` is a superclass of this interface (including if `other == *this`).
kj::Maybe<InterfaceSchema> findSuperclass(uint64_t typeId) const;
// Find the superclass of this interface with the given type ID. Returns null if the interface
// extends no such type.
private:
InterfaceSchema(Schema base): Schema(base) {}
template <typename T> static inline InterfaceSchema fromImpl() {
return InterfaceSchema(Schema(&_::rawBrandedSchema<T>()));
}
friend class Schema;
friend class Type;
kj::Maybe<Method> findMethodByName(kj::StringPtr name, uint& counter) const;
bool extends(InterfaceSchema other, uint& counter) const;
kj::Maybe<InterfaceSchema> findSuperclass(uint64_t typeId, uint& counter) const;
// We protect against malicious schemas with large or cyclic hierarchies by cutting off the
// search when the counter reaches a threshold.
};
class InterfaceSchema::Method {
public:
Method() = default;
inline schema::Method::Reader getProto() const { return proto; }
inline InterfaceSchema getContainingInterface() const { return parent; }
inline uint16_t getOrdinal() const { return ordinal; }
inline uint getIndex() const { return ordinal; }
StructSchema getParamType() const;
StructSchema getResultType() const;
// Get the parameter and result types, including substituting generic parameters.
inline bool operator==(const Method& other) const;
inline bool operator!=(const Method& other) const { return !(*this == other); }
private:
InterfaceSchema parent;
uint16_t ordinal;
schema::Method::Reader proto;
inline Method(InterfaceSchema parent, uint16_t ordinal,
schema::Method::Reader proto)
: parent(parent), ordinal(ordinal), proto(proto) {}
friend class InterfaceSchema;
};
class InterfaceSchema::MethodList {
public:
MethodList() = default; // empty list
inline uint size() const { return list.size(); }
inline Method operator[](uint index) const { return Method(parent, index, list[index]); }
typedef _::IndexingIterator<const MethodList, Method> Iterator;
inline Iterator begin() const { return Iterator(this, 0); }
inline Iterator end() const { return Iterator(this, size()); }
private:
InterfaceSchema parent;
List<schema::Method>::Reader list;
inline MethodList(InterfaceSchema parent, List<schema::Method>::Reader list)
: parent(parent), list(list) {}
friend class InterfaceSchema;
};
class InterfaceSchema::SuperclassList {
public:
SuperclassList() = default; // empty list
inline uint size() const { return list.size(); }
InterfaceSchema operator[](uint index) const;
typedef _::IndexingIterator<const SuperclassList, InterfaceSchema> Iterator;
inline Iterator begin() const { return Iterator(this, 0); }
inline Iterator end() const { return Iterator(this, size()); }
private:
InterfaceSchema parent;
List<schema::Superclass>::Reader list;
inline SuperclassList(InterfaceSchema parent, List<schema::Superclass>::Reader list)
: parent(parent), list(list) {}
friend class InterfaceSchema;
};
// -------------------------------------------------------------------
class ConstSchema: public Schema {
// Represents a constant declaration.
//
// `ConstSchema` can be implicitly cast to DynamicValue to read its value.
public:
inline ConstSchema(): Schema(&_::NULL_CONST_SCHEMA.defaultBrand) {}
template <typename T>
ReaderFor<T> as() const;
// Read the constant's value. This is a convenience method equivalent to casting the ConstSchema
// to a DynamicValue and then calling its `as<T>()` method. For dependency reasons, this method
// is defined in <capnp/dynamic.h>, which you must #include explicitly.
uint32_t getValueSchemaOffset() const;
// Much like StructSchema::Field::getDefaultValueSchemaOffset(), if the constant has pointer
// type, this gets the offset from the beginning of the constant's schema node to a pointer
// representing the constant value.
Type getType() const;
private:
ConstSchema(Schema base): Schema(base) {}
friend class Schema;
};
// -------------------------------------------------------------------
class Type {
public:
struct BrandParameter {
uint64_t scopeId;
uint index;
};
struct ImplicitParameter {
uint index;
};
inline Type();
inline Type(schema::Type::Which primitive);
inline Type(StructSchema schema);
inline Type(EnumSchema schema);
inline Type(InterfaceSchema schema);
inline Type(ListSchema schema);
inline Type(schema::Type::AnyPointer::Unconstrained::Which anyPointerKind);
inline Type(BrandParameter param);
inline Type(ImplicitParameter param);
template <typename T>
inline static Type from();
inline schema::Type::Which which() const;
StructSchema asStruct() const;
EnumSchema asEnum() const;
InterfaceSchema asInterface() const;
ListSchema asList() const;
// Each of these methods may only be called if which() returns the corresponding type.
kj::Maybe<BrandParameter> getBrandParameter() const;
// Only callable if which() returns ANY_POINTER. Returns null if the type is just a regular
// AnyPointer and not a parameter.
kj::Maybe<ImplicitParameter> getImplicitParameter() const;
// Only callable if which() returns ANY_POINTER. Returns null if the type is just a regular
// AnyPointer and not a parameter. "Implicit parameters" refer to type parameters on methods.
inline schema::Type::AnyPointer::Unconstrained::Which whichAnyPointerKind() const;
// Only callable if which() returns ANY_POINTER.
inline bool isVoid() const;
inline bool isBool() const;
inline bool isInt8() const;
inline bool isInt16() const;
inline bool isInt32() const;
inline bool isInt64() const;
inline bool isUInt8() const;
inline bool isUInt16() const;
inline bool isUInt32() const;
inline bool isUInt64() const;
inline bool isFloat32() const;
inline bool isFloat64() const;
inline bool isText() const;
inline bool isData() const;
inline bool isList() const;
inline bool isEnum() const;
inline bool isStruct() const;
inline bool isInterface() const;
inline bool isAnyPointer() const;
bool operator==(const Type& other) const;
inline bool operator!=(const Type& other) const { return !(*this == other); }
size_t hashCode() const;
inline Type wrapInList(uint depth = 1) const;
// Return the Type formed by wrapping this type in List() `depth` times.
inline Type(schema::Type::Which derived, const _::RawBrandedSchema* schema);
// For internal use.
private:
schema::Type::Which baseType; // type not including applications of List()
uint8_t listDepth; // 0 for T, 1 for List(T), 2 for List(List(T)), ...
bool isImplicitParam;
// If true, this refers to an implicit method parameter. baseType must be ANY_POINTER, scopeId
// must be zero, and paramIndex indicates the parameter index.
union {
uint16_t paramIndex;
// If baseType is ANY_POINTER but this Type actually refers to a type parameter, this is the
// index of the parameter among the parameters at its scope, and `scopeId` below is the type ID
// of the scope where the parameter was defined.
schema::Type::AnyPointer::Unconstrained::Which anyPointerKind;
// If scopeId is zero and isImplicitParam is false.
};
union {
const _::RawBrandedSchema* schema; // if type is struct, enum, interface...
uint64_t scopeId; // if type is AnyPointer but it's actually a type parameter...
};
Type(schema::Type::Which baseType, uint8_t listDepth, const _::RawBrandedSchema* schema)
: baseType(baseType), listDepth(listDepth), schema(schema) {
KJ_IREQUIRE(baseType != schema::Type::ANY_POINTER);
}
void requireUsableAs(Type expected) const;
friend class ListSchema; // only for requireUsableAs()
};
// -------------------------------------------------------------------
class ListSchema {
// ListSchema is a little different because list types are not described by schema nodes. So,
// ListSchema doesn't subclass Schema.
public:
ListSchema() = default;
static ListSchema of(schema::Type::Which primitiveType);
static ListSchema of(StructSchema elementType);
static ListSchema of(EnumSchema elementType);
static ListSchema of(InterfaceSchema elementType);
static ListSchema of(ListSchema elementType);
static ListSchema of(Type elementType);
// Construct the schema for a list of the given type.
static ListSchema of(schema::Type::Reader elementType, Schema context)
KJ_DEPRECATED("Does not handle generics correctly.");
// DEPRECATED: This method cannot correctly account for generic type parameter bindings that
// may apply to the input type. Instead of using this method, use a method of the Schema API
// that corresponds to the exact kind of dependency. For example, to get a field type, use
// StructSchema::Field::getType().
//
// Construct from an element type schema. Requires a context which can handle getDependency()
// requests for any type ID found in the schema.
Type getElementType() const;
inline schema::Type::Which whichElementType() const;
// Get the element type's "which()". ListSchema does not actually store a schema::Type::Reader
// describing the element type, but if it did, this would be equivalent to calling
// .getBody().which() on that type.
StructSchema getStructElementType() const;
EnumSchema getEnumElementType() const;
InterfaceSchema getInterfaceElementType() const;
ListSchema getListElementType() const;
// Get the schema for complex element types. Each of these throws an exception if the element
// type is not of the requested kind.
inline bool operator==(const ListSchema& other) const { return elementType == other.elementType; }
inline bool operator!=(const ListSchema& other) const { return elementType != other.elementType; }
template <typename T>
void requireUsableAs() const;
private:
Type elementType;
inline explicit ListSchema(Type elementType): elementType(elementType) {}
template <typename T>
struct FromImpl;
template <typename T> static inline ListSchema fromImpl() {
return FromImpl<T>::get();
}
void requireUsableAs(ListSchema expected) const;
friend class Schema;
};
// =======================================================================================
// inline implementation
template <> inline schema::Type::Which Schema::from<Void>() { return schema::Type::VOID; }
template <> inline schema::Type::Which Schema::from<bool>() { return schema::Type::BOOL; }
template <> inline schema::Type::Which Schema::from<int8_t>() { return schema::Type::INT8; }
template <> inline schema::Type::Which Schema::from<int16_t>() { return schema::Type::INT16; }
template <> inline schema::Type::Which Schema::from<int32_t>() { return schema::Type::INT32; }
template <> inline schema::Type::Which Schema::from<int64_t>() { return schema::Type::INT64; }
template <> inline schema::Type::Which Schema::from<uint8_t>() { return schema::Type::UINT8; }
template <> inline schema::Type::Which Schema::from<uint16_t>() { return schema::Type::UINT16; }
template <> inline schema::Type::Which Schema::from<uint32_t>() { return schema::Type::UINT32; }
template <> inline schema::Type::Which Schema::from<uint64_t>() { return schema::Type::UINT64; }
template <> inline schema::Type::Which Schema::from<float>() { return schema::Type::FLOAT32; }
template <> inline schema::Type::Which Schema::from<double>() { return schema::Type::FLOAT64; }
template <> inline schema::Type::Which Schema::from<Text>() { return schema::Type::TEXT; }
template <> inline schema::Type::Which Schema::from<Data>() { return schema::Type::DATA; }
inline Schema Schema::getDependency(uint64_t id) const {
return getDependency(id, 0);
}
inline bool Schema::isBranded() const {
return raw != &raw->generic->defaultBrand;
}
inline Schema Schema::getGeneric() const {
return Schema(&raw->generic->defaultBrand);
}
template <typename T>
inline void Schema::requireUsableAs() const {
requireUsableAs(&_::rawSchema<T>());
}
inline bool StructSchema::Field::operator==(const Field& other) const {
return parent == other.parent && index == other.index;
}
inline bool EnumSchema::Enumerant::operator==(const Enumerant& other) const {
return parent == other.parent && ordinal == other.ordinal;
}
inline bool InterfaceSchema::Method::operator==(const Method& other) const {
return parent == other.parent && ordinal == other.ordinal;
}
inline ListSchema ListSchema::of(StructSchema elementType) {
return ListSchema(Type(elementType));
}
inline ListSchema ListSchema::of(EnumSchema elementType) {
return ListSchema(Type(elementType));
}
inline ListSchema ListSchema::of(InterfaceSchema elementType) {
return ListSchema(Type(elementType));
}
inline ListSchema ListSchema::of(ListSchema elementType) {
return ListSchema(Type(elementType));
}
inline ListSchema ListSchema::of(Type elementType) {
return ListSchema(elementType);
}
inline Type ListSchema::getElementType() const {
return elementType;
}
inline schema::Type::Which ListSchema::whichElementType() const {
return elementType.which();
}
inline StructSchema ListSchema::getStructElementType() const {
return elementType.asStruct();
}
inline EnumSchema ListSchema::getEnumElementType() const {
return elementType.asEnum();
}
inline InterfaceSchema ListSchema::getInterfaceElementType() const {
return elementType.asInterface();
}
inline ListSchema ListSchema::getListElementType() const {
return elementType.asList();
}
template <typename T>
inline void ListSchema::requireUsableAs() const {
static_assert(kind<T>() == Kind::LIST,
"ListSchema::requireUsableAs<T>() requires T is a list type.");
requireUsableAs(Schema::from<T>());
}
inline void ListSchema::requireUsableAs(ListSchema expected) const {
elementType.requireUsableAs(expected.elementType);
}
template <typename T>
struct ListSchema::FromImpl<List<T>> {
static inline ListSchema get() { return of(Schema::from<T>()); }
};
inline Type::Type(): baseType(schema::Type::VOID), listDepth(0), schema(nullptr) {}
inline Type::Type(schema::Type::Which primitive)
: baseType(primitive), listDepth(0), isImplicitParam(false) {
KJ_IREQUIRE(primitive != schema::Type::STRUCT &&
primitive != schema::Type::ENUM &&
primitive != schema::Type::INTERFACE &&
primitive != schema::Type::LIST);
if (primitive == schema::Type::ANY_POINTER) {
scopeId = 0;
anyPointerKind = schema::Type::AnyPointer::Unconstrained::ANY_KIND;
} else {
schema = nullptr;
}
}
inline Type::Type(schema::Type::Which derived, const _::RawBrandedSchema* schema)
: baseType(derived), listDepth(0), isImplicitParam(false), schema(schema) {
KJ_IREQUIRE(derived == schema::Type::STRUCT ||
derived == schema::Type::ENUM ||
derived == schema::Type::INTERFACE);
}
inline Type::Type(StructSchema schema)
: baseType(schema::Type::STRUCT), listDepth(0), schema(schema.raw) {}
inline Type::Type(EnumSchema schema)
: baseType(schema::Type::ENUM), listDepth(0), schema(schema.raw) {}
inline Type::Type(InterfaceSchema schema)
: baseType(schema::Type::INTERFACE), listDepth(0), schema(schema.raw) {}
inline Type::Type(ListSchema schema)
: Type(schema.getElementType()) { ++listDepth; }
inline Type::Type(schema::Type::AnyPointer::Unconstrained::Which anyPointerKind)
: baseType(schema::Type::ANY_POINTER), listDepth(0), isImplicitParam(false),
anyPointerKind(anyPointerKind), scopeId(0) {}
inline Type::Type(BrandParameter param)
: baseType(schema::Type::ANY_POINTER), listDepth(0), isImplicitParam(false),
paramIndex(param.index), scopeId(param.scopeId) {}
inline Type::Type(ImplicitParameter param)
: baseType(schema::Type::ANY_POINTER), listDepth(0), isImplicitParam(true),
paramIndex(param.index), scopeId(0) {}
inline schema::Type::Which Type::which() const {
return listDepth > 0 ? schema::Type::LIST : baseType;
}
inline schema::Type::AnyPointer::Unconstrained::Which Type::whichAnyPointerKind() const {
KJ_IREQUIRE(baseType == schema::Type::ANY_POINTER);
return !isImplicitParam && scopeId == 0 ? anyPointerKind
: schema::Type::AnyPointer::Unconstrained::ANY_KIND;
}
template <typename T>
inline Type Type::from() { return Type(Schema::from<T>()); }
inline bool Type::isVoid () const { return baseType == schema::Type::VOID && listDepth == 0; }
inline bool Type::isBool () const { return baseType == schema::Type::BOOL && listDepth == 0; }
inline bool Type::isInt8 () const { return baseType == schema::Type::INT8 && listDepth == 0; }
inline bool Type::isInt16 () const { return baseType == schema::Type::INT16 && listDepth == 0; }
inline bool Type::isInt32 () const { return baseType == schema::Type::INT32 && listDepth == 0; }
inline bool Type::isInt64 () const { return baseType == schema::Type::INT64 && listDepth == 0; }
inline bool Type::isUInt8 () const { return baseType == schema::Type::UINT8 && listDepth == 0; }
inline bool Type::isUInt16 () const { return baseType == schema::Type::UINT16 && listDepth == 0; }
inline bool Type::isUInt32 () const { return baseType == schema::Type::UINT32 && listDepth == 0; }
inline bool Type::isUInt64 () const { return baseType == schema::Type::UINT64 && listDepth == 0; }
inline bool Type::isFloat32() const { return baseType == schema::Type::FLOAT32 && listDepth == 0; }
inline bool Type::isFloat64() const { return baseType == schema::Type::FLOAT64 && listDepth == 0; }
inline bool Type::isText () const { return baseType == schema::Type::TEXT && listDepth == 0; }
inline bool Type::isData () const { return baseType == schema::Type::DATA && listDepth == 0; }
inline bool Type::isList () const { return listDepth > 0; }
inline bool Type::isEnum () const { return baseType == schema::Type::ENUM && listDepth == 0; }
inline bool Type::isStruct () const { return baseType == schema::Type::STRUCT && listDepth == 0; }
inline bool Type::isInterface() const {
return baseType == schema::Type::INTERFACE && listDepth == 0;
}
inline bool Type::isAnyPointer() const {
return baseType == schema::Type::ANY_POINTER && listDepth == 0;
}
inline Type Type::wrapInList(uint depth) const {
Type result = *this;
result.listDepth += depth;
return result;
}
} // namespace capnp
#endif // CAPNP_SCHEMA_H_

View File

@ -1,64 +0,0 @@
// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#ifndef CAPNP_SERIALIZE_ASYNC_H_
#define CAPNP_SERIALIZE_ASYNC_H_
#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS)
#pragma GCC system_header
#endif
#include <kj/async-io.h>
#include "message.h"
namespace capnp {
kj::Promise<kj::Own<MessageReader>> readMessage(
kj::AsyncInputStream& input, ReaderOptions options = ReaderOptions(),
kj::ArrayPtr<word> scratchSpace = nullptr);
// Read a message asynchronously.
//
// `input` must remain valid until the returned promise resolves (or is canceled).
//
// `scratchSpace`, if provided, must remain valid until the returned MessageReader is destroyed.
kj::Promise<kj::Maybe<kj::Own<MessageReader>>> tryReadMessage(
kj::AsyncInputStream& input, ReaderOptions options = ReaderOptions(),
kj::ArrayPtr<word> scratchSpace = nullptr);
// Like `readMessage` but returns null on EOF.
kj::Promise<void> writeMessage(kj::AsyncOutputStream& output,
kj::ArrayPtr<const kj::ArrayPtr<const word>> segments)
KJ_WARN_UNUSED_RESULT;
kj::Promise<void> writeMessage(kj::AsyncOutputStream& output, MessageBuilder& builder)
KJ_WARN_UNUSED_RESULT;
// Write asynchronously. The parameters must remain valid until the returned promise resolves.
// =======================================================================================
// inline implementation details
inline kj::Promise<void> writeMessage(kj::AsyncOutputStream& output, MessageBuilder& builder) {
return writeMessage(output, builder.getSegmentsForOutput());
}
} // namespace capnp
#endif // CAPNP_SERIALIZE_ASYNC_H_

View File

@ -1,130 +0,0 @@
// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#ifndef CAPNP_SERIALIZE_PACKED_H_
#define CAPNP_SERIALIZE_PACKED_H_
#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS)
#pragma GCC system_header
#endif
#include "serialize.h"
namespace capnp {
namespace _ { // private
class PackedInputStream: public kj::InputStream {
// An input stream that unpacks packed data with a picky constraint: The caller must read data
// in the exact same size and sequence as the data was written to PackedOutputStream.
public:
explicit PackedInputStream(kj::BufferedInputStream& inner);
KJ_DISALLOW_COPY(PackedInputStream);
~PackedInputStream() noexcept(false);
// implements InputStream ------------------------------------------
size_t tryRead(void* buffer, size_t minBytes, size_t maxBytes) override;
void skip(size_t bytes) override;
private:
kj::BufferedInputStream& inner;
};
class PackedOutputStream: public kj::OutputStream {
public:
explicit PackedOutputStream(kj::BufferedOutputStream& inner);
KJ_DISALLOW_COPY(PackedOutputStream);
~PackedOutputStream() noexcept(false);
// implements OutputStream -----------------------------------------
void write(const void* buffer, size_t bytes) override;
private:
kj::BufferedOutputStream& inner;
};
} // namespace _ (private)
class PackedMessageReader: private _::PackedInputStream, public InputStreamMessageReader {
public:
PackedMessageReader(kj::BufferedInputStream& inputStream, ReaderOptions options = ReaderOptions(),
kj::ArrayPtr<word> scratchSpace = nullptr);
KJ_DISALLOW_COPY(PackedMessageReader);
~PackedMessageReader() noexcept(false);
};
class PackedFdMessageReader: private kj::FdInputStream, private kj::BufferedInputStreamWrapper,
public PackedMessageReader {
public:
PackedFdMessageReader(int fd, ReaderOptions options = ReaderOptions(),
kj::ArrayPtr<word> scratchSpace = nullptr);
// Read message from a file descriptor, without taking ownership of the descriptor.
// Note that if you want to reuse the descriptor after the reader is destroyed, you'll need to
// seek it, since otherwise the position is unspecified.
PackedFdMessageReader(kj::AutoCloseFd fd, ReaderOptions options = ReaderOptions(),
kj::ArrayPtr<word> scratchSpace = nullptr);
// Read a message from a file descriptor, taking ownership of the descriptor.
KJ_DISALLOW_COPY(PackedFdMessageReader);
~PackedFdMessageReader() noexcept(false);
};
void writePackedMessage(kj::BufferedOutputStream& output, MessageBuilder& builder);
void writePackedMessage(kj::BufferedOutputStream& output,
kj::ArrayPtr<const kj::ArrayPtr<const word>> segments);
// Write a packed message to a buffered output stream.
void writePackedMessage(kj::OutputStream& output, MessageBuilder& builder);
void writePackedMessage(kj::OutputStream& output,
kj::ArrayPtr<const kj::ArrayPtr<const word>> segments);
// Write a packed message to an unbuffered output stream. If you intend to write multiple messages
// in succession, consider wrapping your output in a buffered stream in order to reduce system
// call overhead.
void writePackedMessageToFd(int fd, MessageBuilder& builder);
void writePackedMessageToFd(int fd, kj::ArrayPtr<const kj::ArrayPtr<const word>> segments);
// Write a single packed message to the file descriptor.
size_t computeUnpackedSizeInWords(kj::ArrayPtr<const byte> packedBytes);
// Computes the number of words to which the given packed bytes will unpack. Not intended for use
// in performance-sensitive situations.
// =======================================================================================
// inline stuff
inline void writePackedMessage(kj::BufferedOutputStream& output, MessageBuilder& builder) {
writePackedMessage(output, builder.getSegmentsForOutput());
}
inline void writePackedMessage(kj::OutputStream& output, MessageBuilder& builder) {
writePackedMessage(output, builder.getSegmentsForOutput());
}
inline void writePackedMessageToFd(int fd, MessageBuilder& builder) {
writePackedMessageToFd(fd, builder.getSegmentsForOutput());
}
} // namespace capnp
#endif // CAPNP_SERIALIZE_PACKED_H_

View File

@ -1,96 +0,0 @@
// Copyright (c) 2015 Philip Quinn.
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#ifndef CAPNP_SERIALIZE_TEXT_H_
#define CAPNP_SERIALIZE_TEXT_H_
#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS)
#pragma GCC system_header
#endif
#include <kj/string.h>
#include "dynamic.h"
#include "orphan.h"
#include "schema.h"
namespace capnp {
class TextCodec {
// Reads and writes Cap'n Proto objects in a plain text format (as used in the schema
// language for constants, and read/written by the 'decode' and 'encode' commands of
// the capnp tool).
//
// This format is useful for debugging or human input, but it is not a robust alternative
// to the binary format. Changes to a schema's types or names that are permitted in a
// schema's binary evolution will likely break messages stored in this format.
//
// Note that definitions or references (to constants, other fields, or files) are not
// permitted in this format. To evaluate declarations with the full expressiveness of the
// schema language, see `capnp::SchemaParser`.
//
// Requires linking with the capnpc library.
public:
TextCodec();
~TextCodec() noexcept(true);
void setPrettyPrint(bool enabled);
// If enabled, pads the output of `encode()` with spaces and newlines to make it more
// human-readable.
template <typename T>
kj::String encode(T&& value) const;
kj::String encode(DynamicValue::Reader value) const;
// Encode any Cap'n Proto value.
template <typename T>
Orphan<T> decode(kj::StringPtr input, Orphanage orphanage) const;
// Decode a text message into a Cap'n Proto object of type T, allocated in the given
// orphanage. Any errors parsing the input or assigning the fields of T are thrown as
// exceptions.
void decode(kj::StringPtr input, DynamicStruct::Builder output) const;
// Decode a text message for a struct into the given builder. Any errors parsing the
// input or assigning the fields of the output are thrown as exceptions.
// TODO(someday): expose some control over the error handling?
private:
Orphan<DynamicValue> decode(kj::StringPtr input, Type type, Orphanage orphanage) const;
bool prettyPrint;
};
// =======================================================================================
// inline stuff
template <typename T>
inline kj::String TextCodec::encode(T&& value) const {
return encode(DynamicValue::Reader(ReaderFor<FromAny<T>>(kj::fwd<T>(value))));
}
template <typename T>
inline Orphan<T> TextCodec::decode(kj::StringPtr input, Orphanage orphanage) const {
return decode(input, Type::from<T>(), orphanage).template releaseAs<T>();
}
} // namespace capnp
#endif // CAPNP_SERIALIZE_TEXT_H_

View File

@ -1,237 +0,0 @@
// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
// This file implements a simple serialization format for Cap'n Proto messages. The format
// is as follows:
//
// * 32-bit little-endian segment count (4 bytes).
// * 32-bit little-endian size of each segment (4*(segment count) bytes).
// * Padding so that subsequent data is 64-bit-aligned (0 or 4 bytes). (I.e., if there are an even
// number of segments, there are 4 bytes of zeros here, otherwise there is no padding.)
// * Data from each segment, in order (8*sum(segment sizes) bytes)
//
// This format has some important properties:
// - It is self-delimiting, so multiple messages may be written to a stream without any external
// delimiter.
// - The total size and position of each segment can be determined by reading only the first part
// of the message, allowing lazy and random-access reading of the segment data.
// - A message is always at least 8 bytes.
// - A single-segment message can be read entirely in two system calls with no buffering.
// - A multi-segment message can be read entirely in three system calls with no buffering.
// - The format is appropriate for mmap()ing since all data is aligned.
#ifndef CAPNP_SERIALIZE_H_
#define CAPNP_SERIALIZE_H_
#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS)
#pragma GCC system_header
#endif
#include "message.h"
#include <kj/io.h>
namespace capnp {
class FlatArrayMessageReader: public MessageReader {
// Parses a message from a flat array. Note that it makes sense to use this together with mmap()
// for extremely fast parsing.
public:
FlatArrayMessageReader(kj::ArrayPtr<const word> array, ReaderOptions options = ReaderOptions());
// The array must remain valid until the MessageReader is destroyed.
kj::ArrayPtr<const word> getSegment(uint id) override;
const word* getEnd() const { return end; }
// Get a pointer just past the end of the message as determined by reading the message header.
// This could actually be before the end of the input array. This pointer is useful e.g. if
// you know that the input array has extra stuff appended after the message and you want to
// get at it.
private:
// Optimize for single-segment case.
kj::ArrayPtr<const word> segment0;
kj::Array<kj::ArrayPtr<const word>> moreSegments;
const word* end;
};
kj::ArrayPtr<const word> initMessageBuilderFromFlatArrayCopy(
kj::ArrayPtr<const word> array, MessageBuilder& target,
ReaderOptions options = ReaderOptions());
// Convenience function which reads a message using `FlatArrayMessageReader` then copies the
// content into the target `MessageBuilder`, verifying that the message structure is valid
// (although not necessarily that it matches the desired schema).
//
// Returns an ArrayPtr containing any words left over in the array after consuming the whole
// message. This is useful when reading multiple messages that have been concatenated. See also
// FlatArrayMessageReader::getEnd().
//
// (Note that it's also possible to initialize a `MessageBuilder` directly without a copy using one
// of `MessageBuilder`'s constructors. However, this approach skips the validation step and is not
// safe to use on untrusted input. Therefore, we do not provide a convenience method for it.)
kj::Array<word> messageToFlatArray(MessageBuilder& builder);
// Constructs a flat array containing the entire content of the given message.
//
// To output the message as bytes, use `.asBytes()` on the returned word array. Keep in mind that
// `asBytes()` returns an ArrayPtr, so you have to save the Array as well to prevent it from being
// deleted. For example:
//
// kj::Array<capnp::word> words = messageToFlatArray(myMessage);
// kj::ArrayPtr<kj::byte> bytes = words.asBytes();
// write(fd, bytes.begin(), bytes.size());
kj::Array<word> messageToFlatArray(kj::ArrayPtr<const kj::ArrayPtr<const word>> segments);
// Version of messageToFlatArray that takes a raw segment array.
size_t computeSerializedSizeInWords(MessageBuilder& builder);
// Returns the size, in words, that will be needed to serialize the message, including the header.
size_t computeSerializedSizeInWords(kj::ArrayPtr<const kj::ArrayPtr<const word>> segments);
// Version of computeSerializedSizeInWords that takes a raw segment array.
size_t expectedSizeInWordsFromPrefix(kj::ArrayPtr<const word> messagePrefix);
// Given a prefix of a serialized message, try to determine the expected total size of the message,
// in words. The returned size is based on the information known so far; it may be an underestimate
// if the prefix doesn't contain the full segment table.
//
// If the returned value is greater than `messagePrefix.size()`, then the message is not yet
// complete and the app cannot parse it yet. If the returned value is less than or equal to
// `messagePrefix.size()`, then the returned value is the exact total size of the message; any
// remaining bytes are part of the next message.
//
// This function is useful when reading messages from a stream in an asynchronous way, but when
// using the full KJ async infrastructure would be too difficult. Each time bytes are received,
// use this function to determine if an entire message is ready to be parsed.
// =======================================================================================
class InputStreamMessageReader: public MessageReader {
// A MessageReader that reads from an abstract kj::InputStream. See also StreamFdMessageReader
// for a subclass specific to file descriptors.
public:
InputStreamMessageReader(kj::InputStream& inputStream,
ReaderOptions options = ReaderOptions(),
kj::ArrayPtr<word> scratchSpace = nullptr);
~InputStreamMessageReader() noexcept(false);
// implements MessageReader ----------------------------------------
kj::ArrayPtr<const word> getSegment(uint id) override;
private:
kj::InputStream& inputStream;
byte* readPos;
// Optimize for single-segment case.
kj::ArrayPtr<const word> segment0;
kj::Array<kj::ArrayPtr<const word>> moreSegments;
kj::Array<word> ownedSpace;
// Only if scratchSpace wasn't big enough.
kj::UnwindDetector unwindDetector;
};
void readMessageCopy(kj::InputStream& input, MessageBuilder& target,
ReaderOptions options = ReaderOptions(),
kj::ArrayPtr<word> scratchSpace = nullptr);
// Convenience function which reads a message using `InputStreamMessageReader` then copies the
// content into the target `MessageBuilder`, verifying that the message structure is valid
// (although not necessarily that it matches the desired schema).
//
// (Note that it's also possible to initialize a `MessageBuilder` directly without a copy using one
// of `MessageBuilder`'s constructors. However, this approach skips the validation step and is not
// safe to use on untrusted input. Therefore, we do not provide a convenience method for it.)
void writeMessage(kj::OutputStream& output, MessageBuilder& builder);
// Write the message to the given output stream.
void writeMessage(kj::OutputStream& output, kj::ArrayPtr<const kj::ArrayPtr<const word>> segments);
// Write the segment array to the given output stream.
// =======================================================================================
// Specializations for reading from / writing to file descriptors.
class StreamFdMessageReader: private kj::FdInputStream, public InputStreamMessageReader {
// A MessageReader that reads from a steam-based file descriptor.
public:
StreamFdMessageReader(int fd, ReaderOptions options = ReaderOptions(),
kj::ArrayPtr<word> scratchSpace = nullptr)
: FdInputStream(fd), InputStreamMessageReader(*this, options, scratchSpace) {}
// Read message from a file descriptor, without taking ownership of the descriptor.
StreamFdMessageReader(kj::AutoCloseFd fd, ReaderOptions options = ReaderOptions(),
kj::ArrayPtr<word> scratchSpace = nullptr)
: FdInputStream(kj::mv(fd)), InputStreamMessageReader(*this, options, scratchSpace) {}
// Read a message from a file descriptor, taking ownership of the descriptor.
~StreamFdMessageReader() noexcept(false);
};
void readMessageCopyFromFd(int fd, MessageBuilder& target,
ReaderOptions options = ReaderOptions(),
kj::ArrayPtr<word> scratchSpace = nullptr);
// Convenience function which reads a message using `StreamFdMessageReader` then copies the
// content into the target `MessageBuilder`, verifying that the message structure is valid
// (although not necessarily that it matches the desired schema).
//
// (Note that it's also possible to initialize a `MessageBuilder` directly without a copy using one
// of `MessageBuilder`'s constructors. However, this approach skips the validation step and is not
// safe to use on untrusted input. Therefore, we do not provide a convenience method for it.)
void writeMessageToFd(int fd, MessageBuilder& builder);
// Write the message to the given file descriptor.
//
// This function throws an exception on any I/O error. If your code is not exception-safe, be sure
// you catch this exception at the call site. If throwing an exception is not acceptable, you
// can implement your own OutputStream with arbitrary error handling and then use writeMessage().
void writeMessageToFd(int fd, kj::ArrayPtr<const kj::ArrayPtr<const word>> segments);
// Write the segment array to the given file descriptor.
//
// This function throws an exception on any I/O error. If your code is not exception-safe, be sure
// you catch this exception at the call site. If throwing an exception is not acceptable, you
// can implement your own OutputStream with arbitrary error handling and then use writeMessage().
// =======================================================================================
// inline stuff
inline kj::Array<word> messageToFlatArray(MessageBuilder& builder) {
return messageToFlatArray(builder.getSegmentsForOutput());
}
inline size_t computeSerializedSizeInWords(MessageBuilder& builder) {
return computeSerializedSizeInWords(builder.getSegmentsForOutput());
}
inline void writeMessage(kj::OutputStream& output, MessageBuilder& builder) {
writeMessage(output, builder.getSegmentsForOutput());
}
inline void writeMessageToFd(int fd, MessageBuilder& builder) {
writeMessageToFd(fd, builder.getSegmentsForOutput());
}
} // namespace capnp
#endif // SERIALIZE_H_

View File

@ -1,426 +0,0 @@
/* vim: set sw=8 ts=8 sts=8 noet: */
/* capnp_c.h
*
* Copyright (C) 2013 James McKaskill
* Copyright (C) 2014 Steve Dee
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
#ifndef CAPNP_C_H
#define CAPNP_C_H
#include <stdint.h>
#include <stdio.h>
#if defined(unix) && !defined(__APPLE__)
#include <endian.h>
#endif
// ssize_t is not defined in stdint.h in MSVC.
#ifdef _MSC_VER
typedef intmax_t ssize_t;
#endif
#ifdef __cplusplus
extern "C" {
#endif
#if defined(__cplusplus) || (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L)
#define CAPN_INLINE static inline
#else
#define CAPN_INLINE static
#endif
#define CAPN_VERSION 1
/* struct capn is a common structure shared between segments in the same
* session/context so that far pointers between segments will be created.
*
* lookup is used to lookup segments by id when derefencing a far pointer
*
* create is used to create or lookup an alternate segment that has at least
* sz available (ie returned seg->len + sz <= seg->cap)
*
* create_local is used to create a segment for the copy tree and should be
* allocated in the local memory space.
*
* Allocated segments must be zero initialized.
*
* create and lookup can be NULL if you don't need multiple segments and don't
* want to support copying
*
* seglist and copylist are linked lists which can be used to free up segments
* on cleanup, but should not be modified by the user.
*
* lookup, create, create_local, and user can be set by the user. Other values
* should be zero initialized.
*/
struct capn {
/* user settable */
struct capn_segment *(*lookup)(void* /*user*/, uint32_t /*id */);
struct capn_segment *(*create)(void* /*user*/, uint32_t /*id */, int /*sz*/);
struct capn_segment *(*create_local)(void* /*user*/, int /*sz*/);
void *user;
/* zero initialized, user should not modify */
uint32_t segnum;
struct capn_tree *copy;
struct capn_tree *segtree;
struct capn_segment *seglist, *lastseg;
struct capn_segment *copylist;
};
/* struct capn_tree is a rb tree header used internally for the segment id
* lookup and copy tree */
struct capn_tree {
struct capn_tree *parent, *link[2];
unsigned int red : 1;
};
struct capn_tree *capn_tree_insert(struct capn_tree *root, struct capn_tree *n);
/* struct capn_segment contains the information about a single segment.
*
* capn points to a struct capn that is shared between segments in the
* same session
*
* id specifies the segment id, used for far pointers
*
* data specifies the segment data. This should not move after creation.
*
* len specifies the current segment length. This is 0 for a blank
* segment.
*
* cap specifies the segment capacity.
*
* When creating new structures len will be incremented until it reaces cap,
* at which point a new segment will be requested via capn->create. The
* create callback can either create a new segment or expand an existing
* one by incrementing cap and returning the expanded segment.
*
* data, len, and cap must all by 8 byte aligned
*
* data, len, cap, and user should all set by the user. Other values
* should be zero initialized.
*/
#ifdef _MSC_VER
__declspec(align(64))
#endif
struct capn_segment {
struct capn_tree hdr;
struct capn_segment *next;
struct capn *capn;
uint32_t id;
/* user settable */
char *data;
size_t len, cap;
void *user;
};
enum CAPN_TYPE {
CAPN_NULL = 0,
CAPN_STRUCT = 1,
CAPN_LIST = 2,
CAPN_PTR_LIST = 3,
CAPN_BIT_LIST = 4,
CAPN_FAR_POINTER = 5,
};
struct capn_ptr {
unsigned int type : 4;
unsigned int has_ptr_tag : 1;
unsigned int is_list_member : 1;
unsigned int is_composite_list : 1;
unsigned int datasz : 19;
unsigned int ptrs : 16;
int len;
char *data;
struct capn_segment *seg;
};
struct capn_text {
int len;
const char *str;
struct capn_segment *seg;
};
typedef struct capn_ptr capn_ptr;
typedef struct capn_text capn_text;
typedef struct {capn_ptr p;} capn_data;
typedef struct {capn_ptr p;} capn_list1;
typedef struct {capn_ptr p;} capn_list8;
typedef struct {capn_ptr p;} capn_list16;
typedef struct {capn_ptr p;} capn_list32;
typedef struct {capn_ptr p;} capn_list64;
struct capn_msg {
struct capn_segment *seg;
uint64_t iface;
uint16_t method;
capn_ptr args;
};
/* capn_append_segment appends a segment to a session */
void capn_append_segment(struct capn*, struct capn_segment*);
capn_ptr capn_root(struct capn *c);
void capn_resolve(capn_ptr *p);
#define capn_len(list) ((list).p.type == CAPN_FAR_POINTER ? (capn_resolve(&(list).p), (list).p.len) : (list).p.len)
/* capn_getp|setp functions get/set ptrs in list/structs
* off is the list index or pointer index in a struct
* capn_setp will copy the data, create far pointers, etc if the target
* is in a different segment/context.
* Both of these will use/return inner pointers for composite lists.
*/
capn_ptr capn_getp(capn_ptr p, int off, int resolve);
int capn_setp(capn_ptr p, int off, capn_ptr tgt);
capn_text capn_get_text(capn_ptr p, int off, capn_text def);
capn_data capn_get_data(capn_ptr p, int off);
int capn_set_text(capn_ptr p, int off, capn_text tgt);
/* capn_get* functions get data from a list
* The length of the list is given by p->size
* off specifies how far into the list to start
* sz indicates the number of elements to get
* The function returns the number of elements read or -1 on an error.
* off must be byte aligned for capn_getv1
*/
int capn_get1(capn_list1 p, int off);
uint8_t capn_get8(capn_list8 p, int off);
uint16_t capn_get16(capn_list16 p, int off);
uint32_t capn_get32(capn_list32 p, int off);
uint64_t capn_get64(capn_list64 p, int off);
int capn_getv1(capn_list1 p, int off, uint8_t *data, int sz);
int capn_getv8(capn_list8 p, int off, uint8_t *data, int sz);
int capn_getv16(capn_list16 p, int off, uint16_t *data, int sz);
int capn_getv32(capn_list32 p, int off, uint32_t *data, int sz);
int capn_getv64(capn_list64 p, int off, uint64_t *data, int sz);
/* capn_set* functions set data in a list
* off specifies how far into the list to start
* sz indicates the number of elements to write
* The function returns the number of elemnts written or -1 on an error.
* off must be byte aligned for capn_setv1
*/
int capn_set1(capn_list1 p, int off, int v);
int capn_set8(capn_list8 p, int off, uint8_t v);
int capn_set16(capn_list16 p, int off, uint16_t v);
int capn_set32(capn_list32 p, int off, uint32_t v);
int capn_set64(capn_list64 p, int off, uint64_t v);
int capn_setv1(capn_list1 p, int off, const uint8_t *data, int sz);
int capn_setv8(capn_list8 p, int off, const uint8_t *data, int sz);
int capn_setv16(capn_list16 p, int off, const uint16_t *data, int sz);
int capn_setv32(capn_list32 p, int off, const uint32_t *data, int sz);
int capn_setv64(capn_list64 p, int off, const uint64_t *data, int sz);
/* capn_new_* functions create a new object
* datasz is in bytes, ptrs is # of pointers, sz is # of elements in the list
* On an error a CAPN_NULL pointer is returned
*/
capn_ptr capn_new_string(struct capn_segment *seg, const char *str, ssize_t sz);
capn_ptr capn_new_struct(struct capn_segment *seg, int datasz, int ptrs);
capn_ptr capn_new_interface(struct capn_segment *seg, int datasz, int ptrs);
capn_ptr capn_new_ptr_list(struct capn_segment *seg, int sz);
capn_ptr capn_new_list(struct capn_segment *seg, int sz, int datasz, int ptrs);
capn_list1 capn_new_list1(struct capn_segment *seg, int sz);
capn_list8 capn_new_list8(struct capn_segment *seg, int sz);
capn_list16 capn_new_list16(struct capn_segment *seg, int sz);
capn_list32 capn_new_list32(struct capn_segment *seg, int sz);
capn_list64 capn_new_list64(struct capn_segment *seg, int sz);
/* capn_read|write* functions read/write struct values
* off is the offset into the structure in bytes
* Rarely should these be called directly, instead use the generated code.
* Data must be xored with the default value
* These are inlined
*/
CAPN_INLINE uint8_t capn_read8(capn_ptr p, int off);
CAPN_INLINE uint16_t capn_read16(capn_ptr p, int off);
CAPN_INLINE uint32_t capn_read32(capn_ptr p, int off);
CAPN_INLINE uint64_t capn_read64(capn_ptr p, int off);
CAPN_INLINE int capn_write1(capn_ptr p, int off, int val);
CAPN_INLINE int capn_write8(capn_ptr p, int off, uint8_t val);
CAPN_INLINE int capn_write16(capn_ptr p, int off, uint16_t val);
CAPN_INLINE int capn_write32(capn_ptr p, int off, uint32_t val);
CAPN_INLINE int capn_write64(capn_ptr p, int off, uint64_t val);
/* capn_init_malloc inits the capn struct with a create function which
* allocates segments on the heap using malloc
*
* capn_init_(fp|mem) inits by reading segments in from the file/memory buffer
* in serialized form (optionally packed). It will then setup the create
* function ala capn_init_malloc so that further segments can be created.
*
* capn_free frees all the segment headers and data created by the create
* function setup by capn_init_*
*/
void capn_init_malloc(struct capn *c);
int capn_init_fp(struct capn *c, FILE *f, int packed);
int capn_init_mem(struct capn *c, const uint8_t *p, size_t sz, int packed);
/* capn_write_(fp|mem) writes segments to the file/memory buffer in
* serialized form and returns the number of bytes written.
*/
/* TODO */
/*int capn_write_fp(struct capn *c, FILE *f, int packed);*/
int capn_write_fd(struct capn *c, ssize_t (*write_fd)(int fd, void *p, size_t count), int fd, int packed);
int capn_write_mem(struct capn *c, uint8_t *p, size_t sz, int packed);
void capn_free(struct capn *c);
void capn_reset_copy(struct capn *c);
/* Inline functions */
CAPN_INLINE uint8_t capn_flip8(uint8_t v) {
return v;
}
CAPN_INLINE uint16_t capn_flip16(uint16_t v) {
#if defined(__BYTE_ORDER) && (__BYTE_ORDER == __LITTLE_ENDIAN)
return v;
#elif defined(__BYTE_ORDER) && (__BYTE_ORDER == __BIG_ENDIAN) && \
defined(__GNUC__) && __GNUC__ >= 4 && __GNUC_MINOR__ >= 8
return __builtin_bswap16(v);
#else
union { uint16_t u; uint8_t v[2]; } s;
s.v[0] = (uint8_t)v;
s.v[1] = (uint8_t)(v>>8);
return s.u;
#endif
}
CAPN_INLINE uint32_t capn_flip32(uint32_t v) {
#if defined(__BYTE_ORDER) && (__BYTE_ORDER == __LITTLE_ENDIAN)
return v;
#elif defined(__BYTE_ORDER) && (__BYTE_ORDER == __BIG_ENDIAN) && \
defined(__GNUC__) && __GNUC__ >= 4 && __GNUC_MINOR__ >= 8
return __builtin_bswap32(v);
#else
union { uint32_t u; uint8_t v[4]; } s;
s.v[0] = (uint8_t)v;
s.v[1] = (uint8_t)(v>>8);
s.v[2] = (uint8_t)(v>>16);
s.v[3] = (uint8_t)(v>>24);
return s.u;
#endif
}
CAPN_INLINE uint64_t capn_flip64(uint64_t v) {
#if defined(__BYTE_ORDER) && (__BYTE_ORDER == __LITTLE_ENDIAN)
return v;
#elif defined(__BYTE_ORDER) && (__BYTE_ORDER == __BIG_ENDIAN) && \
defined(__GNUC__) && __GNUC__ >= 4 && __GNUC_MINOR__ >= 8
return __builtin_bswap64(v);
#else
union { uint64_t u; uint8_t v[8]; } s;
s.v[0] = (uint8_t)v;
s.v[1] = (uint8_t)(v>>8);
s.v[2] = (uint8_t)(v>>16);
s.v[3] = (uint8_t)(v>>24);
s.v[4] = (uint8_t)(v>>32);
s.v[5] = (uint8_t)(v>>40);
s.v[6] = (uint8_t)(v>>48);
s.v[7] = (uint8_t)(v>>56);
return s.u;
#endif
}
CAPN_INLINE int capn_write1(capn_ptr p, int off, int val) {
if (off >= p.datasz*8) {
return -1;
} else if (val) {
uint8_t tmp = (uint8_t)(1 << (off & 7));
((uint8_t*) p.data)[off >> 3] |= tmp;
return 0;
} else {
uint8_t tmp = (uint8_t)(~(1 << (off & 7)));
((uint8_t*) p.data)[off >> 3] &= tmp;
return 0;
}
}
CAPN_INLINE uint8_t capn_read8(capn_ptr p, int off) {
return off+1 <= p.datasz ? capn_flip8(*(uint8_t*) (p.data+off)) : 0;
}
CAPN_INLINE int capn_write8(capn_ptr p, int off, uint8_t val) {
if (off+1 <= p.datasz) {
*(uint8_t*) (p.data+off) = capn_flip8(val);
return 0;
} else {
return -1;
}
}
CAPN_INLINE uint16_t capn_read16(capn_ptr p, int off) {
return off+2 <= p.datasz ? capn_flip16(*(uint16_t*) (p.data+off)) : 0;
}
CAPN_INLINE int capn_write16(capn_ptr p, int off, uint16_t val) {
if (off+2 <= p.datasz) {
*(uint16_t*) (p.data+off) = capn_flip16(val);
return 0;
} else {
return -1;
}
}
CAPN_INLINE uint32_t capn_read32(capn_ptr p, int off) {
return off+4 <= p.datasz ? capn_flip32(*(uint32_t*) (p.data+off)) : 0;
}
CAPN_INLINE int capn_write32(capn_ptr p, int off, uint32_t val) {
if (off+4 <= p.datasz) {
*(uint32_t*) (p.data+off) = capn_flip32(val);
return 0;
} else {
return -1;
}
}
CAPN_INLINE uint64_t capn_read64(capn_ptr p, int off) {
return off+8 <= p.datasz ? capn_flip64(*(uint64_t*) (p.data+off)) : 0;
}
CAPN_INLINE int capn_write64(capn_ptr p, int off, uint64_t val) {
if (off+8 <= p.datasz) {
*(uint64_t*) (p.data+off) = capn_flip64(val);
return 0;
} else {
return -1;
}
}
union capn_conv_f32 {
uint32_t u;
float f;
};
union capn_conv_f64 {
uint64_t u;
double f;
};
CAPN_INLINE float capn_to_f32(uint32_t v) {
union capn_conv_f32 u;
u.u = v;
return u.f;
}
CAPN_INLINE double capn_to_f64(uint64_t v) {
union capn_conv_f64 u;
u.u = v;
return u.f;
}
CAPN_INLINE uint32_t capn_from_f32(float v) {
union capn_conv_f32 u;
u.f = v;
return u.u;
}
CAPN_INLINE uint64_t capn_from_f64(double v) {
union capn_conv_f64 u;
u.f = v;
return u.u;
}
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,213 +0,0 @@
// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#ifndef KJ_ARENA_H_
#define KJ_ARENA_H_
#if defined(__GNUC__) && !KJ_HEADER_WARNINGS
#pragma GCC system_header
#endif
#include "memory.h"
#include "array.h"
#include "string.h"
namespace kj {
class Arena {
// A class which allows several objects to be allocated in contiguous chunks of memory, then
// frees them all at once.
//
// Allocating from the same Arena in multiple threads concurrently is NOT safe, because making
// it safe would require atomic operations that would slow down allocation even when
// single-threaded. If you need to use arena allocation in a multithreaded context, consider
// allocating thread-local arenas.
public:
explicit Arena(size_t chunkSizeHint = 1024);
// Create an Arena. `chunkSizeHint` hints at where to start when allocating chunks, but is only
// a hint -- the Arena will, for example, allocate progressively larger chunks as time goes on,
// in order to reduce overall allocation overhead.
explicit Arena(ArrayPtr<byte> scratch);
// Allocates from the given scratch space first, only resorting to the heap when it runs out.
KJ_DISALLOW_COPY(Arena);
~Arena() noexcept(false);
template <typename T, typename... Params>
T& allocate(Params&&... params);
template <typename T>
ArrayPtr<T> allocateArray(size_t size);
// Allocate an object or array of type T. If T has a non-trivial destructor, that destructor
// will be run during the Arena's destructor. Such destructors are run in opposite order of
// allocation. Note that these methods must maintain a list of destructors to call, which has
// overhead, but this overhead only applies if T has a non-trivial destructor.
template <typename T, typename... Params>
Own<T> allocateOwn(Params&&... params);
template <typename T>
Array<T> allocateOwnArray(size_t size);
template <typename T>
ArrayBuilder<T> allocateOwnArrayBuilder(size_t capacity);
// Allocate an object or array of type T. Destructors are executed when the returned Own<T>
// or Array<T> goes out-of-scope, which must happen before the Arena is destroyed. This variant
// is useful when you need to control when the destructor is called. This variant also avoids
// the need for the Arena itself to keep track of destructors to call later, which may make it
// slightly more efficient.
template <typename T>
inline T& copy(T&& value) { return allocate<Decay<T>>(kj::fwd<T>(value)); }
// Allocate a copy of the given value in the arena. This is just a shortcut for calling the
// type's copy (or move) constructor.
StringPtr copyString(StringPtr content);
// Make a copy of the given string inside the arena, and return a pointer to the copy.
private:
struct ChunkHeader {
ChunkHeader* next;
byte* pos; // first unallocated byte in this chunk
byte* end; // end of this chunk
};
struct ObjectHeader {
void (*destructor)(void*);
ObjectHeader* next;
};
size_t nextChunkSize;
ChunkHeader* chunkList = nullptr;
ObjectHeader* objectList = nullptr;
ChunkHeader* currentChunk = nullptr;
void cleanup();
// Run all destructors, leaving the above pointers null. If a destructor throws, the State is
// left in a consistent state, such that if cleanup() is called again, it will pick up where
// it left off.
void* allocateBytes(size_t amount, uint alignment, bool hasDisposer);
// Allocate the given number of bytes. `hasDisposer` must be true if `setDisposer()` may be
// called on this pointer later.
void* allocateBytesInternal(size_t amount, uint alignment);
// Try to allocate the given number of bytes without taking a lock. Fails if and only if there
// is no space left in the current chunk.
void setDestructor(void* ptr, void (*destructor)(void*));
// Schedule the given destructor to be executed when the Arena is destroyed. `ptr` must be a
// pointer previously returned by an `allocateBytes()` call for which `hasDisposer` was true.
template <typename T>
static void destroyArray(void* pointer) {
size_t elementCount = *reinterpret_cast<size_t*>(pointer);
constexpr size_t prefixSize = kj::max(alignof(T), sizeof(size_t));
DestructorOnlyArrayDisposer::instance.disposeImpl(
reinterpret_cast<byte*>(pointer) + prefixSize,
sizeof(T), elementCount, elementCount, &destroyObject<T>);
}
template <typename T>
static void destroyObject(void* pointer) {
dtor(*reinterpret_cast<T*>(pointer));
}
};
// =======================================================================================
// Inline implementation details
template <typename T, typename... Params>
T& Arena::allocate(Params&&... params) {
T& result = *reinterpret_cast<T*>(allocateBytes(
sizeof(T), alignof(T), !__has_trivial_destructor(T)));
if (!__has_trivial_constructor(T) || sizeof...(Params) > 0) {
ctor(result, kj::fwd<Params>(params)...);
}
if (!__has_trivial_destructor(T)) {
setDestructor(&result, &destroyObject<T>);
}
return result;
}
template <typename T>
ArrayPtr<T> Arena::allocateArray(size_t size) {
if (__has_trivial_destructor(T)) {
ArrayPtr<T> result =
arrayPtr(reinterpret_cast<T*>(allocateBytes(
sizeof(T) * size, alignof(T), false)), size);
if (!__has_trivial_constructor(T)) {
for (size_t i = 0; i < size; i++) {
ctor(result[i]);
}
}
return result;
} else {
// Allocate with a 64-bit prefix in which we store the array size.
constexpr size_t prefixSize = kj::max(alignof(T), sizeof(size_t));
void* base = allocateBytes(sizeof(T) * size + prefixSize, alignof(T), true);
size_t& tag = *reinterpret_cast<size_t*>(base);
ArrayPtr<T> result =
arrayPtr(reinterpret_cast<T*>(reinterpret_cast<byte*>(base) + prefixSize), size);
setDestructor(base, &destroyArray<T>);
if (__has_trivial_constructor(T)) {
tag = size;
} else {
// In case of constructor exceptions, we need the tag to end up storing the number of objects
// that were successfully constructed, so that they'll be properly destroyed.
tag = 0;
for (size_t i = 0; i < size; i++) {
ctor(result[i]);
tag = i + 1;
}
}
return result;
}
}
template <typename T, typename... Params>
Own<T> Arena::allocateOwn(Params&&... params) {
T& result = *reinterpret_cast<T*>(allocateBytes(sizeof(T), alignof(T), false));
if (!__has_trivial_constructor(T) || sizeof...(Params) > 0) {
ctor(result, kj::fwd<Params>(params)...);
}
return Own<T>(&result, DestructorOnlyDisposer<T>::instance);
}
template <typename T>
Array<T> Arena::allocateOwnArray(size_t size) {
ArrayBuilder<T> result = allocateOwnArrayBuilder<T>(size);
for (size_t i = 0; i < size; i++) {
result.add();
}
return result.finish();
}
template <typename T>
ArrayBuilder<T> Arena::allocateOwnArrayBuilder(size_t capacity) {
return ArrayBuilder<T>(
reinterpret_cast<T*>(allocateBytes(sizeof(T) * capacity, alignof(T), false)),
capacity, DestructorOnlyArrayDisposer::instance);
}
} // namespace kj
#endif // KJ_ARENA_H_

View File

@ -1,813 +0,0 @@
// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#ifndef KJ_ARRAY_H_
#define KJ_ARRAY_H_
#if defined(__GNUC__) && !KJ_HEADER_WARNINGS
#pragma GCC system_header
#endif
#include "common.h"
#include <string.h>
#include <initializer_list>
namespace kj {
// =======================================================================================
// ArrayDisposer -- Implementation details.
class ArrayDisposer {
// Much like Disposer from memory.h.
protected:
// Do not declare a destructor, as doing so will force a global initializer for
// HeapArrayDisposer::instance.
virtual void disposeImpl(void* firstElement, size_t elementSize, size_t elementCount,
size_t capacity, void (*destroyElement)(void*)) const = 0;
// Disposes of the array. `destroyElement` invokes the destructor of each element, or is nullptr
// if the elements have trivial destructors. `capacity` is the amount of space that was
// allocated while `elementCount` is the number of elements that were actually constructed;
// these are always the same number for Array<T> but may be different when using ArrayBuilder<T>.
public:
template <typename T>
void dispose(T* firstElement, size_t elementCount, size_t capacity) const;
// Helper wrapper around disposeImpl().
//
// Callers must not call dispose() on the same array twice, even if the first call throws
// an exception.
private:
template <typename T, bool hasTrivialDestructor = __has_trivial_destructor(T)>
struct Dispose_;
};
class ExceptionSafeArrayUtil {
// Utility class that assists in constructing or destroying elements of an array, where the
// constructor or destructor could throw exceptions. In case of an exception,
// ExceptionSafeArrayUtil's destructor will call destructors on all elements that have been
// constructed but not destroyed. Remember that destructors that throw exceptions are required
// to use UnwindDetector to detect unwind and avoid exceptions in this case. Therefore, no more
// than one exception will be thrown (and the program will not terminate).
public:
inline ExceptionSafeArrayUtil(void* ptr, size_t elementSize, size_t constructedElementCount,
void (*destroyElement)(void*))
: pos(reinterpret_cast<byte*>(ptr) + elementSize * constructedElementCount),
elementSize(elementSize), constructedElementCount(constructedElementCount),
destroyElement(destroyElement) {}
KJ_DISALLOW_COPY(ExceptionSafeArrayUtil);
inline ~ExceptionSafeArrayUtil() noexcept(false) {
if (constructedElementCount > 0) destroyAll();
}
void construct(size_t count, void (*constructElement)(void*));
// Construct the given number of elements.
void destroyAll();
// Destroy all elements. Call this immediately before ExceptionSafeArrayUtil goes out-of-scope
// to ensure that one element throwing an exception does not prevent the others from being
// destroyed.
void release() { constructedElementCount = 0; }
// Prevent ExceptionSafeArrayUtil's destructor from destroying the constructed elements.
// Call this after you've successfully finished constructing.
private:
byte* pos;
size_t elementSize;
size_t constructedElementCount;
void (*destroyElement)(void*);
};
class DestructorOnlyArrayDisposer: public ArrayDisposer {
public:
static const DestructorOnlyArrayDisposer instance;
void disposeImpl(void* firstElement, size_t elementSize, size_t elementCount,
size_t capacity, void (*destroyElement)(void*)) const override;
};
class NullArrayDisposer: public ArrayDisposer {
// An ArrayDisposer that does nothing. Can be used to construct a fake Arrays that doesn't
// actually own its content.
public:
static const NullArrayDisposer instance;
void disposeImpl(void* firstElement, size_t elementSize, size_t elementCount,
size_t capacity, void (*destroyElement)(void*)) const override;
};
// =======================================================================================
// Array
template <typename T>
class Array {
// An owned array which will automatically be disposed of (using an ArrayDisposer) in the
// destructor. Can be moved, but not copied. Much like Own<T>, but for arrays rather than
// single objects.
public:
inline Array(): ptr(nullptr), size_(0), disposer(nullptr) {}
inline Array(decltype(nullptr)): ptr(nullptr), size_(0), disposer(nullptr) {}
inline Array(Array&& other) noexcept
: ptr(other.ptr), size_(other.size_), disposer(other.disposer) {
other.ptr = nullptr;
other.size_ = 0;
}
inline Array(Array<RemoveConstOrDisable<T>>&& other) noexcept
: ptr(other.ptr), size_(other.size_), disposer(other.disposer) {
other.ptr = nullptr;
other.size_ = 0;
}
inline Array(T* firstElement, size_t size, const ArrayDisposer& disposer)
: ptr(firstElement), size_(size), disposer(&disposer) {}
KJ_DISALLOW_COPY(Array);
inline ~Array() noexcept { dispose(); }
inline operator ArrayPtr<T>() {
return ArrayPtr<T>(ptr, size_);
}
inline operator ArrayPtr<const T>() const {
return ArrayPtr<T>(ptr, size_);
}
inline ArrayPtr<T> asPtr() {
return ArrayPtr<T>(ptr, size_);
}
inline ArrayPtr<const T> asPtr() const {
return ArrayPtr<T>(ptr, size_);
}
inline size_t size() const { return size_; }
inline T& operator[](size_t index) const {
KJ_IREQUIRE(index < size_, "Out-of-bounds Array access.");
return ptr[index];
}
inline const T* begin() const { return ptr; }
inline const T* end() const { return ptr + size_; }
inline const T& front() const { return *ptr; }
inline const T& back() const { return *(ptr + size_ - 1); }
inline T* begin() { return ptr; }
inline T* end() { return ptr + size_; }
inline T& front() { return *ptr; }
inline T& back() { return *(ptr + size_ - 1); }
inline ArrayPtr<T> slice(size_t start, size_t end) {
KJ_IREQUIRE(start <= end && end <= size_, "Out-of-bounds Array::slice().");
return ArrayPtr<T>(ptr + start, end - start);
}
inline ArrayPtr<const T> slice(size_t start, size_t end) const {
KJ_IREQUIRE(start <= end && end <= size_, "Out-of-bounds Array::slice().");
return ArrayPtr<const T>(ptr + start, end - start);
}
inline ArrayPtr<const byte> asBytes() const { return asPtr().asBytes(); }
inline ArrayPtr<PropagateConst<T, byte>> asBytes() { return asPtr().asBytes(); }
inline ArrayPtr<const char> asChars() const { return asPtr().asChars(); }
inline ArrayPtr<PropagateConst<T, char>> asChars() { return asPtr().asChars(); }
inline Array<PropagateConst<T, byte>> releaseAsBytes() {
// Like asBytes() but transfers ownership.
static_assert(sizeof(T) == sizeof(byte),
"releaseAsBytes() only possible on arrays with byte-size elements (e.g. chars).");
Array<PropagateConst<T, byte>> result(
reinterpret_cast<PropagateConst<T, byte>*>(ptr), size_, *disposer);
ptr = nullptr;
size_ = 0;
return result;
}
inline Array<PropagateConst<T, char>> releaseAsChars() {
// Like asChars() but transfers ownership.
static_assert(sizeof(T) == sizeof(PropagateConst<T, char>),
"releaseAsChars() only possible on arrays with char-size elements (e.g. bytes).");
Array<PropagateConst<T, char>> result(
reinterpret_cast<PropagateConst<T, char>*>(ptr), size_, *disposer);
ptr = nullptr;
size_ = 0;
return result;
}
inline bool operator==(decltype(nullptr)) const { return size_ == 0; }
inline bool operator!=(decltype(nullptr)) const { return size_ != 0; }
inline Array& operator=(decltype(nullptr)) {
dispose();
return *this;
}
inline Array& operator=(Array&& other) {
dispose();
ptr = other.ptr;
size_ = other.size_;
disposer = other.disposer;
other.ptr = nullptr;
other.size_ = 0;
return *this;
}
private:
T* ptr;
size_t size_;
const ArrayDisposer* disposer;
inline void dispose() {
// Make sure that if an exception is thrown, we are left with a null ptr, so we won't possibly
// dispose again.
T* ptrCopy = ptr;
size_t sizeCopy = size_;
if (ptrCopy != nullptr) {
ptr = nullptr;
size_ = 0;
disposer->dispose(ptrCopy, sizeCopy, sizeCopy);
}
}
template <typename U>
friend class Array;
};
static_assert(!canMemcpy<Array<char>>(), "canMemcpy<>() is broken");
namespace _ { // private
class HeapArrayDisposer final: public ArrayDisposer {
public:
template <typename T>
static T* allocate(size_t count);
template <typename T>
static T* allocateUninitialized(size_t count);
static const HeapArrayDisposer instance;
private:
static void* allocateImpl(size_t elementSize, size_t elementCount, size_t capacity,
void (*constructElement)(void*), void (*destroyElement)(void*));
// Allocates and constructs the array. Both function pointers are null if the constructor is
// trivial, otherwise destroyElement is null if the constructor doesn't throw.
virtual void disposeImpl(void* firstElement, size_t elementSize, size_t elementCount,
size_t capacity, void (*destroyElement)(void*)) const override;
template <typename T, bool hasTrivialConstructor = __has_trivial_constructor(T),
bool hasNothrowConstructor = __has_nothrow_constructor(T)>
struct Allocate_;
};
} // namespace _ (private)
template <typename T>
inline Array<T> heapArray(size_t size) {
// Much like `heap<T>()` from memory.h, allocates a new array on the heap.
return Array<T>(_::HeapArrayDisposer::allocate<T>(size), size,
_::HeapArrayDisposer::instance);
}
template <typename T> Array<T> heapArray(const T* content, size_t size);
template <typename T> Array<T> heapArray(ArrayPtr<T> content);
template <typename T> Array<T> heapArray(ArrayPtr<const T> content);
template <typename T, typename Iterator> Array<T> heapArray(Iterator begin, Iterator end);
template <typename T> Array<T> heapArray(std::initializer_list<T> init);
// Allocate a heap array containing a copy of the given content.
template <typename T, typename Container>
Array<T> heapArrayFromIterable(Container&& a) { return heapArray<T>(a.begin(), a.end()); }
template <typename T>
Array<T> heapArrayFromIterable(Array<T>&& a) { return mv(a); }
// =======================================================================================
// ArrayBuilder
template <typename T>
class ArrayBuilder {
// Class which lets you build an Array<T> specifying the exact constructor arguments for each
// element, rather than starting by default-constructing them.
public:
ArrayBuilder(): ptr(nullptr), pos(nullptr), endPtr(nullptr) {}
ArrayBuilder(decltype(nullptr)): ptr(nullptr), pos(nullptr), endPtr(nullptr) {}
explicit ArrayBuilder(RemoveConst<T>* firstElement, size_t capacity,
const ArrayDisposer& disposer)
: ptr(firstElement), pos(firstElement), endPtr(firstElement + capacity),
disposer(&disposer) {}
ArrayBuilder(ArrayBuilder&& other)
: ptr(other.ptr), pos(other.pos), endPtr(other.endPtr), disposer(other.disposer) {
other.ptr = nullptr;
other.pos = nullptr;
other.endPtr = nullptr;
}
KJ_DISALLOW_COPY(ArrayBuilder);
inline ~ArrayBuilder() noexcept(false) { dispose(); }
inline operator ArrayPtr<T>() {
return arrayPtr(ptr, pos);
}
inline operator ArrayPtr<const T>() const {
return arrayPtr(ptr, pos);
}
inline ArrayPtr<T> asPtr() {
return arrayPtr(ptr, pos);
}
inline ArrayPtr<const T> asPtr() const {
return arrayPtr(ptr, pos);
}
inline size_t size() const { return pos - ptr; }
inline size_t capacity() const { return endPtr - ptr; }
inline T& operator[](size_t index) const {
KJ_IREQUIRE(index < implicitCast<size_t>(pos - ptr), "Out-of-bounds Array access.");
return ptr[index];
}
inline const T* begin() const { return ptr; }
inline const T* end() const { return pos; }
inline const T& front() const { return *ptr; }
inline const T& back() const { return *(pos - 1); }
inline T* begin() { return ptr; }
inline T* end() { return pos; }
inline T& front() { return *ptr; }
inline T& back() { return *(pos - 1); }
ArrayBuilder& operator=(ArrayBuilder&& other) {
dispose();
ptr = other.ptr;
pos = other.pos;
endPtr = other.endPtr;
disposer = other.disposer;
other.ptr = nullptr;
other.pos = nullptr;
other.endPtr = nullptr;
return *this;
}
ArrayBuilder& operator=(decltype(nullptr)) {
dispose();
return *this;
}
template <typename... Params>
T& add(Params&&... params) {
KJ_IREQUIRE(pos < endPtr, "Added too many elements to ArrayBuilder.");
ctor(*pos, kj::fwd<Params>(params)...);
return *pos++;
}
template <typename Container>
void addAll(Container&& container) {
addAll<decltype(container.begin()), !isReference<Container>()>(
container.begin(), container.end());
}
template <typename Iterator, bool move = false>
void addAll(Iterator start, Iterator end);
void removeLast() {
KJ_IREQUIRE(pos > ptr, "No elements present to remove.");
kj::dtor(*--pos);
}
void truncate(size_t size) {
KJ_IREQUIRE(size <= this->size(), "can't use truncate() to expand");
T* target = ptr + size;
if (__has_trivial_destructor(T)) {
pos = target;
} else {
while (pos > target) {
kj::dtor(*--pos);
}
}
}
void resize(size_t size) {
KJ_IREQUIRE(size <= capacity(), "can't resize past capacity");
T* target = ptr + size;
if (target > pos) {
// expand
if (__has_trivial_constructor(T)) {
pos = target;
} else {
while (pos < target) {
kj::ctor(*pos++);
}
}
} else {
// truncate
if (__has_trivial_destructor(T)) {
pos = target;
} else {
while (pos > target) {
kj::dtor(*--pos);
}
}
}
}
Array<T> finish() {
// We could safely remove this check if we assume that the disposer implementation doesn't
// need to know the original capacity, as is thes case with HeapArrayDisposer since it uses
// operator new() or if we created a custom disposer for ArrayBuilder which stores the capacity
// in a prefix. But that would make it hard to write cleverer heap allocators, and anyway this
// check might catch bugs. Probably people should use Vector if they want to build arrays
// without knowing the final size in advance.
KJ_IREQUIRE(pos == endPtr, "ArrayBuilder::finish() called prematurely.");
Array<T> result(reinterpret_cast<T*>(ptr), pos - ptr, *disposer);
ptr = nullptr;
pos = nullptr;
endPtr = nullptr;
return result;
}
inline bool isFull() const {
return pos == endPtr;
}
private:
T* ptr;
RemoveConst<T>* pos;
T* endPtr;
const ArrayDisposer* disposer;
inline void dispose() {
// Make sure that if an exception is thrown, we are left with a null ptr, so we won't possibly
// dispose again.
T* ptrCopy = ptr;
T* posCopy = pos;
T* endCopy = endPtr;
if (ptrCopy != nullptr) {
ptr = nullptr;
pos = nullptr;
endPtr = nullptr;
disposer->dispose(ptrCopy, posCopy - ptrCopy, endCopy - ptrCopy);
}
}
};
template <typename T>
inline ArrayBuilder<T> heapArrayBuilder(size_t size) {
// Like `heapArray<T>()` but does not default-construct the elements. You must construct them
// manually by calling `add()`.
return ArrayBuilder<T>(_::HeapArrayDisposer::allocateUninitialized<RemoveConst<T>>(size),
size, _::HeapArrayDisposer::instance);
}
// =======================================================================================
// Inline Arrays
template <typename T, size_t fixedSize>
class FixedArray {
// A fixed-width array whose storage is allocated inline rather than on the heap.
public:
inline size_t size() const { return fixedSize; }
inline T* begin() { return content; }
inline T* end() { return content + fixedSize; }
inline const T* begin() const { return content; }
inline const T* end() const { return content + fixedSize; }
inline operator ArrayPtr<T>() {
return arrayPtr(content, fixedSize);
}
inline operator ArrayPtr<const T>() const {
return arrayPtr(content, fixedSize);
}
inline T& operator[](size_t index) { return content[index]; }
inline const T& operator[](size_t index) const { return content[index]; }
private:
T content[fixedSize];
};
template <typename T, size_t fixedSize>
class CappedArray {
// Like `FixedArray` but can be dynamically resized as long as the size does not exceed the limit
// specified by the template parameter.
//
// TODO(someday): Don't construct elements past currentSize?
public:
inline KJ_CONSTEXPR() CappedArray(): currentSize(fixedSize) {}
inline explicit constexpr CappedArray(size_t s): currentSize(s) {}
inline size_t size() const { return currentSize; }
inline void setSize(size_t s) { KJ_IREQUIRE(s <= fixedSize); currentSize = s; }
inline T* begin() { return content; }
inline T* end() { return content + currentSize; }
inline const T* begin() const { return content; }
inline const T* end() const { return content + currentSize; }
inline operator ArrayPtr<T>() {
return arrayPtr(content, currentSize);
}
inline operator ArrayPtr<const T>() const {
return arrayPtr(content, currentSize);
}
inline T& operator[](size_t index) { return content[index]; }
inline const T& operator[](size_t index) const { return content[index]; }
private:
size_t currentSize;
T content[fixedSize];
};
// =======================================================================================
// KJ_MAP
#define KJ_MAP(elementName, array) \
::kj::_::Mapper<KJ_DECLTYPE_REF(array)>(array) * \
[&](typename ::kj::_::Mapper<KJ_DECLTYPE_REF(array)>::Element elementName)
// Applies some function to every element of an array, returning an Array of the results, with
// nice syntax. Example:
//
// StringPtr foo = "abcd";
// Array<char> bar = KJ_MAP(c, foo) -> char { return c + 1; };
// KJ_ASSERT(str(bar) == "bcde");
namespace _ { // private
template <typename T>
struct Mapper {
T array;
Mapper(T&& array): array(kj::fwd<T>(array)) {}
template <typename Func>
auto operator*(Func&& func) -> Array<decltype(func(*array.begin()))> {
auto builder = heapArrayBuilder<decltype(func(*array.begin()))>(array.size());
for (auto iter = array.begin(); iter != array.end(); ++iter) {
builder.add(func(*iter));
}
return builder.finish();
}
typedef decltype(*kj::instance<T>().begin()) Element;
};
template <typename T, size_t s>
struct Mapper<T(&)[s]> {
T* array;
Mapper(T* array): array(array) {}
template <typename Func>
auto operator*(Func&& func) -> Array<decltype(func(*array))> {
auto builder = heapArrayBuilder<decltype(func(*array))>(s);
for (size_t i = 0; i < s; i++) {
builder.add(func(array[i]));
}
return builder.finish();
}
typedef decltype(*array)& Element;
};
} // namespace _ (private)
// =======================================================================================
// Inline implementation details
template <typename T>
struct ArrayDisposer::Dispose_<T, true> {
static void dispose(T* firstElement, size_t elementCount, size_t capacity,
const ArrayDisposer& disposer) {
disposer.disposeImpl(const_cast<RemoveConst<T>*>(firstElement),
sizeof(T), elementCount, capacity, nullptr);
}
};
template <typename T>
struct ArrayDisposer::Dispose_<T, false> {
static void destruct(void* ptr) {
kj::dtor(*reinterpret_cast<T*>(ptr));
}
static void dispose(T* firstElement, size_t elementCount, size_t capacity,
const ArrayDisposer& disposer) {
disposer.disposeImpl(firstElement, sizeof(T), elementCount, capacity, &destruct);
}
};
template <typename T>
void ArrayDisposer::dispose(T* firstElement, size_t elementCount, size_t capacity) const {
Dispose_<T>::dispose(firstElement, elementCount, capacity, *this);
}
namespace _ { // private
template <typename T>
struct HeapArrayDisposer::Allocate_<T, true, true> {
static T* allocate(size_t elementCount, size_t capacity) {
return reinterpret_cast<T*>(allocateImpl(
sizeof(T), elementCount, capacity, nullptr, nullptr));
}
};
template <typename T>
struct HeapArrayDisposer::Allocate_<T, false, true> {
static void construct(void* ptr) {
kj::ctor(*reinterpret_cast<T*>(ptr));
}
static T* allocate(size_t elementCount, size_t capacity) {
return reinterpret_cast<T*>(allocateImpl(
sizeof(T), elementCount, capacity, &construct, nullptr));
}
};
template <typename T>
struct HeapArrayDisposer::Allocate_<T, false, false> {
static void construct(void* ptr) {
kj::ctor(*reinterpret_cast<T*>(ptr));
}
static void destruct(void* ptr) {
kj::dtor(*reinterpret_cast<T*>(ptr));
}
static T* allocate(size_t elementCount, size_t capacity) {
return reinterpret_cast<T*>(allocateImpl(
sizeof(T), elementCount, capacity, &construct, &destruct));
}
};
template <typename T>
T* HeapArrayDisposer::allocate(size_t count) {
return Allocate_<T>::allocate(count, count);
}
template <typename T>
T* HeapArrayDisposer::allocateUninitialized(size_t count) {
return Allocate_<T, true, true>::allocate(0, count);
}
template <typename Element, typename Iterator, bool move, bool = canMemcpy<Element>()>
struct CopyConstructArray_;
template <typename T, bool move>
struct CopyConstructArray_<T, T*, move, true> {
static inline T* apply(T* __restrict__ pos, T* start, T* end) {
memcpy(pos, start, reinterpret_cast<byte*>(end) - reinterpret_cast<byte*>(start));
return pos + (end - start);
}
};
template <typename T>
struct CopyConstructArray_<T, const T*, false, true> {
static inline T* apply(T* __restrict__ pos, const T* start, const T* end) {
memcpy(pos, start, reinterpret_cast<const byte*>(end) - reinterpret_cast<const byte*>(start));
return pos + (end - start);
}
};
template <typename T, typename Iterator, bool move>
struct CopyConstructArray_<T, Iterator, move, true> {
static inline T* apply(T* __restrict__ pos, Iterator start, Iterator end) {
// Since both the copy constructor and assignment operator are trivial, we know that assignment
// is equivalent to copy-constructing. So we can make this case somewhat easier for the
// compiler to optimize.
while (start != end) {
*pos++ = *start++;
}
return pos;
}
};
template <typename T, typename Iterator>
struct CopyConstructArray_<T, Iterator, false, false> {
struct ExceptionGuard {
T* start;
T* pos;
inline explicit ExceptionGuard(T* pos): start(pos), pos(pos) {}
~ExceptionGuard() noexcept(false) {
while (pos > start) {
dtor(*--pos);
}
}
};
static T* apply(T* __restrict__ pos, Iterator start, Iterator end) {
// Verify that T can be *implicitly* constructed from the source values.
if (false) implicitCast<T>(*start);
if (noexcept(T(*start))) {
while (start != end) {
ctor(*pos++, *start++);
}
return pos;
} else {
// Crap. This is complicated.
ExceptionGuard guard(pos);
while (start != end) {
ctor(*guard.pos, *start++);
++guard.pos;
}
guard.start = guard.pos;
return guard.pos;
}
}
};
template <typename T, typename Iterator>
struct CopyConstructArray_<T, Iterator, true, false> {
// Actually move-construct.
struct ExceptionGuard {
T* start;
T* pos;
inline explicit ExceptionGuard(T* pos): start(pos), pos(pos) {}
~ExceptionGuard() noexcept(false) {
while (pos > start) {
dtor(*--pos);
}
}
};
static T* apply(T* __restrict__ pos, Iterator start, Iterator end) {
// Verify that T can be *implicitly* constructed from the source values.
if (false) implicitCast<T>(kj::mv(*start));
if (noexcept(T(kj::mv(*start)))) {
while (start != end) {
ctor(*pos++, kj::mv(*start++));
}
return pos;
} else {
// Crap. This is complicated.
ExceptionGuard guard(pos);
while (start != end) {
ctor(*guard.pos, kj::mv(*start++));
++guard.pos;
}
guard.start = guard.pos;
return guard.pos;
}
}
};
} // namespace _ (private)
template <typename T>
template <typename Iterator, bool move>
void ArrayBuilder<T>::addAll(Iterator start, Iterator end) {
pos = _::CopyConstructArray_<RemoveConst<T>, Decay<Iterator>, move>::apply(pos, start, end);
}
template <typename T>
Array<T> heapArray(const T* content, size_t size) {
ArrayBuilder<T> builder = heapArrayBuilder<T>(size);
builder.addAll(content, content + size);
return builder.finish();
}
template <typename T>
Array<T> heapArray(T* content, size_t size) {
ArrayBuilder<T> builder = heapArrayBuilder<T>(size);
builder.addAll(content, content + size);
return builder.finish();
}
template <typename T>
Array<T> heapArray(ArrayPtr<T> content) {
ArrayBuilder<T> builder = heapArrayBuilder<T>(content.size());
builder.addAll(content);
return builder.finish();
}
template <typename T>
Array<T> heapArray(ArrayPtr<const T> content) {
ArrayBuilder<T> builder = heapArrayBuilder<T>(content.size());
builder.addAll(content);
return builder.finish();
}
template <typename T, typename Iterator> Array<T>
heapArray(Iterator begin, Iterator end) {
ArrayBuilder<T> builder = heapArrayBuilder<T>(end - begin);
builder.addAll(begin, end);
return builder.finish();
}
template <typename T>
inline Array<T> heapArray(std::initializer_list<T> init) {
return heapArray<T>(init.begin(), init.end());
}
} // namespace kj
#endif // KJ_ARRAY_H_

File diff suppressed because it is too large Load Diff

View File

@ -1,561 +0,0 @@
// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#ifndef KJ_ASYNC_IO_H_
#define KJ_ASYNC_IO_H_
#if defined(__GNUC__) && !KJ_HEADER_WARNINGS
#pragma GCC system_header
#endif
#include "async.h"
#include "function.h"
#include "thread.h"
#include "time.h"
struct sockaddr;
namespace kj {
#if _WIN32
class Win32EventPort;
#else
class UnixEventPort;
#endif
class NetworkAddress;
class AsyncOutputStream;
// =======================================================================================
// Streaming I/O
class AsyncInputStream {
// Asynchronous equivalent of InputStream (from io.h).
public:
virtual Promise<size_t> read(void* buffer, size_t minBytes, size_t maxBytes);
virtual Promise<size_t> tryRead(void* buffer, size_t minBytes, size_t maxBytes) = 0;
Promise<void> read(void* buffer, size_t bytes);
virtual Maybe<uint64_t> tryGetLength();
// Get the remaining number of bytes that will be produced by this stream, if known.
//
// This is used e.g. to fill in the Content-Length header of an HTTP message. If unknown, the
// HTTP implementation may need to fall back to Transfer-Encoding: chunked.
//
// The default implementation always returns null.
virtual Promise<uint64_t> pumpTo(
AsyncOutputStream& output, uint64_t amount = kj::maxValue);
// Read `amount` bytes from this stream (or to EOF) and write them to `output`, returning the
// total bytes actually pumped (which is only less than `amount` if EOF was reached).
//
// Override this if your stream type knows how to pump itself to certain kinds of output
// streams more efficiently than via the naive approach. You can use
// kj::dynamicDowncastIfAvailable() to test for stream types you recognize, and if none match,
// delegate to the default implementation.
//
// The default implementation first tries calling output.tryPumpFrom(), but if that fails, it
// performs a naive pump by allocating a buffer and reading to it / writing from it in a loop.
Promise<Array<byte>> readAllBytes();
Promise<String> readAllText();
// Read until EOF and return as one big byte array or string.
};
class AsyncOutputStream {
// Asynchronous equivalent of OutputStream (from io.h).
public:
virtual Promise<void> write(const void* buffer, size_t size) KJ_WARN_UNUSED_RESULT = 0;
virtual Promise<void> write(ArrayPtr<const ArrayPtr<const byte>> pieces)
KJ_WARN_UNUSED_RESULT = 0;
virtual Maybe<Promise<uint64_t>> tryPumpFrom(
AsyncInputStream& input, uint64_t amount = kj::maxValue);
// Implements double-dispatch for AsyncInputStream::pumpTo().
//
// This method should only be called from within an implementation of pumpTo().
//
// This method examines the type of `input` to find optimized ways to pump data from it to this
// output stream. If it finds one, it performs the pump. Otherwise, it returns null.
//
// The default implementation always returns null.
};
class AsyncIoStream: public AsyncInputStream, public AsyncOutputStream {
// A combination input and output stream.
public:
virtual void shutdownWrite() = 0;
// Cleanly shut down just the write end of the stream, while keeping the read end open.
virtual void abortRead() {}
// Similar to shutdownWrite, but this will shut down the read end of the stream, and should only
// be called when an error has occurred.
virtual void getsockopt(int level, int option, void* value, uint* length);
virtual void setsockopt(int level, int option, const void* value, uint length);
// Corresponds to getsockopt() and setsockopt() syscalls. Will throw an "unimplemented" exception
// if the stream is not a socket or the option is not appropriate for the socket type. The
// default implementations always throw "unimplemented".
virtual void getsockname(struct sockaddr* addr, uint* length);
virtual void getpeername(struct sockaddr* addr, uint* length);
// Corresponds to getsockname() and getpeername() syscalls. Will throw an "unimplemented"
// exception if the stream is not a socket. The default implementations always throw
// "unimplemented".
//
// Note that we don't provide methods that return NetworkAddress because it usually wouldn't
// be useful. You can't connect() to or listen() on these addresses, obviously, because they are
// ephemeral addresses for a single connection.
};
struct OneWayPipe {
// A data pipe with an input end and an output end. (Typically backed by pipe() system call.)
Own<AsyncInputStream> in;
Own<AsyncOutputStream> out;
};
struct TwoWayPipe {
// A data pipe that supports sending in both directions. Each end's output sends data to the
// other end's input. (Typically backed by socketpair() system call.)
Own<AsyncIoStream> ends[2];
};
class ConnectionReceiver {
// Represents a server socket listening on a port.
public:
virtual Promise<Own<AsyncIoStream>> accept() = 0;
// Accept the next incoming connection.
virtual uint getPort() = 0;
// Gets the port number, if applicable (i.e. if listening on IP). This is useful if you didn't
// specify a port when constructing the NetworkAddress -- one will have been assigned
// automatically.
virtual void getsockopt(int level, int option, void* value, uint* length);
virtual void setsockopt(int level, int option, const void* value, uint length);
// Same as the methods of AsyncIoStream.
};
// =======================================================================================
// Datagram I/O
class AncillaryMessage {
// Represents an ancillary message (aka control message) received using the recvmsg() system
// call (or equivalent). Most apps will not use this.
public:
inline AncillaryMessage(int level, int type, ArrayPtr<const byte> data);
AncillaryMessage() = default;
inline int getLevel() const;
// Originating protocol / socket level.
inline int getType() const;
// Protocol-specific message type.
template <typename T>
inline Maybe<const T&> as();
// Interpret the ancillary message as the given struct type. Most ancillary messages are some
// sort of struct, so this is a convenient way to access it. Returns nullptr if the message
// is smaller than the struct -- this can happen if the message was truncated due to
// insufficient ancillary buffer space.
template <typename T>
inline ArrayPtr<const T> asArray();
// Interpret the ancillary message as an array of items. If the message size does not evenly
// divide into elements of type T, the remainder is discarded -- this can happen if the message
// was truncated due to insufficient ancillary buffer space.
private:
int level;
int type;
ArrayPtr<const byte> data;
// Message data. In most cases you should use `as()` or `asArray()`.
};
class DatagramReceiver {
// Class encapsulating the recvmsg() system call. You must specify the DatagramReceiver's
// capacity in advance; if a received packet is larger than the capacity, it will be truncated.
public:
virtual Promise<void> receive() = 0;
// Receive a new message, overwriting this object's content.
//
// receive() may reuse the same buffers for content and ancillary data with each call.
template <typename T>
struct MaybeTruncated {
T value;
bool isTruncated;
// True if the Receiver's capacity was insufficient to receive the value and therefore the
// value is truncated.
};
virtual MaybeTruncated<ArrayPtr<const byte>> getContent() = 0;
// Get the content of the datagram.
virtual MaybeTruncated<ArrayPtr<const AncillaryMessage>> getAncillary() = 0;
// Ancilarry messages received with the datagram. See the recvmsg() system call and the cmsghdr
// struct. Most apps don't need this.
//
// If the returned value is truncated, then the last message in the array may itself be
// truncated, meaning its as<T>() method will return nullptr or its asArray<T>() method will
// return fewer elements than expected. Truncation can also mean that additional messages were
// available but discarded.
virtual NetworkAddress& getSource() = 0;
// Get the datagram sender's address.
struct Capacity {
size_t content = 8192;
// How much space to allocate for the datagram content. If a datagram is received that is
// larger than this, it will be truncated, with no way to recover the tail.
size_t ancillary = 0;
// How much space to allocate for ancillary messages. As with content, if the ancillary data
// is larger than this, it will be truncated.
};
};
class DatagramPort {
public:
virtual Promise<size_t> send(const void* buffer, size_t size, NetworkAddress& destination) = 0;
virtual Promise<size_t> send(ArrayPtr<const ArrayPtr<const byte>> pieces,
NetworkAddress& destination) = 0;
virtual Own<DatagramReceiver> makeReceiver(
DatagramReceiver::Capacity capacity = DatagramReceiver::Capacity()) = 0;
// Create a new `Receiver` that can be used to receive datagrams. `capacity` specifies how much
// space to allocate for the received message. The `DatagramPort` must outlive the `Receiver`.
virtual uint getPort() = 0;
// Gets the port number, if applicable (i.e. if listening on IP). This is useful if you didn't
// specify a port when constructing the NetworkAddress -- one will have been assigned
// automatically.
virtual void getsockopt(int level, int option, void* value, uint* length);
virtual void setsockopt(int level, int option, const void* value, uint length);
// Same as the methods of AsyncIoStream.
};
// =======================================================================================
// Networks
class NetworkAddress {
// Represents a remote address to which the application can connect.
public:
virtual Promise<Own<AsyncIoStream>> connect() = 0;
// Make a new connection to this address.
//
// The address must not be a wildcard ("*"). If it is an IP address, it must have a port number.
virtual Own<ConnectionReceiver> listen() = 0;
// Listen for incoming connections on this address.
//
// The address must be local.
virtual Own<DatagramPort> bindDatagramPort();
// Open this address as a datagram (e.g. UDP) port.
//
// The address must be local.
virtual Own<NetworkAddress> clone() = 0;
// Returns an equivalent copy of this NetworkAddress.
virtual String toString() = 0;
// Produce a human-readable string which hopefully can be passed to Network::parseAddress()
// to reproduce this address, although whether or not that works of course depends on the Network
// implementation. This should be called only to display the address to human users, who will
// hopefully know what they are able to do with it.
};
class Network {
// Factory for NetworkAddress instances, representing the network services offered by the
// operating system.
//
// This interface typically represents broad authority, and well-designed code should limit its
// use to high-level startup code and user interaction. Low-level APIs should accept
// NetworkAddress instances directly and work from there, if at all possible.
public:
virtual Promise<Own<NetworkAddress>> parseAddress(StringPtr addr, uint portHint = 0) = 0;
// Construct a network address from a user-provided string. The format of the address
// strings is not specified at the API level, and application code should make no assumptions
// about them. These strings should always be provided by humans, and said humans will know
// what format to use in their particular context.
//
// `portHint`, if provided, specifies the "standard" IP port number for the application-level
// service in play. If the address turns out to be an IP address (v4 or v6), and it lacks a
// port number, this port will be used. If `addr` lacks a port number *and* `portHint` is
// omitted, then the returned address will only support listen() and bindDatagramPort()
// (not connect()), and an unused port will be chosen each time one of those methods is called.
virtual Own<NetworkAddress> getSockaddr(const void* sockaddr, uint len) = 0;
// Construct a network address from a legacy struct sockaddr.
};
// =======================================================================================
// I/O Provider
class AsyncIoProvider {
// Class which constructs asynchronous wrappers around the operating system's I/O facilities.
//
// Generally, the implementation of this interface must integrate closely with a particular
// `EventLoop` implementation. Typically, the EventLoop implementation itself will provide
// an AsyncIoProvider.
public:
virtual OneWayPipe newOneWayPipe() = 0;
// Creates an input/output stream pair representing the ends of a one-way pipe (e.g. created with
// the pipe(2) system call).
virtual TwoWayPipe newTwoWayPipe() = 0;
// Creates two AsyncIoStreams representing the two ends of a two-way pipe (e.g. created with
// socketpair(2) system call). Data written to one end can be read from the other.
virtual Network& getNetwork() = 0;
// Creates a new `Network` instance representing the networks exposed by the operating system.
//
// DO NOT CALL THIS except at the highest levels of your code, ideally in the main() function. If
// you call this from low-level code, then you are preventing higher-level code from injecting an
// alternative implementation. Instead, if your code needs to use network functionality, it
// should ask for a `Network` as a constructor or method parameter, so that higher-level code can
// chose what implementation to use. The system network is essentially a singleton. See:
// http://www.object-oriented-security.org/lets-argue/singletons
//
// Code that uses the system network should not make any assumptions about what kinds of
// addresses it will parse, as this could differ across platforms. String addresses should come
// strictly from the user, who will know how to write them correctly for their system.
//
// With that said, KJ currently supports the following string address formats:
// - IPv4: "1.2.3.4", "1.2.3.4:80"
// - IPv6: "1234:5678::abcd", "[1234:5678::abcd]:80"
// - Local IP wildcard (covers both v4 and v6): "*", "*:80"
// - Symbolic names: "example.com", "example.com:80", "example.com:http", "1.2.3.4:http"
// - Unix domain: "unix:/path/to/socket"
struct PipeThread {
// A combination of a thread and a two-way pipe that communicates with that thread.
//
// The fields are intentionally ordered so that the pipe will be destroyed (and therefore
// disconnected) before the thread is destroyed (and therefore joined). Thus if the thread
// arranges to exit when it detects disconnect, destruction should be clean.
Own<Thread> thread;
Own<AsyncIoStream> pipe;
};
virtual PipeThread newPipeThread(
Function<void(AsyncIoProvider&, AsyncIoStream&, WaitScope&)> startFunc) = 0;
// Create a new thread and set up a two-way pipe (socketpair) which can be used to communicate
// with it. One end of the pipe is passed to the thread's start function and the other end of
// the pipe is returned. The new thread also gets its own `AsyncIoProvider` instance and will
// already have an active `EventLoop` when `startFunc` is called.
//
// TODO(someday): I'm not entirely comfortable with this interface. It seems to be doing too
// much at once but I'm not sure how to cleanly break it down.
virtual Timer& getTimer() = 0;
// Returns a `Timer` based on real time. Time does not pass while event handlers are running --
// it only updates when the event loop polls for system events. This means that calling `now()`
// on this timer does not require a system call.
//
// This timer is not affected by changes to the system date. It is unspecified whether the timer
// continues to count while the system is suspended.
};
class LowLevelAsyncIoProvider {
// Similar to `AsyncIoProvider`, but represents a lower-level interface that may differ on
// different operating systems. You should prefer to use `AsyncIoProvider` over this interface
// whenever possible, as `AsyncIoProvider` is portable and friendlier to dependency-injection.
//
// On Unix, this interface can be used to import native file descriptors into the async framework.
// Different implementations of this interface might work on top of different event handling
// primitives, such as poll vs. epoll vs. kqueue vs. some higher-level event library.
//
// On Windows, this interface can be used to import native HANDLEs into the async framework.
// Different implementations of this interface might work on top of different event handling
// primitives, such as I/O completion ports vs. completion routines.
//
// TODO(port): Actually implement Windows support.
public:
// ---------------------------------------------------------------------------
// Unix-specific stuff
enum Flags {
// Flags controlling how to wrap a file descriptor.
TAKE_OWNERSHIP = 1 << 0,
// The returned object should own the file descriptor, automatically closing it when destroyed.
// The close-on-exec flag will be set on the descriptor if it is not already.
//
// If this flag is not used, then the file descriptor is not automatically closed and the
// close-on-exec flag is not modified.
#if !_WIN32
ALREADY_CLOEXEC = 1 << 1,
// Indicates that the close-on-exec flag is known already to be set, so need not be set again.
// Only relevant when combined with TAKE_OWNERSHIP.
//
// On Linux, all system calls which yield new file descriptors have flags or variants which
// set the close-on-exec flag immediately. Unfortunately, other OS's do not.
ALREADY_NONBLOCK = 1 << 2
// Indicates that the file descriptor is known already to be in non-blocking mode, so the flag
// need not be set again. Otherwise, all wrap*Fd() methods will enable non-blocking mode
// automatically.
//
// On Linux, all system calls which yield new file descriptors have flags or variants which
// enable non-blocking mode immediately. Unfortunately, other OS's do not.
#endif
};
#if _WIN32
typedef uintptr_t Fd;
// On Windows, the `fd` parameter to each of these methods must be a SOCKET, and must have the
// flag WSA_FLAG_OVERLAPPED (which socket() uses by default, but WSASocket() wants you to specify
// explicitly).
#else
typedef int Fd;
// On Unix, any arbitrary file descriptor is supported.
#endif
virtual Own<AsyncInputStream> wrapInputFd(Fd fd, uint flags = 0) = 0;
// Create an AsyncInputStream wrapping a file descriptor.
//
// `flags` is a bitwise-OR of the values of the `Flags` enum.
virtual Own<AsyncOutputStream> wrapOutputFd(Fd fd, uint flags = 0) = 0;
// Create an AsyncOutputStream wrapping a file descriptor.
//
// `flags` is a bitwise-OR of the values of the `Flags` enum.
virtual Own<AsyncIoStream> wrapSocketFd(Fd fd, uint flags = 0) = 0;
// Create an AsyncIoStream wrapping a socket file descriptor.
//
// `flags` is a bitwise-OR of the values of the `Flags` enum.
virtual Promise<Own<AsyncIoStream>> wrapConnectingSocketFd(
Fd fd, const struct sockaddr* addr, uint addrlen, uint flags = 0) = 0;
// Create an AsyncIoStream wrapping a socket and initiate a connection to the given address.
// The returned promise does not resolve until connection has completed.
//
// `flags` is a bitwise-OR of the values of the `Flags` enum.
virtual Own<ConnectionReceiver> wrapListenSocketFd(Fd fd, uint flags = 0) = 0;
// Create an AsyncIoStream wrapping a listen socket file descriptor. This socket should already
// have had `bind()` and `listen()` called on it, so it's ready for `accept()`.
//
// `flags` is a bitwise-OR of the values of the `Flags` enum.
virtual Own<DatagramPort> wrapDatagramSocketFd(Fd fd, uint flags = 0);
virtual Timer& getTimer() = 0;
// Returns a `Timer` based on real time. Time does not pass while event handlers are running --
// it only updates when the event loop polls for system events. This means that calling `now()`
// on this timer does not require a system call.
//
// This timer is not affected by changes to the system date. It is unspecified whether the timer
// continues to count while the system is suspended.
};
Own<AsyncIoProvider> newAsyncIoProvider(LowLevelAsyncIoProvider& lowLevel);
// Make a new AsyncIoProvider wrapping a `LowLevelAsyncIoProvider`.
struct AsyncIoContext {
Own<LowLevelAsyncIoProvider> lowLevelProvider;
Own<AsyncIoProvider> provider;
WaitScope& waitScope;
#if _WIN32
Win32EventPort& win32EventPort;
#else
UnixEventPort& unixEventPort;
// TEMPORARY: Direct access to underlying UnixEventPort, mainly for waiting on signals. This
// field will go away at some point when we have a chance to improve these interfaces.
#endif
};
AsyncIoContext setupAsyncIo();
// Convenience method which sets up the current thread with everything it needs to do async I/O.
// The returned objects contain an `EventLoop` which is wrapping an appropriate `EventPort` for
// doing I/O on the host system, so everything is ready for the thread to start making async calls
// and waiting on promises.
//
// You would typically call this in your main() loop or in the start function of a thread.
// Example:
//
// int main() {
// auto ioContext = kj::setupAsyncIo();
//
// // Now we can call an async function.
// Promise<String> textPromise = getHttp(*ioContext.provider, "http://example.com");
//
// // And we can wait for the promise to complete. Note that you can only use `wait()`
// // from the top level, not from inside a promise callback.
// String text = textPromise.wait(ioContext.waitScope);
// print(text);
// return 0;
// }
//
// WARNING: An AsyncIoContext can only be used in the thread and process that created it. In
// particular, note that after a fork(), an AsyncIoContext created in the parent process will
// not work correctly in the child, even if the parent ceases to use its copy. In particular
// note that this means that server processes which daemonize themselves at startup must wait
// until after daemonization to create an AsyncIoContext.
// =======================================================================================
// inline implementation details
inline AncillaryMessage::AncillaryMessage(
int level, int type, ArrayPtr<const byte> data)
: level(level), type(type), data(data) {}
inline int AncillaryMessage::getLevel() const { return level; }
inline int AncillaryMessage::getType() const { return type; }
template <typename T>
inline Maybe<const T&> AncillaryMessage::as() {
if (data.size() >= sizeof(T)) {
return *reinterpret_cast<const T*>(data.begin());
} else {
return nullptr;
}
}
template <typename T>
inline ArrayPtr<const T> AncillaryMessage::asArray() {
return arrayPtr(reinterpret_cast<const T*>(data.begin()), data.size() / sizeof(T));
}
} // namespace kj
#endif // KJ_ASYNC_IO_H_

View File

@ -1,218 +0,0 @@
// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
// This file contains a bunch of internal declarations that must appear before async.h can start.
// We don't define these directly in async.h because it makes the file hard to read.
#ifndef KJ_ASYNC_PRELUDE_H_
#define KJ_ASYNC_PRELUDE_H_
#if defined(__GNUC__) && !KJ_HEADER_WARNINGS
#pragma GCC system_header
#endif
#include "exception.h"
#include "tuple.h"
namespace kj {
class EventLoop;
template <typename T>
class Promise;
class WaitScope;
template <typename T>
Promise<Array<T>> joinPromises(Array<Promise<T>>&& promises);
Promise<void> joinPromises(Array<Promise<void>>&& promises);
namespace _ { // private
template <typename T> struct JoinPromises_ { typedef T Type; };
template <typename T> struct JoinPromises_<Promise<T>> { typedef T Type; };
template <typename T>
using JoinPromises = typename JoinPromises_<T>::Type;
// If T is Promise<U>, resolves to U, otherwise resolves to T.
//
// TODO(cleanup): Rename to avoid confusion with joinPromises() call which is completely
// unrelated.
class PropagateException {
// A functor which accepts a kj::Exception as a parameter and returns a broken promise of
// arbitrary type which simply propagates the exception.
public:
class Bottom {
public:
Bottom(Exception&& exception): exception(kj::mv(exception)) {}
Exception asException() { return kj::mv(exception); }
private:
Exception exception;
};
Bottom operator()(Exception&& e) {
return Bottom(kj::mv(e));
}
Bottom operator()(const Exception& e) {
return Bottom(kj::cp(e));
}
};
template <typename Func, typename T>
struct ReturnType_ { typedef decltype(instance<Func>()(instance<T>())) Type; };
template <typename Func>
struct ReturnType_<Func, void> { typedef decltype(instance<Func>()()) Type; };
template <typename Func, typename T>
using ReturnType = typename ReturnType_<Func, T>::Type;
// The return type of functor Func given a parameter of type T, with the special exception that if
// T is void, this is the return type of Func called with no arguments.
template <typename T> struct SplitTuplePromise_ { typedef Promise<T> Type; };
template <typename... T>
struct SplitTuplePromise_<kj::_::Tuple<T...>> {
typedef kj::Tuple<Promise<JoinPromises<T>>...> Type;
};
template <typename T>
using SplitTuplePromise = typename SplitTuplePromise_<T>::Type;
// T -> Promise<T>
// Tuple<T> -> Tuple<Promise<T>>
struct Void {};
// Application code should NOT refer to this! See `kj::READY_NOW` instead.
template <typename T> struct FixVoid_ { typedef T Type; };
template <> struct FixVoid_<void> { typedef Void Type; };
template <typename T> using FixVoid = typename FixVoid_<T>::Type;
// FixVoid<T> is just T unless T is void in which case it is _::Void (an empty struct).
template <typename T> struct UnfixVoid_ { typedef T Type; };
template <> struct UnfixVoid_<Void> { typedef void Type; };
template <typename T> using UnfixVoid = typename UnfixVoid_<T>::Type;
// UnfixVoid is the opposite of FixVoid.
template <typename In, typename Out>
struct MaybeVoidCaller {
// Calls the function converting a Void input to an empty parameter list and a void return
// value to a Void output.
template <typename Func>
static inline Out apply(Func& func, In&& in) {
return func(kj::mv(in));
}
};
template <typename In, typename Out>
struct MaybeVoidCaller<In&, Out> {
template <typename Func>
static inline Out apply(Func& func, In& in) {
return func(in);
}
};
template <typename Out>
struct MaybeVoidCaller<Void, Out> {
template <typename Func>
static inline Out apply(Func& func, Void&& in) {
return func();
}
};
template <typename In>
struct MaybeVoidCaller<In, Void> {
template <typename Func>
static inline Void apply(Func& func, In&& in) {
func(kj::mv(in));
return Void();
}
};
template <typename In>
struct MaybeVoidCaller<In&, Void> {
template <typename Func>
static inline Void apply(Func& func, In& in) {
func(in);
return Void();
}
};
template <>
struct MaybeVoidCaller<Void, Void> {
template <typename Func>
static inline Void apply(Func& func, Void&& in) {
func();
return Void();
}
};
template <typename T>
inline T&& returnMaybeVoid(T&& t) {
return kj::fwd<T>(t);
}
inline void returnMaybeVoid(Void&& v) {}
class ExceptionOrValue;
class PromiseNode;
class ChainPromiseNode;
template <typename T>
class ForkHub;
class TaskSetImpl;
class Event;
class PromiseBase {
public:
kj::String trace();
// Dump debug info about this promise.
private:
Own<PromiseNode> node;
PromiseBase() = default;
PromiseBase(Own<PromiseNode>&& node): node(kj::mv(node)) {}
friend class kj::EventLoop;
friend class ChainPromiseNode;
template <typename>
friend class kj::Promise;
friend class TaskSetImpl;
template <typename U>
friend Promise<Array<U>> kj::joinPromises(Array<Promise<U>>&& promises);
friend Promise<void> kj::joinPromises(Array<Promise<void>>&& promises);
};
void detach(kj::Promise<void>&& promise);
void waitImpl(Own<_::PromiseNode>&& node, _::ExceptionOrValue& result, WaitScope& waitScope);
Promise<void> yield();
Own<PromiseNode> neverDone();
class NeverDone {
public:
template <typename T>
operator Promise<T>() const {
return Promise<T>(false, neverDone());
}
KJ_NORETURN(void wait(WaitScope& waitScope) const);
};
} // namespace _ (private)
} // namespace kj
#endif // KJ_ASYNC_PRELUDE_H_

View File

@ -1,274 +0,0 @@
// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#ifndef KJ_ASYNC_UNIX_H_
#define KJ_ASYNC_UNIX_H_
#if _WIN32
#error "This file is Unix-specific. On Windows, include async-win32.h instead."
#endif
#if defined(__GNUC__) && !KJ_HEADER_WARNINGS
#pragma GCC system_header
#endif
#include "async.h"
#include "time.h"
#include "vector.h"
#include "io.h"
#include <signal.h>
#if __linux__ && !__BIONIC__ && !defined(KJ_USE_EPOLL)
// Default to epoll on Linux, except on Bionic (Android) which doesn't have signalfd.h.
#define KJ_USE_EPOLL 1
#endif
namespace kj {
class UnixEventPort: public EventPort {
// An EventPort implementation which can wait for events on file descriptors as well as signals.
// This API only makes sense on Unix.
//
// The implementation uses `poll()` or possibly a platform-specific API (e.g. epoll, kqueue).
// To also wait on signals without race conditions, the implementation may block signals until
// just before `poll()` while using a signal handler which `siglongjmp()`s back to just before
// the signal was unblocked, or it may use a nicer platform-specific API like signalfd.
//
// The implementation reserves a signal for internal use. By default, it uses SIGUSR1. If you
// need to use SIGUSR1 for something else, you must offer a different signal by calling
// setReservedSignal() at startup.
//
// WARNING: A UnixEventPort can only be used in the thread and process that created it. In
// particular, note that after a fork(), a UnixEventPort created in the parent process will
// not work correctly in the child, even if the parent ceases to use its copy. In particular
// note that this means that server processes which daemonize themselves at startup must wait
// until after daemonization to create a UnixEventPort.
public:
UnixEventPort();
~UnixEventPort() noexcept(false);
class FdObserver;
// Class that watches an fd for readability or writability. See definition below.
Promise<siginfo_t> onSignal(int signum);
// When the given signal is delivered to this thread, return the corresponding siginfo_t.
// The signal must have been captured using `captureSignal()`.
//
// If `onSignal()` has not been called, the signal will remain blocked in this thread.
// Therefore, a signal which arrives before `onSignal()` was called will not be "missed" -- the
// next call to 'onSignal()' will receive it. Also, you can control which thread receives a
// process-wide signal by only calling `onSignal()` on that thread's event loop.
//
// The result of waiting on the same signal twice at once is undefined.
static void captureSignal(int signum);
// Arranges for the given signal to be captured and handled via UnixEventPort, so that you may
// then pass it to `onSignal()`. This method is static because it registers a signal handler
// which applies process-wide. If any other threads exist in the process when `captureSignal()`
// is called, you *must* set the signal mask in those threads to block this signal, otherwise
// terrible things will happen if the signal happens to be delivered to those threads. If at
// all possible, call `captureSignal()` *before* creating threads, so that threads you create in
// the future will inherit the proper signal mask.
//
// To un-capture a signal, simply install a different signal handler and then un-block it from
// the signal mask.
static void setReservedSignal(int signum);
// Sets the signal number which `UnixEventPort` reserves for internal use. If your application
// needs to use SIGUSR1, call this at startup (before any calls to `captureSignal()` and before
// constructing an `UnixEventPort`) to offer a different signal.
Timer& getTimer() { return timerImpl; }
// implements EventPort ------------------------------------------------------
bool wait() override;
bool poll() override;
void wake() const override;
private:
struct TimerSet; // Defined in source file to avoid STL include.
class TimerPromiseAdapter;
class SignalPromiseAdapter;
TimerImpl timerImpl;
SignalPromiseAdapter* signalHead = nullptr;
SignalPromiseAdapter** signalTail = &signalHead;
TimePoint readClock();
void gotSignal(const siginfo_t& siginfo);
friend class TimerPromiseAdapter;
#if KJ_USE_EPOLL
AutoCloseFd epollFd;
AutoCloseFd signalFd;
AutoCloseFd eventFd; // Used for cross-thread wakeups.
sigset_t signalFdSigset;
// Signal mask as currently set on the signalFd. Tracked so we can detect whether or not it
// needs updating.
bool doEpollWait(int timeout);
#else
class PollContext;
FdObserver* observersHead = nullptr;
FdObserver** observersTail = &observersHead;
unsigned long long threadId; // actually pthread_t
#endif
};
class UnixEventPort::FdObserver {
// Object which watches a file descriptor to determine when it is readable or writable.
//
// For listen sockets, "readable" means that there is a connection to accept(). For everything
// else, it means that read() (or recv()) will return data.
//
// The presence of out-of-band data should NOT fire this event. However, the event may
// occasionally fire spuriously (when there is actually no data to read), and one thing that can
// cause such spurious events is the arrival of OOB data on certain platforms whose event
// interfaces fail to distinguish between regular and OOB data (e.g. Mac OSX).
//
// WARNING: The exact behavior of this class differs across systems, since event interfaces
// vary wildly. Be sure to read the documentation carefully and avoid depending on unspecified
// behavior. If at all possible, use the higher-level AsyncInputStream interface instead.
public:
enum Flags {
OBSERVE_READ = 1,
OBSERVE_WRITE = 2,
OBSERVE_URGENT = 4,
OBSERVE_READ_WRITE = OBSERVE_READ | OBSERVE_WRITE
};
FdObserver(UnixEventPort& eventPort, int fd, uint flags);
// Begin watching the given file descriptor for readability. Only one ReadObserver may exist
// for a given file descriptor at a time.
~FdObserver() noexcept(false);
KJ_DISALLOW_COPY(FdObserver);
Promise<void> whenBecomesReadable();
// Resolves the next time the file descriptor transitions from having no data to read to having
// some data to read.
//
// KJ uses "edge-triggered" event notification whenever possible. As a result, it is an error
// to call this method when there is already data in the read buffer which has been there since
// prior to the last turn of the event loop or prior to creation FdWatcher. In this case, it is
// unspecified whether the promise will ever resolve -- it depends on the underlying event
// mechanism being used.
//
// In order to avoid this problem, make sure that you only call `whenBecomesReadable()`
// only at times when you know the buffer is empty. You know this for sure when one of the
// following happens:
// * read() or recv() fails with EAGAIN or EWOULDBLOCK. (You MUST have non-blocking mode
// enabled on the fd!)
// * The file descriptor is a regular byte-oriented object (like a socket or pipe),
// read() or recv() returns fewer than the number of bytes requested, and `atEndHint()`
// returns false. This can only happen if the buffer is empty but EOF is not reached. (Note,
// though, that for record-oriented file descriptors like Linux's inotify interface, this
// rule does not hold, because it could simply be that the next record did not fit into the
// space available.)
//
// It is an error to call `whenBecomesReadable()` again when the promise returned previously
// has not yet resolved. If you do this, the previous promise may throw an exception.
inline Maybe<bool> atEndHint() { return atEnd; }
// Returns true if the event system has indicated that EOF has been received. There may still
// be data in the read buffer, but once that is gone, there's nothing left.
//
// Returns false if the event system has indicated that EOF had NOT been received as of the
// last turn of the event loop.
//
// Returns nullptr if the event system does not know whether EOF has been reached. In this
// case, the only way to know for sure is to call read() or recv() and check if it returns
// zero.
//
// This hint may be useful as an optimization to avoid an unnecessary system call.
Promise<void> whenBecomesWritable();
// Resolves the next time the file descriptor transitions from having no space available in the
// write buffer to having some space available.
//
// KJ uses "edge-triggered" event notification whenever possible. As a result, it is an error
// to call this method when there is already space in the write buffer which has been there
// since prior to the last turn of the event loop or prior to creation FdWatcher. In this case,
// it is unspecified whether the promise will ever resolve -- it depends on the underlying
// event mechanism being used.
//
// In order to avoid this problem, make sure that you only call `whenBecomesWritable()`
// only at times when you know the buffer is full. You know this for sure when one of the
// following happens:
// * write() or send() fails with EAGAIN or EWOULDBLOCK. (You MUST have non-blocking mode
// enabled on the fd!)
// * write() or send() succeeds but accepts fewer than the number of bytes provided. This can
// only happen if the buffer is full.
//
// It is an error to call `whenBecomesWritable()` again when the promise returned previously
// has not yet resolved. If you do this, the previous promise may throw an exception.
Promise<void> whenUrgentDataAvailable();
// Resolves the next time the file descriptor's read buffer contains "urgent" data.
//
// The conditions for availability of urgent data are specific to the file descriptor's
// underlying implementation.
//
// It is an error to call `whenUrgentDataAvailable()` again when the promise returned previously
// has not yet resolved. If you do this, the previous promise may throw an exception.
//
// WARNING: This has some known weird behavior on macOS. See
// https://github.com/sandstorm-io/capnproto/issues/374.
private:
UnixEventPort& eventPort;
int fd;
uint flags;
kj::Maybe<Own<PromiseFulfiller<void>>> readFulfiller;
kj::Maybe<Own<PromiseFulfiller<void>>> writeFulfiller;
kj::Maybe<Own<PromiseFulfiller<void>>> urgentFulfiller;
// Replaced each time `whenBecomesReadable()` or `whenBecomesWritable()` is called. Reverted to
// null every time an event is fired.
Maybe<bool> atEnd;
void fire(short events);
#if !KJ_USE_EPOLL
FdObserver* next;
FdObserver** prev;
// Linked list of observers which currently have a non-null readFulfiller or writeFulfiller.
// If `prev` is null then the observer is not currently in the list.
short getEventMask();
#endif
friend class UnixEventPort;
};
} // namespace kj
#endif // KJ_ASYNC_UNIX_H_

View File

@ -1,234 +0,0 @@
// Copyright (c) 2016 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#ifndef KJ_ASYNC_WIN32_H_
#define KJ_ASYNC_WIN32_H_
#if !_WIN32
#error "This file is Windows-specific. On Unix, include async-unix.h instead."
#endif
#include "async.h"
#include "time.h"
#include "io.h"
#include <atomic>
#include <inttypes.h>
// Include windows.h as lean as possible. (If you need more of the Windows API for your app,
// #include windows.h yourself before including this header.)
#define WIN32_LEAN_AND_MEAN 1
#define NOSERVICE 1
#define NOMCX 1
#define NOIME 1
#include <windows.h>
#include "windows-sanity.h"
namespace kj {
class Win32EventPort: public EventPort {
// Abstract base interface for EventPorts that can listen on Win32 event types. Due to the
// absurd complexity of the Win32 API, it's not possible to standardize on a single
// implementation of EventPort. In particular, there is no way for a single thread to use I/O
// completion ports (the most efficient way of handling I/O) while at the same time waiting for
// signalable handles or UI messages.
//
// Note that UI messages are not supported at all by this interface because the message queue
// is implemented by user32.dll and we want libkj to depend only on kernel32.dll. A separate
// compat library could provide a Win32EventPort implementation that works with the UI message
// queue.
public:
// ---------------------------------------------------------------------------
// overlapped I/O
struct IoResult {
DWORD errorCode;
DWORD bytesTransferred;
};
class IoOperation {
public:
virtual LPOVERLAPPED getOverlapped() = 0;
// Gets the OVERLAPPED structure to pass to the Win32 I/O call. Do NOT modify it; just pass it
// on.
virtual Promise<IoResult> onComplete() = 0;
// After making the Win32 call, if the return value indicates that the operation was
// successfully queued (i.e. the completion event will definitely occur), call this to wait
// for completion.
//
// You MUST call this if the operation was successfully queued, and you MUST NOT call this
// otherwise. If the Win32 call failed (without queuing any operation or event) then you should
// simply drop the IoOperation object.
//
// Dropping the returned Promise cancels the operation via Win32's CancelIoEx(). The destructor
// will wait for the cancellation to complete, such that after dropping the proimse it is safe
// to free the buffer that the operation was reading from / writing to.
//
// You may safely drop the `IoOperation` while still waiting for this promise. You may not,
// however, drop the `IoObserver`.
};
class IoObserver {
public:
virtual Own<IoOperation> newOperation(uint64_t offset) = 0;
// Begin an I/O operation. For file operations, `offset` is the offset within the file at
// which the operation will start. For stream operations, `offset` is ignored.
};
virtual Own<IoObserver> observeIo(HANDLE handle) = 0;
// Given a handle which supports overlapped I/O, arrange to receive I/O completion events via
// this EventPort.
//
// Different Win32EventPort implementations may handle this in different ways, such as by using
// completion routines (APCs) or by using I/O completion ports. The caller should not assume
// any particular technique.
//
// WARNING: It is only safe to call observeIo() on a particular handle once during its lifetime.
// You cannot observe the same handle from multiple Win32EventPorts, even if not at the same
// time. This is because the Win32 API provides no way to disassociate a handle from an I/O
// completion port once it is associated.
// ---------------------------------------------------------------------------
// signalable handles
//
// Warning: Due to limitations in the Win32 API, implementations of EventPort may be forced to
// spawn additional threads to wait for signaled objects. This is necessary if the EventPort
// implementation is based on I/O completion ports, or if you need to wait on more than 64
// handles at once.
class SignalObserver {
public:
virtual Promise<void> onSignaled() = 0;
// Returns a promise that completes the next time the handle enters the signaled state.
//
// Depending on the type of handle, the handle may automatically be reset to a non-signaled
// state before the promise resolves. The underlying implementaiton uses WaitForSingleObject()
// or an equivalent wait call, so check the documentation for that to understand the semantics.
//
// If the handle is a mutex and it is abandoned without being unlocked, the promise breaks with
// an exception.
virtual Promise<bool> onSignaledOrAbandoned() = 0;
// Like onSingaled(), but instead of throwing when a mutex is abandoned, resolves to `true`.
// Resolves to `false` for non-abandoned signals.
};
virtual Own<SignalObserver> observeSignalState(HANDLE handle) = 0;
// Given a handle that supports waiting for it to become "signaled" via WaitForSingleObject(),
// return an object that can wait for this state using the EventPort.
// ---------------------------------------------------------------------------
// APCs
virtual void allowApc() = 0;
// If this is ever called, the Win32EventPort will switch modes so that APCs can be scheduled
// on the thread, e.g. through the Win32 QueueUserAPC() call. In the future, this may be enabled
// by default. However, as of this writing, Wine does not support the necessary
// GetQueuedCompletionStatusEx() call, thus allowApc() breaks Wine support. (Tested on Wine
// 1.8.7.)
//
// If the event port implementation can't support APCs for some reason, this throws.
// ---------------------------------------------------------------------------
// time
virtual Timer& getTimer() = 0;
};
class Win32WaitObjectThreadPool {
// Helper class that implements Win32EventPort::observeSignalState() by spawning additional
// threads as needed to perform the actual waiting.
//
// This class is intended to be used to assist in building Win32EventPort implementations.
public:
Win32WaitObjectThreadPool(uint mainThreadCount = 0);
// `mainThreadCount` indicates the number of objects the main thread is able to listen on
// directly. Typically this would be zero (e.g. if the main thread watches an I/O completion
// port) or MAXIMUM_WAIT_OBJECTS (e.g. if the main thread is a UI thread but can use
// MsgWaitForMultipleObjectsEx() to wait on some handles at the same time as messages).
Own<Win32EventPort::SignalObserver> observeSignalState(HANDLE handle);
// Implemetns Win32EventPort::observeSignalState().
uint prepareMainThreadWait(HANDLE* handles[]);
// Call immediately before invoking WaitForMultipleObjects() or similar in the main thread.
// Fills in `handles` with the handle pointers to wait on, and returns the number of handles
// in this array. (The array should be allocated to be at least the size passed to the
// constructor).
//
// There's no need to call this if `mainThreadCount` as passed to the constructor was zero.
bool finishedMainThreadWait(DWORD returnCode);
// Call immediately after invoking WaitForMultipleObjects() or similar in the main thread,
// passing the value returend by that call. Returns true if the event indicated by `returnCode`
// has been handled (i.e. it was WAIT_OBJECT_n or WAIT_ABANDONED_n where n is in-range for the
// last call to prepareMainThreadWait()).
};
class Win32IocpEventPort final: public Win32EventPort {
// An EventPort implementation which uses Windows I/O completion ports to listen for events.
//
// With this implementation, observeSignalState() requires spawning a separate thread.
public:
Win32IocpEventPort();
~Win32IocpEventPort() noexcept(false);
// implements EventPort ------------------------------------------------------
bool wait() override;
bool poll() override;
void wake() const override;
// implements Win32IocpEventPort ---------------------------------------------
Own<IoObserver> observeIo(HANDLE handle) override;
Own<SignalObserver> observeSignalState(HANDLE handle) override;
Timer& getTimer() override { return timerImpl; }
void allowApc() override { isAllowApc = true; }
private:
class IoPromiseAdapter;
class IoOperationImpl;
class IoObserverImpl;
AutoCloseHandle iocp;
AutoCloseHandle thread;
Win32WaitObjectThreadPool waitThreads;
TimerImpl timerImpl;
mutable std::atomic<bool> sentWake {false};
bool isAllowApc = false;
static TimePoint readClock();
void waitIocp(DWORD timeoutMs);
// Wait on the I/O completion port for up to timeoutMs and pump events. Does not advance the
// timer; caller must do that.
bool receivedWake();
static AutoCloseHandle newIocpHandle();
static AutoCloseHandle openCurrentThread();
};
} // namespace kj
#endif // KJ_ASYNC_WIN32_H_

View File

@ -1,682 +0,0 @@
// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#ifndef KJ_ASYNC_H_
#define KJ_ASYNC_H_
#if defined(__GNUC__) && !KJ_HEADER_WARNINGS
#pragma GCC system_header
#endif
#include "async-prelude.h"
#include "exception.h"
#include "refcount.h"
namespace kj {
class EventLoop;
class WaitScope;
template <typename T>
class Promise;
template <typename T>
class ForkedPromise;
template <typename T>
class PromiseFulfiller;
template <typename T>
struct PromiseFulfillerPair;
template <typename Func, typename T>
using PromiseForResult = Promise<_::JoinPromises<_::ReturnType<Func, T>>>;
// Evaluates to the type of Promise for the result of calling functor type Func with parameter type
// T. If T is void, then the promise is for the result of calling Func with no arguments. If
// Func itself returns a promise, the promises are joined, so you never get Promise<Promise<T>>.
// =======================================================================================
// Promises
template <typename T>
class Promise: protected _::PromiseBase {
// The basic primitive of asynchronous computation in KJ. Similar to "futures", but designed
// specifically for event loop concurrency. Similar to E promises and JavaScript Promises/A.
//
// A Promise represents a promise to produce a value of type T some time in the future. Once
// that value has been produced, the promise is "fulfilled". Alternatively, a promise can be
// "broken", with an Exception describing what went wrong. You may implicitly convert a value of
// type T to an already-fulfilled Promise<T>. You may implicitly convert the constant
// `kj::READY_NOW` to an already-fulfilled Promise<void>. You may also implicitly convert a
// `kj::Exception` to an already-broken promise of any type.
//
// Promises are linear types -- they are moveable but not copyable. If a Promise is destroyed
// or goes out of scope (without being moved elsewhere), any ongoing asynchronous operations
// meant to fulfill the promise will be canceled if possible. All methods of `Promise` (unless
// otherwise noted) actually consume the promise in the sense of move semantics. (Arguably they
// should be rvalue-qualified, but at the time this interface was created compilers didn't widely
// support that yet and anyway it would be pretty ugly typing kj::mv(promise).whatever().) If
// you want to use one Promise in two different places, you must fork it with `fork()`.
//
// To use the result of a Promise, you must call `then()` and supply a callback function to
// call with the result. `then()` returns another promise, for the result of the callback.
// Any time that this would result in Promise<Promise<T>>, the promises are collapsed into a
// simple Promise<T> that first waits for the outer promise, then the inner. Example:
//
// // Open a remote file, read the content, and then count the
// // number of lines of text.
// // Note that none of the calls here block. `file`, `content`
// // and `lineCount` are all initialized immediately before any
// // asynchronous operations occur. The lambda callbacks are
// // called later.
// Promise<Own<File>> file = openFtp("ftp://host/foo/bar");
// Promise<String> content = file.then(
// [](Own<File> file) -> Promise<String> {
// return file.readAll();
// });
// Promise<int> lineCount = content.then(
// [](String text) -> int {
// uint count = 0;
// for (char c: text) count += (c == '\n');
// return count;
// });
//
// For `then()` to work, the current thread must have an active `EventLoop`. Each callback
// is scheduled to execute in that loop. Since `then()` schedules callbacks only on the current
// thread's event loop, you do not need to worry about two callbacks running at the same time.
// You will need to set up at least one `EventLoop` at the top level of your program before you
// can use promises.
//
// To adapt a non-Promise-based asynchronous API to promises, use `newAdaptedPromise()`.
//
// Systems using promises should consider supporting the concept of "pipelining". Pipelining
// means allowing a caller to start issuing method calls against a promised object before the
// promise has actually been fulfilled. This is particularly useful if the promise is for a
// remote object living across a network, as this can avoid round trips when chaining a series
// of calls. It is suggested that any class T which supports pipelining implement a subclass of
// Promise<T> which adds "eventual send" methods -- methods which, when called, say "please
// invoke the corresponding method on the promised value once it is available". These methods
// should in turn return promises for the eventual results of said invocations. Cap'n Proto,
// for example, implements the type `RemotePromise` which supports pipelining RPC requests -- see
// `capnp/capability.h`.
//
// KJ Promises are based on E promises:
// http://wiki.erights.org/wiki/Walnut/Distributed_Computing#Promises
//
// KJ Promises are also inspired in part by the evolving standards for JavaScript/ECMAScript
// promises, which are themselves influenced by E promises:
// http://promisesaplus.com/
// https://github.com/domenic/promises-unwrapping
public:
Promise(_::FixVoid<T> value);
// Construct an already-fulfilled Promise from a value of type T. For non-void promises, the
// parameter type is simply T. So, e.g., in a function that returns `Promise<int>`, you can
// say `return 123;` to return a promise that is already fulfilled to 123.
//
// For void promises, use `kj::READY_NOW` as the value, e.g. `return kj::READY_NOW`.
Promise(kj::Exception&& e);
// Construct an already-broken Promise.
inline Promise(decltype(nullptr)) {}
template <typename Func, typename ErrorFunc = _::PropagateException>
PromiseForResult<Func, T> then(Func&& func, ErrorFunc&& errorHandler = _::PropagateException())
KJ_WARN_UNUSED_RESULT;
// Register a continuation function to be executed when the promise completes. The continuation
// (`func`) takes the promised value (an rvalue of type `T`) as its parameter. The continuation
// may return a new value; `then()` itself returns a promise for the continuation's eventual
// result. If the continuation itself returns a `Promise<U>`, then `then()` shall also return
// a `Promise<U>` which first waits for the original promise, then executes the continuation,
// then waits for the inner promise (i.e. it automatically "unwraps" the promise).
//
// In all cases, `then()` returns immediately. The continuation is executed later. The
// continuation is always executed on the same EventLoop (and, therefore, the same thread) which
// called `then()`, therefore no synchronization is necessary on state shared by the continuation
// and the surrounding scope. If no EventLoop is running on the current thread, `then()` throws
// an exception.
//
// You may also specify an error handler continuation as the second parameter. `errorHandler`
// must be a functor taking a parameter of type `kj::Exception&&`. It must return the same
// type as `func` returns (except when `func` returns `Promise<U>`, in which case `errorHandler`
// may return either `Promise<U>` or just `U`). The default error handler simply propagates the
// exception to the returned promise.
//
// Either `func` or `errorHandler` may, of course, throw an exception, in which case the promise
// is broken. When compiled with -fno-exceptions, the framework will still detect when a
// recoverable exception was thrown inside of a continuation and will consider the promise
// broken even though a (presumably garbage) result was returned.
//
// If the returned promise is destroyed before the callback runs, the callback will be canceled
// (it will never run).
//
// Note that `then()` -- like all other Promise methods -- consumes the promise on which it is
// called, in the sense of move semantics. After returning, the original promise is no longer
// valid, but `then()` returns a new promise.
//
// *Advanced implementation tips:* Most users will never need to worry about the below, but
// it is good to be aware of.
//
// As an optimization, if the callback function `func` does _not_ return another promise, then
// execution of `func` itself may be delayed until its result is known to be needed. The
// expectation here is that `func` is just doing some transformation on the results, not
// scheduling any other actions, therefore the system doesn't need to be proactive about
// evaluating it. This way, a chain of trivial then() transformations can be executed all at
// once without repeatedly re-scheduling through the event loop. Use the `eagerlyEvaluate()`
// method to suppress this behavior.
//
// On the other hand, if `func` _does_ return another promise, then the system evaluates `func`
// as soon as possible, because the promise it returns might be for a newly-scheduled
// long-running asynchronous task.
//
// As another optimization, when a callback function registered with `then()` is actually
// scheduled, it is scheduled to occur immediately, preempting other work in the event queue.
// This allows a long chain of `then`s to execute all at once, improving cache locality by
// clustering operations on the same data. However, this implies that starvation can occur
// if a chain of `then()`s takes a very long time to execute without ever stopping to wait for
// actual I/O. To solve this, use `kj::evalLater()` to yield control; this way, all other events
// in the queue will get a chance to run before your callback is executed.
Promise<void> ignoreResult() KJ_WARN_UNUSED_RESULT { return then([](T&&) {}); }
// Convenience method to convert the promise to a void promise by ignoring the return value.
//
// You must still wait on the returned promise if you want the task to execute.
template <typename ErrorFunc>
Promise<T> catch_(ErrorFunc&& errorHandler) KJ_WARN_UNUSED_RESULT;
// Equivalent to `.then(identityFunc, errorHandler)`, where `identifyFunc` is a function that
// just returns its input.
T wait(WaitScope& waitScope);
// Run the event loop until the promise is fulfilled, then return its result. If the promise
// is rejected, throw an exception.
//
// wait() is primarily useful at the top level of a program -- typically, within the function
// that allocated the EventLoop. For example, a program that performs one or two RPCs and then
// exits would likely use wait() in its main() function to wait on each RPC. On the other hand,
// server-side code generally cannot use wait(), because it has to be able to accept multiple
// requests at once.
//
// If the promise is rejected, `wait()` throws an exception. If the program was compiled without
// exceptions (-fno-exceptions), this will usually abort. In this case you really should first
// use `then()` to set an appropriate handler for the exception case, so that the promise you
// actually wait on never throws.
//
// `waitScope` is an object proving that the caller is in a scope where wait() is allowed. By
// convention, any function which might call wait(), or which might call another function which
// might call wait(), must take `WaitScope&` as one of its parameters. This is needed for two
// reasons:
// * `wait()` is not allowed during an event callback, because event callbacks are themselves
// called during some other `wait()`, and such recursive `wait()`s would only be able to
// complete in LIFO order, which might mean that the outer `wait()` ends up waiting longer
// than it is supposed to. To prevent this, a `WaitScope` cannot be constructed or used during
// an event callback.
// * Since `wait()` runs the event loop, unrelated event callbacks may execute before `wait()`
// returns. This means that anyone calling `wait()` must be reentrant -- state may change
// around them in arbitrary ways. Therefore, callers really need to know if a function they
// are calling might wait(), and the `WaitScope&` parameter makes this clear.
//
// TODO(someday): Implement fibers, and let them call wait() even when they are handling an
// event.
ForkedPromise<T> fork() KJ_WARN_UNUSED_RESULT;
// Forks the promise, so that multiple different clients can independently wait on the result.
// `T` must be copy-constructable for this to work. Or, in the special case where `T` is
// `Own<U>`, `U` must have a method `Own<U> addRef()` which returns a new reference to the same
// (or an equivalent) object (probably implemented via reference counting).
_::SplitTuplePromise<T> split();
// Split a promise for a tuple into a tuple of promises.
//
// E.g. if you have `Promise<kj::Tuple<T, U>>`, `split()` returns
// `kj::Tuple<Promise<T>, Promise<U>>`.
Promise<T> exclusiveJoin(Promise<T>&& other) KJ_WARN_UNUSED_RESULT;
// Return a new promise that resolves when either the original promise resolves or `other`
// resolves (whichever comes first). The promise that didn't resolve first is canceled.
// TODO(someday): inclusiveJoin(), or perhaps just join(), which waits for both completions
// and produces a tuple?
template <typename... Attachments>
Promise<T> attach(Attachments&&... attachments) KJ_WARN_UNUSED_RESULT;
// "Attaches" one or more movable objects (often, Own<T>s) to the promise, such that they will
// be destroyed when the promise resolves. This is useful when a promise's callback contains
// pointers into some object and you want to make sure the object still exists when the callback
// runs -- after calling then(), use attach() to add necessary objects to the result.
template <typename ErrorFunc>
Promise<T> eagerlyEvaluate(ErrorFunc&& errorHandler) KJ_WARN_UNUSED_RESULT;
Promise<T> eagerlyEvaluate(decltype(nullptr)) KJ_WARN_UNUSED_RESULT;
// Force eager evaluation of this promise. Use this if you are going to hold on to the promise
// for awhile without consuming the result, but you want to make sure that the system actually
// processes it.
//
// `errorHandler` is a function that takes `kj::Exception&&`, like the second parameter to
// `then()`, except that it must return void. We make you specify this because otherwise it's
// easy to forget to handle errors in a promise that you never use. You may specify nullptr for
// the error handler if you are sure that ignoring errors is fine, or if you know that you'll
// eventually wait on the promise somewhere.
template <typename ErrorFunc>
void detach(ErrorFunc&& errorHandler);
// Allows the promise to continue running in the background until it completes or the
// `EventLoop` is destroyed. Be careful when using this: since you can no longer cancel this
// promise, you need to make sure that the promise owns all the objects it touches or make sure
// those objects outlive the EventLoop.
//
// `errorHandler` is a function that takes `kj::Exception&&`, like the second parameter to
// `then()`, except that it must return void.
//
// This function exists mainly to implement the Cap'n Proto requirement that RPC calls cannot be
// canceled unless the callee explicitly permits it.
kj::String trace();
// Returns a dump of debug info about this promise. Not for production use. Requires RTTI.
// This method does NOT consume the promise as other methods do.
private:
Promise(bool, Own<_::PromiseNode>&& node): PromiseBase(kj::mv(node)) {}
// Second parameter prevent ambiguity with immediate-value constructor.
template <typename>
friend class Promise;
friend class EventLoop;
template <typename U, typename Adapter, typename... Params>
friend Promise<U> newAdaptedPromise(Params&&... adapterConstructorParams);
template <typename U>
friend PromiseFulfillerPair<U> newPromiseAndFulfiller();
template <typename>
friend class _::ForkHub;
friend class _::TaskSetImpl;
friend Promise<void> _::yield();
friend class _::NeverDone;
template <typename U>
friend Promise<Array<U>> joinPromises(Array<Promise<U>>&& promises);
friend Promise<void> joinPromises(Array<Promise<void>>&& promises);
};
template <typename T>
class ForkedPromise {
// The result of `Promise::fork()` and `EventLoop::fork()`. Allows branches to be created.
// Like `Promise<T>`, this is a pass-by-move type.
public:
inline ForkedPromise(decltype(nullptr)) {}
Promise<T> addBranch();
// Add a new branch to the fork. The branch is equivalent to the original promise.
private:
Own<_::ForkHub<_::FixVoid<T>>> hub;
inline ForkedPromise(bool, Own<_::ForkHub<_::FixVoid<T>>>&& hub): hub(kj::mv(hub)) {}
friend class Promise<T>;
friend class EventLoop;
};
constexpr _::Void READY_NOW = _::Void();
// Use this when you need a Promise<void> that is already fulfilled -- this value can be implicitly
// cast to `Promise<void>`.
constexpr _::NeverDone NEVER_DONE = _::NeverDone();
// The opposite of `READY_NOW`, return this when the promise should never resolve. This can be
// implicitly converted to any promise type. You may also call `NEVER_DONE.wait()` to wait
// forever (useful for servers).
template <typename Func>
PromiseForResult<Func, void> evalLater(Func&& func) KJ_WARN_UNUSED_RESULT;
// Schedule for the given zero-parameter function to be executed in the event loop at some
// point in the near future. Returns a Promise for its result -- or, if `func()` itself returns
// a promise, `evalLater()` returns a Promise for the result of resolving that promise.
//
// Example usage:
// Promise<int> x = evalLater([]() { return 123; });
//
// The above is exactly equivalent to:
// Promise<int> x = Promise<void>(READY_NOW).then([]() { return 123; });
//
// If the returned promise is destroyed before the callback runs, the callback will be canceled
// (never called).
//
// If you schedule several evaluations with `evalLater` during the same callback, they are
// guaranteed to be executed in order.
template <typename Func>
PromiseForResult<Func, void> evalNow(Func&& func) KJ_WARN_UNUSED_RESULT;
// Run `func()` and return a promise for its result. `func()` executes before `evalNow()` returns.
// If `func()` throws an exception, the exception is caught and wrapped in a promise -- this is the
// main reason why `evalNow()` is useful.
template <typename T>
Promise<Array<T>> joinPromises(Array<Promise<T>>&& promises);
// Join an array of promises into a promise for an array.
// =======================================================================================
// Hack for creating a lambda that holds an owned pointer.
template <typename Func, typename MovedParam>
class CaptureByMove {
public:
inline CaptureByMove(Func&& func, MovedParam&& param)
: func(kj::mv(func)), param(kj::mv(param)) {}
template <typename... Params>
inline auto operator()(Params&&... params)
-> decltype(kj::instance<Func>()(kj::instance<MovedParam&&>(), kj::fwd<Params>(params)...)) {
return func(kj::mv(param), kj::fwd<Params>(params)...);
}
private:
Func func;
MovedParam param;
};
template <typename Func, typename MovedParam>
inline CaptureByMove<Func, Decay<MovedParam>> mvCapture(MovedParam&& param, Func&& func) {
// Hack to create a "lambda" which captures a variable by moving it rather than copying or
// referencing. C++14 generalized captures should make this obsolete, but for now in C++11 this
// is commonly needed for Promise continuations that own their state. Example usage:
//
// Own<Foo> ptr = makeFoo();
// Promise<int> promise = callRpc();
// promise.then(mvCapture(ptr, [](Own<Foo>&& ptr, int result) {
// return ptr->finish(result);
// }));
return CaptureByMove<Func, Decay<MovedParam>>(kj::fwd<Func>(func), kj::mv(param));
}
// =======================================================================================
// Advanced promise construction
template <typename T>
class PromiseFulfiller {
// A callback which can be used to fulfill a promise. Only the first call to fulfill() or
// reject() matters; subsequent calls are ignored.
public:
virtual void fulfill(T&& value) = 0;
// Fulfill the promise with the given value.
virtual void reject(Exception&& exception) = 0;
// Reject the promise with an error.
virtual bool isWaiting() = 0;
// Returns true if the promise is still unfulfilled and someone is potentially waiting for it.
// Returns false if fulfill()/reject() has already been called *or* if the promise to be
// fulfilled has been discarded and therefore the result will never be used anyway.
template <typename Func>
bool rejectIfThrows(Func&& func);
// Call the function (with no arguments) and return true. If an exception is thrown, call
// `fulfiller.reject()` and then return false. When compiled with exceptions disabled,
// non-fatal exceptions are still detected and handled correctly.
};
template <>
class PromiseFulfiller<void> {
// Specialization of PromiseFulfiller for void promises. See PromiseFulfiller<T>.
public:
virtual void fulfill(_::Void&& value = _::Void()) = 0;
// Call with zero parameters. The parameter is a dummy that only exists so that subclasses don't
// have to specialize for <void>.
virtual void reject(Exception&& exception) = 0;
virtual bool isWaiting() = 0;
template <typename Func>
bool rejectIfThrows(Func&& func);
};
template <typename T, typename Adapter, typename... Params>
Promise<T> newAdaptedPromise(Params&&... adapterConstructorParams);
// Creates a new promise which owns an instance of `Adapter` which encapsulates the operation
// that will eventually fulfill the promise. This is primarily useful for adapting non-KJ
// asynchronous APIs to use promises.
//
// An instance of `Adapter` will be allocated and owned by the returned `Promise`. A
// `PromiseFulfiller<T>&` will be passed as the first parameter to the adapter's constructor,
// and `adapterConstructorParams` will be forwarded as the subsequent parameters. The adapter
// is expected to perform some asynchronous operation and call the `PromiseFulfiller<T>` once
// it is finished.
//
// The adapter is destroyed when its owning Promise is destroyed. This may occur before the
// Promise has been fulfilled. In this case, the adapter's destructor should cancel the
// asynchronous operation. Once the adapter is destroyed, the fulfillment callback cannot be
// called.
//
// An adapter implementation should be carefully written to ensure that it cannot accidentally
// be left unfulfilled permanently because of an exception. Consider making liberal use of
// `PromiseFulfiller<T>::rejectIfThrows()`.
template <typename T>
struct PromiseFulfillerPair {
Promise<_::JoinPromises<T>> promise;
Own<PromiseFulfiller<T>> fulfiller;
};
template <typename T>
PromiseFulfillerPair<T> newPromiseAndFulfiller();
// Construct a Promise and a separate PromiseFulfiller which can be used to fulfill the promise.
// If the PromiseFulfiller is destroyed before either of its methods are called, the Promise is
// implicitly rejected.
//
// Although this function is easier to use than `newAdaptedPromise()`, it has the serious drawback
// that there is no way to handle cancellation (i.e. detect when the Promise is discarded).
//
// You can arrange to fulfill a promise with another promise by using a promise type for T. E.g.
// `newPromiseAndFulfiller<Promise<U>>()` will produce a promise of type `Promise<U>` but the
// fulfiller will be of type `PromiseFulfiller<Promise<U>>`. Thus you pass a `Promise<U>` to the
// `fulfill()` callback, and the promises are chained.
// =======================================================================================
// TaskSet
class TaskSet {
// Holds a collection of Promise<void>s and ensures that each executes to completion. Memory
// associated with each promise is automatically freed when the promise completes. Destroying
// the TaskSet itself automatically cancels all unfinished promises.
//
// This is useful for "daemon" objects that perform background tasks which aren't intended to
// fulfill any particular external promise, but which may need to be canceled (and thus can't
// use `Promise::detach()`). The daemon object holds a TaskSet to collect these tasks it is
// working on. This way, if the daemon itself is destroyed, the TaskSet is detroyed as well,
// and everything the daemon is doing is canceled.
public:
class ErrorHandler {
public:
virtual void taskFailed(kj::Exception&& exception) = 0;
};
TaskSet(ErrorHandler& errorHandler);
// `loop` will be used to wait on promises. `errorHandler` will be executed any time a task
// throws an exception, and will execute within the given EventLoop.
~TaskSet() noexcept(false);
void add(Promise<void>&& promise);
kj::String trace();
// Return debug info about all promises currently in the TaskSet.
private:
Own<_::TaskSetImpl> impl;
};
// =======================================================================================
// The EventLoop class
class EventPort {
// Interfaces between an `EventLoop` and events originating from outside of the loop's thread.
// All such events come in through the `EventPort` implementation.
//
// An `EventPort` implementation may interface with low-level operating system APIs and/or other
// threads. You can also write an `EventPort` which wraps some other (non-KJ) event loop
// framework, allowing the two to coexist in a single thread.
public:
virtual bool wait() = 0;
// Wait for an external event to arrive, sleeping if necessary. Once at least one event has
// arrived, queue it to the event loop (e.g. by fulfilling a promise) and return.
//
// This is called during `Promise::wait()` whenever the event queue becomes empty, in order to
// wait for new events to populate the queue.
//
// It is safe to return even if nothing has actually been queued, so long as calling `wait()` in
// a loop will eventually sleep. (That is to say, false positives are fine.)
//
// Returns true if wake() has been called from another thread. (Precisely, returns true if
// no previous call to wait `wait()` nor `poll()` has returned true since `wake()` was last
// called.)
virtual bool poll() = 0;
// Check if any external events have arrived, but do not sleep. If any events have arrived,
// add them to the event queue (e.g. by fulfilling promises) before returning.
//
// This may be called during `Promise::wait()` when the EventLoop has been executing for a while
// without a break but is still non-empty.
//
// Returns true if wake() has been called from another thread. (Precisely, returns true if
// no previous call to wait `wait()` nor `poll()` has returned true since `wake()` was last
// called.)
virtual void setRunnable(bool runnable);
// Called to notify the `EventPort` when the `EventLoop` has work to do; specifically when it
// transitions from empty -> runnable or runnable -> empty. This is typically useful when
// integrating with an external event loop; if the loop is currently runnable then you should
// arrange to call run() on it soon. The default implementation does nothing.
virtual void wake() const;
// Wake up the EventPort's thread from another thread.
//
// Unlike all other methods on this interface, `wake()` may be called from another thread, hence
// it is `const`.
//
// Technically speaking, `wake()` causes the target thread to cease sleeping and not to sleep
// again until `wait()` or `poll()` has returned true at least once.
//
// The default implementation throws an UNIMPLEMENTED exception.
};
class EventLoop {
// Represents a queue of events being executed in a loop. Most code won't interact with
// EventLoop directly, but instead use `Promise`s to interact with it indirectly. See the
// documentation for `Promise`.
//
// Each thread can have at most one current EventLoop. To make an `EventLoop` current for
// the thread, create a `WaitScope`. Async APIs require that the thread has a current EventLoop,
// or they will throw exceptions. APIs that use `Promise::wait()` additionally must explicitly
// be passed a reference to the `WaitScope` to make the caller aware that they might block.
//
// Generally, you will want to construct an `EventLoop` at the top level of your program, e.g.
// in the main() function, or in the start function of a thread. You can then use it to
// construct some promises and wait on the result. Example:
//
// int main() {
// // `loop` becomes the official EventLoop for the thread.
// MyEventPort eventPort;
// EventLoop loop(eventPort);
//
// // Now we can call an async function.
// Promise<String> textPromise = getHttp("http://example.com");
//
// // And we can wait for the promise to complete. Note that you can only use `wait()`
// // from the top level, not from inside a promise callback.
// String text = textPromise.wait();
// print(text);
// return 0;
// }
//
// Most applications that do I/O will prefer to use `setupAsyncIo()` from `async-io.h` rather
// than allocate an `EventLoop` directly.
public:
EventLoop();
// Construct an `EventLoop` which does not receive external events at all.
explicit EventLoop(EventPort& port);
// Construct an `EventLoop` which receives external events through the given `EventPort`.
~EventLoop() noexcept(false);
void run(uint maxTurnCount = maxValue);
// Run the event loop for `maxTurnCount` turns or until there is nothing left to be done,
// whichever comes first. This never calls the `EventPort`'s `sleep()` or `poll()`. It will
// call the `EventPort`'s `setRunnable(false)` if the queue becomes empty.
bool isRunnable();
// Returns true if run() would currently do anything, or false if the queue is empty.
private:
EventPort& port;
bool running = false;
// True while looping -- wait() is then not allowed.
bool lastRunnableState = false;
// What did we last pass to port.setRunnable()?
_::Event* head = nullptr;
_::Event** tail = &head;
_::Event** depthFirstInsertPoint = &head;
Own<_::TaskSetImpl> daemons;
bool turn();
void setRunnable(bool runnable);
void enterScope();
void leaveScope();
friend void _::detach(kj::Promise<void>&& promise);
friend void _::waitImpl(Own<_::PromiseNode>&& node, _::ExceptionOrValue& result,
WaitScope& waitScope);
friend class _::Event;
friend class WaitScope;
};
class WaitScope {
// Represents a scope in which asynchronous programming can occur. A `WaitScope` should usually
// be allocated on the stack and serves two purposes:
// * While the `WaitScope` exists, its `EventLoop` is registered as the current loop for the
// thread. Most operations dealing with `Promise` (including all of its methods) do not work
// unless the thread has a current `EventLoop`.
// * `WaitScope` may be passed to `Promise::wait()` to synchronously wait for a particular
// promise to complete. See `Promise::wait()` for an extended discussion.
public:
inline explicit WaitScope(EventLoop& loop): loop(loop) { loop.enterScope(); }
inline ~WaitScope() { loop.leaveScope(); }
KJ_DISALLOW_COPY(WaitScope);
private:
EventLoop& loop;
friend class EventLoop;
friend void _::waitImpl(Own<_::PromiseNode>&& node, _::ExceptionOrValue& result,
WaitScope& waitScope);
};
} // namespace kj
#include "async-inl.h"
#endif // KJ_ASYNC_H_

File diff suppressed because it is too large Load Diff

View File

@ -1,122 +0,0 @@
// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#ifndef KJ_COMPAT_GTEST_H_
#define KJ_COMPAT_GTEST_H_
// This file defines compatibility macros converting Google Test tests into KJ tests.
//
// This is only intended to cover the most common functionality. Many tests will likely need
// additional tweaks. For instance:
// - Using operator<< to print information on failure is not supported. Instead, switch to
// KJ_ASSERT/KJ_EXPECT and pass in stuff to print as additional parameters.
// - Test fixtures are not supported. Allocate your "test fixture" on the stack instead. Do setup
// in the constructor, teardown in the destructor.
#include "../test.h"
namespace kj {
namespace _ { // private
template <typename T>
T abs(T value) { return value < 0 ? -value : value; }
inline bool floatAlmostEqual(float a, float b) {
return a == b || abs(a - b) < (abs(a) + abs(b)) * 1e-5;
}
inline bool doubleAlmostEqual(double a, double b) {
return a == b || abs(a - b) < (abs(a) + abs(b)) * 1e-12;
}
} // namespace _ (private)
#define EXPECT_FALSE(x) KJ_EXPECT(!(x))
#define EXPECT_TRUE(x) KJ_EXPECT(x)
#define EXPECT_EQ(x, y) KJ_EXPECT((x) == (y), x, y)
#define EXPECT_NE(x, y) KJ_EXPECT((x) != (y), x, y)
#define EXPECT_LE(x, y) KJ_EXPECT((x) <= (y), x, y)
#define EXPECT_GE(x, y) KJ_EXPECT((x) >= (y), x, y)
#define EXPECT_LT(x, y) KJ_EXPECT((x) < (y), x, y)
#define EXPECT_GT(x, y) KJ_EXPECT((x) > (y), x, y)
#define EXPECT_STREQ(x, y) KJ_EXPECT(::strcmp(x, y) == 0, x, y)
#define EXPECT_FLOAT_EQ(x, y) KJ_EXPECT(::kj::_::floatAlmostEqual(y, x), y, x);
#define EXPECT_DOUBLE_EQ(x, y) KJ_EXPECT(::kj::_::doubleAlmostEqual(y, x), y, x);
#define ASSERT_FALSE(x) KJ_ASSERT(!(x))
#define ASSERT_TRUE(x) KJ_ASSERT(x)
#define ASSERT_EQ(x, y) KJ_ASSERT((x) == (y), x, y)
#define ASSERT_NE(x, y) KJ_ASSERT((x) != (y), x, y)
#define ASSERT_LE(x, y) KJ_ASSERT((x) <= (y), x, y)
#define ASSERT_GE(x, y) KJ_ASSERT((x) >= (y), x, y)
#define ASSERT_LT(x, y) KJ_ASSERT((x) < (y), x, y)
#define ASSERT_GT(x, y) KJ_ASSERT((x) > (y), x, y)
#define ASSERT_STREQ(x, y) KJ_ASSERT(::strcmp(x, y) == 0, x, y)
#define ASSERT_FLOAT_EQ(x, y) KJ_ASSERT(::kj::_::floatAlmostEqual(y, x), y, x);
#define ASSERT_DOUBLE_EQ(x, y) KJ_ASSERT(::kj::_::doubleAlmostEqual(y, x), y, x);
class AddFailureAdapter {
public:
AddFailureAdapter(const char* file, int line): file(file), line(line) {}
~AddFailureAdapter() {
if (!handled) {
_::Debug::log(file, line, LogSeverity::ERROR, "expectation failed");
}
}
template <typename T>
void operator<<(T&& info) {
handled = true;
_::Debug::log(file, line, LogSeverity::ERROR, "\"expectation failed\", info",
"expectation failed", kj::fwd<T>(info));
}
private:
bool handled = false;
const char* file;
int line;
};
#define ADD_FAILURE() ::kj::AddFailureAdapter(__FILE__, __LINE__)
#if KJ_NO_EXCEPTIONS
#define EXPECT_ANY_THROW(code) \
KJ_EXPECT(::kj::_::expectFatalThrow(nullptr, nullptr, [&]() { code; }))
#else
#define EXPECT_ANY_THROW(code) \
KJ_EXPECT(::kj::runCatchingExceptions([&]() { code; }) != nullptr)
#endif
#define EXPECT_NONFATAL_FAILURE(code) \
EXPECT_TRUE(kj::runCatchingExceptions([&]() { code; }) != nullptr);
#ifdef KJ_DEBUG
#define EXPECT_DEBUG_ANY_THROW EXPECT_ANY_THROW
#else
#define EXPECT_DEBUG_ANY_THROW(EXP)
#endif
#define TEST(x, y) KJ_TEST("legacy test: " #x "/" #y)
} // namespace kj
#endif // KJ_COMPAT_GTEST_H_

View File

@ -1,636 +0,0 @@
// Copyright (c) 2017 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#ifndef KJ_COMPAT_HTTP_H_
#define KJ_COMPAT_HTTP_H_
// The KJ HTTP client/server library.
//
// This is a simple library which can be used to implement an HTTP client or server. Properties
// of this library include:
// - Uses KJ async framework.
// - Agnostic to transport layer -- you can provide your own.
// - Header parsing is zero-copy -- it results in strings that point directly into the buffer
// received off the wire.
// - Application code which reads and writes headers refers to headers by symbolic names, not by
// string literals, with lookups being array-index-based, not map-based. To make this possible,
// the application announces what headers it cares about in advance, in order to assign numeric
// values to them.
// - Methods are identified by an enum.
#include <kj/string.h>
#include <kj/vector.h>
#include <kj/memory.h>
#include <kj/one-of.h>
#include <kj/async-io.h>
namespace kj {
#define KJ_HTTP_FOR_EACH_METHOD(MACRO) \
MACRO(GET) \
MACRO(HEAD) \
MACRO(POST) \
MACRO(PUT) \
MACRO(DELETE) \
MACRO(PATCH) \
MACRO(PURGE) \
MACRO(OPTIONS) \
MACRO(TRACE) \
/* standard methods */ \
/* */ \
/* (CONNECT is intentionally omitted since it is handled specially in HttpHandler) */ \
\
MACRO(COPY) \
MACRO(LOCK) \
MACRO(MKCOL) \
MACRO(MOVE) \
MACRO(PROPFIND) \
MACRO(PROPPATCH) \
MACRO(SEARCH) \
MACRO(UNLOCK) \
/* WebDAV */ \
\
MACRO(REPORT) \
MACRO(MKACTIVITY) \
MACRO(CHECKOUT) \
MACRO(MERGE) \
/* Subversion */ \
\
MACRO(MSEARCH) \
MACRO(NOTIFY) \
MACRO(SUBSCRIBE) \
MACRO(UNSUBSCRIBE)
/* UPnP */
#define KJ_HTTP_FOR_EACH_CONNECTION_HEADER(MACRO) \
MACRO(connection, "Connection") \
MACRO(contentLength, "Content-Length") \
MACRO(keepAlive, "Keep-Alive") \
MACRO(te, "TE") \
MACRO(trailer, "Trailer") \
MACRO(transferEncoding, "Transfer-Encoding") \
MACRO(upgrade, "Upgrade")
enum class HttpMethod {
// Enum of known HTTP methods.
//
// We use an enum rather than a string to allow for faster parsing and switching and to reduce
// ambiguity.
#define DECLARE_METHOD(id) id,
KJ_HTTP_FOR_EACH_METHOD(DECLARE_METHOD)
#undef DECLARE_METHOD
};
kj::StringPtr KJ_STRINGIFY(HttpMethod method);
kj::Maybe<HttpMethod> tryParseHttpMethod(kj::StringPtr name);
class HttpHeaderTable;
class HttpHeaderId {
// Identifies an HTTP header by numeric ID that indexes into an HttpHeaderTable.
//
// The KJ HTTP API prefers that headers be identified by these IDs for a few reasons:
// - Integer lookups are much more efficient than string lookups.
// - Case-insensitivity is awkward to deal with when const strings are being passed to the lookup
// method.
// - Writing out strings less often means fewer typos.
//
// See HttpHeaderTable for usage hints.
public:
HttpHeaderId() = default;
inline bool operator==(const HttpHeaderId& other) const { return id == other.id; }
inline bool operator!=(const HttpHeaderId& other) const { return id != other.id; }
inline bool operator< (const HttpHeaderId& other) const { return id < other.id; }
inline bool operator> (const HttpHeaderId& other) const { return id > other.id; }
inline bool operator<=(const HttpHeaderId& other) const { return id <= other.id; }
inline bool operator>=(const HttpHeaderId& other) const { return id >= other.id; }
inline size_t hashCode() const { return id; }
kj::StringPtr toString() const;
void requireFrom(HttpHeaderTable& table) const;
// In debug mode, throws an exception if the HttpHeaderId is not from the given table.
//
// In opt mode, no-op.
#define KJ_HTTP_FOR_EACH_BUILTIN_HEADER(MACRO) \
MACRO(HOST, "Host") \
MACRO(DATE, "Date") \
MACRO(LOCATION, "Location") \
MACRO(CONTENT_TYPE, "Content-Type")
// For convenience, these very-common headers are valid for all HttpHeaderTables. You can refer
// to them like:
//
// HttpHeaderId::HOST
//
// TODO(0.7): Fill this out with more common headers.
#define DECLARE_HEADER(id, name) \
static const HttpHeaderId id;
// Declare a constant for each builtin header, e.g.: HttpHeaderId::CONNECTION
KJ_HTTP_FOR_EACH_BUILTIN_HEADER(DECLARE_HEADER);
#undef DECLARE_HEADER
private:
HttpHeaderTable* table;
uint id;
inline explicit constexpr HttpHeaderId(HttpHeaderTable* table, uint id): table(table), id(id) {}
friend class HttpHeaderTable;
friend class HttpHeaders;
};
class HttpHeaderTable {
// Construct an HttpHeaderTable to declare which headers you'll be interested in later on, and
// to manufacture IDs for them.
//
// Example:
//
// // Build a header table with the headers we are interested in.
// kj::HttpHeaderTable::Builder builder;
// const HttpHeaderId accept = builder.add("Accept");
// const HttpHeaderId contentType = builder.add("Content-Type");
// kj::HttpHeaderTable table(kj::mv(builder));
//
// // Create an HTTP client.
// auto client = kj::newHttpClient(table, network);
//
// // Get http://example.com.
// HttpHeaders headers(table);
// headers.set(accept, "text/html");
// auto response = client->send(kj::HttpMethod::GET, "http://example.com", headers)
// .wait(waitScope);
// auto msg = kj::str("Response content type: ", response.headers.get(contentType));
struct IdsByNameMap;
public:
HttpHeaderTable();
// Constructs a table that only contains the builtin headers.
class Builder {
public:
Builder();
HttpHeaderId add(kj::StringPtr name);
Own<HttpHeaderTable> build();
HttpHeaderTable& getFutureTable();
// Get the still-unbuilt header table. You cannot actually use it until build() has been
// called.
//
// This method exists to help when building a shared header table -- the Builder may be passed
// to several components, each of which will register the headers they need and get a reference
// to the future table.
private:
kj::Own<HttpHeaderTable> table;
};
KJ_DISALLOW_COPY(HttpHeaderTable); // Can't copy because HttpHeaderId points to the table.
~HttpHeaderTable() noexcept(false);
uint idCount();
// Return the number of IDs in the table.
kj::Maybe<HttpHeaderId> stringToId(kj::StringPtr name);
// Try to find an ID for the given name. The matching is case-insensitive, per the HTTP spec.
//
// Note: if `name` contains characters that aren't allowed in HTTP header names, this may return
// a bogus value rather than null, due to optimizations used in case-insensitive matching.
kj::StringPtr idToString(HttpHeaderId id);
// Get the canonical string name for the given ID.
private:
kj::Vector<kj::StringPtr> namesById;
kj::Own<IdsByNameMap> idsByName;
};
class HttpHeaders {
// Represents a set of HTTP headers.
//
// This class guards against basic HTTP header injection attacks: Trying to set a header name or
// value containing a newline, carriage return, or other invalid character will throw an
// exception.
public:
explicit HttpHeaders(HttpHeaderTable& table);
KJ_DISALLOW_COPY(HttpHeaders);
HttpHeaders(HttpHeaders&&) = default;
HttpHeaders& operator=(HttpHeaders&&) = default;
void clear();
// Clears all contents, as if the object was freshly-allocated. However, calling this rather
// than actually re-allocating the object may avoid re-allocation of internal objects.
HttpHeaders clone() const;
// Creates a deep clone of the HttpHeaders. The returned object owns all strings it references.
HttpHeaders cloneShallow() const;
// Creates a shallow clone of the HttpHeaders. The returned object references the same strings
// as the original, owning none of them.
kj::Maybe<kj::StringPtr> get(HttpHeaderId id) const;
// Read a header.
template <typename Func>
void forEach(Func&& func) const;
// Calls `func(name, value)` for each header in the set -- including headers that aren't mapped
// to IDs in the header table. Both inputs are of type kj::StringPtr.
void set(HttpHeaderId id, kj::StringPtr value);
void set(HttpHeaderId id, kj::String&& value);
// Sets a header value, overwriting the existing value.
//
// The String&& version is equivalent to calling the other version followed by takeOwnership().
//
// WARNING: It is the caller's responsibility to ensure that `value` remains valid until the
// HttpHeaders object is destroyed. This allows string literals to be passed without making a
// copy, but complicates the use of dynamic values. Hint: Consider using `takeOwnership()`.
void add(kj::StringPtr name, kj::StringPtr value);
void add(kj::StringPtr name, kj::String&& value);
void add(kj::String&& name, kj::String&& value);
// Append a header. `name` will be looked up in the header table, but if it's not mapped, the
// header will be added to the list of unmapped headers.
//
// The String&& versions are equivalent to calling the other version followed by takeOwnership().
//
// WARNING: It is the caller's responsibility to ensure that `name` and `value` remain valid
// until the HttpHeaders object is destroyed. This allows string literals to be passed without
// making a copy, but complicates the use of dynamic values. Hint: Consider using
// `takeOwnership()`.
void unset(HttpHeaderId id);
// Removes a header.
//
// It's not possible to remove a header by string name because non-indexed headers would take
// O(n) time to remove. Instead, construct a new HttpHeaders object and copy contents.
void takeOwnership(kj::String&& string);
void takeOwnership(kj::Array<char>&& chars);
void takeOwnership(HttpHeaders&& otherHeaders);
// Takes overship of a string so that it lives until the HttpHeaders object is destroyed. Useful
// when you've passed a dynamic value to set() or add() or parse*().
struct ConnectionHeaders {
// These headers govern details of the specific HTTP connection or framing of the content.
// Hence, they are managed internally within the HTTP library, and never appear in an
// HttpHeaders structure.
#define DECLARE_HEADER(id, name) \
kj::StringPtr id;
KJ_HTTP_FOR_EACH_CONNECTION_HEADER(DECLARE_HEADER)
#undef DECLARE_HEADER
};
struct Request {
HttpMethod method;
kj::StringPtr url;
ConnectionHeaders connectionHeaders;
};
struct Response {
uint statusCode;
kj::StringPtr statusText;
ConnectionHeaders connectionHeaders;
};
kj::Maybe<Request> tryParseRequest(kj::ArrayPtr<char> content);
kj::Maybe<Response> tryParseResponse(kj::ArrayPtr<char> content);
// Parse an HTTP header blob and add all the headers to this object.
//
// `content` should be all text from the start of the request to the first occurrance of two
// newlines in a row -- including the first of these two newlines, but excluding the second.
//
// The parse is performed with zero copies: The callee clobbers `content` with '\0' characters
// to split it into a bunch of shorter strings. The caller must keep `content` valid until the
// `HttpHeaders` is destroyed, or pass it to `takeOwnership()`.
kj::String serializeRequest(HttpMethod method, kj::StringPtr url,
const ConnectionHeaders& connectionHeaders) const;
kj::String serializeResponse(uint statusCode, kj::StringPtr statusText,
const ConnectionHeaders& connectionHeaders) const;
// Serialize the headers as a complete request or response blob. The blob uses '\r\n' newlines
// and includes the double-newline to indicate the end of the headers.
kj::String toString() const;
private:
HttpHeaderTable* table;
kj::Array<kj::StringPtr> indexedHeaders;
// Size is always table->idCount().
struct Header {
kj::StringPtr name;
kj::StringPtr value;
};
kj::Vector<Header> unindexedHeaders;
kj::Vector<kj::Array<char>> ownedStrings;
kj::Maybe<uint> addNoCheck(kj::StringPtr name, kj::StringPtr value);
kj::StringPtr cloneToOwn(kj::StringPtr str);
kj::String serialize(kj::ArrayPtr<const char> word1,
kj::ArrayPtr<const char> word2,
kj::ArrayPtr<const char> word3,
const ConnectionHeaders& connectionHeaders) const;
bool parseHeaders(char* ptr, char* end, ConnectionHeaders& connectionHeaders);
// TODO(perf): Arguably we should store a map, but header sets are never very long
// TODO(perf): We could optimize for common headers by storing them directly as fields. We could
// also add direct accessors for those headers.
};
class WebSocket {
public:
WebSocket(kj::Own<kj::AsyncIoStream> stream);
// Create a WebSocket wrapping the given I/O stream.
kj::Promise<void> send(kj::ArrayPtr<const byte> message);
kj::Promise<void> send(kj::ArrayPtr<const char> message);
};
class HttpClient {
// Interface to the client end of an HTTP connection.
//
// There are two kinds of clients:
// * Host clients are used when talking to a specific host. The `url` specified in a request
// is actually just a path. (A `Host` header is still required in all requests.)
// * Proxy clients are used when the target could be any arbitrary host on the internet.
// The `url` specified in a request is a full URL including protocol and hostname.
public:
struct Response {
uint statusCode;
kj::StringPtr statusText;
const HttpHeaders* headers;
kj::Own<kj::AsyncInputStream> body;
// `statusText` and `headers` remain valid until `body` is dropped.
};
struct Request {
kj::Own<kj::AsyncOutputStream> body;
// Write the request entity body to this stream, then drop it when done.
//
// May be null for GET and HEAD requests (which have no body) and requests that have
// Content-Length: 0.
kj::Promise<Response> response;
// Promise for the eventual respnose.
};
virtual Request request(HttpMethod method, kj::StringPtr url, const HttpHeaders& headers,
kj::Maybe<uint64_t> expectedBodySize = nullptr) = 0;
// Perform an HTTP request.
//
// `url` may be a full URL (with protocol and host) or it may be only the path part of the URL,
// depending on whether the client is a proxy client or a host client.
//
// `url` and `headers` need only remain valid until `request()` returns (they can be
// stack-allocated).
//
// `expectedBodySize`, if provided, must be exactly the number of bytes that will be written to
// the body. This will trigger use of the `Content-Length` connection header. Otherwise,
// `Transfer-Encoding: chunked` will be used.
struct WebSocketResponse {
uint statusCode;
kj::StringPtr statusText;
const HttpHeaders* headers;
kj::OneOf<kj::Own<kj::AsyncInputStream>, kj::Own<WebSocket>> upstreamOrBody;
// `statusText` and `headers` remain valid until `upstreamOrBody` is dropped.
};
virtual kj::Promise<WebSocketResponse> openWebSocket(
kj::StringPtr url, const HttpHeaders& headers, kj::Own<WebSocket> downstream);
// Tries to open a WebSocket. Default implementation calls send() and never returns a WebSocket.
//
// `url` and `headers` are invalidated when the returned promise resolves.
virtual kj::Promise<kj::Own<kj::AsyncIoStream>> connect(kj::String host);
// Handles CONNECT requests. Only relevant for proxy clients. Default implementation throws
// UNIMPLEMENTED.
};
class HttpService {
// Interface which HTTP services should implement.
//
// This interface is functionally equivalent to HttpClient, but is intended for applications to
// implement rather than call. The ergonomics and performance of the method signatures are
// optimized for the serving end.
//
// As with clients, there are two kinds of services:
// * Host services are used when talking to a specific host. The `url` specified in a request
// is actually just a path. (A `Host` header is still required in all requests, and the service
// may in fact serve multiple origins via this header.)
// * Proxy services are used when the target could be any arbitrary host on the internet, i.e. to
// implement an HTTP proxy. The `url` specified in a request is a full URL including protocol
// and hostname.
public:
class Response {
public:
virtual kj::Own<kj::AsyncOutputStream> send(
uint statusCode, kj::StringPtr statusText, const HttpHeaders& headers,
kj::Maybe<uint64_t> expectedBodySize = nullptr) = 0;
// Begin the response.
//
// `statusText` and `headers` need only remain valid until send() returns (they can be
// stack-allocated).
};
virtual kj::Promise<void> request(
HttpMethod method, kj::StringPtr url, const HttpHeaders& headers,
kj::AsyncInputStream& requestBody, Response& response) = 0;
// Perform an HTTP request.
//
// `url` may be a full URL (with protocol and host) or it may be only the path part of the URL,
// depending on whether the service is a proxy service or a host service.
//
// `url` and `headers` are invalidated on the first read from `requestBody` or when the returned
// promise resolves, whichever comes first.
class WebSocketResponse: public Response {
public:
kj::Own<WebSocket> startWebSocket(
uint statusCode, kj::StringPtr statusText, const HttpHeaders& headers,
WebSocket& upstream);
// Begin the response.
//
// `statusText` and `headers` need only remain valid until startWebSocket() returns (they can
// be stack-allocated).
};
virtual kj::Promise<void> openWebSocket(
kj::StringPtr url, const HttpHeaders& headers, WebSocketResponse& response);
// Tries to open a WebSocket. Default implementation calls request() and never returns a
// WebSocket.
//
// `url` and `headers` are invalidated when the returned promise resolves.
virtual kj::Promise<kj::Own<kj::AsyncIoStream>> connect(kj::String host);
// Handles CONNECT requests. Only relevant for proxy services. Default implementation throws
// UNIMPLEMENTED.
};
kj::Own<HttpClient> newHttpClient(HttpHeaderTable& responseHeaderTable, kj::Network& network,
kj::Maybe<kj::Network&> tlsNetwork = nullptr);
// Creates a proxy HttpClient that connects to hosts over the given network.
//
// `responseHeaderTable` is used when parsing HTTP responses. Requests can use any header table.
//
// `tlsNetwork` is required to support HTTPS destination URLs. Otherwise, only HTTP URLs can be
// fetched.
kj::Own<HttpClient> newHttpClient(HttpHeaderTable& responseHeaderTable, kj::AsyncIoStream& stream);
// Creates an HttpClient that speaks over the given pre-established connection. The client may
// be used as a proxy client or a host client depending on whether the peer is operating as
// a proxy.
//
// Note that since this client has only one stream to work with, it will try to pipeline all
// requests on this stream. If one request or response has an I/O failure, all subsequent requests
// fail as well. If the destination server chooses to close the connection after a response,
// subsequent requests will fail. If a response takes a long time, it blocks subsequent responses.
// If a WebSocket is opened successfully, all subsequent requests fail.
kj::Own<HttpClient> newHttpClient(HttpService& service);
kj::Own<HttpService> newHttpService(HttpClient& client);
// Adapts an HttpClient to an HttpService and vice versa.
struct HttpServerSettings {
kj::Duration headerTimeout = 15 * kj::SECONDS;
// After initial connection open, or after receiving the first byte of a pipelined request,
// the client must send the complete request within this time.
kj::Duration pipelineTimeout = 5 * kj::SECONDS;
// After one request/response completes, we'll wait up to this long for a pipelined request to
// arrive.
};
class HttpServer: private kj::TaskSet::ErrorHandler {
// Class which listens for requests on ports or connections and sends them to an HttpService.
public:
typedef HttpServerSettings Settings;
HttpServer(kj::Timer& timer, HttpHeaderTable& requestHeaderTable, HttpService& service,
Settings settings = Settings());
// Set up an HttpServer that directs incoming connections to the given service. The service
// may be a host service or a proxy service depending on whether you are intending to implement
// an HTTP server or an HTTP proxy.
kj::Promise<void> drain();
// Stop accepting new connections or new requests on existing connections. Finish any requests
// that are already executing, then close the connections. Returns once no more requests are
// in-flight.
kj::Promise<void> listenHttp(kj::ConnectionReceiver& port);
// Accepts HTTP connections on the given port and directs them to the handler.
//
// The returned promise never completes normally. It may throw if port.accept() throws. Dropping
// the returned promise will cause the server to stop listening on the port, but already-open
// connections will continue to be served. Destroy the whole HttpServer to cancel all I/O.
kj::Promise<void> listenHttp(kj::Own<kj::AsyncIoStream> connection);
// Reads HTTP requests from the given connection and directs them to the handler. A successful
// completion of the promise indicates that all requests received on the connection resulted in
// a complete response, and the client closed the connection gracefully or drain() was called.
// The promise throws if an unparseable request is received or if some I/O error occurs. Dropping
// the returned promise will cancel all I/O on the connection and cancel any in-flight requests.
private:
class Connection;
kj::Timer& timer;
HttpHeaderTable& requestHeaderTable;
HttpService& service;
Settings settings;
bool draining = false;
kj::ForkedPromise<void> onDrain;
kj::Own<kj::PromiseFulfiller<void>> drainFulfiller;
uint connectionCount = 0;
kj::Maybe<kj::Own<kj::PromiseFulfiller<void>>> zeroConnectionsFulfiller;
kj::TaskSet tasks;
HttpServer(kj::Timer& timer, HttpHeaderTable& requestHeaderTable, HttpService& service,
Settings settings, kj::PromiseFulfillerPair<void> paf);
kj::Promise<void> listenLoop(kj::ConnectionReceiver& port);
void taskFailed(kj::Exception&& exception) override;
};
// =======================================================================================
// inline implementation
inline void HttpHeaderId::requireFrom(HttpHeaderTable& table) const {
KJ_IREQUIRE(this->table == nullptr || this->table == &table,
"the provided HttpHeaderId is from the wrong HttpHeaderTable");
}
inline kj::Own<HttpHeaderTable> HttpHeaderTable::Builder::build() { return kj::mv(table); }
inline HttpHeaderTable& HttpHeaderTable::Builder::getFutureTable() { return *table; }
inline uint HttpHeaderTable::idCount() { return namesById.size(); }
inline kj::StringPtr HttpHeaderTable::idToString(HttpHeaderId id) {
id.requireFrom(*this);
return namesById[id.id];
}
inline kj::Maybe<kj::StringPtr> HttpHeaders::get(HttpHeaderId id) const {
id.requireFrom(*table);
auto result = indexedHeaders[id.id];
return result == nullptr ? kj::Maybe<kj::StringPtr>(nullptr) : result;
}
inline void HttpHeaders::unset(HttpHeaderId id) {
id.requireFrom(*table);
indexedHeaders[id.id] = nullptr;
}
template <typename Func>
inline void HttpHeaders::forEach(Func&& func) const {
for (auto i: kj::indices(indexedHeaders)) {
if (indexedHeaders[i] != nullptr) {
func(table->idToString(HttpHeaderId(table, i)), indexedHeaders[i]);
}
}
for (auto& header: unindexedHeaders) {
func(header.name, header.value);
}
}
} // namespace kj
#endif // KJ_COMPAT_HTTP_H_

View File

@ -1,555 +0,0 @@
// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
// This file declares convenient macros for debug logging and error handling. The macros make
// it excessively easy to extract useful context information from code. Example:
//
// KJ_ASSERT(a == b, a, b, "a and b must be the same.");
//
// On failure, this will throw an exception whose description looks like:
//
// myfile.c++:43: bug in code: expected a == b; a = 14; b = 72; a and b must be the same.
//
// As you can see, all arguments after the first provide additional context.
//
// The macros available are:
//
// * `KJ_LOG(severity, ...)`: Just writes a log message, to stderr by default (but you can
// intercept messages by implementing an ExceptionCallback). `severity` is `INFO`, `WARNING`,
// `ERROR`, or `FATAL`. By default, `INFO` logs are not written, but for command-line apps the
// user should be able to pass a flag like `--verbose` to enable them. Other log levels are
// enabled by default. Log messages -- like exceptions -- can be intercepted by registering an
// ExceptionCallback.
//
// * `KJ_DBG(...)`: Like `KJ_LOG`, but intended specifically for temporary log lines added while
// debugging a particular problem. Calls to `KJ_DBG` should always be deleted before committing
// code. It is suggested that you set up a pre-commit hook that checks for this.
//
// * `KJ_ASSERT(condition, ...)`: Throws an exception if `condition` is false, or aborts if
// exceptions are disabled. This macro should be used to check for bugs in the surrounding code
// and its dependencies, but NOT to check for invalid input. The macro may be followed by a
// brace-delimited code block; if so, the block will be executed in the case where the assertion
// fails, before throwing the exception. If control jumps out of the block (e.g. with "break",
// "return", or "goto"), then the error is considered "recoverable" -- in this case, if
// exceptions are disabled, execution will continue normally rather than aborting (but if
// exceptions are enabled, an exception will still be thrown on exiting the block). A "break"
// statement in particular will jump to the code immediately after the block (it does not break
// any surrounding loop or switch). Example:
//
// KJ_ASSERT(value >= 0, "Value cannot be negative.", value) {
// // Assertion failed. Set value to zero to "recover".
// value = 0;
// // Don't abort if exceptions are disabled. Continue normally.
// // (Still throw an exception if they are enabled, though.)
// break;
// }
// // When exceptions are disabled, we'll get here even if the assertion fails.
// // Otherwise, we get here only if the assertion passes.
//
// * `KJ_REQUIRE(condition, ...)`: Like `KJ_ASSERT` but used to check preconditions -- e.g. to
// validate parameters passed from a caller. A failure indicates that the caller is buggy.
//
// * `KJ_SYSCALL(code, ...)`: Executes `code` assuming it makes a system call. A negative result
// is considered an error, with error code reported via `errno`. EINTR is handled by retrying.
// Other errors are handled by throwing an exception. If you need to examine the return code,
// assign it to a variable like so:
//
// int fd;
// KJ_SYSCALL(fd = open(filename, O_RDONLY), filename);
//
// `KJ_SYSCALL` can be followed by a recovery block, just like `KJ_ASSERT`.
//
// * `KJ_NONBLOCKING_SYSCALL(code, ...)`: Like KJ_SYSCALL, but will not throw an exception on
// EAGAIN/EWOULDBLOCK. The calling code should check the syscall's return value to see if it
// indicates an error; in this case, it can assume the error was EAGAIN because any other error
// would have caused an exception to be thrown.
//
// * `KJ_CONTEXT(...)`: Notes additional contextual information relevant to any exceptions thrown
// from within the current scope. That is, until control exits the block in which KJ_CONTEXT()
// is used, if any exception is generated, it will contain the given information in its context
// chain. This is helpful because it can otherwise be very difficult to come up with error
// messages that make sense within low-level helper code. Note that the parameters to
// KJ_CONTEXT() are only evaluated if an exception is thrown. This implies that any variables
// used must remain valid until the end of the scope.
//
// Notes:
// * Do not write expressions with side-effects in the message content part of the macro, as the
// message will not necessarily be evaluated.
// * For every macro `FOO` above except `LOG`, there is also a `FAIL_FOO` macro used to report
// failures that already happened. For the macros that check a boolean condition, `FAIL_FOO`
// omits the first parameter and behaves like it was `false`. `FAIL_SYSCALL` and
// `FAIL_RECOVERABLE_SYSCALL` take a string and an OS error number as the first two parameters.
// The string should be the name of the failed system call.
// * For every macro `FOO` above, there is a `DFOO` version (or `RECOVERABLE_DFOO`) which is only
// executed in debug mode, i.e. when KJ_DEBUG is defined. KJ_DEBUG is defined automatically
// by common.h when compiling without optimization (unless NDEBUG is defined), but you can also
// define it explicitly (e.g. -DKJ_DEBUG). Generally, production builds should NOT use KJ_DEBUG
// as it may enable expensive checks that are unlikely to fail.
#ifndef KJ_DEBUG_H_
#define KJ_DEBUG_H_
#if defined(__GNUC__) && !KJ_HEADER_WARNINGS
#pragma GCC system_header
#endif
#include "string.h"
#include "exception.h"
#ifdef ERROR
// This is problematic because windows.h #defines ERROR, which we use in an enum here.
#error "Make sure to to undefine ERROR (or just #include <kj/windows-sanity.h>) before this file"
#endif
namespace kj {
#if _MSC_VER
// MSVC does __VA_ARGS__ differently from GCC:
// - A trailing comma before an empty __VA_ARGS__ is removed automatically, whereas GCC wants
// you to request this behavior with "##__VA_ARGS__".
// - If __VA_ARGS__ is passed directly as an argument to another macro, it will be treated as a
// *single* argument rather than an argument list. This can be worked around by wrapping the
// outer macro call in KJ_EXPAND(), which appraently forces __VA_ARGS__ to be expanded before
// the macro is evaluated. I don't understand the C preprocessor.
// - Using "#__VA_ARGS__" to stringify __VA_ARGS__ expands to zero tokens when __VA_ARGS__ is
// empty, rather than expanding to an empty string literal. We can work around by concatenating
// with an empty string literal.
#define KJ_EXPAND(X) X
#define KJ_LOG(severity, ...) \
if (!::kj::_::Debug::shouldLog(::kj::LogSeverity::severity)) {} else \
::kj::_::Debug::log(__FILE__, __LINE__, ::kj::LogSeverity::severity, \
"" #__VA_ARGS__, __VA_ARGS__)
#define KJ_DBG(...) KJ_EXPAND(KJ_LOG(DBG, __VA_ARGS__))
#define KJ_REQUIRE(cond, ...) \
if (KJ_LIKELY(cond)) {} else \
for (::kj::_::Debug::Fault f(__FILE__, __LINE__, ::kj::Exception::Type::FAILED, \
#cond, "" #__VA_ARGS__, __VA_ARGS__);; f.fatal())
#define KJ_FAIL_REQUIRE(...) \
for (::kj::_::Debug::Fault f(__FILE__, __LINE__, ::kj::Exception::Type::FAILED, \
nullptr, "" #__VA_ARGS__, __VA_ARGS__);; f.fatal())
#define KJ_SYSCALL(call, ...) \
if (auto _kjSyscallResult = ::kj::_::Debug::syscall([&](){return (call);}, false)) {} else \
for (::kj::_::Debug::Fault f(__FILE__, __LINE__, \
_kjSyscallResult.getErrorNumber(), #call, "" #__VA_ARGS__, __VA_ARGS__);; f.fatal())
#define KJ_NONBLOCKING_SYSCALL(call, ...) \
if (auto _kjSyscallResult = ::kj::_::Debug::syscall([&](){return (call);}, true)) {} else \
for (::kj::_::Debug::Fault f(__FILE__, __LINE__, \
_kjSyscallResult.getErrorNumber(), #call, "" #__VA_ARGS__, __VA_ARGS__);; f.fatal())
#define KJ_FAIL_SYSCALL(code, errorNumber, ...) \
for (::kj::_::Debug::Fault f(__FILE__, __LINE__, \
errorNumber, code, "" #__VA_ARGS__, __VA_ARGS__);; f.fatal())
#if _WIN32
#define KJ_WIN32(call, ...) \
if (::kj::_::Debug::isWin32Success(call)) {} else \
for (::kj::_::Debug::Fault f(__FILE__, __LINE__, \
::kj::_::Debug::getWin32Error(), #call, "" #__VA_ARGS__, __VA_ARGS__);; f.fatal())
#define KJ_WINSOCK(call, ...) \
if ((call) != SOCKET_ERROR) {} else \
for (::kj::_::Debug::Fault f(__FILE__, __LINE__, \
::kj::_::Debug::getWin32Error(), #call, "" #__VA_ARGS__, __VA_ARGS__);; f.fatal())
#define KJ_FAIL_WIN32(code, errorNumber, ...) \
for (::kj::_::Debug::Fault f(__FILE__, __LINE__, \
::kj::_::Debug::Win32Error(errorNumber), code, "" #__VA_ARGS__, __VA_ARGS__);; f.fatal())
#endif
#define KJ_UNIMPLEMENTED(...) \
for (::kj::_::Debug::Fault f(__FILE__, __LINE__, ::kj::Exception::Type::UNIMPLEMENTED, \
nullptr, "" #__VA_ARGS__, __VA_ARGS__);; f.fatal())
// TODO(msvc): MSVC mis-deduces `ContextImpl<decltype(func)>` as `ContextImpl<int>` in some edge
// cases, such as inside nested lambdas inside member functions. Wrapping the type in
// `decltype(instance<...>())` helps it deduce the context function's type correctly.
#define KJ_CONTEXT(...) \
auto KJ_UNIQUE_NAME(_kjContextFunc) = [&]() -> ::kj::_::Debug::Context::Value { \
return ::kj::_::Debug::Context::Value(__FILE__, __LINE__, \
::kj::_::Debug::makeDescription("" #__VA_ARGS__, __VA_ARGS__)); \
}; \
decltype(::kj::instance<::kj::_::Debug::ContextImpl<decltype(KJ_UNIQUE_NAME(_kjContextFunc))>>()) \
KJ_UNIQUE_NAME(_kjContext)(KJ_UNIQUE_NAME(_kjContextFunc))
#define KJ_REQUIRE_NONNULL(value, ...) \
(*[&] { \
auto _kj_result = ::kj::_::readMaybe(value); \
if (KJ_UNLIKELY(!_kj_result)) { \
::kj::_::Debug::Fault(__FILE__, __LINE__, ::kj::Exception::Type::FAILED, \
#value " != nullptr", "" #__VA_ARGS__, __VA_ARGS__).fatal(); \
} \
return _kj_result; \
}())
#define KJ_EXCEPTION(type, ...) \
::kj::Exception(::kj::Exception::Type::type, __FILE__, __LINE__, \
::kj::_::Debug::makeDescription("" #__VA_ARGS__, __VA_ARGS__))
#else
#define KJ_LOG(severity, ...) \
if (!::kj::_::Debug::shouldLog(::kj::LogSeverity::severity)) {} else \
::kj::_::Debug::log(__FILE__, __LINE__, ::kj::LogSeverity::severity, \
#__VA_ARGS__, ##__VA_ARGS__)
#define KJ_DBG(...) KJ_LOG(DBG, ##__VA_ARGS__)
#define KJ_REQUIRE(cond, ...) \
if (KJ_LIKELY(cond)) {} else \
for (::kj::_::Debug::Fault f(__FILE__, __LINE__, ::kj::Exception::Type::FAILED, \
#cond, #__VA_ARGS__, ##__VA_ARGS__);; f.fatal())
#define KJ_FAIL_REQUIRE(...) \
for (::kj::_::Debug::Fault f(__FILE__, __LINE__, ::kj::Exception::Type::FAILED, \
nullptr, #__VA_ARGS__, ##__VA_ARGS__);; f.fatal())
#define KJ_SYSCALL(call, ...) \
if (auto _kjSyscallResult = ::kj::_::Debug::syscall([&](){return (call);}, false)) {} else \
for (::kj::_::Debug::Fault f(__FILE__, __LINE__, \
_kjSyscallResult.getErrorNumber(), #call, #__VA_ARGS__, ##__VA_ARGS__);; f.fatal())
#define KJ_NONBLOCKING_SYSCALL(call, ...) \
if (auto _kjSyscallResult = ::kj::_::Debug::syscall([&](){return (call);}, true)) {} else \
for (::kj::_::Debug::Fault f(__FILE__, __LINE__, \
_kjSyscallResult.getErrorNumber(), #call, #__VA_ARGS__, ##__VA_ARGS__);; f.fatal())
#define KJ_FAIL_SYSCALL(code, errorNumber, ...) \
for (::kj::_::Debug::Fault f(__FILE__, __LINE__, \
errorNumber, code, #__VA_ARGS__, ##__VA_ARGS__);; f.fatal())
#if _WIN32
#define KJ_WIN32(call, ...) \
if (::kj::_::Debug::isWin32Success(call)) {} else \
for (::kj::_::Debug::Fault f(__FILE__, __LINE__, \
::kj::_::Debug::getWin32Error(), #call, #__VA_ARGS__, ##__VA_ARGS__);; f.fatal())
#define KJ_WINSOCK(call, ...) \
if ((call) != SOCKET_ERROR) {} else \
for (::kj::_::Debug::Fault f(__FILE__, __LINE__, \
::kj::_::Debug::getWin32Error(), #call, #__VA_ARGS__, ##__VA_ARGS__);; f.fatal())
#define KJ_FAIL_WIN32(code, errorNumber, ...) \
for (::kj::_::Debug::Fault f(__FILE__, __LINE__, \
::kj::_::Debug::Win32Error(errorNumber), code, #__VA_ARGS__, ##__VA_ARGS__);; f.fatal())
#endif
#define KJ_UNIMPLEMENTED(...) \
for (::kj::_::Debug::Fault f(__FILE__, __LINE__, ::kj::Exception::Type::UNIMPLEMENTED, \
nullptr, #__VA_ARGS__, ##__VA_ARGS__);; f.fatal())
#define KJ_CONTEXT(...) \
auto KJ_UNIQUE_NAME(_kjContextFunc) = [&]() -> ::kj::_::Debug::Context::Value { \
return ::kj::_::Debug::Context::Value(__FILE__, __LINE__, \
::kj::_::Debug::makeDescription(#__VA_ARGS__, ##__VA_ARGS__)); \
}; \
::kj::_::Debug::ContextImpl<decltype(KJ_UNIQUE_NAME(_kjContextFunc))> \
KJ_UNIQUE_NAME(_kjContext)(KJ_UNIQUE_NAME(_kjContextFunc))
#define KJ_REQUIRE_NONNULL(value, ...) \
(*({ \
auto _kj_result = ::kj::_::readMaybe(value); \
if (KJ_UNLIKELY(!_kj_result)) { \
::kj::_::Debug::Fault(__FILE__, __LINE__, ::kj::Exception::Type::FAILED, \
#value " != nullptr", #__VA_ARGS__, ##__VA_ARGS__).fatal(); \
} \
kj::mv(_kj_result); \
}))
#define KJ_EXCEPTION(type, ...) \
::kj::Exception(::kj::Exception::Type::type, __FILE__, __LINE__, \
::kj::_::Debug::makeDescription(#__VA_ARGS__, ##__VA_ARGS__))
#endif
#define KJ_SYSCALL_HANDLE_ERRORS(call) \
if (int _kjSyscallError = ::kj::_::Debug::syscallError([&](){return (call);}, false)) \
switch (int error = _kjSyscallError)
// Like KJ_SYSCALL, but doesn't throw. Instead, the block after the macro is a switch block on the
// error. Additionally, the int value `error` is defined within the block. So you can do:
//
// KJ_SYSCALL_HANDLE_ERRORS(foo()) {
// case ENOENT:
// handleNoSuchFile();
// break;
// case EEXIST:
// handleExists();
// break;
// default:
// KJ_FAIL_SYSCALL("foo()", error);
// } else {
// handleSuccessCase();
// }
#define KJ_ASSERT KJ_REQUIRE
#define KJ_FAIL_ASSERT KJ_FAIL_REQUIRE
#define KJ_ASSERT_NONNULL KJ_REQUIRE_NONNULL
// Use "ASSERT" in place of "REQUIRE" when the problem is local to the immediate surrounding code.
// That is, if the assert ever fails, it indicates that the immediate surrounding code is broken.
#ifdef KJ_DEBUG
#define KJ_DLOG KJ_LOG
#define KJ_DASSERT KJ_ASSERT
#define KJ_DREQUIRE KJ_REQUIRE
#else
#define KJ_DLOG(...) do {} while (false)
#define KJ_DASSERT(...) do {} while (false)
#define KJ_DREQUIRE(...) do {} while (false)
#endif
namespace _ { // private
class Debug {
public:
Debug() = delete;
typedef LogSeverity Severity; // backwards-compatibility
#if _WIN32
struct Win32Error {
// Hack for overloading purposes.
uint number;
inline explicit Win32Error(uint number): number(number) {}
};
#endif
static inline bool shouldLog(LogSeverity severity) { return severity >= minSeverity; }
// Returns whether messages of the given severity should be logged.
static inline void setLogLevel(LogSeverity severity) { minSeverity = severity; }
// Set the minimum message severity which will be logged.
//
// TODO(someday): Expose publicly.
template <typename... Params>
static void log(const char* file, int line, LogSeverity severity, const char* macroArgs,
Params&&... params);
class Fault {
public:
template <typename Code, typename... Params>
Fault(const char* file, int line, Code code,
const char* condition, const char* macroArgs, Params&&... params);
Fault(const char* file, int line, Exception::Type type,
const char* condition, const char* macroArgs);
Fault(const char* file, int line, int osErrorNumber,
const char* condition, const char* macroArgs);
#if _WIN32
Fault(const char* file, int line, Win32Error osErrorNumber,
const char* condition, const char* macroArgs);
#endif
~Fault() noexcept(false);
KJ_NOINLINE KJ_NORETURN(void fatal());
// Throw the exception.
private:
void init(const char* file, int line, Exception::Type type,
const char* condition, const char* macroArgs, ArrayPtr<String> argValues);
void init(const char* file, int line, int osErrorNumber,
const char* condition, const char* macroArgs, ArrayPtr<String> argValues);
#if _WIN32
void init(const char* file, int line, Win32Error osErrorNumber,
const char* condition, const char* macroArgs, ArrayPtr<String> argValues);
#endif
Exception* exception;
};
class SyscallResult {
public:
inline SyscallResult(int errorNumber): errorNumber(errorNumber) {}
inline operator void*() { return errorNumber == 0 ? this : nullptr; }
inline int getErrorNumber() { return errorNumber; }
private:
int errorNumber;
};
template <typename Call>
static SyscallResult syscall(Call&& call, bool nonblocking);
template <typename Call>
static int syscallError(Call&& call, bool nonblocking);
#if _WIN32
static bool isWin32Success(int boolean);
static bool isWin32Success(void* handle);
static Win32Error getWin32Error();
#endif
class Context: public ExceptionCallback {
public:
Context();
KJ_DISALLOW_COPY(Context);
virtual ~Context() noexcept(false);
struct Value {
const char* file;
int line;
String description;
inline Value(const char* file, int line, String&& description)
: file(file), line(line), description(mv(description)) {}
};
virtual Value evaluate() = 0;
virtual void onRecoverableException(Exception&& exception) override;
virtual void onFatalException(Exception&& exception) override;
virtual void logMessage(LogSeverity severity, const char* file, int line, int contextDepth,
String&& text) override;
private:
bool logged;
Maybe<Value> value;
Value ensureInitialized();
};
template <typename Func>
class ContextImpl: public Context {
public:
inline ContextImpl(Func& func): func(func) {}
KJ_DISALLOW_COPY(ContextImpl);
Value evaluate() override {
return func();
}
private:
Func& func;
};
template <typename... Params>
static String makeDescription(const char* macroArgs, Params&&... params);
private:
static LogSeverity minSeverity;
static void logInternal(const char* file, int line, LogSeverity severity, const char* macroArgs,
ArrayPtr<String> argValues);
static String makeDescriptionInternal(const char* macroArgs, ArrayPtr<String> argValues);
static int getOsErrorNumber(bool nonblocking);
// Get the error code of the last error (e.g. from errno). Returns -1 on EINTR.
};
template <typename... Params>
void Debug::log(const char* file, int line, LogSeverity severity, const char* macroArgs,
Params&&... params) {
String argValues[sizeof...(Params)] = {str(params)...};
logInternal(file, line, severity, macroArgs, arrayPtr(argValues, sizeof...(Params)));
}
template <>
inline void Debug::log<>(const char* file, int line, LogSeverity severity, const char* macroArgs) {
logInternal(file, line, severity, macroArgs, nullptr);
}
template <typename Code, typename... Params>
Debug::Fault::Fault(const char* file, int line, Code code,
const char* condition, const char* macroArgs, Params&&... params)
: exception(nullptr) {
String argValues[sizeof...(Params)] = {str(params)...};
init(file, line, code, condition, macroArgs,
arrayPtr(argValues, sizeof...(Params)));
}
inline Debug::Fault::Fault(const char* file, int line, int osErrorNumber,
const char* condition, const char* macroArgs)
: exception(nullptr) {
init(file, line, osErrorNumber, condition, macroArgs, nullptr);
}
inline Debug::Fault::Fault(const char* file, int line, kj::Exception::Type type,
const char* condition, const char* macroArgs)
: exception(nullptr) {
init(file, line, type, condition, macroArgs, nullptr);
}
#if _WIN32
inline Debug::Fault::Fault(const char* file, int line, Win32Error osErrorNumber,
const char* condition, const char* macroArgs)
: exception(nullptr) {
init(file, line, osErrorNumber, condition, macroArgs, nullptr);
}
inline bool Debug::isWin32Success(int boolean) {
return boolean;
}
inline bool Debug::isWin32Success(void* handle) {
// Assume null and INVALID_HANDLE_VALUE mean failure.
return handle != nullptr && handle != (void*)-1;
}
#endif
template <typename Call>
Debug::SyscallResult Debug::syscall(Call&& call, bool nonblocking) {
while (call() < 0) {
int errorNum = getOsErrorNumber(nonblocking);
// getOsErrorNumber() returns -1 to indicate EINTR.
// Also, if nonblocking is true, then it returns 0 on EAGAIN, which will then be treated as a
// non-error.
if (errorNum != -1) {
return SyscallResult(errorNum);
}
}
return SyscallResult(0);
}
template <typename Call>
int Debug::syscallError(Call&& call, bool nonblocking) {
while (call() < 0) {
int errorNum = getOsErrorNumber(nonblocking);
// getOsErrorNumber() returns -1 to indicate EINTR.
// Also, if nonblocking is true, then it returns 0 on EAGAIN, which will then be treated as a
// non-error.
if (errorNum != -1) {
return errorNum;
}
}
return 0;
}
template <typename... Params>
String Debug::makeDescription(const char* macroArgs, Params&&... params) {
String argValues[sizeof...(Params)] = {str(params)...};
return makeDescriptionInternal(macroArgs, arrayPtr(argValues, sizeof...(Params)));
}
template <>
inline String Debug::makeDescription<>(const char* macroArgs) {
return makeDescriptionInternal(macroArgs, nullptr);
}
} // namespace _ (private)
} // namespace kj
#endif // KJ_DEBUG_H_

View File

@ -1,363 +0,0 @@
// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#ifndef KJ_EXCEPTION_H_
#define KJ_EXCEPTION_H_
#if defined(__GNUC__) && !KJ_HEADER_WARNINGS
#pragma GCC system_header
#endif
#include "memory.h"
#include "array.h"
#include "string.h"
namespace kj {
class ExceptionImpl;
class Exception {
// Exception thrown in case of fatal errors.
//
// Actually, a subclass of this which also implements std::exception will be thrown, but we hide
// that fact from the interface to avoid #including <exception>.
public:
enum class Type {
// What kind of failure?
FAILED = 0,
// Something went wrong. This is the usual error type. KJ_ASSERT and KJ_REQUIRE throw this
// error type.
OVERLOADED = 1,
// The call failed because of a temporary lack of resources. This could be space resources
// (out of memory, out of disk space) or time resources (request queue overflow, operation
// timed out).
//
// The operation might work if tried again, but it should NOT be repeated immediately as this
// may simply exacerbate the problem.
DISCONNECTED = 2,
// The call required communication over a connection that has been lost. The callee will need
// to re-establish connections and try again.
UNIMPLEMENTED = 3
// The requested method is not implemented. The caller may wish to revert to a fallback
// approach based on other methods.
// IF YOU ADD A NEW VALUE:
// - Update the stringifier.
// - Update Cap'n Proto's RPC protocol's Exception.Type enum.
};
Exception(Type type, const char* file, int line, String description = nullptr) noexcept;
Exception(Type type, String file, int line, String description = nullptr) noexcept;
Exception(const Exception& other) noexcept;
Exception(Exception&& other) = default;
~Exception() noexcept;
const char* getFile() const { return file; }
int getLine() const { return line; }
Type getType() const { return type; }
StringPtr getDescription() const { return description; }
ArrayPtr<void* const> getStackTrace() const { return arrayPtr(trace, traceCount); }
struct Context {
// Describes a bit about what was going on when the exception was thrown.
const char* file;
int line;
String description;
Maybe<Own<Context>> next;
Context(const char* file, int line, String&& description, Maybe<Own<Context>>&& next)
: file(file), line(line), description(mv(description)), next(mv(next)) {}
Context(const Context& other) noexcept;
};
inline Maybe<const Context&> getContext() const {
KJ_IF_MAYBE(c, context) {
return **c;
} else {
return nullptr;
}
}
void wrapContext(const char* file, int line, String&& description);
// Wraps the context in a new node. This becomes the head node returned by getContext() -- it
// is expected that contexts will be added in reverse order as the exception passes up the
// callback stack.
KJ_NOINLINE void extendTrace(uint ignoreCount);
// Append the current stack trace to the exception's trace, ignoring the first `ignoreCount`
// frames (see `getStackTrace()` for discussion of `ignoreCount`).
KJ_NOINLINE void truncateCommonTrace();
// Remove the part of the stack trace which the exception shares with the caller of this method.
// This is used by the async library to remove the async infrastructure from the stack trace
// before replacing it with the async trace.
void addTrace(void* ptr);
// Append the given pointer to the backtrace, if it is not already full. This is used by the
// async library to trace through the promise chain that led to the exception.
private:
String ownFile;
const char* file;
int line;
Type type;
String description;
Maybe<Own<Context>> context;
void* trace[32];
uint traceCount;
friend class ExceptionImpl;
};
StringPtr KJ_STRINGIFY(Exception::Type type);
String KJ_STRINGIFY(const Exception& e);
// =======================================================================================
enum class LogSeverity {
INFO, // Information describing what the code is up to, which users may request to see
// with a flag like `--verbose`. Does not indicate a problem. Not printed by
// default; you must call setLogLevel(INFO) to enable.
WARNING, // A problem was detected but execution can continue with correct output.
ERROR, // Something is wrong, but execution can continue with garbage output.
FATAL, // Something went wrong, and execution cannot continue.
DBG // Temporary debug logging. See KJ_DBG.
// Make sure to update the stringifier if you add a new severity level.
};
StringPtr KJ_STRINGIFY(LogSeverity severity);
class ExceptionCallback {
// If you don't like C++ exceptions, you may implement and register an ExceptionCallback in order
// to perform your own exception handling. For example, a reasonable thing to do is to have
// onRecoverableException() set a flag indicating that an error occurred, and then check for that
// flag just before writing to storage and/or returning results to the user. If the flag is set,
// discard whatever you have and return an error instead.
//
// ExceptionCallbacks must always be allocated on the stack. When an exception is thrown, the
// newest ExceptionCallback on the calling thread's stack is called. The default implementation
// of each method calls the next-oldest ExceptionCallback for that thread. Thus the callbacks
// behave a lot like try/catch blocks, except that they are called before any stack unwinding
// occurs.
public:
ExceptionCallback();
KJ_DISALLOW_COPY(ExceptionCallback);
virtual ~ExceptionCallback() noexcept(false);
virtual void onRecoverableException(Exception&& exception);
// Called when an exception has been raised, but the calling code has the ability to continue by
// producing garbage output. This method _should_ throw the exception, but is allowed to simply
// return if garbage output is acceptable.
//
// The global default implementation throws an exception unless the library was compiled with
// -fno-exceptions, in which case it logs an error and returns.
virtual void onFatalException(Exception&& exception);
// Called when an exception has been raised and the calling code cannot continue. If this method
// returns normally, abort() will be called. The method must throw the exception to avoid
// aborting.
//
// The global default implementation throws an exception unless the library was compiled with
// -fno-exceptions, in which case it logs an error and returns.
virtual void logMessage(LogSeverity severity, const char* file, int line, int contextDepth,
String&& text);
// Called when something wants to log some debug text. `contextDepth` indicates how many levels
// of context the message passed through; it may make sense to indent the message accordingly.
//
// The global default implementation writes the text to stderr.
enum class StackTraceMode {
FULL,
// Stringifying a stack trace will attempt to determine source file and line numbers. This may
// be expensive. For example, on Linux, this shells out to `addr2line`.
//
// This is the default in debug builds.
ADDRESS_ONLY,
// Stringifying a stack trace will only generate a list of code addresses.
//
// This is the default in release builds.
NONE
// Generating a stack trace will always return an empty array.
//
// This avoids ever unwinding the stack. On Windows in particular, the stack unwinding library
// has been observed to be pretty slow, so exception-heavy code might benefit significantly
// from this setting. (But exceptions should be rare...)
};
virtual StackTraceMode stackTraceMode();
// Returns the current preferred stack trace mode.
protected:
ExceptionCallback& next;
private:
ExceptionCallback(ExceptionCallback& next);
class RootExceptionCallback;
friend ExceptionCallback& getExceptionCallback();
};
ExceptionCallback& getExceptionCallback();
// Returns the current exception callback.
KJ_NOINLINE KJ_NORETURN(void throwFatalException(kj::Exception&& exception, uint ignoreCount = 0));
// Invoke the exception callback to throw the given fatal exception. If the exception callback
// returns, abort.
KJ_NOINLINE void throwRecoverableException(kj::Exception&& exception, uint ignoreCount = 0);
// Invoke the exception callback to throw the given recoverable exception. If the exception
// callback returns, return normally.
// =======================================================================================
namespace _ { class Runnable; }
template <typename Func>
Maybe<Exception> runCatchingExceptions(Func&& func) noexcept;
// Executes the given function (usually, a lambda returning nothing) catching any exceptions that
// are thrown. Returns the Exception if there was one, or null if the operation completed normally.
// Non-KJ exceptions will be wrapped.
//
// If exception are disabled (e.g. with -fno-exceptions), this will still detect whether any
// recoverable exceptions occurred while running the function and will return those.
class UnwindDetector {
// Utility for detecting when a destructor is called due to unwind. Useful for:
// - Avoiding throwing exceptions in this case, which would terminate the program.
// - Detecting whether to commit or roll back a transaction.
//
// To use this class, either inherit privately from it or declare it as a member. The detector
// works by comparing the exception state against that when the constructor was called, so for
// an object that was actually constructed during exception unwind, it will behave as if no
// unwind is taking place. This is usually the desired behavior.
public:
UnwindDetector();
bool isUnwinding() const;
// Returns true if the current thread is in a stack unwind that it wasn't in at the time the
// object was constructed.
template <typename Func>
void catchExceptionsIfUnwinding(Func&& func) const;
// Runs the given function (e.g., a lambda). If isUnwinding() is true, any exceptions are
// caught and treated as secondary faults, meaning they are considered to be side-effects of the
// exception that is unwinding the stack. Otherwise, exceptions are passed through normally.
private:
uint uncaughtCount;
void catchExceptionsAsSecondaryFaults(_::Runnable& runnable) const;
};
namespace _ { // private
class Runnable {
public:
virtual void run() = 0;
};
template <typename Func>
class RunnableImpl: public Runnable {
public:
RunnableImpl(Func&& func): func(kj::mv(func)) {}
void run() override {
func();
}
private:
Func func;
};
Maybe<Exception> runCatchingExceptions(Runnable& runnable) noexcept;
} // namespace _ (private)
template <typename Func>
Maybe<Exception> runCatchingExceptions(Func&& func) noexcept {
_::RunnableImpl<Decay<Func>> runnable(kj::fwd<Func>(func));
return _::runCatchingExceptions(runnable);
}
template <typename Func>
void UnwindDetector::catchExceptionsIfUnwinding(Func&& func) const {
if (isUnwinding()) {
_::RunnableImpl<Decay<Func>> runnable(kj::fwd<Func>(func));
catchExceptionsAsSecondaryFaults(runnable);
} else {
func();
}
}
#define KJ_ON_SCOPE_SUCCESS(code) \
::kj::UnwindDetector KJ_UNIQUE_NAME(_kjUnwindDetector); \
KJ_DEFER(if (!KJ_UNIQUE_NAME(_kjUnwindDetector).isUnwinding()) { code; })
// Runs `code` if the current scope is exited normally (not due to an exception).
#define KJ_ON_SCOPE_FAILURE(code) \
::kj::UnwindDetector KJ_UNIQUE_NAME(_kjUnwindDetector); \
KJ_DEFER(if (KJ_UNIQUE_NAME(_kjUnwindDetector).isUnwinding()) { code; })
// Runs `code` if the current scope is exited due to an exception.
// =======================================================================================
KJ_NOINLINE ArrayPtr<void* const> getStackTrace(ArrayPtr<void*> space, uint ignoreCount);
// Attempt to get the current stack trace, returning a list of pointers to instructions. The
// returned array is a slice of `space`. Provide a larger `space` to get a deeper stack trace.
// If the platform doesn't support stack traces, returns an empty array.
//
// `ignoreCount` items will be truncated from the front of the trace. This is useful for chopping
// off a prefix of the trace that is uninteresting to the developer because it's just locations
// inside the debug infrastructure that is requesting the trace. Be careful to mark functions as
// KJ_NOINLINE if you intend to count them in `ignoreCount`. Note that, unfortunately, the
// ignored entries will still waste space in the `space` array (and the returned array's `begin()`
// is never exactly equal to `space.begin()` due to this effect, even if `ignoreCount` is zero
// since `getStackTrace()` needs to ignore its own internal frames).
String stringifyStackTrace(ArrayPtr<void* const>);
// Convert the stack trace to a string with file names and line numbers. This may involve executing
// suprocesses.
String getStackTrace();
// Get a stack trace right now and stringify it. Useful for debugging.
void printStackTraceOnCrash();
// Registers signal handlers on common "crash" signals like SIGSEGV that will (attempt to) print
// a stack trace. You should call this as early as possible on program startup. Programs using
// KJ_MAIN get this automatically.
kj::StringPtr trimSourceFilename(kj::StringPtr filename);
// Given a source code file name, trim off noisy prefixes like "src/" or
// "/ekam-provider/canonical/".
} // namespace kj
#endif // KJ_EXCEPTION_H_

View File

@ -1,277 +0,0 @@
// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#ifndef KJ_FUNCTION_H_
#define KJ_FUNCTION_H_
#if defined(__GNUC__) && !KJ_HEADER_WARNINGS
#pragma GCC system_header
#endif
#include "memory.h"
namespace kj {
template <typename Signature>
class Function;
// Function wrapper using virtual-based polymorphism. Use this when template polymorphism is
// not possible. You can, for example, accept a Function as a parameter:
//
// void setFilter(Function<bool(const Widget&)> filter);
//
// The caller of `setFilter()` may then pass any callable object as the parameter. The callable
// object does not have to have the exact signature specified, just one that is "compatible" --
// i.e. the return type is covariant and the parameters are contravariant.
//
// Unlike `std::function`, `kj::Function`s are movable but not copyable, just like `kj::Own`. This
// is to avoid unexpected heap allocation or slow atomic reference counting.
//
// When a `Function` is constructed from an lvalue, it captures only a reference to the value.
// When constructed from an rvalue, it invokes the value's move constructor. So, for example:
//
// struct AddN {
// int n;
// int operator(int i) { return i + n; }
// }
//
// Function<int(int, int)> f1 = AddN{2};
// // f1 owns an instance of AddN. It may safely be moved out
// // of the local scope.
//
// AddN adder(2);
// Function<int(int, int)> f2 = adder;
// // f2 contains a reference to `adder`. Thus, it becomes invalid
// // when `adder` goes out-of-scope.
//
// AddN adder2(2);
// Function<int(int, int)> f3 = kj::mv(adder2);
// // f3 owns an insatnce of AddN moved from `adder2`. f3 may safely
// // be moved out of the local scope.
//
// Additionally, a Function may be bound to a class method using KJ_BIND_METHOD(object, methodName).
// For example:
//
// class Printer {
// public:
// void print(int i);
// void print(kj::StringPtr s);
// };
//
// Printer p;
//
// Function<void(uint)> intPrinter = KJ_BIND_METHOD(p, print);
// // Will call Printer::print(int).
//
// Function<void(const char*)> strPrinter = KJ_BIND_METHOD(p, print);
// // Will call Printer::print(kj::StringPtr).
//
// Notice how KJ_BIND_METHOD is able to figure out which overload to use depending on the kind of
// Function it is binding to.
template <typename Signature>
class ConstFunction;
// Like Function, but wraps a "const" (i.e. thread-safe) call.
template <typename Return, typename... Params>
class Function<Return(Params...)> {
public:
template <typename F>
inline Function(F&& f): impl(heap<Impl<F>>(kj::fwd<F>(f))) {}
Function() = default;
// Make sure people don't accidentally end up wrapping a reference when they meant to return
// a function.
KJ_DISALLOW_COPY(Function);
Function(Function&) = delete;
Function& operator=(Function&) = delete;
template <typename T> Function(const Function<T>&) = delete;
template <typename T> Function& operator=(const Function<T>&) = delete;
template <typename T> Function(const ConstFunction<T>&) = delete;
template <typename T> Function& operator=(const ConstFunction<T>&) = delete;
Function(Function&&) = default;
Function& operator=(Function&&) = default;
inline Return operator()(Params... params) {
return (*impl)(kj::fwd<Params>(params)...);
}
Function reference() {
// Forms a new Function of the same type that delegates to this Function by reference.
// Therefore, this Function must outlive the returned Function, but otherwise they behave
// exactly the same.
return *impl;
}
private:
class Iface {
public:
virtual Return operator()(Params... params) = 0;
};
template <typename F>
class Impl final: public Iface {
public:
explicit Impl(F&& f): f(kj::fwd<F>(f)) {}
Return operator()(Params... params) override {
return f(kj::fwd<Params>(params)...);
}
private:
F f;
};
Own<Iface> impl;
};
template <typename Return, typename... Params>
class ConstFunction<Return(Params...)> {
public:
template <typename F>
inline ConstFunction(F&& f): impl(heap<Impl<F>>(kj::fwd<F>(f))) {}
ConstFunction() = default;
// Make sure people don't accidentally end up wrapping a reference when they meant to return
// a function.
KJ_DISALLOW_COPY(ConstFunction);
ConstFunction(ConstFunction&) = delete;
ConstFunction& operator=(ConstFunction&) = delete;
template <typename T> ConstFunction(const ConstFunction<T>&) = delete;
template <typename T> ConstFunction& operator=(const ConstFunction<T>&) = delete;
template <typename T> ConstFunction(const Function<T>&) = delete;
template <typename T> ConstFunction& operator=(const Function<T>&) = delete;
ConstFunction(ConstFunction&&) = default;
ConstFunction& operator=(ConstFunction&&) = default;
inline Return operator()(Params... params) const {
return (*impl)(kj::fwd<Params>(params)...);
}
ConstFunction reference() const {
// Forms a new ConstFunction of the same type that delegates to this ConstFunction by reference.
// Therefore, this ConstFunction must outlive the returned ConstFunction, but otherwise they
// behave exactly the same.
return *impl;
}
private:
class Iface {
public:
virtual Return operator()(Params... params) const = 0;
};
template <typename F>
class Impl final: public Iface {
public:
explicit Impl(F&& f): f(kj::fwd<F>(f)) {}
Return operator()(Params... params) const override {
return f(kj::fwd<Params>(params)...);
}
private:
F f;
};
Own<Iface> impl;
};
#if 1
namespace _ { // private
template <typename T, typename Signature, Signature method>
class BoundMethod;
template <typename T, typename Return, typename... Params, Return (Decay<T>::*method)(Params...)>
class BoundMethod<T, Return (Decay<T>::*)(Params...), method> {
public:
BoundMethod(T&& t): t(kj::fwd<T>(t)) {}
Return operator()(Params&&... params) {
return (t.*method)(kj::fwd<Params>(params)...);
}
private:
T t;
};
template <typename T, typename Return, typename... Params,
Return (Decay<T>::*method)(Params...) const>
class BoundMethod<T, Return (Decay<T>::*)(Params...) const, method> {
public:
BoundMethod(T&& t): t(kj::fwd<T>(t)) {}
Return operator()(Params&&... params) const {
return (t.*method)(kj::fwd<Params>(params)...);
}
private:
T t;
};
} // namespace _ (private)
#define KJ_BIND_METHOD(obj, method) \
::kj::_::BoundMethod<KJ_DECLTYPE_REF(obj), \
decltype(&::kj::Decay<decltype(obj)>::method), \
&::kj::Decay<decltype(obj)>::method>(obj)
// Macro that produces a functor object which forwards to the method `obj.name`. If `obj` is an
// lvalue, the functor will hold a reference to it. If `obj` is an rvalue, the functor will
// contain a copy (by move) of it.
//
// The current implementation requires that the method is not overloaded.
//
// TODO(someday): C++14's generic lambdas may be able to simplify this code considerably, and
// probably make it work with overloaded methods.
#else
// Here's a better implementation of the above that doesn't work with GCC (but does with Clang)
// because it uses a local class with a template method. Sigh. This implementation supports
// overloaded methods.
#define KJ_BIND_METHOD(obj, method) \
({ \
typedef KJ_DECLTYPE_REF(obj) T; \
class F { \
public: \
inline F(T&& t): t(::kj::fwd<T>(t)) {} \
template <typename... Params> \
auto operator()(Params&&... params) \
-> decltype(::kj::instance<T>().method(::kj::fwd<Params>(params)...)) { \
return t.method(::kj::fwd<Params>(params)...); \
} \
private: \
T t; \
}; \
(F(obj)); \
})
// Macro that produces a functor object which forwards to the method `obj.name`. If `obj` is an
// lvalue, the functor will hold a reference to it. If `obj` is an rvalue, the functor will
// contain a copy (by move) of it.
#endif
} // namespace kj
#endif // KJ_FUNCTION_H_

View File

@ -1,419 +0,0 @@
// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#ifndef KJ_IO_H_
#define KJ_IO_H_
#if defined(__GNUC__) && !KJ_HEADER_WARNINGS
#pragma GCC system_header
#endif
#include <stddef.h>
#include "common.h"
#include "array.h"
#include "exception.h"
namespace kj {
// =======================================================================================
// Abstract interfaces
class InputStream {
public:
virtual ~InputStream() noexcept(false);
size_t read(void* buffer, size_t minBytes, size_t maxBytes);
// Reads at least minBytes and at most maxBytes, copying them into the given buffer. Returns
// the size read. Throws an exception on errors. Implemented in terms of tryRead().
//
// maxBytes is the number of bytes the caller really wants, but minBytes is the minimum amount
// needed by the caller before it can start doing useful processing. If the stream returns less
// than maxBytes, the caller will usually call read() again later to get the rest. Returning
// less than maxBytes is useful when it makes sense for the caller to parallelize processing
// with I/O.
//
// Never blocks if minBytes is zero. If minBytes is zero and maxBytes is non-zero, this may
// attempt a non-blocking read or may just return zero. To force a read, use a non-zero minBytes.
// To detect EOF without throwing an exception, use tryRead().
//
// If the InputStream can't produce minBytes, it MUST throw an exception, as the caller is not
// expected to understand how to deal with partial reads.
virtual size_t tryRead(void* buffer, size_t minBytes, size_t maxBytes) = 0;
// Like read(), but may return fewer than minBytes on EOF.
inline void read(void* buffer, size_t bytes) { read(buffer, bytes, bytes); }
// Convenience method for reading an exact number of bytes.
virtual void skip(size_t bytes);
// Skips past the given number of bytes, discarding them. The default implementation read()s
// into a scratch buffer.
};
class OutputStream {
public:
virtual ~OutputStream() noexcept(false);
virtual void write(const void* buffer, size_t size) = 0;
// Always writes the full size. Throws exception on error.
virtual void write(ArrayPtr<const ArrayPtr<const byte>> pieces);
// Equivalent to write()ing each byte array in sequence, which is what the default implementation
// does. Override if you can do something better, e.g. use writev() to do the write in a single
// syscall.
};
class BufferedInputStream: public InputStream {
// An input stream which buffers some bytes in memory to reduce system call overhead.
// - OR -
// An input stream that actually reads from some in-memory data structure and wants to give its
// caller a direct pointer to that memory to potentially avoid a copy.
public:
virtual ~BufferedInputStream() noexcept(false);
ArrayPtr<const byte> getReadBuffer();
// Get a direct pointer into the read buffer, which contains the next bytes in the input. If the
// caller consumes any bytes, it should then call skip() to indicate this. This always returns a
// non-empty buffer or throws an exception. Implemented in terms of tryGetReadBuffer().
virtual ArrayPtr<const byte> tryGetReadBuffer() = 0;
// Like getReadBuffer() but may return an empty buffer on EOF.
};
class BufferedOutputStream: public OutputStream {
// An output stream which buffers some bytes in memory to reduce system call overhead.
// - OR -
// An output stream that actually writes into some in-memory data structure and wants to give its
// caller a direct pointer to that memory to potentially avoid a copy.
public:
virtual ~BufferedOutputStream() noexcept(false);
virtual ArrayPtr<byte> getWriteBuffer() = 0;
// Get a direct pointer into the write buffer. The caller may choose to fill in some prefix of
// this buffer and then pass it to write(), in which case write() may avoid a copy. It is
// incorrect to pass to write any slice of this buffer which is not a prefix.
};
// =======================================================================================
// Buffered streams implemented as wrappers around regular streams
class BufferedInputStreamWrapper: public BufferedInputStream {
// Implements BufferedInputStream in terms of an InputStream.
//
// Note that the underlying stream's position is unpredictable once the wrapper is destroyed,
// unless the entire stream was consumed. To read a predictable number of bytes in a buffered
// way without going over, you'd need this wrapper to wrap some other wrapper which itself
// implements an artificial EOF at the desired point. Such a stream should be trivial to write
// but is not provided by the library at this time.
public:
explicit BufferedInputStreamWrapper(InputStream& inner, ArrayPtr<byte> buffer = nullptr);
// Creates a buffered stream wrapping the given non-buffered stream. No guarantee is made about
// the position of the inner stream after a buffered wrapper has been created unless the entire
// input is read.
//
// If the second parameter is non-null, the stream uses the given buffer instead of allocating
// its own. This may improve performance if the buffer can be reused.
KJ_DISALLOW_COPY(BufferedInputStreamWrapper);
~BufferedInputStreamWrapper() noexcept(false);
// implements BufferedInputStream ----------------------------------
ArrayPtr<const byte> tryGetReadBuffer() override;
size_t tryRead(void* buffer, size_t minBytes, size_t maxBytes) override;
void skip(size_t bytes) override;
private:
InputStream& inner;
Array<byte> ownedBuffer;
ArrayPtr<byte> buffer;
ArrayPtr<byte> bufferAvailable;
};
class BufferedOutputStreamWrapper: public BufferedOutputStream {
// Implements BufferedOutputStream in terms of an OutputStream. Note that writes to the
// underlying stream may be delayed until flush() is called or the wrapper is destroyed.
public:
explicit BufferedOutputStreamWrapper(OutputStream& inner, ArrayPtr<byte> buffer = nullptr);
// Creates a buffered stream wrapping the given non-buffered stream.
//
// If the second parameter is non-null, the stream uses the given buffer instead of allocating
// its own. This may improve performance if the buffer can be reused.
KJ_DISALLOW_COPY(BufferedOutputStreamWrapper);
~BufferedOutputStreamWrapper() noexcept(false);
void flush();
// Force the wrapper to write any remaining bytes in its buffer to the inner stream. Note that
// this only flushes this object's buffer; this object has no idea how to flush any other buffers
// that may be present in the underlying stream.
// implements BufferedOutputStream ---------------------------------
ArrayPtr<byte> getWriteBuffer() override;
void write(const void* buffer, size_t size) override;
private:
OutputStream& inner;
Array<byte> ownedBuffer;
ArrayPtr<byte> buffer;
byte* bufferPos;
UnwindDetector unwindDetector;
};
// =======================================================================================
// Array I/O
class ArrayInputStream: public BufferedInputStream {
public:
explicit ArrayInputStream(ArrayPtr<const byte> array);
KJ_DISALLOW_COPY(ArrayInputStream);
~ArrayInputStream() noexcept(false);
// implements BufferedInputStream ----------------------------------
ArrayPtr<const byte> tryGetReadBuffer() override;
size_t tryRead(void* buffer, size_t minBytes, size_t maxBytes) override;
void skip(size_t bytes) override;
private:
ArrayPtr<const byte> array;
};
class ArrayOutputStream: public BufferedOutputStream {
public:
explicit ArrayOutputStream(ArrayPtr<byte> array);
KJ_DISALLOW_COPY(ArrayOutputStream);
~ArrayOutputStream() noexcept(false);
ArrayPtr<byte> getArray() {
// Get the portion of the array which has been filled in.
return arrayPtr(array.begin(), fillPos);
}
// implements BufferedInputStream ----------------------------------
ArrayPtr<byte> getWriteBuffer() override;
void write(const void* buffer, size_t size) override;
private:
ArrayPtr<byte> array;
byte* fillPos;
};
class VectorOutputStream: public BufferedOutputStream {
public:
explicit VectorOutputStream(size_t initialCapacity = 4096);
KJ_DISALLOW_COPY(VectorOutputStream);
~VectorOutputStream() noexcept(false);
ArrayPtr<byte> getArray() {
// Get the portion of the array which has been filled in.
return arrayPtr(vector.begin(), fillPos);
}
// implements BufferedInputStream ----------------------------------
ArrayPtr<byte> getWriteBuffer() override;
void write(const void* buffer, size_t size) override;
private:
Array<byte> vector;
byte* fillPos;
void grow(size_t minSize);
};
// =======================================================================================
// File descriptor I/O
class AutoCloseFd {
// A wrapper around a file descriptor which automatically closes the descriptor when destroyed.
// The wrapper supports move construction for transferring ownership of the descriptor. If
// close() returns an error, the destructor throws an exception, UNLESS the destructor is being
// called during unwind from another exception, in which case the close error is ignored.
//
// If your code is not exception-safe, you should not use AutoCloseFd. In this case you will
// have to call close() yourself and handle errors appropriately.
public:
inline AutoCloseFd(): fd(-1) {}
inline AutoCloseFd(decltype(nullptr)): fd(-1) {}
inline explicit AutoCloseFd(int fd): fd(fd) {}
inline AutoCloseFd(AutoCloseFd&& other) noexcept: fd(other.fd) { other.fd = -1; }
KJ_DISALLOW_COPY(AutoCloseFd);
~AutoCloseFd() noexcept(false);
inline AutoCloseFd& operator=(AutoCloseFd&& other) {
AutoCloseFd old(kj::mv(*this));
fd = other.fd;
other.fd = -1;
return *this;
}
inline AutoCloseFd& operator=(decltype(nullptr)) {
AutoCloseFd old(kj::mv(*this));
return *this;
}
inline operator int() const { return fd; }
inline int get() const { return fd; }
operator bool() const = delete;
// Deleting this operator prevents accidental use in boolean contexts, which
// the int conversion operator above would otherwise allow.
inline bool operator==(decltype(nullptr)) { return fd < 0; }
inline bool operator!=(decltype(nullptr)) { return fd >= 0; }
private:
int fd;
UnwindDetector unwindDetector;
};
inline auto KJ_STRINGIFY(const AutoCloseFd& fd)
-> decltype(kj::toCharSequence(implicitCast<int>(fd))) {
return kj::toCharSequence(implicitCast<int>(fd));
}
class FdInputStream: public InputStream {
// An InputStream wrapping a file descriptor.
public:
explicit FdInputStream(int fd): fd(fd) {}
explicit FdInputStream(AutoCloseFd fd): fd(fd), autoclose(mv(fd)) {}
KJ_DISALLOW_COPY(FdInputStream);
~FdInputStream() noexcept(false);
size_t tryRead(void* buffer, size_t minBytes, size_t maxBytes) override;
inline int getFd() const { return fd; }
private:
int fd;
AutoCloseFd autoclose;
};
class FdOutputStream: public OutputStream {
// An OutputStream wrapping a file descriptor.
public:
explicit FdOutputStream(int fd): fd(fd) {}
explicit FdOutputStream(AutoCloseFd fd): fd(fd), autoclose(mv(fd)) {}
KJ_DISALLOW_COPY(FdOutputStream);
~FdOutputStream() noexcept(false);
void write(const void* buffer, size_t size) override;
void write(ArrayPtr<const ArrayPtr<const byte>> pieces) override;
inline int getFd() const { return fd; }
private:
int fd;
AutoCloseFd autoclose;
};
// =======================================================================================
// Win32 Handle I/O
#ifdef _WIN32
class AutoCloseHandle {
// A wrapper around a Win32 HANDLE which automatically closes the handle when destroyed.
// The wrapper supports move construction for transferring ownership of the handle. If
// CloseHandle() returns an error, the destructor throws an exception, UNLESS the destructor is
// being called during unwind from another exception, in which case the close error is ignored.
//
// If your code is not exception-safe, you should not use AutoCloseHandle. In this case you will
// have to call close() yourself and handle errors appropriately.
public:
inline AutoCloseHandle(): handle((void*)-1) {}
inline AutoCloseHandle(decltype(nullptr)): handle((void*)-1) {}
inline explicit AutoCloseHandle(void* handle): handle(handle) {}
inline AutoCloseHandle(AutoCloseHandle&& other) noexcept: handle(other.handle) {
other.handle = (void*)-1;
}
KJ_DISALLOW_COPY(AutoCloseHandle);
~AutoCloseHandle() noexcept(false);
inline AutoCloseHandle& operator=(AutoCloseHandle&& other) {
AutoCloseHandle old(kj::mv(*this));
handle = other.handle;
other.handle = (void*)-1;
return *this;
}
inline AutoCloseHandle& operator=(decltype(nullptr)) {
AutoCloseHandle old(kj::mv(*this));
return *this;
}
inline operator void*() const { return handle; }
inline void* get() const { return handle; }
operator bool() const = delete;
// Deleting this operator prevents accidental use in boolean contexts, which
// the void* conversion operator above would otherwise allow.
inline bool operator==(decltype(nullptr)) { return handle != (void*)-1; }
inline bool operator!=(decltype(nullptr)) { return handle == (void*)-1; }
private:
void* handle; // -1 (aka INVALID_HANDLE_VALUE) if not valid.
};
class HandleInputStream: public InputStream {
// An InputStream wrapping a Win32 HANDLE.
public:
explicit HandleInputStream(void* handle): handle(handle) {}
explicit HandleInputStream(AutoCloseHandle handle): handle(handle), autoclose(mv(handle)) {}
KJ_DISALLOW_COPY(HandleInputStream);
~HandleInputStream() noexcept(false);
size_t tryRead(void* buffer, size_t minBytes, size_t maxBytes) override;
private:
void* handle;
AutoCloseHandle autoclose;
};
class HandleOutputStream: public OutputStream {
// An OutputStream wrapping a Win32 HANDLE.
public:
explicit HandleOutputStream(void* handle): handle(handle) {}
explicit HandleOutputStream(AutoCloseHandle handle): handle(handle), autoclose(mv(handle)) {}
KJ_DISALLOW_COPY(HandleOutputStream);
~HandleOutputStream() noexcept(false);
void write(const void* buffer, size_t size) override;
private:
void* handle;
AutoCloseHandle autoclose;
};
#endif // _WIN32
} // namespace kj
#endif // KJ_IO_H_

View File

@ -1,407 +0,0 @@
// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#ifndef KJ_MAIN_H_
#define KJ_MAIN_H_
#if defined(__GNUC__) && !KJ_HEADER_WARNINGS
#pragma GCC system_header
#endif
#include "array.h"
#include "string.h"
#include "vector.h"
#include "function.h"
namespace kj {
class ProcessContext {
// Context for command-line programs.
public:
virtual StringPtr getProgramName() = 0;
// Get argv[0] as passed to main().
KJ_NORETURN(virtual void exit()) = 0;
// Indicates program completion. The program is considered successful unless `error()` was
// called. Typically this exits with _Exit(), meaning that the stack is not unwound, buffers
// are not flushed, etc. -- it is the responsibility of the caller to flush any buffers that
// matter. However, an alternate context implementation e.g. for unit testing purposes could
// choose to throw an exception instead.
//
// At first this approach may sound crazy. Isn't it much better to shut down cleanly? What if
// you lose data? However, it turns out that if you look at each common class of program, _Exit()
// is almost always preferable. Let's break it down:
//
// * Commands: A typical program you might run from the command line is single-threaded and
// exits quickly and deterministically. Commands often use buffered I/O and need to flush
// those buffers before exit. However, most of the work performed by destructors is not
// flushing buffers, but rather freeing up memory, placing objects into freelists, and closing
// file descriptors. All of this is irrelevant if the process is about to exit anyway, and
// for a command that runs quickly, time wasted freeing heap space may make a real difference
// in the overall runtime of a script. Meanwhile, it is usually easy to determine exactly what
// resources need to be flushed before exit, and easy to tell if they are not being flushed
// (because the command fails to produce the expected output). Therefore, it is reasonably
// easy for commands to explicitly ensure all output is flushed before exiting, and it is
// probably a good idea for them to do so anyway, because write failures should be detected
// and handled. For commands, a good strategy is to allocate any objects that require clean
// destruction on the stack, and allow them to go out of scope before the command exits.
// Meanwhile, any resources which do not need to be cleaned up should be allocated as members
// of the command's main class, whose destructor normally will not be called.
//
// * Interactive apps: Programs that interact with the user (whether they be graphical apps
// with windows or console-based apps like emacs) generally exit only when the user asks them
// to. Such applications may store large data structures in memory which need to be synced
// to disk, such as documents or user preferences. However, relying on stack unwind or global
// destructors as the mechanism for ensuring such syncing occurs is probably wrong. First of
// all, it's 2013, and applications ought to be actively syncing changes to non-volatile
// storage the moment those changes are made. Applications can crash at any time and a crash
// should never lose data that is more than half a second old. Meanwhile, if a user actually
// does try to close an application while unsaved changes exist, the application UI should
// prompt the user to decide what to do. Such a UI mechanism is obviously too high level to
// be implemented via destructors, so KJ's use of _Exit() shouldn't make a difference here.
//
// * Servers: A good server is fault-tolerant, prepared for the possibility that at any time
// it could crash, the OS could decide to kill it off, or the machine it is running on could
// just die. So, using _Exit() should be no problem. In fact, servers generally never even
// call exit anyway; they are killed externally.
//
// * Batch jobs: A long-running batch job is something between a command and a server. It
// probably knows exactly what needs to be flushed before exiting, and it probably should be
// fault-tolerant.
//
// Meanwhile, regardless of program type, if you are adhering to KJ style, then the use of
// _Exit() shouldn't be a problem anyway:
//
// * KJ style forbids global mutable state (singletons) in general and global constructors and
// destructors in particular. Therefore, everything that could possibly need cleanup either
// lives on the stack or is transitively owned by something living on the stack.
//
// * Calling exit() simply means "Don't clean up anything older than this stack frame.". If you
// have resources that require cleanup before exit, make sure they are owned by stack frames
// beyond the one that eventually calls exit(). To be as safe as possible, don't place any
// state in your program's main class, and don't call exit() yourself. Then, runMainAndExit()
// will do it, and the only thing on the stack at that time will be your main class, which
// has no state anyway.
//
// TODO(someday): Perhaps we should use the new std::quick_exit(), so that at_quick_exit() is
// available for those who really think they need it. Unfortunately, it is not yet available
// on many platforms.
virtual void warning(StringPtr message) = 0;
// Print the given message to standard error. A newline is printed after the message if it
// doesn't already have one.
virtual void error(StringPtr message) = 0;
// Like `warning()`, but also sets a flag indicating that the process has failed, and that when
// it eventually exits it should indicate an error status.
KJ_NORETURN(virtual void exitError(StringPtr message)) = 0;
// Equivalent to `error(message)` followed by `exit()`.
KJ_NORETURN(virtual void exitInfo(StringPtr message)) = 0;
// Displays the given non-error message to the user and then calls `exit()`. This is used to
// implement things like --help.
virtual void increaseLoggingVerbosity() = 0;
// Increase the level of detail produced by the debug logging system. `MainBuilder` invokes
// this if the caller uses the -v flag.
// TODO(someday): Add interfaces representing standard OS resources like the filesystem, so that
// these things can be mocked out.
};
class TopLevelProcessContext final: public ProcessContext {
// A ProcessContext implementation appropriate for use at the actual entry point of a process
// (as opposed to when you are trying to call a program's main function from within some other
// program). This implementation writes errors to stderr, and its `exit()` method actually
// calls the C `quick_exit()` function.
public:
explicit TopLevelProcessContext(StringPtr programName);
struct CleanShutdownException { int exitCode; };
// If the environment variable KJ_CLEAN_SHUTDOWN is set, then exit() will actually throw this
// exception rather than exiting. `kj::runMain()` catches this exception and returns normally.
// This is useful primarily for testing purposes, to assist tools like memory leak checkers that
// are easily confused by quick_exit().
StringPtr getProgramName() override;
KJ_NORETURN(void exit() override);
void warning(StringPtr message) override;
void error(StringPtr message) override;
KJ_NORETURN(void exitError(StringPtr message) override);
KJ_NORETURN(void exitInfo(StringPtr message) override);
void increaseLoggingVerbosity() override;
private:
StringPtr programName;
bool cleanShutdown;
bool hadErrors = false;
};
typedef Function<void(StringPtr programName, ArrayPtr<const StringPtr> params)> MainFunc;
int runMainAndExit(ProcessContext& context, MainFunc&& func, int argc, char* argv[]);
// Runs the given main function and then exits using the given context. If an exception is thrown,
// this will catch it, report it via the context and exit with an error code.
//
// Normally this function does not return, because returning would probably lead to wasting time
// on cleanup when the process is just going to exit anyway. However, to facilitate memory leak
// checkers and other tools that require a clean shutdown to do their job, if the environment
// variable KJ_CLEAN_SHUTDOWN is set, the function will in fact return an exit code, which should
// then be returned from main().
//
// Most users will use the KJ_MAIN() macro rather than call this function directly.
#define KJ_MAIN(MainClass) \
int main(int argc, char* argv[]) { \
::kj::TopLevelProcessContext context(argv[0]); \
MainClass mainObject(context); \
return ::kj::runMainAndExit(context, mainObject.getMain(), argc, argv); \
}
// Convenience macro for declaring a main function based on the given class. The class must have
// a constructor that accepts a ProcessContext& and a method getMain() which returns
// kj::MainFunc (probably building it using a MainBuilder).
class MainBuilder {
// Builds a main() function with nice argument parsing. As options and arguments are parsed,
// corresponding callbacks are called, so that you never have to write a massive switch()
// statement to interpret arguments. Additionally, this approach encourages you to write
// main classes that have a reasonable API that can be used as an alternative to their
// command-line interface.
//
// All StringPtrs passed to MainBuilder must remain valid until option parsing completes. The
// assumption is that these strings will all be literals, making this an easy requirement. If
// not, consider allocating them in an Arena.
//
// Some flags are automatically recognized by the main functions built by this class:
// --help: Prints help text and exits. The help text is constructed based on the
// information you provide to the builder as you define each flag.
// --verbose: Increase logging verbosity.
// --version: Print version information and exit.
//
// Example usage:
//
// class FooMain {
// public:
// FooMain(kj::ProcessContext& context): context(context) {}
//
// bool setAll() { all = true; return true; }
// // Enable the --all flag.
//
// kj::MainBuilder::Validity setOutput(kj::StringPtr name) {
// // Set the output file.
//
// if (name.endsWith(".foo")) {
// outputFile = name;
// return true;
// } else {
// return "Output file must have extension .foo.";
// }
// }
//
// kj::MainBuilder::Validity processInput(kj::StringPtr name) {
// // Process an input file.
//
// if (!exists(name)) {
// return kj::str(name, ": file not found");
// }
// // ... process the input file ...
// return true;
// }
//
// kj::MainFunc getMain() {
// return MainBuilder(context, "Foo Builder v1.5", "Reads <source>s and builds a Foo.")
// .addOption({'a', "all"}, KJ_BIND_METHOD(*this, setAll),
// "Frob all the widgets. Otherwise, only some widgets are frobbed.")
// .addOptionWithArg({'o', "output"}, KJ_BIND_METHOD(*this, setOutput),
// "<filename>", "Output to <filename>. Must be a .foo file.")
// .expectOneOrMoreArgs("<source>", KJ_BIND_METHOD(*this, processInput))
// .build();
// }
//
// private:
// bool all = false;
// kj::StringPtr outputFile;
// kj::ProcessContext& context;
// };
public:
MainBuilder(ProcessContext& context, StringPtr version,
StringPtr briefDescription, StringPtr extendedDescription = nullptr);
~MainBuilder() noexcept(false);
class OptionName {
public:
OptionName() = default;
inline OptionName(char shortName): isLong(false), shortName(shortName) {}
inline OptionName(const char* longName): isLong(true), longName(longName) {}
private:
bool isLong;
union {
char shortName;
const char* longName;
};
friend class MainBuilder;
};
class Validity {
public:
inline Validity(bool valid) {
if (!valid) errorMessage = heapString("invalid argument");
}
inline Validity(const char* errorMessage)
: errorMessage(heapString(errorMessage)) {}
inline Validity(String&& errorMessage)
: errorMessage(kj::mv(errorMessage)) {}
inline const Maybe<String>& getError() const { return errorMessage; }
inline Maybe<String> releaseError() { return kj::mv(errorMessage); }
private:
Maybe<String> errorMessage;
friend class MainBuilder;
};
MainBuilder& addOption(std::initializer_list<OptionName> names, Function<Validity()> callback,
StringPtr helpText);
// Defines a new option (flag). `names` is a list of characters and strings that can be used to
// specify the option on the command line. Single-character names are used with "-" while string
// names are used with "--". `helpText` is a natural-language description of the flag.
//
// `callback` is called when the option is seen. Its return value indicates whether the option
// was accepted. If not, further option processing stops, and error is written, and the process
// exits.
//
// Example:
//
// builder.addOption({'a', "all"}, KJ_BIND_METHOD(*this, showAll), "Show all files.");
//
// This option could be specified in the following ways:
//
// -a
// --all
//
// Note that single-character option names can be combined into a single argument. For example,
// `-abcd` is equivalent to `-a -b -c -d`.
//
// The help text for this option would look like:
//
// -a, --all
// Show all files.
//
// Note that help text is automatically word-wrapped.
MainBuilder& addOptionWithArg(std::initializer_list<OptionName> names,
Function<Validity(StringPtr)> callback,
StringPtr argumentTitle, StringPtr helpText);
// Like `addOption()`, but adds an option which accepts an argument. `argumentTitle` is used in
// the help text. The argument text is passed to the callback.
//
// Example:
//
// builder.addOptionWithArg({'o', "output"}, KJ_BIND_METHOD(*this, setOutput),
// "<filename>", "Output to <filename>.");
//
// This option could be specified with an argument of "foo" in the following ways:
//
// -ofoo
// -o foo
// --output=foo
// --output foo
//
// Note that single-character option names can be combined, but only the last option can have an
// argument, since the characters after the option letter are interpreted as the argument. E.g.
// `-abofoo` would be equivalent to `-a -b -o foo`.
//
// The help text for this option would look like:
//
// -o FILENAME, --output=FILENAME
// Output to FILENAME.
MainBuilder& addSubCommand(StringPtr name, Function<MainFunc()> getSubParser,
StringPtr briefHelpText);
// If exactly the given name is seen as an argument, invoke getSubParser() and then pass all
// remaining arguments to the parser it returns. This is useful for implementing commands which
// have lots of sub-commands, like "git" (which has sub-commands "checkout", "branch", "pull",
// etc.).
//
// `getSubParser` is only called if the command is seen. This avoids building main functions
// for commands that aren't used.
//
// `briefHelpText` should be brief enough to show immediately after the command name on a single
// line. It will not be wrapped. Users can use the built-in "help" command to get extended
// help on a particular command.
MainBuilder& expectArg(StringPtr title, Function<Validity(StringPtr)> callback);
MainBuilder& expectOptionalArg(StringPtr title, Function<Validity(StringPtr)> callback);
MainBuilder& expectZeroOrMoreArgs(StringPtr title, Function<Validity(StringPtr)> callback);
MainBuilder& expectOneOrMoreArgs(StringPtr title, Function<Validity(StringPtr)> callback);
// Set callbacks to handle arguments. `expectArg()` and `expectOptionalArg()` specify positional
// arguments with special handling, while `expect{Zero,One}OrMoreArgs()` specifies a handler for
// an argument list (the handler is called once for each argument in the list). `title`
// specifies how the argument should be represented in the usage text.
//
// All options callbacks are called before argument callbacks, regardless of their ordering on
// the command line. This matches GNU getopt's behavior of permuting non-flag arguments to the
// end of the argument list. Also matching getopt, the special option "--" indicates that the
// rest of the command line is all arguments, not options, even if they start with '-'.
//
// The interpretation of positional arguments is fairly flexible. The non-optional arguments can
// be expected at the beginning, end, or in the middle. If more arguments are specified than
// the number of non-optional args, they are assigned to the optional argument handlers in the
// order of registration.
//
// For example, say you called:
// builder.expectArg("<foo>", ...);
// builder.expectOptionalArg("<bar>", ...);
// builder.expectArg("<baz>", ...);
// builder.expectZeroOrMoreArgs("<qux>", ...);
// builder.expectArg("<corge>", ...);
//
// This command requires at least three arguments: foo, baz, and corge. If four arguments are
// given, the second is assigned to bar. If five or more arguments are specified, then the
// arguments between the third and last are assigned to qux. Note that it never makes sense
// to call `expect*OrMoreArgs()` more than once since only the first call would ever be used.
//
// In practice, you probably shouldn't create such complicated commands as in the above example.
// But, this flexibility seems necessary to support commands where the first argument is special
// as well as commands (like `cp`) where the last argument is special.
MainBuilder& callAfterParsing(Function<Validity()> callback);
// Call the given function after all arguments have been parsed.
MainFunc build();
// Build the "main" function, which simply parses the arguments. Once this returns, the
// `MainBuilder` is no longer valid.
private:
struct Impl;
Own<Impl> impl;
class MainImpl;
};
} // namespace kj
#endif // KJ_MAIN_H_

View File

@ -1,406 +0,0 @@
// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#ifndef KJ_MEMORY_H_
#define KJ_MEMORY_H_
#if defined(__GNUC__) && !KJ_HEADER_WARNINGS
#pragma GCC system_header
#endif
#include "common.h"
namespace kj {
// =======================================================================================
// Disposer -- Implementation details.
class Disposer {
// Abstract interface for a thing that "disposes" of objects, where "disposing" usually means
// calling the destructor followed by freeing the underlying memory. `Own<T>` encapsulates an
// object pointer with corresponding Disposer.
//
// Few developers will ever touch this interface. It is primarily useful for those implementing
// custom memory allocators.
protected:
// Do not declare a destructor, as doing so will force a global initializer for each HeapDisposer
// instance. Eww!
virtual void disposeImpl(void* pointer) const = 0;
// Disposes of the object, given a pointer to the beginning of the object. If the object is
// polymorphic, this pointer is determined by dynamic_cast<void*>(). For non-polymorphic types,
// Own<T> does not allow any casting, so the pointer exactly matches the original one given to
// Own<T>.
public:
template <typename T>
void dispose(T* object) const;
// Helper wrapper around disposeImpl().
//
// If T is polymorphic, calls `disposeImpl(dynamic_cast<void*>(object))`, otherwise calls
// `disposeImpl(implicitCast<void*>(object))`.
//
// Callers must not call dispose() on the same pointer twice, even if the first call throws
// an exception.
private:
template <typename T, bool polymorphic = __is_polymorphic(T)>
struct Dispose_;
};
template <typename T>
class DestructorOnlyDisposer: public Disposer {
// A disposer that merely calls the type's destructor and nothing else.
public:
static const DestructorOnlyDisposer instance;
void disposeImpl(void* pointer) const override {
reinterpret_cast<T*>(pointer)->~T();
}
};
template <typename T>
const DestructorOnlyDisposer<T> DestructorOnlyDisposer<T>::instance = DestructorOnlyDisposer<T>();
class NullDisposer: public Disposer {
// A disposer that does nothing.
public:
static const NullDisposer instance;
void disposeImpl(void* pointer) const override {}
};
// =======================================================================================
// Own<T> -- An owned pointer.
template <typename T>
class Own {
// A transferrable title to a T. When an Own<T> goes out of scope, the object's Disposer is
// called to dispose of it. An Own<T> can be efficiently passed by move, without relocating the
// underlying object; this transfers ownership.
//
// This is much like std::unique_ptr, except:
// - You cannot release(). An owned object is not necessarily allocated with new (see next
// point), so it would be hard to use release() correctly.
// - The deleter is made polymorphic by virtual call rather than by template. This is much
// more powerful -- it allows the use of custom allocators, freelists, etc. This could
// _almost_ be accomplished with unique_ptr by forcing everyone to use something like
// std::unique_ptr<T, kj::Deleter>, except that things get hairy in the presence of multiple
// inheritance and upcasting, and anyway if you force everyone to use a custom deleter
// then you've lost any benefit to interoperating with the "standard" unique_ptr.
public:
KJ_DISALLOW_COPY(Own);
inline Own(): disposer(nullptr), ptr(nullptr) {}
inline Own(Own&& other) noexcept
: disposer(other.disposer), ptr(other.ptr) { other.ptr = nullptr; }
inline Own(Own<RemoveConstOrDisable<T>>&& other) noexcept
: disposer(other.disposer), ptr(other.ptr) { other.ptr = nullptr; }
template <typename U, typename = EnableIf<canConvert<U*, T*>()>>
inline Own(Own<U>&& other) noexcept
: disposer(other.disposer), ptr(other.ptr) {
static_assert(__is_polymorphic(T),
"Casting owned pointers requires that the target type is polymorphic.");
other.ptr = nullptr;
}
inline Own(T* ptr, const Disposer& disposer) noexcept: disposer(&disposer), ptr(ptr) {}
~Own() noexcept(false) { dispose(); }
inline Own& operator=(Own&& other) {
// Move-assingnment operator.
// Careful, this might own `other`. Therefore we have to transfer the pointers first, then
// dispose.
const Disposer* disposerCopy = disposer;
T* ptrCopy = ptr;
disposer = other.disposer;
ptr = other.ptr;
other.ptr = nullptr;
if (ptrCopy != nullptr) {
disposerCopy->dispose(const_cast<RemoveConst<T>*>(ptrCopy));
}
return *this;
}
inline Own& operator=(decltype(nullptr)) {
dispose();
return *this;
}
template <typename U>
Own<U> downcast() {
// Downcast the pointer to Own<U>, destroying the original pointer. If this pointer does not
// actually point at an instance of U, the results are undefined (throws an exception in debug
// mode if RTTI is enabled, otherwise you're on your own).
Own<U> result;
if (ptr != nullptr) {
result.ptr = &kj::downcast<U>(*ptr);
result.disposer = disposer;
ptr = nullptr;
}
return result;
}
#define NULLCHECK KJ_IREQUIRE(ptr != nullptr, "null Own<> dereference")
inline T* operator->() { NULLCHECK; return ptr; }
inline const T* operator->() const { NULLCHECK; return ptr; }
inline T& operator*() { NULLCHECK; return *ptr; }
inline const T& operator*() const { NULLCHECK; return *ptr; }
#undef NULLCHECK
inline T* get() { return ptr; }
inline const T* get() const { return ptr; }
inline operator T*() { return ptr; }
inline operator const T*() const { return ptr; }
private:
const Disposer* disposer; // Only valid if ptr != nullptr.
T* ptr;
inline explicit Own(decltype(nullptr)): disposer(nullptr), ptr(nullptr) {}
inline bool operator==(decltype(nullptr)) { return ptr == nullptr; }
inline bool operator!=(decltype(nullptr)) { return ptr != nullptr; }
// Only called by Maybe<Own<T>>.
inline void dispose() {
// Make sure that if an exception is thrown, we are left with a null ptr, so we won't possibly
// dispose again.
T* ptrCopy = ptr;
if (ptrCopy != nullptr) {
ptr = nullptr;
disposer->dispose(const_cast<RemoveConst<T>*>(ptrCopy));
}
}
template <typename U>
friend class Own;
friend class Maybe<Own<T>>;
};
namespace _ { // private
template <typename T>
class OwnOwn {
public:
inline OwnOwn(Own<T>&& value) noexcept: value(kj::mv(value)) {}
inline Own<T>& operator*() & { return value; }
inline const Own<T>& operator*() const & { return value; }
inline Own<T>&& operator*() && { return kj::mv(value); }
inline const Own<T>&& operator*() const && { return kj::mv(value); }
inline Own<T>* operator->() { return &value; }
inline const Own<T>* operator->() const { return &value; }
inline operator Own<T>*() { return value ? &value : nullptr; }
inline operator const Own<T>*() const { return value ? &value : nullptr; }
private:
Own<T> value;
};
template <typename T>
OwnOwn<T> readMaybe(Maybe<Own<T>>&& maybe) { return OwnOwn<T>(kj::mv(maybe.ptr)); }
template <typename T>
Own<T>* readMaybe(Maybe<Own<T>>& maybe) { return maybe.ptr ? &maybe.ptr : nullptr; }
template <typename T>
const Own<T>* readMaybe(const Maybe<Own<T>>& maybe) { return maybe.ptr ? &maybe.ptr : nullptr; }
} // namespace _ (private)
template <typename T>
class Maybe<Own<T>> {
public:
inline Maybe(): ptr(nullptr) {}
inline Maybe(Own<T>&& t) noexcept: ptr(kj::mv(t)) {}
inline Maybe(Maybe&& other) noexcept: ptr(kj::mv(other.ptr)) {}
template <typename U>
inline Maybe(Maybe<Own<U>>&& other): ptr(mv(other.ptr)) {}
template <typename U>
inline Maybe(Own<U>&& other): ptr(mv(other)) {}
inline Maybe(decltype(nullptr)) noexcept: ptr(nullptr) {}
inline operator Maybe<T&>() { return ptr.get(); }
inline operator Maybe<const T&>() const { return ptr.get(); }
inline Maybe& operator=(Maybe&& other) { ptr = kj::mv(other.ptr); return *this; }
inline bool operator==(decltype(nullptr)) const { return ptr == nullptr; }
inline bool operator!=(decltype(nullptr)) const { return ptr != nullptr; }
Own<T>& orDefault(Own<T>& defaultValue) {
if (ptr == nullptr) {
return defaultValue;
} else {
return ptr;
}
}
const Own<T>& orDefault(const Own<T>& defaultValue) const {
if (ptr == nullptr) {
return defaultValue;
} else {
return ptr;
}
}
template <typename Func>
auto map(Func&& f) & -> Maybe<decltype(f(instance<Own<T>&>()))> {
if (ptr == nullptr) {
return nullptr;
} else {
return f(ptr);
}
}
template <typename Func>
auto map(Func&& f) const & -> Maybe<decltype(f(instance<const Own<T>&>()))> {
if (ptr == nullptr) {
return nullptr;
} else {
return f(ptr);
}
}
template <typename Func>
auto map(Func&& f) && -> Maybe<decltype(f(instance<Own<T>&&>()))> {
if (ptr == nullptr) {
return nullptr;
} else {
return f(kj::mv(ptr));
}
}
template <typename Func>
auto map(Func&& f) const && -> Maybe<decltype(f(instance<const Own<T>&&>()))> {
if (ptr == nullptr) {
return nullptr;
} else {
return f(kj::mv(ptr));
}
}
private:
Own<T> ptr;
template <typename U>
friend class Maybe;
template <typename U>
friend _::OwnOwn<U> _::readMaybe(Maybe<Own<U>>&& maybe);
template <typename U>
friend Own<U>* _::readMaybe(Maybe<Own<U>>& maybe);
template <typename U>
friend const Own<U>* _::readMaybe(const Maybe<Own<U>>& maybe);
};
namespace _ { // private
template <typename T>
class HeapDisposer final: public Disposer {
public:
virtual void disposeImpl(void* pointer) const override { delete reinterpret_cast<T*>(pointer); }
static const HeapDisposer instance;
};
template <typename T>
const HeapDisposer<T> HeapDisposer<T>::instance = HeapDisposer<T>();
} // namespace _ (private)
template <typename T, typename... Params>
Own<T> heap(Params&&... params) {
// heap<T>(...) allocates a T on the heap, forwarding the parameters to its constructor. The
// exact heap implementation is unspecified -- for now it is operator new, but you should not
// assume this. (Since we know the object size at delete time, we could actually implement an
// allocator that is more efficient than operator new.)
return Own<T>(new T(kj::fwd<Params>(params)...), _::HeapDisposer<T>::instance);
}
template <typename T>
Own<Decay<T>> heap(T&& orig) {
// Allocate a copy (or move) of the argument on the heap.
//
// The purpose of this overload is to allow you to omit the template parameter as there is only
// one argument and the purpose is to copy it.
typedef Decay<T> T2;
return Own<T2>(new T2(kj::fwd<T>(orig)), _::HeapDisposer<T2>::instance);
}
// =======================================================================================
// SpaceFor<T> -- assists in manual allocation
template <typename T>
class SpaceFor {
// A class which has the same size and alignment as T but does not call its constructor or
// destructor automatically. Instead, call construct() to construct a T in the space, which
// returns an Own<T> which will take care of calling T's destructor later.
public:
inline SpaceFor() {}
inline ~SpaceFor() {}
template <typename... Params>
Own<T> construct(Params&&... params) {
ctor(value, kj::fwd<Params>(params)...);
return Own<T>(&value, DestructorOnlyDisposer<T>::instance);
}
private:
union {
T value;
};
};
// =======================================================================================
// Inline implementation details
template <typename T>
struct Disposer::Dispose_<T, true> {
static void dispose(T* object, const Disposer& disposer) {
// Note that dynamic_cast<void*> does not require RTTI to be enabled, because the offset to
// the top of the object is in the vtable -- as it obviously needs to be to correctly implement
// operator delete.
disposer.disposeImpl(dynamic_cast<void*>(object));
}
};
template <typename T>
struct Disposer::Dispose_<T, false> {
static void dispose(T* object, const Disposer& disposer) {
disposer.disposeImpl(static_cast<void*>(object));
}
};
template <typename T>
void Disposer::dispose(T* object) const {
Dispose_<T>::dispose(object, *this);
}
} // namespace kj
#endif // KJ_MEMORY_H_

View File

@ -1,369 +0,0 @@
// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#ifndef KJ_MUTEX_H_
#define KJ_MUTEX_H_
#if defined(__GNUC__) && !KJ_HEADER_WARNINGS
#pragma GCC system_header
#endif
#include "memory.h"
#include <inttypes.h>
#if __linux__ && !defined(KJ_USE_FUTEX)
#define KJ_USE_FUTEX 1
#endif
#if !KJ_USE_FUTEX && !_WIN32
// On Linux we use futex. On other platforms we wrap pthreads.
// TODO(someday): Write efficient low-level locking primitives for other platforms.
#include <pthread.h>
#endif
namespace kj {
// =======================================================================================
// Private details -- public interfaces follow below.
namespace _ { // private
class Mutex {
// Internal implementation details. See `MutexGuarded<T>`.
public:
Mutex();
~Mutex();
KJ_DISALLOW_COPY(Mutex);
enum Exclusivity {
EXCLUSIVE,
SHARED
};
void lock(Exclusivity exclusivity);
void unlock(Exclusivity exclusivity);
void assertLockedByCaller(Exclusivity exclusivity);
// In debug mode, assert that the mutex is locked by the calling thread, or if that is
// non-trivial, assert that the mutex is locked (which should be good enough to catch problems
// in unit tests). In non-debug builds, do nothing.
private:
#if KJ_USE_FUTEX
uint futex;
// bit 31 (msb) = set if exclusive lock held
// bit 30 (msb) = set if threads are waiting for exclusive lock
// bits 0-29 = count of readers; If an exclusive lock is held, this is the count of threads
// waiting for a read lock, otherwise it is the count of threads that currently hold a read
// lock.
static constexpr uint EXCLUSIVE_HELD = 1u << 31;
static constexpr uint EXCLUSIVE_REQUESTED = 1u << 30;
static constexpr uint SHARED_COUNT_MASK = EXCLUSIVE_REQUESTED - 1;
#elif _WIN32
uintptr_t srwLock; // Actually an SRWLOCK, but don't want to #include <windows.h> in header.
#else
mutable pthread_rwlock_t mutex;
#endif
};
class Once {
// Internal implementation details. See `Lazy<T>`.
public:
#if KJ_USE_FUTEX
inline Once(bool startInitialized = false)
: futex(startInitialized ? INITIALIZED : UNINITIALIZED) {}
#else
Once(bool startInitialized = false);
~Once();
#endif
KJ_DISALLOW_COPY(Once);
class Initializer {
public:
virtual void run() = 0;
};
void runOnce(Initializer& init);
#if _WIN32 // TODO(perf): Can we make this inline on win32 somehow?
bool isInitialized() noexcept;
#else
inline bool isInitialized() noexcept {
// Fast path check to see if runOnce() would simply return immediately.
#if KJ_USE_FUTEX
return __atomic_load_n(&futex, __ATOMIC_ACQUIRE) == INITIALIZED;
#else
return __atomic_load_n(&state, __ATOMIC_ACQUIRE) == INITIALIZED;
#endif
}
#endif
void reset();
// Returns the state from initialized to uninitialized. It is an error to call this when
// not already initialized, or when runOnce() or isInitialized() might be called concurrently in
// another thread.
private:
#if KJ_USE_FUTEX
uint futex;
enum State {
UNINITIALIZED,
INITIALIZING,
INITIALIZING_WITH_WAITERS,
INITIALIZED
};
#elif _WIN32
uintptr_t initOnce; // Actually an INIT_ONCE, but don't want to #include <windows.h> in header.
#else
enum State {
UNINITIALIZED,
INITIALIZED
};
State state;
pthread_mutex_t mutex;
#endif
};
} // namespace _ (private)
// =======================================================================================
// Public interface
template <typename T>
class Locked {
// Return type for `MutexGuarded<T>::lock()`. `Locked<T>` provides access to the bounded object
// and unlocks the mutex when it goes out of scope.
public:
KJ_DISALLOW_COPY(Locked);
inline Locked(): mutex(nullptr), ptr(nullptr) {}
inline Locked(Locked&& other): mutex(other.mutex), ptr(other.ptr) {
other.mutex = nullptr;
other.ptr = nullptr;
}
inline ~Locked() {
if (mutex != nullptr) mutex->unlock(isConst<T>() ? _::Mutex::SHARED : _::Mutex::EXCLUSIVE);
}
inline Locked& operator=(Locked&& other) {
if (mutex != nullptr) mutex->unlock(isConst<T>() ? _::Mutex::SHARED : _::Mutex::EXCLUSIVE);
mutex = other.mutex;
ptr = other.ptr;
other.mutex = nullptr;
other.ptr = nullptr;
return *this;
}
inline void release() {
if (mutex != nullptr) mutex->unlock(isConst<T>() ? _::Mutex::SHARED : _::Mutex::EXCLUSIVE);
mutex = nullptr;
ptr = nullptr;
}
inline T* operator->() { return ptr; }
inline const T* operator->() const { return ptr; }
inline T& operator*() { return *ptr; }
inline const T& operator*() const { return *ptr; }
inline T* get() { return ptr; }
inline const T* get() const { return ptr; }
inline operator T*() { return ptr; }
inline operator const T*() const { return ptr; }
private:
_::Mutex* mutex;
T* ptr;
inline Locked(_::Mutex& mutex, T& value): mutex(&mutex), ptr(&value) {}
template <typename U>
friend class MutexGuarded;
};
template <typename T>
class MutexGuarded {
// An object of type T, bounded by a mutex. In order to access the object, you must lock it.
//
// Write locks are not "recursive" -- trying to lock again in a thread that already holds a lock
// will deadlock. Recursive write locks are usually a sign of bad design.
//
// Unfortunately, **READ LOCKS ARE NOT RECURSIVE** either. Common sense says they should be.
// But on many operating systems (BSD, OSX), recursively read-locking a pthread_rwlock is
// actually unsafe. The problem is that writers are "prioritized" over readers, so a read lock
// request will block if any write lock requests are outstanding. So, if thread A takes a read
// lock, thread B requests a write lock (and starts waiting), and then thread A tries to take
// another read lock recursively, the result is deadlock.
public:
template <typename... Params>
explicit MutexGuarded(Params&&... params);
// Initialize the mutex-bounded object by passing the given parameters to its constructor.
Locked<T> lockExclusive() const;
// Exclusively locks the object and returns it. The returned `Locked<T>` can be passed by
// move, similar to `Own<T>`.
//
// This method is declared `const` in accordance with KJ style rules which say that constness
// should be used to indicate thread-safety. It is safe to share a const pointer between threads,
// but it is not safe to share a mutable pointer. Since the whole point of MutexGuarded is to
// be shared between threads, its methods should be const, even though locking it produces a
// non-const pointer to the contained object.
Locked<const T> lockShared() const;
// Lock the value for shared access. Multiple shared locks can be taken concurrently, but cannot
// be held at the same time as a non-shared lock.
inline const T& getWithoutLock() const { return value; }
inline T& getWithoutLock() { return value; }
// Escape hatch for cases where some external factor guarantees that it's safe to get the
// value. You should treat these like const_cast -- be highly suspicious of any use.
inline const T& getAlreadyLockedShared() const;
inline T& getAlreadyLockedShared();
inline T& getAlreadyLockedExclusive() const;
// Like `getWithoutLock()`, but asserts that the lock is already held by the calling thread.
private:
mutable _::Mutex mutex;
mutable T value;
};
template <typename T>
class MutexGuarded<const T> {
// MutexGuarded cannot guard a const type. This would be pointless anyway, and would complicate
// the implementation of Locked<T>, which uses constness to decide what kind of lock it holds.
static_assert(sizeof(T) < 0, "MutexGuarded's type cannot be const.");
};
template <typename T>
class Lazy {
// A lazily-initialized value.
public:
template <typename Func>
T& get(Func&& init);
template <typename Func>
const T& get(Func&& init) const;
// The first thread to call get() will invoke the given init function to construct the value.
// Other threads will block until construction completes, then return the same value.
//
// `init` is a functor(typically a lambda) which takes `SpaceFor<T>&` as its parameter and returns
// `Own<T>`. If `init` throws an exception, the exception is propagated out of that thread's
// call to `get()`, and subsequent calls behave as if `get()` hadn't been called at all yet --
// in other words, subsequent calls retry initialization until it succeeds.
private:
mutable _::Once once;
mutable SpaceFor<T> space;
mutable Own<T> value;
template <typename Func>
class InitImpl;
};
// =======================================================================================
// Inline implementation details
template <typename T>
template <typename... Params>
inline MutexGuarded<T>::MutexGuarded(Params&&... params)
: value(kj::fwd<Params>(params)...) {}
template <typename T>
inline Locked<T> MutexGuarded<T>::lockExclusive() const {
mutex.lock(_::Mutex::EXCLUSIVE);
return Locked<T>(mutex, value);
}
template <typename T>
inline Locked<const T> MutexGuarded<T>::lockShared() const {
mutex.lock(_::Mutex::SHARED);
return Locked<const T>(mutex, value);
}
template <typename T>
inline const T& MutexGuarded<T>::getAlreadyLockedShared() const {
#ifdef KJ_DEBUG
mutex.assertLockedByCaller(_::Mutex::SHARED);
#endif
return value;
}
template <typename T>
inline T& MutexGuarded<T>::getAlreadyLockedShared() {
#ifdef KJ_DEBUG
mutex.assertLockedByCaller(_::Mutex::SHARED);
#endif
return value;
}
template <typename T>
inline T& MutexGuarded<T>::getAlreadyLockedExclusive() const {
#ifdef KJ_DEBUG
mutex.assertLockedByCaller(_::Mutex::EXCLUSIVE);
#endif
return const_cast<T&>(value);
}
template <typename T>
template <typename Func>
class Lazy<T>::InitImpl: public _::Once::Initializer {
public:
inline InitImpl(const Lazy<T>& lazy, Func&& func): lazy(lazy), func(kj::fwd<Func>(func)) {}
void run() override {
lazy.value = func(lazy.space);
}
private:
const Lazy<T>& lazy;
Func func;
};
template <typename T>
template <typename Func>
inline T& Lazy<T>::get(Func&& init) {
if (!once.isInitialized()) {
InitImpl<Func> initImpl(*this, kj::fwd<Func>(init));
once.runOnce(initImpl);
}
return *value;
}
template <typename T>
template <typename Func>
inline const T& Lazy<T>::get(Func&& init) const {
if (!once.isInitialized()) {
InitImpl<Func> initImpl(*this, kj::fwd<Func>(init));
once.runOnce(initImpl);
}
return *value;
}
} // namespace kj
#endif // KJ_MUTEX_H_

View File

@ -1,155 +0,0 @@
// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#ifndef KJ_ONE_OF_H_
#define KJ_ONE_OF_H_
#if defined(__GNUC__) && !KJ_HEADER_WARNINGS
#pragma GCC system_header
#endif
#include "common.h"
namespace kj {
namespace _ { // private
template <uint i, typename Key, typename First, typename... Rest>
struct TypeIndex_ { static constexpr uint value = TypeIndex_<i + 1, Key, Rest...>::value; };
template <uint i, typename Key, typename... Rest>
struct TypeIndex_<i, Key, Key, Rest...> { static constexpr uint value = i; };
} // namespace _ (private)
template <typename... Variants>
class OneOf {
template <typename Key>
static inline constexpr uint typeIndex() { return _::TypeIndex_<1, Key, Variants...>::value; }
// Get the 1-based index of Key within the type list Types.
public:
inline OneOf(): tag(0) {}
OneOf(const OneOf& other) { copyFrom(other); }
OneOf(OneOf&& other) { moveFrom(other); }
~OneOf() { destroy(); }
OneOf& operator=(const OneOf& other) { if (tag != 0) destroy(); copyFrom(other); return *this; }
OneOf& operator=(OneOf&& other) { if (tag != 0) destroy(); moveFrom(other); return *this; }
inline bool operator==(decltype(nullptr)) const { return tag == 0; }
inline bool operator!=(decltype(nullptr)) const { return tag != 0; }
template <typename T>
bool is() const {
return tag == typeIndex<T>();
}
template <typename T>
T& get() {
KJ_IREQUIRE(is<T>(), "Must check OneOf::is<T>() before calling get<T>().");
return *reinterpret_cast<T*>(space);
}
template <typename T>
const T& get() const {
KJ_IREQUIRE(is<T>(), "Must check OneOf::is<T>() before calling get<T>().");
return *reinterpret_cast<const T*>(space);
}
template <typename T, typename... Params>
T& init(Params&&... params) {
if (tag != 0) destroy();
ctor(*reinterpret_cast<T*>(space), kj::fwd<Params>(params)...);
tag = typeIndex<T>();
return *reinterpret_cast<T*>(space);
}
private:
uint tag;
static inline constexpr size_t maxSize(size_t a) {
return a;
}
template <typename... Rest>
static inline constexpr size_t maxSize(size_t a, size_t b, Rest... rest) {
return maxSize(kj::max(a, b), rest...);
}
// Returns the maximum of all the parameters.
// TODO(someday): Generalize the above template and make it common. I tried, but C++ decided to
// be difficult so I cut my losses.
static constexpr auto spaceSize = maxSize(sizeof(Variants)...);
// TODO(msvc): This constant could just as well go directly inside space's bracket's, where it's
// used, but MSVC suffers a parse error on `...`.
union {
byte space[spaceSize];
void* forceAligned;
// TODO(someday): Use C++11 alignas() once we require GCC 4.8 / Clang 3.3.
};
template <typename... T>
inline void doAll(T... t) {}
template <typename T>
inline bool destroyVariant() {
if (tag == typeIndex<T>()) {
tag = 0;
dtor(*reinterpret_cast<T*>(space));
}
return false;
}
void destroy() {
doAll(destroyVariant<Variants>()...);
}
template <typename T>
inline bool copyVariantFrom(const OneOf& other) {
if (other.is<T>()) {
ctor(*reinterpret_cast<T*>(space), other.get<T>());
}
return false;
}
void copyFrom(const OneOf& other) {
// Initialize as a copy of `other`. Expects that `this` starts out uninitialized, so the tag
// is invalid.
tag = other.tag;
doAll(copyVariantFrom<Variants>(other)...);
}
template <typename T>
inline bool moveVariantFrom(OneOf& other) {
if (other.is<T>()) {
ctor(*reinterpret_cast<T*>(space), kj::mv(other.get<T>()));
}
return false;
}
void moveFrom(OneOf& other) {
// Initialize as a copy of `other`. Expects that `this` starts out uninitialized, so the tag
// is invalid.
tag = other.tag;
doAll(moveVariantFrom<Variants>(other)...);
}
};
} // namespace kj
#endif // KJ_ONE_OF_H_

View File

@ -1,361 +0,0 @@
// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
// This file contains parsers useful for character stream inputs, including parsers to parse
// common kinds of tokens like identifiers, numbers, and quoted strings.
#ifndef KJ_PARSE_CHAR_H_
#define KJ_PARSE_CHAR_H_
#if defined(__GNUC__) && !KJ_HEADER_WARNINGS
#pragma GCC system_header
#endif
#include "common.h"
#include "../string.h"
#include <inttypes.h>
namespace kj {
namespace parse {
// =======================================================================================
// Exact char/string.
class ExactString_ {
public:
constexpr inline ExactString_(const char* str): str(str) {}
template <typename Input>
Maybe<Tuple<>> operator()(Input& input) const {
const char* ptr = str;
while (*ptr != '\0') {
if (input.atEnd() || input.current() != *ptr) return nullptr;
input.next();
++ptr;
}
return Tuple<>();
}
private:
const char* str;
};
constexpr inline ExactString_ exactString(const char* str) {
return ExactString_(str);
}
template <char c>
constexpr ExactlyConst_<char, c> exactChar() {
// Returns a parser that matches exactly the character given by the template argument (returning
// no result).
return ExactlyConst_<char, c>();
}
// =======================================================================================
// Char ranges / sets
class CharGroup_ {
public:
constexpr inline CharGroup_(): bits{0, 0, 0, 0} {}
constexpr inline CharGroup_ orRange(unsigned char first, unsigned char last) const {
return CharGroup_(bits[0] | (oneBits(last + 1) & ~oneBits(first )),
bits[1] | (oneBits(last - 63) & ~oneBits(first - 64)),
bits[2] | (oneBits(last - 127) & ~oneBits(first - 128)),
bits[3] | (oneBits(last - 191) & ~oneBits(first - 192)));
}
constexpr inline CharGroup_ orAny(const char* chars) const {
return *chars == 0 ? *this : orChar(*chars).orAny(chars + 1);
}
constexpr inline CharGroup_ orChar(unsigned char c) const {
return CharGroup_(bits[0] | bit(c),
bits[1] | bit(c - 64),
bits[2] | bit(c - 128),
bits[3] | bit(c - 256));
}
constexpr inline CharGroup_ orGroup(CharGroup_ other) const {
return CharGroup_(bits[0] | other.bits[0],
bits[1] | other.bits[1],
bits[2] | other.bits[2],
bits[3] | other.bits[3]);
}
constexpr inline CharGroup_ invert() const {
return CharGroup_(~bits[0], ~bits[1], ~bits[2], ~bits[3]);
}
constexpr inline bool contains(unsigned char c) const {
return (bits[c / 64] & (1ll << (c % 64))) != 0;
}
template <typename Input>
Maybe<char> operator()(Input& input) const {
if (input.atEnd()) return nullptr;
unsigned char c = input.current();
if (contains(c)) {
input.next();
return c;
} else {
return nullptr;
}
}
private:
typedef unsigned long long Bits64;
constexpr inline CharGroup_(Bits64 a, Bits64 b, Bits64 c, Bits64 d): bits{a, b, c, d} {}
Bits64 bits[4];
static constexpr inline Bits64 oneBits(int count) {
return count <= 0 ? 0ll : count >= 64 ? -1ll : ((1ll << count) - 1);
}
static constexpr inline Bits64 bit(int index) {
return index < 0 ? 0 : index >= 64 ? 0 : (1ll << index);
}
};
constexpr inline CharGroup_ charRange(char first, char last) {
// Create a parser which accepts any character in the range from `first` to `last`, inclusive.
// For example: `charRange('a', 'z')` matches all lower-case letters. The parser's result is the
// character matched.
//
// The returned object has methods which can be used to match more characters. The following
// produces a parser which accepts any letter as well as '_', '+', '-', and '.'.
//
// charRange('a', 'z').orRange('A', 'Z').orChar('_').orAny("+-.")
//
// You can also use `.invert()` to match the opposite set of characters.
return CharGroup_().orRange(first, last);
}
#if _MSC_VER
#define anyOfChars(chars) CharGroup_().orAny(chars)
// TODO(msvc): MSVC ICEs on the proper definition of `anyOfChars()`, which in turn prevents us from
// building the compiler or schema parser. We don't know why this happens, but Harris found that
// this horrible, horrible hack makes things work. This is awful, but it's better than nothing.
// Hopefully, MSVC will get fixed soon and we'll be able to remove this.
#else
constexpr inline CharGroup_ anyOfChars(const char* chars) {
// Returns a parser that accepts any of the characters in the given string (which should usually
// be a literal). The returned parser is of the same type as returned by `charRange()` -- see
// that function for more info.
return CharGroup_().orAny(chars);
}
#endif
// =======================================================================================
namespace _ { // private
struct ArrayToString {
inline String operator()(const Array<char>& arr) const {
return heapString(arr);
}
};
} // namespace _ (private)
template <typename SubParser>
constexpr inline auto charsToString(SubParser&& subParser)
-> decltype(transform(kj::fwd<SubParser>(subParser), _::ArrayToString())) {
// Wraps a parser that returns Array<char> such that it returns String instead.
return parse::transform(kj::fwd<SubParser>(subParser), _::ArrayToString());
}
// =======================================================================================
// Basic character classes.
constexpr auto alpha = charRange('a', 'z').orRange('A', 'Z');
constexpr auto digit = charRange('0', '9');
constexpr auto alphaNumeric = alpha.orGroup(digit);
constexpr auto nameStart = alpha.orChar('_');
constexpr auto nameChar = alphaNumeric.orChar('_');
constexpr auto hexDigit = charRange('0', '9').orRange('a', 'f').orRange('A', 'F');
constexpr auto octDigit = charRange('0', '7');
constexpr auto whitespaceChar = anyOfChars(" \f\n\r\t\v");
constexpr auto controlChar = charRange(0, 0x1f).invert().orGroup(whitespaceChar).invert();
constexpr auto whitespace = many(anyOfChars(" \f\n\r\t\v"));
constexpr auto discardWhitespace = discard(many(discard(anyOfChars(" \f\n\r\t\v"))));
// Like discard(whitespace) but avoids some memory allocation.
// =======================================================================================
// Identifiers
namespace _ { // private
struct IdentifierToString {
inline String operator()(char first, const Array<char>& rest) const {
String result = heapString(rest.size() + 1);
result[0] = first;
memcpy(result.begin() + 1, rest.begin(), rest.size());
return result;
}
};
} // namespace _ (private)
constexpr auto identifier = transform(sequence(nameStart, many(nameChar)), _::IdentifierToString());
// Parses an identifier (e.g. a C variable name).
// =======================================================================================
// Integers
namespace _ { // private
inline char parseDigit(char c) {
if (c < 'A') return c - '0';
if (c < 'a') return c - 'A' + 10;
return c - 'a' + 10;
}
template <uint base>
struct ParseInteger {
inline uint64_t operator()(const Array<char>& digits) const {
return operator()('0', digits);
}
uint64_t operator()(char first, const Array<char>& digits) const {
uint64_t result = parseDigit(first);
for (char digit: digits) {
result = result * base + parseDigit(digit);
}
return result;
}
};
} // namespace _ (private)
constexpr auto integer = sequence(
oneOf(
transform(sequence(exactChar<'0'>(), exactChar<'x'>(), oneOrMore(hexDigit)), _::ParseInteger<16>()),
transform(sequence(exactChar<'0'>(), many(octDigit)), _::ParseInteger<8>()),
transform(sequence(charRange('1', '9'), many(digit)), _::ParseInteger<10>())),
notLookingAt(alpha.orAny("_.")));
// =======================================================================================
// Numbers (i.e. floats)
namespace _ { // private
struct ParseFloat {
double operator()(const Array<char>& digits,
const Maybe<Array<char>>& fraction,
const Maybe<Tuple<Maybe<char>, Array<char>>>& exponent) const;
};
} // namespace _ (private)
constexpr auto number = transform(
sequence(
oneOrMore(digit),
optional(sequence(exactChar<'.'>(), many(digit))),
optional(sequence(discard(anyOfChars("eE")), optional(anyOfChars("+-")), many(digit))),
notLookingAt(alpha.orAny("_."))),
_::ParseFloat());
// =======================================================================================
// Quoted strings
namespace _ { // private
struct InterpretEscape {
char operator()(char c) const {
switch (c) {
case 'a': return '\a';
case 'b': return '\b';
case 'f': return '\f';
case 'n': return '\n';
case 'r': return '\r';
case 't': return '\t';
case 'v': return '\v';
default: return c;
}
}
};
struct ParseHexEscape {
inline char operator()(char first, char second) const {
return (parseDigit(first) << 4) | parseDigit(second);
}
};
struct ParseHexByte {
inline byte operator()(char first, char second) const {
return (parseDigit(first) << 4) | parseDigit(second);
}
};
struct ParseOctEscape {
inline char operator()(char first, Maybe<char> second, Maybe<char> third) const {
char result = first - '0';
KJ_IF_MAYBE(digit1, second) {
result = (result << 3) | (*digit1 - '0');
KJ_IF_MAYBE(digit2, third) {
result = (result << 3) | (*digit2 - '0');
}
}
return result;
}
};
} // namespace _ (private)
constexpr auto escapeSequence =
sequence(exactChar<'\\'>(), oneOf(
transform(anyOfChars("abfnrtv'\"\\\?"), _::InterpretEscape()),
transform(sequence(exactChar<'x'>(), hexDigit, hexDigit), _::ParseHexEscape()),
transform(sequence(octDigit, optional(octDigit), optional(octDigit)),
_::ParseOctEscape())));
// A parser that parses a C-string-style escape sequence (starting with a backslash). Returns
// a char.
constexpr auto doubleQuotedString = charsToString(sequence(
exactChar<'\"'>(),
many(oneOf(anyOfChars("\\\n\"").invert(), escapeSequence)),
exactChar<'\"'>()));
// Parses a C-style double-quoted string.
constexpr auto singleQuotedString = charsToString(sequence(
exactChar<'\''>(),
many(oneOf(anyOfChars("\\\n\'").invert(), escapeSequence)),
exactChar<'\''>()));
// Parses a C-style single-quoted string.
constexpr auto doubleQuotedHexBinary = sequence(
exactChar<'0'>(), exactChar<'x'>(), exactChar<'\"'>(),
oneOrMore(transform(sequence(discardWhitespace, hexDigit, hexDigit), _::ParseHexByte())),
discardWhitespace,
exactChar<'\"'>());
// Parses a double-quoted hex binary literal. Returns Array<byte>.
} // namespace parse
} // namespace kj
#endif // KJ_PARSE_CHAR_H_

View File

@ -1,824 +0,0 @@
// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
// Parser combinator framework!
//
// This file declares several functions which construct parsers, usually taking other parsers as
// input, thus making them parser combinators.
//
// A valid parser is any functor which takes a reference to an input cursor (defined below) as its
// input and returns a Maybe. The parser returns null on parse failure, or returns the parsed
// result on success.
//
// An "input cursor" is any type which implements the same interface as IteratorInput, below. Such
// a type acts as a pointer to the current input location. When a parser returns successfully, it
// will have updated the input cursor to point to the position just past the end of what was parsed.
// On failure, the cursor position is unspecified.
#ifndef KJ_PARSE_COMMON_H_
#define KJ_PARSE_COMMON_H_
#if defined(__GNUC__) && !KJ_HEADER_WARNINGS
#pragma GCC system_header
#endif
#include "../common.h"
#include "../memory.h"
#include "../array.h"
#include "../tuple.h"
#include "../vector.h"
#if _MSC_VER
#include <type_traits> // result_of_t
#endif
namespace kj {
namespace parse {
template <typename Element, typename Iterator>
class IteratorInput {
// A parser input implementation based on an iterator range.
public:
IteratorInput(Iterator begin, Iterator end)
: parent(nullptr), pos(begin), end(end), best(begin) {}
explicit IteratorInput(IteratorInput& parent)
: parent(&parent), pos(parent.pos), end(parent.end), best(parent.pos) {}
~IteratorInput() {
if (parent != nullptr) {
parent->best = kj::max(kj::max(pos, best), parent->best);
}
}
KJ_DISALLOW_COPY(IteratorInput);
void advanceParent() {
parent->pos = pos;
}
void forgetParent() {
parent = nullptr;
}
bool atEnd() { return pos == end; }
auto current() -> decltype(*instance<Iterator>()) {
KJ_IREQUIRE(!atEnd());
return *pos;
}
auto consume() -> decltype(*instance<Iterator>()) {
KJ_IREQUIRE(!atEnd());
return *pos++;
}
void next() {
KJ_IREQUIRE(!atEnd());
++pos;
}
Iterator getBest() { return kj::max(pos, best); }
Iterator getPosition() { return pos; }
private:
IteratorInput* parent;
Iterator pos;
Iterator end;
Iterator best; // furthest we got with any sub-input
};
template <typename T> struct OutputType_;
template <typename T> struct OutputType_<Maybe<T>> { typedef T Type; };
template <typename Parser, typename Input>
using OutputType = typename OutputType_<
#if _MSC_VER
std::result_of_t<Parser(Input)>
// The instance<T&>() based version below results in:
// C2064: term does not evaluate to a function taking 1 arguments
#else
decltype(instance<Parser&>()(instance<Input&>()))
#endif
>::Type;
// Synonym for the output type of a parser, given the parser type and the input type.
// =======================================================================================
template <typename Input, typename Output>
class ParserRef {
// Acts as a reference to some other parser, with simplified type. The referenced parser
// is polymorphic by virtual call rather than templates. For grammars of non-trivial size,
// it is important to inject refs into the grammar here and there to prevent the parser types
// from becoming ridiculous. Using too many of them can hurt performance, though.
public:
ParserRef(): parser(nullptr), wrapper(nullptr) {}
ParserRef(const ParserRef&) = default;
ParserRef(ParserRef&&) = default;
ParserRef& operator=(const ParserRef& other) = default;
ParserRef& operator=(ParserRef&& other) = default;
template <typename Other>
constexpr ParserRef(Other&& other)
: parser(&other), wrapper(&WrapperImplInstance<Decay<Other>>::instance) {
static_assert(kj::isReference<Other>(), "ParserRef should not be assigned to a temporary.");
}
template <typename Other>
inline ParserRef& operator=(Other&& other) {
static_assert(kj::isReference<Other>(), "ParserRef should not be assigned to a temporary.");
parser = &other;
wrapper = &WrapperImplInstance<Decay<Other>>::instance;
return *this;
}
KJ_ALWAYS_INLINE(Maybe<Output> operator()(Input& input) const) {
// Always inline in the hopes that this allows branch prediction to kick in so the virtual call
// doesn't hurt so much.
return wrapper->parse(parser, input);
}
private:
struct Wrapper {
virtual Maybe<Output> parse(const void* parser, Input& input) const = 0;
};
template <typename ParserImpl>
struct WrapperImpl: public Wrapper {
Maybe<Output> parse(const void* parser, Input& input) const override {
return (*reinterpret_cast<const ParserImpl*>(parser))(input);
}
};
template <typename ParserImpl>
struct WrapperImplInstance {
#if _MSC_VER
// TODO(msvc): MSVC currently fails to initialize vtable pointers for constexpr values so
// we have to make this just const instead.
static const WrapperImpl<ParserImpl> instance;
#else
static constexpr WrapperImpl<ParserImpl> instance = WrapperImpl<ParserImpl>();
#endif
};
const void* parser;
const Wrapper* wrapper;
};
template <typename Input, typename Output>
template <typename ParserImpl>
#if _MSC_VER
const typename ParserRef<Input, Output>::template WrapperImpl<ParserImpl>
ParserRef<Input, Output>::WrapperImplInstance<ParserImpl>::instance = WrapperImpl<ParserImpl>();
#else
constexpr typename ParserRef<Input, Output>::template WrapperImpl<ParserImpl>
ParserRef<Input, Output>::WrapperImplInstance<ParserImpl>::instance;
#endif
template <typename Input, typename ParserImpl>
constexpr ParserRef<Input, OutputType<ParserImpl, Input>> ref(ParserImpl& impl) {
// Constructs a ParserRef. You must specify the input type explicitly, e.g.
// `ref<MyInput>(myParser)`.
return ParserRef<Input, OutputType<ParserImpl, Input>>(impl);
}
// -------------------------------------------------------------------
// any
// Output = one token
class Any_ {
public:
template <typename Input>
Maybe<Decay<decltype(instance<Input>().consume())>> operator()(Input& input) const {
if (input.atEnd()) {
return nullptr;
} else {
return input.consume();
}
}
};
constexpr Any_ any = Any_();
// A parser which matches any token and simply returns it.
// -------------------------------------------------------------------
// exactly()
// Output = Tuple<>
template <typename T>
class Exactly_ {
public:
explicit constexpr Exactly_(T&& expected): expected(expected) {}
template <typename Input>
Maybe<Tuple<>> operator()(Input& input) const {
if (input.atEnd() || input.current() != expected) {
return nullptr;
} else {
input.next();
return Tuple<>();
}
}
private:
T expected;
};
template <typename T>
constexpr Exactly_<T> exactly(T&& expected) {
// Constructs a parser which succeeds when the input is exactly the token specified. The
// result is always the empty tuple.
return Exactly_<T>(kj::fwd<T>(expected));
}
// -------------------------------------------------------------------
// exactlyConst()
// Output = Tuple<>
template <typename T, T expected>
class ExactlyConst_ {
public:
explicit constexpr ExactlyConst_() {}
template <typename Input>
Maybe<Tuple<>> operator()(Input& input) const {
if (input.atEnd() || input.current() != expected) {
return nullptr;
} else {
input.next();
return Tuple<>();
}
}
};
template <typename T, T expected>
constexpr ExactlyConst_<T, expected> exactlyConst() {
// Constructs a parser which succeeds when the input is exactly the token specified. The
// result is always the empty tuple. This parser is templated on the token value which may cause
// it to perform better -- or worse. Be sure to measure.
return ExactlyConst_<T, expected>();
}
// -------------------------------------------------------------------
// constResult()
template <typename SubParser, typename Result>
class ConstResult_ {
public:
explicit constexpr ConstResult_(SubParser&& subParser, Result&& result)
: subParser(kj::fwd<SubParser>(subParser)), result(kj::fwd<Result>(result)) {}
template <typename Input>
Maybe<Result> operator()(Input& input) const {
if (subParser(input) == nullptr) {
return nullptr;
} else {
return result;
}
}
private:
SubParser subParser;
Result result;
};
template <typename SubParser, typename Result>
constexpr ConstResult_<SubParser, Result> constResult(SubParser&& subParser, Result&& result) {
// Constructs a parser which returns exactly `result` if `subParser` is successful.
return ConstResult_<SubParser, Result>(kj::fwd<SubParser>(subParser), kj::fwd<Result>(result));
}
template <typename SubParser>
constexpr ConstResult_<SubParser, Tuple<>> discard(SubParser&& subParser) {
// Constructs a parser which wraps `subParser` but discards the result.
return constResult(kj::fwd<SubParser>(subParser), Tuple<>());
}
// -------------------------------------------------------------------
// sequence()
// Output = Flattened Tuple of outputs of sub-parsers.
template <typename... SubParsers> class Sequence_;
template <typename FirstSubParser, typename... SubParsers>
class Sequence_<FirstSubParser, SubParsers...> {
public:
template <typename T, typename... U>
explicit constexpr Sequence_(T&& firstSubParser, U&&... rest)
: first(kj::fwd<T>(firstSubParser)), rest(kj::fwd<U>(rest)...) {}
// TODO(msvc): The trailing return types on `operator()` and `parseNext()` expose at least two
// bugs in MSVC:
//
// 1. An ICE.
// 2. 'error C2672: 'operator __surrogate_func': no matching overloaded function found)',
// which crops up in numerous places when trying to build the capnp command line tools.
//
// The only workaround I found for both bugs is to omit the trailing return types and instead
// rely on C++14's return type deduction.
template <typename Input>
auto operator()(Input& input) const
#ifndef _MSC_VER
-> Maybe<decltype(tuple(
instance<OutputType<FirstSubParser, Input>>(),
instance<OutputType<SubParsers, Input>>()...))>
#endif
{
return parseNext(input);
}
template <typename Input, typename... InitialParams>
auto parseNext(Input& input, InitialParams&&... initialParams) const
#ifndef _MSC_VER
-> Maybe<decltype(tuple(
kj::fwd<InitialParams>(initialParams)...,
instance<OutputType<FirstSubParser, Input>>(),
instance<OutputType<SubParsers, Input>>()...))>
#endif
{
KJ_IF_MAYBE(firstResult, first(input)) {
return rest.parseNext(input, kj::fwd<InitialParams>(initialParams)...,
kj::mv(*firstResult));
} else {
// TODO(msvc): MSVC depends on return type deduction to compile this function, so we need to
// help it deduce the right type on this code path.
return Maybe<decltype(tuple(
kj::fwd<InitialParams>(initialParams)...,
instance<OutputType<FirstSubParser, Input>>(),
instance<OutputType<SubParsers, Input>>()...))>{nullptr};
}
}
private:
FirstSubParser first;
Sequence_<SubParsers...> rest;
};
template <>
class Sequence_<> {
public:
template <typename Input>
Maybe<Tuple<>> operator()(Input& input) const {
return parseNext(input);
}
template <typename Input, typename... Params>
auto parseNext(Input& input, Params&&... params) const ->
Maybe<decltype(tuple(kj::fwd<Params>(params)...))> {
return tuple(kj::fwd<Params>(params)...);
}
};
template <typename... SubParsers>
constexpr Sequence_<SubParsers...> sequence(SubParsers&&... subParsers) {
// Constructs a parser that executes each of the parameter parsers in sequence and returns a
// tuple of their results.
return Sequence_<SubParsers...>(kj::fwd<SubParsers>(subParsers)...);
}
// -------------------------------------------------------------------
// many()
// Output = Array of output of sub-parser, or just a uint count if the sub-parser returns Tuple<>.
template <typename SubParser, bool atLeastOne>
class Many_ {
template <typename Input, typename Output = OutputType<SubParser, Input>>
struct Impl;
public:
explicit constexpr Many_(SubParser&& subParser)
: subParser(kj::fwd<SubParser>(subParser)) {}
template <typename Input>
auto operator()(Input& input) const
-> decltype(Impl<Input>::apply(instance<const SubParser&>(), input));
private:
SubParser subParser;
};
template <typename SubParser, bool atLeastOne>
template <typename Input, typename Output>
struct Many_<SubParser, atLeastOne>::Impl {
static Maybe<Array<Output>> apply(const SubParser& subParser, Input& input) {
typedef Vector<OutputType<SubParser, Input>> Results;
Results results;
while (!input.atEnd()) {
Input subInput(input);
KJ_IF_MAYBE(subResult, subParser(subInput)) {
subInput.advanceParent();
results.add(kj::mv(*subResult));
} else {
break;
}
}
if (atLeastOne && results.empty()) {
return nullptr;
}
return results.releaseAsArray();
}
};
template <typename SubParser, bool atLeastOne>
template <typename Input>
struct Many_<SubParser, atLeastOne>::Impl<Input, Tuple<>> {
// If the sub-parser output is Tuple<>, just return a count.
static Maybe<uint> apply(const SubParser& subParser, Input& input) {
uint count = 0;
while (!input.atEnd()) {
Input subInput(input);
KJ_IF_MAYBE(subResult, subParser(subInput)) {
subInput.advanceParent();
++count;
} else {
break;
}
}
if (atLeastOne && count == 0) {
return nullptr;
}
return count;
}
};
template <typename SubParser, bool atLeastOne>
template <typename Input>
auto Many_<SubParser, atLeastOne>::operator()(Input& input) const
-> decltype(Impl<Input>::apply(instance<const SubParser&>(), input)) {
return Impl<Input, OutputType<SubParser, Input>>::apply(subParser, input);
}
template <typename SubParser>
constexpr Many_<SubParser, false> many(SubParser&& subParser) {
// Constructs a parser that repeatedly executes the given parser until it fails, returning an
// Array of the results (or a uint count if `subParser` returns an empty tuple).
return Many_<SubParser, false>(kj::fwd<SubParser>(subParser));
}
template <typename SubParser>
constexpr Many_<SubParser, true> oneOrMore(SubParser&& subParser) {
// Like `many()` but the parser must parse at least one item to be successful.
return Many_<SubParser, true>(kj::fwd<SubParser>(subParser));
}
// -------------------------------------------------------------------
// times()
// Output = Array of output of sub-parser, or Tuple<> if sub-parser returns Tuple<>.
template <typename SubParser>
class Times_ {
template <typename Input, typename Output = OutputType<SubParser, Input>>
struct Impl;
public:
explicit constexpr Times_(SubParser&& subParser, uint count)
: subParser(kj::fwd<SubParser>(subParser)), count(count) {}
template <typename Input>
auto operator()(Input& input) const
-> decltype(Impl<Input>::apply(instance<const SubParser&>(), instance<uint>(), input));
private:
SubParser subParser;
uint count;
};
template <typename SubParser>
template <typename Input, typename Output>
struct Times_<SubParser>::Impl {
static Maybe<Array<Output>> apply(const SubParser& subParser, uint count, Input& input) {
auto results = heapArrayBuilder<OutputType<SubParser, Input>>(count);
while (results.size() < count) {
if (input.atEnd()) {
return nullptr;
} else KJ_IF_MAYBE(subResult, subParser(input)) {
results.add(kj::mv(*subResult));
} else {
return nullptr;
}
}
return results.finish();
}
};
template <typename SubParser>
template <typename Input>
struct Times_<SubParser>::Impl<Input, Tuple<>> {
// If the sub-parser output is Tuple<>, just return a count.
static Maybe<Tuple<>> apply(const SubParser& subParser, uint count, Input& input) {
uint actualCount = 0;
while (actualCount < count) {
if (input.atEnd()) {
return nullptr;
} else KJ_IF_MAYBE(subResult, subParser(input)) {
++actualCount;
} else {
return nullptr;
}
}
return tuple();
}
};
template <typename SubParser>
template <typename Input>
auto Times_<SubParser>::operator()(Input& input) const
-> decltype(Impl<Input>::apply(instance<const SubParser&>(), instance<uint>(), input)) {
return Impl<Input, OutputType<SubParser, Input>>::apply(subParser, count, input);
}
template <typename SubParser>
constexpr Times_<SubParser> times(SubParser&& subParser, uint count) {
// Constructs a parser that repeats the subParser exactly `count` times.
return Times_<SubParser>(kj::fwd<SubParser>(subParser), count);
}
// -------------------------------------------------------------------
// optional()
// Output = Maybe<output of sub-parser>
template <typename SubParser>
class Optional_ {
public:
explicit constexpr Optional_(SubParser&& subParser)
: subParser(kj::fwd<SubParser>(subParser)) {}
template <typename Input>
Maybe<Maybe<OutputType<SubParser, Input>>> operator()(Input& input) const {
typedef Maybe<OutputType<SubParser, Input>> Result;
Input subInput(input);
KJ_IF_MAYBE(subResult, subParser(subInput)) {
subInput.advanceParent();
return Result(kj::mv(*subResult));
} else {
return Result(nullptr);
}
}
private:
SubParser subParser;
};
template <typename SubParser>
constexpr Optional_<SubParser> optional(SubParser&& subParser) {
// Constructs a parser that accepts zero or one of the given sub-parser, returning a Maybe
// of the sub-parser's result.
return Optional_<SubParser>(kj::fwd<SubParser>(subParser));
}
// -------------------------------------------------------------------
// oneOf()
// All SubParsers must have same output type, which becomes the output type of the
// OneOfParser.
template <typename... SubParsers>
class OneOf_;
template <typename FirstSubParser, typename... SubParsers>
class OneOf_<FirstSubParser, SubParsers...> {
public:
explicit constexpr OneOf_(FirstSubParser&& firstSubParser, SubParsers&&... rest)
: first(kj::fwd<FirstSubParser>(firstSubParser)), rest(kj::fwd<SubParsers>(rest)...) {}
template <typename Input>
Maybe<OutputType<FirstSubParser, Input>> operator()(Input& input) const {
{
Input subInput(input);
Maybe<OutputType<FirstSubParser, Input>> firstResult = first(subInput);
if (firstResult != nullptr) {
subInput.advanceParent();
return kj::mv(firstResult);
}
}
// Hoping for some tail recursion here...
return rest(input);
}
private:
FirstSubParser first;
OneOf_<SubParsers...> rest;
};
template <>
class OneOf_<> {
public:
template <typename Input>
decltype(nullptr) operator()(Input& input) const {
return nullptr;
}
};
template <typename... SubParsers>
constexpr OneOf_<SubParsers...> oneOf(SubParsers&&... parsers) {
// Constructs a parser that accepts one of a set of options. The parser behaves as the first
// sub-parser in the list which returns successfully. All of the sub-parsers must return the
// same type.
return OneOf_<SubParsers...>(kj::fwd<SubParsers>(parsers)...);
}
// -------------------------------------------------------------------
// transform()
// Output = Result of applying transform functor to input value. If input is a tuple, it is
// unpacked to form the transformation parameters.
template <typename Position>
struct Span {
public:
inline const Position& begin() const { return begin_; }
inline const Position& end() const { return end_; }
Span() = default;
inline constexpr Span(Position&& begin, Position&& end): begin_(mv(begin)), end_(mv(end)) {}
private:
Position begin_;
Position end_;
};
template <typename Position>
constexpr Span<Decay<Position>> span(Position&& start, Position&& end) {
return Span<Decay<Position>>(kj::fwd<Position>(start), kj::fwd<Position>(end));
}
template <typename SubParser, typename TransformFunc>
class Transform_ {
public:
explicit constexpr Transform_(SubParser&& subParser, TransformFunc&& transform)
: subParser(kj::fwd<SubParser>(subParser)), transform(kj::fwd<TransformFunc>(transform)) {}
template <typename Input>
Maybe<decltype(kj::apply(instance<TransformFunc&>(),
instance<OutputType<SubParser, Input>&&>()))>
operator()(Input& input) const {
KJ_IF_MAYBE(subResult, subParser(input)) {
return kj::apply(transform, kj::mv(*subResult));
} else {
return nullptr;
}
}
private:
SubParser subParser;
TransformFunc transform;
};
template <typename SubParser, typename TransformFunc>
class TransformOrReject_ {
public:
explicit constexpr TransformOrReject_(SubParser&& subParser, TransformFunc&& transform)
: subParser(kj::fwd<SubParser>(subParser)), transform(kj::fwd<TransformFunc>(transform)) {}
template <typename Input>
decltype(kj::apply(instance<TransformFunc&>(), instance<OutputType<SubParser, Input>&&>()))
operator()(Input& input) const {
KJ_IF_MAYBE(subResult, subParser(input)) {
return kj::apply(transform, kj::mv(*subResult));
} else {
return nullptr;
}
}
private:
SubParser subParser;
TransformFunc transform;
};
template <typename SubParser, typename TransformFunc>
class TransformWithLocation_ {
public:
explicit constexpr TransformWithLocation_(SubParser&& subParser, TransformFunc&& transform)
: subParser(kj::fwd<SubParser>(subParser)), transform(kj::fwd<TransformFunc>(transform)) {}
template <typename Input>
Maybe<decltype(kj::apply(instance<TransformFunc&>(),
instance<Span<Decay<decltype(instance<Input&>().getPosition())>>>(),
instance<OutputType<SubParser, Input>&&>()))>
operator()(Input& input) const {
auto start = input.getPosition();
KJ_IF_MAYBE(subResult, subParser(input)) {
return kj::apply(transform, Span<decltype(start)>(kj::mv(start), input.getPosition()),
kj::mv(*subResult));
} else {
return nullptr;
}
}
private:
SubParser subParser;
TransformFunc transform;
};
template <typename SubParser, typename TransformFunc>
constexpr Transform_<SubParser, TransformFunc> transform(
SubParser&& subParser, TransformFunc&& functor) {
// Constructs a parser which executes some other parser and then transforms the result by invoking
// `functor` on it. Typically `functor` is a lambda. It is invoked using `kj::apply`,
// meaning tuples will be unpacked as arguments.
return Transform_<SubParser, TransformFunc>(
kj::fwd<SubParser>(subParser), kj::fwd<TransformFunc>(functor));
}
template <typename SubParser, typename TransformFunc>
constexpr TransformOrReject_<SubParser, TransformFunc> transformOrReject(
SubParser&& subParser, TransformFunc&& functor) {
// Like `transform()` except that `functor` returns a `Maybe`. If it returns null, parsing fails,
// otherwise the parser's result is the content of the `Maybe`.
return TransformOrReject_<SubParser, TransformFunc>(
kj::fwd<SubParser>(subParser), kj::fwd<TransformFunc>(functor));
}
template <typename SubParser, typename TransformFunc>
constexpr TransformWithLocation_<SubParser, TransformFunc> transformWithLocation(
SubParser&& subParser, TransformFunc&& functor) {
// Like `transform` except that `functor` also takes a `Span` as its first parameter specifying
// the location of the parsed content. The span's position type is whatever the parser input's
// getPosition() returns.
return TransformWithLocation_<SubParser, TransformFunc>(
kj::fwd<SubParser>(subParser), kj::fwd<TransformFunc>(functor));
}
// -------------------------------------------------------------------
// notLookingAt()
// Fails if the given parser succeeds at the current location.
template <typename SubParser>
class NotLookingAt_ {
public:
explicit constexpr NotLookingAt_(SubParser&& subParser)
: subParser(kj::fwd<SubParser>(subParser)) {}
template <typename Input>
Maybe<Tuple<>> operator()(Input& input) const {
Input subInput(input);
subInput.forgetParent();
if (subParser(subInput) == nullptr) {
return Tuple<>();
} else {
return nullptr;
}
}
private:
SubParser subParser;
};
template <typename SubParser>
constexpr NotLookingAt_<SubParser> notLookingAt(SubParser&& subParser) {
// Constructs a parser which fails at any position where the given parser succeeds. Otherwise,
// it succeeds without consuming any input and returns an empty tuple.
return NotLookingAt_<SubParser>(kj::fwd<SubParser>(subParser));
}
// -------------------------------------------------------------------
// endOfInput()
// Output = Tuple<>, only succeeds if at end-of-input
class EndOfInput_ {
public:
template <typename Input>
Maybe<Tuple<>> operator()(Input& input) const {
if (input.atEnd()) {
return Tuple<>();
} else {
return nullptr;
}
}
};
constexpr EndOfInput_ endOfInput = EndOfInput_();
// A parser that succeeds only if it is called with no input.
} // namespace parse
} // namespace kj
#endif // KJ_PARSE_COMMON_H_

View File

@ -1,107 +0,0 @@
// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include "memory.h"
#ifndef KJ_REFCOUNT_H_
#define KJ_REFCOUNT_H_
#if defined(__GNUC__) && !KJ_HEADER_WARNINGS
#pragma GCC system_header
#endif
namespace kj {
class Refcounted: private Disposer {
// Subclass this to create a class that contains a reference count. Then, use
// `kj::refcounted<T>()` to allocate a new refcounted pointer.
//
// Do NOT use this lightly. Refcounting is a crutch. Good designs should strive to make object
// ownership clear, so that refcounting is not necessary. All that said, reference counting can
// sometimes simplify code that would otherwise become convoluted with explicit ownership, even
// when ownership relationships are clear at an abstract level.
//
// NOT THREADSAFE: This refcounting implementation assumes that an object's references are
// manipulated only in one thread, because atomic (thread-safe) refcounting is surprisingly slow.
//
// In general, abstract classes should _not_ subclass this. The concrete class at the bottom
// of the hierarchy should be the one to decide how it implements refcounting. Interfaces should
// expose only an `addRef()` method that returns `Own<InterfaceType>`. There are two reasons for
// this rule:
// 1. Interfaces would need to virtually inherit Refcounted, otherwise two refcounted interfaces
// could not be inherited by the same subclass. Virtual inheritance is awkward and
// inefficient.
// 2. An implementation may decide that it would rather return a copy than a refcount, or use
// some other strategy.
//
// TODO(cleanup): Rethink above. Virtual inheritance is not necessarily that bad. OTOH, a
// virtual function call for every refcount is sad in its own way. A Ref<T> type to replace
// Own<T> could also be nice.
public:
virtual ~Refcounted() noexcept(false);
inline bool isShared() const { return refcount > 1; }
// Check if there are multiple references to this object. This is sometimes useful for deciding
// whether it's safe to modify the object vs. make a copy.
private:
mutable uint refcount = 0;
// "mutable" because disposeImpl() is const. Bleh.
void disposeImpl(void* pointer) const override;
template <typename T>
static Own<T> addRefInternal(T* object);
template <typename T>
friend Own<T> addRef(T& object);
template <typename T, typename... Params>
friend Own<T> refcounted(Params&&... params);
};
template <typename T, typename... Params>
inline Own<T> refcounted(Params&&... params) {
// Allocate a new refcounted instance of T, passing `params` to its constructor. Returns an
// initial reference to the object. More references can be created with `kj::addRef()`.
return Refcounted::addRefInternal(new T(kj::fwd<Params>(params)...));
}
template <typename T>
Own<T> addRef(T& object) {
// Return a new reference to `object`, which must subclass Refcounted and have been allocated
// using `kj::refcounted<>()`. It is suggested that subclasses implement a non-static addRef()
// method which wraps this and returns the appropriate type.
KJ_IREQUIRE(object.Refcounted::refcount > 0, "Object not allocated with kj::refcounted().");
return Refcounted::addRefInternal(&object);
}
template <typename T>
Own<T> Refcounted::addRefInternal(T* object) {
Refcounted* refcounted = object;
++refcounted->refcount;
return Own<T>(object, *refcounted);
}
} // namespace kj
#endif // KJ_REFCOUNT_H_

View File

@ -1,88 +0,0 @@
// Copyright (c) 2014 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
/*
* Compatibility layer for stdlib iostream
*/
#ifndef KJ_STD_IOSTREAM_H_
#define KJ_STD_IOSTREAM_H_
#if defined(__GNUC__) && !KJ_HEADER_WARNINGS
#pragma GCC system_header
#endif
#include "../io.h"
#include <iostream>
namespace kj {
namespace std {
class StdOutputStream: public kj::OutputStream {
public:
explicit StdOutputStream(::std::ostream& stream) : stream_(stream) {}
~StdOutputStream() noexcept(false) {}
virtual void write(const void* src, size_t size) override {
// Always writes the full size.
stream_.write((char*)src, size);
}
virtual void write(ArrayPtr<const ArrayPtr<const byte>> pieces) override {
// Equivalent to write()ing each byte array in sequence, which is what the
// default implementation does. Override if you can do something better,
// e.g. use writev() to do the write in a single syscall.
for (auto piece : pieces) {
write(piece.begin(), piece.size());
}
}
private:
::std::ostream& stream_;
};
class StdInputStream: public kj::InputStream {
public:
explicit StdInputStream(::std::istream& stream) : stream_(stream) {}
~StdInputStream() noexcept(false) {}
virtual size_t tryRead(
void* buffer, size_t minBytes, size_t maxBytes) override {
// Like read(), but may return fewer than minBytes on EOF.
stream_.read((char*)buffer, maxBytes);
return stream_.gcount();
}
private:
::std::istream& stream_;
};
} // namespace std
} // namespace kj
#endif // KJ_STD_IOSTREAM_H_

View File

@ -1,212 +0,0 @@
// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#ifndef KJ_STRING_TREE_H_
#define KJ_STRING_TREE_H_
#if defined(__GNUC__) && !KJ_HEADER_WARNINGS
#pragma GCC system_header
#endif
#include "string.h"
namespace kj {
class StringTree {
// A long string, represented internally as a tree of strings. This data structure is like a
// String, but optimized for concatenation and iteration at the expense of seek time. The
// structure is intended to be used for building large text blobs from many small pieces, where
// repeatedly concatenating smaller strings into larger ones would waste copies. This structure
// is NOT intended for use cases requiring random access or computing substrings. For those,
// you should use a Rope, which is a much more complicated data structure.
//
// The proper way to construct a StringTree is via kj::strTree(...), which works just like
// kj::str(...) but returns a StringTree rather than a String.
//
// KJ_STRINGIFY() functions that construct large strings from many smaller strings are encouraged
// to return StringTree rather than a flat char container.
public:
inline StringTree(): size_(0) {}
inline StringTree(String&& text): size_(text.size()), text(kj::mv(text)) {}
StringTree(Array<StringTree>&& pieces, StringPtr delim);
// Build a StringTree by concatenating the given pieces, delimited by the given delimiter
// (e.g. ", ").
inline size_t size() const { return size_; }
template <typename Func>
void visit(Func&& func) const;
String flatten() const;
// Return the contents as a string.
// TODO(someday): flatten() when *this is an rvalue and when branches.size() == 0 could simply
// return `kj::mv(text)`. Requires reference qualifiers (Clang 3.3 / GCC 4.8).
void flattenTo(char* __restrict__ target) const;
// Copy the contents to the given character array. Does not add a NUL terminator.
private:
size_t size_;
String text;
struct Branch;
Array<Branch> branches; // In order.
inline void fill(char* pos, size_t branchIndex);
template <typename First, typename... Rest>
void fill(char* pos, size_t branchIndex, First&& first, Rest&&... rest);
template <typename... Rest>
void fill(char* pos, size_t branchIndex, StringTree&& first, Rest&&... rest);
template <typename... Rest>
void fill(char* pos, size_t branchIndex, Array<char>&& first, Rest&&... rest);
template <typename... Rest>
void fill(char* pos, size_t branchIndex, String&& first, Rest&&... rest);
template <typename... Params>
static StringTree concat(Params&&... params);
static StringTree&& concat(StringTree&& param) { return kj::mv(param); }
template <typename T>
static inline size_t flatSize(const T& t) { return t.size(); }
static inline size_t flatSize(String&& s) { return 0; }
static inline size_t flatSize(StringTree&& s) { return 0; }
template <typename T>
static inline size_t branchCount(const T& t) { return 0; }
static inline size_t branchCount(String&& s) { return 1; }
static inline size_t branchCount(StringTree&& s) { return 1; }
template <typename... Params>
friend StringTree strTree(Params&&... params);
};
inline StringTree&& KJ_STRINGIFY(StringTree&& tree) { return kj::mv(tree); }
inline const StringTree& KJ_STRINGIFY(const StringTree& tree) { return tree; }
inline StringTree KJ_STRINGIFY(Array<StringTree>&& trees) { return StringTree(kj::mv(trees), ""); }
template <typename... Params>
StringTree strTree(Params&&... params);
// Build a StringTree by stringifying the given parameters and concatenating the results.
// If any of the parameters stringify to StringTree rvalues, they will be incorporated as
// branches to avoid a copy.
// =======================================================================================
// Inline implementation details
namespace _ { // private
template <typename... Rest>
char* fill(char* __restrict__ target, const StringTree& first, Rest&&... rest) {
// Make str() work with stringifiers that return StringTree by patching fill().
first.flattenTo(target);
return fill(target + first.size(), kj::fwd<Rest>(rest)...);
}
template <typename T> constexpr bool isStringTree() { return false; }
template <> constexpr bool isStringTree<StringTree>() { return true; }
inline StringTree&& toStringTreeOrCharSequence(StringTree&& tree) { return kj::mv(tree); }
inline StringTree toStringTreeOrCharSequence(String&& str) { return StringTree(kj::mv(str)); }
template <typename T>
inline auto toStringTreeOrCharSequence(T&& value)
-> decltype(toCharSequence(kj::fwd<T>(value))) {
static_assert(!isStringTree<Decay<T>>(),
"When passing a StringTree into kj::strTree(), either pass it by rvalue "
"(use kj::mv(value)) or explicitly call value.flatten() to make a copy.");
return toCharSequence(kj::fwd<T>(value));
}
} // namespace _ (private)
struct StringTree::Branch {
size_t index;
// Index in `text` where this branch should be inserted.
StringTree content;
};
template <typename Func>
void StringTree::visit(Func&& func) const {
size_t pos = 0;
for (auto& branch: branches) {
if (branch.index > pos) {
func(text.slice(pos, branch.index));
pos = branch.index;
}
branch.content.visit(func);
}
if (text.size() > pos) {
func(text.slice(pos, text.size()));
}
}
inline void StringTree::fill(char* pos, size_t branchIndex) {
KJ_IREQUIRE(pos == text.end() && branchIndex == branches.size(),
kj::str(text.end() - pos, ' ', branches.size() - branchIndex).cStr());
}
template <typename First, typename... Rest>
void StringTree::fill(char* pos, size_t branchIndex, First&& first, Rest&&... rest) {
pos = _::fill(pos, kj::fwd<First>(first));
fill(pos, branchIndex, kj::fwd<Rest>(rest)...);
}
template <typename... Rest>
void StringTree::fill(char* pos, size_t branchIndex, StringTree&& first, Rest&&... rest) {
branches[branchIndex].index = pos - text.begin();
branches[branchIndex].content = kj::mv(first);
fill(pos, branchIndex + 1, kj::fwd<Rest>(rest)...);
}
template <typename... Rest>
void StringTree::fill(char* pos, size_t branchIndex, String&& first, Rest&&... rest) {
branches[branchIndex].index = pos - text.begin();
branches[branchIndex].content = StringTree(kj::mv(first));
fill(pos, branchIndex + 1, kj::fwd<Rest>(rest)...);
}
template <typename... Params>
StringTree StringTree::concat(Params&&... params) {
StringTree result;
result.size_ = _::sum({params.size()...});
result.text = heapString(
_::sum({StringTree::flatSize(kj::fwd<Params>(params))...}));
result.branches = heapArray<StringTree::Branch>(
_::sum({StringTree::branchCount(kj::fwd<Params>(params))...}));
result.fill(result.text.begin(), 0, kj::fwd<Params>(params)...);
return result;
}
template <typename... Params>
StringTree strTree(Params&&... params) {
return StringTree::concat(_::toStringTreeOrCharSequence(kj::fwd<Params>(params))...);
}
} // namespace kj
#endif // KJ_STRING_TREE_H_

View File

@ -1,534 +0,0 @@
// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#ifndef KJ_STRING_H_
#define KJ_STRING_H_
#if defined(__GNUC__) && !KJ_HEADER_WARNINGS
#pragma GCC system_header
#endif
#include <initializer_list>
#include "array.h"
#include <string.h>
namespace kj {
class StringPtr;
class String;
class StringTree; // string-tree.h
// Our STL string SFINAE trick does not work with GCC 4.7, but it works with Clang and GCC 4.8, so
// we'll just preprocess it out if not supported.
#if __clang__ || __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8) || _MSC_VER
#define KJ_COMPILER_SUPPORTS_STL_STRING_INTEROP 1
#endif
// =======================================================================================
// StringPtr -- A NUL-terminated ArrayPtr<const char> containing UTF-8 text.
//
// NUL bytes are allowed to appear before the end of the string. The only requirement is that
// a NUL byte appear immediately after the last byte of the content. This terminator byte is not
// counted in the string's size.
class StringPtr {
public:
inline StringPtr(): content("", 1) {}
inline StringPtr(decltype(nullptr)): content("", 1) {}
inline StringPtr(const char* value): content(value, strlen(value) + 1) {}
inline StringPtr(const char* value, size_t size): content(value, size + 1) {
KJ_IREQUIRE(value[size] == '\0', "StringPtr must be NUL-terminated.");
}
inline StringPtr(const char* begin, const char* end): StringPtr(begin, end - begin) {}
inline StringPtr(const String& value);
#if KJ_COMPILER_SUPPORTS_STL_STRING_INTEROP
template <typename T, typename = decltype(instance<T>().c_str())>
inline StringPtr(const T& t): StringPtr(t.c_str()) {}
// Allow implicit conversion from any class that has a c_str() method (namely, std::string).
// We use a template trick to detect std::string in order to avoid including the header for
// those who don't want it.
template <typename T, typename = decltype(instance<T>().c_str())>
inline operator T() const { return cStr(); }
// Allow implicit conversion to any class that has a c_str() method (namely, std::string).
// We use a template trick to detect std::string in order to avoid including the header for
// those who don't want it.
#endif
inline operator ArrayPtr<const char>() const;
inline ArrayPtr<const char> asArray() const;
inline ArrayPtr<const byte> asBytes() const { return asArray().asBytes(); }
// Result does not include NUL terminator.
inline const char* cStr() const { return content.begin(); }
// Returns NUL-terminated string.
inline size_t size() const { return content.size() - 1; }
// Result does not include NUL terminator.
inline char operator[](size_t index) const { return content[index]; }
inline const char* begin() const { return content.begin(); }
inline const char* end() const { return content.end() - 1; }
inline bool operator==(decltype(nullptr)) const { return content.size() <= 1; }
inline bool operator!=(decltype(nullptr)) const { return content.size() > 1; }
inline bool operator==(const StringPtr& other) const;
inline bool operator!=(const StringPtr& other) const { return !(*this == other); }
inline bool operator< (const StringPtr& other) const;
inline bool operator> (const StringPtr& other) const { return other < *this; }
inline bool operator<=(const StringPtr& other) const { return !(other < *this); }
inline bool operator>=(const StringPtr& other) const { return !(*this < other); }
inline StringPtr slice(size_t start) const;
inline ArrayPtr<const char> slice(size_t start, size_t end) const;
// A string slice is only NUL-terminated if it is a suffix, so slice() has a one-parameter
// version that assumes end = size().
inline bool startsWith(const StringPtr& other) const;
inline bool endsWith(const StringPtr& other) const;
inline Maybe<size_t> findFirst(char c) const;
inline Maybe<size_t> findLast(char c) const;
template <typename T>
T parseAs() const;
// Parse string as template number type.
// Integer numbers prefixed by "0x" and "0X" are parsed in base 16 (like strtoi with base 0).
// Integer numbers prefixed by "0" are parsed in base 10 (unlike strtoi with base 0).
// Overflowed integer numbers throw exception.
// Overflowed floating numbers return inf.
private:
inline StringPtr(ArrayPtr<const char> content): content(content) {}
ArrayPtr<const char> content;
};
inline bool operator==(const char* a, const StringPtr& b) { return b == a; }
inline bool operator!=(const char* a, const StringPtr& b) { return b != a; }
template <> char StringPtr::parseAs<char>() const;
template <> signed char StringPtr::parseAs<signed char>() const;
template <> unsigned char StringPtr::parseAs<unsigned char>() const;
template <> short StringPtr::parseAs<short>() const;
template <> unsigned short StringPtr::parseAs<unsigned short>() const;
template <> int StringPtr::parseAs<int>() const;
template <> unsigned StringPtr::parseAs<unsigned>() const;
template <> long StringPtr::parseAs<long>() const;
template <> unsigned long StringPtr::parseAs<unsigned long>() const;
template <> long long StringPtr::parseAs<long long>() const;
template <> unsigned long long StringPtr::parseAs<unsigned long long>() const;
template <> float StringPtr::parseAs<float>() const;
template <> double StringPtr::parseAs<double>() const;
// =======================================================================================
// String -- A NUL-terminated Array<char> containing UTF-8 text.
//
// NUL bytes are allowed to appear before the end of the string. The only requirement is that
// a NUL byte appear immediately after the last byte of the content. This terminator byte is not
// counted in the string's size.
//
// To allocate a String, you must call kj::heapString(). We do not implement implicit copying to
// the heap because this hides potential inefficiency from the developer.
class String {
public:
String() = default;
inline String(decltype(nullptr)): content(nullptr) {}
inline String(char* value, size_t size, const ArrayDisposer& disposer);
// Does not copy. `size` does not include NUL terminator, but `value` must be NUL-terminated.
inline explicit String(Array<char> buffer);
// Does not copy. Requires `buffer` ends with `\0`.
inline operator ArrayPtr<char>();
inline operator ArrayPtr<const char>() const;
inline ArrayPtr<char> asArray();
inline ArrayPtr<const char> asArray() const;
inline ArrayPtr<byte> asBytes() { return asArray().asBytes(); }
inline ArrayPtr<const byte> asBytes() const { return asArray().asBytes(); }
// Result does not include NUL terminator.
inline Array<char> releaseArray() { return kj::mv(content); }
// Disowns the backing array (which includes the NUL terminator) and returns it. The String value
// is clobbered (as if moved away).
inline const char* cStr() const;
inline size_t size() const;
// Result does not include NUL terminator.
inline char operator[](size_t index) const;
inline char& operator[](size_t index);
inline char* begin();
inline char* end();
inline const char* begin() const;
inline const char* end() const;
inline bool operator==(decltype(nullptr)) const { return content.size() <= 1; }
inline bool operator!=(decltype(nullptr)) const { return content.size() > 1; }
inline bool operator==(const StringPtr& other) const { return StringPtr(*this) == other; }
inline bool operator!=(const StringPtr& other) const { return StringPtr(*this) != other; }
inline bool operator< (const StringPtr& other) const { return StringPtr(*this) < other; }
inline bool operator> (const StringPtr& other) const { return StringPtr(*this) > other; }
inline bool operator<=(const StringPtr& other) const { return StringPtr(*this) <= other; }
inline bool operator>=(const StringPtr& other) const { return StringPtr(*this) >= other; }
inline bool startsWith(const StringPtr& other) const { return StringPtr(*this).startsWith(other);}
inline bool endsWith(const StringPtr& other) const { return StringPtr(*this).endsWith(other); }
inline StringPtr slice(size_t start) const { return StringPtr(*this).slice(start); }
inline ArrayPtr<const char> slice(size_t start, size_t end) const {
return StringPtr(*this).slice(start, end);
}
inline Maybe<size_t> findFirst(char c) const { return StringPtr(*this).findFirst(c); }
inline Maybe<size_t> findLast(char c) const { return StringPtr(*this).findLast(c); }
template <typename T>
T parseAs() const { return StringPtr(*this).parseAs<T>(); }
// Parse as number
private:
Array<char> content;
};
inline bool operator==(const char* a, const String& b) { return b == a; }
inline bool operator!=(const char* a, const String& b) { return b != a; }
String heapString(size_t size);
// Allocate a String of the given size on the heap, not including NUL terminator. The NUL
// terminator will be initialized automatically but the rest of the content is not initialized.
String heapString(const char* value);
String heapString(const char* value, size_t size);
String heapString(StringPtr value);
String heapString(const String& value);
String heapString(ArrayPtr<const char> value);
// Allocates a copy of the given value on the heap.
// =======================================================================================
// Magic str() function which transforms parameters to text and concatenates them into one big
// String.
namespace _ { // private
inline size_t sum(std::initializer_list<size_t> nums) {
size_t result = 0;
for (auto num: nums) {
result += num;
}
return result;
}
inline char* fill(char* ptr) { return ptr; }
template <typename... Rest>
char* fill(char* __restrict__ target, const StringTree& first, Rest&&... rest);
// Make str() work with stringifiers that return StringTree by patching fill().
//
// Defined in string-tree.h.
template <typename First, typename... Rest>
char* fill(char* __restrict__ target, const First& first, Rest&&... rest) {
auto i = first.begin();
auto end = first.end();
while (i != end) {
*target++ = *i++;
}
return fill(target, kj::fwd<Rest>(rest)...);
}
template <typename... Params>
String concat(Params&&... params) {
// Concatenate a bunch of containers into a single Array. The containers can be anything that
// is iterable and whose elements can be converted to `char`.
String result = heapString(sum({params.size()...}));
fill(result.begin(), kj::fwd<Params>(params)...);
return result;
}
inline String concat(String&& arr) {
return kj::mv(arr);
}
struct Stringifier {
// This is a dummy type with only one instance: STR (below). To make an arbitrary type
// stringifiable, define `operator*(Stringifier, T)` to return an iterable container of `char`.
// The container type must have a `size()` method. Be sure to declare the operator in the same
// namespace as `T` **or** in the global scope.
//
// A more usual way to accomplish what we're doing here would be to require that you define
// a function like `toString(T)` and then rely on argument-dependent lookup. However, this has
// the problem that it pollutes other people's namespaces and even the global namespace. For
// example, some other project may already have functions called `toString` which do something
// different. Declaring `operator*` with `Stringifier` as the left operand cannot conflict with
// anything.
inline ArrayPtr<const char> operator*(ArrayPtr<const char> s) const { return s; }
inline ArrayPtr<const char> operator*(ArrayPtr<char> s) const { return s; }
inline ArrayPtr<const char> operator*(const Array<const char>& s) const { return s; }
inline ArrayPtr<const char> operator*(const Array<char>& s) const { return s; }
template<size_t n>
inline ArrayPtr<const char> operator*(const CappedArray<char, n>& s) const { return s; }
template<size_t n>
inline ArrayPtr<const char> operator*(const FixedArray<char, n>& s) const { return s; }
inline ArrayPtr<const char> operator*(const char* s) const { return arrayPtr(s, strlen(s)); }
inline ArrayPtr<const char> operator*(const String& s) const { return s.asArray(); }
inline ArrayPtr<const char> operator*(const StringPtr& s) const { return s.asArray(); }
inline Range<char> operator*(const Range<char>& r) const { return r; }
inline Repeat<char> operator*(const Repeat<char>& r) const { return r; }
inline FixedArray<char, 1> operator*(char c) const {
FixedArray<char, 1> result;
result[0] = c;
return result;
}
StringPtr operator*(decltype(nullptr)) const;
StringPtr operator*(bool b) const;
CappedArray<char, 5> operator*(signed char i) const;
CappedArray<char, 5> operator*(unsigned char i) const;
CappedArray<char, sizeof(short) * 3 + 2> operator*(short i) const;
CappedArray<char, sizeof(unsigned short) * 3 + 2> operator*(unsigned short i) const;
CappedArray<char, sizeof(int) * 3 + 2> operator*(int i) const;
CappedArray<char, sizeof(unsigned int) * 3 + 2> operator*(unsigned int i) const;
CappedArray<char, sizeof(long) * 3 + 2> operator*(long i) const;
CappedArray<char, sizeof(unsigned long) * 3 + 2> operator*(unsigned long i) const;
CappedArray<char, sizeof(long long) * 3 + 2> operator*(long long i) const;
CappedArray<char, sizeof(unsigned long long) * 3 + 2> operator*(unsigned long long i) const;
CappedArray<char, 24> operator*(float f) const;
CappedArray<char, 32> operator*(double f) const;
CappedArray<char, sizeof(const void*) * 3 + 2> operator*(const void* s) const;
template <typename T>
String operator*(ArrayPtr<T> arr) const;
template <typename T>
String operator*(const Array<T>& arr) const;
#if KJ_COMPILER_SUPPORTS_STL_STRING_INTEROP // supports expression SFINAE?
template <typename T, typename Result = decltype(instance<T>().toString())>
inline Result operator*(T&& value) const { return kj::fwd<T>(value).toString(); }
#endif
};
static KJ_CONSTEXPR(const) Stringifier STR = Stringifier();
} // namespace _ (private)
template <typename T>
auto toCharSequence(T&& value) -> decltype(_::STR * kj::fwd<T>(value)) {
// Returns an iterable of chars that represent a textual representation of the value, suitable
// for debugging.
//
// Most users should use str() instead, but toCharSequence() may occasionally be useful to avoid
// heap allocation overhead that str() implies.
//
// To specialize this function for your type, see KJ_STRINGIFY.
return _::STR * kj::fwd<T>(value);
}
CappedArray<char, sizeof(unsigned char) * 2 + 1> hex(unsigned char i);
CappedArray<char, sizeof(unsigned short) * 2 + 1> hex(unsigned short i);
CappedArray<char, sizeof(unsigned int) * 2 + 1> hex(unsigned int i);
CappedArray<char, sizeof(unsigned long) * 2 + 1> hex(unsigned long i);
CappedArray<char, sizeof(unsigned long long) * 2 + 1> hex(unsigned long long i);
template <typename... Params>
String str(Params&&... params) {
// Magic function which builds a string from a bunch of arbitrary values. Example:
// str(1, " / ", 2, " = ", 0.5)
// returns:
// "1 / 2 = 0.5"
// To teach `str` how to stringify a type, see `Stringifier`.
return _::concat(toCharSequence(kj::fwd<Params>(params))...);
}
inline String str(String&& s) { return mv(s); }
// Overload to prevent redundant allocation.
template <typename T>
String strArray(T&& arr, const char* delim) {
size_t delimLen = strlen(delim);
KJ_STACK_ARRAY(decltype(_::STR * arr[0]), pieces, kj::size(arr), 8, 32);
size_t size = 0;
for (size_t i = 0; i < kj::size(arr); i++) {
if (i > 0) size += delimLen;
pieces[i] = _::STR * arr[i];
size += pieces[i].size();
}
String result = heapString(size);
char* pos = result.begin();
for (size_t i = 0; i < kj::size(arr); i++) {
if (i > 0) {
memcpy(pos, delim, delimLen);
pos += delimLen;
}
pos = _::fill(pos, pieces[i]);
}
return result;
}
namespace _ { // private
template <typename T>
inline String Stringifier::operator*(ArrayPtr<T> arr) const {
return strArray(arr, ", ");
}
template <typename T>
inline String Stringifier::operator*(const Array<T>& arr) const {
return strArray(arr, ", ");
}
} // namespace _ (private)
#define KJ_STRINGIFY(...) operator*(::kj::_::Stringifier, __VA_ARGS__)
// Defines a stringifier for a custom type. Example:
//
// class Foo {...};
// inline StringPtr KJ_STRINGIFY(const Foo& foo) { return foo.name(); }
//
// This allows Foo to be passed to str().
//
// The function should be declared either in the same namespace as the target type or in the global
// namespace. It can return any type which is an iterable container of chars.
// =======================================================================================
// Inline implementation details.
inline StringPtr::StringPtr(const String& value): content(value.begin(), value.size() + 1) {}
inline StringPtr::operator ArrayPtr<const char>() const {
return content.slice(0, content.size() - 1);
}
inline ArrayPtr<const char> StringPtr::asArray() const {
return content.slice(0, content.size() - 1);
}
inline bool StringPtr::operator==(const StringPtr& other) const {
return content.size() == other.content.size() &&
memcmp(content.begin(), other.content.begin(), content.size() - 1) == 0;
}
inline bool StringPtr::operator<(const StringPtr& other) const {
bool shorter = content.size() < other.content.size();
int cmp = memcmp(content.begin(), other.content.begin(),
shorter ? content.size() : other.content.size());
return cmp < 0 || (cmp == 0 && shorter);
}
inline StringPtr StringPtr::slice(size_t start) const {
return StringPtr(content.slice(start, content.size()));
}
inline ArrayPtr<const char> StringPtr::slice(size_t start, size_t end) const {
return content.slice(start, end);
}
inline bool StringPtr::startsWith(const StringPtr& other) const {
return other.content.size() <= content.size() &&
memcmp(content.begin(), other.content.begin(), other.size()) == 0;
}
inline bool StringPtr::endsWith(const StringPtr& other) const {
return other.content.size() <= content.size() &&
memcmp(end() - other.size(), other.content.begin(), other.size()) == 0;
}
inline Maybe<size_t> StringPtr::findFirst(char c) const {
const char* pos = reinterpret_cast<const char*>(memchr(content.begin(), c, size()));
if (pos == nullptr) {
return nullptr;
} else {
return pos - content.begin();
}
}
inline Maybe<size_t> StringPtr::findLast(char c) const {
for (size_t i = size(); i > 0; --i) {
if (content[i-1] == c) {
return i-1;
}
}
return nullptr;
}
inline String::operator ArrayPtr<char>() {
return content == nullptr ? ArrayPtr<char>(nullptr) : content.slice(0, content.size() - 1);
}
inline String::operator ArrayPtr<const char>() const {
return content == nullptr ? ArrayPtr<const char>(nullptr) : content.slice(0, content.size() - 1);
}
inline ArrayPtr<char> String::asArray() {
return content == nullptr ? ArrayPtr<char>(nullptr) : content.slice(0, content.size() - 1);
}
inline ArrayPtr<const char> String::asArray() const {
return content == nullptr ? ArrayPtr<const char>(nullptr) : content.slice(0, content.size() - 1);
}
inline const char* String::cStr() const { return content == nullptr ? "" : content.begin(); }
inline size_t String::size() const { return content == nullptr ? 0 : content.size() - 1; }
inline char String::operator[](size_t index) const { return content[index]; }
inline char& String::operator[](size_t index) { return content[index]; }
inline char* String::begin() { return content == nullptr ? nullptr : content.begin(); }
inline char* String::end() { return content == nullptr ? nullptr : content.end() - 1; }
inline const char* String::begin() const { return content == nullptr ? nullptr : content.begin(); }
inline const char* String::end() const { return content == nullptr ? nullptr : content.end() - 1; }
inline String::String(char* value, size_t size, const ArrayDisposer& disposer)
: content(value, size + 1, disposer) {
KJ_IREQUIRE(value[size] == '\0', "String must be NUL-terminated.");
}
inline String::String(Array<char> buffer): content(kj::mv(buffer)) {
KJ_IREQUIRE(content.size() > 0 && content.back() == '\0', "String must be NUL-terminated.");
}
inline String heapString(const char* value) {
return heapString(value, strlen(value));
}
inline String heapString(StringPtr value) {
return heapString(value.begin(), value.size());
}
inline String heapString(const String& value) {
return heapString(value.begin(), value.size());
}
inline String heapString(ArrayPtr<const char> value) {
return heapString(value.begin(), value.size());
}
} // namespace kj
#endif // KJ_STRING_H_

View File

@ -1,167 +0,0 @@
// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#ifndef KJ_TEST_H_
#define KJ_TEST_H_
#if defined(__GNUC__) && !KJ_HEADER_WARNINGS
#pragma GCC system_header
#endif
#include "debug.h"
#include "vector.h"
#include "function.h"
namespace kj {
class TestRunner;
class TestCase {
public:
TestCase(const char* file, uint line, const char* description);
~TestCase();
virtual void run() = 0;
private:
const char* file;
uint line;
const char* description;
TestCase* next;
TestCase** prev;
bool matchedFilter;
friend class TestRunner;
};
#define KJ_TEST(description) \
/* Make sure the linker fails if tests are not in anonymous namespaces. */ \
extern int KJ_CONCAT(YouMustWrapTestsInAnonymousNamespace, __COUNTER__) KJ_UNUSED; \
class KJ_UNIQUE_NAME(TestCase): public ::kj::TestCase { \
public: \
KJ_UNIQUE_NAME(TestCase)(): ::kj::TestCase(__FILE__, __LINE__, description) {} \
void run() override; \
} KJ_UNIQUE_NAME(testCase); \
void KJ_UNIQUE_NAME(TestCase)::run()
#if _MSC_VER
#define KJ_INDIRECT_EXPAND(m, vargs) m vargs
#define KJ_FAIL_EXPECT(...) \
KJ_INDIRECT_EXPAND(KJ_LOG, (ERROR , __VA_ARGS__));
#define KJ_EXPECT(cond, ...) \
if (cond); else KJ_INDIRECT_EXPAND(KJ_FAIL_EXPECT, ("failed: expected " #cond , __VA_ARGS__))
#else
#define KJ_FAIL_EXPECT(...) \
KJ_LOG(ERROR, ##__VA_ARGS__);
#define KJ_EXPECT(cond, ...) \
if (cond); else KJ_FAIL_EXPECT("failed: expected " #cond, ##__VA_ARGS__)
#endif
#define KJ_EXPECT_THROW_RECOVERABLE(type, code) \
do { \
KJ_IF_MAYBE(e, ::kj::runCatchingExceptions([&]() { code; })) { \
KJ_EXPECT(e->getType() == ::kj::Exception::Type::type, \
"code threw wrong exception type: " #code, e->getType()); \
} else { \
KJ_FAIL_EXPECT("code did not throw: " #code); \
} \
} while (false)
#define KJ_EXPECT_THROW_RECOVERABLE_MESSAGE(message, code) \
do { \
KJ_IF_MAYBE(e, ::kj::runCatchingExceptions([&]() { code; })) { \
KJ_EXPECT(::kj::_::hasSubstring(e->getDescription(), message), \
"exception description didn't contain expected substring", e->getDescription()); \
} else { \
KJ_FAIL_EXPECT("code did not throw: " #code); \
} \
} while (false)
#if KJ_NO_EXCEPTIONS
#define KJ_EXPECT_THROW(type, code) \
do { \
KJ_EXPECT(::kj::_::expectFatalThrow(type, nullptr, [&]() { code; })); \
} while (false)
#define KJ_EXPECT_THROW_MESSAGE(message, code) \
do { \
KJ_EXPECT(::kj::_::expectFatalThrow(nullptr, kj::StringPtr(message), [&]() { code; })); \
} while (false)
#else
#define KJ_EXPECT_THROW KJ_EXPECT_THROW_RECOVERABLE
#define KJ_EXPECT_THROW_MESSAGE KJ_EXPECT_THROW_RECOVERABLE_MESSAGE
#endif
#define KJ_EXPECT_LOG(level, substring) \
::kj::_::LogExpectation KJ_UNIQUE_NAME(_kjLogExpectation)(::kj::LogSeverity::level, substring)
// Expects that a log message with the given level and substring text will be printed within
// the current scope. This message will not cause the test to fail, even if it is an error.
// =======================================================================================
namespace _ { // private
bool hasSubstring(kj::StringPtr haystack, kj::StringPtr needle);
#if KJ_NO_EXCEPTIONS
bool expectFatalThrow(Maybe<Exception::Type> type, Maybe<StringPtr> message,
Function<void()> code);
// Expects that the given code will throw a fatal exception matching the given type and/or message.
// Since exceptions are disabled, the test will fork() and run in a subprocess. On Windows, where
// fork() is not available, this always returns true.
#endif
class LogExpectation: public ExceptionCallback {
public:
LogExpectation(LogSeverity severity, StringPtr substring);
~LogExpectation();
void logMessage(LogSeverity severity, const char* file, int line, int contextDepth,
String&& text) override;
private:
LogSeverity severity;
StringPtr substring;
bool seen;
UnwindDetector unwindDetector;
};
class GlobFilter {
// Implements glob filters for the --filter flag.
//
// Exposed in header only for testing.
public:
explicit GlobFilter(const char* pattern);
explicit GlobFilter(ArrayPtr<const char> pattern);
bool matches(StringPtr name);
private:
String pattern;
Vector<uint> states;
void applyState(char c, int state);
};
} // namespace _ (private)
} // namespace kj
#endif // KJ_TEST_H_

View File

@ -1,82 +0,0 @@
// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#ifndef KJ_THREAD_H_
#define KJ_THREAD_H_
#if defined(__GNUC__) && !KJ_HEADER_WARNINGS
#pragma GCC system_header
#endif
#include "common.h"
#include "function.h"
#include "exception.h"
namespace kj {
class Thread {
// A thread! Pass a lambda to the constructor, and it runs in the thread. The destructor joins
// the thread. If the function throws an exception, it is rethrown from the thread's destructor
// (if not unwinding from another exception).
public:
explicit Thread(Function<void()> func);
KJ_DISALLOW_COPY(Thread);
~Thread() noexcept(false);
#if !_WIN32
void sendSignal(int signo);
// Send a Unix signal to the given thread, using pthread_kill or an equivalent.
#endif
void detach();
// Don't join the thread in ~Thread().
private:
struct ThreadState {
Function<void()> func;
kj::Maybe<kj::Exception> exception;
unsigned int refcount;
// Owned by the parent thread and the child thread.
void unref();
};
ThreadState* state;
#if _WIN32
void* threadHandle;
#else
unsigned long long threadId; // actually pthread_t
#endif
bool detached = false;
#if _WIN32
static unsigned long __stdcall runThread(void* ptr);
#else
static void* runThread(void* ptr);
#endif
};
} // namespace kj
#endif // KJ_THREAD_H_

View File

@ -1,136 +0,0 @@
// Copyright (c) 2014, Jason Choy <jjwchoy@gmail.com>
// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#ifndef KJ_THREADLOCAL_H_
#define KJ_THREADLOCAL_H_
#if defined(__GNUC__) && !KJ_HEADER_WARNINGS
#pragma GCC system_header
#endif
// This file declares a macro `KJ_THREADLOCAL_PTR` for declaring thread-local pointer-typed
// variables. Use like:
// KJ_THREADLOCAL_PTR(MyType) foo = nullptr;
// This is equivalent to:
// thread_local MyType* foo = nullptr;
// This can only be used at the global scope.
//
// AVOID USING THIS. Use of thread-locals is discouraged because they often have many of the same
// properties as singletons: http://www.object-oriented-security.org/lets-argue/singletons
//
// Also, thread-locals tend to be hostile to event-driven code, which can be particularly
// surprising when using fibers (all fibers in the same thread will share the same threadlocals,
// even though they do not share a stack).
//
// That said, thread-locals are sometimes needed for runtime logistics in the KJ framework. For
// example, the current exception callback and current EventLoop are stored as thread-local
// pointers. Since KJ only ever needs to store pointers, not values, we avoid the question of
// whether these values' destructors need to be run, and we avoid the need for heap allocation.
#include "common.h"
#if !defined(KJ_USE_PTHREAD_THREADLOCAL) && defined(__APPLE__)
#include "TargetConditionals.h"
#if TARGET_OS_IPHONE
// iOS apparently does not support __thread (nor C++11 thread_local).
#define KJ_USE_PTHREAD_TLS 1
#endif
#endif
#if KJ_USE_PTHREAD_TLS
#include <pthread.h>
#endif
namespace kj {
#if KJ_USE_PTHREAD_TLS
// If __thread is unavailable, we'll fall back to pthreads.
#define KJ_THREADLOCAL_PTR(type) \
namespace { struct KJ_UNIQUE_NAME(_kj_TlpTag); } \
static ::kj::_::ThreadLocalPtr< type, KJ_UNIQUE_NAME(_kj_TlpTag)>
// Hack: In order to ensure each thread-local results in a unique template instance, we declare
// a one-off dummy type to use as the second type parameter.
namespace _ { // private
template <typename T, typename>
class ThreadLocalPtr {
// Hacky type to emulate __thread T*. We need a separate instance of the ThreadLocalPtr template
// for every thread-local variable, because we don't want to require a global constructor, and in
// order to initialize the TLS on first use we need to use a local static variable (in getKey()).
// Each template instance will get a separate such local static variable, fulfilling our need.
public:
ThreadLocalPtr() = default;
constexpr ThreadLocalPtr(decltype(nullptr)) {}
// Allow initialization to nullptr without a global constructor.
inline ThreadLocalPtr& operator=(T* val) {
pthread_setspecific(getKey(), val);
return *this;
}
inline operator T*() const {
return get();
}
inline T& operator*() const {
return *get();
}
inline T* operator->() const {
return get();
}
private:
inline T* get() const {
return reinterpret_cast<T*>(pthread_getspecific(getKey()));
}
inline static pthread_key_t getKey() {
static pthread_key_t key = createKey();
return key;
}
static pthread_key_t createKey() {
pthread_key_t key;
pthread_key_create(&key, 0);
return key;
}
};
} // namespace _ (private)
#elif __GNUC__
#define KJ_THREADLOCAL_PTR(type) static __thread type*
// GCC's __thread is lighter-weight than thread_local and is good enough for our purposes.
#else
#define KJ_THREADLOCAL_PTR(type) static thread_local type*
#endif // KJ_USE_PTHREAD_TLS
} // namespace kj
#endif // KJ_THREADLOCAL_H_

View File

@ -1,174 +0,0 @@
// Copyright (c) 2014 Google Inc. (contributed by Remy Blank <rblank@google.com>)
// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#ifndef KJ_TIME_H_
#define KJ_TIME_H_
#if defined(__GNUC__) && !KJ_HEADER_WARNINGS
#pragma GCC system_header
#endif
#include "async.h"
#include "units.h"
#include <inttypes.h>
namespace kj {
namespace _ { // private
class NanosecondLabel;
class TimeLabel;
class DateLabel;
} // namespace _ (private)
using Duration = Quantity<int64_t, _::NanosecondLabel>;
// A time value, in nanoseconds.
constexpr Duration NANOSECONDS = unit<Duration>();
constexpr Duration MICROSECONDS = 1000 * NANOSECONDS;
constexpr Duration MILLISECONDS = 1000 * MICROSECONDS;
constexpr Duration SECONDS = 1000 * MILLISECONDS;
constexpr Duration MINUTES = 60 * SECONDS;
constexpr Duration HOURS = 60 * MINUTES;
constexpr Duration DAYS = 24 * HOURS;
using TimePoint = Absolute<Duration, _::TimeLabel>;
// An absolute time measured by some particular instance of `Timer`. `Time`s from two different
// `Timer`s may be measured from different origins and so are not necessarily compatible.
using Date = Absolute<Duration, _::DateLabel>;
// A point in real-world time, measured relative to the Unix epoch (Jan 1, 1970 00:00:00 UTC).
constexpr Date UNIX_EPOCH = origin<Date>();
// The `Date` representing Jan 1, 1970 00:00:00 UTC.
class Clock {
// Interface to read the current date and time.
public:
virtual Date now() = 0;
};
Clock& nullClock();
// A clock which always returns UNIX_EPOCH as the current time. Useful when you don't care about
// time.
class Timer {
// Interface to time and timer functionality.
//
// Each `Timer` may have a different origin, and some `Timer`s may in fact tick at a different
// rate than real time (e.g. a `Timer` could represent CPU time consumed by a thread). However,
// all `Timer`s are monotonic: time will never appear to move backwards, even if the calendar
// date as tracked by the system is manually modified.
public:
virtual TimePoint now() = 0;
// Returns the current value of a clock that moves steadily forward, independent of any
// changes in the wall clock. The value is updated every time the event loop waits,
// and is constant in-between waits.
virtual Promise<void> atTime(TimePoint time) = 0;
// Returns a promise that returns as soon as now() >= time.
virtual Promise<void> afterDelay(Duration delay) = 0;
// Equivalent to atTime(now() + delay).
template <typename T>
Promise<T> timeoutAt(TimePoint time, Promise<T>&& promise) KJ_WARN_UNUSED_RESULT;
// Return a promise equivalent to `promise` but which throws an exception (and cancels the
// original promise) if it hasn't completed by `time`. The thrown exception is of type
// "OVERLOADED".
template <typename T>
Promise<T> timeoutAfter(Duration delay, Promise<T>&& promise) KJ_WARN_UNUSED_RESULT;
// Return a promise equivalent to `promise` but which throws an exception (and cancels the
// original promise) if it hasn't completed after `delay` from now. The thrown exception is of
// type "OVERLOADED".
private:
static kj::Exception makeTimeoutException();
};
class TimerImpl final: public Timer {
// Implementation of Timer that expects an external caller -- usually, the EventPort
// implementation -- to tell it when time has advanced.
public:
TimerImpl(TimePoint startTime);
~TimerImpl() noexcept(false);
Maybe<TimePoint> nextEvent();
// Returns the time at which the next scheduled timer event will occur, or null if no timer
// events are scheduled.
Maybe<uint64_t> timeoutToNextEvent(TimePoint start, Duration unit, uint64_t max);
// Convenience method which computes a timeout value to pass to an event-waiting system call to
// cause it to time out when the next timer event occurs.
//
// `start` is the time at which the timeout starts counting. This is typically not the same as
// now() since some time may have passed since the last time advanceTo() was called.
//
// `unit` is the time unit in which the timeout is measured. This is often MILLISECONDS. Note
// that this method will fractional values *up*, to guarantee that the returned timeout waits
// until just *after* the time the event is scheduled.
//
// The timeout will be clamped to `max`. Use this to avoid an overflow if e.g. the OS wants a
// 32-bit value or a signed value.
//
// Returns nullptr if there are no future events.
void advanceTo(TimePoint newTime);
// Set the time to `time` and fire any at() events that have been passed.
// implements Timer ----------------------------------------------------------
TimePoint now() override;
Promise<void> atTime(TimePoint time) override;
Promise<void> afterDelay(Duration delay) override;
private:
struct Impl;
class TimerPromiseAdapter;
TimePoint time;
Own<Impl> impl;
};
// =======================================================================================
// inline implementation details
template <typename T>
Promise<T> Timer::timeoutAt(TimePoint time, Promise<T>&& promise) {
return promise.exclusiveJoin(atTime(time).then([]() -> kj::Promise<T> {
return makeTimeoutException();
}));
}
template <typename T>
Promise<T> Timer::timeoutAfter(Duration delay, Promise<T>&& promise) {
return promise.exclusiveJoin(afterDelay(delay).then([]() -> kj::Promise<T> {
return makeTimeoutException();
}));
}
inline TimePoint TimerImpl::now() { return time; }
} // namespace kj
#endif // KJ_TIME_H_

View File

@ -1,364 +0,0 @@
// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
// This file defines a notion of tuples that is simpler that `std::tuple`. It works as follows:
// - `kj::Tuple<A, B, C> is the type of a tuple of an A, a B, and a C.
// - `kj::tuple(a, b, c)` returns a tuple containing a, b, and c. If any of these are themselves
// tuples, they are flattened, so `tuple(a, tuple(b, c), d)` is equivalent to `tuple(a, b, c, d)`.
// - `kj::get<n>(myTuple)` returns the element of `myTuple` at index n.
// - `kj::apply(func, ...)` calls func on the following arguments after first expanding any tuples
// in the argument list. So `kj::apply(foo, a, tuple(b, c), d)` would call `foo(a, b, c, d)`.
//
// Note that:
// - The type `Tuple<T>` is a synonym for T. This is why `get` and `apply` are not members of the
// type.
// - It is illegal for an element of `Tuple` to itself be a tuple, as tuples are meant to be
// flattened.
// - It is illegal for an element of `Tuple` to be a reference, due to problems this would cause
// with type inference and `tuple()`.
#ifndef KJ_TUPLE_H_
#define KJ_TUPLE_H_
#if defined(__GNUC__) && !KJ_HEADER_WARNINGS
#pragma GCC system_header
#endif
#include "common.h"
namespace kj {
namespace _ { // private
template <size_t index, typename... T>
struct TypeByIndex_;
template <typename First, typename... Rest>
struct TypeByIndex_<0, First, Rest...> {
typedef First Type;
};
template <size_t index, typename First, typename... Rest>
struct TypeByIndex_<index, First, Rest...>
: public TypeByIndex_<index - 1, Rest...> {};
template <size_t index>
struct TypeByIndex_<index> {
static_assert(index != index, "Index out-of-range.");
};
template <size_t index, typename... T>
using TypeByIndex = typename TypeByIndex_<index, T...>::Type;
// Chose a particular type out of a list of types, by index.
template <size_t... s>
struct Indexes {};
// Dummy helper type that just encapsulates a sequential list of indexes, so that we can match
// templates against them and unpack them with '...'.
template <size_t end, size_t... prefix>
struct MakeIndexes_: public MakeIndexes_<end - 1, end - 1, prefix...> {};
template <size_t... prefix>
struct MakeIndexes_<0, prefix...> {
typedef Indexes<prefix...> Type;
};
template <size_t end>
using MakeIndexes = typename MakeIndexes_<end>::Type;
// Equivalent to Indexes<0, 1, 2, ..., end>.
template <typename... T>
class Tuple;
template <size_t index, typename... U>
inline TypeByIndex<index, U...>& getImpl(Tuple<U...>& tuple);
template <size_t index, typename... U>
inline TypeByIndex<index, U...>&& getImpl(Tuple<U...>&& tuple);
template <size_t index, typename... U>
inline const TypeByIndex<index, U...>& getImpl(const Tuple<U...>& tuple);
template <uint index, typename T>
struct TupleElement {
// Encapsulates one element of a tuple. The actual tuple implementation multiply-inherits
// from a TupleElement for each element, which is more efficient than a recursive definition.
T value;
TupleElement() = default;
constexpr inline TupleElement(const T& value): value(value) {}
constexpr inline TupleElement(T&& value): value(kj::mv(value)) {}
};
template <uint index, typename T>
struct TupleElement<index, T&> {
// If tuples contained references, one of the following would have to be true:
// - `auto x = tuple(y, z)` would cause x to be a tuple of references to y and z, which is
// probably not what you expected.
// - `Tuple<Foo&, Bar&> x = tuple(a, b)` would not work, because `tuple()` returned
// Tuple<Foo, Bar>.
static_assert(sizeof(T*) == 0, "Sorry, tuples cannot contain references.");
};
template <uint index, typename... T>
struct TupleElement<index, Tuple<T...>> {
static_assert(sizeof(Tuple<T...>*) == 0,
"Tuples cannot contain other tuples -- they should be flattened.");
};
template <typename Indexes, typename... Types>
struct TupleImpl;
template <size_t... indexes, typename... Types>
struct TupleImpl<Indexes<indexes...>, Types...>
: public TupleElement<indexes, Types>... {
// Implementation of Tuple. The only reason we need this rather than rolling this into class
// Tuple (below) is so that we can get "indexes" as an unpackable list.
static_assert(sizeof...(indexes) == sizeof...(Types), "Incorrect use of TupleImpl.");
template <typename... Params>
inline TupleImpl(Params&&... params)
: TupleElement<indexes, Types>(kj::fwd<Params>(params))... {
// Work around Clang 3.2 bug 16303 where this is not detected. (Unfortunately, Clang sometimes
// segfaults instead.)
static_assert(sizeof...(params) == sizeof...(indexes),
"Wrong number of parameters to Tuple constructor.");
}
template <typename... U>
constexpr inline TupleImpl(Tuple<U...>&& other)
: TupleElement<indexes, Types>(kj::mv(getImpl<indexes>(other)))... {}
template <typename... U>
constexpr inline TupleImpl(Tuple<U...>& other)
: TupleElement<indexes, Types>(getImpl<indexes>(other))... {}
template <typename... U>
constexpr inline TupleImpl(const Tuple<U...>& other)
: TupleElement<indexes, Types>(getImpl<indexes>(other))... {}
};
struct MakeTupleFunc;
template <typename... T>
class Tuple {
// The actual Tuple class (used for tuples of size other than 1).
public:
template <typename... U>
constexpr inline Tuple(Tuple<U...>&& other): impl(kj::mv(other)) {}
template <typename... U>
constexpr inline Tuple(Tuple<U...>& other): impl(other) {}
template <typename... U>
constexpr inline Tuple(const Tuple<U...>& other): impl(other) {}
private:
template <typename... Params>
constexpr Tuple(Params&&... params): impl(kj::fwd<Params>(params)...) {}
TupleImpl<MakeIndexes<sizeof...(T)>, T...> impl;
template <size_t index, typename... U>
friend inline TypeByIndex<index, U...>& getImpl(Tuple<U...>& tuple);
template <size_t index, typename... U>
friend inline TypeByIndex<index, U...>&& getImpl(Tuple<U...>&& tuple);
template <size_t index, typename... U>
friend inline const TypeByIndex<index, U...>& getImpl(const Tuple<U...>& tuple);
friend struct MakeTupleFunc;
};
template <>
class Tuple<> {
// Simplified zero-member version of Tuple. In particular this is important to make sure that
// Tuple<>() is constexpr.
};
template <typename T>
class Tuple<T>;
// Single-element tuple should never be used. The public API should ensure this.
template <size_t index, typename... T>
inline TypeByIndex<index, T...>& getImpl(Tuple<T...>& tuple) {
// Get member of a Tuple by index, e.g. `get<2>(myTuple)`.
static_assert(index < sizeof...(T), "Tuple element index out-of-bounds.");
return implicitCast<TupleElement<index, TypeByIndex<index, T...>>&>(tuple.impl).value;
}
template <size_t index, typename... T>
inline TypeByIndex<index, T...>&& getImpl(Tuple<T...>&& tuple) {
// Get member of a Tuple by index, e.g. `get<2>(myTuple)`.
static_assert(index < sizeof...(T), "Tuple element index out-of-bounds.");
return kj::mv(implicitCast<TupleElement<index, TypeByIndex<index, T...>>&>(tuple.impl).value);
}
template <size_t index, typename... T>
inline const TypeByIndex<index, T...>& getImpl(const Tuple<T...>& tuple) {
// Get member of a Tuple by index, e.g. `get<2>(myTuple)`.
static_assert(index < sizeof...(T), "Tuple element index out-of-bounds.");
return implicitCast<const TupleElement<index, TypeByIndex<index, T...>>&>(tuple.impl).value;
}
template <size_t index, typename T>
inline T&& getImpl(T&& value) {
// Get member of a Tuple by index, e.g. `getImpl<2>(myTuple)`.
// Non-tuples are equivalent to one-element tuples.
static_assert(index == 0, "Tuple element index out-of-bounds.");
return kj::fwd<T>(value);
}
template <typename Func, typename SoFar, typename... T>
struct ExpandAndApplyResult_;
// Template which computes the return type of applying Func to T... after flattening tuples.
// SoFar starts as Tuple<> and accumulates the flattened parameter types -- so after this template
// is recursively expanded, T... is empty and SoFar is a Tuple containing all the parameters.
template <typename Func, typename First, typename... Rest, typename... T>
struct ExpandAndApplyResult_<Func, Tuple<T...>, First, Rest...>
: public ExpandAndApplyResult_<Func, Tuple<T..., First>, Rest...> {};
template <typename Func, typename... FirstTypes, typename... Rest, typename... T>
struct ExpandAndApplyResult_<Func, Tuple<T...>, Tuple<FirstTypes...>, Rest...>
: public ExpandAndApplyResult_<Func, Tuple<T...>, FirstTypes&&..., Rest...> {};
template <typename Func, typename... FirstTypes, typename... Rest, typename... T>
struct ExpandAndApplyResult_<Func, Tuple<T...>, Tuple<FirstTypes...>&, Rest...>
: public ExpandAndApplyResult_<Func, Tuple<T...>, FirstTypes&..., Rest...> {};
template <typename Func, typename... FirstTypes, typename... Rest, typename... T>
struct ExpandAndApplyResult_<Func, Tuple<T...>, const Tuple<FirstTypes...>&, Rest...>
: public ExpandAndApplyResult_<Func, Tuple<T...>, const FirstTypes&..., Rest...> {};
template <typename Func, typename... T>
struct ExpandAndApplyResult_<Func, Tuple<T...>> {
typedef decltype(instance<Func>()(instance<T&&>()...)) Type;
};
template <typename Func, typename... T>
using ExpandAndApplyResult = typename ExpandAndApplyResult_<Func, Tuple<>, T...>::Type;
// Computes the expected return type of `expandAndApply()`.
template <typename Func>
inline auto expandAndApply(Func&& func) -> ExpandAndApplyResult<Func> {
return func();
}
template <typename Func, typename First, typename... Rest>
struct ExpandAndApplyFunc {
Func&& func;
First&& first;
ExpandAndApplyFunc(Func&& func, First&& first)
: func(kj::fwd<Func>(func)), first(kj::fwd<First>(first)) {}
template <typename... T>
auto operator()(T&&... params)
-> decltype(this->func(kj::fwd<First>(first), kj::fwd<T>(params)...)) {
return this->func(kj::fwd<First>(first), kj::fwd<T>(params)...);
}
};
template <typename Func, typename First, typename... Rest>
inline auto expandAndApply(Func&& func, First&& first, Rest&&... rest)
-> ExpandAndApplyResult<Func, First, Rest...> {
return expandAndApply(
ExpandAndApplyFunc<Func, First, Rest...>(kj::fwd<Func>(func), kj::fwd<First>(first)),
kj::fwd<Rest>(rest)...);
}
template <typename Func, typename... FirstTypes, typename... Rest>
inline auto expandAndApply(Func&& func, Tuple<FirstTypes...>&& first, Rest&&... rest)
-> ExpandAndApplyResult<Func, FirstTypes&&..., Rest...> {
return expandAndApplyWithIndexes(MakeIndexes<sizeof...(FirstTypes)>(),
kj::fwd<Func>(func), kj::mv(first), kj::fwd<Rest>(rest)...);
}
template <typename Func, typename... FirstTypes, typename... Rest>
inline auto expandAndApply(Func&& func, Tuple<FirstTypes...>& first, Rest&&... rest)
-> ExpandAndApplyResult<Func, FirstTypes..., Rest...> {
return expandAndApplyWithIndexes(MakeIndexes<sizeof...(FirstTypes)>(),
kj::fwd<Func>(func), first, kj::fwd<Rest>(rest)...);
}
template <typename Func, typename... FirstTypes, typename... Rest>
inline auto expandAndApply(Func&& func, const Tuple<FirstTypes...>& first, Rest&&... rest)
-> ExpandAndApplyResult<Func, FirstTypes..., Rest...> {
return expandAndApplyWithIndexes(MakeIndexes<sizeof...(FirstTypes)>(),
kj::fwd<Func>(func), first, kj::fwd<Rest>(rest)...);
}
template <typename Func, typename... FirstTypes, typename... Rest, size_t... indexes>
inline auto expandAndApplyWithIndexes(
Indexes<indexes...>, Func&& func, Tuple<FirstTypes...>&& first, Rest&&... rest)
-> ExpandAndApplyResult<Func, FirstTypes&&..., Rest...> {
return expandAndApply(kj::fwd<Func>(func), kj::mv(getImpl<indexes>(first))...,
kj::fwd<Rest>(rest)...);
}
template <typename Func, typename... FirstTypes, typename... Rest, size_t... indexes>
inline auto expandAndApplyWithIndexes(
Indexes<indexes...>, Func&& func, const Tuple<FirstTypes...>& first, Rest&&... rest)
-> ExpandAndApplyResult<Func, FirstTypes..., Rest...> {
return expandAndApply(kj::fwd<Func>(func), getImpl<indexes>(first)...,
kj::fwd<Rest>(rest)...);
}
struct MakeTupleFunc {
template <typename... Params>
Tuple<Decay<Params>...> operator()(Params&&... params) {
return Tuple<Decay<Params>...>(kj::fwd<Params>(params)...);
}
template <typename Param>
Decay<Param> operator()(Param&& param) {
return kj::fwd<Param>(param);
}
};
} // namespace _ (private)
template <typename... T> struct Tuple_ { typedef _::Tuple<T...> Type; };
template <typename T> struct Tuple_<T> { typedef T Type; };
template <typename... T> using Tuple = typename Tuple_<T...>::Type;
// Tuple type. `Tuple<T>` (i.e. a single-element tuple) is a synonym for `T`. Tuples of size
// other than 1 expand to an internal type. Either way, you can construct a Tuple using
// `kj::tuple(...)`, get an element by index `i` using `kj::get<i>(myTuple)`, and expand the tuple
// as arguments to a function using `kj::apply(func, myTuple)`.
//
// Tuples are always flat -- that is, no element of a Tuple is ever itself a Tuple. If you
// construct a tuple from other tuples, the elements are flattened and concatenated.
template <typename... Params>
inline auto tuple(Params&&... params)
-> decltype(_::expandAndApply(_::MakeTupleFunc(), kj::fwd<Params>(params)...)) {
// Construct a new tuple from the given values. Any tuples in the argument list will be
// flattened into the result.
return _::expandAndApply(_::MakeTupleFunc(), kj::fwd<Params>(params)...);
}
template <size_t index, typename Tuple>
inline auto get(Tuple&& tuple) -> decltype(_::getImpl<index>(kj::fwd<Tuple>(tuple))) {
// Unpack and return the tuple element at the given index. The index is specified as a template
// parameter, e.g. `kj::get<3>(myTuple)`.
return _::getImpl<index>(kj::fwd<Tuple>(tuple));
}
template <typename Func, typename... Params>
inline auto apply(Func&& func, Params&&... params)
-> decltype(_::expandAndApply(kj::fwd<Func>(func), kj::fwd<Params>(params)...)) {
// Apply a function to some arguments, expanding tuples into separate arguments.
return _::expandAndApply(kj::fwd<Func>(func), kj::fwd<Params>(params)...);
}
template <typename T> struct TupleSize_ { static constexpr size_t size = 1; };
template <typename... T> struct TupleSize_<_::Tuple<T...>> {
static constexpr size_t size = sizeof...(T);
};
template <typename T>
constexpr size_t tupleSize() { return TupleSize_<T>::size; }
// Returns size of the tuple T.
} // namespace kj
#endif // KJ_TUPLE_H_

File diff suppressed because it is too large Load Diff

View File

@ -1,144 +0,0 @@
// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#ifndef KJ_VECTOR_H_
#define KJ_VECTOR_H_
#if defined(__GNUC__) && !KJ_HEADER_WARNINGS
#pragma GCC system_header
#endif
#include "array.h"
namespace kj {
template <typename T>
class Vector {
// Similar to std::vector, but based on KJ framework.
//
// This implementation always uses move constructors when growing the backing array. If the
// move constructor throws, the Vector is left in an inconsistent state. This is acceptable
// under KJ exception theory which assumes that exceptions leave things in inconsistent states.
// TODO(someday): Allow specifying a custom allocator.
public:
inline Vector() = default;
inline explicit Vector(size_t capacity): builder(heapArrayBuilder<T>(capacity)) {}
inline operator ArrayPtr<T>() { return builder; }
inline operator ArrayPtr<const T>() const { return builder; }
inline ArrayPtr<T> asPtr() { return builder.asPtr(); }
inline ArrayPtr<const T> asPtr() const { return builder.asPtr(); }
inline size_t size() const { return builder.size(); }
inline bool empty() const { return size() == 0; }
inline size_t capacity() const { return builder.capacity(); }
inline T& operator[](size_t index) const { return builder[index]; }
inline const T* begin() const { return builder.begin(); }
inline const T* end() const { return builder.end(); }
inline const T& front() const { return builder.front(); }
inline const T& back() const { return builder.back(); }
inline T* begin() { return builder.begin(); }
inline T* end() { return builder.end(); }
inline T& front() { return builder.front(); }
inline T& back() { return builder.back(); }
inline Array<T> releaseAsArray() {
// TODO(perf): Avoid a copy/move by allowing Array<T> to point to incomplete space?
if (!builder.isFull()) {
setCapacity(size());
}
return builder.finish();
}
template <typename... Params>
inline T& add(Params&&... params) {
if (builder.isFull()) grow();
return builder.add(kj::fwd<Params>(params)...);
}
template <typename Iterator>
inline void addAll(Iterator begin, Iterator end) {
size_t needed = builder.size() + (end - begin);
if (needed > builder.capacity()) grow(needed);
builder.addAll(begin, end);
}
template <typename Container>
inline void addAll(Container&& container) {
addAll(container.begin(), container.end());
}
inline void removeLast() {
builder.removeLast();
}
inline void resize(size_t size) {
if (size > builder.capacity()) grow(size);
builder.resize(size);
}
inline void operator=(decltype(nullptr)) {
builder = nullptr;
}
inline void clear() {
while (builder.size() > 0) {
builder.removeLast();
}
}
inline void truncate(size_t size) {
builder.truncate(size);
}
inline void reserve(size_t size) {
if (size > builder.capacity()) {
setCapacity(size);
}
}
private:
ArrayBuilder<T> builder;
void grow(size_t minCapacity = 0) {
setCapacity(kj::max(minCapacity, capacity() == 0 ? 4 : capacity() * 2));
}
void setCapacity(size_t newSize) {
if (builder.size() > newSize) {
builder.truncate(newSize);
}
ArrayBuilder<T> newBuilder = heapArrayBuilder<T>(newSize);
newBuilder.addAll(kj::mv(builder));
builder = kj::mv(newBuilder);
}
};
template <typename T>
inline auto KJ_STRINGIFY(const Vector<T>& v) -> decltype(toCharSequence(v.asPtr())) {
return toCharSequence(v.asPtr());
}
} // namespace kj
#endif // KJ_VECTOR_H_

View File

@ -1,41 +0,0 @@
// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#ifndef KJ_WINDOWS_SANITY_H_
#define KJ_WINDOWS_SANITY_H_
#if defined(__GNUC__) && !KJ_HEADER_WARNINGS
#pragma GCC system_header
#endif
#ifndef _INC_WINDOWS
#error "windows.h needs to be included before kj/windows-sanity.h (or perhaps you don't need either?)"
#endif
namespace win32 {
const auto ERROR_ = ERROR;
#undef ERROR
const auto ERROR = ERROR_;
}
using win32::ERROR;
#endif // KJ_WINDOWS_SANITY_H_

View File

@ -1,41 +0,0 @@
# libcapnp-json.la - a libtool library file
# Generated by libtool (GNU libtool) 2.4.6 Debian-2.4.6-2
#
# Please DO NOT delete this file!
# It is necessary for linking the library.
# The name that we can dlopen(3).
dlname='libcapnp-json-0.6.1.so'
# Names of this library.
library_names='libcapnp-json-0.6.1.so libcapnp-json-0.6.1.so libcapnp-json.so'
# The name of the static archive.
old_library='libcapnp-json.a'
# Linker flags that cannot go in dependency_libs.
inherited_linker_flags=' -pthread'
# Libraries that this one depends upon.
dependency_libs=' /home/batman/openpilot/external/capnp/lib/libcapnp.la /home/batman/openpilot/external/capnp/lib/libkj.la -lpthread'
# Names of additional weak libraries provided by this library
weak_library_names=''
# Version information for libcapnp-json.
current=0
age=0
revision=0
# Is this an already installed library?
installed=yes
# Should we warn about portability when linking against -modules?
shouldnotlink=no
# Files to dlopen/dlpreopen
dlopen=''
dlpreopen=''
# Directory that this library needs to be installed in:
libdir='/home/batman/openpilot/external/capnp/lib'

View File

@ -1,41 +0,0 @@
# libcapnp-rpc.la - a libtool library file
# Generated by libtool (GNU libtool) 2.4.6 Debian-2.4.6-2
#
# Please DO NOT delete this file!
# It is necessary for linking the library.
# The name that we can dlopen(3).
dlname='libcapnp-rpc-0.6.1.so'
# Names of this library.
library_names='libcapnp-rpc-0.6.1.so libcapnp-rpc-0.6.1.so libcapnp-rpc.so'
# The name of the static archive.
old_library='libcapnp-rpc.a'
# Linker flags that cannot go in dependency_libs.
inherited_linker_flags=' -pthread'
# Libraries that this one depends upon.
dependency_libs=' /home/batman/openpilot/external/capnp/lib/libcapnp.la /home/batman/openpilot/external/capnp/lib/libkj-async.la /home/batman/openpilot/external/capnp/lib/libkj.la -lpthread'
# Names of additional weak libraries provided by this library
weak_library_names=''
# Version information for libcapnp-rpc.
current=0
age=0
revision=0
# Is this an already installed library?
installed=yes
# Should we warn about portability when linking against -modules?
shouldnotlink=no
# Files to dlopen/dlpreopen
dlopen=''
dlpreopen=''
# Directory that this library needs to be installed in:
libdir='/home/batman/openpilot/external/capnp/lib'

View File

@ -1,41 +0,0 @@
# libcapnp.la - a libtool library file
# Generated by libtool (GNU libtool) 2.4.6 Debian-2.4.6-2
#
# Please DO NOT delete this file!
# It is necessary for linking the library.
# The name that we can dlopen(3).
dlname='libcapnp-0.6.1.so'
# Names of this library.
library_names='libcapnp-0.6.1.so libcapnp-0.6.1.so libcapnp.so'
# The name of the static archive.
old_library='libcapnp.a'
# Linker flags that cannot go in dependency_libs.
inherited_linker_flags=' -pthread'
# Libraries that this one depends upon.
dependency_libs=' /home/batman/openpilot/external/capnp/lib/libkj.la -lpthread'
# Names of additional weak libraries provided by this library
weak_library_names=''
# Version information for libcapnp.
current=0
age=0
revision=0
# Is this an already installed library?
installed=yes
# Should we warn about portability when linking against -modules?
shouldnotlink=no
# Files to dlopen/dlpreopen
dlopen=''
dlpreopen=''
# Directory that this library needs to be installed in:
libdir='/home/batman/openpilot/external/capnp/lib'

View File

@ -1,41 +0,0 @@
# libcapnp_c.la - a libtool library file
# Generated by libtool (GNU libtool) 2.4.6 Debian-2.4.6-0.1
#
# Please DO NOT delete this file!
# It is necessary for linking the library.
# The name that we can dlopen(3).
dlname='libcapnp_c.so.0'
# Names of this library.
library_names='libcapnp_c.so.0.0.0 libcapnp_c.so.0 libcapnp_c.so'
# The name of the static archive.
old_library='libcapnp_c.a'
# Linker flags that cannot go in dependency_libs.
inherited_linker_flags=''
# Libraries that this one depends upon.
dependency_libs=''
# Names of additional weak libraries provided by this library
weak_library_names=''
# Version information for libcapnp_c.
current=0
age=0
revision=0
# Is this an already installed library?
installed=yes
# Should we warn about portability when linking against -modules?
shouldnotlink=no
# Files to dlopen/dlpreopen
dlopen=''
dlpreopen=''
# Directory that this library needs to be installed in:
libdir='/home/batman/openpilot/external/capnp/lib'

View File

@ -1 +0,0 @@
libcapnp_c.so.0.0.0

Binary file not shown.

View File

@ -1,41 +0,0 @@
# libcapnpc.la - a libtool library file
# Generated by libtool (GNU libtool) 2.4.6 Debian-2.4.6-2
#
# Please DO NOT delete this file!
# It is necessary for linking the library.
# The name that we can dlopen(3).
dlname='libcapnpc-0.6.1.so'
# Names of this library.
library_names='libcapnpc-0.6.1.so libcapnpc-0.6.1.so libcapnpc.so'
# The name of the static archive.
old_library='libcapnpc.a'
# Linker flags that cannot go in dependency_libs.
inherited_linker_flags=' -pthread'
# Libraries that this one depends upon.
dependency_libs=' /home/batman/openpilot/external/capnp/lib/libcapnp.la /home/batman/openpilot/external/capnp/lib/libkj.la -lpthread'
# Names of additional weak libraries provided by this library
weak_library_names=''
# Version information for libcapnpc.
current=0
age=0
revision=0
# Is this an already installed library?
installed=yes
# Should we warn about portability when linking against -modules?
shouldnotlink=no
# Files to dlopen/dlpreopen
dlopen=''
dlpreopen=''
# Directory that this library needs to be installed in:
libdir='/home/batman/openpilot/external/capnp/lib'

Some files were not shown because too many files have changed in this diff Show More