test_pickling.cpp revision 11986
112855Sgabeblack@google.com/*
212855Sgabeblack@google.com    tests/test_pickling.cpp -- pickle support
312855Sgabeblack@google.com
412855Sgabeblack@google.com    Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
512855Sgabeblack@google.com
612855Sgabeblack@google.com    All rights reserved. Use of this source code is governed by a
712855Sgabeblack@google.com    BSD-style license that can be found in the LICENSE file.
812855Sgabeblack@google.com*/
912855Sgabeblack@google.com
1012855Sgabeblack@google.com#include "pybind11_tests.h"
1112855Sgabeblack@google.com
1212855Sgabeblack@google.comclass Pickleable {
1312855Sgabeblack@google.compublic:
1412855Sgabeblack@google.com    Pickleable(const std::string &value) : m_value(value) { }
1512855Sgabeblack@google.com    const std::string &value() const { return m_value; }
1612855Sgabeblack@google.com
1712855Sgabeblack@google.com    void setExtra1(int extra1) { m_extra1 = extra1; }
1812855Sgabeblack@google.com    void setExtra2(int extra2) { m_extra2 = extra2; }
1912855Sgabeblack@google.com    int extra1() const { return m_extra1; }
2012855Sgabeblack@google.com    int extra2() const { return m_extra2; }
2112855Sgabeblack@google.comprivate:
2212855Sgabeblack@google.com    std::string m_value;
2312855Sgabeblack@google.com    int m_extra1 = 0;
2412855Sgabeblack@google.com    int m_extra2 = 0;
2512855Sgabeblack@google.com};
2612855Sgabeblack@google.com
2712855Sgabeblack@google.comclass PickleableWithDict {
2812855Sgabeblack@google.compublic:
2912855Sgabeblack@google.com    PickleableWithDict(const std::string &value) : value(value) { }
3012855Sgabeblack@google.com
3112855Sgabeblack@google.com    std::string value;
3212855Sgabeblack@google.com    int extra;
3312855Sgabeblack@google.com};
3412855Sgabeblack@google.com
3512855Sgabeblack@google.comtest_initializer pickling([](py::module &m) {
3612855Sgabeblack@google.com    py::class_<Pickleable>(m, "Pickleable")
3712855Sgabeblack@google.com        .def(py::init<std::string>())
3812855Sgabeblack@google.com        .def("value", &Pickleable::value)
3912855Sgabeblack@google.com        .def("extra1", &Pickleable::extra1)
4012855Sgabeblack@google.com        .def("extra2", &Pickleable::extra2)
4112855Sgabeblack@google.com        .def("setExtra1", &Pickleable::setExtra1)
4212855Sgabeblack@google.com        .def("setExtra2", &Pickleable::setExtra2)
4312855Sgabeblack@google.com        // For details on the methods below, refer to
4412855Sgabeblack@google.com        // http://docs.python.org/3/library/pickle.html#pickling-class-instances
4512855Sgabeblack@google.com        .def("__getstate__", [](const Pickleable &p) {
4612855Sgabeblack@google.com            /* Return a tuple that fully encodes the state of the object */
4712855Sgabeblack@google.com            return py::make_tuple(p.value(), p.extra1(), p.extra2());
4812855Sgabeblack@google.com        })
4912855Sgabeblack@google.com        .def("__setstate__", [](Pickleable &p, py::tuple t) {
5012855Sgabeblack@google.com            if (t.size() != 3)
5112855Sgabeblack@google.com                throw std::runtime_error("Invalid state!");
5212855Sgabeblack@google.com            /* Invoke the constructor (need to use in-place version) */
5312855Sgabeblack@google.com            new (&p) Pickleable(t[0].cast<std::string>());
5412855Sgabeblack@google.com
5512855Sgabeblack@google.com            /* Assign any additional state */
5612855Sgabeblack@google.com            p.setExtra1(t[1].cast<int>());
5712855Sgabeblack@google.com            p.setExtra2(t[2].cast<int>());
5812855Sgabeblack@google.com        });
5912855Sgabeblack@google.com
6012855Sgabeblack@google.com    py::class_<PickleableWithDict>(m, "PickleableWithDict", py::dynamic_attr())
6112855Sgabeblack@google.com        .def(py::init<std::string>())
6212855Sgabeblack@google.com        .def_readwrite("value", &PickleableWithDict::value)
6312855Sgabeblack@google.com        .def_readwrite("extra", &PickleableWithDict::extra)
6412855Sgabeblack@google.com        .def("__getstate__", [](py::object self) {
6512855Sgabeblack@google.com            /* Also include __dict__ in state */
6612855Sgabeblack@google.com            return py::make_tuple(self.attr("value"), self.attr("extra"), self.attr("__dict__"));
6712855Sgabeblack@google.com        })
6812855Sgabeblack@google.com        .def("__setstate__", [](py::object self, py::tuple t) {
6912855Sgabeblack@google.com            if (t.size() != 3)
7012855Sgabeblack@google.com                throw std::runtime_error("Invalid state!");
7112855Sgabeblack@google.com            /* Cast and construct */
7212855Sgabeblack@google.com            auto& p = self.cast<PickleableWithDict&>();
7312855Sgabeblack@google.com            new (&p) Pickleable(t[0].cast<std::string>());
7412855Sgabeblack@google.com
7512855Sgabeblack@google.com            /* Assign C++ state */
7612855Sgabeblack@google.com            p.extra = t[1].cast<int>();
7712855Sgabeblack@google.com
7812855Sgabeblack@google.com            /* Assign Python state */
7912855Sgabeblack@google.com            self.attr("__dict__") = t[2];
8012855Sgabeblack@google.com        });
8112855Sgabeblack@google.com});
82