1 /++ 2 Resource loader module 3 4 Using the loader, you can load various resources that 5 will be kept in memory. They can be accessed by their 6 name or path, they can also be unloaded from memory. 7 8 Please note that it is unnecessary to reload `download` since it does 9 not exist, it is implemented using the download-upload method. It will 10 load the resource from the .temp folder. 11 12 Macros: 13 LREF = <a href="#$1">$1</a> 14 HREF = <a href="$1">$2</a> 15 16 Authors: $(HREF https://github.com/TodNaz,TodNaz) 17 Copyright: Copyright (c) 2020 - 2021, TodNaz. 18 License: $(HREF https://github.com/TodNaz/Tida/blob/master/LICENSE,MIT) 19 +/ 20 module tida.loader; 21 22 import std.path : baseName, stripExtension; 23 import std.file : exists,mkdir; 24 25 __gshared Loader _loader; 26 27 /// Loader instance. 28 Loader loader() @trusted 29 { 30 return _loader; 31 } 32 33 /// Resource descriptor 34 struct Resource 35 { 36 public: 37 Object object; /// Object 38 string type; /// Type name object 39 string path; /// Releative path object 40 string name; /// Local name object 41 bool isFont = false; 42 43 @trusted: 44 /++ 45 Initializes a resource. For this, he saves the name of the type and later, 46 according to this type, he can determine further calls to it. 47 48 Params: 49 resource = Object resource. 50 +/ 51 void init(T)(T resource) 52 { 53 object = resource; 54 type = typeid(T).toString; 55 } 56 57 /++ 58 The method to get the object. 59 If the object turns out to be the wrong one, the contract will work. 60 +/ 61 T get(T)() 62 in(typeid(T).toString == type) 63 do 64 { 65 return cast(T) object; 66 } 67 68 void free() 69 { 70 destroy(object); 71 } 72 } 73 74 /++ 75 Resource loader. Loads resources, fonts and more 76 and keeps it in memory. 77 +/ 78 class Loader 79 { 80 import std.path; 81 import std.exception : enforce; 82 83 private: 84 Resource[] resources; 85 86 public @safe: 87 /++ 88 Will load the resource, having only its path as 89 input. The entire loading implementation lies with 90 the resource itself. The manager will simply keep 91 this resource in memory. 92 93 Params: 94 T = Data type. 95 path = Path to the file. 96 name = Name. 97 98 Retunrs: 99 T 100 101 Throws: `LoadException` if the loader determines 102 that the file does not exist. There may be other 103 errors while loading, see their documentation, 104 for example `Image`. 105 106 Example: 107 --- 108 Image img = loader.load!Image("a.png"); 109 --- 110 +/ 111 T load(T)(immutable string path,string name = "null") 112 { 113 if (this.get!T(path) !is null) 114 return this.get!T(path); 115 116 T obj = new T(); 117 Resource res; 118 119 synchronized 120 { 121 enforce!Exception(path.exists, "Not find file `" ~ path ~ "`!"); 122 123 if(name == "null") 124 name = path.baseName.stripExtension; 125 126 obj.load(path); 127 128 res.path = path; 129 res.name = name; 130 res.init!T(obj); 131 132 this.resources ~= (res); 133 } 134 135 return obj; 136 } 137 138 /++ 139 Loads multiple resources in one fell swoop using an associated array. 140 141 Params: 142 T = Data type. 143 paths = Paths and names for loading resources. 144 145 Throws: `LoadException` if the loader determines 146 that the file does not exist. There may be other 147 errors while loading, see their documentation, 148 for example `Image`. 149 150 Example: 151 --- 152 loader.load!Image([ 153 "op1" : "image.png", 154 "op2" : "image2.png" 155 ]); 156 --- 157 +/ 158 void load(T)(immutable string[string] paths) 159 { 160 foreach (key; paths.keys) 161 { 162 this.load!T(paths[key],key); 163 } 164 } 165 166 private size_t pos(T)(T res) 167 { 168 foreach (size_t i; 0 .. resources.length) 169 { 170 if (resources[i].object is res) 171 { 172 return i; 173 } 174 } 175 176 throw new Exception("Unknown resource"); 177 } 178 179 /++ 180 Frees the resource from memory by calling the `free` 181 construct on the resource if it has unreleased pointers 182 and so on, and later removes the resource from the array, 183 letting the garbage collector destroy this object. 184 185 Params: 186 T = Resource class 187 path = Name or Path to file resource 188 189 Example: 190 --- 191 loader.free!Image("myImage"); 192 --- 193 +/ 194 void free(T)(immutable string path) @trusted 195 { 196 auto obj = get!T(path); 197 198 if (obj is null) 199 return; 200 201 resources.remove(pos(obj)); 202 synchronized destroy(obj); 203 } 204 205 /++ 206 Frees the resource from memory by calling the `free` 207 construct on the resource if it has unreleased pointers 208 and so on, and later removes the resource from the array, 209 letting the garbage collector destroy this object. 210 211 Params: 212 T = Resource class 213 obj = Resource object 214 215 Example: 216 --- 217 auto myImage = loader.load!Image(...); 218 loader.free(myImage); 219 --- 220 +/ 221 void free(T)(T obj) @trusted 222 { 223 if (obj is null) 224 return; 225 226 resources.remove(pos!T(obj)); 227 synchronized destroy(obj); 228 } 229 230 /++ 231 Returns a resource by name or path. 232 233 Params: 234 name = name resource(or path) 235 236 Returns: 237 `null` if the resource is not found. 238 If found, will return a `T` of the 239 appropriate size. 240 +/ 241 T get(T)(immutable string name) 242 { 243 foreach (e; this.resources) 244 { 245 if (e.path == name) 246 return e.get!T; 247 248 if (e.name == name) 249 return e.get!T; 250 } 251 252 return null; 253 } 254 255 /++ 256 Will add a resource that was not loaded through the manager. 257 Please note that it must have a path and a name. 258 259 Params: 260 res = Resource. 261 +/ 262 void add(Resource res) 263 { 264 this.resources ~= (res); 265 } 266 267 ~this() @safe 268 { 269 foreach (res; resources) 270 { 271 res.free(); 272 } 273 } 274 }