1 module uim.oop.mixins.properties.expandable;
2 
3 import std..string;
4 import uim.core;
5 
6 // Mixin for expandable string datatypes
7 template XString(string name) {
8 	const char[] XString = "
9 	string _"~name~";
10 	@safe auto "~name~"() { return _"~name~"; }
11 
12 	@safe O "~name~"(this O)(string[] addValues...) { this."~name~"(addValues); return cast(O)this; }
13 	@safe O "~name~"(this O)(string[] addValues) { _"~name~" ~= addValues.join(); return cast(O)this; }
14 
15 	@safe O clear"~name.capitalize~"(this O)() { _"~name~" = null; return cast(O)this; }	
16 	";
17 }
18 unittest {
19 	class Test { mixin(XString!"a"); }
20 	assert((new Test).a("x").a == "x");
21 	assert((new Test).a("x").a("x").a == "xx");
22 	assert((new Test).a("x", "x").a == "xx");
23 	assert((new Test).a(["x", "x"]).a == "xx");
24 	assert((new Test).a("x").clearA.a == "");
25 }
26 
27 // Mixin for expandable string array datatypes
28 template XStringArray(string name) {
29 	const char[] Name = name.capitalize;
30 	const char[] XStringArray = "
31 	string[] _"~name~";
32 	@safe auto "~name~"() { return _"~name~"; }
33 
34 	@safe O "~name~"(this O)(string[] values...) { this."~name~"(values); return cast(O)this; }
35 	@safe O "~name~"(this O)(string[] values) { _"~name~" ~= values; return cast(O)this; }
36 	
37 	@safe O remove"~Name~"(this O)(string[] values...) { this.remove"~Name~"(values); return cast(O)this; }	
38 	@safe O remove"~Name~"(this O)(string[] values) {
39 		foreach(value; values) _"~name~" = _"~name~".sub(value); return cast(O)this; }	
40 	
41 	@safe O clear"~Name~"(this O)() { _"~name~" = null; return cast(O)this; }	
42 	";
43 }
44 unittest {
45 	class Test { mixin(XStringArray!"a"); }
46 	assert((new Test).a("x").a == ["x"]);
47 	assert((new Test).a("x").a("x").a == ["x", "x"]);
48 	assert((new Test).a("x", "x").a == ["x", "x"]);
49 	assert((new Test).a("x").clearA.a == null);
50 	assert((new Test).a(["a", "b", "c"]).a == ["a", "b", "c"]);
51  	assert((new Test).a(["a", "b", "c"]).removeA("x").a == ["a", "b", "c"]);
52 	assert((new Test).a(["a", "b", "c", "a"]).a == ["a", "b", "c", "a"]); 
53   assert((new Test).a(["a", "b", "c", "a"]).removeA("a").a == ["b", "c", "a"]);
54 	assert((new Test).a(["a", "b", "c", "a"]).removeA(["a"]).a == ["b", "c", "a"]); 
55 	//assert((new Test).a(["a", "b", "c"]).removeA(["a"], true).a == ["b", "c"]);
56 }
57 
58 // Mixin for expandable string associative array datatypes
59 template XStringAA(string name) {
60 	const char[] Name = name.capitalize;
61 	const char[] XStringAA = "
62 	string[string] _"~name~";
63 	@safe auto "~name~"() { return _"~name~"; }
64 	@safe auto "~name~"(string key) { return _"~name~".get(key, ``); }
65 
66 	@safe O "~name~"(this O)(string key, string value) { _"~name~"[key] = value; return cast(O)this; }
67 	@safe O "~name~"(this O)(string[string] addValues) { foreach(kv; addValues.byKeyValue) _"~name~"[kv.key] = kv.value; return cast(O)this; }
68 	
69 	@safe O remove"~Name~"(this O)(string[] values...) { this.remove(values); return cast(O)this; }	
70 	@safe O remove"~Name~"(this O)(string[] values) { foreach(value; values) _name = _"~name~".remove(value); return cast(O)this; }	
71 	
72 	@safe O clear"~Name~"(this O)() { _"~name~" = null; return cast(O)this; }	
73 	";
74 }
75 unittest {
76 	class Test { mixin(XStringAA!"a"); }
77 	assert((new Test).a(["a":"x"]).a == ["a":"x"]);
78 	assert((new Test).a("a", "x").a == ["a":"x"]);
79 	assert((new Test).a("a", "x").clearA.a == null);
80 }
81 
82 template XPropertyAA(string key, string value, string name) {
83 	const char[] Name = capitalize(name);
84 	const char[] datatype = value~`[`~key~`]`;
85 
86 	const char[] XPropertyAA = `	`~datatype~` _`~name~`; 
87 	@safe auto `~name~`() { return _`~name~`; }
88 	@safe auto `~name~`(`~key~` key) { return _`~name~`[key]; }
89 
90 	@safe auto `~name~`(this O)(`~key~`[] keys...) { return this.`~name~`(keys); }
91 	@safe auto `~name~`(this O)(`~key~`[] keys) { return _`~name~`.select(keys); }
92 
93 	@safe O `~name~`(this O)(`~datatype~` values) { _`~name~` = _`~name~`.add(values); return cast(O)this; }
94 
95 	@safe O `~name~`Init(this O)(`~key~`[] keys, `~value~` value) { foreach(k; keys) _`~name~`[k] = value; return cast(O)this; }
96 	@safe O `~name~`Add(this O)(`~datatype~` values) { _`~name~` = _`~name~`.add(values); return cast(O)this; }
97 	@safe O `~name~`Sub(this O)(`~datatype~` values) { _`~name~` = _`~name~`.sub(values); return cast(O)this; }
98 
99 	@safe O remove`~Name~`(this O)(`~key~`[] keys...) { return this.remove`~Name~`(keys); return cast(O)this; }
100 	@safe O remove`~Name~`(this O)(`~key~`[] keys) { _`~name~` = _`~name~`.sub(keys); return cast(O)this; }
101 
102 	@safe O clear`~Name~`(this O)() { _`~name~` = _`~name~`.clear; return cast(O)this; }
103 `;
104 }
105 unittest {
106 	class Test { mixin(XPropertyAA!("int", "double", "a")); }
107  	assert((new Test).a([1:1.0]).a[1] == 1.0);
108  	assert((new Test).a([1:1.0]).a.hasKey(1));
109  	assert((new Test).a([1:1.0]).a([2:3.0]).a.hasKey(2));
110  	assert(!(new Test).a([1:1.0, 2:3.0]).aSub([2:3.0]).a.hasKey(2));
111  	assert((new Test).aInit([1, 2], 1.0).a[1] == 1.0);
112 }
113 
114 template XPropertyArray(string datatype, string name) {
115 	const char[] Name = capitalize(name);
116 	const char[] XPropertyArray = `
117 	`~datatype~`[] _`~name~`; 
118 	@safe auto `~name~`() { return _`~name~`; }
119 
120 	@safe O `~name~`(this O)(`~datatype~`[] values...) { _`~name~` = _`~name~`.add(values); return cast(O)this; }
121 	@safe O `~name~`(this O)(`~datatype~`[] values, bool unique = false) { _`~name~` = _`~name~`.add(values, unique); return cast(O)this; }
122 	
123 	@safe O remove`~Name~`(this O)(`~datatype~`[] values...) { remove`~Name~`(values); return cast(O)this; }
124 	@safe O remove`~Name~`(this O)(`~datatype~`[] values) { 
125 		foreach(value; values) if (value.index(_`~name~`) != -1) _`~name~`.remove(value.index(_`~name~`)); 
126 		return cast(O)this; }
127 
128 	@safe O clear`~Name~`(this O)() { _`~name~` = null; return cast(O)this; }
129 `;
130 }
131 unittest {
132 	class Test { mixin(XPropertyArray!("int", "a")); }
133  	assert((new Test).a(0).a == [0]);
134 	assert((new Test).a(0).a(1).a == [0, 1]);
135 	assert((new Test).a(0, 1).a == [0, 1]);
136 	assert((new Test).a(0).clearA.a == null);
137 	assert((new Test).a([1, 2, 3]).a == [1, 2, 3]);
138  	// assert((new Test).a([1, 2, 3]).removeA(4).a == [1, 2, 3]);
139 	/* assert((new Test).a([1, 2, 3, 1]).a == [1, 2, 3, 1]); 
140   assert((new Test).a([1, 2, 3, 1]).removeA(1).a == [2, 3, 1]);
141 	assert((new Test).a([1, 2, 3, 1]).removeA([1]).a == [2, 3, 1]);  */
142  	//assert((new Test).a(["a", "b", "c"]).removeA(["a"], true).a == ["b", "c"]);
143 }