1 module vibeauth.collection; 2 3 import vibe.data.json; 4 5 import std.traits; 6 import std.stdio; 7 import std.algorithm.searching; 8 import std.algorithm.iteration; 9 import std.exception; 10 import std.uuid; 11 import std.conv; 12 import std.datetime; 13 import std.array; 14 import std.functional; 15 16 import std.range.interfaces; 17 import std.range.primitives; 18 19 class ItemNotFoundException : Exception { 20 this(string msg = null, Throwable next = null) { super(msg, next); } 21 this(string msg, string file, size_t line, Throwable next = null) { 22 super(msg, file, line, next); 23 } 24 } 25 26 interface ICollection(T) { 27 alias idType = typeof(T.id); 28 29 void add(T item); 30 31 void remove(const idType id); 32 void onRemove(void function(T)); 33 void onRemove(void delegate(T)); 34 35 size_t length(); 36 T opIndex(string index); 37 auto opBinaryRight(string op)(idType id); 38 int opApply(int delegate(T) dg); 39 int opApply(int delegate(ulong, T) dg); 40 @property bool empty(); 41 ICollection!T save(); 42 } 43 44 class Collection(T) : ICollection!T { 45 alias idType = typeof(T.id); 46 47 protected T[] list; 48 49 private void delegate(T) _onRemove; 50 51 this(T[] list = []) { 52 this.list = list; 53 } 54 55 void add(T item) { 56 enforce(!list.map!(a => a.id).canFind(item.id), "An item with the same id `" ~ item.id.to!string ~ "` already exists"); 57 list ~= item; 58 } 59 60 void remove(const idType id) { 61 auto item = list.filter!(a => a.id == id).front; 62 63 raiseOnRemove(item); 64 65 list = list.filter!(a => a.id != id).array; 66 } 67 68 69 void onRemove(void function(T) handler) { 70 onRemove(handler.toDelegate); 71 } 72 73 void onRemove(void delegate(T) handler) { 74 _onRemove = handler; 75 } 76 77 size_t length() { 78 return list.length; 79 } 80 81 T opIndex(string index) { 82 static if(is(string == idType)) { 83 auto list = list.find!(a => a.id == index); 84 85 enforce!ItemNotFoundException(list.count > 0, "Item not found"); 86 87 return list[0]; 88 } else { 89 throw new Exception("not implemented"); 90 } 91 } 92 93 auto opBinaryRight(string op)(idType id) { 94 static if (op == "in") { 95 return !list.filter!(a => a.id == id).empty; 96 } else { 97 static assert(false, op ~ " not implemented for `ItemCollection`"); 98 } 99 } 100 101 int opApply(int delegate(T) dg) { 102 int result = 0; 103 104 foreach(item; list) { 105 result = dg(item); 106 if (result) 107 break; 108 } 109 110 return result; 111 } 112 113 int opApply(int delegate(ulong, T) dg) { 114 int result = 0; 115 ulong idx = 0; 116 117 foreach(item; list) { 118 static if(is(size_t == idType)) { 119 idx = item.id; 120 } 121 122 result = dg(idx, item); 123 124 static if(!is(size_t == idType)) { 125 idx++; 126 } 127 128 if (result) 129 break; 130 } 131 132 return result; 133 } 134 135 @property bool empty() { 136 return list.empty; 137 } 138 139 ICollection!T save() { 140 return new Collection!T(list.dup); 141 } 142 143 private { 144 void raiseOnRemove(T item) { 145 if(_onRemove is null) { 146 return; 147 } 148 149 _onRemove(item); 150 } 151 } 152 }