aboutsummaryrefslogtreecommitdiff
path: root/include/cppbor/cppbor.h
diff options
context:
space:
mode:
Diffstat (limited to 'include/cppbor/cppbor.h')
-rw-r--r--include/cppbor/cppbor.h117
1 files changed, 70 insertions, 47 deletions
diff --git a/include/cppbor/cppbor.h b/include/cppbor/cppbor.h
index f9d371e..1409bf8 100644
--- a/include/cppbor/cppbor.h
+++ b/include/cppbor/cppbor.h
@@ -63,7 +63,7 @@ class Bool;
class Array;
class Map;
class Null;
-class Semantic;
+class SemanticTag;
class EncodedItem;
/**
@@ -128,8 +128,39 @@ class Item {
const Map* asMap() const { return const_cast<Item*>(this)->asMap(); }
virtual Array* asArray() { return nullptr; }
const Array* asArray() const { return const_cast<Item*>(this)->asArray(); }
- virtual Semantic* asSemantic() { return nullptr; }
- const Semantic* asSemantic() const { return const_cast<Item*>(this)->asSemantic(); }
+
+ // Like those above, these methods safely downcast an Item when it's actually a SemanticTag.
+ // However, if you think you want to use these methods, you probably don't. Typically, the way
+ // you should handle tagged Items is by calling the appropriate method above (e.g. asInt())
+ // which will return a pointer to the tagged Item, rather than the tag itself. If you want to
+ // find out if the Item* you're holding is to something with one or more tags applied, see
+ // semanticTagCount() and semanticTag() below.
+ virtual SemanticTag* asSemanticTag() { return nullptr; }
+ const SemanticTag* asSemanticTag() const { return const_cast<Item*>(this)->asSemanticTag(); }
+
+ /**
+ * Returns the number of semantic tags prefixed to this Item.
+ */
+ virtual size_t semanticTagCount() const { return 0; }
+
+ /**
+ * Returns the semantic tag at the specified nesting level `nesting`, iff `nesting` is less than
+ * the value returned by semanticTagCount().
+ *
+ * CBOR tags are "nested" by applying them in sequence. The "rightmost" tag is the "inner" tag.
+ * That is, given:
+ *
+ * 4(5(6("AES"))) which encodes as C1 C2 C3 63 414553
+ *
+ * The tstr "AES" is tagged with 6. The combined entity ("AES" tagged with 6) is tagged with 5,
+ * etc. So in this example, semanticTagCount() would return 3, and semanticTag(0) would return
+ * 5 semanticTag(1) would return 5 and semanticTag(2) would return 4. For values of n > 2,
+ * semanticTag(n) will return 0, but this is a meaningless value.
+ *
+ * If this layering is confusing, you probably don't have to worry about it. Nested tagging does
+ * not appear to be common, so semanticTag(0) is the only one you'll use.
+ */
+ virtual uint64_t semanticTag(size_t /* nesting */ = 0) const { return 0; }
/**
* Returns true if this is a "compound" item, i.e. one that contains one or more other items.
@@ -614,64 +645,58 @@ class Map : public Item {
bool mCanonicalized = false;
};
-class Semantic : public Item {
+class SemanticTag : public Item {
public:
static constexpr MajorType kMajorType = SEMANTIC;
template <typename T>
- explicit Semantic(uint64_t value, T&& child);
-
- Semantic(const Semantic& other) = delete;
- Semantic(Semantic&&) = default;
- Semantic& operator=(const Semantic& other) = delete;
- Semantic& operator=(Semantic&&) = default;
-
- bool operator==(const Semantic& other) const&;
+ SemanticTag(uint64_t tagValue, T&& taggedItem);
+ SemanticTag(const SemanticTag& other) = delete;
+ SemanticTag(SemanticTag&&) = default;
+ SemanticTag& operator=(const SemanticTag& other) = delete;
+ SemanticTag& operator=(SemanticTag&&) = default;
+
+ bool operator==(const SemanticTag& other) const& {
+ return mValue == other.mValue && *mTaggedItem == *other.mTaggedItem;
+ }
bool isCompound() const override { return true; }
- virtual size_t size() const {
- assertInvariant();
- return 1;
- }
+ virtual size_t size() const { return 1; }
- size_t encodedSize() const override {
- return std::accumulate(mEntries.begin(), mEntries.end(), headerSize(mValue),
- [](size_t sum, auto& entry) { return sum + entry->encodedSize(); });
- }
+ // Encoding returns the tag + enclosed Item.
+ size_t encodedSize() const override { return headerSize(mValue) + mTaggedItem->encodedSize(); }
using Item::encode; // Make base versions visible.
uint8_t* encode(uint8_t* pos, const uint8_t* end) const override;
void encode(EncodeCallback encodeCallback) const override;
- MajorType type() const override { return kMajorType; }
- Semantic* asSemantic() override { return this; }
-
- const std::unique_ptr<Item>& child() const {
- assertInvariant();
- return mEntries[0];
- }
-
- std::unique_ptr<Item>& child() {
- assertInvariant();
- return mEntries[0];
- }
+ // type() is a bit special. In normal usage it should return the wrapped type, but during
+ // parsing when we haven't yet parsed the tagged item, it needs to return SEMANTIC.
+ MajorType type() const override { return mTaggedItem ? mTaggedItem->type() : SEMANTIC; }
+ SemanticTag* asSemanticTag() override { return this; }
+
+ // Type information reflects the enclosed Item. Note that if the immediately-enclosed Item is
+ // another tag, these methods will recurse down to the non-tag Item.
+ Int* asInt() override { return mTaggedItem->asInt(); }
+ Uint* asUint() override { return mTaggedItem->asUint(); }
+ Nint* asNint() override { return mTaggedItem->asNint(); }
+ Tstr* asTstr() override { return mTaggedItem->asTstr(); }
+ Bstr* asBstr() override { return mTaggedItem->asBstr(); }
+ Simple* asSimple() override { return mTaggedItem->asSimple(); }
+ Map* asMap() override { return mTaggedItem->asMap(); }
+ Array* asArray() override { return mTaggedItem->asArray(); }
- uint64_t value() const { return mValue; }
+ std::unique_ptr<Item> clone() const override;
- std::unique_ptr<Item> clone() const override {
- assertInvariant();
- return std::make_unique<Semantic>(mValue, mEntries[0]->clone());
- }
+ size_t semanticTagCount() const override;
+ uint64_t semanticTag(size_t nesting = 0) const override;
protected:
- Semantic() = default;
- Semantic(uint64_t value) : mValue(value) {}
+ SemanticTag() = default;
+ SemanticTag(uint64_t value) : mValue(value) {}
uint64_t mValue;
- std::vector<std::unique_ptr<Item>> mEntries;
-
- private:
- void assertInvariant() const;
+ std::unique_ptr<Item> mTaggedItem;
};
/**
@@ -955,9 +980,7 @@ const std::unique_ptr<Item>& Map::get(Key key) const {
}
template <typename T>
-Semantic::Semantic(uint64_t value, T&& child) : mValue(value) {
- mEntries.reserve(1);
- mEntries.push_back(details::makeItem(std::forward<T>(child)));
-}
+SemanticTag::SemanticTag(uint64_t value, T&& taggedItem)
+ : mValue(value), mTaggedItem(details::makeItem(std::forward<T>(taggedItem))) {}
} // namespace cppbor