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 string getPath() 69 { 70 return path; 71 } 72 73 string getName() 74 { 75 return name; 76 } 77 78 void free() 79 { 80 destroy(object); 81 } 82 } 83 84 /++ 85 Resource loader. Loads resources, fonts and more 86 and keeps it in memory. 87 +/ 88 class Loader 89 { 90 import std.path; 91 import std.exception : enforce; 92 93 private: 94 Resource[] resources; 95 96 public @safe: 97 /++ 98 Will load the resource, having only its path as 99 input. The entire loading implementation lies with 100 the resource itself. The manager will simply keep 101 this resource in memory. 102 103 Params: 104 T = Data type. 105 path = Path to the file. 106 name = Name. 107 108 Retunrs: 109 T 110 111 Throws: `LoadException` if the loader determines 112 that the file does not exist. There may be other 113 errors while loading, see their documentation, 114 for example `Image`. 115 116 Example: 117 --- 118 Image img = loader.load!Image("a.png"); 119 --- 120 +/ 121 T load(T)(immutable string path,string name = "null") 122 { 123 if (this.get!T(path) !is null) 124 return this.get!T(path); 125 126 T obj = new T(); 127 Resource res; 128 129 synchronized 130 { 131 enforce!Exception(path.exists, "Not find file `" ~ path ~ "`!"); 132 133 if(name == "null") 134 name = path.baseName.stripExtension; 135 136 obj.load(path); 137 138 res.path = path; 139 res.name = name; 140 res.init!T(obj); 141 142 this.resources ~= (res); 143 } 144 145 return obj; 146 } 147 148 /++ 149 Loads multiple resources in one fell swoop using an associated array. 150 151 Params: 152 T = Data type. 153 paths = Paths and names for loading resources. 154 155 Throws: `LoadException` if the loader determines 156 that the file does not exist. There may be other 157 errors while loading, see their documentation, 158 for example `Image`. 159 160 Example: 161 --- 162 loader.load!Image([ 163 "op1" : "image.png", 164 "op2" : "image2.png" 165 ]); 166 --- 167 +/ 168 void load(T)(immutable string[string] paths) 169 { 170 foreach (key; paths.keys) 171 { 172 this.load!T(paths[key],key); 173 } 174 } 175 176 private size_t pos(T)(T res) 177 { 178 foreach (size_t i; 0 .. resources.length) 179 { 180 if (resources[i].object is res) 181 { 182 return i; 183 } 184 } 185 186 throw new Exception("Unknown resource"); 187 } 188 189 /++ 190 Frees the resource from memory by calling the `free` 191 construct on the resource if it has unreleased pointers 192 and so on, and later removes the resource from the array, 193 letting the garbage collector destroy this object. 194 195 Params: 196 T = Resource class 197 path = Name or Path to file resource 198 199 Example: 200 --- 201 loader.free!Image("myImage"); 202 --- 203 +/ 204 void free(T)(immutable string path) @trusted 205 { 206 auto obj = get!T(path); 207 208 if (obj is null) 209 return; 210 211 resources.remove(pos(obj)); 212 synchronized destroy(obj); 213 } 214 215 /++ 216 Frees the resource from memory by calling the `free` 217 construct on the resource if it has unreleased pointers 218 and so on, and later removes the resource from the array, 219 letting the garbage collector destroy this object. 220 221 Params: 222 T = Resource class 223 obj = Resource object 224 225 Example: 226 --- 227 auto myImage = loader.load!Image(...); 228 loader.free(myImage); 229 --- 230 +/ 231 void free(T)(T obj) @trusted 232 { 233 if (obj is null) 234 return; 235 236 resources.remove(pos!T(obj)); 237 synchronized destroy(obj); 238 } 239 240 /++ 241 Returns a resource by name or path. 242 243 Params: 244 name = name resource(or path) 245 246 Returns: 247 `null` if the resource is not found. 248 If found, will return a `T` of the 249 appropriate size. 250 +/ 251 T get(T)(immutable string name) 252 { 253 foreach (e; this.resources) 254 { 255 if (e.getPath() == name) 256 return e.get!T; 257 258 if (e.getName() == name) 259 return e.get!T; 260 } 261 262 return null; 263 } 264 265 /++ 266 Will add a resource that was not loaded through the manager. 267 Please note that it must have a path and a name. 268 269 Params: 270 res = Resource. 271 +/ 272 void add(Resource res) 273 { 274 this.resources ~= (res); 275 } 276 277 ~this() @safe 278 { 279 foreach (res; resources) 280 { 281 res.free(); 282 } 283 } 284 }