aboutsummaryrefslogtreecommitdiff
path: root/src/setting.hpp
blob: 6e10a8abc1ccb3e1c4664d11213918511bedc836 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
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 <gio/gio.h>

#include <algorithm>
#include <cstddef>
#include <cstdint>
#include <memory>
#include <optional>
#include <string>
#include <variant>
#include <vector>

namespace wanda
{

struct setting;

/**
 * @brief A convenience type to represent setting keys
 */
using key = type_wrapper<std::string, struct KeyTag>;

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<setting> 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<std::monostate, bool, std::int32_t, std::int64_t, std::uint32_t, std::uint64_t, double, std::string, std::vector<std::string>>;

    value_type operator*() const;

    template <typename Type>
    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<Type, bool>)
                {
                  return g_settings_set_boolean(setting, key, value);
                }
                else if constexpr (std::is_same_v<Type, std::int32_t>)
                {
                  return g_settings_set_int(setting, key, value);
                }
                else if constexpr (std::is_same_v<Type, std::int64_t>)
                {
                  return g_settings_set_int64(setting, key, value);
                }
                else if constexpr (std::is_same_v<Type, std::uint32_t>)
                {
                  return g_settings_set_uint(setting, key, value);
                }
                else if constexpr (std::is_same_v<Type, std::uint64_t>)
                {
                  return g_settings_set_uint64(setting, key, value);
                }
                else if constexpr (std::is_same_v<Type, double>)
                {
                  return g_settings_set_double(setting, key, value);
                }
                else if constexpr (std::is_same_v<Type, std::string>)
                {
                  return g_settings_set_string(setting, key, value.c_str());
                }
                else if constexpr (std::is_same_v<Type, std::vector<std::string>>)
                {
                  auto temp = std::vector<gchar const *>{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<Type>{}, "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};
    }

  private:
    entry(setting const &schema, key key);

    std::unique_ptr<GSettings, decltype(&g_object_unref)> m_settings;

    key m_key;

    friend setting;
  };

  /**
   * @brief Get the entry for the given key
   * 
   * @return An <code>std::optional</code> wrapping the entry associated with
   * the given key, or an empty <code>std::optional</code> if the desired key
   * does not exist in the setting's schema.
   */
  std::optional<entry> operator[](key key) const;

private:
  explicit setting(GSettingsSchema *schema);

  std::unique_ptr<GSettingsSchema, decltype(&g_settings_schema_unref)> m_schema;

  friend std::optional<setting> literals::operator""_setting(char const *, std::size_t);
};

} // namespace wanda

#endif