Initial merge-commit of the OIC code. Should successfully do discovery for single...
[platform/upstream/iotivity.git] / include / OCProperties.h
1 //******************************************************************
2 //
3 // Copyright 2014 Intel Corporation All Rights Reserved.
4 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
5
6 #ifndef __INTEL_OCPROPERTIES_H_20140708
7  #define __INTEL_OCPROPERTIES_H_20140708
8
9 #include <list>
10 #include <array>
11 #include <deque>
12 #include <vector>
13 #include <algorithm>
14 #include <functional>
15
16 #include <sstream>
17 #include <ostream>
18 #include <iostream>
19
20 #include <iterator>
21 #include <type_traits>
22
23 #include "OCException.h"
24
25 namespace OC { namespace OCReflect {
26
27 enum class property_type : uint8_t {
28     nil                 = 1,
29     boolean,
30     integer,
31     rational,
32     string,     
33     list,
34
35         INVALID
36 };
37
38 enum class property_attribute : uint8_t {
39     r,
40     w,
41     rw
42 };
43
44 struct property_signature
45 {
46  OC::OCReflect::property_type       type;
47  OC::OCReflect::property_attribute  attribute;
48
49  public:
50  property_signature()
51   : type(OC::OCReflect::property_type::nil),
52     attribute(OC::OCReflect::property_attribute::rw)
53  {}
54
55  property_signature(const OC::OCReflect::property_type& type_)
56   : type(type_),
57     attribute(OC::OCReflect::property_attribute::rw)
58  {}
59
60  property_signature(const OC::OCReflect::property_type type_, const OC::OCReflect::property_attribute attribute_)
61   : type(type_),
62     attribute(attribute_)
63  {}
64 };
65
66 typedef std::vector<property_type>                                                      property_type_vector;
67
68 typedef std::vector<property_signature>                     property_signature_vector;
69
70 typedef std::vector<char>                                   property_data;
71
72 typedef std::tuple<std::string, property_signature>         named_property_binding;
73 typedef std::vector<named_property_binding>                                     named_property_binding_vector;
74
75 typedef std::tuple<named_property_binding, property_data>   property;
76 typedef std::tuple<property_signature, property_data>       tagged_property;         // eg. a return value
77
78 typedef std::vector<property>                               property_vector;
79
80 typedef std::function<property(property_vector)>            bound_function;
81
82 namespace detail {
83
84 // Great name, huh? Must be late in the day:
85 inline property_signature_vector typev2signaturev(const property_type_vector& ptv, const property_attribute pa = property_attribute::rw)
86 {
87  property_signature_vector psv(ptv.size());
88
89  std::transform(std::begin(ptv), std::end(ptv), std::back_inserter(psv),
90                 [&pa](const property_type& pt) -> property_signature { return property_signature(pt, pa); });
91
92  return psv;
93 }
94
95 }
96
97 namespace detail {
98
99 // Helper for constructing sequences (like vector<property>) from a parameter pack:
100 template <typename SeqT, typename T>
101 SeqT make_seq(const T& x)
102 {
103  return SeqT { x };
104 }
105
106 template <typename SeqT, typename T, typename ...TS>
107 SeqT make_seq(const T& x, const TS&... xs)
108 {
109  SeqT s { x };
110
111  auto vs = make_seq<SeqT>(xs...);
112
113  s.insert(s.end(), std::make_move_iterator(vs.begin()), std::make_move_iterator(vs.end()));
114
115  return s;
116 }
117
118 } // namespace OC::OCReflect::detail
119
120 }} // namespace OC::OCReflect
121
122 // Prettyprinters:
123 namespace OC { namespace OCReflect {
124
125 std::ostream& operator<<(std::ostream& os, const OC::OCReflect::property_type& pt);
126 std::ostream& operator<<(std::ostream& os, const OC::OCReflect::property_attribute& pa);
127 std::ostream& operator<<(std::ostream& os, const OC::OCReflect::property_signature& ps);
128 std::ostream& operator<<(std::ostream& os, const OC::OCReflect::property& p);
129
130 std::ostream& operator<<(std::ostream& os, const OC::OCReflect::property_type_vector& pv);
131 std::ostream& operator<<(std::ostream& os, const OC::OCReflect::property_vector& p);
132
133 std::ostream& operator<<(std::ostream& os, const OC::OCReflect::method_binding& mb);
134
135 }} // namespace OC::OCReflect
136
137 /* JFW: I wonder if I can do this...
138 constexpr OC::OCReflect::property_type map_property_type(bool)
139 {
140  return OC::OCReflect::property_type::boolean;
141 }
142 */
143
144 // Map concerete to property type enumerations:
145 namespace OC { namespace OCReflect {
146
147 template <typename T>
148 struct map_property_type
149 {
150  static const uint8_t value = static_cast<const uint8_t>(OC::OCReflect::property_type::INVALID);
151 };
152
153 template <>
154 struct map_property_type<bool>
155 {
156  static const uint8_t value = static_cast<const uint8_t>(OC::OCReflect::property_type::boolean);
157 };
158
159 template <>
160 struct map_property_type<int64_t>
161 {
162  static const uint8_t value = static_cast<const uint8_t>(OC::OCReflect::property_type::integer);
163 };
164
165 template <>
166 struct map_property_type<double>
167 {
168  static const uint8_t value = static_cast<const uint8_t>(OC::OCReflect::property_type::rational);
169 };
170
171 template <>
172 struct map_property_type<std::string>
173 {
174  static const uint8_t value = static_cast<const uint8_t>(OC::OCReflect::property_type::string);
175 };
176
177 template <>
178 struct map_property_type<const char *>
179 {
180  static const uint8_t value = static_cast<const uint8_t>(OC::OCReflect::property_type::string);
181 };
182
183 }} // namespace OC::OCReflect
184
185 /*
186 // Sequence containers:
187 template <>
188 struct map_property_type< template <class T, class A> >
189 {
190  static const uint8_t value = static_const<const uint8_t>(OC::OCReflect::property_type::list);
191 };
192
193 template <>
194 struct map_property_type<std::vector>
195 {
196  static const uint8_t value = static_const<const uint8_t>(OC::OCReflect::property_type::list);
197 };
198
199 template <>
200 struct map_property_type<std::list>
201 {
202  static const uint8_t value = static_const<const uint8_t>(OC::OCReflect::property_type::list);
203 };
204
205 template <>
206 struct map_property_type<std::forward_list>
207 {
208  static const uint8_t value = static_const<const uint8_t>(OC::OCReflect::property_type::list);
209 };
210
211 template <>
212 struct map_property_type<std::deque>
213 {
214  static const uint8_t value = static_const<const uint8_t>(OC::OCReflect::property_type::list);
215 };
216 */
217
218 namespace OC { namespace OCReflect { namespace to_property {
219
220 OC::OCReflect::tagged_property convert(const bool& in);
221 OC::OCReflect::tagged_property convert(const int& in);
222 OC::OCReflect::tagged_property convert(const int64_t& in);
223 OC::OCReflect::tagged_property convert(const double& in);
224 OC::OCReflect::tagged_property convert(const std::string& in);
225
226 }}} // namespace OC::OCReflect::to_property
227
228 typedef std::tuple<OC::OCReflect::property_data::const_iterator, OC::OCReflect::property_data::const_iterator>  pd_iter_tuple;
229
230 pd_iter_tuple consume_typecheck(const OC::OCReflect::property_type expected_pt, const OC::OCReflect::property_data& in);
231
232 namespace OC { namespace OCReflect { namespace from_property {
233
234 typedef OC::OCReflect::property_data::const_iterator pdci;
235 typedef std::tuple<pdci, pdci>  pd_iter_pair;
236
237 /* We need to use a struct to get around the fact that we can't partially specialize against a
238 free function's signature-- nothing else special happening here: */
239 struct conversion {
240
241 static void convert(const pd_iter_pair& in, bool& out)
242 {
243  out = static_cast<bool>(static_cast<int>(*(std::get<0>(in))));
244 }
245
246 static void convert(const pd_iter_pair& in, int64_t& out)
247 {
248  std::copy(std::get<0>(in), std::get<1>(in), reinterpret_cast<char *>(&out));
249 }
250
251 static void convert(const pd_iter_pair& in, double& out)
252 {
253  std::copy(std::get<0>(in), std::get<1>(in), reinterpret_cast<char *>(&out));
254 }
255
256 static void convert(const pd_iter_pair& in, std::string& out)
257 {
258  out.assign(std::get<0>(in), std::get<1>(in));
259 }
260
261 /*
262 template <template <class T, class AllocT> class SeqT>
263 static void convert(const pd_iter_pair& in, SeqT& out)
264 {
265  std::copy(std::get<0>(in), std::get<1>(in), std::back_inserter(out));
266 }
267 */
268
269 };
270
271 }}} // namespace OC::OCReflect::from_property
272
273 namespace OC { namespace OCReflect {
274
275 inline OC::OCReflect::named_property_binding make_named_property_binding(const std::string& name, const OC::OCReflect::property_type pt, const OC::OCReflect::property_attribute pa = OC::OCReflect::property_attribute::rw)
276 {
277  return OC::OCReflect::named_property_binding { name, { pt, pa } };
278 }
279
280 }} // namespace OC::OCReflect
281
282 // ...probably not-so-efficent, but we want it "working" for now:
283 namespace OC { namespace OCReflect {
284
285 // ...a class just to facilitate the usual ADL trick:
286 struct make_property {
287
288 // ...work around array->bool conversion:
289 static OC::OCReflect::property apply(const char *in, const std::string& name)
290 {
291  return apply(std::string(in), name);
292 }
293
294 template <class InT>
295 static OC::OCReflect::property apply(const InT& in, const std::string& name)
296 {
297 /* JFW:
298  static_assert(property_valid(InT, OC::OCReflect::property_type::INVALID),
299                "invalid input type for make_property()");
300 */
301
302  OC::OCReflect::tagged_property         tp { OC::OCReflect::to_property::convert(in) };
303  OC::OCReflect::named_property_binding npb { name, { std::get<0>(tp) } };
304
305  OC::OCReflect::property_data& tp_data = std::get<1>(tp);
306
307  // Encode the type, followed by the data:
308  OC::OCReflect::property_data encoded_data;
309
310  encoded_data.push_back(OC::OCReflect::map_property_type<InT>::value);
311  std::copy(std::begin(tp_data), std::end(tp_data), std::back_inserter(encoded_data));
312
313  return OC::OCReflect::property(npb, encoded_data);
314 }
315
316 /*
317 // Pretend you didn't see this, and I won't tell anyone where you hide the bodies:
318 template <class InT>
319 make_property(const InT& in, const std::string& name, OC::OCReflect::property& out)
320 {
321  out = detail::make_property::apply(in, name, out);
322 }
323 */
324
325 }; // struct make_property
326
327 }} // namespace OC::OCReflect
328
329 namespace OC { namespace OCReflect {
330
331 template <class OutT>
332 OutT concretize(const OC::OCReflect::property_data& pd)
333 {
334  OutT ret;
335
336  OC::OCReflect::from_property::conversion::convert(
337         consume_typecheck(
338                 static_cast<OC::OCReflect::property_type>(
339                         OC::OCReflect::map_property_type<OutT>::value), pd), ret);
340
341  return ret;
342 }
343
344 template <class OutT>
345 OutT concretize(const OC::OCReflect::tagged_property& tp)
346 {
347  return concretize<OutT>(std::get<1>(tp));
348 }
349
350 template <class OutT>
351 OutT concretize(const OC::OCReflect::property& p)
352 {
353  return concretize<OutT>(std::get<1>(p));
354 }
355
356 }} // namespace OC::OCReflect
357
358 namespace OC { namespace OCReflect {
359
360 // Runtime dynamic cast from entities to concrete types:
361 template <class OutT>
362 OutT narrow(const entity& e)
363 {
364  return OutT(); // placeholder
365 }
366
367 struct method_signature
368 {
369  property_signature           ret_signature;
370  property_signature_vector    param_signatures;
371
372  public:
373  method_signature(const property_type& return_type, const property_signature_vector& param_types_)
374   : ret_signature(return_type, OC::OCReflect::property_attribute::r),
375     param_signatures(param_types_)
376  {}
377
378  method_signature(const property_type& return_type, const property_type_vector& param_types_)
379   : ret_signature(return_type, OC::OCReflect::property_attribute::r),
380     param_signatures(detail::typev2signaturev(param_types_))
381  {}
382
383  template <typename ...ParameterT>
384  method_signature(const property_type& return_type, const ParameterT& ...params_)
385   : ret_signature(return_type, OC::OCReflect::property_attribute::r),
386     param_signatures { detail::make_seq<property_signature_vector>(params_...) }
387  {}
388 };
389
390 }} // namespace OC::OCReflect
391
392 namespace OC { namespace OCReflect {
393
394 struct method_binding
395 {
396  friend std::ostream& operator<<(std::ostream& os, const OC::OCReflect::method_binding& mb);
397
398  public:
399  std::string            name;
400  bound_function         f;
401  method_signature       signature;
402
403  private:
404  static unsigned long long anon;
405
406  public: 
407  method_binding() 
408   : name("__ANONYMOUS__"), 
409     signature { property_type::nil, {{ property_type::nil, property_attribute::r }} }
410  {}
411
412  method_binding(bound_function& f,
413                 method_signature& signature_)
414   : signature(signature_)
415  {}
416
417  method_binding(const std::string& name_, bound_function& f_, 
418                 const property_type& return_type_, const property_type_vector& param_types_)
419   : name(name_),
420     f(f_),
421     signature { return_type_, param_types_ } 
422  {}
423
424  method_binding(const std::string& name_, bound_function& f_,
425                 const method_signature& signature_)
426   : name(name_),
427     f(f_),
428    signature(signature_)
429  {}
430 };
431
432 struct property_binding
433 {
434  template <typename PropertyT>
435  property_binding(PropertyT& property, const named_property_binding& pb)
436  {
437  }
438 };
439
440 }} // namespace OC::OCReflect
441
442 #endif