// Copyright (C) 2013 Davis E. King (davis@dlib.net) // License: Boost Software License See LICENSE.txt for the full license. #ifndef DLIB_SERIALIZE_PiCKLE_Hh_ #define DLIB_SERIALIZE_PiCKLE_Hh_ #include <dlib/serialize.h> #include <pybind11/pybind11.h> #include <sstream> #include <dlib/vectorstream.h> namespace py = pybind11; namespace dlib { template<typename T> py::tuple getstate(const T& item) { using namespace dlib; std::vector<char> buf; buf.reserve(5000); vectorstream sout(buf); serialize(item, sout); return py::make_tuple(py::handle( PyBytes_FromStringAndSize(buf.size()?&buf[0]:0, buf.size()))); } template<typename T> T setstate(py::tuple state) { using namespace dlib; if (len(state) != 1) { PyErr_SetObject(PyExc_ValueError, py::str("expected 1-item tuple in call to __setstate__; got {}").format(state).ptr() ); throw py::error_already_set(); } // We used to serialize by converting to a str but the boost.python routines for // doing this don't work in Python 3. You end up getting an error about invalid // UTF-8 encodings. So instead we access the python C interface directly and use // bytes objects. However, we keep the deserialization code that worked with str // for backwards compatibility with previously pickled files. T item; py::object obj = state[0]; if (py::isinstance<py::str>(obj)) { py::str data = state[0].cast<py::str>(); std::string temp = data; std::istringstream sin(temp); deserialize(item, sin); } else if(PyBytes_Check(py::object(state[0]).ptr())) { py::object obj = state[0]; char* data = PyBytes_AsString(obj.ptr()); unsigned long num = PyBytes_Size(obj.ptr()); std::istringstream sin(std::string(data, num)); deserialize(item, sin); } else { throw error("Unable to unpickle, error in input file."); } return item; } } #endif // DLIB_SERIALIZE_PiCKLE_Hh_