#ifndef TYPES_H
#define TYPES_H


#include <type_traits>
#include <cstdint>


// Some basic types that should build serializable structures from
template<typename T>
using Array      = std::vector<T>;
using Boolean    = bool;
using Byte       = uint8_t;
using Char       = int8_t;
using Unsigned32 = uint32_t;
using Unsigned64 = uint64_t;
using Integer32  = int32_t;
using Integer64  = int64_t;
using Float32    = float;
using Float64    = double;
using String     = std::string;

// discourage 16bit types, CPUs aren't so efficient at these
// TODO: enums

/*
 
   about enums:
   
        Looks like C++17 might make reflection of enums nice.
            http://aantron.github.io/better-enums/demo/C++17ReflectionProposal.html
        In the mean time, something like this gets close with the use of an ugly macro where the enums are declared
        however it provides similar syntax to what C++17 may have for using the reflection
            http://melpon.org/wandbox/permlink/QelcwZNLi4gIx8Ux
 
 */

struct EnumBaseValue
{
  Integer32   id;
  String      name;
};


struct EnumBase
{
  String                name;
  Array<EnumBaseValue>  values;
};


#define DECLARE_STRUCT(name) \
    struct name { \
      private: \
        typedef name _this_type; \
        static const char* _this_name() { return #name; } \
      public: \
        typedef struct { \
          static const decltype(std::make_tuple()) tuple() { \
            return std::make_tuple(); \
          }

#define DECLARE_MEMBER(type, name, ...) \
        } blah##name; \
        \
        type name = type(__VA_ARGS__); \
        \
        typedef struct { \
          static type& get_##name(_this_type& _this) { \
            return _this.name; \
          } \
          typedef decltype(std::tuple_cat(blah##name::tuple(), std::make_tuple(#name, get_##name))) ret_type; \
          static const ret_type tuple() { \
            return std::tuple_cat(blah##name::tuple(), std::make_tuple(#name, get_##name)); \
          }

#define END_STRUCT() \
        } last; \
        template <class V> \
        void Visit(V& v) \
        { \
          v.Enter(_this_name()); \
          static auto tup = last::tuple(); \
          for_each(v, *this, tup); \
          v.Exit(_this_name()); \
        } \
    };


#endif // TYPES_H

