summaryrefslogtreecommitdiffhomepage
path: root/src/entity.hpp
blob: b46fefcc93feab4de5f6321c72ad7a4a8c6b6ecc (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
#pragma once
#include "compat/integer-types.hpp"
#include <concepts>
#include <type_traits>
#include <tuple>
#include <utility>
#include <algorithm>

#include <Corrade/Containers/StringView.h>

namespace floormat {}

namespace floormat::entities {

template<typename T> struct pass_by_value : std::bool_constant<std::is_fundamental_v<T>> {};
template<typename T> constexpr inline bool pass_by_value_v = pass_by_value<T>::value;
template<> struct pass_by_value<StringView> : std::true_type {};

template<typename T> using const_qualified = std::conditional_t<pass_by_value_v<T>, T, const T&>;
template<typename T> using ref_qualified = std::conditional_t<pass_by_value_v<T>, T, T&>;
template<typename T> using move_qualified = std::conditional_t<pass_by_value_v<T>, T, T&&>;

template<typename F, typename T, typename FieldType>
concept FieldReader_memfn = requires(const T x, F f) {
    { (x.*f)() } -> std::convertible_to<FieldType>;
};

template<typename F, typename T, typename FieldType>
concept FieldReader_ptr = requires(const T x, F f) {
    { x.*f } -> std::convertible_to<FieldType>;
};

template<typename F, typename T, typename FieldType>
concept FieldReader_function = requires(const T x, F f) {
    { f(x) } -> std::convertible_to<FieldType>;
};

template<typename F, typename T, typename FieldType>
concept FieldReader = requires {
    requires FieldReader_memfn<F, T, FieldType> ||
             FieldReader_ptr<F, T, FieldType> ||
             FieldReader_function<F, T, FieldType>;
};

template<typename F, typename T, typename FieldType>
concept FieldWriter_memfn = requires(T x, move_qualified<FieldType> value, F f) {
    { (x.*f)(value) } -> std::same_as<void>;
};

template<typename F, typename T, typename FieldType>
concept FieldWriter_ptr = requires(T x, move_qualified<FieldType> value, F f) {
    { x.*f = value };
};

template<typename F, typename T, typename FieldType>
concept FieldWriter_function = requires(T x, move_qualified<FieldType> value, F f) {
    { f(x, value) } -> std::same_as<void>;
};

template<typename F, typename T, typename FieldType>
concept FieldWriter = requires {
    requires FieldWriter_memfn<F, T, FieldType> ||
             FieldWriter_ptr<F, T, FieldType> ||
             FieldWriter_function<F, T, FieldType>;
};

template<typename Obj, typename Type, typename R>
struct read_field {
    static Type read(const Obj& x, R r) { return r(x); }
};

template<typename Obj, typename Type>
struct read_field<Obj, Type, Type (Obj::*)() const> {
    static Type read(const Obj& x, Type (Obj::*r)() const) { return (x.*r)(); }
};

template<typename Obj, typename Type>
struct read_field<Obj, Type, Type Obj::*> {
    static Type read(const Obj& x, Type Obj::*r) { return x.*r; }
};

template<typename Obj, typename FieldType, typename Writer> struct write_field {
    static void write(Obj& x, Writer w, move_qualified<FieldType> value) { w(x, value); }
};

template<typename Obj, typename Type>
struct write_field<Obj, Type, void(Obj::*)(move_qualified<Type>)> {
    static void write(Obj& x, void(Obj::*w)(move_qualified<Type>), move_qualified<Type> value) { (x.*w)(value); }
};

template<typename Obj, typename Type>
struct write_field<Obj, Type, Type Obj::*> {
    static void write(Obj& x, Type Obj::* w, move_qualified<Type> value) { x.*w = value; }
};

template<typename Obj, typename FieldType, FieldReader<Obj, FieldType> R, FieldWriter<Obj, FieldType> W>
struct field {
    using Object = Obj;
    using Type = FieldType;
    using Reader = R;
    using Writer = W;

    StringView name;
    [[no_unique_address]] Reader reader;
    [[no_unique_address]] Writer writer;

    constexpr field(StringView name, Reader r, Writer w) noexcept : name{name}, reader{r}, writer{w} {}
    decltype(auto) read(const Obj& x) const { return read_field<Obj, FieldType, R>::read(x, reader); }
    void write(Obj& x, move_qualified<FieldType> v) const { write_field<Obj, FieldType, W>::write(x, writer, v); }
};

template<typename Obj>
struct entity final {
    template<typename FieldType>
    struct Field {
        template<FieldReader<Obj, FieldType> R, FieldWriter<Obj, FieldType> W>
        static consteval auto make(StringView name, R r, W w) noexcept {
            return field<Obj, FieldType, R, W> { name, r, w };
        }
    };
};

template<typename Key, typename KeyT, typename... Xs>
struct assoc final {
    template<typename T> using Types = std::tuple<Xs...>;
    consteval assoc(Xs&&... xs) {

    }

private:
    template<typename T> struct cell { Key key; T value; };
    std::tuple<cell<Xs>...> _tuple;
};

} // namespace floormat::entities