1 /**
2 Copyright: Copyright (c) 2016-2018 Andrey Penechko.
3 License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0).
4 Authors: Andrey Penechko.
5 */
6 module datadriven.api;
7 
8 import std.traits : TemplateArgsOf;
9 import std.typecons : BitFlags;
10 
11 enum Replication
12 {
13 	none,
14 	toDb = 1 << 0,
15 	toClient = 1 << 1,
16 }
17 
18 struct Component {
19 	this(string _key, Replication flags) {
20 		key = _key;
21 		replication = flags;
22 	}
23 	string key;
24 	BitFlags!Replication replication = BitFlags!Replication(Replication.toDb, Replication.toClient);
25 }
26 
27 template componentUda(C)
28 {
29 	import std.traits : hasUDA, getUDAs;
30 	static if (hasUDA!(C, Component))
31 		Component componentUda = getUDAs!(C, Component)[0];
32 	else
33 		static assert(false, "Component " ~ C.stringof ~ " has no Component UDA");
34 }
35 
36 alias EntityId = ulong;
37 
38 alias componentType(ComponentStorage) = TemplateArgsOf!ComponentStorage[0];
39 
40 // tests if CS is a Component storage of components C
41 template isComponentStorage(CS, C)
42 {
43 	enum bool isComponentStorage = is(typeof(
44 	(inout int = 0)
45 	{
46 		CS cs = CS.init;
47 		C c = C.init;
48 		EntityId id = EntityId.init;
49 
50 		cs.set(id, c); // Can add component
51 		cs.remove(id); // Can remove component
52 		C* cptr = cs.get(id); // Can get component pointer
53 
54 		foreach(key, value; cs)
55 		{
56 			id = key;
57 			c = value = c;
58 		}
59 	}));
60 }
61 
62 // tests if CS is a Component storage of any component type
63 template isAnyComponentStorage(CS)
64 {
65 	static if (is(CS.ComponentType C))
66 		enum bool isAnyComponentStorage = isComponentStorage!(CS, C);
67 	else
68 		enum bool isAnyComponentStorage = false;
69 }
70 
71 template isEntitySet(S)
72 {
73 	enum bool isEntitySet = is(typeof(
74 	(inout int = 0)
75 	{
76 		S s = S.init;
77 		EntityId id = EntityId.init;
78 
79 		s.set(id); // Can add component
80 		s.remove(id); // Can remove component
81 		bool contains = s.get(id); // Can check presence
82 
83 		foreach(key; s)
84 		{
85 			id = key;
86 		}
87 	}));
88 }
89 
90 unittest
91 {
92 	struct A {}
93 	struct B
94 	{
95 		void set(EntityId);
96 		void remove(EntityId);
97 		bool get(EntityId);
98 		int opApply(scope int delegate(in EntityId) del) {
99 			return 0;
100 		}
101 	}
102 	struct C
103 	{
104 		void set(EntityId, int);
105 		void remove(EntityId);
106 		int* get(EntityId);
107 		int opApply(scope int delegate(in EntityId, ref int) del) {
108 			return 0;
109 		}
110 		alias ComponentType = int;
111 	}
112 	static assert(!isComponentStorage!(A, int));
113 	static assert(!isAnyComponentStorage!A);
114 	static assert(!isEntitySet!(A));
115 
116 	static assert(!isComponentStorage!(B, int));
117 	static assert(!isAnyComponentStorage!B);
118 	static assert( isEntitySet!(B));
119 
120 	static assert( isComponentStorage!(C, int));
121 	static assert( isAnyComponentStorage!C);
122 	static assert(!isEntitySet!(C));
123 }