{"id":21819,"url":"https://patchwork.libcamera.org/api/1.1/patches/21819/?format=json","web_url":"https://patchwork.libcamera.org/patch/21819/","project":{"id":1,"url":"https://patchwork.libcamera.org/api/1.1/projects/1/?format=json","name":"libcamera","link_name":"libcamera","list_id":"libcamera_core","list_email":"libcamera-devel@lists.libcamera.org","web_url":"","scm_url":"","webscm_url":""},"msgid":"<20241106175901.83960-2-jacopo.mondi@ideasonboard.com>","date":"2024-11-06T17:58:51","name":"[1/3] libcamera: Implement YamlEmitter","commit_ref":null,"pull_url":null,"state":"superseded","archived":false,"hash":"c1eb3398bb92e503b2eac207a5e370d9f5116607","submitter":{"id":143,"url":"https://patchwork.libcamera.org/api/1.1/people/143/?format=json","name":"Jacopo Mondi","email":"jacopo.mondi@ideasonboard.com"},"delegate":null,"mbox":"https://patchwork.libcamera.org/patch/21819/mbox/","series":[{"id":4773,"url":"https://patchwork.libcamera.org/api/1.1/series/4773/?format=json","web_url":"https://patchwork.libcamera.org/project/libcamera/list/?series=4773","date":"2024-11-06T17:58:50","name":"libcamera: Add support for dumping capture script in YAML","version":1,"mbox":"https://patchwork.libcamera.org/series/4773/mbox/"}],"comments":"https://patchwork.libcamera.org/api/patches/21819/comments/","check":"pending","checks":"https://patchwork.libcamera.org/api/patches/21819/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 995F9C324E\n\tfor <parsemail@patchwork.libcamera.org>;\n\tWed,  6 Nov 2024 17:59:13 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 26A9B65435;\n\tWed,  6 Nov 2024 18:59:13 +0100 (CET)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 019F665432\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed,  6 Nov 2024 18:59:10 +0100 (CET)","from ideasonboard.com (93-61-96-190.ip145.fastwebnet.it\n\t[93.61.96.190])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 7BAE6C80;\n\tWed,  6 Nov 2024 18:59:01 +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=\"wPsOxB7Y\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1730915941;\n\tbh=jFTln8oGrWCy1Ik8GlmMhkgfS8bgoZ1LY5c5xZI3Pgs=;\n\th=From:To:Cc:Subject:Date:In-Reply-To:References:From;\n\tb=wPsOxB7YSXKNoLRvO7tIzOA21QkEg9uTT09a0WAmtKg8Su+g/6zRdYcehJ+QvPShH\n\tGZT+ryWZwAwFnC305Z+zjUG80Pl8jiLTs7yNhgOVlwD2KmqAb98N0JiSWVl5WkINXu\n\tKZUZR/NH4+6tb2Ft2w/5OuOfK6X7k3qYeq70/ebc=","From":"Jacopo Mondi <jacopo.mondi@ideasonboard.com>","To":"libcamera-devel@lists.libcamera.org","Cc":"Jacopo Mondi <jacopo.mondi@ideasonboard.com>","Subject":"[PATCH 1/3] libcamera: Implement YamlEmitter","Date":"Wed,  6 Nov 2024 18:58:51 +0100","Message-ID":"<20241106175901.83960-2-jacopo.mondi@ideasonboard.com>","X-Mailer":"git-send-email 2.47.0","In-Reply-To":"<20241106175901.83960-1-jacopo.mondi@ideasonboard.com>","References":"<20241106175901.83960-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 | 164 ++++++\n src/libcamera/meson.build                 |   1 +\n src/libcamera/yaml_emitter.cpp            | 577 ++++++++++++++++++++++\n 4 files changed, 743 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 1c5eef9cab80..7533b075fde2 100644\n--- a/include/libcamera/internal/meson.build\n+++ b/include/libcamera/internal/meson.build\n@@ -41,6 +41,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..78196a7f147f\n--- /dev/null\n+++ b/include/libcamera/internal/yaml_emitter.h\n@@ -0,0 +1,164 @@\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+\n+\tYamlOutput(YamlEmitter *emitter)\n+\t\t: emitter_(emitter)\n+\t{\n+\t}\n+\n+\tYamlOutput &operator=(YamlOutput &&other)\n+\t{\n+\t\temitter_ = other.emitter_;\n+\t\tother.emitter_ = nullptr;\n+\n+\t\treturn *this;\n+\t}\n+\n+\tint emitScalar(std::string_view scalar);\n+\tint emitMappingStart();\n+\tint emitMappingEnd();\n+\tint emitSequenceStart();\n+\tint emitSequenceEnd();\n+\n+\tYamlScalar scalar();\n+\tYamlDict dict();\n+\tYamlList list();\n+\n+\tYamlEmitter *emitter_ = nullptr;\n+\tyaml_event_t event_;\n+\n+private:\n+\tLIBCAMERA_DISABLE_COPY(YamlOutput)\n+};\n+\n+class YamlRoot : public YamlOutput\n+{\n+public:\n+\tYamlRoot() = 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()), emitterRoot_(std::move(emitter))\n+\t{\n+\t}\n+\n+\tstd::unique_ptr<YamlEmitter> emitterRoot_;\n+};\n+\n+class YamlScalar : public YamlOutput\n+{\n+public:\n+\tYamlScalar() = default;\n+\t~YamlScalar() = default;\n+\n+\tvoid operator=(std::string_view scalar);\n+\n+private:\n+\tfriend class YamlOutput;\n+\n+\tYamlScalar(YamlEmitter *emitter);\n+};\n+\n+class YamlList : public YamlOutput\n+{\n+public:\n+\tYamlList() = 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);\n+};\n+\n+class YamlDict : public YamlOutput\n+{\n+public:\n+\tYamlDict() = 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+\n+\tYamlScalar operator[](std::string_view key);\n+\n+private:\n+\tfriend class YamlOutput;\n+\n+\tYamlDict(YamlEmitter *emitter);\n+};\n+\n+} /* namespace libcamera */\ndiff --git a/src/libcamera/meson.build b/src/libcamera/meson.build\nindex aa9ab0291854..5b8af4103085 100644\n--- a/src/libcamera/meson.build\n+++ b/src/libcamera/meson.build\n@@ -51,6 +51,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..fa3de91ce988\n--- /dev/null\n+++ b/src/libcamera/yaml_emitter.cpp\n@@ -0,0 +1,577 @@\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+ * 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 populating it with dictionaries and lists with the YamlRoot::dict()\n+ * and 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+ * instances, 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+\tstd::string filePath(path);\n+\tfile_.setFileName(filePath);\n+\tfile_.open(File::OpenModeFlag::WriteOnly);\n+}\n+\n+/**\n+ * \\brief Destroy the YamlEmitter\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 scalers, 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 problem\";\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_, NULL, NULL, NULL, 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 YamlScalar,\n+ * YamlList and YamlDict classes which are meant to be used by users of the\n+ * YAML emitter helpers.\n+ *\n+ * The YamlOutput base class provides functions to create YAML lists and\n+ * dictionaries and to populate them.\n+ *\n+ * Instances of this class cannot be instantiated directly by applications.\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+ * \\fn YamlOutput::YamlOutput(YamlEmitter *emitter)\n+ * \\brief Create a YamlOutput instance with an associated emitter\n+ * \\param[in] emitter The YAML emitter\n+ */\n+\n+/**\n+ * \\fn YamlOutput &YamlOutput::operator=(YamlOutput &&other)\n+ * \\brief The move-assignment operator\n+ * \\param[in] other The instance to be moved\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+\tyaml_scalar_event_initialize(&emitter_->event_, NULL, NULL, 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_, NULL, NULL,\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_, NULL, NULL,\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 scalar instance\n+ * \\return An instance of YamlScalar\n+ */\n+YamlScalar YamlOutput::scalar()\n+{\n+\treturn YamlScalar(emitter_);\n+}\n+\n+/**\n+ * \\brief Create a dictionary instance\n+ * \\return An instance of YamlDict\n+ */\n+YamlDict YamlOutput::dict()\n+{\n+\treturn YamlDict(emitter_);\n+}\n+\n+/**\n+ * \\brief Create a list instance\n+ * \\return An instance of YamlList\n+ */\n+YamlList YamlOutput::list()\n+{\n+\treturn YamlList(emitter_);\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+ * \\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 by the users of this class. In order to start using\n+ * and populating the YamlRoot instance a valid and initialized instance,\n+ * created using the YamlEmitter::root() function, has to be move-assigned to\n+ * the 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+ * \\brief Delete a YamlRoot\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+ * \\brief Move assignment operator\n+ *\n+ * Move-assign a YamlRoot instance. This function is typically used to assign an\n+ * initialized instance returned by YamlEmitter::root() to a non-initialized\n+ * one.\n+ *\n+ * \\return A reference to this instance of YamlRoot\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();\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();\n+}\n+\n+/**\n+ * \\class YamlScalar\n+ *\n+ * A YamlScalar can be assigned to an std::string_view to emit them as YAML\n+ * elements.\n+ */\n+\n+/**\n+ * \\brief Create a YamlScalar instance\n+ */\n+YamlScalar::YamlScalar(YamlEmitter *emitter)\n+\t: YamlOutput(emitter)\n+{\n+}\n+\n+/**\n+ * \\brief Emit \\a scalar as a YAML scalar\n+ * \\param[in] scalar The element to emit in the YAML output\n+ */\n+void YamlScalar::operator=(std::string_view scalar)\n+{\n+\temitScalar(scalar);\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+ * \\brief Create a YamlList\n+ */\n+YamlList::YamlList(YamlEmitter *emitter)\n+\t: YamlOutput(emitter)\n+{\n+}\n+\n+/**\n+ * \\brief Destroy a YamlList instance\n+ */\n+YamlList::~YamlList()\n+{\n+\temitSequenceEnd();\n+}\n+\n+/**\n+ * \\fn YamlList &YamlList::operator=(YamlList &&other)\n+ * \\brief Move-assignment operator\n+ * \\param[inout] other The instance to move\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+\temitScalar(scalar);\n+}\n+\n+/**\n+ * \\copydoc YamlOutput::list()\n+ */\n+YamlList YamlList::list()\n+{\n+\tint ret = emitSequenceStart();\n+\tif (ret)\n+\t\treturn {};\n+\n+\treturn YamlOutput::list();\n+}\n+\n+/**\n+ * \\copydoc YamlOutput::dict()\n+ */\n+YamlDict YamlList::dict()\n+{\n+\tint ret = emitMappingStart();\n+\tif (ret)\n+\t\treturn {};\n+\n+\treturn YamlOutput::dict();\n+}\n+\n+/**\n+ * \\class YamlDict\n+ *\n+ * A YamlDict can be populated with scalars using operator[] and allows to\n+ * create other lists and dictionaries associated with a key.\n+ */\n+\n+/**\n+ * \\fn YamlDict::YamlDict()\n+ * \\brief Create a non-initialized instance of a YamlDict\n+ */\n+\n+YamlDict::YamlDict(YamlEmitter *emitter)\n+\t: YamlOutput(emitter)\n+{\n+}\n+\n+/**\n+ * \\brief Destroy a YamlDict instance\n+ */\n+YamlDict::~YamlDict()\n+{\n+\temitMappingEnd();\n+}\n+\n+/**\n+ * \\fn YamlDict &YamlDict::operator=(YamlDict &&other)\n+ * \\brief Move-assignment operator\n+ * \\param[inout] other The instance to move\n+ */\n+\n+/**\n+ * \\copydoc YamlOutput::list()\n+ */\n+YamlList YamlDict::list(std::string_view key)\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();\n+}\n+\n+/**\n+ * \\copydoc YamlOutput::dict()\n+ */\n+YamlDict YamlDict::dict(std::string_view key)\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();\n+}\n+\n+/**\n+ * \\brief Create a scalar associated with \\a key in the dictionary\n+ * \\param[in] key The key associated with the newly created scalar\n+ * \\return A YamlScalar that application can use to output text\n+ */\n+YamlScalar YamlDict::operator[](std::string_view key)\n+{\n+\tint ret = emitScalar(key);\n+\tif (ret)\n+\t\treturn {};\n+\n+\treturn YamlOutput::scalar();\n+}\n+\n+} /* namespace libcamera */\n","prefixes":["1/3"]}