blob: 6fbccd3b69f3f5eece0bed7b175d9da149baa8ed [file] [log] [blame] [edit]
/* Copyright 2023 The ChromiumOS Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
/* Specialised YamlNode, representing a YAML sequence.
*
* This is equivalent to vectors/lists in programming languages.
*/
#include "tools/mctk/yaml_tree.h"
#include <stddef.h> /* size_t */
#include <yaml.h>
#include <memory> /* std::unique_ptr */
#include <utility> /* std::move */
#include <vector>
#include "tools/mctk/debug.h"
bool YamlSequence::ParseOneListElement(yaml_parser_t& parser) {
yaml_event_t event;
if (!yaml_parser_parse(&parser, &event))
return false;
if (event.type == YAML_SEQUENCE_END_EVENT) {
yaml_event_delete(&event);
return true;
}
auto new_node = YamlNode::FromParserEvent(parser, event);
yaml_event_delete(&event);
if (!new_node)
return false;
this->list_.push_back(std::move(new_node));
return this->ParseOneListElement(parser);
}
/* Caller is responsible for deleting the event passed in */
std::unique_ptr<YamlSequence> YamlSequence::FromParserEvent(
yaml_parser_t& parser, yaml_event_t& start_event) {
MCTK_ASSERT_EQ(start_event.type, YAML_SEQUENCE_START_EVENT);
auto new_seq = std::make_unique<YamlSequence>();
if (!new_seq)
return NULL;
/* Store YAML formatting style for debugging purposes */
new_seq->implicit_ = start_event.data.sequence_start.implicit;
new_seq->style_ = start_event.data.sequence_start.style;
if (new_seq->ParseOneListElement(parser))
return new_seq;
return NULL;
}
bool YamlSequence::Emit(yaml_emitter_t& emitter) {
yaml_event_t event;
if (!yaml_sequence_start_event_initialize(
&event, NULL, reinterpret_cast<const yaml_char_t*>(YAML_SEQ_TAG),
implicit_, style_))
return false;
if (!yaml_emitter_emit(&emitter, &event))
return false;
for (auto& node : this->list_) {
node->Emit(emitter);
}
if (!yaml_sequence_end_event_initialize(&event))
return false;
if (!yaml_emitter_emit(&emitter, &event))
return false;
return true;
}
/* Parse a whole array of the same basic type, but only if the
* array size matches the expected number of elements.
*/
template <typename T>
std::optional<std::vector<T>> YamlSequence::ReadArray(size_t expected_count) {
if (list_.size() != expected_count)
return std::nullopt;
std::vector<T> out_vec;
for (auto& node : list_) {
std::optional<T> temp = node->Read<T>();
if (!temp)
return std::nullopt;
out_vec.push_back(*temp);
}
return std::optional<std::vector<T>>(out_vec);
}
template std::optional<std::vector<__u32>> YamlSequence::ReadArray(
size_t expected_count);
template std::optional<std::vector<__u8>> YamlSequence::ReadArray(
size_t expected_count);