blob: 49d080e372e9b70b1ba50aa33c49681a6bb9527d [file] [log] [blame]
// 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