ores.cpp.oresmd.resolver

Table of Contents

The resolver: one resolve_<asset_class> function per class, generated from the spec's Fields table. The fill strategy per field is structural: a field with a default resolves via pick (requirement wins, then the default, else throw), a mandatory string resolves via pick_mandatory_string (empty string treated as absent), everything else via pick_optional. The vol field is skipped. The function definitions follow the manifest's parse_order; the dispatch in oresmd_resolver::resolve follows variant_order.

1. Template

{{! GENERATED FILE — tangled from ores.cpp.oresmd.resolver.org. Edit the org source. }}
{{{cpp_license}}}
#include "ores.marketdata.core/oresmd/oresmd_resolver.hpp"
#include "ores.marketdata.core/oresmd/oresmd_exception.hpp"
#include <boost/throw_exception.hpp>
#include <format>

namespace {

using namespace ores::marketdata::domain;
using ores::marketdata::core::oresmd_exception;

template <typename T>
T pick(const std::optional<T>& required, const std::optional<T>& fallback, std::string_view field) {
    if (required)
        return *required;
    if (fallback)
        return *fallback;
    BOOST_THROW_EXCEPTION(
        oresmd_exception(std::format("oresmd resolve: '{}' is unresolved.", field)));
}

template <typename T>
std::optional<T> pick_optional(const std::optional<T>& required, const std::optional<T>& fallback) {
    return required ? required : fallback;
}

/**
 * @brief Like pick(), but for the mandatory string fields (pair/ccy/ticker/...) that have
 * no sensible non-empty default -- an identifier struct's mandatory std::string members
 * are never themselves optional, so a caller passing an unfilled `defaults` identifier
 * has that field default-constructed to "", not "absent". Treating "" as absent here,
 * on both the requirement and the fallback, is what lets resolve() actually detect an
 * unresolved mandatory field instead of silently resolving it to an empty string.
 */
std::string pick_mandatory_string(const std::optional<std::string>& required,
                                  const std::string& fallback,
                                  std::string_view field) {
    if (required && !required->empty())
        return *required;
    if (!fallback.empty())
        return fallback;
    BOOST_THROW_EXCEPTION(
        oresmd_exception(std::format("oresmd resolve: '{}' is unresolved.", field)));
}

{{#oresmd_parse_specs}}
market_data_identifier resolve_{{asset_class}}(const {{asset_class}}_market_data_requirement& req,
    const market_data_identifier& defaults) {
    const auto* d = std::get_if<{{asset_class}}_market_data_identifier>(&defaults);
    {{asset_class}}_market_data_identifier id;
{{#fields}}
{{^resolver_skip}}
{{#default}}
    id.{{name}} = pick(req.{{name}}, d ? std::optional(d->{{name}}) : std::nullopt, "{{name}}");
{{/default}}
{{^default}}
{{#is_mandatory_string}}
    id.{{name}} = pick_mandatory_string(req.{{name}}, d ? d->{{name}} : std::string{}, "{{name}}");
{{/is_mandatory_string}}
{{^is_mandatory_string}}
    id.{{name}} = pick_optional(req.{{name}}, d ? d->{{name}} : std::nullopt);
{{/is_mandatory_string}}
{{/default}}
{{/resolver_skip}}
{{/fields}}
    return id;
}

{{/oresmd_parse_specs}}
}

namespace ores::marketdata::core {

domain::market_data_identifier
oresmd_resolver::resolve(const domain::market_data_requirement& requirement,
                         const domain::market_data_identifier& defaults) {
    return std::visit(
        [&defaults](const auto& req) -> domain::market_data_identifier {
            using T = std::decay_t<decltype(req)>;
{{#oresmd_variant_specs}}
{{#variant_first}}            if constexpr{{/variant_first}}{{^variant_first}}            else if constexpr{{/variant_first}} (std::is_same_v<T, {{asset_class}}_market_data_requirement>)
                return resolve_{{asset_class}}(req, defaults);
{{/oresmd_variant_specs}}
        },
        requirement);
}

}

Emacs 29.3 (Org mode 9.6.15)