Commit 65146e05 authored by Matthew Maurer's avatar Matthew Maurer

Merge branch 'master' into canonicalize-pr

parents ca8c1386 981814eb
......@@ -109,6 +109,9 @@ if(NOT MSVC) # Don't install pkg-config files when building with MSVC
configure_file(capnp-rpc.pc.in "${CMAKE_CURRENT_BINARY_DIR}/capnp-rpc.pc" @ONLY)
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/capnp-rpc.pc" DESTINATION "${LIB_INSTALL_DIR}/pkgconfig")
configure_file(capnp-json.pc.in "${CMAKE_CURRENT_BINARY_DIR}/capnp-json.pc" @ONLY)
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/capnp-json.pc" DESTINATION "${LIB_INSTALL_DIR}/pkgconfig")
endif()
unset(STDLIB_FLAG)
......
......@@ -74,7 +74,8 @@ public_capnpc_inputs = \
src/capnp/schema.capnp \
src/capnp/rpc.capnp \
src/capnp/rpc-twoparty.capnp \
src/capnp/persistent.capnp
src/capnp/persistent.capnp \
src/capnp/compat/json.capnp
capnpc_inputs = \
$(public_capnpc_inputs) \
......@@ -92,12 +93,15 @@ capnpc_outputs = \
src/capnp/rpc-twoparty.capnp.h \
src/capnp/persistent.capnp.c++ \
src/capnp/persistent.capnp.h \
src/capnp/compat/json.capnp.h \
src/capnp/compat/json.capnp.c++ \
src/capnp/compiler/lexer.capnp.c++ \
src/capnp/compiler/lexer.capnp.h \
src/capnp/compiler/grammar.capnp.c++ \
src/capnp/compiler/grammar.capnp.h
includecapnpdir = $(includedir)/capnp
includecapnpcompatdir = $(includecapnpdir)/compat
includekjdir = $(includedir)/kj
includekjparsedir = $(includekjdir)/parse
includekjstddir = $(includekjdir)/std
......@@ -183,10 +187,14 @@ includecapnp_HEADERS = \
src/capnp/persistent.capnp.h \
src/capnp/ez-rpc.h
includecapnpcompat_HEADERS = \
src/capnp/compat/json.h \
src/capnp/compat/json.capnp.h
if LITE_MODE
lib_LTLIBRARIES = libkj.la libkj-test.la libcapnp.la
else
lib_LTLIBRARIES = libkj.la libkj-test.la libkj-async.la libcapnp.la libcapnp-rpc.la libcapnpc.la
lib_LTLIBRARIES = libkj.la libkj-test.la libkj-async.la libcapnp.la libcapnp-rpc.la libcapnp-json.la libcapnpc.la
endif
# Don't include security release in soname -- we want to replace old binaries
......@@ -266,6 +274,12 @@ libcapnp_rpc_la_SOURCES= \
src/capnp/persistent.capnp.c++ \
src/capnp/ez-rpc.c++
libcapnp_json_la_LIBADD = libcapnp.la libkj-async.la libkj.la $(PTHREAD_LIBS)
libcapnp_json_la_LDFLAGS = -release $(SO_VERSION) -no-undefined
libcapnp_json_la_SOURCES= \
src/capnp/compat/json.c++ \
src/capnp/compat/json.capnp.c++
libcapnpc_la_LIBADD = libcapnp.la libkj.la $(PTHREAD_LIBS)
libcapnpc_la_LDFLAGS = -release $(SO_VERSION) -no-undefined
libcapnpc_la_SOURCES= \
......@@ -388,9 +402,16 @@ heavy_tests = \
src/capnp/rpc-test.c++ \
src/capnp/rpc-twoparty-test.c++ \
src/capnp/ez-rpc-test.c++ \
src/capnp/compat/json-test.c++ \
src/capnp/compiler/lexer-test.c++ \
src/capnp/compiler/md5-test.c++
capnp_test_LDADD = libcapnpc.la libcapnp-rpc.la libcapnp.la libkj-async.la libkj-test.la libkj.la
capnp_test_LDADD = libcapnpc.la \
libcapnp-rpc.la \
libcapnp-json.la \
libcapnp.la \
libkj-async.la \
libkj-test.la \
libkj.la
endif !LITE_MODE
......
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
Name: Cap'n Proto JSON
Description: JSON encoder and decoder for Cap'n Proto objects
Version: @VERSION@
Libs: -L${libdir} -lcapnp-json
Requires: capnp = @VERSION@ kj-async = @VERSION@
Cflags: -I${includedir}
......@@ -134,6 +134,7 @@ endfunction()
find_package(PkgConfig QUIET)
pkg_check_modules(PKGCONFIG_CAPNP capnp)
pkg_check_modules(PKGCONFIG_CAPNP_RPC capnp-rpc QUIET)
pkg_check_modules(PKGCONFIG_CAPNP_JSON capnp-json QUIET)
find_library(CAPNP_LIB_KJ kj
HINTS "${PKGCONFIG_CAPNP_LIBDIR}" ${PKGCONFIG_CAPNP_LIBRARY_DIRS}
......@@ -147,12 +148,16 @@ find_library(CAPNP_LIB_CAPNP capnp
find_library(CAPNP_LIB_CAPNP-RPC capnp-rpc
HINTS "${PKGCONFIG_CAPNP_RPC_LIBDIR}" ${PKGCONFIG_CAPNP_RPC_LIBRARY_DIRS}
)
mark_as_advanced(CAPNP_LIB_KJ CAPNP_LIB_KJ-ASYNC CAPNP_LIB_CAPNP CAPNP_LIB_CAPNP-RPC)
find_library(CAPNP_LIB_CAPNP-JSON capnp-json
HINTS "${PKGCONFIG_CAPNP_JSON_LIBDIR}" ${PKGCONFIG_CAPNP_JSON_LIBRARY_DIRS}
)
mark_as_advanced(CAPNP_LIB_KJ CAPNP_LIB_KJ-ASYNC CAPNP_LIB_CAPNP CAPNP_LIB_CAPNP-RPC CAPNP_LIB_CAPNP-JSON)
set(CAPNP_LIBRARIES_LITE
${CAPNP_LIB_CAPNP}
${CAPNP_LIB_KJ}
)
set(CAPNP_LIBRARIES
${CAPNP_LIB_CAPNP-JSON}
${CAPNP_LIB_CAPNP-RPC}
${CAPNP_LIB_CAPNP}
${CAPNP_LIB_KJ-ASYNC}
......
......@@ -101,5 +101,5 @@ AC_SUBST([STDLIB_FLAG])
LIBS="$PTHREAD_LIBS $LIBS"
CXXFLAGS="$CXXFLAGS $PTHREAD_CFLAGS"
AC_CONFIG_FILES([Makefile capnp.pc capnp-rpc.pc kj.pc kj-async.pc])
AC_CONFIG_FILES([Makefile capnp.pc capnp-rpc.pc capnp-json.pc kj.pc kj-async.pc])
AC_OUTPUT
......@@ -7,4 +7,5 @@ export PATH=$PWD/bin:$PWD:$PATH
capnp compile -Isrc --no-standard-import --src-prefix=src -oc++:src \
src/capnp/c++.capnp src/capnp/schema.capnp \
src/capnp/compiler/lexer.capnp src/capnp/compiler/grammar.capnp \
src/capnp/rpc.capnp src/capnp/rpc-twoparty.capnp src/capnp/persistent.capnp
src/capnp/rpc.capnp src/capnp/rpc-twoparty.capnp src/capnp/persistent.capnp \
src/capnp/compat/json.capnp
......@@ -94,6 +94,26 @@ if(NOT CAPNP_LITE)
install(FILES ${capnp-rpc_headers} ${capnp-rpc_schemas} DESTINATION "${INCLUDE_INSTALL_DIR}/capnp")
endif()
# capnp-json ========================================================================
set(capnp-json_sources
compat/json.c++
compat/json.capnp.c++
)
set(capnp-json_headers
compat/json.h
compat/json.capnp.h
)
set(capnp-json_schemas
compat/json.capnp
)
if(NOT CAPNP_LITE)
add_library(capnp-json ${capnp-json_sources})
target_link_libraries(capnp-json capnp kj-async kj)
install(TARGETS capnp-json ARCHIVE DESTINATION "${LIB_INSTALL_DIR}")
install(FILES ${capnp-json_headers} ${capnp-json_schemas} DESTINATION "${INCLUDE_INSTALL_DIR}/capnp/compat")
endif()
# Tools/Compilers ==============================================================
set(capnpc_sources
......@@ -185,7 +205,7 @@ if(BUILD_TESTING)
if(CAPNP_LITE)
set(test_libraries capnp kj-test kj)
else()
set(test_libraries capnp-rpc capnp capnpc kj-async kj-test kj)
set(test_libraries capnp-json capnp-rpc capnp capnpc kj-async kj-test kj)
endif()
add_executable(capnp-tests
......@@ -228,6 +248,7 @@ if(BUILD_TESTING)
compiler/lexer-test.c++
compiler/md5-test.c++
test-util.c++
compat/json-test.c++
${test_capnp_cpp_files}
${test_capnp_h_files}
)
......
......@@ -37,7 +37,8 @@ case "$INPUT" in
*capnp/rpc-twoparty.capnp | \
*capnp/persistent.capnp | \
*capnp/compiler/lexer.capnp | \
*capnp/compiler/grammar.capnp )
*capnp/compiler/grammar.capnp | \
*capnp/compat/json.capnp )
exit 0
;;
esac
......
This diff is collapsed.
This diff is collapsed.
......@@ -41,11 +41,13 @@ TESTDATA=`dirname "$0"`/../testdata
$CAPNP encode $SCHEMA TestAllTypes < $TESTDATA/short.txt | cmp $TESTDATA/binary - || fail encode
$CAPNP encode --flat $SCHEMA TestAllTypes < $TESTDATA/short.txt | cmp $TESTDATA/flat - || fail encode flat
$CAPNP encode --packed $SCHEMA TestAllTypes < $TESTDATA/short.txt | cmp $TESTDATA/packed - || fail encode packed
$CAPNP encode --packed --flat $SCHEMA TestAllTypes < $TESTDATA/short.txt | cmp $TESTDATA/packedflat - || fail encode packedflat
$CAPNP encode $SCHEMA TestAllTypes < $TESTDATA/pretty.txt | cmp $TESTDATA/binary - || fail parse pretty
$CAPNP decode $SCHEMA TestAllTypes < $TESTDATA/binary | cmp $TESTDATA/pretty.txt - || fail decode
$CAPNP decode --flat $SCHEMA TestAllTypes < $TESTDATA/flat | cmp $TESTDATA/pretty.txt - || fail decode flat
$CAPNP decode --packed $SCHEMA TestAllTypes < $TESTDATA/packed | cmp $TESTDATA/pretty.txt - || fail decode packed
$CAPNP decode --packed --flat $SCHEMA TestAllTypes < $TESTDATA/packedflat | cmp $TESTDATA/pretty.txt - || fail decode packedflat
$CAPNP decode --short $SCHEMA TestAllTypes < $TESTDATA/binary | cmp $TESTDATA/short.txt - || fail decode short
$CAPNP decode $SCHEMA TestAllTypes < $TESTDATA/segmented | cmp $TESTDATA/pretty.txt - || fail decode segmented
......
This diff is collapsed.
......@@ -1662,6 +1662,8 @@ struct WireHelpers {
return { segment, ptr };
} else {
// List of structs.
KJ_DASSERT(value.structDataSize % BITS_PER_WORD == 0 * BITS);
WordCount declDataSize = roundBitsUpToWords(value.structDataSize);
WirePointerCount declPointerCount = value.structPointerCount;
......
......@@ -667,7 +667,8 @@ class ListBuilder: public kj::DisallowConstCopy {
public:
inline explicit ListBuilder(ElementSize elementSize)
: segment(nullptr), capTable(nullptr), ptr(nullptr), elementCount(0 * ELEMENTS),
step(0 * BITS / ELEMENTS), elementSize(elementSize) {}
step(0 * BITS / ELEMENTS), elementSize(elementSize), structDataSize(0 * BITS),
structPointerCount(0 * POINTERS) {}
MSVC_DEFAULT_ASSIGNMENT_WORKAROUND(, ListBuilder)
......
......@@ -39,6 +39,11 @@ public:
~TestPipe() {}
const std::string& getData() { return data; }
kj::ArrayPtr<const byte> getArray() {
return kj::arrayPtr(reinterpret_cast<const byte*>(data.data()), data.size());
}
void resetRead(size_t preferredReadSize = kj::maxValue) {
readPos = 0;
this->preferredReadSize = preferredReadSize;
......@@ -84,6 +89,8 @@ private:
void expectPacksTo(kj::ArrayPtr<const byte> unpacked, kj::ArrayPtr<const byte> packed) {
TestPipe pipe;
EXPECT_EQ(unpacked.size(), computeUnpackedSizeInWords(packed) * sizeof(word));
// -----------------------------------------------------------------
// write
......@@ -244,6 +251,8 @@ TEST(Packed, RoundTrip) {
TestPipe pipe;
writePackedMessage(pipe, builder);
EXPECT_EQ(computeSerializedSizeInWords(builder), computeUnpackedSizeInWords(pipe.getArray()));
PackedMessageReader reader(pipe);
checkTestMessage(reader.getRoot<TestAllTypes>());
}
......@@ -255,6 +264,8 @@ TEST(Packed, RoundTripScratchSpace) {
TestPipe pipe;
writePackedMessage(pipe, builder);
EXPECT_EQ(computeSerializedSizeInWords(builder), computeUnpackedSizeInWords(pipe.getArray()));
word scratch[1024];
PackedMessageReader reader(pipe, ReaderOptions(), kj::ArrayPtr<word>(scratch, 1024));
checkTestMessage(reader.getRoot<TestAllTypes>());
......@@ -267,6 +278,8 @@ TEST(Packed, RoundTripLazy) {
TestPipe pipe(1);
writePackedMessage(pipe, builder);
EXPECT_EQ(computeSerializedSizeInWords(builder), computeUnpackedSizeInWords(pipe.getArray()));
PackedMessageReader reader(pipe);
checkTestMessage(reader.getRoot<TestAllTypes>());
}
......@@ -278,6 +291,8 @@ TEST(Packed, RoundTripOddSegmentCount) {
TestPipe pipe;
writePackedMessage(pipe, builder);
EXPECT_EQ(computeSerializedSizeInWords(builder), computeUnpackedSizeInWords(pipe.getArray()));
PackedMessageReader reader(pipe);
checkTestMessage(reader.getRoot<TestAllTypes>());
}
......@@ -289,6 +304,8 @@ TEST(Packed, RoundTripOddSegmentCountLazy) {
TestPipe pipe(1);
writePackedMessage(pipe, builder);
EXPECT_EQ(computeSerializedSizeInWords(builder), computeUnpackedSizeInWords(pipe.getArray()));
PackedMessageReader reader(pipe);
checkTestMessage(reader.getRoot<TestAllTypes>());
}
......@@ -300,6 +317,8 @@ TEST(Packed, RoundTripEvenSegmentCount) {
TestPipe pipe;
writePackedMessage(pipe, builder);
EXPECT_EQ(computeSerializedSizeInWords(builder), computeUnpackedSizeInWords(pipe.getArray()));
PackedMessageReader reader(pipe);
checkTestMessage(reader.getRoot<TestAllTypes>());
}
......@@ -311,6 +330,8 @@ TEST(Packed, RoundTripEvenSegmentCountLazy) {
TestPipe pipe(1);
writePackedMessage(pipe, builder);
EXPECT_EQ(computeSerializedSizeInWords(builder), computeUnpackedSizeInWords(pipe.getArray()));
PackedMessageReader reader(pipe);
checkTestMessage(reader.getRoot<TestAllTypes>());
}
......@@ -326,6 +347,9 @@ TEST(Packed, RoundTripTwoMessages) {
writePackedMessage(pipe, builder);
writePackedMessage(pipe, builder2);
EXPECT_EQ(computeSerializedSizeInWords(builder) + computeSerializedSizeInWords(builder2),
computeUnpackedSizeInWords(pipe.getArray()));
{
PackedMessageReader reader(pipe);
checkTestMessage(reader.getRoot<TestAllTypes>());
......@@ -346,6 +370,8 @@ TEST(Packed, RoundTripAllZero) {
TestPipe pipe;
writePackedMessage(pipe, builder);
EXPECT_EQ(computeSerializedSizeInWords(builder), computeUnpackedSizeInWords(pipe.getArray()));
PackedMessageReader reader(pipe);
checkTestMessageAllZero(reader.getRoot<TestAllTypes>());
......@@ -362,6 +388,8 @@ TEST(Packed, RoundTripAllZeroScratchSpace) {
TestPipe pipe;
writePackedMessage(pipe, builder);
EXPECT_EQ(computeSerializedSizeInWords(builder), computeUnpackedSizeInWords(pipe.getArray()));
word scratch[1024];
PackedMessageReader reader(pipe, ReaderOptions(), kj::ArrayPtr<word>(scratch, 1024));
checkTestMessageAllZero(reader.getRoot<TestAllTypes>());
......@@ -374,6 +402,8 @@ TEST(Packed, RoundTripAllZeroLazy) {
TestPipe pipe(1);
writePackedMessage(pipe, builder);
EXPECT_EQ(computeSerializedSizeInWords(builder), computeUnpackedSizeInWords(pipe.getArray()));
PackedMessageReader reader(pipe);
checkTestMessageAllZero(reader.getRoot<TestAllTypes>());
}
......@@ -385,6 +415,8 @@ TEST(Packed, RoundTripAllZeroOddSegmentCount) {
TestPipe pipe;
writePackedMessage(pipe, builder);
EXPECT_EQ(computeSerializedSizeInWords(builder), computeUnpackedSizeInWords(pipe.getArray()));
PackedMessageReader reader(pipe);
checkTestMessageAllZero(reader.getRoot<TestAllTypes>());
}
......@@ -396,6 +428,8 @@ TEST(Packed, RoundTripAllZeroOddSegmentCountLazy) {
TestPipe pipe(1);
writePackedMessage(pipe, builder);
EXPECT_EQ(computeSerializedSizeInWords(builder), computeUnpackedSizeInWords(pipe.getArray()));
PackedMessageReader reader(pipe);
checkTestMessageAllZero(reader.getRoot<TestAllTypes>());
}
......@@ -407,6 +441,8 @@ TEST(Packed, RoundTripAllZeroEvenSegmentCount) {
TestPipe pipe;
writePackedMessage(pipe, builder);
EXPECT_EQ(computeSerializedSizeInWords(builder), computeUnpackedSizeInWords(pipe.getArray()));
PackedMessageReader reader(pipe);
checkTestMessageAllZero(reader.getRoot<TestAllTypes>());
}
......@@ -418,6 +454,8 @@ TEST(Packed, RoundTripAllZeroEvenSegmentCountLazy) {
TestPipe pipe(1);
writePackedMessage(pipe, builder);
EXPECT_EQ(computeSerializedSizeInWords(builder), computeUnpackedSizeInWords(pipe.getArray()));
PackedMessageReader reader(pipe);
checkTestMessageAllZero(reader.getRoot<TestAllTypes>());
}
......@@ -434,6 +472,8 @@ TEST(Packed, RoundTripHugeString) {
TestPipe pipe;
writePackedMessage(pipe, builder);
EXPECT_EQ(computeSerializedSizeInWords(builder), computeUnpackedSizeInWords(pipe.getArray()));
PackedMessageReader reader(pipe);
EXPECT_TRUE(reader.getRoot<TestAllTypes>().getTextField() == huge);
}
......@@ -448,6 +488,8 @@ TEST(Packed, RoundTripHugeStringScratchSpace) {
TestPipe pipe;
writePackedMessage(pipe, builder);
EXPECT_EQ(computeSerializedSizeInWords(builder), computeUnpackedSizeInWords(pipe.getArray()));
word scratch[1024];
PackedMessageReader reader(pipe, ReaderOptions(), kj::ArrayPtr<word>(scratch, 1024));
EXPECT_TRUE(reader.getRoot<TestAllTypes>().getTextField() == huge);
......@@ -463,6 +505,8 @@ TEST(Packed, RoundTripHugeStringLazy) {
TestPipe pipe(1);
writePackedMessage(pipe, builder);
EXPECT_EQ(computeSerializedSizeInWords(builder), computeUnpackedSizeInWords(pipe.getArray()));
PackedMessageReader reader(pipe);
EXPECT_TRUE(reader.getRoot<TestAllTypes>().getTextField() == huge);
}
......@@ -477,6 +521,8 @@ TEST(Packed, RoundTripHugeStringOddSegmentCount) {
TestPipe pipe;
writePackedMessage(pipe, builder);
EXPECT_EQ(computeSerializedSizeInWords(builder), computeUnpackedSizeInWords(pipe.getArray()));
PackedMessageReader reader(pipe);
EXPECT_TRUE(reader.getRoot<TestAllTypes>().getTextField() == huge);
}
......@@ -491,6 +537,8 @@ TEST(Packed, RoundTripHugeStringOddSegmentCountLazy) {
TestPipe pipe(1);
writePackedMessage(pipe, builder);
EXPECT_EQ(computeSerializedSizeInWords(builder), computeUnpackedSizeInWords(pipe.getArray()));
PackedMessageReader reader(pipe);
EXPECT_TRUE(reader.getRoot<TestAllTypes>().getTextField() == huge);
}
......@@ -505,6 +553,8 @@ TEST(Packed, RoundTripHugeStringEvenSegmentCount) {
TestPipe pipe;
writePackedMessage(pipe, builder);
EXPECT_EQ(computeSerializedSizeInWords(builder), computeUnpackedSizeInWords(pipe.getArray()));
PackedMessageReader reader(pipe);
EXPECT_TRUE(reader.getRoot<TestAllTypes>().getTextField() == huge);
}
......@@ -519,6 +569,8 @@ TEST(Packed, RoundTripHugeStringEvenSegmentCountLazy) {
TestPipe pipe(1);
writePackedMessage(pipe, builder);
EXPECT_EQ(computeSerializedSizeInWords(builder), computeUnpackedSizeInWords(pipe.getArray()));
PackedMessageReader reader(pipe);
EXPECT_TRUE(reader.getRoot<TestAllTypes>().getTextField() == huge);
}
......
......@@ -43,7 +43,7 @@ size_t PackedInputStream::tryRead(void* dst, size_t minBytes, size_t maxBytes) {
uint8_t* const outEnd = reinterpret_cast<uint8_t*>(dst) + maxBytes;
uint8_t* const outMin = reinterpret_cast<uint8_t*>(dst) + minBytes;
kj::ArrayPtr<const byte> buffer = inner.getReadBuffer();
kj::ArrayPtr<const byte> buffer = inner.tryGetReadBuffer();
if (buffer.size() == 0) {
return 0;
}
......@@ -476,4 +476,32 @@ void writePackedMessageToFd(int fd, kj::ArrayPtr<const kj::ArrayPtr<const word>>
writePackedMessage(output, segments);
}
size_t computeUnpackedSizeInWords(kj::ArrayPtr<const byte> packedBytes) {
const byte* ptr = packedBytes.begin();
const byte* end = packedBytes.end();
size_t total = 0;
while (ptr < end) {
uint tag = *ptr;
size_t count = __builtin_popcount(tag);
total += 1;
KJ_REQUIRE(end - ptr >= count, "invalid packed data");
ptr += count + 1;
if (tag == 0) {
KJ_REQUIRE(ptr < end, "invalid packed data");
total += *ptr++;
} else if (tag == 0xff) {
KJ_REQUIRE(ptr < end, "invalid packed data");
size_t words = *ptr++;
total += words;
size_t bytes = words * sizeof(word);
KJ_REQUIRE(end - ptr >= bytes, "invalid packed data");
ptr += bytes;
}
}
return total;
}
} // namespace capnp
......@@ -106,6 +106,10 @@ 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
......
......@@ -103,6 +103,22 @@ public:
}
}
inline void operator=(decltype(nullptr)) {
builder = nullptr;
}
inline void clear() {
while (builder.size() > 0) {
builder.removeLast();
}
}
inline void truncate(size_t size) {
while (builder.size() > size) {
builder.removeLast();
}
}
private:
ArrayBuilder<T> builder;
......
......@@ -22,7 +22,7 @@ project's documentation for details.
##### Serialization only
* [C](https://github.com/jmckaskill/c-capnproto) by [@jmckaskill](https://github.com/jmckaskill)
* [C](https://github.com/opensourcerouting/c-capnproto) by [OpenSourceRouting](https://www.opensourcerouting.org/) / [@eqvinox](https://github.com/eqvinox) (originally by [@jmckaskill](https://github.com/jmckaskill))
* [C#](https://github.com/mgravell/capnproto-net) by [@mgravell](https://github.com/mgravell)
* [Go](https://github.com/glycerine/go-capnproto) by [@glycerine](https://github.com/glycerine) (originally by [@jmckaskill](https://github.com/jmckaskill))
* [Java](https://github.com/dwrensha/capnproto-java/) by [@dwrensha](https://github.com/dwrensha)
......@@ -41,8 +41,8 @@ new languages.
* [Common Test Framework](https://github.com/kaos/capnp_test) by [@kaos](https://github.com/kaos)
* [Sublime Syntax Highlighting](https://github.com/joshuawarner32/capnproto-sublime) by
[@joshuawarner32](https://github.com/joshuawarner32)
* [Vim Syntax Highlighting](https://github.com/cstrahan/vim-capnp) by
[@cstrahan](https://github.com/cstrahan)
* [Vim Syntax Highlighting](https://github.com/peter-edge/vim-capnp) by [@peter-edge](https://github.com/peter-edge)
(originally by [@cstrahan](https://github.com/cstrahan))
* [Wireshark Dissector Plugin](https://github.com/kaos/wireshark-plugins) by [@kaos](https://github.com/kaos)
## Contribute Your Own!
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment