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

#include <Corrade/Containers/StringView.h>

namespace floormat {}

namespace floormat::entities {

template<typename T> using const_qualified = std::conditional_t<std::is_fundamental_v<T>, T, const T&>;
template<typename T> using ref_qualified = std::conditional_t<std::is_fundamental_v<T>, T, T&>;
template<typename T> using move_qualified = std::conditional_t<std::is_fundamental_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;
    Reader reader;
    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 {
    template<typename FieldType>
    struct Field {
        template<FieldReader<Obj, FieldType> R, FieldWriter<Obj, FieldType> W>
        struct make final : field<Obj, FieldType, R, W> {
            consteval make(StringView name_, R r, W w) noexcept : field<Obj, FieldType, R, W>{name_, r, w} {}
        };
        template<FieldReader<Obj, FieldType> R, FieldWriter<Obj, FieldType> W>
        make(StringView name, R r, W w) -> make<R, W>;
    };
};

} // namespace floormat::entities