nlib
msgpack/usertype/usertype.cpp

This sample reads and writes a user data type with MessagePack. The sample performs the following operations.

The source code of the sample is shown below.

#include <string>
using nlib_ns::msgpack::MpObject;
using nlib_ns::msgpack::MpReader;
using nlib_ns::msgpack::MpWriter;
class MenuItem {
public:
MenuItem() : m_ItemCode(0), m_Price(0) {}
void SetItemCode(int code) { m_ItemCode = code; }
void SetDescription(const std::string& rhs) { m_Description = rhs; }
void SetPrice(int price) { m_Price = price; }
int GetItemCode() const { return m_ItemCode; }
const std::string& GetDescription() const { return m_Description; }
int GetPrice() const { return m_Price; }
bool operator!=(const MenuItem& rhs) {
return m_ItemCode != rhs.m_ItemCode || m_Description != rhs.m_Description ||
m_Price != rhs.m_Price;
}
void Print() {
nlib_printf("code: %d, \"%s\", price: %d\n", m_ItemCode, m_Description.c_str(), m_Price);
}
private:
int m_ItemCode;
std::string m_Description;
int m_Price;
};
NLIB_NAMESPACE_BEGIN
namespace msgpack {
// Specialize the function template MpRead in nlib_ns::msgpack namespace,
// and you can define the deserializer for MenuItem.
template <>
bool MpRead<MenuItem>(MpReader* obj, MenuItem* v) {
size_t count;
if (!obj->GetNextMapNum(&count)) return false;
int code = 0;
std::string desc;
int price = 0;
for (size_t i = 0; i < count; ++i) {
// Your code should not depend on the order of keys.
std::string key;
MpObject value;
if (!obj->Read(&key)) return false;
if (key == "itemCode") {
if (!obj->Read(&code)) return false;
} else if (key == "itemName") {
if (!obj->Read(&desc)) return false;
} else if (key == "itemPrice") {
if (!obj->Read(&price)) return false;
}
}
// Sets up MenuItem object after you can read all the values successfully.
v->SetItemCode(code);
v->SetDescription(desc);
v->SetPrice(price);
return true;
}
// Specialize the function template MpWrite in nlib_ns::msgpack namespace,
// and you can define the serializer for MenuItem.
template <>
bool MpWrite<MenuItem>(MpWriter* obj, const MenuItem& v) {
if (!obj->WriteMapCount(3)) return false;
if (!obj->Write("itemCode")) return false;
if (!obj->Write(v.GetItemCode())) return false;
if (!obj->Write("itemName")) return false;
if (!obj->Write(v.GetDescription())) return false;
if (!obj->Write("itemPrice")) return false;
if (!obj->Write(v.GetPrice())) return false;
return true;
}
} // namespace msgpack
NLIB_NAMESPACE_END
bool ReadWriteUserType() {
MenuItem menu[3];
menu[0].SetItemCode(91);
menu[0].SetDescription("ramen with salt based soup");
menu[0].SetPrice(800);
menu[1].SetItemCode(94);
menu[1].SetDescription("ramen with miso based soup");
menu[1].SetPrice(790);
menu[2].SetItemCode(95);
menu[2].SetDescription("ramen with a pork bone broth");
menu[2].SetPrice(820);
nlib_printf("MENU to be serialized:\n");
menu[0].Print();
menu[1].Print();
menu[2].Print();
// Serializes onto the memory
ReallocOutputStream ostr;
MpWriter w;
if (!w.Init(&ostr)) return false;
if (!w.Write(menu)) return false;
if (!w.Close()) return false;
if (!ostr.Flush()) return false;
// Reads the serialized data
MpReader r;
MenuItem copiedMenu[3];
ReallocOutputStream::UniquePtrType data;
size_t data_size = ostr.Release(&data);
MemoryInputStream istr(data.get(), data_size);
if (!r.Init(&istr)) return false;
if (!r.Read(copiedMenu)) return false;
nlib_printf("\nDeserialized MENU:\n");
copiedMenu[0].Print();
copiedMenu[1].Print();
copiedMenu[2].Print();
if (copiedMenu[0] != menu[0]) return false;
if (copiedMenu[1] != menu[1]) return false;
if (copiedMenu[2] != menu[2]) return false;
return true;
}
bool SampleMain(int, char**) { return ReadWriteUserType(); }
NLIB_MAINFUNC