1 //===- MsgPackTypes.h - MsgPack Types ---------------------------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 /// \file 11 /// This is a data structure for representing MessagePack "documents", with 12 /// methods to go to and from MessagePack. The types also specialize YAMLIO 13 /// traits in order to go to and from YAML. 14 // 15 //===----------------------------------------------------------------------===// 16 17 #include "llvm/ADT/Optional.h" 18 #include "llvm/BinaryFormat/MsgPackReader.h" 19 #include "llvm/BinaryFormat/MsgPackWriter.h" 20 #include "llvm/Support/Casting.h" 21 #include "llvm/Support/YAMLTraits.h" 22 #include <vector> 23 24 #ifndef LLVM_BINARYFORMAT_MSGPACKTYPES_H 25 #define LLVM_BINARYFORMAT_MSGPACKTYPES_H 26 27 namespace llvm { 28 namespace msgpack { 29 30 class Node; 31 32 /// Short-hand for a Node pointer. 33 using NodePtr = std::shared_ptr<Node>; 34 35 /// Short-hand for an Optional Node pointer. 36 using OptNodePtr = Optional<NodePtr>; 37 38 /// Abstract base-class which can be any MessagePack type. 39 class Node { 40 public: 41 enum NodeKind { 42 NK_Scalar, 43 NK_Array, 44 NK_Map, 45 }; 46 47 private: 48 virtual void anchor() = 0; 49 const NodeKind Kind; 50 51 static Expected<OptNodePtr> readArray(Reader &MPReader, size_t Length); 52 static Expected<OptNodePtr> readMap(Reader &MPReader, size_t Length); 53 54 public: getKind()55 NodeKind getKind() const { return Kind; } 56 57 /// Construct a Node. Used by derived classes to track kind information. Node(NodeKind Kind)58 Node(NodeKind Kind) : Kind(Kind) {} 59 60 virtual ~Node() = default; 61 62 /// Read from a MessagePack reader \p MPReader, returning an error if one is 63 /// encountered, or None if \p MPReader is at the end of stream, or some Node 64 /// pointer if some type is read. 65 static Expected<OptNodePtr> read(Reader &MPReader); 66 67 /// Write to a MessagePack writer \p MPWriter. 68 virtual void write(Writer &MPWriter) = 0; 69 }; 70 71 /// A MessagePack scalar. 72 class ScalarNode : public Node { 73 public: 74 enum ScalarKind { 75 SK_Int, 76 SK_UInt, 77 SK_Nil, 78 SK_Boolean, 79 SK_Float, 80 SK_String, 81 SK_Binary, 82 }; 83 84 private: 85 void anchor() override; 86 87 void destroy(); 88 89 ScalarKind SKind; 90 91 union { 92 int64_t IntValue; 93 uint64_t UIntValue; 94 bool BoolValue; 95 double FloatValue; 96 std::string StringValue; 97 }; 98 99 public: 100 /// Construct an Int ScalarNode. 101 ScalarNode(int64_t IntValue); 102 /// Construct an Int ScalarNode. 103 ScalarNode(int32_t IntValue); 104 /// Construct an UInt ScalarNode. 105 ScalarNode(uint64_t UIntValue); 106 /// Construct an UInt ScalarNode. 107 ScalarNode(uint32_t UIntValue); 108 /// Construct a Nil ScalarNode. 109 ScalarNode(); 110 /// Construct a Boolean ScalarNode. 111 ScalarNode(bool BoolValue); 112 /// Construct a Float ScalarNode. 113 ScalarNode(double FloatValue); 114 /// Construct a String ScalarNode. 115 ScalarNode(StringRef StringValue); 116 /// Construct a String ScalarNode. 117 ScalarNode(const char *StringValue); 118 /// Construct a String ScalarNode. 119 ScalarNode(std::string &&StringValue); 120 /// Construct a Binary ScalarNode. 121 ScalarNode(MemoryBufferRef BinaryValue); 122 123 ~ScalarNode(); 124 125 ScalarNode &operator=(const ScalarNode &RHS) = delete; 126 /// A ScalarNode can only be move assigned. 127 ScalarNode &operator=(ScalarNode &&RHS); 128 129 /// Change the kind of this ScalarNode, zero initializing it to the new type. setScalarKind(ScalarKind SKind)130 void setScalarKind(ScalarKind SKind) { 131 switch (SKind) { 132 case SK_Int: 133 *this = int64_t(0); 134 break; 135 case SK_UInt: 136 *this = uint64_t(0); 137 break; 138 case SK_Boolean: 139 *this = false; 140 break; 141 case SK_Float: 142 *this = 0.0; 143 break; 144 case SK_String: 145 *this = StringRef(); 146 break; 147 case SK_Binary: 148 *this = MemoryBufferRef("", ""); 149 break; 150 case SK_Nil: 151 *this = ScalarNode(); 152 break; 153 } 154 } 155 156 /// Get the current kind of ScalarNode. getScalarKind()157 ScalarKind getScalarKind() { return SKind; } 158 159 /// Get the value of an Int scalar. 160 /// 161 /// \warning Assumes getScalarKind() == SK_Int getInt()162 int64_t getInt() { 163 assert(SKind == SK_Int); 164 return IntValue; 165 } 166 167 /// Get the value of a UInt scalar. 168 /// 169 /// \warning Assumes getScalarKind() == SK_UInt getUInt()170 uint64_t getUInt() { 171 assert(SKind == SK_UInt); 172 return UIntValue; 173 } 174 175 /// Get the value of an Boolean scalar. 176 /// 177 /// \warning Assumes getScalarKind() == SK_Boolean getBool()178 bool getBool() { 179 assert(SKind == SK_Boolean); 180 return BoolValue; 181 } 182 183 /// Get the value of an Float scalar. 184 /// 185 /// \warning Assumes getScalarKind() == SK_Float getFloat()186 double getFloat() { 187 assert(SKind == SK_Float); 188 return FloatValue; 189 } 190 191 /// Get the value of a String scalar. 192 /// 193 /// \warning Assumes getScalarKind() == SK_String getString()194 StringRef getString() { 195 assert(SKind == SK_String); 196 return StringValue; 197 } 198 199 /// Get the value of a Binary scalar. 200 /// 201 /// \warning Assumes getScalarKind() == SK_Binary getBinary()202 StringRef getBinary() { 203 assert(SKind == SK_Binary); 204 return StringValue; 205 } 206 classof(const Node * N)207 static bool classof(const Node *N) { return N->getKind() == NK_Scalar; } 208 209 void write(Writer &MPWriter) override; 210 211 /// Parse a YAML scalar of the current ScalarKind from \p ScalarStr. 212 /// 213 /// \returns An empty string on success, otherwise an error message. 214 StringRef inputYAML(StringRef ScalarStr); 215 216 /// Output a YAML scalar of the current ScalarKind into \p OS. 217 void outputYAML(raw_ostream &OS) const; 218 219 /// Determine which YAML quoting type the current value would need when 220 /// output. 221 yaml::QuotingType mustQuoteYAML(StringRef ScalarStr) const; 222 223 /// Get the YAML tag for the current ScalarKind. 224 StringRef getYAMLTag() const; 225 226 /// Flag which affects how the type handles YAML tags when reading and 227 /// writing. 228 /// 229 /// When false, tags are used when reading and writing. When reading, the tag 230 /// is used to decide the ScalarKind before parsing. When writing, the tag is 231 /// output along with the value. 232 /// 233 /// When true, tags are ignored when reading and writing. When reading, the 234 /// ScalarKind is always assumed to be String. When writing, the tag is not 235 /// output. 236 bool IgnoreTag = false; 237 238 static const char *IntTag; 239 static const char *NilTag; 240 static const char *BooleanTag; 241 static const char *FloatTag; 242 static const char *StringTag; 243 static const char *BinaryTag; 244 }; 245 246 class ArrayNode : public Node, public std::vector<NodePtr> { 247 void anchor() override; 248 249 public: ArrayNode()250 ArrayNode() : Node(NK_Array) {} classof(const Node * N)251 static bool classof(const Node *N) { return N->getKind() == NK_Array; } 252 write(Writer & MPWriter)253 void write(Writer &MPWriter) override { 254 MPWriter.writeArraySize(this->size()); 255 for (auto &N : *this) 256 N->write(MPWriter); 257 } 258 }; 259 260 class MapNode : public Node, public StringMap<NodePtr> { 261 void anchor() override; 262 263 public: MapNode()264 MapNode() : Node(NK_Map) {} classof(const Node * N)265 static bool classof(const Node *N) { return N->getKind() == NK_Map; } 266 write(Writer & MPWriter)267 void write(Writer &MPWriter) override { 268 MPWriter.writeMapSize(this->size()); 269 for (auto &N : *this) { 270 MPWriter.write(N.first()); 271 N.second->write(MPWriter); 272 } 273 } 274 }; 275 276 } // end namespace msgpack 277 278 namespace yaml { 279 280 template <> struct PolymorphicTraits<msgpack::NodePtr> { 281 static NodeKind getKind(const msgpack::NodePtr &N) { 282 if (isa<msgpack::ScalarNode>(*N)) 283 return NodeKind::Scalar; 284 if (isa<msgpack::MapNode>(*N)) 285 return NodeKind::Map; 286 if (isa<msgpack::ArrayNode>(*N)) 287 return NodeKind::Sequence; 288 llvm_unreachable("NodeKind not supported"); 289 } 290 static msgpack::ScalarNode &getAsScalar(msgpack::NodePtr &N) { 291 if (!N || !isa<msgpack::ScalarNode>(*N)) 292 N.reset(new msgpack::ScalarNode()); 293 return *cast<msgpack::ScalarNode>(N.get()); 294 } 295 static msgpack::MapNode &getAsMap(msgpack::NodePtr &N) { 296 if (!N || !isa<msgpack::MapNode>(*N)) 297 N.reset(new msgpack::MapNode()); 298 return *cast<msgpack::MapNode>(N.get()); 299 } 300 static msgpack::ArrayNode &getAsSequence(msgpack::NodePtr &N) { 301 if (!N || !isa<msgpack::ArrayNode>(*N)) 302 N.reset(new msgpack::ArrayNode()); 303 return *cast<msgpack::ArrayNode>(N.get()); 304 } 305 }; 306 307 template <> struct TaggedScalarTraits<msgpack::ScalarNode> { 308 static void output(const msgpack::ScalarNode &S, void *Ctxt, 309 raw_ostream &ScalarOS, raw_ostream &TagOS) { 310 if (!S.IgnoreTag) 311 TagOS << S.getYAMLTag(); 312 S.outputYAML(ScalarOS); 313 } 314 315 static StringRef input(StringRef ScalarStr, StringRef Tag, void *Ctxt, 316 msgpack::ScalarNode &S) { 317 if (Tag == msgpack::ScalarNode::IntTag) { 318 S.setScalarKind(msgpack::ScalarNode::SK_UInt); 319 if (S.inputYAML(ScalarStr) == StringRef()) 320 return StringRef(); 321 S.setScalarKind(msgpack::ScalarNode::SK_Int); 322 return S.inputYAML(ScalarStr); 323 } 324 325 if (S.IgnoreTag || Tag == msgpack::ScalarNode::StringTag || 326 Tag == "tag:yaml.org,2002:str") 327 S.setScalarKind(msgpack::ScalarNode::SK_String); 328 else if (Tag == msgpack::ScalarNode::NilTag) 329 S.setScalarKind(msgpack::ScalarNode::SK_Nil); 330 else if (Tag == msgpack::ScalarNode::BooleanTag) 331 S.setScalarKind(msgpack::ScalarNode::SK_Boolean); 332 else if (Tag == msgpack::ScalarNode::FloatTag) 333 S.setScalarKind(msgpack::ScalarNode::SK_Float); 334 else if (Tag == msgpack::ScalarNode::StringTag) 335 S.setScalarKind(msgpack::ScalarNode::SK_String); 336 else if (Tag == msgpack::ScalarNode::BinaryTag) 337 S.setScalarKind(msgpack::ScalarNode::SK_Binary); 338 else 339 return "Unsupported messagepack tag"; 340 341 return S.inputYAML(ScalarStr); 342 } 343 344 static QuotingType mustQuote(const msgpack::ScalarNode &S, StringRef Str) { 345 return S.mustQuoteYAML(Str); 346 } 347 }; 348 349 template <> struct CustomMappingTraits<msgpack::MapNode> { 350 static void inputOne(IO &IO, StringRef Key, msgpack::MapNode &M) { 351 IO.mapRequired(Key.str().c_str(), M[Key]); 352 } 353 static void output(IO &IO, msgpack::MapNode &M) { 354 for (auto &N : M) 355 IO.mapRequired(N.getKey().str().c_str(), N.getValue()); 356 } 357 }; 358 359 template <> struct SequenceTraits<msgpack::ArrayNode> { 360 static size_t size(IO &IO, msgpack::ArrayNode &A) { return A.size(); } 361 static msgpack::NodePtr &element(IO &IO, msgpack::ArrayNode &A, 362 size_t Index) { 363 if (Index >= A.size()) 364 A.resize(Index + 1); 365 return A[Index]; 366 } 367 }; 368 369 } // end namespace yaml 370 } // end namespace llvm 371 372 #endif // LLVM_BINARYFORMAT_MSGPACKTYPES_H 373