Program Listing for File TOMLUtils.hpp
↰ Return to documentation for file (src/utils/TOMLUtils.hpp)
#ifndef TOMLUTILS_HPP
#define TOMLUTILS_HPP
#include "../pdfs/PDF.hpp"
#include "../pdfs/PDFFileParser.hpp"
#include "../pdfs/PDFSegmentDelta.hpp"
#include "MiscUtils.hpp"
#include <exception>
#include <filesystem>
#include <memory>
#include <optional>
#include <stdexcept>
#include <string>
#include <toml.hpp>
#include <tuple>
#include <utility>
#include <vector>
namespace utils
{
inline auto stringArrayContents(const toml::array* arr) -> std::vector<std::string>
{
std::vector<std::string> result;
if (arr != nullptr)
{
arr->for_each([&result](auto&& el) -> void {
if constexpr (toml::is_string<decltype(el)>)
{
result.push_back(std::string(el));
}
});
}
return result;
}
inline auto getStringArrayField(const toml::table& registry, const std::string& key)
-> std::vector<std::string>
{
return stringArrayContents(registry.at_path(key).as_array());
}
inline auto initPDFFromKey(const toml::table& inputDeck,
const std::string& key,
const std::string& prefix = "") -> pdfs::PDF
{
// First check for numerical value
const std::optional<double> num =
inputDeck.at_path(key).value<double>();
if (num.has_value())
{
auto delta = std::make_unique<pdfs::PDFSegmentDelta>(num.value());
auto pdf = pdfs::PDF(std::move(delta));
return std::move(pdf);
}
// Next check for string value
const std::optional<std::string> pdfFile =
inputDeck.at_path(key).value<std::string>();
if (pdfFile.has_value())
{
auto pdfFilePath = getFilePath(pdfFile.value(), prefix).string();
if (pdfFilePath.empty())
{
throw std::runtime_error(
"initPDFFromKey: pdf file " + pdfFile.value() + " not found");
}
auto pdf = pdfs::parsePDFDescriptor(pdfFilePath);
return std::move(pdf);
}
// If we get here, key does not exist or has invalid type
throw std::runtime_error(
"initPDFFromKey: invalid entry for " + key);
}
inline auto parseTOMLFile(const std::string& fileName, const std::string& context)
-> std::pair<toml::table, std::filesystem::path>
{
auto path = getFilePath(fileName);
if (path.empty())
{
throw std::runtime_error(
context + ": registry " + fileName + " not found");
}
toml::table table;
try
{
table = toml::parse_file(path.string());
}
catch (const std::exception&)
{
throw std::runtime_error(
context + ": registry " + path.string() + " is not a valid toml file");
}
return { std::move(table), std::move(path) };
}
inline auto parseSetRegistry(
const std::string& registryName,
const std::string& setsKey,
const std::string& itemNoun,
const std::string& context,
const bool requireFeH = true)
-> std::tuple<toml::table, std::filesystem::path, std::vector<std::string>>
{
auto [registry, registryPath] = parseTOMLFile(registryName, context);
auto sets = getStringArrayField(registry, setsKey);
if (sets.empty())
{
throw std::runtime_error(
context + ": registry " + registryPath.string() +
" does not contain a valid [" + setsKey + "] field");
}
for (const auto& s : sets)
{
if (!registry.contains(s))
{
std::string msg = context + ": registry " + registryPath.string();
msg += " is missing entry for ";
msg += itemNoun;
msg += " ";
msg += s;
throw std::runtime_error(msg);
}
const auto entry = registry.at_path(s);
if (!entry.at_path("file") || (requireFeH && !entry.at_path("Fe_H")))
{
std::string msg = context + ": registry " + registryPath.string();
msg += ", entry for ";
msg += itemNoun;
msg += " ";
msg += s;
msg += requireFeH ?
" is missing required 'file' or 'Fe_H' fields" :
" is missing required 'file' field";
throw std::runtime_error(msg);
}
}
return { std::move(registry), std::move(registryPath), std::move(sets) };
}
} // namespace utils
#endif // TOMLUTILS_HPP