test_pickling.cpp revision 11986
111986Sandreas.sandberg@arm.com/*
211986Sandreas.sandberg@arm.com    tests/test_pickling.cpp -- pickle support
311986Sandreas.sandberg@arm.com
411986Sandreas.sandberg@arm.com    Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
511986Sandreas.sandberg@arm.com
611986Sandreas.sandberg@arm.com    All rights reserved. Use of this source code is governed by a
711986Sandreas.sandberg@arm.com    BSD-style license that can be found in the LICENSE file.
811986Sandreas.sandberg@arm.com*/
911986Sandreas.sandberg@arm.com
1011986Sandreas.sandberg@arm.com#include "pybind11_tests.h"
1111986Sandreas.sandberg@arm.com
1211986Sandreas.sandberg@arm.comclass Pickleable {
1311986Sandreas.sandberg@arm.compublic:
1411986Sandreas.sandberg@arm.com    Pickleable(const std::string &value) : m_value(value) { }
1511986Sandreas.sandberg@arm.com    const std::string &value() const { return m_value; }
1611986Sandreas.sandberg@arm.com
1711986Sandreas.sandberg@arm.com    void setExtra1(int extra1) { m_extra1 = extra1; }
1811986Sandreas.sandberg@arm.com    void setExtra2(int extra2) { m_extra2 = extra2; }
1911986Sandreas.sandberg@arm.com    int extra1() const { return m_extra1; }
2011986Sandreas.sandberg@arm.com    int extra2() const { return m_extra2; }
2111986Sandreas.sandberg@arm.comprivate:
2211986Sandreas.sandberg@arm.com    std::string m_value;
2311986Sandreas.sandberg@arm.com    int m_extra1 = 0;
2411986Sandreas.sandberg@arm.com    int m_extra2 = 0;
2511986Sandreas.sandberg@arm.com};
2611986Sandreas.sandberg@arm.com
2711986Sandreas.sandberg@arm.comclass PickleableWithDict {
2811986Sandreas.sandberg@arm.compublic:
2911986Sandreas.sandberg@arm.com    PickleableWithDict(const std::string &value) : value(value) { }
3011986Sandreas.sandberg@arm.com
3111986Sandreas.sandberg@arm.com    std::string value;
3211986Sandreas.sandberg@arm.com    int extra;
3311986Sandreas.sandberg@arm.com};
3411986Sandreas.sandberg@arm.com
3511986Sandreas.sandberg@arm.comtest_initializer pickling([](py::module &m) {
3611986Sandreas.sandberg@arm.com    py::class_<Pickleable>(m, "Pickleable")
3711986Sandreas.sandberg@arm.com        .def(py::init<std::string>())
3811986Sandreas.sandberg@arm.com        .def("value", &Pickleable::value)
3911986Sandreas.sandberg@arm.com        .def("extra1", &Pickleable::extra1)
4011986Sandreas.sandberg@arm.com        .def("extra2", &Pickleable::extra2)
4111986Sandreas.sandberg@arm.com        .def("setExtra1", &Pickleable::setExtra1)
4211986Sandreas.sandberg@arm.com        .def("setExtra2", &Pickleable::setExtra2)
4311986Sandreas.sandberg@arm.com        // For details on the methods below, refer to
4411986Sandreas.sandberg@arm.com        // http://docs.python.org/3/library/pickle.html#pickling-class-instances
4511986Sandreas.sandberg@arm.com        .def("__getstate__", [](const Pickleable &p) {
4611986Sandreas.sandberg@arm.com            /* Return a tuple that fully encodes the state of the object */
4711986Sandreas.sandberg@arm.com            return py::make_tuple(p.value(), p.extra1(), p.extra2());
4811986Sandreas.sandberg@arm.com        })
4911986Sandreas.sandberg@arm.com        .def("__setstate__", [](Pickleable &p, py::tuple t) {
5011986Sandreas.sandberg@arm.com            if (t.size() != 3)
5111986Sandreas.sandberg@arm.com                throw std::runtime_error("Invalid state!");
5211986Sandreas.sandberg@arm.com            /* Invoke the constructor (need to use in-place version) */
5311986Sandreas.sandberg@arm.com            new (&p) Pickleable(t[0].cast<std::string>());
5411986Sandreas.sandberg@arm.com
5511986Sandreas.sandberg@arm.com            /* Assign any additional state */
5611986Sandreas.sandberg@arm.com            p.setExtra1(t[1].cast<int>());
5711986Sandreas.sandberg@arm.com            p.setExtra2(t[2].cast<int>());
5811986Sandreas.sandberg@arm.com        });
5911986Sandreas.sandberg@arm.com
6011986Sandreas.sandberg@arm.com    py::class_<PickleableWithDict>(m, "PickleableWithDict", py::dynamic_attr())
6111986Sandreas.sandberg@arm.com        .def(py::init<std::string>())
6211986Sandreas.sandberg@arm.com        .def_readwrite("value", &PickleableWithDict::value)
6311986Sandreas.sandberg@arm.com        .def_readwrite("extra", &PickleableWithDict::extra)
6411986Sandreas.sandberg@arm.com        .def("__getstate__", [](py::object self) {
6511986Sandreas.sandberg@arm.com            /* Also include __dict__ in state */
6611986Sandreas.sandberg@arm.com            return py::make_tuple(self.attr("value"), self.attr("extra"), self.attr("__dict__"));
6711986Sandreas.sandberg@arm.com        })
6811986Sandreas.sandberg@arm.com        .def("__setstate__", [](py::object self, py::tuple t) {
6911986Sandreas.sandberg@arm.com            if (t.size() != 3)
7011986Sandreas.sandberg@arm.com                throw std::runtime_error("Invalid state!");
7111986Sandreas.sandberg@arm.com            /* Cast and construct */
7211986Sandreas.sandberg@arm.com            auto& p = self.cast<PickleableWithDict&>();
7311986Sandreas.sandberg@arm.com            new (&p) Pickleable(t[0].cast<std::string>());
7411986Sandreas.sandberg@arm.com
7511986Sandreas.sandberg@arm.com            /* Assign C++ state */
7611986Sandreas.sandberg@arm.com            p.extra = t[1].cast<int>();
7711986Sandreas.sandberg@arm.com
7811986Sandreas.sandberg@arm.com            /* Assign Python state */
7911986Sandreas.sandberg@arm.com            self.attr("__dict__") = t[2];
8011986Sandreas.sandberg@arm.com        });
8111986Sandreas.sandberg@arm.com});
82