blob: 386063d92e25eccea100c1bc30e3fadfcc799981 [file] [log] [blame]
// Copyright 2024 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.
#ifndef SRC_DEVELOPER_FFX_LIB_FUCHSIA_CONTROLLER_CPP_FIDL_CODEC_UTILS_H_
#define SRC_DEVELOPER_FFX_LIB_FUCHSIA_CONTROLLER_CPP_FIDL_CODEC_UTILS_H_
#include <Python.h>
#include <locale>
#include <sstream>
#include <string>
#include <unordered_set>
namespace fuchsia_controller::fidl_codec::utils {
// Converts camel case to lower snake case. Does not handle acronyms.
inline std::string ToLowerSnake(std::string_view s) {
std::stringstream ss;
auto iter = s.cbegin();
ss.put(std::tolower(*iter, std::locale()));
iter++;
for (; iter != s.cend(); ++iter) {
auto c = *iter;
if (std::isupper(c)) {
ss.put('_');
}
ss.put(std::tolower(c, std::locale()));
}
return ss.str();
}
// This is a recreation of the "normalize_member_name" function from Python.
inline std::string NormalizeMemberName(std::string_view s) {
// These keywords are taken from the Python docs:
// https://docs.python.org/3/reference/lexical_analysis.html#keywords
// Uppercase keywords have been omitted.
static std::unordered_set<std::string> python_keywords = {
// clang-format off
// LINT.IfChange
// keep-sorted start
"ArithmeticError",
"AssertionError",
"AttributeError",
"BaseException",
"BaseExceptionGroup",
"BlockingIOError",
"BrokenPipeError",
"BufferError",
"BytesWarning",
"ChildProcessError",
"ConnectionAbortedError",
"ConnectionError",
"ConnectionRefusedError",
"ConnectionResetError",
"DeprecationWarning",
"EOFError",
"Ellipsis",
"EncodingWarning",
"EnvironmentError",
"Exception",
"ExceptionGroup",
"False",
"FileExistsError",
"FileNotFoundError",
"FloatingPointError",
"FutureWarning",
"GeneratorExit",
"IOError",
"ImportError",
"ImportWarning",
"IndentationError",
"IndexError",
"InterruptedError",
"IsADirectoryError",
"KeyError",
"KeyboardInterrupt",
"LookupError",
"MemoryError",
"ModuleNotFoundError",
"NameError",
"None",
"NotADirectoryError",
"NotImplemented",
"NotImplementedError",
"OSError",
"OverflowError",
"PendingDeprecationWarning",
"PermissionError",
"ProcessLookupError",
"RecursionError",
"ReferenceError",
"ResourceWarning",
"RuntimeError",
"RuntimeWarning",
"StopAsyncIteration",
"StopIteration",
"SyntaxError",
"SyntaxWarning",
"SystemError",
"SystemExit",
"TabError",
"TimeoutError",
"True",
"TypeError",
"UnboundLocalError",
"UnicodeDecodeError",
"UnicodeEncodeError",
"UnicodeError",
"UnicodeTranslateError",
"UnicodeWarning",
"UserWarning",
"ValueError",
"Warning",
"ZeroDivisionError",
"abs",
"aiter",
"all",
"and",
"anext",
"any",
"as",
"ascii",
"assert",
"async",
"await",
"bin",
"bool",
"break",
"breakpoint",
"bytearray",
"bytes",
"callable",
"case",
"chr",
"class",
"classmethod",
"compile",
"complex",
"continue",
"copyright",
"credits",
"def",
"del",
"delattr",
"dict",
"dir",
"divmod",
"elif",
"else",
"enumerate",
"eval",
"except",
"exec",
"exit",
"filter",
"finally",
"float",
"for",
"format",
"from",
"frozenset",
"getattr",
"global",
"globals",
"hasattr",
"hash",
"help",
"hex",
"id",
"if",
"import",
"in",
"input",
"int",
"is",
"isinstance",
"issubclass",
"iter",
"lambda",
"len",
"license",
"list",
"locals",
"map",
"match",
"max",
"memoryview",
"min",
"next",
"nonlocal",
"not",
"object",
"oct",
"open",
"or",
"ord",
"pass",
"pow",
"print",
"property",
"quit",
"raise",
"range",
"repr",
"return",
"reversed",
"round",
"self",
"set",
"setattr",
"slice",
"sorted",
"staticmethod",
"str",
"sum",
"super",
"try",
"tuple",
"type",
"vars",
"while",
"with",
"yield",
"zip",
// keep-sorted end
// LINT.ThenChange(//src/developer/ffx/lib/fuchsia-controller/cpp/fidl_codec/utils.h, //tools/fidl/fidlgen_python/codegen/ir.go, //tools/fidl/gidl/backend/python/conformance.go)
// clang-format on
};
auto lower_snake = ToLowerSnake(s);
if (python_keywords.contains(lower_snake)) {
lower_snake.append("_");
}
return lower_snake;
}
static constexpr uint32_t MINUS_ONE_U32 = std::numeric_limits<uint32_t>::max();
static constexpr uint64_t MINUS_ONE_U64 = std::numeric_limits<uint64_t>::max();
static_assert(sizeof(unsigned long long) == sizeof(uint64_t)); // NOLINT
inline uint32_t PyLong_AsU32(PyObject* py_long) {
auto res = PyLong_AsUnsignedLongLong(py_long);
if (res > static_cast<uint64_t>(MINUS_ONE_U32)) {
PyErr_Format(PyExc_OverflowError, "Value %" PRIu64 " too large for u32", res);
return MINUS_ONE_U32;
}
return static_cast<uint32_t>(res);
}
inline uint64_t PyLong_AsU64(PyObject* py_long) {
return static_cast<uint64_t>(PyLong_AsUnsignedLongLong(py_long));
}
class Buffer {
public:
explicit Buffer(Py_buffer buf) : buffer_(buf) {}
~Buffer() { PyBuffer_Release(&buffer_); }
Py_ssize_t len() const { return buffer_.len; }
void* buf() const { return buffer_.buf; }
Buffer(const Buffer&) = delete;
Buffer& operator=(const Buffer&) = delete;
Buffer(Buffer&&) = delete;
Buffer& operator=(Buffer&&) = delete;
private:
Py_buffer buffer_;
};
} // namespace fuchsia_controller::fidl_codec::utils
#endif // SRC_DEVELOPER_FFX_LIB_FUCHSIA_CONTROLLER_CPP_FIDL_CODEC_UTILS_H_