1 ///
2 module libasync.event;
3 
4 import core.thread;
5 import libasync.types;
6 import libasync.events;
7 
8 /// Takes a raw kernel-emitted file descriptor and registers its events into the event loop for async processing
9 /// NOTE: If it's a socket, it must be made non-blocking before being passed here.
10 /// NOTE: By default dispatched events are READ, WRITE, and ERROR; enabling 'stateful' adds CONNECT and CLOSE
11 class AsyncEvent
12 {
13 nothrow:
14 private:
15 	Thread m_owner;
16 	EventLoop m_evLoop;
17 	fd_t m_evId;
18 	bool m_stateful;
19 
20 public:
21 	///
22 	this(EventLoop evl, fd_t ev_id, bool stateful = false)
23 	in {
24 		assert(evl !is null && ev_id > 0);
25 	}
26 	body {
27 		m_evLoop = evl;
28 		import core.thread : Thread;
29 		m_owner = Thread.getThis();
30 		m_evId = ev_id;
31 		m_stateful = stateful;
32 	}
33 
34 	///
35 	@property bool hasError() const
36 	{
37 		return (cast(EventLoop)m_evLoop).status.code != Status.OK;
38 	}
39 
40 	/// Used to diagnose errors when run() or kill() returns false
41 	@property StatusInfo status() const {
42 		return (cast(EventLoop)m_evLoop).status;
43 	}
44 
45 	/// Human-readable string describing the error
46 	@property string error() const {
47 		return (cast(EventLoop)m_evLoop).error;
48 	}
49 
50 	/// Registers the signal handler in the event loop
51 	bool run(void delegate(EventCode) del)
52 	in {
53 		debug assert(Thread.getThis() is cast(Thread)m_owner);
54 	}
55 	body {
56 
57 		EventHandler handler;
58 		handler.del = del;
59 		handler.ev = this;
60 		return (cast(EventLoop) m_evLoop).run(this, handler);
61 	}
62 
63 	/// Returns the Thread that created this object.
64 	synchronized @property Thread owner() const {
65 		return cast(Thread) m_owner;
66 	}
67 
68 	///
69 	@property fd_t id() const {
70 		return m_evId;
71 	}
72 
73 	/// Removes the event from the event loop, closing the file descriptor if necessary,
74 	/// and cleans up the underlying resources.
75 	bool kill(bool forced = false)
76 	body {
77 		scope(exit) m_evId = 0;
78 		return m_evLoop.kill(this, forced);
79 	}
80 
81 package:
82 	mixin COSocketMixins;
83 
84 	@property bool stateful() const {
85 		return m_stateful;
86 	}
87 
88 	@property void stateful(bool stateful) {
89 		m_stateful = stateful;
90 	}
91 
92 	@property void id(fd_t id) {
93 		m_evId = id;
94 	}
95 }
96 
97 package struct EventHandler {
98 	AsyncEvent ev;
99 	void delegate(EventCode) del;
100 	void opCall(EventCode code){
101 		assert(ev !is null);
102 		del(code);
103 		assert(ev !is null);
104 		return;
105 	}
106 }
107 
108 ///
109 enum EventCode : char {
110 	///
111 	ERROR = 0,
112 	///
113 	READ,
114 	///
115 	WRITE,
116 	///
117 	CONNECT,
118 	///
119 	CLOSE
120 }