| // 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_FUCHSIA_CONTROLLER_CPP_FIDL_CODEC_UTILS_H_ | |
| #define SRC_DEVELOPER_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/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_FUCHSIA_CONTROLLER_CPP_FIDL_CODEC_UTILS_H_ |