Commit b4f80598 authored by Kenton Varda's avatar Kenton Varda

Text and data blobs.

parent 8b7e9096
// Copyright (c) 2013, Kenton Varda <temporal@gmail.com>
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "blob.h"
#include <gtest/gtest.h>
#include <iostream>
#include <string>
namespace capnproto {
std::ostream& operator<<(std::ostream& os, const Data::Reader& value) {
return os.write(value.data(), value.size());
}
std::ostream& operator<<(std::ostream& os, const Data::Builder& value) {
return os.write(value.data(), value.size());
}
namespace {
TEST(Blob, Text) {
std::string str = "foo";
Text::Reader text = str;
EXPECT_STREQ("foo", text);
EXPECT_STREQ("foo", text.c_str());
EXPECT_STREQ("foo", text.data());
EXPECT_EQ(3u, text.size());
std::string str2 = text;
EXPECT_EQ("foo", str2);
Text::Reader text2 = "bar";
EXPECT_STREQ("bar", text2);
char c[4] = "baz";
Text::Reader text3(c);
EXPECT_STREQ("baz", text3);
Text::Builder builder(c, 3);
EXPECT_STREQ("baz", builder);
EXPECT_EQ(Data::Reader("az"), builder.slice(1, 3));
}
TEST(Blob, Data) {
std::string str = "foo";
Data::Reader data = str;
EXPECT_EQ(3u, data.size());
std::string str2 = data;
EXPECT_EQ("foo", str2);
Data::Reader data2 = "bar";
EXPECT_EQ("bar", data2.as<std::string>());
char c[4] = "baz";
Data::Reader data3(c);
EXPECT_EQ("baz", data3.as<std::string>());
Data::Builder builder(c, 3);
EXPECT_EQ("baz", builder.as<std::string>());
EXPECT_EQ(Data::Reader("az"), builder.slice(1, 3));
}
} // namespace
} // namespace capnproto
// Copyright (c) 2013, Kenton Varda <temporal@gmail.com>
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "blob.h"
namespace capnproto {
char Text::Builder::nulstr[1] = "";
} // namespace capnproto
// Copyright (c) 2013, Kenton Varda <temporal@gmail.com>
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef CAPNPROTO_BLOB_H_
#define CAPNPROTO_BLOB_H_
#include "macros.h"
#include "type-safety.h"
#include <string.h>
namespace capnproto {
struct Data {
class Reader;
class Builder;
};
struct Text {
class Reader;
class Builder;
};
class Data::Reader {
// 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.
//
// Data::Reader can be implicitly converted to any type which has a constructor that takes a
// (const char*, size) pair, and can be implicitly constructed from any type that has data()
// and size() methods. Many types follow this pattern, such as std::string. Data::Reader can
// also be implicitly constructed from a NUL-terminated char*.
public:
inline Reader(): bytes(nullptr), size_(0) {}
inline Reader(const char* bytes): bytes(bytes), size_(strlen(bytes)) {}
inline Reader(char* bytes): bytes(bytes), size_(strlen(bytes)) {}
inline Reader(const char* bytes, uint size): bytes(bytes), size_(size) {}
template <typename T>
inline Reader(const T& other): bytes(other.data()), size_(other.size()) {}
// Primarily intended for converting from std::string.
template <typename T>
inline operator T() const { return T(bytes, size_); }
// Primarily intended for converting to std::string.
template <typename T>
inline T as() const { return T(bytes, size_); }
// Explicitly converts to the desired type, which must have a (const char*, size) constructor.
inline const char* data() const { return bytes; }
inline uint size() const { return size_; }
inline const char operator[](uint index) const { return bytes[index]; }
inline Reader slice(uint start, uint end) const {
CAPNPROTO_DEBUG_ASSERT(start <= end && end <= size_, "Out-of-bounds slice.");
return Reader(bytes + start, end - start);
}
inline bool operator==(const Reader& other) const {
return size_ == other.size_ && memcmp(bytes, other.bytes, size_) == 0;
}
inline bool operator<=(const Reader& other) const {
bool shorter = size_ <= other.size_;
int cmp = memcmp(bytes, other.bytes, shorter ? size_ : other.size_);
return cmp < 0 ? true : cmp > 0 ? false : size_ <= other.size_;
}
inline bool operator!=(const Reader& other) const { return !(*this == other); }
inline bool operator>=(const Reader& other) const { return other <= *this; }
inline bool operator< (const Reader& other) const { return !(other <= *this); }
inline bool operator> (const Reader& other) const { return !(*this <= other); }
private:
const char* bytes;
uint size_;
};
class Text::Reader: public Data::Reader {
// 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.
//
// TextReader can be implicitly converted to and from const char*. Additionally, it can be
// implicitly converted to any type that can be constructed from a (const char*, size) pair, as
// well as from any type which has c_str() and size() methods. Many types follow this pattern,
// such as std::string.
public:
inline Reader(): Data::Reader("", 0) {}
inline Reader(const char* text): Data::Reader(text, strlen(text)) {
CAPNPROTO_DEBUG_ASSERT(text[size()] == '\0', "Text must be NUL-terminated.");
}
inline Reader(char* text): Data::Reader(text, strlen(text)) {
CAPNPROTO_DEBUG_ASSERT(text[size()] == '\0', "Text must be NUL-terminated.");
}
inline Reader(const char* text, uint size): Data::Reader(text, size) {
CAPNPROTO_DEBUG_ASSERT(text[size] == '\0', "Text must be NUL-terminated.");
}
template <typename T>
inline Reader(const T& other): Data::Reader(other.c_str(), other.size()) {
// Primarily intended for converting from std::string.
CAPNPROTO_DEBUG_ASSERT(data()[size()] == '\0',
"Text must be NUL-terminated.");
}
inline const char* c_str() const { return data(); }
inline operator const char*() const { return data(); }
};
class Data::Builder {
// Like Data::Reader except the pointers aren't const, and it can't be implicitly constructed from
// other types.
public:
inline Builder(): bytes(nullptr), size_(0) {}
inline Builder(char* bytes, uint size): bytes(bytes), size_(size) {}
template <typename T>
inline operator T() const { return T(bytes, size_); }
// Primarily intended for converting to std::string.
inline operator Data::Reader() const { return Data::Reader(bytes, size_); }
template <typename T>
inline T as() const { return T(bytes, size_); }
// Explicitly converts to the desired type, which must have a (char*, size) constructor.
inline char* data() const { return bytes; }
inline uint size() const { return size_; }
inline char& operator[](uint index) const { return bytes[index]; }
inline Builder slice(uint start, uint end) const {
CAPNPROTO_DEBUG_ASSERT(start <= end && end <= size_, "Out-of-bounds slice.");
return Builder(bytes + start, end - start);
}
inline bool operator==(const Builder& other) const {
return size_ == other.size_ && memcmp(bytes, other.bytes, size_) == 0;
}
inline bool operator<=(const Builder& other) const {
bool shorter = size_ <= other.size_;
int cmp = memcmp(bytes, other.bytes, shorter ? size_ : other.size_);
return cmp < 0 ? true : cmp > 0 ? false : size_ <= other.size_;
}
inline bool operator!=(const Builder& other) const { return !(*this == other); }
inline bool operator>=(const Builder& other) const { return other <= *this; }
inline bool operator< (const Builder& other) const { return !(other <= *this); }
inline bool operator> (const Builder& other) const { return !(*this <= other); }
template <typename T>
inline void copyFrom(const T& other) const {
CAPNPROTO_DEBUG_ASSERT(size() == other.size(), "Sizes must match to copy.");
memcpy(bytes, other.data(), other.size());
}
inline void copyFrom(const void* other) const {
memcpy(bytes, other, size_);
}
private:
char* bytes;
uint size_;
};
class Text::Builder: public Data::Builder {
// Like Text::Reader except the pointers aren't const, and it can't be implicitly constructed from
// other types. The Text::Builder automatically initializes the NUL terminator at construction,
// so it is never necessary for the caller to do so.
public:
inline Builder(): Data::Builder(nulstr, 0) {}
inline Builder(char* text, uint size): Data::Builder(text, size) { text[size] = '\0'; }
inline char* c_str() const { return data(); }
inline operator char*() const { return data(); }
inline operator const char*() const { return data(); }
private:
static char nulstr[1];
};
} // namespace capnproto
#endif // CAPNPROTO_BLOB_H_
......@@ -45,6 +45,7 @@ TEST(Encoding, Simple) {
builder.setB(45);
builder.setC(67);
builder.initD().setX(55.25);
builder.setTx("foo");
{
List<int32_t>::Builder listBuilder = builder.initNums(5);
......@@ -146,6 +147,7 @@ TEST(Encoding, Simple) {
EXPECT_EQ(45, builder.getB());
EXPECT_EQ(67, builder.getC());
EXPECT_EQ(55.25, builder.getD().getX());
EXPECT_STREQ("foo", builder.getTx());
Foo::Reader reader(StructReader::readRoot(
segment->getStartPtr(), Foo::DEFAULT.words, segment, 4));
......@@ -154,6 +156,7 @@ TEST(Encoding, Simple) {
EXPECT_EQ(45, reader.getB());
EXPECT_EQ(67, reader.getC());
EXPECT_EQ(55.25, reader.getD().getX());
EXPECT_STREQ("foo", reader.getTx());
{
List<int32_t>::Reader listReader = reader.getNums();
......
......@@ -98,24 +98,24 @@ class IndexingIterator {
public:
IndexingIterator() = default;
inline Element operator*() { return (*container)[index]; }
inline TemporaryPointer<Element> operator->() {
inline Element operator*() const { return (*container)[index]; }
inline TemporaryPointer<Element> operator->() const {
return TemporaryPointer<Element>((*container)[index]);
}
inline Element operator[]( int off) { return (*container)[index]; }
inline Element operator[](uint off) { return (*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) { return IndexingIterator(container, index + amount); }
inline IndexingIterator operator-(uint amount) { return IndexingIterator(container, index - amount); }
inline IndexingIterator operator+( int amount) { return IndexingIterator(container, index + amount); }
inline IndexingIterator operator-( int amount) { return IndexingIterator(container, index - amount); }
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) { return index - other.index; }
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; }
......@@ -124,12 +124,12 @@ public:
// STL says comparing iterators of different containers is not allowed, so we only compare
// indices here.
inline bool operator==(const IndexingIterator& other) { return index == other.index; }
inline bool operator!=(const IndexingIterator& other) { return index != other.index; }
inline bool operator<=(const IndexingIterator& other) { return index <= other.index; }
inline bool operator>=(const IndexingIterator& other) { return index >= other.index; }
inline bool operator< (const IndexingIterator& other) { return index < other.index; }
inline bool operator> (const IndexingIterator& other) { 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; }
inline bool operator> (const IndexingIterator& other) const { return index > other.index; }
private:
Container* container;
......@@ -316,6 +316,90 @@ struct List<List<T>, false> {
};
};
template <>
struct List<Data, false> {
class Reader {
public:
Reader() = default;
inline explicit Reader(internal::ListReader reader): reader(reader) {}
inline uint size() { return reader.size() / ELEMENTS; }
inline Data::Reader operator[](uint index) {
return reader.getDataElement(index * REFERENCES);
}
typedef internal::IndexingIterator<Reader, Data::Reader> iterator;
inline iterator begin() { return iterator(this, 0); }
inline iterator end() { return iterator(this, size()); }
private:
internal::ListReader reader;
};
class Builder {
public:
Builder() = default;
inline explicit Builder(internal::ListBuilder builder): builder(builder) {}
inline uint size() { return builder.size() / ELEMENTS; }
inline Data::Builder operator[](uint index) {
return builder.getDataElement(index * REFERENCES);
}
inline Data::Builder init(uint index, uint size) {
return builder.initDataElement(index * REFERENCES, size * BYTES);
}
typedef internal::IndexingIterator<Builder, Data::Builder> iterator;
inline iterator begin() { return iterator(this, 0); }
inline iterator end() { return iterator(this, size()); }
private:
internal::ListBuilder builder;
};
};
template <>
struct List<Text, false> {
class Reader {
public:
Reader() = default;
inline explicit Reader(internal::ListReader reader): reader(reader) {}
inline uint size() { return reader.size() / ELEMENTS; }
inline Text::Reader operator[](uint index) {
return reader.getTextElement(index * REFERENCES);
}
typedef internal::IndexingIterator<Reader, Text::Reader> iterator;
inline iterator begin() { return iterator(this, 0); }
inline iterator end() { return iterator(this, size()); }
private:
internal::ListReader reader;
};
class Builder {
public:
Builder() = default;
inline explicit Builder(internal::ListBuilder builder): builder(builder) {}
inline uint size() { return builder.size() / ELEMENTS; }
inline Text::Builder operator[](uint index) {
return builder.getTextElement(index * REFERENCES);
}
inline Text::Builder init(uint index, uint size) {
return builder.initTextElement(index * REFERENCES, size * BYTES);
}
typedef internal::IndexingIterator<Builder, Text::Builder> iterator;
inline iterator begin() { return iterator(this, 0); }
inline iterator end() { return iterator(this, size()); }
private:
internal::ListBuilder builder;
};
};
} // namespace capnproto
#endif // CAPNPROTO_LIST_H_
This diff is collapsed.
......@@ -32,6 +32,7 @@
#include "macros.h"
#include "type-safety.h"
#include "blob.h"
namespace capnproto {
class SegmentReader;
......@@ -124,6 +125,23 @@ public:
// already allocated, it is allocated as a deep copy of the given default value (a trusted
// message). If the default value is null, an empty list is used.
Text::Builder initTextField(WireReferenceCount refIndex, ByteCount size) const;
// Initialize the text field to the given size in bytes (not including NUL terminator) and return
// a Text::Builder which can be used to fill in the content.
void setTextField(WireReferenceCount refIndex, Text::Reader value) const;
// Set the text field to a copy of the given text.
Text::Builder getTextField(WireReferenceCount refIndex,
const void* defaultValue, ByteCount defaultSize) const;
// Get the text field. If it is not initialized, initialize it to a copy of the given default.
Data::Builder initDataField(WireReferenceCount refIndex, ByteCount size) const;
void setDataField(WireReferenceCount refIndex, Data::Reader value) const;
Data::Builder getDataField(WireReferenceCount refIndex,
const void* defaultValue, ByteCount defaultSize) const;
// Same as *Text*, but for data blobs.
StructReader asReader() const;
// Gets a StructReader pointing at the same memory.
......@@ -174,6 +192,14 @@ public:
// Get the list field at the given index in the reference segment, or the default value if not
// initialized. The default value is allowed to be null, in which case an empty list is used.
Text::Reader getTextField(WireReferenceCount refIndex,
const void* defaultValue, ByteCount defaultSize) const;
// Gets the text field, or the given default value if not initialized.
Data::Reader getDataField(WireReferenceCount refIndex,
const void* defaultValue, ByteCount defaultSize) const;
// Gets the data field, or the given default value if not initialized.
private:
SegmentReader* segment; // Memory segment in which the struct resides.
......@@ -244,6 +270,20 @@ public:
// Get the existing list element at the given index. Returns an empty list if the element is
// not initialized.
Text::Builder initTextElement(WireReferenceCount index, ByteCount size) const;
// Initialize the text element to the given size in bytes (not including NUL terminator) and
// return a Text::Builder which can be used to fill in the content.
void setTextElement(WireReferenceCount index, Text::Reader value) const;
// Set the text element to a copy of the given text.
Text::Builder getTextElement(WireReferenceCount index) const;
// Get the text element. If it is not initialized, returns an empty Text::Builder.
Data::Builder initDataElement(WireReferenceCount index, ByteCount size) const;
void setDataElement(WireReferenceCount index, Data::Reader value) const;
Data::Builder getDataElement(WireReferenceCount index) const;
ListReader asReader(FieldSize elementSize) const;
// Get a ListReader pointing at the same memory. Use this version only for non-struct lists.
......@@ -283,6 +323,12 @@ public:
ListReader getListElement(WireReferenceCount index, FieldSize expectedElementSize) const;
// Get the list element at the given index.
Text::Reader getTextElement(WireReferenceCount index) const;
// Get the text element. If it is not initialized, returns an empty Text::Reader.
Data::Reader getDataElement(WireReferenceCount index) const;
// Get the data element. If it is not initialized, returns an empty Data::Reader.
private:
SegmentReader* segment; // Memory segment in which the list resides.
......
......@@ -49,12 +49,16 @@ hashString str =
MD5.hash $
UTF8.encode str
isPrimitive (BuiltinType _) = True
isPrimitive t@(BuiltinType _) = not $ isBlob t
isPrimitive (EnumType _) = True
isPrimitive (StructType _) = False
isPrimitive (InterfaceType _) = False
isPrimitive (ListType _) = False
isBlob (BuiltinType BuiltinText) = True
isBlob (BuiltinType BuiltinData) = True
isBlob _ = False
isStruct (StructType _) = True
isStruct _ = False
......@@ -67,6 +71,10 @@ isNonStructList _ = False
isStructList (ListType t) = isStruct t
isStructList _ = False
blobTypeString (BuiltinType BuiltinText) = "Text"
blobTypeString (BuiltinType BuiltinData) = "Data"
blobTypeString _ = error "Not a blob."
cxxTypeString (BuiltinType BuiltinVoid) = "void"
cxxTypeString (BuiltinType BuiltinBool) = "bool"
cxxTypeString (BuiltinType BuiltinInt8) = " ::int8_t"
......@@ -79,8 +87,8 @@ cxxTypeString (BuiltinType BuiltinUInt32) = " ::uint32_t"
cxxTypeString (BuiltinType BuiltinUInt64) = " ::uint64_t"
cxxTypeString (BuiltinType BuiltinFloat32) = "float"
cxxTypeString (BuiltinType BuiltinFloat64) = "double"
cxxTypeString (BuiltinType BuiltinText) = "TODO"
cxxTypeString (BuiltinType BuiltinData) = "TODO"
cxxTypeString (BuiltinType BuiltinText) = " ::capnproto::Text"
cxxTypeString (BuiltinType BuiltinData) = " ::capnproto::Data"
cxxTypeString (EnumType desc) = enumName desc -- TODO: full name
cxxTypeString (StructType desc) = structName desc -- TODO: full name
cxxTypeString (InterfaceType desc) = interfaceName desc -- TODO: full name
......@@ -146,11 +154,15 @@ elementType _ = error "Called elementType on non-list."
repeatedlyTake _ [] = []
repeatedlyTake n l = take n l : repeatedlyTake n (drop n l)
defaultBytesContext :: Monad m => (String -> MuType m) -> [Word8] -> MuContext m
defaultBytesContext parent bytes = mkStrContext context where
defaultBytesContext :: Monad m => (String -> MuType m) -> TypeDesc -> [Word8] -> MuContext m
defaultBytesContext parent t bytes = mkStrContext context where
codeLines = map (delimit ", ") $ repeatedlyTake 8 $ map (printf "%3d") bytes
context "defaultByteList" = MuVariable $ delimit ",\n " codeLines
context "defaultWordCount" = MuVariable $ div (length bytes + 7) 8
context "defaultBlobSize" = case t of
BuiltinType BuiltinText -> MuVariable (length bytes - 1) -- Don't include NUL terminator.
BuiltinType BuiltinData -> MuVariable (length bytes)
_ -> error "defaultBlobSize used on non-blob."
context s = parent s
fieldContext parent desc = mkStrContext context where
......@@ -159,15 +171,17 @@ fieldContext parent desc = mkStrContext context where
context "fieldTitleCase" = MuVariable $ toTitleCase $ fieldName desc
context "fieldUpperCase" = MuVariable $ toUpperCaseWithUnderscores $ fieldName desc
context "fieldIsPrimitive" = MuBool $ isPrimitive $ fieldType desc
context "fieldIsBlob" = MuBool $ isBlob $ fieldType desc
context "fieldIsStruct" = MuBool $ isStruct $ fieldType desc
context "fieldIsList" = MuBool $ isList $ fieldType desc
context "fieldIsNonStructList" = MuBool $ isNonStructList $ fieldType desc
context "fieldIsStructList" = MuBool $ isStructList $ fieldType desc
context "fieldDefaultBytes" =
case fieldDefaultValue desc >>= defaultValueBytes (fieldType desc) of
Just v -> MuList [defaultBytesContext context v]
Just v -> MuList [defaultBytesContext context (fieldType desc) v]
Nothing -> muNull
context "fieldType" = MuVariable $ cxxTypeString $ fieldType desc
context "fieldBlobType" = MuVariable $ blobTypeString $ fieldType desc
context "fieldOffset" = MuVariable $ fieldOffset desc
context "fieldDefaultValue" = case fieldDefaultValue desc of
Just v -> MuVariable $ cxxValueString v
......@@ -184,7 +198,7 @@ structContext parent desc = mkStrContext context where
context "structDataSize" = MuVariable $ packingDataSize $ structPacking desc
context "structReferenceCount" = MuVariable $ packingReferenceCount $ structPacking desc
context "structChildren" = MuList [] -- TODO
context "structDefault" = MuList [defaultBytesContext context
context "structDefault" = MuList [defaultBytesContext context (StructType desc)
(encodeMessage (StructType desc) (StructValueDesc []))]
context s = parent s
......
......@@ -66,6 +66,9 @@ public:
{{#fieldIsPrimitive}}
inline {{fieldType}} get{{fieldTitleCase}}();
{{/fieldIsPrimitive}}
{{#fieldIsBlob}}
inline {{fieldType}}::Reader get{{fieldTitleCase}}();
{{/fieldIsBlob}}
{{#fieldIsStruct}}
inline {{fieldType}}::Reader get{{fieldTitleCase}}();
{{/fieldIsStruct}}
......@@ -90,6 +93,11 @@ public:
inline {{fieldType}} get{{fieldTitleCase}}();
inline void set{{fieldTitleCase}}({{fieldType}} value);
{{/fieldIsPrimitive}}
{{#fieldIsBlob}}
inline {{fieldType}}::Builder get{{fieldTitleCase}}();
inline void set{{fieldTitleCase}}({{fieldType}}::Reader value);
inline {{fieldType}}::Builder init{{fieldTitleCase}}(unsigned int size);
{{/fieldIsBlob}}
{{#fieldIsStruct}}
inline {{fieldType}}::Builder init{{fieldTitleCase}}();
inline {{fieldType}}::Builder get{{fieldTitleCase}}();
......@@ -117,12 +125,22 @@ inline {{fieldType}} {{structName}}::Reader::get{{fieldTitleCase}}() {
{{fieldOffset}} * ::capnproto::ELEMENTS, {{fieldDefaultValue}});
}
{{/fieldIsPrimitive}}
{{#fieldIsBlob}}
inline {{fieldType}}::Reader {{structName}}::Reader::get{{fieldTitleCase}}() {
return _reader.get{{fieldBlobType}}Field(
{{fieldOffset}} * ::capnproto::REFERENCES,
{{#fieldDefaultBytes}}
DEFAULT_{{fieldUpperCase}}.words, {{defaultBlobSize}} * ::capnproto::BYTES
{{/fieldDefaultBytes}}
{{^fieldDefaultBytes}}nullptr, 0 * ::capnproto::BYTES{{/fieldDefaultBytes}});
}
{{/fieldIsBlob}}
{{#fieldIsStruct}}
inline {{fieldType}}::Reader {{structName}}::Reader::get{{fieldTitleCase}}() {
{{! TODO: Support per-field default values. }}
return {{fieldType}}::Reader(_reader.getStructField(
{{fieldOffset}} * ::capnproto::REFERENCES,
{{#fieldDefaultBytes}}DEFAULT_{{fieldUpperCase}}{{/fieldDefaultBytes}}
{{#fieldDefaultBytes}}DEFAULT_{{fieldUpperCase}}.words{{/fieldDefaultBytes}}
{{^fieldDefaultBytes}}{{fieldType}}::DEFAULT.words{{/fieldDefaultBytes}}));
}
{{/fieldIsStruct}}
......@@ -150,6 +168,22 @@ inline void {{structName}}::Builder::set{{fieldTitleCase}}({{fieldType}} value)
{{fieldOffset}} * ::capnproto::ELEMENTS, value);
}
{{/fieldIsPrimitive}}
{{#fieldIsBlob}}
inline {{fieldType}}::Builder {{structName}}::Builder::get{{fieldTitleCase}}() {
return _builder.get{{fieldBlobType}}Field({{fieldOffset}} * ::capnproto::REFERENCES,
{{#fieldDefaultBytes}}
DEFAULT_{{fieldUpperCase}}.words, {{defaultBlobSize}} * ::capnproto::BYTES
{{/fieldDefaultBytes}}
{{^fieldDefaultBytes}}nullptr, 0 * ::capnproto::BYTES{{/fieldDefaultBytes}});
}
inline void {{structName}}::Builder::set{{fieldTitleCase}}({{fieldType}}::Reader value) {
_builder.set{{fieldBlobType}}Field({{fieldOffset}} * ::capnproto::REFERENCES, value);
}
inline {{fieldType}}::Builder {{structName}}::Builder::init{{fieldTitleCase}}(unsigned int size) {
return _builder.init{{fieldBlobType}}Field(
{{fieldOffset}} * ::capnproto::REFERENCES, size * ::capnproto::BYTES);
}
{{/fieldIsBlob}}
{{#fieldIsStruct}}
inline {{fieldType}}::Builder {{structName}}::Builder::init{{fieldTitleCase}}() {
return {{fieldType}}::Builder(_builder.initStructField(
......@@ -159,7 +193,7 @@ inline {{fieldType}}::Builder {{structName}}::Builder::get{{fieldTitleCase}}() {
{{! TODO: Support per-field default values. }}
return {{fieldType}}::Builder(_builder.getStructField(
{{fieldOffset}} * ::capnproto::REFERENCES,
{{#fieldDefaultBytes}}DEFAULT_{{fieldUpperCase}}{{/fieldDefaultBytes}}
{{#fieldDefaultBytes}}DEFAULT_{{fieldUpperCase}}.words{{/fieldDefaultBytes}}
{{^fieldDefaultBytes}}{{fieldType}}::DEFAULT.words{{/fieldDefaultBytes}}));
}
{{/fieldIsStruct}}
......
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