]> git.xonotic.org Git - xonotic/netradiant.git/blob - libs/property.h
Merge commit '4f80165b29510dac0d86a230993a04717143e542' into master-merge
[xonotic/netradiant.git] / libs / property.h
1 #ifndef INCLUDED_IMPORTEXPORT_H
2 #define INCLUDED_IMPORTEXPORT_H
3
4 #include "generic/callback.h"
5 #include "string/string.h"
6
7 template<class T>
8 struct Property {
9     // todo: just return T, don't use continuation passing style
10     Callback<void(const Callback<void(T)> &returnz)> get;
11     Callback<void(T value)> set;
12 };
13
14 // implementation
15
16 template<class Self, class T = Self>
17 struct PropertyImpl {
18     static void Export(const Self &self, const Callback<void(T)> &returnz) {
19         returnz(self);
20     }
21
22     static void Import(Self &self, T value) {
23         self = value;
24     }
25 };
26
27 namespace detail {
28
29     template<class I>
30     using propertyimpl_self = typename std::remove_reference<get_argument<decltype(&I::Import), 0>>::type;
31
32     template<class I>
33     using propertyimpl_other = get_argument<decltype(&I::Import), 1>;
34
35     template<class I>
36     using propertyimpl_other_free = get_argument<decltype(&I::Import), 0>;
37
38 }
39
40 // adaptor
41
42 template<
43         class Self,
44         class T = Self,
45         class I = PropertyImpl<Self, T>
46 >
47 struct PropertyAdaptor {
48     using Type = Self;
49     using Other = T;
50
51     using Get = ConstReferenceCaller<Self, void(const Callback<void(T)> &), I::Export>;
52     using Set = ReferenceCaller<Self, void(T), I::Import>;
53 };
54
55 template<
56         class T,
57         class I
58 >
59 struct PropertyAdaptorFree {
60     using Other = T;
61
62     using Get = FreeCaller<void(const Callback<void(T)> &), I::Export>;
63     using Set = FreeCaller<void(T), I::Import>;
64 };
65
66 // explicit full
67
68 template<class A>
69 Property<typename A::Other> make_property(typename A::Type &self) {
70     return {typename A::Get(self), typename A::Set(self)};
71 }
72
73 template<class A>
74 Property<typename A::Other> make_property() {
75     return {typename A::Get(), typename A::Set()};
76 }
77
78 // explicit impl
79
80 template<class I, class Self = detail::propertyimpl_self<I>, class T = detail::propertyimpl_other<I>>
81 using property_impl = PropertyAdaptor<Self, T, I>;
82
83 template<class I, class Self, class T = detail::propertyimpl_other<I>>
84 Property<T> make_property(Self &self) {
85     return make_property<property_impl<I>>(self);
86 }
87
88 template<class I, class T = detail::propertyimpl_other_free<I>>
89 using property_impl_free = PropertyAdaptorFree<T, I>;
90
91 template<class I, class T = detail::propertyimpl_other_free<I>>
92 Property<T> make_property() {
93     return make_property<property_impl_free<I>>();
94 }
95
96 // implicit
97
98 template<class Self, class T = Self>
99 Property<T> make_property(Self &self) {
100     return make_property<PropertyAdaptor<Self, T>>(self);
101 }
102
103 // chain
104
105 template<typename DST, typename SRC, typename X, typename A>
106 struct make_property_chain_I_1 {
107     static void ExportThunk(const Callback<void(DST)> &self, SRC value) {
108         PropertyImpl<SRC, DST>::Export(value, self);
109     }
110
111     static void Export(const X &self, const Callback<void(DST)> &returnz) {
112         A::Get::thunk_(self, ConstReferenceCaller<Callback<void(DST)>, void(SRC), ExportThunk>(returnz));
113     }
114
115     static void Import(X &self, DST value) {
116         SRC out;
117         PropertyImpl<SRC, DST>::Import(out, value);
118         A::Set::thunk_(self, out);
119     }
120 };
121
122 template<class I_Outer, class I_Inner>
123 Property<detail::propertyimpl_other<I_Outer>> make_property_chain(detail::propertyimpl_self<I_Inner> &it) {
124     using DST = detail::propertyimpl_other<I_Outer>;
125     using SRC = detail::propertyimpl_self<I_Outer>;
126     using X = detail::propertyimpl_self<I_Inner>;
127
128     using A = property_impl<I_Inner>;
129     using I = make_property_chain_I_1<DST, SRC, X, A>;
130     return make_property<PropertyAdaptor<X, DST, I>>(it);
131 }
132
133 template<typename DST, typename SRC, typename A>
134 struct make_property_chain_I_2 {
135     static void ExportThunk(const Callback<void(DST)> &self, SRC value) {
136         PropertyImpl<SRC, DST>::Export(value, self);
137     }
138
139     static void Export(const Callback<void(DST)> &returnz) {
140         A::Get::thunk_(nullptr, ConstReferenceCaller<Callback<void(DST)>, void(SRC), ExportThunk>(returnz));
141     }
142
143     static void Import(DST value) {
144         SRC out;
145         PropertyImpl<SRC, DST>::Import(out, value);
146         A::Set::thunk_(nullptr, out);
147     }
148 };
149
150 template<class I_Outer, class I_Inner>
151 Property<detail::propertyimpl_other<I_Outer>> make_property_chain() {
152     using DST = detail::propertyimpl_other<I_Outer>;
153     using SRC = detail::propertyimpl_self<I_Outer>;
154
155     using A = property_impl_free<I_Inner>;
156     using I = make_property_chain_I_2<DST, SRC, A>;
157     
158     return make_property<PropertyAdaptorFree<DST, I>>();
159 }
160
161 // specializations
162
163 template<>
164 struct PropertyImpl<CopiedString, const char *> {
165     static void Export(const CopiedString &self, const Callback<void(const char *)> &returnz) {
166         returnz(self.c_str());
167     }
168
169     static void Import(CopiedString &self, const char *value) {
170         self = value;
171     }
172 };
173
174 #endif