1 module ws.thread.loader;
2 
3 import
4 	core.thread,
5 	std.traits,
6 	ws.wm,
7 	ws.thread.awaiter,
8 	ws.log,
9 	ws.list,
10 	ws.event,
11 	ws.io;
12 
13 __gshared:
14 
15 
16 class Loadable {
17 	
18 	enum: size_t {
19 		Idle,
20 		Loading,
21 		Loaded,
22 		Error
23 	}
24 	
25 	this(){
26 		loadState = Loadable.Idle;
27 		onLoaded = new LoadedQueue;
28 	}
29 	
30 	void finish(){
31 		synchronized(this){
32 			state = Loaded;
33 		}
34 	}
35 	
36 	@property size_t loadState(){
37 		synchronized(this) {
38 			return state;
39 		}
40 	}
41 	
42 	@property size_t loadState(size_t s){
43 		synchronized(this){
44 			state = s;
45 			if(s == Loaded)
46 				onLoaded();
47 			return state;
48 		}
49 	}
50 	
51 	@property bool loaded(){
52 		synchronized(this) {
53 			return state == Loaded;
54 		}
55 	}
56 	
57 	Loader loader;
58 	LoadedQueue onLoaded;
59 	
60 	private:
61 		size_t state;
62 			
63 		class LoadedQueue: ws.event.Event!() {
64 			void opOpAssign(string op)(void delegate() d) if(op=="~") {
65 				if(loaded)
66 					d();
67 				else
68 					super.opOpAssign!op(d);
69 			}
70 		}
71 
72 }
73 
74 alias void delegate() Function;
75 
76 
77 interface Loader {
78 
79 	void run(Function);
80 
81 	int length();
82 
83 }
84 
85 
86 class LoaderQueue: Loader {
87 	
88 	private List!Function queue;
89 
90 	this(){
91 		queue = new List!Function;
92 	}
93 
94 	override int length(){
95 		synchronized(this){
96 			return cast(int)queue.length;
97 		}
98 	}
99 
100 	override void run(Function fn){
101 		synchronized(this){
102 			queue ~= fn;
103 		}
104 	}
105 
106 	void tick(){
107 		if(length){
108 			Function fn;
109 			synchronized(this){
110 				fn = queue.popFront();
111 			}
112 			fn();
113 		}
114 	}
115 
116 }
117 
118 
119 class LoaderThread: LoaderQueue {
120 
121 	private Thread worker;
122 
123 	void shutdown(){
124 		synchronized(this)
125 			queue = null;
126 	}
127 
128 	this(void delegate() precall){
129 		queue = new List!Function;
130 		worker = new Thread({
131 			worker.priority = Thread.PRIORITY_MIN;
132 			worker.isDaemon = true;
133 			while(worker.isRunning && queue){
134 				try {
135 					while(worker && worker.isRunning && queue && !queue.length)
136 						worker.sleep(msecs(10));
137 					if(!queue)
138 						return;
139 					Function cb;
140 					synchronized(this)
141 						cb = queue.popFront();
142 					precall();
143 					cb();
144 				}catch(Throwable t)
145 					Log.error("THREAD ERROR: " ~ t.toString());
146 			}
147 		});
148 		worker.start();
149 	}
150 
151 }