Show a patch.

GET /api/patches/22147/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 22147,
    "url": "https://patchwork.libcamera.org/api/patches/22147/?format=api",
    "web_url": "https://patchwork.libcamera.org/patch/22147/",
    "project": {
        "id": 1,
        "url": "https://patchwork.libcamera.org/api/projects/1/?format=api",
        "name": "libcamera",
        "link_name": "libcamera",
        "list_id": "libcamera_core",
        "list_email": "libcamera-devel@lists.libcamera.org",
        "web_url": "",
        "scm_url": "",
        "webscm_url": ""
    },
    "msgid": "<20241202133404.41431-2-jacopo.mondi@ideasonboard.com>",
    "date": "2024-12-02T13:34:00",
    "name": "[v2,1/4] libcamera: Implement YamlEmitter",
    "commit_ref": null,
    "pull_url": null,
    "state": "new",
    "archived": false,
    "hash": "fb78d53d41a0ab3be487841b48d5255d0018b9ca",
    "submitter": {
        "id": 143,
        "url": "https://patchwork.libcamera.org/api/people/143/?format=api",
        "name": "Jacopo Mondi",
        "email": "jacopo.mondi@ideasonboard.com"
    },
    "delegate": null,
    "mbox": "https://patchwork.libcamera.org/patch/22147/mbox/",
    "series": [
        {
            "id": 4837,
            "url": "https://patchwork.libcamera.org/api/series/4837/?format=api",
            "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=4837",
            "date": "2024-12-02T13:33:59",
            "name": "libcamera: Add support for dumping capture script in YAML",
            "version": 2,
            "mbox": "https://patchwork.libcamera.org/series/4837/mbox/"
        }
    ],
    "comments": "https://patchwork.libcamera.org/api/patches/22147/comments/",
    "check": "pending",
    "checks": "https://patchwork.libcamera.org/api/patches/22147/checks/",
    "tags": {},
    "headers": {
        "Return-Path": "<libcamera-devel-bounces@lists.libcamera.org>",
        "X-Original-To": "parsemail@patchwork.libcamera.org",
        "Delivered-To": "parsemail@patchwork.libcamera.org",
        "Received": [
            "from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id 1C7BFBEFBE\n\tfor <parsemail@patchwork.libcamera.org>;\n\tMon,  2 Dec 2024 13:34:17 +0000 (UTC)",
            "from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 8C53766069;\n\tMon,  2 Dec 2024 14:34:13 +0100 (CET)",
            "from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 929AD66040\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon,  2 Dec 2024 14:34:10 +0100 (CET)",
            "from ideasonboard.com (mob-5-90-236-68.net.vodafone.it\n\t[5.90.236.68])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id A64D275A;\n\tMon,  2 Dec 2024 14:33:43 +0100 (CET)"
        ],
        "Authentication-Results": "lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"NWJR6iRC\"; dkim-atps=neutral",
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1733146424;\n\tbh=4clINLyOxNeTfw/ssU7qARDlzT04DLr1FwFQfBDRrVY=;\n\th=From:To:Cc:Subject:Date:In-Reply-To:References:From;\n\tb=NWJR6iRCP+hOVExUglJ+foKJlMY0rkXJDqEzqsUm+dyC4b8oLb3GU6UQBlcld+LM0\n\tmSyh8CR/kK72Ru+2mM7DLVNyjd5XAXl/vhV366aR0+YicrFCeUvV9GqqWpwfBqbFQb\n\tRhFNgGsAHLngvluCx6hdTphByp/3MU/wFNnDlv54=",
        "From": "Jacopo Mondi <jacopo.mondi@ideasonboard.com>",
        "To": "libcamera-devel@lists.libcamera.org",
        "Cc": "Jacopo Mondi <jacopo.mondi@ideasonboard.com>",
        "Subject": "[PATCH v2 1/4] libcamera: Implement YamlEmitter",
        "Date": "Mon,  2 Dec 2024 14:34:00 +0100",
        "Message-ID": "<20241202133404.41431-2-jacopo.mondi@ideasonboard.com>",
        "X-Mailer": "git-send-email 2.47.0",
        "In-Reply-To": "<20241202133404.41431-1-jacopo.mondi@ideasonboard.com>",
        "References": "<20241202133404.41431-1-jacopo.mondi@ideasonboard.com>",
        "MIME-Version": "1.0",
        "Content-Transfer-Encoding": "8bit",
        "X-BeenThere": "libcamera-devel@lists.libcamera.org",
        "X-Mailman-Version": "2.1.29",
        "Precedence": "list",
        "List-Id": "<libcamera-devel.lists.libcamera.org>",
        "List-Unsubscribe": "<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>",
        "List-Archive": "<https://lists.libcamera.org/pipermail/libcamera-devel/>",
        "List-Post": "<mailto:libcamera-devel@lists.libcamera.org>",
        "List-Help": "<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>",
        "List-Subscribe": "<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>",
        "Errors-To": "libcamera-devel-bounces@lists.libcamera.org",
        "Sender": "\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"
    },
    "content": "Implement a helpers to allow outputting text in YAML format.\n\nThe class of helpers allows to create list and dictionaries and emit\nscalar values starting from a YamlRoot object initialized with\na file path.\n\nSigned-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>\n---\n include/libcamera/internal/meson.build    |   1 +\n include/libcamera/internal/yaml_emitter.h | 149 +++++\n src/libcamera/meson.build                 |   1 +\n src/libcamera/yaml_emitter.cpp            | 719 ++++++++++++++++++++++\n 4 files changed, 870 insertions(+)\n create mode 100644 include/libcamera/internal/yaml_emitter.h\n create mode 100644 src/libcamera/yaml_emitter.cpp",
    "diff": "diff --git a/include/libcamera/internal/meson.build b/include/libcamera/internal/meson.build\nindex 1dddcd50c90b..357d96566cfb 100644\n--- a/include/libcamera/internal/meson.build\n+++ b/include/libcamera/internal/meson.build\n@@ -42,6 +42,7 @@ libcamera_internal_headers = files([\n     'v4l2_pixelformat.h',\n     'v4l2_subdevice.h',\n     'v4l2_videodevice.h',\n+    'yaml_emitter.h',\n     'yaml_parser.h',\n ])\n \ndiff --git a/include/libcamera/internal/yaml_emitter.h b/include/libcamera/internal/yaml_emitter.h\nnew file mode 100644\nindex 000000000000..22b3c43b919d\n--- /dev/null\n+++ b/include/libcamera/internal/yaml_emitter.h\n@@ -0,0 +1,149 @@\n+/* SPDX-License-Identifier: LGPL-2.1-or-later */\n+/*\n+ * Copyright (C) 2024, Ideas On Board Oy\n+ *\n+ * libcamera YAML emitter helper\n+ */\n+\n+#pragma once\n+\n+#include <memory>\n+#include <string>\n+#include <string_view>\n+\n+#include <libcamera/base/class.h>\n+#include <libcamera/base/file.h>\n+\n+#include <yaml.h>\n+\n+namespace libcamera {\n+\n+class YamlDict;\n+class YamlEvent;\n+class YamlList;\n+class YamlRoot;\n+class YamlScalar;\n+\n+class YamlEmitter final\n+{\n+public:\n+\t~YamlEmitter();\n+\n+\tstatic YamlRoot root(const std::string &path);\n+\n+private:\n+\tfriend class YamlOutput;\n+\tfriend class YamlRoot;\n+\n+\tLIBCAMERA_DISABLE_COPY(YamlEmitter)\n+\n+\tYamlEmitter(const std::string &path);\n+\n+\tvoid logError();\n+\tvoid init();\n+\tint emit();\n+\n+\tFile file_;\n+\tyaml_event_t event_;\n+\tyaml_emitter_t emitter_;\n+};\n+\n+class YamlOutput\n+{\n+public:\n+\tbool valid() const { return !!emitter_; }\n+\n+protected:\n+\tYamlOutput() = default;\n+\tYamlOutput(YamlOutput &&other);\n+\tYamlOutput(YamlEmitter *emitter, YamlOutput *parent);\n+\n+\tvirtual ~YamlOutput();\n+\n+\tYamlOutput &operator=(YamlOutput &&other);\n+\n+\tint emitScalar(std::string_view scalar);\n+\tint emitMappingStart();\n+\tint emitMappingEnd();\n+\tint emitSequenceStart();\n+\tint emitSequenceEnd();\n+\n+\tYamlDict dict(YamlOutput *parent);\n+\tYamlList list(YamlOutput *parent);\n+\n+\tYamlEmitter *emitter_ = nullptr;\n+\tyaml_event_t event_;\n+\n+\tYamlOutput *parent_ = nullptr;\n+\tYamlOutput *child_ = nullptr;\n+\n+private:\n+\tLIBCAMERA_DISABLE_COPY(YamlOutput)\n+\n+\tvoid unlinkChildren(YamlOutput *node);\n+};\n+\n+class YamlRoot : public YamlOutput\n+{\n+public:\n+\tYamlRoot() = default;\n+\tYamlRoot(YamlRoot &&other) = default;\n+\t~YamlRoot();\n+\n+\tYamlRoot &operator=(YamlRoot &&other) = default;\n+\n+\tYamlList list();\n+\tYamlDict dict();\n+\n+private:\n+\tLIBCAMERA_DISABLE_COPY(YamlRoot)\n+\n+\tfriend class YamlEmitter;\n+\n+\tYamlRoot(std::unique_ptr<YamlEmitter> emitter)\n+\t\t: YamlOutput(emitter.get(), nullptr), emitterRoot_(std::move(emitter))\n+\t{\n+\t}\n+\n+\tstd::unique_ptr<YamlEmitter> emitterRoot_;\n+};\n+\n+class YamlList : public YamlOutput\n+{\n+public:\n+\tYamlList() = default;\n+\tYamlList(YamlList &&other) = default;\n+\t~YamlList();\n+\n+\tYamlList &operator=(YamlList &&other) = default;\n+\n+\tYamlList list();\n+\tYamlDict dict();\n+\tvoid scalar(std::string_view scalar);\n+\n+private:\n+\tfriend class YamlOutput;\n+\n+\tYamlList(YamlEmitter *emitter, YamlOutput *parent);\n+};\n+\n+class YamlDict : public YamlOutput\n+{\n+public:\n+\tYamlDict() = default;\n+\tYamlDict(YamlDict &&other) = default;\n+\t~YamlDict();\n+\n+\tYamlDict &operator=(YamlDict &&other) = default;\n+\n+\tYamlList list(std::string_view key);\n+\tYamlDict dict(std::string_view key);\n+\tvoid scalar(std::string_view key, std::string_view scalar);\n+\n+private:\n+\tfriend class YamlOutput;\n+\n+\tYamlDict(YamlEmitter *emitter, YamlOutput *parent);\n+};\n+\n+} /* namespace libcamera */\ndiff --git a/src/libcamera/meson.build b/src/libcamera/meson.build\nindex 21cae11756d6..933b98bf05e9 100644\n--- a/src/libcamera/meson.build\n+++ b/src/libcamera/meson.build\n@@ -52,6 +52,7 @@ libcamera_internal_sources = files([\n     'v4l2_pixelformat.cpp',\n     'v4l2_subdevice.cpp',\n     'v4l2_videodevice.cpp',\n+    'yaml_emitter.cpp',\n     'yaml_parser.cpp',\n ])\n \ndiff --git a/src/libcamera/yaml_emitter.cpp b/src/libcamera/yaml_emitter.cpp\nnew file mode 100644\nindex 000000000000..c0629e249c57\n--- /dev/null\n+++ b/src/libcamera/yaml_emitter.cpp\n@@ -0,0 +1,719 @@\n+/* SPDX-License-Identifier: LGPL-2.1-or-later */\n+/*\n+ * Copyright (C) 2024, Ideas On Board Oy\n+ *\n+ * libcamera YAML emitter helper\n+ */\n+\n+#include \"libcamera/internal/yaml_emitter.h\"\n+\n+#include <libcamera/base/log.h>\n+\n+/**\n+ * \\file yaml_emitter.h\n+ * \\brief A YAML emitter helper\n+ *\n+ * The YAML emitter helpers allow users to emit output in YAML format.\n+\n+ * Unlike YAML writers that operate on a fully populated representation of the\n+ * data, the YAML emitter outputs YAML data on the fly. It is suitable for\n+ * outputting large amount of data with low overhead and no runtime heap\n+ * allocation.\n+ *\n+ * To emit YAML users of the these helper classes create a root node with\n+ *\n+ * \\code\n+\tstd::string filePath(\"...\");\n+\tauto root = YamlEmitter::root(filePath);\n+   \\endcode\n+ *\n+ * and start emitting dictionaries and lists with the YamlRoot::dict() and\n+ * YamlRoot::list() functions.\n+ *\n+ * The classes part of this file implement RAII-style handling of YAML\n+ * events. By creating a YamlList and YamlDict instance the associated YAML\n+ * sequence start and mapping start events are emitted and once the instances\n+ * gets destroyed the corresponding sequence end and mapping end events are\n+ * emitted.\n+ *\n+ * From an initialized YamlRoot instance is possible to create YAML list and\n+ * dictionaries.\n+ *\n+ * \\code\n+\tYamlDict dict = root.dict();\n+\tYamlList list = root.list();\n+   \\endcode\n+ *\n+ * YamlDict instances can be populated with scalars associated with a key\n+ *\n+ * \\code\n+\tdict[\"key\"] = \"value\";\n+   \\endcode\n+ *\n+ * and it is possible to create lists and dictionaries, associated with a key\n+ *\n+ * \\code\n+\tYamlDict subDict = dict.dict(\"newDict\");\n+\tYamlList subList = dict.list(\"newList\");\n+   \\endcode\n+ *\n+ * YamlList instances can be populated with scalar elements\n+ *\n+ * \\code\n+\tlist.scalar(\"x\");\n+\tlist.scalar(\"y\");\n+   \\endcode\n+ *\n+ * and with dictionaries and lists too\n+ *\n+ * \\code\n+\tYamlDict subDict = list.dict();\n+\tYamlList subList = list.list();\n+   \\endcode\n+ */\n+\n+namespace libcamera {\n+\n+LOG_DEFINE_CATEGORY(YamlEmitter)\n+\n+namespace {\n+\n+int yamlWrite(void *data, unsigned char *buffer, size_t size)\n+{\n+\tFile *file = static_cast<File *>(data);\n+\n+\tSpan<unsigned char> buf{ buffer, size };\n+\tssize_t ret = file->write(buf);\n+\tif (ret < 0) {\n+\t\tLOG(YamlEmitter, Error) << \"Write error: \" << strerror(ret);\n+\t\treturn 0;\n+\t}\n+\n+\treturn 1;\n+}\n+\n+} /* namespace */\n+\n+/**\n+ * \\class YamlEmitter\n+ *\n+ * YAML helper classes entry point. This class allows to create a YamlRoot\n+ * instance, using the YamlEmitter::root() function, that users can populate\n+ * with lists, dictionaries and scalars.\n+ */\n+\n+YamlEmitter::YamlEmitter(const std::string &path)\n+{\n+\tfile_.setFileName(path);\n+\tfile_.open(File::OpenModeFlag::WriteOnly);\n+}\n+\n+YamlEmitter::~YamlEmitter()\n+{\n+\tyaml_event_delete(&event_);\n+\tyaml_emitter_delete(&emitter_);\n+}\n+\n+/**\n+ * \\brief Create an initialized instance of YamlRoot\n+ * \\param[in] path The YAML output file path\n+ *\n+ * Create an initialized instance of the YamlRoot class that users can start\n+ * using and populating with scalars, lists and dictionaries.\n+ *\n+ * \\return An initialized YamlRoot instance\n+ */\n+YamlRoot YamlEmitter::root(const std::string &path)\n+{\n+\tstd::unique_ptr<YamlEmitter> emitter{ new YamlEmitter(path) };\n+\n+\temitter->init();\n+\n+\treturn YamlRoot(std::move(emitter));\n+}\n+\n+void YamlEmitter::logError()\n+{\n+\tswitch (emitter_.error) {\n+\tcase YAML_MEMORY_ERROR:\n+\t\tLOG(YamlEmitter, Error)\n+\t\t\t<< \"Memory error: Not enough memory for emitting\";\n+\t\tbreak;\n+\n+\tcase YAML_WRITER_ERROR:\n+\t\tLOG(YamlEmitter, Error)\n+\t\t\t<< \"Writer error: \" << emitter_.problem;\n+\t\tbreak;\n+\n+\tcase YAML_EMITTER_ERROR:\n+\t\tLOG(YamlEmitter, Error)\n+\t\t\t<< \"Emitter error: \" << emitter_.problem;\n+\t\tbreak;\n+\n+\tdefault:\n+\t\tLOG(YamlEmitter, Error) << \"Internal error\";\n+\t\tbreak;\n+\t}\n+}\n+\n+void YamlEmitter::init()\n+{\n+\tyaml_emitter_initialize(&emitter_);\n+\tyaml_emitter_set_output(&emitter_, yamlWrite, &file_);\n+\n+\tyaml_stream_start_event_initialize(&event_, YAML_UTF8_ENCODING);\n+\temit();\n+\n+\tyaml_document_start_event_initialize(&event_, nullptr, nullptr,\n+\t\t\t\t\t     nullptr, 0);\n+\temit();\n+}\n+\n+int YamlEmitter::emit()\n+{\n+\tint ret = yaml_emitter_emit(&emitter_, &event_);\n+\tif (!ret) {\n+\t\tlogError();\n+\t\treturn -EINVAL;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * \\class YamlOutput\n+ *\n+ * The YamlOutput base class. From this class are derived the YamlList and\n+ * YamlDict classes which are meant to be used by users of the YAML emitter\n+ * helpers.\n+ *\n+ * The YamlOutput base class provides functions to create YAML lists and\n+ * dictionaries and to populate them.\n+ *\n+ * This class cannot be instantiated directly.\n+ */\n+\n+/**\n+ * \\fn YamlOutput::YamlOutput()\n+ * \\brief The default constructor\n+ *\n+ * Create an empty, non-initialized instance. The newly created instance cannot\n+ * be used without being first move-assigned to a valid and initialized\n+ * instance. Valid instances of this class can only be created using the\n+ * YamlRoot::list(), YamlRoot::dict(), YamlList::list(), YamlList::dict(),\n+ * YamlDict::list() and YamlDict::dict() functions.\n+ */\n+\n+/**\n+ * \\brief Create a YamlOutput instance with an associated \\a emitter and \\a parent\n+ * \\param[in] emitter The YAML emitter\n+ * \\param[in] parent Pointer to the parent node\n+ *\n+ * Create a YamlOutput with a valid YamlEmitter and with a reference to the\n+ * parent node. The parent's child_ pointer is assigned to the newly created\n+ * instance. If the parent already has a valid child_ reference, unlink and\n+ * invalidate the chain of previously assigned children nodes by resetting their\n+ * parent_ pointer. None of the children nodes can be used anymore from this\n+ * point on.\n+ */\n+YamlOutput::YamlOutput(YamlEmitter *emitter, YamlOutput *parent)\n+\t: emitter_(emitter), parent_(parent)\n+{\n+\tif (!parent_)\n+\t\treturn;\n+\n+\tunlinkChildren(parent_->child_);\n+\tparent_->child_ = this;\n+}\n+\n+/**\n+ * \\brief Move constructor\n+ * \\param[in] other The instance to be moved\n+ *\n+ * Move an instance and invalidate \\a other. The move constructor reassigns\n+ * the parent's child_ to point to the newly initialized instance.\n+ */\n+YamlOutput::YamlOutput(YamlOutput &&other)\n+{\n+\temitter_ = other.emitter_;\n+\tevent_ = other.event_;\n+\tparent_ = other.parent_;\n+\tchild_ = other.child_;\n+\n+\tother.emitter_ = nullptr;\n+\tother.event_ = {};\n+\tother.parent_ = nullptr;\n+\tother.child_ = nullptr;\n+\n+\tif (parent_)\n+\t\tparent_->child_ = this;\n+}\n+\n+YamlOutput::~YamlOutput()\n+{\n+\tif (parent_)\n+\t\tparent_->child_ = nullptr;\n+}\n+\n+void YamlOutput::unlinkChildren(YamlOutput *node)\n+{\n+\tYamlOutput *nextNode = node;\n+\twhile (nextNode) {\n+\t\tYamlOutput *nextChild = nextNode->child_;\n+\n+\t\tnextNode->parent_ = nullptr;\n+\t\tnextNode->child_ = nullptr;\n+\t\tnextNode = nextChild;\n+\t}\n+}\n+\n+/**\n+ * \\brief Move assignment operator\n+ * \\param[in] other The instance to be moved\n+ *\n+ * Move-assign an instance and invalidate \\a other. The move assignment operator\n+ * reassigns the parent's child_ to point to the newly initialized instance.\n+ */\n+YamlOutput &YamlOutput::operator=(YamlOutput &&other)\n+{\n+\temitter_ = other.emitter_;\n+\tevent_ = other.event_;\n+\tparent_ = other.parent_;\n+\tchild_ = other.child_;\n+\n+\tother.emitter_ = nullptr;\n+\tother.event_ = {};\n+\tother.parent_ = nullptr;\n+\tother.child_ = nullptr;\n+\n+\tif (parent_)\n+\t\tparent_->child_ = this;\n+\n+\treturn *this;\n+}\n+\n+/**\n+ * \\fn YamlOutput::valid()\n+ * \\brief Check if a YamlOutput instance has been correctly initialized\n+ * \\return True if the instance has been initialized, false otherwise\n+ */\n+\n+/**\n+ * \\brief Emit \\a scalar as a YAML scalar\n+ * \\param[in] scalar The element to emit\n+ * \\return 0 in case of success, a negative error value otherwise\n+ */\n+int YamlOutput::emitScalar(std::string_view scalar)\n+{\n+\tif (!valid())\n+\t\treturn -EINVAL;\n+\n+\tconst yaml_char_t *value = reinterpret_cast<const yaml_char_t *>\n+\t\t\t\t   (scalar.data());\n+\n+\t/*\n+\t * \\todo Remove the const_cast<yaml_char_t> of 'value' when\n+\t * dropping support for libyaml versions < 0.2.3 (shipped in Debian11).\n+\t *\n+\t * https://github.com/yaml/libyaml/pull/140\n+\t */\n+\tyaml_scalar_event_initialize(&emitter_->event_, nullptr, nullptr,\n+\t\t\t\t     const_cast<yaml_char_t *>(value),\n+\t\t\t\t     scalar.length(), true, false,\n+\t\t\t\t     YAML_PLAIN_SCALAR_STYLE);\n+\treturn emitter_->emit();\n+}\n+\n+/**\n+ * \\brief Emit the mapping start YAML event\n+ * \\return 0 in case of success, a negative error value otherwise\n+ */\n+int YamlOutput::emitMappingStart()\n+{\n+\tif (!valid())\n+\t\treturn -EINVAL;\n+\n+\tyaml_mapping_start_event_initialize(&emitter_->event_, nullptr, nullptr,\n+\t\t\t\t\t    true, YAML_BLOCK_MAPPING_STYLE);\n+\treturn emitter_->emit();\n+}\n+\n+/**\n+ * \\brief Emit the mapping end YAML event\n+ * \\return 0 in case of success, a negative error value otherwise\n+ */\n+int YamlOutput::emitMappingEnd()\n+{\n+\tif (!valid())\n+\t\treturn -EINVAL;\n+\n+\tyaml_mapping_end_event_initialize(&emitter_->event_);\n+\treturn emitter_->emit();\n+}\n+\n+/**\n+ * \\brief Emit the sequence start YAML event\n+ * \\return 0 in case of success, a negative error value otherwise\n+ */\n+int YamlOutput::emitSequenceStart()\n+{\n+\tif (!valid())\n+\t\treturn -EINVAL;\n+\n+\tyaml_sequence_start_event_initialize(&emitter_->event_, nullptr, nullptr,\n+\t\t\t\t\t     true, YAML_BLOCK_SEQUENCE_STYLE);\n+\treturn emitter_->emit();\n+}\n+\n+/**\n+ * \\brief Emit the sequence end YAML event\n+ * \\return 0 in case of success, a negative error value otherwise\n+ */\n+int YamlOutput::emitSequenceEnd()\n+{\n+\tif (!valid())\n+\t\treturn -EINVAL;\n+\n+\tyaml_sequence_end_event_initialize(&emitter_->event_);\n+\treturn emitter_->emit();\n+}\n+\n+/**\n+ * \\brief Create a dictionary instance\n+ * \\return An instance of YamlDict\n+ */\n+YamlDict YamlOutput::dict(YamlOutput *parent)\n+{\n+\treturn YamlDict(emitter_, parent);\n+}\n+\n+/**\n+ * \\brief Create a list instance\n+ * \\return An instance of YamlList\n+ */\n+YamlList YamlOutput::list(YamlOutput *parent)\n+{\n+\treturn YamlList(emitter_, parent);\n+}\n+\n+/**\n+ * \\var YamlOutput::emitter_\n+ * \\brief The emitter used by this YamlObject to output YAML events\n+ */\n+\n+/**\n+ * \\var YamlOutput::event_\n+ * \\brief The YAML event used by this YamlObject\n+ */\n+\n+/**\n+ * \\var YamlOutput::parent_\n+ * \\brief The parent node, set at object creation time\n+ *\n+ * The parent_ class member references the parent node. Only nodes with a valid\n+ * parent can emit valid YAML output. The parent_ pointer is reset to an invalid\n+ * value when a new child is created on the parent node, effectively\n+ * invalidating the current instance.\n+ */\n+\n+/**\n+ * \\var YamlOutput::child_\n+ * \\brief The child node\n+ *\n+ * The child_ class member references any eventual child created from the\n+ * current instance using the list() and dict() functions. Only a single\n+ * valid child_ at the time can be assigned to a YamlOutput instance, if\n+ * multiple child are created the last created ones overwrites the child_\n+ * pointer and invalidates all other children.\n+ */\n+\n+/**\n+ * \\class YamlRoot\n+ *\n+ * The YAML root node. A valid YamlRoot instance can only be created using the\n+ * YamlEmitter::root() function. The typical initialization pattern of users of\n+ * this class is similar to the one in the following example:\n+ *\n+ * \\code\n+\tclass YamlUser\n+\t{\n+\tpublic:\n+\t\tYamlUser();\n+\n+\tprivate:\n+\t\tYamlRool root_;\n+\t};\n+\n+\tYamlUser::YamlUser()\n+\t{\n+\t\troot_ = YamlEmitter::root(\"/path/to/yaml/file.yml\");\n+\t}\n+   \\endcode\n+ *\n+ * A YamlRoot element can be populated with list and dictionaries.\n+ */\n+\n+/**\n+ * \\fn YamlRoot::YamlRoot()\n+ * \\brief Construct a YamlRoot instance without initializing it\n+ *\n+ * A YamlRoot instance can be created in non-initialized state typically to be\n+ * stored as a class member to maintain their lifetime active. In order to start\n+ * using and populating a YamlRoot, a valid and initialized instance created\n+ * using the YamlEmitter::root() function has to be move-assigned to a\n+ * non-initialized instance.\n+ *\n+ * \\code\n+\tYamlRoot root;\n+\n+\troot = YamlEmitter::root(\"/path/to/yaml/file.yml\");\n+   \\endcode\n+ */\n+\n+/**\n+ * \\fn YamlRoot::YamlRoot()\n+ * \\copydoc YamlOutput::YamlOutput()\n+ */\n+\n+/**\n+ * \\fn YamlRoot &YamlRoot::YamlRoot(YamlRoot &&other)\n+ * \\copydoc YamlOutput &YamlOutput::YamlOutput(YamlOutput &&other)\n+ */\n+\n+YamlRoot::~YamlRoot()\n+{\n+\tif (!valid())\n+\t\treturn;\n+\n+\tyaml_document_end_event_initialize(&emitter_->event_, 0);\n+\temitterRoot_->emit();\n+\n+\tyaml_stream_end_event_initialize(&emitter_->event_);\n+\temitterRoot_->emit();\n+}\n+\n+/**\n+ * \\fn YamlRoot &YamlRoot::operator=(YamlRoot &&other)\n+ * \\copydoc YamlOutput &operator=(YamlOutput &&other)\n+ */\n+\n+/**\n+ * \\copydoc YamlOutput::dict()\n+ */\n+YamlDict YamlRoot::dict()\n+{\n+\tint ret = emitMappingStart();\n+\tif (ret)\n+\t\treturn {};\n+\n+\treturn YamlOutput::dict(this);\n+}\n+\n+/**\n+ * \\copydoc YamlOutput::list()\n+ */\n+YamlList YamlRoot::list()\n+{\n+\tint ret = emitSequenceStart();\n+\tif (ret)\n+\t\treturn {};\n+\n+\treturn YamlOutput::list(this);\n+}\n+\n+/**\n+ * \\class YamlList\n+ *\n+ * A YamlList can be populated with scalars and allows to create nested lists\n+ * and dictionaries.\n+ */\n+\n+/**\n+ * \\fn YamlList::YamlList()\n+ * \\copydoc YamlOutput::YamlOutput()\n+ */\n+\n+/**\n+ * \\copydoc YamlOutput::YamlOutput(YamlEmitter *emitter, YamlOutput *parent)\n+ */\n+YamlList::YamlList(YamlEmitter *emitter, YamlOutput *parent)\n+\t: YamlOutput(emitter, parent)\n+{\n+}\n+\n+/**\n+ * \\fn YamlList &YamlList::YamlList(YamlList &&other)\n+ * \\copydoc YamlOutput &YamlOutput::YamlOutput(YamlOutput &&other)\n+ */\n+\n+YamlList::~YamlList()\n+{\n+\temitSequenceEnd();\n+}\n+\n+/**\n+ * \\fn YamlList &YamlList::operator=(YamlList &&other)\n+ * \\copydoc YamlOutput &operator=(YamlOutput &&other)\n+ */\n+\n+/**\n+ * \\copydoc YamlOutput::list()\n+ */\n+YamlList YamlList::list()\n+{\n+\tif (!parent_) {\n+\t\tLOG(YamlEmitter, Error)\n+\t\t\t<< \"Invalid usage of the YamlEmitter API. \"\n+\t\t\t<< \" The YAML output might not be correct.\";\n+\t\treturn {};\n+\t}\n+\n+\tint ret = emitSequenceStart();\n+\tif (ret)\n+\t\treturn {};\n+\n+\treturn YamlOutput::list(this);\n+}\n+\n+/**\n+ * \\copydoc YamlOutput::dict()\n+ */\n+YamlDict YamlList::dict()\n+{\n+\tif (!parent_) {\n+\t\tLOG(YamlEmitter, Error)\n+\t\t\t<< \"Invalid usage of the YamlEmitter API. \"\n+\t\t\t<< \" The YAML output might not be correct.\";\n+\t\treturn {};\n+\t}\n+\n+\tint ret = emitMappingStart();\n+\tif (ret)\n+\t\treturn {};\n+\n+\treturn YamlOutput::dict(this);\n+}\n+\n+/**\n+ * \\brief Append \\a scalar to the list\n+ * \\param[in] scalar The element to append to the list\n+ */\n+void YamlList::scalar(std::string_view scalar)\n+{\n+\tif (!parent_) {\n+\t\tLOG(YamlEmitter, Error)\n+\t\t\t<< \"Invalid usage of the YamlEmitter API. \"\n+\t\t\t<< \" The YAML output might not be correct.\";\n+\t\treturn;\n+\t}\n+\n+\temitScalar(scalar);\n+}\n+\n+/**\n+ * \\class YamlDict\n+ *\n+ * A YamlDict can create lists, other dictionaries and emit a scalar associated\n+ * with a key.\n+ */\n+\n+/**\n+ * \\fn YamlDict::YamlDict()\n+ * \\copydoc YamlOutput::YamlOutput()\n+ */\n+\n+/**\n+ * \\copydoc YamlOutput::YamlOutput(YamlEmitter *emitter, YamlOutput *parent)\n+ */\n+YamlDict::YamlDict(YamlEmitter *emitter, YamlOutput *parent)\n+\t: YamlOutput(emitter, parent)\n+{\n+}\n+\n+/**\n+ * \\fn YamlDict &YamlDict::YamlDict(YamlDict &&other)\n+ * \\copydoc YamlOutput &YamlOutput::YamlOutput(YamlOutput &&other)\n+ */\n+\n+YamlDict::~YamlDict()\n+{\n+\temitMappingEnd();\n+}\n+\n+/**\n+ * \\fn YamlDict &YamlDict::operator=(YamlDict &&other)\n+ * \\copydoc YamlOutput &operator=(YamlOutput &&other)\n+ */\n+\n+/**\n+ * \\brief Create a list associated with \\a key\n+ * \\param[in] key The key to associate the list with\n+ * \\return An instance of YamlList\n+ */\n+YamlList YamlDict::list(std::string_view key)\n+{\n+\tif (!parent_) {\n+\t\tLOG(YamlEmitter, Error)\n+\t\t\t<< \"Invalid usage of the YamlEmitter API. \"\n+\t\t\t<< \" The YAML output might not be correct.\";\n+\t\treturn {};\n+\t}\n+\n+\tint ret = emitScalar(key);\n+\tif (ret)\n+\t\treturn {};\n+\n+\tret = emitSequenceStart();\n+\tif (ret)\n+\t\treturn {};\n+\n+\treturn YamlOutput::list(this);\n+}\n+\n+/**\n+ * \\brief Create a dictionary associated with \\a key\n+ * \\param[in] key The key to associate the dictionary with\n+ * \\return An instance of YamlDict\n+ */\n+YamlDict YamlDict::dict(std::string_view key)\n+{\n+\tif (!parent_) {\n+\t\tLOG(YamlEmitter, Error)\n+\t\t\t<< \"Invalid usage of the YamlEmitter API. \"\n+\t\t\t<< \" The YAML output might not be correct.\";\n+\t\treturn {};\n+\t}\n+\n+\tint ret = emitScalar(key);\n+\tif (ret)\n+\t\treturn {};\n+\n+\tret = emitMappingStart();\n+\tif (ret)\n+\t\treturn {};\n+\n+\treturn YamlOutput::dict(this);\n+}\n+\n+/**\n+ * \\brief Emit \\a scalar associated with \\a key in the dictionary\n+ * \\param[in] key The key associated with the newly created scalar\n+ * \\param[in] scalar The scalar to emit\n+ */\n+void YamlDict::scalar(std::string_view key, std::string_view scalar)\n+{\n+\tif (!parent_) {\n+\t\tLOG(YamlEmitter, Error)\n+\t\t\t<< \"Invalid usage of the YamlEmitter API. \"\n+\t\t\t<< \" The YAML output might not be correct.\";\n+\t\treturn;\n+\t}\n+\n+\tint ret = emitScalar(key);\n+\tif (ret)\n+\t\treturn;\n+\n+\temitScalar(scalar);\n+}\n+\n+} /* namespace libcamera */\n",
    "prefixes": [
        "v2",
        "1/4"
    ]
}