blob: 5aa13372e6524eadf02ec4ae7eca41143cdde843 [file] [log] [blame]
// Copyright 2023 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ir.h"
#include "mod.h"
#include "pyerrors.h"
#include "rapidjson/error/en.h"
namespace fuchsia_controller::fidl_codec::ir {
PyMethodDef add_ir_path_py_def = {
"add_ir_path", reinterpret_cast<PyCFunction>(add_ir_path), METH_O,
"Adds the FIDL IR path to the module for use in encoding/decoding. Throws an exception if the "
"file cannot be parsed, or if the file does not exist."};
PyMethodDef add_ir_paths_py_def = {"add_ir_paths", reinterpret_cast<PyCFunction>(add_ir_paths),
METH_O,
"Adds the FIDL IR files to the module's IR library in a batch"};
PyMethodDef get_method_ordinal_py_def = {
"method_ordinal", reinterpret_cast<PyCFunction>(get_method_ordinal),
METH_VARARGS | METH_KEYWORDS,
"Gets the method ordinal number for the specified method. Method is intended to be a string "
"formatted as a FIDL fully qualified name, e.g. '<library>/<declaration>.<member>'. For "
"example: 'fuchsia.developer.ffx/EchoString'. More details can be found at "
"https://fuchsia.dev/fuchsia-src/contribute/governance/rfcs/0043_documentation_comment_format#fully-qualified-names"};
PyMethodDef get_ir_path_py_def = {
"get_ir_path", reinterpret_cast<PyCFunction>(get_ir_path), METH_O,
"Attempts to get the path to the IR based on the library name. Raises an exception if it cannot be found"};
namespace {
PyObject *get_error(const ::fidl_codec::LibraryReadError &loader_err) {
switch (loader_err.value) {
case ::fidl_codec::LibraryReadError::kIoError: {
PyErr_Format(PyExc_RuntimeError, "Unable to open fidl file. Error: %s",
strerror(loader_err.errno_value));
return nullptr;
}
case ::fidl_codec::LibraryReadError::kParseError:
PyErr_SetString(PyExc_RuntimeError,
rapidjson::GetParseError_En(loader_err.parse_result.Code()));
return nullptr;
case ::fidl_codec::LibraryReadError::kOk:
break;
default:
PyErr_SetString(PyExc_RuntimeError, "Unhandled FIDL_codec return result");
return nullptr;
};
Py_RETURN_NONE;
}
} // namespace
PyObject *get_method_ordinal(PyObject *self, PyObject *args, PyObject *kwds) { // NOLINT
static const char *kwlist[] = {"protocol", "method", nullptr};
const char *c_protocol;
const char *c_method;
if (!PyArg_ParseTupleAndKeywords(args, kwds, "ss", const_cast<char **>(kwlist), &c_protocol,
&c_method)) {
return nullptr;
}
std::string_view protocol(c_protocol);
auto const idx = protocol.find('/');
if (idx == std::string::npos) {
PyErr_SetString(PyExc_ValueError,
"protocol not formatted properly, expected {library}/{protocol}");
return nullptr;
}
const std::string library(c_protocol, idx);
std::string_view method(c_method);
auto lib = mod::get_ir_library(library);
if (lib == nullptr) {
return nullptr;
}
::fidl_codec::Protocol *codec_protocol;
if (!lib->GetProtocolByName(protocol, &codec_protocol)) {
PyErr_Format(PyExc_RuntimeError, "Unable to find protocol %s under library %s", c_protocol,
library.c_str());
return nullptr;
}
auto codec_method = codec_protocol->GetMethodByName(method);
if (codec_method == nullptr) {
PyErr_Format(PyExc_RuntimeError, "Unable to find method %s under protocol %s in library %s",
method, protocol, library.c_str());
return nullptr;
}
return PyLong_FromUnsignedLongLong(codec_method->ordinal());
}
PyObject *add_ir_path(PyObject *self, PyObject *path_obj) { // NOLINT
const char *c_path = PyUnicode_AsUTF8AndSize(path_obj, nullptr);
if (c_path == nullptr) {
return nullptr;
}
auto path = std::string(c_path);
::fidl_codec::LibraryReadError loader_err;
mod::get_module_state()->loader->AddPath(path, &loader_err);
return get_error(loader_err);
}
PyObject *get_ir_path(PyObject *self, PyObject *library_name) { // NOLINT
const char *c_lib = PyUnicode_AsUTF8AndSize(library_name, nullptr);
if (c_lib == nullptr) {
return nullptr;
}
auto lib = std::string(c_lib);
::fidl_codec::Library *ir_lib = mod::get_ir_library(lib);
if (ir_lib == nullptr) {
return nullptr;
}
std::string_view ir_lib_source = ir_lib->source();
if (ir_lib_source.empty()) {
PyErr_Format(
PyExc_RuntimeError,
"Library '%s' is loaded but has no associated source file, implying it was loaded directly"
"from a string",
c_lib);
return nullptr;
}
return PyUnicode_FromStringAndSize(ir_lib_source.data(),
static_cast<Py_ssize_t>(ir_lib_source.size()));
}
PyObject *add_ir_paths(PyObject *self, PyObject *path_list) { // NOLINT
if (!PyList_Check(path_list)) {
PyErr_SetString(PyExc_TypeError, "Expected path_list to be a list");
return nullptr;
}
auto len = PyList_Size(path_list);
std::vector<std::string> paths(len);
for (Py_ssize_t i = 0; i < len; ++i) {
auto elmnt = PyList_GetItem(path_list, i);
if (elmnt == nullptr) {
return nullptr;
}
const char *elmnt_str = PyUnicode_AsUTF8AndSize(elmnt, nullptr);
if (elmnt_str == nullptr) {
return nullptr;
}
paths[i] = std::string(elmnt_str);
}
::fidl_codec::LibraryReadError loader_err;
mod::get_module_state()->loader->AddAll(paths, &loader_err);
return get_error(loader_err);
}
} // namespace fuchsia_controller::fidl_codec::ir