From bae92cea3bcbacd7883499da61a0e54f13da6d23 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 26 Nov 2018 20:47:47 +0100 Subject: wanda: architecture rework --- .vscode/settings.json | 4 +- CMakeLists.txt | 9 ++- src/deferred_failure.hpp | 18 ++++++ src/main.cpp | 24 ++++++-- src/optional.hpp | 43 ++++++++----- src/setting.cpp | 105 +++++++++++++++++++++++++++----- src/setting.hpp | 154 +++++++++++++++++++++++++++++++++++++++-------- src/type_wrapper.hpp | 24 +++++--- src/variant.cpp | 17 ------ src/variant.hpp | 47 --------------- 10 files changed, 308 insertions(+), 137 deletions(-) create mode 100644 src/deferred_failure.hpp delete mode 100644 src/variant.cpp delete mode 100644 src/variant.hpp diff --git a/.vscode/settings.json b/.vscode/settings.json index 1231968..3974147 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -8,6 +8,8 @@ "initializer_list": "cpp", "type_traits": "cpp", "utility": "cpp", - "string": "cpp" + "string": "cpp", + "variant": "cpp", + "string_view": "cpp" } } \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 1d913bc..f9b4906 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,12 +20,17 @@ include("ConanDependencies") include("SystemDependencies") add_executable("wanda" + # Executable "src/main.cpp" + + # Components + "src/deferred_failure.hpp" + "src/optional.hpp" "src/setting.cpp" "src/setting.hpp" - "src/variant.cpp" - "src/variant.hpp" + "src/type_wrapper.hpp" ) + target_link_libraries("wanda" "CONAN_PKG::boost_config" "SYSTEM::GIO" diff --git a/src/deferred_failure.hpp b/src/deferred_failure.hpp new file mode 100644 index 0000000..54adb97 --- /dev/null +++ b/src/deferred_failure.hpp @@ -0,0 +1,18 @@ +/** + * @file deferred_failure.hpp + * @author Felix Morgner (felix.morgner@gmail.com) + * @since 1.0.0 + */ + +#ifndef WANDA_DEFERRED_FAILURE_HPP +#define WANDA_DEFERRED_FAILURE_HPP + +#include + +namespace +{ +template +using deferred_failure = std::false_type; +} // namespace + +#endif \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index fb2e0bf..38fdf7f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4,13 +4,25 @@ #include #include -int main() { +#include + +int main() +{ using namespace wanda::literals; using namespace wanda::std_ext; + using namespace std::string_literals; - with("org.gnome.desktop.background"_setting, [](auto & setting){ - with(setting.template get("picture-uri"_key), [](auto & value){ - std::cout << value << '\n'; - }) || []{ std::cerr << "No such key!\n"; }; - }) || []{ std::cerr << "No such setting!\n"; }; + with("org.gnome.desktop.background"_setting, [](auto &setting) { + with(setting["picture-uri"_key], [](auto &value) { + std::visit([](auto &&value) { + using ValueType = std::decay_t; + if constexpr (std::is_same_v) + { + std::cout << value << '\n'; + } + }, + *value); + std::cout << (value = "file:///"s) << '\n'; + }) || [] { std::cerr << "No such key!\n"; }; + }) || [] { std::cerr << "No such setting!\n"; }; } diff --git a/src/optional.hpp b/src/optional.hpp index c178d59..5e1c630 100644 --- a/src/optional.hpp +++ b/src/optional.hpp @@ -1,36 +1,47 @@ +/** + * @file optional.hpp + * @author Felix Morgner (felix.morgner@gmail.com) + * @since 1.0.0 + */ + #ifndef WANDA_OPTIONAL_HPP #define WANDA_OPTIONAL_HPP #include -namespace wanda::std_ext { - -struct failable { +namespace wanda::std_ext +{ +struct failable +{ constexpr static auto success() { return failable{false}; } constexpr static auto failure() { return failable{true}; } - template - constexpr auto operator ||(Handler handler) const { - if(m_failed) { + template + constexpr auto operator||(Handler handler) const + { + if (m_failed) + { handler(); } } -private: - constexpr explicit failable(bool failed) : m_failed{failed} { }; + private: + constexpr explicit failable(bool failed) : m_failed{failed} {}; bool const m_failed; }; -template -auto with(std::optional && object, HandlerType handler) { - if(object) { - handler(object.value()); - return failable::success(); - } - return failable::failure(); +template +auto with(std::optional &&object, HandlerType handler) +{ + if (object) + { + handler(object.value()); + return failable::success(); + } + return failable::failure(); } -} +} // namespace wanda::std_ext #endif \ No newline at end of file diff --git a/src/setting.cpp b/src/setting.cpp index 9ddbfe8..39ae248 100644 --- a/src/setting.cpp +++ b/src/setting.cpp @@ -1,29 +1,102 @@ #include "setting.hpp" -namespace wanda { +#include +#include -namespace literals { - key operator""_key(char const * str, std::size_t len) { - return key{{str, len}}; +namespace wanda +{ + +// UDL implementations + +key literals::operator""_key(char const *str, std::size_t len) +{ + return key{{str, len}}; +} + +std::optional literals::operator""_setting(char const *str, std::size_t len) +{ + auto source = g_settings_schema_source_get_default(); + if (!source) + { + return std::nullopt; } - std::optional operator""_setting(char const * str, std::size_t len) { - auto source = g_settings_schema_source_get_default(); - auto schema = g_settings_schema_source_lookup(source, str, true); - if(schema) { - g_settings_schema_unref(schema); - return setting{::wanda::schema{{str, len}}}; - } + auto schema = g_settings_schema_source_lookup(source, str, true); + if (!schema) + { return std::nullopt; } + + return setting{schema}; } -setting::setting(schema schema) : m_value{g_settings_new(schema.get().c_str())} { } +// 'setting' implementation + +setting::setting(GSettingsSchema *schema) + : m_schema{schema, &g_settings_schema_unref} +{ +} + +std::optional setting::operator[](key key) const +{ + if (!g_settings_schema_has_key(m_schema.get(), key.get().c_str())) + { + return std::nullopt; + } + + return setting::entry{*this, std::move(key)}; +} -setting::setting(setting const & other) : m_value{reinterpret_cast(g_object_ref(other.m_value))} { } +// 'setting::entry' implementation + +setting::entry::entry(setting const &setting, key key) + : m_settings{g_settings_new(g_settings_schema_get_id(setting.m_schema.get())), &g_object_unref}, m_key{key.get()} +{ +} + +setting::entry::value_type setting::entry::operator*() const +{ + auto value = std::unique_ptr{g_settings_get_value(m_settings.get(), m_key.get().c_str()), &g_variant_unref}; + auto raw = value.get(); + + if (g_variant_is_of_type(raw, G_VARIANT_TYPE_BOOLEAN)) + { + return static_cast(g_variant_get_boolean(raw)); + } + else if (g_variant_is_of_type(raw, G_VARIANT_TYPE_INT32)) + { + return static_cast(g_variant_get_int32(raw)); + } + else if (g_variant_is_of_type(raw, G_VARIANT_TYPE_INT64)) + { + return static_cast(g_variant_get_int64(raw)); + } + else if (g_variant_is_of_type(raw, G_VARIANT_TYPE_UINT32)) + { + return static_cast(g_variant_get_uint32(raw)); + } + else if (g_variant_is_of_type(raw, G_VARIANT_TYPE_UINT64)) + { + return static_cast(g_variant_get_uint64(raw)); + } + else if (g_variant_is_of_type(raw, G_VARIANT_TYPE_DOUBLE)) + { + return static_cast(g_variant_get_double(raw)); + } + else if (g_variant_is_of_type(raw, G_VARIANT_TYPE_STRING)) + { + auto size = gsize{}; + auto string = g_variant_get_string(raw, &size); + return std::string{string, size}; + } + else if (g_variant_is_of_type(raw, G_VARIANT_TYPE_STRING_ARRAY)) + { + auto length = gsize{}; + auto data = g_variant_get_strv(raw, &length); + return std::vector{data, data + length}; + } -setting::~setting() { - g_clear_object(&m_value); + return {}; } -} \ No newline at end of file +} // namespace wanda \ No newline at end of file diff --git a/src/setting.hpp b/src/setting.hpp index 6293dd3..6e10a8a 100644 --- a/src/setting.hpp +++ b/src/setting.hpp @@ -1,48 +1,154 @@ +/** + * @file setting.hpp + * @author Felix Morgner (felix.morgner@gmail.com) + * @since 1.0.0 + */ + #ifndef WANDA_setting_HPP #define WANDA_setting_HPP +#include "deferred_failure.hpp" +#include "type_wrapper.hpp" + #include +#include #include +#include +#include #include #include -#include +#include +#include -#include "type_wrapper.hpp" -#include "variant.hpp" -#include - -namespace wanda { +namespace wanda +{ struct setting; -using schema = type_wrapper; + +/** + * @brief A convenience type to represent setting keys + */ using key = type_wrapper; -namespace literals { -key operator""_key(char const * str, std::size_t len); -std::optional operator""_setting(char const * str, std::size_t len); -} +namespace literals +{ +/** + * @brief UDL to create setting keys + */ +key operator""_key(char const *str, std::size_t len); + +/** + * @brief UDL to create setting schemas + */ +std::optional operator""_setting(char const *str, std::size_t lent); +} // namespace literals + +/** + * @brief A simple wrapper for GSettings Schemas + */ +struct setting +{ + struct entry + { + + using value_type = std::variant>; + + value_type operator*() const; + + template + bool operator=(Type value) + { + struct setting_applier + { + setting_applier(GSettings *setting, gchar const *key, Type value) noexcept + : m_result{[&] { + if constexpr (std::is_same_v) + { + return g_settings_set_boolean(setting, key, value); + } + else if constexpr (std::is_same_v) + { + return g_settings_set_int(setting, key, value); + } + else if constexpr (std::is_same_v) + { + return g_settings_set_int64(setting, key, value); + } + else if constexpr (std::is_same_v) + { + return g_settings_set_uint(setting, key, value); + } + else if constexpr (std::is_same_v) + { + return g_settings_set_uint64(setting, key, value); + } + else if constexpr (std::is_same_v) + { + return g_settings_set_double(setting, key, value); + } + else if constexpr (std::is_same_v) + { + return g_settings_set_string(setting, key, value.c_str()); + } + else if constexpr (std::is_same_v>) + { + auto temp = std::vector{value.size() + 1}; + std::transform(value.begin(), value.end(), temp.begin(), [](auto const &str) { return str.c_str(); }); + return g_settings_set_strv(setting, key, temp.data()); + } + else + { + static_assert(deferred_failure{}, "Invalid argument type!"); + } + }()} + { + } + + ~setting_applier() + { + g_settings_sync(); + } + + operator bool() const + { + return m_result; + } + + private: + gboolean const m_result; + }; + + return setting_applier{m_settings.get(), m_key.get().c_str(), value}; + } -struct setting { - ~setting(); + private: + entry(setting const &schema, key key); - setting(setting const & other); + std::unique_ptr m_settings; - template std::optional get(key key) const { - auto value = variant{g_settings_get_value(m_value, key.get().c_str())}; - return value.get(); - } + key m_key; -private: - explicit setting(schema schema); + friend setting; + }; - GSettings * m_value; + /** + * @brief Get the entry for the given key + * + * @return An std::optional wrapping the entry associated with + * the given key, or an empty std::optional if the desired key + * does not exist in the setting's schema. + */ + std::optional operator[](key key) const; - friend std::optional literals::operator""_setting(char const *, std::size_t); -}; +private: + explicit setting(GSettingsSchema *schema); + std::unique_ptr m_schema; -} + friend std::optional literals::operator""_setting(char const *, std::size_t); +}; +} // namespace wanda #endif \ No newline at end of file diff --git a/src/type_wrapper.hpp b/src/type_wrapper.hpp index d3bf694..f14497a 100644 --- a/src/type_wrapper.hpp +++ b/src/type_wrapper.hpp @@ -1,23 +1,31 @@ +/** + * @file type_wrapper.hpp + * @author Felix Morgner (felix.morgner@gmail.com) + * @since 1.0.0 + */ + #ifndef WANDA_TYPE_WRAPPER_HPP #define WANDA_TYPE_WRAPPER_HPP #include -namespace wanda { +namespace wanda +{ -template -struct type_wrapper { +template +struct type_wrapper +{ - explicit type_wrapper(InnerType value) : m_value{std::move(value)} { } + explicit type_wrapper(InnerType value) : m_value{std::move(value)} {} - constexpr explicit operator InnerType const & () const { return get(); } + constexpr explicit operator InnerType const &() const { return get(); } - constexpr InnerType const & get() const { return m_value; } + constexpr InnerType const &get() const { return m_value; } -private: + private: InnerType const m_value; }; -} +} // namespace wanda #endif \ No newline at end of file diff --git a/src/variant.cpp b/src/variant.cpp deleted file mode 100644 index 54e484e..0000000 --- a/src/variant.cpp +++ /dev/null @@ -1,17 +0,0 @@ -#include "variant.hpp" - -namespace wanda { - -variant::variant(GVariant * value) : m_value{value} { } - -variant::~variant() { - if(m_value) { - g_variant_unref(m_value); - } -} - -bool variant::is_of_type(GVariantType const * const type) const { - return g_variant_is_of_type(m_value, type); -} - -} \ No newline at end of file diff --git a/src/variant.hpp b/src/variant.hpp deleted file mode 100644 index 8a5fb03..0000000 --- a/src/variant.hpp +++ /dev/null @@ -1,47 +0,0 @@ -#ifndef WANDA_VARIANT_HPP -#define WANDA_VARIANT_HPP - -#include - -#include -#include -#include - -namespace wanda { - -struct variant { - - explicit variant(GVariant * variant); - - ~variant(); - - template std::optional get() const { - if(!m_value) { - return std::nullopt; - } - - if constexpr(std::is_same_v) { - if(is_of_type(G_VARIANT_TYPE_BOOLEAN)) { - return static_cast(g_variant_get_boolean(m_value)); - } - } else if constexpr(std::is_same_v) { - if(is_of_type(G_VARIANT_TYPE_STRING)) { - auto length = gsize{}; - auto value = g_variant_get_string(m_value, &length); - return std::string(value, static_cast(length)); - } - } - - return std::nullopt; - } - - -private: - bool is_of_type(GVariantType const * const type) const; - - GVariant * const m_value; -}; - -} - -#endif \ No newline at end of file -- cgit v1.2.3