Program Listing for File JsonCast.inl

Return to documentation for file (include/ari/JsonCast.inl)

#include "JsonCast.h"

template <typename T>
void to_json(json& j, const T& obj)
{
    j = meta::serialize(obj);
}

template <typename T>
void from_json(const json& j, T& obj)
{
    meta::deserialize(obj, j);
}

namespace meta
{


template <typename Class,
    typename>
json serialize(const Class& obj)
{
    json value;
    meta::doForAllMembers<Class>(
        [&obj, &value](auto& member)
        {
            auto& valueName = value[member.getName()];
            if (member.canGetConstRef()) {
                valueName = member.get(obj);
            } else if (member.hasGetter()) {
                valueName = member.getCopy(obj); // passing copy as const ref, it's okay
            }
        }
    );
    return value;
}

template <typename Class,
    typename, typename>
json serialize(const Class& obj)
{
    return serialize_basic(obj);
}

template <typename Class>
json serialize_basic(const Class& obj)
{
    return json(obj);
}

// specialization for std::vector
template <typename T>
json serialize_basic(const std::vector<T>& obj)
{
    json value;
    int i = 0;
    for (auto& elem : obj) {
        value[i] = elem;
        ++i;
    }
    return value;
}

// specialization for std::unordered_map
template <typename K, typename V>
json serialize_basic(const std::unordered_map<K, V>& obj)
{
    json value;
    for (auto& pair : obj) {
        value.emplace(castToString(pair.first), pair.second);
    }
    return value;
}


template <typename Class>
Class deserialize(const json& obj)
{
    Class c;
    deserialize(c, obj);
    return c;
}

template <typename Class,
    typename>
void deserialize(Class& obj, const json& object)
{
    if (object.is_object()) {
        meta::doForAllMembers<Class>(
            [&obj, &object](auto& member)
            {
                auto& objName = object[member.getName()];
                if (!objName.is_null()) {
                    using MemberT = meta::get_member_type<decltype(member)>;
                    if (member.hasSetter()) {
                        member.set(obj, objName.template get<MemberT>());
                    } else if (member.canGetRef()) {
                        member.getRef(obj) = objName.template get<MemberT>();
                    } else {
                        throw std::runtime_error("Error: can't deserialize member because it's read only");
                    }
                }
            }
        );
    } else {
        throw std::runtime_error("Error: can't deserialize from Json::json to Class.");
    }
}

template <typename Class,
    typename, typename>
void deserialize(Class& obj, const json& object)
{
    obj = object.get<Class>();
}

// specialization for std::vector
template <typename T>
void deserialize(std::vector<T>& obj, const json& object)
{
    obj.reserve(object.size()); // vector.resize() works only for default constructible types
    for (auto& elem : object) {
        obj.push_back(elem); // push rvalue
    }
}

// specialization for std::unodered_map
template <typename K, typename V>
void deserialize(std::unordered_map<K, V>& obj, const json& object)
{
    for (auto it = object.begin(); it != object.end(); ++it) {
        obj.emplace(fromString<K>(it.key()), it.value());
    }
}

}