Support different GncOptionMultichoiceValue key types.

Scheme can use strings, symbols, or ints as keys in multichoice options,
but C++ can handle only strings. Add conversion and tracking so that the
right key type gets sent back to Scheme.
This commit is contained in:
John Ralls 2021-02-18 17:10:16 -08:00
parent 55a2ed1df8
commit fba0248548
4 changed files with 78 additions and 5 deletions

View File

@ -500,7 +500,8 @@ operator>> (std::istream& iss, OptType& opt)
using GncMultichoiceOptionEntry = std::tuple<const std::string,
const std::string,
const std::string>;
const std::string,
GncOptionMultichoiceKeyType>;
using GncMultichoiceOptionIndexVec = std::vector<std::size_t>;
using GncMultichoiceOptionChoices = std::vector<GncMultichoiceOptionEntry>;
@ -575,7 +576,8 @@ public:
if (vec.size() == 1)
return std::get<0>(m_choices.at(vec[0]));
else
return c_list_string;
throw std::length_error("Retrieving multiple values from a multichoice isn't implemented.");
}
const std::string& get_default_value() const
{
@ -671,6 +673,7 @@ public:
bool is_changed() const noexcept { return m_value != m_default_value; }
GncOptionUIType get_ui_type() const noexcept { return m_ui_type; }
void make_internal() { m_ui_type = GncOptionUIType::INTERNAL; }
GncOptionMultichoiceKeyType get_keytype(unsigned i) const { return std::get<3>(m_choices.at(i)); }
private:
std::size_t find_key (const std::string& key) const noexcept
{

View File

@ -63,6 +63,13 @@ using GncOptionVariant = std::variant<GncOptionValue<std::string>,
using GncOptionVariantPtr = std::unique_ptr<GncOptionVariant>;
enum class GncOptionMultichoiceKeyType
{
SYMBOL,
STRING,
NUMBER,
};
class GncOption
{
public:

View File

@ -51,7 +51,8 @@ using GncOptionAccountList = std::vector<const Account*>;
using GncOptionAccountTypeList = std::vector<GNCAccountType>;
using GncMultichoiceOptionEntry = std::tuple<const std::string,
const std::string,
const std::string>;
const std::string,
GncOptionMultichoiceKeyType>;
using GncMultichoiceOptionChoices = std::vector<GncMultichoiceOptionEntry>;
/**

View File

@ -256,14 +256,34 @@ gnc_option_test_book_destroy(QofBook* book)
%typemap(in) GncMultichoiceOptionChoices&& (GncMultichoiceOptionChoices choices)
{
using KeyType = GncOptionMultichoiceKeyType;
auto len = scm_to_size_t(scm_length($input));
for (std::size_t i = 0; i < len; ++i)
{
SCM vec = scm_list_ref($input, scm_from_size_t(i));
std::string key{scm_to_utf8_string(SCM_SIMPLE_VECTOR_REF(vec, 0))};
SCM keyval, v_ref_0 = SCM_SIMPLE_VECTOR_REF(vec, 0);
GncOptionMultichoiceKeyType keytype;
if (scm_is_symbol(v_ref_0))
{
keyval = scm_symbol_to_string(SCM_SIMPLE_VECTOR_REF(vec, 0));
keytype = KeyType::SYMBOL;
}
else if (scm_is_string(v_ref_0))
{
keyval = SCM_SIMPLE_VECTOR_REF(vec, 0);
keytype = KeyType::STRING;
}
else if (scm_is_integer(v_ref_0))
{
keyval = scm_number_to_string(v_ref_0, scm_from_uint(10u));
keytype = KeyType::NUMBER;
}
else
throw std::invalid_argument("Unsupported key type in multichoice option.");
std::string key{scm_to_utf8_string(keyval)};
std::string name{scm_to_utf8_string(SCM_SIMPLE_VECTOR_REF(vec, 1))};
std::string desc{scm_to_utf8_string(SCM_SIMPLE_VECTOR_REF(vec, 2))};
choices.push_back({std::move(key), std::move(name), std::move(desc)});
choices.push_back({std::move(key), std::move(name), std::move(desc), keytype});
}
$1 = &choices;
}
@ -404,6 +424,45 @@ wrap_unique_ptr(GncOptionDBPtr, GncOptionDB);
%ignore gnc_register_start_date_option(GncOptionDB*, const char*, const char*, const char*, const char*, bool);
%ignore gnc_register_end_date_option(GncOptionDB*, const char*, const char*, const char*, const char*, bool);
%ignore GncOptionMultichoiceKeyType;
/* Replace GncOptionMultichoiceValue::get_value with one that restores the keytype that Scheme sent it. */
%inline %{
SCM get_scm_value(const GncOptionMultichoiceValue& option)
{
using KeyType = GncOptionMultichoiceKeyType;
auto scm_value = [](const char* value, KeyType keytype) -> SCM {
auto scm_str{scm_from_utf8_string(value)};
switch (keytype)
{
case KeyType::SYMBOL:
return scm_string_to_symbol(scm_str);
case KeyType::STRING:
return scm_str;
case KeyType::NUMBER:
return scm_string_to_number(scm_str, scm_from_int(10));
};
};
auto indexes = option.get_multiple();
if (indexes.empty())
indexes = option.get_default_multiple();
if (indexes.empty())
return SCM_BOOL_F;
if (indexes.size() == 1) // FIXME: Should use bool member to decide
return scm_value(option.permissible_value(indexes[0]),
option.get_keytype(indexes[0]));
auto values{scm_list_1(SCM_UNDEFINED)};
for(auto index : indexes)
{
auto val{scm_list_1(scm_value(option.permissible_value(index),
option.get_keytype(index)))};
values = scm_append(scm_list_2(val, values));
}
return scm_reverse(values);
}
%}
%include "gnc-option-date.hpp"
%include "gnc-option.hpp"
%include "gnc-option-impl.hpp"
@ -421,6 +480,9 @@ wrap_unique_ptr(GncOptionDBPtr, GncOptionDB);
SCM get_scm_value()
{
return std::visit([](const auto& option)->SCM {
if constexpr (std::is_same_v<std::decay_t<decltype(option)>,
GncOptionMultichoiceValue>)
return get_scm_value(option);
auto value{option.get_value()};
if constexpr (std::is_same_v<std::decay_t<decltype(value)>,
SCM>)