//===- MsgPackTypes.h - MsgPack Types ---------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // /// \file /// This is a data structure for representing MessagePack "documents", with /// methods to go to and from MessagePack. The types also specialize YAMLIO /// traits in order to go to and from YAML. // //===----------------------------------------------------------------------===// #include "llvm/ADT/Optional.h" #include "llvm/BinaryFormat/MsgPackReader.h" #include "llvm/BinaryFormat/MsgPackWriter.h" #include "llvm/Support/Casting.h" #include "llvm/Support/YAMLTraits.h" #include #ifndef LLVM_BINARYFORMAT_MSGPACKTYPES_H #define LLVM_BINARYFORMAT_MSGPACKTYPES_H namespace llvm { namespace msgpack { class Node; /// Short-hand for a Node pointer. using NodePtr = std::shared_ptr; /// Short-hand for an Optional Node pointer. using OptNodePtr = Optional; /// Abstract base-class which can be any MessagePack type. class Node { public: enum NodeKind { NK_Scalar, NK_Array, NK_Map, }; private: virtual void anchor() = 0; const NodeKind Kind; static Expected readArray(Reader &MPReader, size_t Length); static Expected readMap(Reader &MPReader, size_t Length); public: NodeKind getKind() const { return Kind; } /// Construct a Node. Used by derived classes to track kind information. Node(NodeKind Kind) : Kind(Kind) {} virtual ~Node() = default; /// Read from a MessagePack reader \p MPReader, returning an error if one is /// encountered, or None if \p MPReader is at the end of stream, or some Node /// pointer if some type is read. static Expected read(Reader &MPReader); /// Write to a MessagePack writer \p MPWriter. virtual void write(Writer &MPWriter) = 0; }; /// A MessagePack scalar. class ScalarNode : public Node { public: enum ScalarKind { SK_Int, SK_UInt, SK_Nil, SK_Boolean, SK_Float, SK_String, SK_Binary, }; private: void anchor() override; void destroy(); ScalarKind SKind; union { int64_t IntValue; uint64_t UIntValue; bool BoolValue; double FloatValue; std::string StringValue; }; public: /// Construct an Int ScalarNode. ScalarNode(int64_t IntValue); /// Construct an Int ScalarNode. ScalarNode(int32_t IntValue); /// Construct an UInt ScalarNode. ScalarNode(uint64_t UIntValue); /// Construct an UInt ScalarNode. ScalarNode(uint32_t UIntValue); /// Construct a Nil ScalarNode. ScalarNode(); /// Construct a Boolean ScalarNode. ScalarNode(bool BoolValue); /// Construct a Float ScalarNode. ScalarNode(double FloatValue); /// Construct a String ScalarNode. ScalarNode(StringRef StringValue); /// Construct a String ScalarNode. ScalarNode(const char *StringValue); /// Construct a String ScalarNode. ScalarNode(std::string &&StringValue); /// Construct a Binary ScalarNode. ScalarNode(MemoryBufferRef BinaryValue); ~ScalarNode(); ScalarNode &operator=(const ScalarNode &RHS) = delete; /// A ScalarNode can only be move assigned. ScalarNode &operator=(ScalarNode &&RHS); /// Change the kind of this ScalarNode, zero initializing it to the new type. void setScalarKind(ScalarKind SKind) { switch (SKind) { case SK_Int: *this = int64_t(0); break; case SK_UInt: *this = uint64_t(0); break; case SK_Boolean: *this = false; break; case SK_Float: *this = 0.0; break; case SK_String: *this = StringRef(); break; case SK_Binary: *this = MemoryBufferRef("", ""); break; case SK_Nil: *this = ScalarNode(); break; } } /// Get the current kind of ScalarNode. ScalarKind getScalarKind() { return SKind; } /// Get the value of an Int scalar. /// /// \warning Assumes getScalarKind() == SK_Int int64_t getInt() { assert(SKind == SK_Int); return IntValue; } /// Get the value of a UInt scalar. /// /// \warning Assumes getScalarKind() == SK_UInt uint64_t getUInt() { assert(SKind == SK_UInt); return UIntValue; } /// Get the value of an Boolean scalar. /// /// \warning Assumes getScalarKind() == SK_Boolean bool getBool() { assert(SKind == SK_Boolean); return BoolValue; } /// Get the value of an Float scalar. /// /// \warning Assumes getScalarKind() == SK_Float double getFloat() { assert(SKind == SK_Float); return FloatValue; } /// Get the value of a String scalar. /// /// \warning Assumes getScalarKind() == SK_String StringRef getString() { assert(SKind == SK_String); return StringValue; } /// Get the value of a Binary scalar. /// /// \warning Assumes getScalarKind() == SK_Binary StringRef getBinary() { assert(SKind == SK_Binary); return StringValue; } static bool classof(const Node *N) { return N->getKind() == NK_Scalar; } void write(Writer &MPWriter) override; /// Parse a YAML scalar of the current ScalarKind from \p ScalarStr. /// /// \returns An empty string on success, otherwise an error message. StringRef inputYAML(StringRef ScalarStr); /// Output a YAML scalar of the current ScalarKind into \p OS. void outputYAML(raw_ostream &OS) const; /// Determine which YAML quoting type the current value would need when /// output. yaml::QuotingType mustQuoteYAML(StringRef ScalarStr) const; /// Get the YAML tag for the current ScalarKind. StringRef getYAMLTag() const; /// Flag which affects how the type handles YAML tags when reading and /// writing. /// /// When false, tags are used when reading and writing. When reading, the tag /// is used to decide the ScalarKind before parsing. When writing, the tag is /// output along with the value. /// /// When true, tags are ignored when reading and writing. When reading, the /// ScalarKind is always assumed to be String. When writing, the tag is not /// output. bool IgnoreTag = false; static const char *IntTag; static const char *NilTag; static const char *BooleanTag; static const char *FloatTag; static const char *StringTag; static const char *BinaryTag; }; class ArrayNode : public Node, public std::vector { void anchor() override; public: ArrayNode() : Node(NK_Array) {} static bool classof(const Node *N) { return N->getKind() == NK_Array; } void write(Writer &MPWriter) override { MPWriter.writeArraySize(this->size()); for (auto &N : *this) N->write(MPWriter); } }; class MapNode : public Node, public StringMap { void anchor() override; public: MapNode() : Node(NK_Map) {} static bool classof(const Node *N) { return N->getKind() == NK_Map; } void write(Writer &MPWriter) override { MPWriter.writeMapSize(this->size()); for (auto &N : *this) { MPWriter.write(N.first()); N.second->write(MPWriter); } } }; } // end namespace msgpack namespace yaml { template <> struct PolymorphicTraits { static NodeKind getKind(const msgpack::NodePtr &N) { if (isa(*N)) return NodeKind::Scalar; if (isa(*N)) return NodeKind::Map; if (isa(*N)) return NodeKind::Sequence; llvm_unreachable("NodeKind not supported"); } static msgpack::ScalarNode &getAsScalar(msgpack::NodePtr &N) { if (!N || !isa(*N)) N.reset(new msgpack::ScalarNode()); return *cast(N.get()); } static msgpack::MapNode &getAsMap(msgpack::NodePtr &N) { if (!N || !isa(*N)) N.reset(new msgpack::MapNode()); return *cast(N.get()); } static msgpack::ArrayNode &getAsSequence(msgpack::NodePtr &N) { if (!N || !isa(*N)) N.reset(new msgpack::ArrayNode()); return *cast(N.get()); } }; template <> struct TaggedScalarTraits { static void output(const msgpack::ScalarNode &S, void *Ctxt, raw_ostream &ScalarOS, raw_ostream &TagOS) { if (!S.IgnoreTag) TagOS << S.getYAMLTag(); S.outputYAML(ScalarOS); } static StringRef input(StringRef ScalarStr, StringRef Tag, void *Ctxt, msgpack::ScalarNode &S) { if (Tag == msgpack::ScalarNode::IntTag) { S.setScalarKind(msgpack::ScalarNode::SK_UInt); if (S.inputYAML(ScalarStr) == StringRef()) return StringRef(); S.setScalarKind(msgpack::ScalarNode::SK_Int); return S.inputYAML(ScalarStr); } if (S.IgnoreTag || Tag == msgpack::ScalarNode::StringTag || Tag == "tag:yaml.org,2002:str") S.setScalarKind(msgpack::ScalarNode::SK_String); else if (Tag == msgpack::ScalarNode::NilTag) S.setScalarKind(msgpack::ScalarNode::SK_Nil); else if (Tag == msgpack::ScalarNode::BooleanTag) S.setScalarKind(msgpack::ScalarNode::SK_Boolean); else if (Tag == msgpack::ScalarNode::FloatTag) S.setScalarKind(msgpack::ScalarNode::SK_Float); else if (Tag == msgpack::ScalarNode::StringTag) S.setScalarKind(msgpack::ScalarNode::SK_String); else if (Tag == msgpack::ScalarNode::BinaryTag) S.setScalarKind(msgpack::ScalarNode::SK_Binary); else return "Unsupported messagepack tag"; return S.inputYAML(ScalarStr); } static QuotingType mustQuote(const msgpack::ScalarNode &S, StringRef Str) { return S.mustQuoteYAML(Str); } }; template <> struct CustomMappingTraits { static void inputOne(IO &IO, StringRef Key, msgpack::MapNode &M) { IO.mapRequired(Key.str().c_str(), M[Key]); } static void output(IO &IO, msgpack::MapNode &M) { for (auto &N : M) IO.mapRequired(N.getKey().str().c_str(), N.getValue()); } }; template <> struct SequenceTraits { static size_t size(IO &IO, msgpack::ArrayNode &A) { return A.size(); } static msgpack::NodePtr &element(IO &IO, msgpack::ArrayNode &A, size_t Index) { if (Index >= A.size()) A.resize(Index + 1); return A[Index]; } }; } // end namespace yaml } // end namespace llvm #endif // LLVM_BINARYFORMAT_MSGPACKTYPES_H