[BinaryFormat] Add MsgPackTypes

Add data structure to represent MessagePack "documents" and convert
to/from both MessagePack and YAML encodings.

Differential Revision: https://reviews.llvm.org/D48175

llvm-svn: 346978
This commit is contained in:
Scott Linder 2018-11-15 18:50:01 +00:00
parent 6cda87463f
commit 919fbbbcca
5 changed files with 865 additions and 0 deletions

View File

@ -0,0 +1,372 @@
//===- 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 <vector>
#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<Node>;
/// Short-hand for an Optional Node pointer.
using OptNodePtr = Optional<NodePtr>;
/// 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<OptNodePtr> readArray(Reader &MPReader, size_t Length);
static Expected<OptNodePtr> 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<OptNodePtr> 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<NodePtr> {
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<NodePtr> {
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<msgpack::NodePtr> {
static NodeKind getKind(const msgpack::NodePtr &N) {
if (isa<msgpack::ScalarNode>(*N))
return NodeKind::Scalar;
if (isa<msgpack::MapNode>(*N))
return NodeKind::Map;
if (isa<msgpack::ArrayNode>(*N))
return NodeKind::Sequence;
llvm_unreachable("NodeKind not supported");
}
static msgpack::ScalarNode &getAsScalar(msgpack::NodePtr &N) {
if (!N || !isa<msgpack::ScalarNode>(*N))
N.reset(new msgpack::ScalarNode());
return *cast<msgpack::ScalarNode>(N.get());
}
static msgpack::MapNode &getAsMap(msgpack::NodePtr &N) {
if (!N || !isa<msgpack::MapNode>(*N))
N.reset(new msgpack::MapNode());
return *cast<msgpack::MapNode>(N.get());
}
static msgpack::ArrayNode &getAsSequence(msgpack::NodePtr &N) {
if (!N || !isa<msgpack::ArrayNode>(*N))
N.reset(new msgpack::ArrayNode());
return *cast<msgpack::ArrayNode>(N.get());
}
};
template <> struct TaggedScalarTraits<msgpack::ScalarNode> {
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<msgpack::MapNode> {
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<msgpack::ArrayNode> {
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

View File

@ -2,6 +2,7 @@ add_llvm_library(LLVMBinaryFormat
Dwarf.cpp
Magic.cpp
MsgPackReader.cpp
MsgPackTypes.cpp
MsgPackWriter.cpp
Wasm.cpp

View File

@ -0,0 +1,303 @@
//===- MsgPackTypes.cpp - 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
/// Implementation of types representing MessagePack "documents".
//
//===----------------------------------------------------------------------===//
#include "llvm/BinaryFormat/MsgPackTypes.h"
#include "llvm/Support/Error.h"
using namespace llvm;
using namespace msgpack;
namespace llvm {
namespace msgpack {
void ScalarNode::anchor() {}
void ArrayNode::anchor() {}
void MapNode::anchor() {}
}
}
Expected<OptNodePtr> Node::readArray(Reader &MPReader, size_t Length) {
auto A = std::make_shared<ArrayNode>();
for (size_t I = 0; I < Length; ++I) {
auto OptNodeOrErr = Node::read(MPReader);
if (auto Err = OptNodeOrErr.takeError())
return std::move(Err);
if (!*OptNodeOrErr)
return make_error<StringError>(
"Insufficient array elements",
std::make_error_code(std::errc::invalid_argument));
A->push_back(std::move(**OptNodeOrErr));
}
return OptNodePtr(std::move(A));
}
Expected<OptNodePtr> Node::readMap(Reader &MPReader, size_t Length) {
auto M = std::make_shared<MapNode>();
for (size_t I = 0; I < Length; ++I) {
auto OptKeyOrErr = Node::read(MPReader);
if (auto Err = OptKeyOrErr.takeError())
return std::move(Err);
if (!*OptKeyOrErr)
return make_error<StringError>(
"Insufficient map elements",
std::make_error_code(std::errc::invalid_argument));
auto OptValOrErr = Node::read(MPReader);
if (auto Err = OptValOrErr.takeError())
return std::move(Err);
if (!*OptValOrErr)
return make_error<StringError>(
"Insufficient map elements",
std::make_error_code(std::errc::invalid_argument));
auto *Key = dyn_cast<ScalarNode>((*OptKeyOrErr)->get());
if (!Key)
return make_error<StringError>(
"Only string map keys are supported",
std::make_error_code(std::errc::invalid_argument));
if (Key->getScalarKind() != ScalarNode::SK_String)
return make_error<StringError>(
"Only string map keys are supported",
std::make_error_code(std::errc::invalid_argument));
M->try_emplace(Key->getString(), std::move(**OptValOrErr));
}
return OptNodePtr(std::move(M));
}
Expected<OptNodePtr> Node::read(Reader &MPReader) {
Object Obj;
auto ContinueOrErr = MPReader.read(Obj);
if (auto Err = ContinueOrErr.takeError())
return std::move(Err);
if (!*ContinueOrErr)
return None;
switch (Obj.Kind) {
case Type::Int:
return OptNodePtr(std::make_shared<ScalarNode>(Obj.Int));
case Type::UInt:
return OptNodePtr(std::make_shared<ScalarNode>(Obj.UInt));
case Type::Nil:
return OptNodePtr(std::make_shared<ScalarNode>());
case Type::Boolean:
return OptNodePtr(std::make_shared<ScalarNode>(Obj.Bool));
case Type::Float:
return OptNodePtr(std::make_shared<ScalarNode>(Obj.Float));
case Type::String:
return OptNodePtr(std::make_shared<ScalarNode>(Obj.Raw));
case Type::Binary:
return OptNodePtr(std::make_shared<ScalarNode>(Obj.Raw));
case Type::Array:
return Node::readArray(MPReader, Obj.Length);
case Type::Map:
return Node::readMap(MPReader, Obj.Length);
case Type::Extension:
return make_error<StringError>(
"Extension types are not supported",
std::make_error_code(std::errc::invalid_argument));
}
llvm_unreachable("msgpack::Type not handled");
}
void ScalarNode::destroy() {
switch (SKind) {
case SK_String:
case SK_Binary:
StringValue.~basic_string();
break;
default:
// POD types do not require destruction
break;
}
}
ScalarNode::ScalarNode(int64_t IntValue)
: Node(NK_Scalar), SKind(SK_Int), IntValue(IntValue) {}
ScalarNode::ScalarNode(int32_t IntValue)
: ScalarNode(static_cast<int64_t>(IntValue)) {}
ScalarNode::ScalarNode(uint64_t UIntValue)
: Node(NK_Scalar), SKind(SK_UInt), UIntValue(UIntValue) {}
ScalarNode::ScalarNode(uint32_t IntValue)
: ScalarNode(static_cast<uint64_t>(IntValue)) {}
ScalarNode::ScalarNode() : Node(NK_Scalar), SKind(SK_Nil) {}
ScalarNode::ScalarNode(bool BoolValue)
: Node(NK_Scalar), SKind(SK_Boolean), BoolValue(BoolValue) {}
ScalarNode::ScalarNode(double FloatValue)
: Node(NK_Scalar), SKind(SK_Float), BoolValue(FloatValue) {}
ScalarNode::ScalarNode(StringRef StringValue)
: Node(NK_Scalar), SKind(SK_String) {
new (&this->StringValue) std::string(StringValue);
}
ScalarNode::ScalarNode(const char *StringValue)
: ScalarNode(StringRef(StringValue)) {}
ScalarNode::ScalarNode(std::string &&StringValue)
: Node(NK_Scalar), SKind(SK_String) {
new (&this->StringValue) std::string(StringValue);
}
ScalarNode::ScalarNode(MemoryBufferRef BinaryValue)
: Node(NK_Scalar), SKind(SK_Binary) {
new (&StringValue) std::string(BinaryValue.getBuffer());
}
ScalarNode::~ScalarNode() { destroy(); }
ScalarNode &ScalarNode::operator=(ScalarNode &&RHS) {
destroy();
switch (SKind = RHS.SKind) {
case SK_Int:
IntValue = RHS.IntValue;
break;
case SK_UInt:
UIntValue = RHS.UIntValue;
break;
case SK_Boolean:
BoolValue = RHS.BoolValue;
break;
case SK_Float:
FloatValue = RHS.FloatValue;
break;
case SK_String:
case SK_Binary:
new (&StringValue) std::string(std::move(RHS.StringValue));
break;
case SK_Nil:
// pass
break;
}
return *this;
}
StringRef ScalarNode::inputYAML(StringRef ScalarStr) {
switch (SKind) {
case SK_Int:
return yaml::ScalarTraits<int64_t>::input(ScalarStr, nullptr, IntValue);
case SK_UInt:
return yaml::ScalarTraits<uint64_t>::input(ScalarStr, nullptr, UIntValue);
case SK_Nil:
return StringRef();
case SK_Boolean:
return yaml::ScalarTraits<bool>::input(ScalarStr, nullptr, BoolValue);
case SK_Float:
return yaml::ScalarTraits<double>::input(ScalarStr, nullptr, FloatValue);
case SK_Binary:
case SK_String:
return yaml::ScalarTraits<std::string>::input(ScalarStr, nullptr,
StringValue);
}
llvm_unreachable("unrecognized ScalarKind");
}
void ScalarNode::outputYAML(raw_ostream &OS) const {
switch (SKind) {
case SK_Int:
yaml::ScalarTraits<int64_t>::output(IntValue, nullptr, OS);
break;
case SK_UInt:
yaml::ScalarTraits<uint64_t>::output(UIntValue, nullptr, OS);
break;
case SK_Nil:
yaml::ScalarTraits<StringRef>::output("", nullptr, OS);
break;
case SK_Boolean:
yaml::ScalarTraits<bool>::output(BoolValue, nullptr, OS);
break;
case SK_Float:
yaml::ScalarTraits<double>::output(FloatValue, nullptr, OS);
break;
case SK_Binary:
case SK_String:
yaml::ScalarTraits<std::string>::output(StringValue, nullptr, OS);
break;
}
}
yaml::QuotingType ScalarNode::mustQuoteYAML(StringRef ScalarStr) const {
switch (SKind) {
case SK_Int:
return yaml::ScalarTraits<int64_t>::mustQuote(ScalarStr);
case SK_UInt:
return yaml::ScalarTraits<uint64_t>::mustQuote(ScalarStr);
case SK_Nil:
return yaml::ScalarTraits<StringRef>::mustQuote(ScalarStr);
case SK_Boolean:
return yaml::ScalarTraits<bool>::mustQuote(ScalarStr);
case SK_Float:
return yaml::ScalarTraits<double>::mustQuote(ScalarStr);
case SK_Binary:
case SK_String:
return yaml::ScalarTraits<std::string>::mustQuote(ScalarStr);
}
llvm_unreachable("unrecognized ScalarKind");
}
const char *ScalarNode::IntTag = "!int";
const char *ScalarNode::NilTag = "!nil";
const char *ScalarNode::BooleanTag = "!bool";
const char *ScalarNode::FloatTag = "!float";
const char *ScalarNode::StringTag = "!str";
const char *ScalarNode::BinaryTag = "!bin";
StringRef ScalarNode::getYAMLTag() const {
switch (SKind) {
case SK_Int:
return IntTag;
case SK_UInt:
return IntTag;
case SK_Nil:
return NilTag;
case SK_Boolean:
return BooleanTag;
case SK_Float:
return FloatTag;
case SK_String:
return StringTag;
case SK_Binary:
return BinaryTag;
}
llvm_unreachable("unrecognized ScalarKind");
}
void ScalarNode::write(Writer &MPWriter) {
switch (SKind) {
case SK_Int:
MPWriter.write(IntValue);
break;
case SK_UInt:
MPWriter.write(UIntValue);
break;
case SK_Nil:
MPWriter.writeNil();
break;
case SK_Boolean:
MPWriter.write(BoolValue);
break;
case SK_Float:
MPWriter.write(FloatValue);
break;
case SK_String:
MPWriter.write(StringValue);
break;
case SK_Binary:
MPWriter.write(MemoryBufferRef(StringValue, ""));
break;
}
}

View File

@ -6,6 +6,7 @@ add_llvm_unittest(BinaryFormatTests
DwarfTest.cpp
MachOTest.cpp
MsgPackReaderTest.cpp
MsgPackTypesTest.cpp
MsgPackWriterTest.cpp
TestFileMagic.cpp
)

View File

@ -0,0 +1,188 @@
//===- MsgPackTypesTest.cpp -------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "llvm/BinaryFormat/MsgPackTypes.h"
#include "gtest/gtest.h"
using namespace llvm;
using namespace msgpack;
TEST(MsgPackTypes, TestReadInt) {
Reader MPReader(StringRef("\xd0\x00", 2));
auto OptNodeOrErr = Node::read(MPReader);
ASSERT_TRUE(static_cast<bool>(OptNodeOrErr));
ASSERT_TRUE(*OptNodeOrErr);
auto *S = dyn_cast<ScalarNode>((*OptNodeOrErr)->get());
ASSERT_TRUE(S);
ASSERT_EQ(S->getScalarKind(), ScalarNode::SK_Int);
ASSERT_EQ(S->getInt(), 0);
}
TEST(MsgPackTypes, TestReadArray) {
Reader MPReader(StringRef("\x92\xd0\x01\xc0"));
auto OptNodeOrErr = Node::read(MPReader);
ASSERT_TRUE(static_cast<bool>(OptNodeOrErr));
ASSERT_TRUE(*OptNodeOrErr);
auto *A = dyn_cast<ArrayNode>((*OptNodeOrErr)->get());
ASSERT_TRUE(A);
ASSERT_EQ(A->size(), 2u);
auto *SI = dyn_cast<ScalarNode>((*A)[0].get());
ASSERT_TRUE(SI);
ASSERT_EQ(SI->getScalarKind(), ScalarNode::SK_Int);
ASSERT_EQ(SI->getInt(), 1);
auto *SN = dyn_cast<ScalarNode>((*A)[1].get());
ASSERT_TRUE(SN);
ASSERT_EQ(SN->getScalarKind(), ScalarNode::SK_Nil);
}
TEST(MsgPackTypes, TestReadMap) {
Reader MPReader(StringRef("\x82\xa3"
"foo"
"\xd0\x01\xa3"
"bar"
"\xd0\x02"));
auto OptNodeOrErr = Node::read(MPReader);
ASSERT_TRUE(static_cast<bool>(OptNodeOrErr));
ASSERT_TRUE(*OptNodeOrErr);
auto *A = dyn_cast<MapNode>((*OptNodeOrErr)->get());
ASSERT_TRUE(A);
ASSERT_EQ(A->size(), 2u);
auto *FooS = dyn_cast<ScalarNode>((*A)["foo"].get());
ASSERT_TRUE(FooS);
ASSERT_EQ(FooS->getScalarKind(), ScalarNode::SK_Int);
ASSERT_EQ(FooS->getInt(), 1);
auto *BarS = dyn_cast<ScalarNode>((*A)["bar"].get());
ASSERT_TRUE(BarS);
ASSERT_EQ(BarS->getScalarKind(), ScalarNode::SK_Int);
ASSERT_EQ(BarS->getInt(), 2);
}
TEST(MsgPackTypes, TestWriteInt) {
std::string Buffer;
raw_string_ostream OStream(Buffer);
Writer MPWriter(OStream);
ScalarNode I(int64_t(1));
I.write(MPWriter);
ASSERT_EQ(OStream.str(), "\x01");
}
TEST(MsgPackTypes, TestWriteArray) {
std::string Buffer;
raw_string_ostream OStream(Buffer);
Writer MPWriter(OStream);
ArrayNode A;
A.push_back(std::make_shared<ScalarNode>(int64_t(1)));
A.push_back(std::make_shared<ScalarNode>());
A.write(MPWriter);
ASSERT_EQ(OStream.str(), "\x92\x01\xc0");
}
TEST(MsgPackTypes, TestWriteMap) {
std::string Buffer;
raw_string_ostream OStream(Buffer);
Writer MPWriter(OStream);
MapNode M;
M["foo"] = std::make_shared<ScalarNode>(int64_t(1));
M["bar"] = std::make_shared<ScalarNode>(int64_t(2));
M.write(MPWriter);
ASSERT_EQ(OStream.str(), "\x82\xa3"
"foo"
"\x01\xa3"
"bar"
"\x02");
}
TEST(MsgPackTypes, TestOutputYAMLArray) {
std::string Buffer;
raw_string_ostream OStream(Buffer);
yaml::Output yout(OStream);
ArrayNode A;
A.push_back(std::make_shared<ScalarNode>(int64_t(1)));
A.push_back(std::make_shared<ScalarNode>(int64_t(2)));
yout << A;
ASSERT_EQ(OStream.str(), "---\n- !int 1\n- !int 2\n...\n");
}
TEST(MsgPackTypes, TestInputYAMLArray) {
NodePtr RootNode;
yaml::Input yin("---\n- !int 1\n- !str 2\n...\n");
yin >> RootNode;
auto *A = dyn_cast<ArrayNode>(RootNode.get());
ASSERT_TRUE(A);
ASSERT_EQ(A->size(), 2u);
auto *SI = dyn_cast<ScalarNode>((*A)[0].get());
ASSERT_TRUE(SI);
ASSERT_EQ(SI->getScalarKind(), ScalarNode::SK_UInt);
ASSERT_EQ(SI->getUInt(), 1u);
auto *SS = dyn_cast<ScalarNode>((*A)[1].get());
ASSERT_TRUE(SS);
ASSERT_EQ(SS->getScalarKind(), ScalarNode::SK_String);
ASSERT_EQ(SS->getString(), "2");
}
TEST(MsgPackTypes, TestOutputYAMLMap) {
std::string Buffer;
raw_string_ostream OStream(Buffer);
yaml::Output yout(OStream);
MapNode M;
M["foo"] = std::make_shared<ScalarNode>(int64_t(1));
M["bar"] = std::make_shared<ScalarNode>(uint64_t(2));
auto N = std::make_shared<MapNode>();
(*N)["baz"] = std::make_shared<ScalarNode>(true);
M["qux"] = std::move(N);
yout << M;
ASSERT_EQ(OStream.str(), "---\nfoo: !int 1\nbar: "
"!int 2\nqux: \n baz: "
"!bool true\n...\n");
}
TEST(MsgPackTypes, TestInputYAMLMap) {
NodePtr RootNode;
yaml::Input yin("---\nfoo: !int 1\nbaz: !str 2\n...\n");
yin >> RootNode;
auto *M = dyn_cast<MapNode>(RootNode.get());
ASSERT_TRUE(M);
ASSERT_EQ(M->size(), 2u);
auto *SI = dyn_cast<ScalarNode>((*M)["foo"].get());
ASSERT_TRUE(SI);
ASSERT_EQ(SI->getScalarKind(), ScalarNode::SK_UInt);
ASSERT_EQ(SI->getUInt(), 1u);
auto *SS = dyn_cast<ScalarNode>((*M)["baz"].get());
ASSERT_TRUE(SS);
ASSERT_EQ(SS->getScalarKind(), ScalarNode::SK_String);
ASSERT_EQ(SS->getString(), "2");
}
// Test that the document is parsed into a tree of shared_ptr where each node
// can have multiple owners.
TEST(MsgPackTypes, TestInputShared) {
yaml::Input yin("---\nfoo:\n bar: !int 1\n...\n");
NodePtr InnerMap;
NodePtr IntNode;
{
{
{
NodePtr RootNode;
yin >> RootNode;
auto *M = dyn_cast<MapNode>(RootNode.get());
ASSERT_TRUE(M);
ASSERT_EQ(M->size(), 1u);
InnerMap = (*M)["foo"];
}
auto *N = dyn_cast<MapNode>(InnerMap.get());
ASSERT_TRUE(N);
ASSERT_EQ(N->size(), 1u);
IntNode = (*N)["bar"];
}
auto *S = dyn_cast<ScalarNode>(IntNode.get());
ASSERT_TRUE(S);
ASSERT_EQ(S->getScalarKind(), ScalarNode::SK_UInt);
ASSERT_EQ(S->getUInt(), 1u);
}
}