Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to deserialize using Boost.Hana?

I'm getting started with Boost.Hana and was wondering if there is a way to deserialize back into a Struct that is known to Boost.Hana. I know it's pretty simple to serialize such a Struct into a json string for example, but i did not find any information about the other way around. Is it currently just not possible to deserialize data with Boost.Hana or am i missing something?

like image 736
Xardaska Avatar asked Oct 11 '15 13:10

Xardaska


2 Answers

Hana is a metaprogramming library. It provides tools that can be used to build more complex functionality like serialization, but it does not provide such functionality itself. It's simply not the scope of that library. Also, regarding your particular use case; parsing is not an easy problem and other libraries like Boost.Spirit already try to solve it.

That being said, I sketched an example of using Hana to deserialize JSON. The result is neither efficient nor robust, but it should be enough to give you a glimpse at how Hana could be used to achieve something better. Solving this problem correctly would require implementing a parser combinator library à-la Boost.Spirit, which I won't do here. Here you go:

template <typename T>
  std::enable_if_t<std::is_same<T, int>::value,
T> from_json(std::istream& in) {
    T result;
    in >> result;
    return result;
}

template <typename T>
  std::enable_if_t<std::is_same<T, std::string>::value,
T> from_json(std::istream& in) {
    char quote;
    in >> quote;

    T result;
    char c;
    while (in.get(c) && c != '"') {
        result += c;
    }
    return result;
}


template <typename T>
  std::enable_if_t<hana::Struct<T>::value,
T> from_json(std::istream& in) {
    T result;
    char brace;
    in >> brace;

    hana::for_each(hana::keys(result), [&](auto key) {
        in.ignore(std::numeric_limits<std::streamsize>::max(), ':');
        auto& member = hana::at_key(result, key);
        using Member = std::remove_reference_t<decltype(member)>;
        member = from_json<Member>(in);
    });
    in >> brace;
    return result;
}

template <typename Xs>
  std::enable_if_t<hana::Sequence<Xs>::value,
Xs> from_json(std::istream& in) {
    Xs result;
    char bracket;
    in >> bracket;
    hana::length(result).times.with_index([&](auto i) {
        if (i != 0u) {
            char comma;
            in >> comma;
        }

        auto& element = hana::at(result, i);
        using Element = std::remove_reference_t<decltype(element)>;
        element = from_json<Element>(in);
    });
    in >> bracket;
    return result;
}

And then you can use it like

struct Car {
    BOOST_HANA_DEFINE_STRUCT(Car,
        (std::string, brand),
        (std::string, model)
    );
};

struct Person {
    BOOST_HANA_DEFINE_STRUCT(Person,
        (std::string, name),
        (std::string, last_name),
        (int, age)
    );
};

int main() {
    std::istringstream json(R"EOS(
        [
            {
                "name": "John",
                "last_name": "Doe",
                "age": 30
            },
            {
                "brand": "BMW",
                "model": "Z3"
            },
            {
                "brand": "Audi",
                "model": "A4"
            }
        ]
    )EOS");

    auto actual = from_json<hana::tuple<Person, Car, Car>>(json);

    auto expected = hana::make_tuple(Person{"John", "Doe", 30},
                                     Car{"BMW", "Z3"},
                                     Car{"Audi", "A4"});

    assert(actual == expected);
}

The full example is available here.

like image 86
Louis Dionne Avatar answered Sep 30 '22 05:09

Louis Dionne


The boost::hana json encoder is not compelete (it doesn't escape quotes for example): http://www.boost.org/doc/libs/1_61_0/libs/hana/doc/html/index.html#tutorial-introspection-json

To de-serialize, I'd use boost::spirit::x3: http://ciere.com/cppnow15/x3_docs/index.html

They have a json deserializer example: https://github.com/cierelabs/json_spirit

like image 38
matiu Avatar answered Sep 30 '22 05:09

matiu