blob: 5887312fef4e3ad03579d786210613dae0af73e7 [file]
// Copyright 2025 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 "python_dict_visitor.h"
#include <Python.h>
#include <string>
#include <fuchsia_controller_abi/utils.h>
#include "src/lib/fidl_codec/printer.h"
#include "src/lib/fidl_codec/wire_object.h"
#include "src/lib/fidl_codec/wire_types.h"
#include "utils.h"
namespace fuchsia_controller::fidl_codec::python_dict_visitor {
using FuchsiaControllerObject = ::fuchsia_controller::abi::utils::Object;
using ::fuchsia_controller::fidl_codec::utils::NormalizeMemberName;
void PythonDictVisitor::VisitValue(const ::fidl_codec::Value* node,
const ::fidl_codec::Type* for_type) {
std::stringstream ss;
::fidl_codec::PrettyPrinter printer(ss, ::fidl_codec::WithoutColors, false, "", 0, false);
node->PrettyPrint(for_type, printer);
result_ = PyUnicode_FromString(ss.str().c_str());
}
void PythonDictVisitor::VisitInvalidValue(const ::fidl_codec::InvalidValue* node,
const ::fidl_codec::Type* for_type) {
PyErr_Format(PyExc_TypeError, "invalid value for type: %s",
for_type ? for_type->Name().c_str() : "[unknown]");
}
void PythonDictVisitor::VisitNullValue(const ::fidl_codec::NullValue* node,
const ::fidl_codec::Type* for_type) {
Py_IncRef(Py_None);
result_ = Py_None;
}
void PythonDictVisitor::VisitBoolValue(const ::fidl_codec::BoolValue* node,
const ::fidl_codec::Type* for_type) {
result_ = PyBool_FromLong(node->value());
}
void PythonDictVisitor::VisitStringValue(const ::fidl_codec::StringValue* node,
const ::fidl_codec::Type* for_type) {
result_ = PyUnicode_FromStringAndSize(node->string().data(),
static_cast<Py_ssize_t>(node->string().length()));
}
void PythonDictVisitor::VisitUnionValue(const ::fidl_codec::UnionValue* node,
const ::fidl_codec::Type* type) {
auto res = FuchsiaControllerObject(PyDict_New());
PythonDictVisitor visitor;
node->value()->Visit(&visitor, node->member().type());
if (visitor.result() == nullptr) {
return;
}
PyDict_SetItemString(res.get(), NormalizeMemberName(node->member().name()).c_str(),
visitor.result());
result_ = res.take();
}
void PythonDictVisitor::VisitStructValue(const ::fidl_codec::StructValue* node,
const ::fidl_codec::Type* for_type) {
auto res = FuchsiaControllerObject(PyDict_New());
for (const auto& member : node->struct_definition().members()) {
auto it = node->fields().find(member.get());
if (it == node->fields().end()) {
continue;
}
PythonDictVisitor visitor;
it->second->Visit(&visitor, member->type());
if (visitor.result() == nullptr) {
return;
}
PyDict_SetItemString(res.get(), NormalizeMemberName(member->name()).c_str(), visitor.result());
}
result_ = res.take();
}
void PythonDictVisitor::VisitVectorValue(const ::fidl_codec::VectorValue* node,
const ::fidl_codec::Type* for_type) {
if (for_type == nullptr) {
PyErr_SetString(PyExc_TypeError,
"expected vector type in during decoding. Received null value");
return;
}
const auto component_type = for_type->GetComponentType();
if (component_type == nullptr) {
PyErr_SetString(PyExc_TypeError, "vector value's type does not contain a component type");
return;
}
auto res = FuchsiaControllerObject(PyList_New(static_cast<Py_ssize_t>(node->values().size())));
Py_ssize_t values_size = static_cast<Py_ssize_t>(node->values().size());
const auto& values = node->values();
for (Py_ssize_t i = 0; i < values_size; ++i) {
PythonDictVisitor visitor;
values[i]->Visit(&visitor, component_type);
if (visitor.result() == nullptr) {
return;
}
PyList_SetItem(res.get(), i, visitor.result());
}
result_ = res.take();
}
void PythonDictVisitor::VisitTableValue(const ::fidl_codec::TableValue* node,
const ::fidl_codec::Type* for_type) {
auto res = FuchsiaControllerObject(PyDict_New());
for (const auto& member : node->table_definition().members()) {
if (member != nullptr) {
auto it = node->members().find(member.get());
if (it == node->members().end()) {
Py_IncRef(Py_None);
PyDict_SetItemString(res.get(), NormalizeMemberName(member->name()).c_str(), Py_None);
continue;
}
if (it->second == nullptr || it->second->IsNull()) {
Py_IncRef(Py_None);
PyDict_SetItemString(res.get(), NormalizeMemberName(member->name()).c_str(), Py_None);
continue;
}
PythonDictVisitor visitor;
it->second->Visit(&visitor, member->type());
if (visitor.result() == nullptr) {
return;
}
PyDict_SetItemString(res.get(), NormalizeMemberName(member->name()).c_str(),
visitor.result());
}
}
result_ = res.take();
}
void PythonDictVisitor::VisitDoubleValue(const ::fidl_codec::DoubleValue* node,
const ::fidl_codec::Type* for_type) {
double value;
node->GetDoubleValue(&value);
result_ = PyFloat_FromDouble(value);
}
void PythonDictVisitor::VisitIntegerValue(const ::fidl_codec::IntegerValue* node,
const ::fidl_codec::Type* for_type) {
uint64_t value;
bool negative;
node->GetIntegerValue(&value, &negative);
if (negative) {
// Max possible absolute value for a signed integer (2^63).
if (value > 1ul << 63) {
PyErr_SetString(PyExc_OverflowError, "Integer overflow");
return;
}
int64_t res = static_cast<int64_t>(value);
res *= -1;
result_ = PyLong_FromLongLong(res);
} else {
result_ = PyLong_FromUnsignedLongLong(value);
}
}
void PythonDictVisitor::VisitHandleValue(const ::fidl_codec::HandleValue* handle,
const ::fidl_codec::Type* for_type) {
if (handle->handle().handle == 0) {
Py_INCREF(Py_None);
result_ = Py_None;
} else {
result_ = PyLong_FromUnsignedLongLong(handle->handle().handle);
}
}
} // namespace fuchsia_controller::fidl_codec::python_dict_visitor