1 //===- MsgPackTypes.h - MsgPack Types ---------------------------*- C++ -*-===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
10 /// This is a data structure for representing MessagePack "documents", with
11 /// methods to go to and from MessagePack. The types also specialize YAMLIO
12 /// traits in order to go to and from YAML.
14 //===----------------------------------------------------------------------===//
16 #include "llvm/ADT/Optional.h"
17 #include "llvm/BinaryFormat/MsgPackReader.h"
18 #include "llvm/BinaryFormat/MsgPackWriter.h"
19 #include "llvm/Support/Casting.h"
20 #include "llvm/Support/YAMLTraits.h"
23 #ifndef LLVM_BINARYFORMAT_MSGPACKTYPES_H
24 #define LLVM_BINARYFORMAT_MSGPACKTYPES_H
31 /// Short-hand for a Node pointer.
32 using NodePtr
= std::shared_ptr
<Node
>;
34 /// Short-hand for an Optional Node pointer.
35 using OptNodePtr
= Optional
<NodePtr
>;
37 /// Abstract base-class which can be any MessagePack type.
47 virtual void anchor() = 0;
50 static Expected
<OptNodePtr
> readArray(Reader
&MPReader
, size_t Length
);
51 static Expected
<OptNodePtr
> readMap(Reader
&MPReader
, size_t Length
);
54 NodeKind
getKind() const { return Kind
; }
56 /// Construct a Node. Used by derived classes to track kind information.
57 Node(NodeKind Kind
) : Kind(Kind
) {}
59 virtual ~Node() = default;
61 /// Read from a MessagePack reader \p MPReader, returning an error if one is
62 /// encountered, or None if \p MPReader is at the end of stream, or some Node
63 /// pointer if some type is read.
64 static Expected
<OptNodePtr
> read(Reader
&MPReader
);
66 /// Write to a MessagePack writer \p MPWriter.
67 virtual void write(Writer
&MPWriter
) = 0;
70 /// A MessagePack scalar.
71 class ScalarNode
: public Node
{
84 void anchor() override
;
95 std::string StringValue
;
99 /// Construct an Int ScalarNode.
100 ScalarNode(int64_t IntValue
);
101 /// Construct an Int ScalarNode.
102 ScalarNode(int32_t IntValue
);
103 /// Construct an UInt ScalarNode.
104 ScalarNode(uint64_t UIntValue
);
105 /// Construct an UInt ScalarNode.
106 ScalarNode(uint32_t UIntValue
);
107 /// Construct a Nil ScalarNode.
109 /// Construct a Boolean ScalarNode.
110 ScalarNode(bool BoolValue
);
111 /// Construct a Float ScalarNode.
112 ScalarNode(double FloatValue
);
113 /// Construct a String ScalarNode.
114 ScalarNode(StringRef StringValue
);
115 /// Construct a String ScalarNode.
116 ScalarNode(const char *StringValue
);
117 /// Construct a String ScalarNode.
118 ScalarNode(std::string
&&StringValue
);
119 /// Construct a Binary ScalarNode.
120 ScalarNode(MemoryBufferRef BinaryValue
);
124 ScalarNode
&operator=(const ScalarNode
&RHS
) = delete;
125 /// A ScalarNode can only be move assigned.
126 ScalarNode
&operator=(ScalarNode
&&RHS
);
128 /// Change the kind of this ScalarNode, zero initializing it to the new type.
129 void setScalarKind(ScalarKind SKind
) {
147 *this = MemoryBufferRef("", "");
150 *this = ScalarNode();
155 /// Get the current kind of ScalarNode.
156 ScalarKind
getScalarKind() { return SKind
; }
158 /// Get the value of an Int scalar.
160 /// \warning Assumes getScalarKind() == SK_Int
162 assert(SKind
== SK_Int
);
166 /// Get the value of a UInt scalar.
168 /// \warning Assumes getScalarKind() == SK_UInt
170 assert(SKind
== SK_UInt
);
174 /// Get the value of an Boolean scalar.
176 /// \warning Assumes getScalarKind() == SK_Boolean
178 assert(SKind
== SK_Boolean
);
182 /// Get the value of an Float scalar.
184 /// \warning Assumes getScalarKind() == SK_Float
186 assert(SKind
== SK_Float
);
190 /// Get the value of a String scalar.
192 /// \warning Assumes getScalarKind() == SK_String
193 StringRef
getString() {
194 assert(SKind
== SK_String
);
198 /// Get the value of a Binary scalar.
200 /// \warning Assumes getScalarKind() == SK_Binary
201 StringRef
getBinary() {
202 assert(SKind
== SK_Binary
);
206 static bool classof(const Node
*N
) { return N
->getKind() == NK_Scalar
; }
208 void write(Writer
&MPWriter
) override
;
210 /// Parse a YAML scalar of the current ScalarKind from \p ScalarStr.
212 /// \returns An empty string on success, otherwise an error message.
213 StringRef
inputYAML(StringRef ScalarStr
);
215 /// Output a YAML scalar of the current ScalarKind into \p OS.
216 void outputYAML(raw_ostream
&OS
) const;
218 /// Determine which YAML quoting type the current value would need when
220 yaml::QuotingType
mustQuoteYAML(StringRef ScalarStr
) const;
222 /// Get the YAML tag for the current ScalarKind.
223 StringRef
getYAMLTag() const;
225 /// Flag which affects how the type handles YAML tags when reading and
228 /// When false, tags are used when reading and writing. When reading, the tag
229 /// is used to decide the ScalarKind before parsing. When writing, the tag is
230 /// output along with the value.
232 /// When true, tags are ignored when reading and writing. When reading, the
233 /// ScalarKind is always assumed to be String. When writing, the tag is not
235 bool IgnoreTag
= false;
237 static const char *IntTag
;
238 static const char *NilTag
;
239 static const char *BooleanTag
;
240 static const char *FloatTag
;
241 static const char *StringTag
;
242 static const char *BinaryTag
;
245 class ArrayNode
: public Node
, public std::vector
<NodePtr
> {
246 void anchor() override
;
249 ArrayNode() : Node(NK_Array
) {}
250 static bool classof(const Node
*N
) { return N
->getKind() == NK_Array
; }
252 void write(Writer
&MPWriter
) override
{
253 MPWriter
.writeArraySize(this->size());
254 for (auto &N
: *this)
259 class MapNode
: public Node
, public StringMap
<NodePtr
> {
260 void anchor() override
;
263 MapNode() : Node(NK_Map
) {}
264 static bool classof(const Node
*N
) { return N
->getKind() == NK_Map
; }
266 void write(Writer
&MPWriter
) override
{
267 MPWriter
.writeMapSize(this->size());
268 for (auto &N
: *this) {
269 MPWriter
.write(N
.first());
270 N
.second
->write(MPWriter
);
275 } // end namespace msgpack
279 template <> struct PolymorphicTraits
<msgpack::NodePtr
> {
280 static NodeKind
getKind(const msgpack::NodePtr
&N
) {
281 if (isa
<msgpack::ScalarNode
>(*N
))
282 return NodeKind::Scalar
;
283 if (isa
<msgpack::MapNode
>(*N
))
284 return NodeKind::Map
;
285 if (isa
<msgpack::ArrayNode
>(*N
))
286 return NodeKind::Sequence
;
287 llvm_unreachable("NodeKind not supported");
289 static msgpack::ScalarNode
&getAsScalar(msgpack::NodePtr
&N
) {
290 if (!N
|| !isa
<msgpack::ScalarNode
>(*N
))
291 N
.reset(new msgpack::ScalarNode());
292 return *cast
<msgpack::ScalarNode
>(N
.get());
294 static msgpack::MapNode
&getAsMap(msgpack::NodePtr
&N
) {
295 if (!N
|| !isa
<msgpack::MapNode
>(*N
))
296 N
.reset(new msgpack::MapNode());
297 return *cast
<msgpack::MapNode
>(N
.get());
299 static msgpack::ArrayNode
&getAsSequence(msgpack::NodePtr
&N
) {
300 if (!N
|| !isa
<msgpack::ArrayNode
>(*N
))
301 N
.reset(new msgpack::ArrayNode());
302 return *cast
<msgpack::ArrayNode
>(N
.get());
306 template <> struct TaggedScalarTraits
<msgpack::ScalarNode
> {
307 static void output(const msgpack::ScalarNode
&S
, void *Ctxt
,
308 raw_ostream
&ScalarOS
, raw_ostream
&TagOS
) {
310 TagOS
<< S
.getYAMLTag();
311 S
.outputYAML(ScalarOS
);
314 static StringRef
input(StringRef ScalarStr
, StringRef Tag
, void *Ctxt
,
315 msgpack::ScalarNode
&S
) {
316 if (Tag
== msgpack::ScalarNode::IntTag
) {
317 S
.setScalarKind(msgpack::ScalarNode::SK_UInt
);
318 if (S
.inputYAML(ScalarStr
) == StringRef())
320 S
.setScalarKind(msgpack::ScalarNode::SK_Int
);
321 return S
.inputYAML(ScalarStr
);
324 if (S
.IgnoreTag
|| Tag
== msgpack::ScalarNode::StringTag
||
325 Tag
== "tag:yaml.org,2002:str")
326 S
.setScalarKind(msgpack::ScalarNode::SK_String
);
327 else if (Tag
== msgpack::ScalarNode::NilTag
)
328 S
.setScalarKind(msgpack::ScalarNode::SK_Nil
);
329 else if (Tag
== msgpack::ScalarNode::BooleanTag
)
330 S
.setScalarKind(msgpack::ScalarNode::SK_Boolean
);
331 else if (Tag
== msgpack::ScalarNode::FloatTag
)
332 S
.setScalarKind(msgpack::ScalarNode::SK_Float
);
333 else if (Tag
== msgpack::ScalarNode::StringTag
)
334 S
.setScalarKind(msgpack::ScalarNode::SK_String
);
335 else if (Tag
== msgpack::ScalarNode::BinaryTag
)
336 S
.setScalarKind(msgpack::ScalarNode::SK_Binary
);
338 return "Unsupported messagepack tag";
340 return S
.inputYAML(ScalarStr
);
343 static QuotingType
mustQuote(const msgpack::ScalarNode
&S
, StringRef Str
) {
344 return S
.mustQuoteYAML(Str
);
348 template <> struct CustomMappingTraits
<msgpack::MapNode
> {
349 static void inputOne(IO
&IO
, StringRef Key
, msgpack::MapNode
&M
) {
350 IO
.mapRequired(Key
.str().c_str(), M
[Key
]);
352 static void output(IO
&IO
, msgpack::MapNode
&M
) {
354 IO
.mapRequired(N
.getKey().str().c_str(), N
.getValue());
358 template <> struct SequenceTraits
<msgpack::ArrayNode
> {
359 static size_t size(IO
&IO
, msgpack::ArrayNode
&A
) { return A
.size(); }
360 static msgpack::NodePtr
&element(IO
&IO
, msgpack::ArrayNode
&A
,
362 if (Index
>= A
.size())
368 } // end namespace yaml
369 } // end namespace llvm
371 #endif // LLVM_BINARYFORMAT_MSGPACKTYPES_H