| // Copyright 2019 Google Inc. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| #include "tink/cc/python_file_object_adapter.h" |
| |
| #include "pybind11/pybind11.h" |
| #include "tink/cc/pybind/status_casters.h" |
| |
| namespace crypto { |
| namespace tink { |
| |
| // Defining PYBIND11_OVERLOAD macros here for now. |
| // TODO(b/146426040): Use future macros for OSS absl::Status, StatusOr |
| // when they become available. |
| |
| // Macro to populate pybind11 trampoline class virtual methods with a |
| // util::Status return type. Converts all exceptions derived from |
| // std::exception to a StatusNotOk return. std::abort is called for |
| // all other exceptions, to ensure exceptions don't unwind through code |
| // compiled with -fno-exceptions (or similar, depending on the platform). |
| // Modeled after PYBIND11_OVERLOAD_INT defined in pybind11/pybind11.h. |
| #define PYBIND11_OVERLOAD_PURE_STATUS_RETURN(cname, name, ...) \ |
| try { \ |
| pybind11::gil_scoped_acquire gil; \ |
| pybind11::function overload = \ |
| pybind11::get_overload(static_cast<const cname *>(this), name); \ |
| if (!overload) { \ |
| return util::Status(util::error::UNIMPLEMENTED, \ |
| "No Python overload is defined for " name "."); \ |
| } \ |
| overload(__VA_ARGS__); /* Ignoring return value. */ \ |
| return util::Status(); \ |
| } catch (const std::exception &e) { \ |
| return util::Status(util::error::UNKNOWN, e.what()); \ |
| } catch (...) { \ |
| std::abort(); \ |
| } |
| |
| // Macro to populate pybind11 trampoline class virtual methods with a |
| // util::StatusOr return type. Converts all exceptions as described for |
| // PYBIND11_OVERLOAD_PURE_STATUS_RETURN. |
| #define PYBIND11_OVERLOAD_PURE_STATUSOR_RETURN(statusor_payload_type, cname, \ |
| name, ...) \ |
| try { \ |
| pybind11::gil_scoped_acquire gil; \ |
| pybind11::function overload = \ |
| pybind11::get_overload(static_cast<const cname *>(this), name); \ |
| if (!overload) { \ |
| return util::Status(util::error::UNIMPLEMENTED, \ |
| "No Python overload is defined for " name "."); \ |
| } \ |
| auto o = overload(__VA_ARGS__); \ |
| return o.cast<statusor_payload_type>(); \ |
| } catch (const std::exception &e) { \ |
| return util::Status(util::error::UNKNOWN, e.what()); \ |
| } catch (...) { \ |
| std::abort(); \ |
| } |
| |
| class Pybind11PythonFileObjectAdapter : public PythonFileObjectAdapter { |
| public: |
| // Inherit the constructors. |
| using PythonFileObjectAdapter::PythonFileObjectAdapter; |
| |
| // Trampoline for each virtual member function: |
| |
| util::StatusOr<int> Write(absl::string_view data) override{ |
| PYBIND11_OVERLOAD_PURE_STATUSOR_RETURN( |
| int, PythonFileObjectAdapter, "write", |
| pybind11::bytes(std::string(data)))} |
| |
| util::Status Close() override{ |
| PYBIND11_OVERLOAD_PURE_STATUS_RETURN(PythonFileObjectAdapter, "close")} |
| |
| util::StatusOr<std::string> Read(int size) override { |
| PYBIND11_OVERLOAD_PURE_STATUSOR_RETURN(std::string, PythonFileObjectAdapter, |
| "read", size) |
| } |
| }; |
| |
| void PybindRegisterPythonFileObjectAdapter(pybind11::module* module) { |
| namespace py = pybind11; |
| py::module& m = *module; |
| |
| // TODO(b/146492561): Reduce the number of complicated lambdas. |
| py::class_<PythonFileObjectAdapter, Pybind11PythonFileObjectAdapter, |
| std::shared_ptr<PythonFileObjectAdapter>>( |
| m, "PythonFileObjectAdapter") |
| .def(py::init<>()) |
| .def( |
| "write", |
| [](PythonFileObjectAdapter *self, |
| const py::bytes &data) -> util::StatusOr<int> { |
| return self->Write(std::string(data)); // TODO(b/145925674) |
| }, |
| py::arg("data")) |
| .def("close", &PythonFileObjectAdapter::Close) |
| .def( |
| "read", |
| [](PythonFileObjectAdapter *self, int size) |
| -> util::StatusOr<py::bytes> { return self->Read(size); }, |
| py::arg("size")); |
| } |
| |
| } // namespace tink |
| } // namespace crypto |