eventcore.driver 2/11(18%) line coverage

      
10
20
30
40
50
60
70
80
90
100
110
120
130
140
150
160
170
180
190
200
210
220
230
240
250
260
270
280
290
300
310
320
330
340
350
360
370
380
390
400
410
420
430
440
450
460
470
480
490
500
510
520
530
540
550
560
570
580
590
600
610
620
630
640
650
660
670
680
690
700
710
720
730
740
750
760
770
780
790
800
810
820
830
840
850
860
870
880
890
900
910
920
930
940
950
960
970
980
990
1000
1010
1020
1030
1040
1050
1060
1070
1080
1090
1100
1110
1120
1130
1140
1150
1160
1170
1180
1190
1200
1210
1220
1230
1240
1250
1260
1270
1280
1290
1300
1310
1320
1330
1340
1350
1360
1370
1380
1390
1400
1410
1420
1430
1440
1450
1460
1470
1480
1490
1500
1510
1520
1530
1540
1550
1560
1570
1580
1590
1600
1610
1620
1630
1640
1650
1660
1670
1680
1690
1700
1710
1720
1730
1740
1750
1760
1770
1780
1790
1800
1810
1820
1830
1840
1850
1860
1870
1880
1890
1900
1910
1920
1930
1940
1950
1960
1970
1980
1990
2000
2010
2020
2030
2040
2050
2060
2070
2080
2090
2100
2110
2120
2130
2140
2150
2160
2170
2180
2190
2200
2210
2220
2230
2240
2250
2260
2270
2280
2290
2300
2310
2320
2330
2340
2350
2360
2370
2380
2390
2400
2410
2420
2430
2440
2450
2460
2470
2480
2490
2500
2510
2520
2530
2540
2550
2560
2570
2580
2590
2600
2610
2620
2630
2640
2650
2660
2670
2680
2690
2700
2710
2720
2730
2740
2750
2760
2770
2780
2790
2800
2810
2820
2830
2840
2850
2860
2870
2880
2890
2900
2910
2920
2930
2940
2950
2960
2970
2980
2990
3000
3010
3020
3030
3040
3050
3060
3070
3080
3090
3100
3110
3120
3130
3140
3150
3160
3170
3180
3190
3200
3210
3220
3230
3240
3250
3260
3270
3280
3290
3300
3310
3320
3330
3340
3350
3360
3370
3380
3390
3400
3410
3420
3430
3440
3450
3460
3470
3480
3490
3500
3510
3520
3530
3540
3550
3560
3570
3580
3590
3600
3610
3620
3630
3640
3650
3660
3670
3680
3690
3700
3710
3720
3730
3740
3750
3760
3770
3780
3790
3800
3810
3820
3830
3840
3850
3860
3870
3880
3890
3900
3910
3920
3930
3940
3950
3960
3970
3980
3990
4000
4010
4020
4030
4040
4050
4060
4070
4080
4090
4100
4110
4120
4130
4140
4150
4160
4170
4180
4190
4200
4210
4220
4230
4240
4250
4260
4270
4280
4290
4300
4310
4320
4330
4340
4350
4360
4370
4380
4390
4400
4410
4420
4430
4440
4450
4460
4470
4480
4490
4500
4510
4520
4530
4540
4550
4560
4570
4580
4590
4600
4610
4620
4630
4640
4650
4660
4670
4680
4690
4700
4710
4720
4730
4740
4750
4760
4770
4780
4790
4800
4810
4820
4830
4840
4850
4860
4870
4880
4890
4900
4910
4920
4930
4940
4950
4960
4970
4980
4990
5000
5010
5020
5030
5040
5050
5060
5070
5080
5090
5100
5110
5120
5130
5140
5150
5160
5170
5180
5190
5200
5210
5220
5230
5240
5250
5260
5270
5280
5290
5300
5310
5320
5330
5340
5350
5360
5370
5380
5390
5400
5410
5420
5430
5440
5450
5460
5470
5480
5490
5500
5510
5520
5530
5540
5550
5560
5570
5580
5590
5600
5610
5620
5630
5640
5650
5660
5670
5680
5690
5700
5710
5720
5730
5740
5750
5760
5770
5780
5790
5800
5810
5820
5830
5840
5850
5860
5870
5880
5890
5900
5910
5920
5930
5940
5950
5960
5970
5980
5990
6000
6010
6020
6030
6040
6050
6060
6070
6080
6090
6100
6110
6120
6130
6140
6150
6160
6170
6180
6190
6200
6210
6220
6230
6240
6250
6260
6270
6280
6290
6300
6310
6320
6330
6340
6350
6360
6370
6380
6390
6400
6410
6420
6430
6440
6450
6460
6470
6480
6490
6500
6510
6520
6530
6540
6550
6560
6570
6580
6590
6600
6610
6620
6630
6640
6650
6660
6670
6680
6690
6700
6710
6720
6730
6740
6750
6760
6770
6780
6790
6800
6810
6820
6830
6840
6850
6860
6870
6880
6890
6900
6910
6920
6930
6940
6950
6960
6970
6980
6990
7000
7010
7020
7030
7040
7050
7060
7070
7080
7090
7100
7110
7120
7130
7140
7150
7160
7170
7180
7190
7200
7210
7220
7230
7240
7250
7260
7270
7280
7290
7300
7310
7320
7330
7340
7350
7360
7370
7380
7390
7400
7410
7420
7430
7440
7450
7460
7470
7480
7490
7500
7510
7520
7530
75472
7550
7560
7570
7580
7590
7600
7610
7620
76316
7640
7650
7660
7670
7680
7690
7700
7710
7720
7730
7740
7750
7760
7770
7780
7790
7800
7810
7820
/** Definition of the core event driver interface. This module contains all declarations necessary for defining and using event drivers. Event driver implementations will usually inherit from `EventDriver` using a `final` class to avoid virtual function overhead. Callback_Behavior: All callbacks follow the same rules to enable generic implementation of high-level libraries, such as vibe.d. Except for "listen" style callbacks, each callback will only ever be called at most once. If the operation does not get canceled, the callback will be called exactly once. In case it gets manually canceled using the corresponding API function, the callback is guaranteed to not be called. However, the associated operation might still finish - either before the cancellation function returns, or afterwards. */ module eventcore.driver; @safe: /*@nogc:*/ nothrow: import core.time : Duration; import std.socket : Address; import std.stdint : intptr_t; /** Encapsulates a full event driver. This interface provides access to the individual driver features, as well as a central `dispose` method that must be called before the driver gets destroyed or before the process gets terminated. */ interface EventDriver { @safe: /*@nogc:*/ nothrow: /// Core event loop functionality @property inout(EventDriverCore) core() inout; /// Core event loop functionality @property shared(inout(EventDriverCore)) core() shared inout; /// Single shot and recurring timers @property inout(EventDriverTimers) timers() inout; /// Cross-thread events (thread local access) @property inout(EventDriverEvents) events() inout; /// Cross-thread events (cross-thread access) @property shared(inout(EventDriverEvents)) events() shared inout; /// UNIX/POSIX signal reception @property inout(EventDriverSignals) signals() inout; /// Stream and datagram sockets @property inout(EventDriverSockets) sockets() inout; /// DNS queries @property inout(EventDriverDNS) dns() inout; /// Local file operations @property inout(EventDriverFiles) files() inout; /// Directory change watching @property inout(EventDriverWatchers) watchers() inout; /// Releases all resources associated with the driver void dispose(); } /** Provides generic event loop control. */ interface EventDriverCore { @safe: /*@nogc:*/ nothrow: /** The number of pending callbacks. When this number drops to zero, the event loop can safely be quit. It is guaranteed that no callbacks will be made anymore, unless new callbacks get registered. */ size_t waiterCount(); /** Runs the event loop to process a chunk of events. This method optionally waits for an event to arrive if none are present in the event queue. The function will return after either the specified timeout has elapsed, or once the event queue has been fully emptied. Params: timeout = Maximum amount of time to wait for an event. A duration of zero will cause the function to only process pending events. A duration of `Duration.max`, if necessary, will wait indefinitely until an event arrives. */ ExitReason processEvents(Duration timeout); /** Causes `processEvents` to return with `ExitReason.exited` as soon as possible. A call to `processEvents` that is currently in progress will be notified so that it returns immediately. If no call is in progress, the next call to `processEvents` will immediately return with `ExitReason.exited`. */ void exit(); /** Resets the exit flag. `processEvents` will automatically reset the exit flag before it returns with `ExitReason.exited`. However, if `exit` is called outside of `processEvents`, the next call to `processEvents` will return with `ExitCode.exited` immediately. This function can be used to avoid this. */ void clearExitFlag(); /** Executes a callback in the thread owning the driver. */ void runInOwnerThread(ThreadCallback del, intptr_t param) shared; /// Low-level user data access. Use `getUserData` instead. protected void* rawUserData(StreamSocketFD descriptor, size_t size, DataInitializer initialize, DataInitializer destroy) @system; /// ditto protected void* rawUserData(DatagramSocketFD descriptor, size_t size, DataInitializer initialize, DataInitializer destroy) @system; /** Deprecated - use `EventDriverSockets.userData` instead. */ deprecated("Use `EventDriverSockets.userData` instead.") @property final ref T userData(T, FD)(FD descriptor) @trusted { import std.conv : emplace; static void init(void* ptr) { emplace(cast(T*)ptr); } static void destr(void* ptr) { destroy(*cast(T*)ptr); } return *cast(T*)rawUserData(descriptor, T.sizeof, &init, &destr); } } /** Provides access to socket functionality. The interface supports two classes of sockets - stream sockets and datagram sockets. */ interface EventDriverSockets { @safe: /*@nogc:*/ nothrow: /** Connects to a stream listening socket. */ StreamSocketFD connectStream(scope Address peer_address, scope Address bind_address, ConnectCallback on_connect); /** Aborts asynchronous connect by closing the socket. This function may only invoked if the connection state is `ConnectionState.connecting`. It will cancel the connection attempt and guarantees that the connection callback will not be invoked in the future. Note that upon completion, the socket handle will be invalid, regardless of the number of calls to `addRef`, and must not be used for further operations. Params: sock = Handle of the socket that is currently establishing a connection */ void cancelConnectStream(StreamSocketFD sock); /** Adopts an existing stream socket. The given socket must be in a connected state. It will be automatically switched to non-blocking mode if necessary. Beware that this may have side effects in other code that uses the socket and assumes blocking operations. Params: socket = Socket file descriptor to adopt Returns: Returns a socket handle corresponding to the passed socket descriptor. If the same file descriptor is already registered, `StreamSocketFD.invalid` will be returned instead. */ StreamSocketFD adoptStream(int socket); /// Creates a socket listening for incoming stream connections. StreamListenSocketFD listenStream(scope Address bind_address, StreamListenOptions options, AcceptCallback on_accept); final StreamListenSocketFD listenStream(scope Address bind_address, AcceptCallback on_accept) { return listenStream(bind_address, StreamListenOptions.defaults, on_accept); } /// Starts to wait for incoming connections on a listening socket. void waitForConnections(StreamListenSocketFD sock, AcceptCallback on_accept); /// Determines the current connection state. ConnectionState getConnectionState(StreamSocketFD sock); /** Retrieves the bind address of a socket. Example: The following code can be used to retrieve an IPv4/IPv6 address allocated on the stack. Note that Unix domain sockets require a larger buffer (e.g. `sockaddr_storage`). --- scope storage = new UnknownAddress; scope sockaddr = new RefAddress(storage.name, storage.nameLen); eventDriver.sockets.getLocalAddress(sock, sockaddr); --- */ bool getLocalAddress(SocketFD sock, scope RefAddress dst); /** Retrieves the address of the connected peer. Example: The following code can be used to retrieve an IPv4/IPv6 address allocated on the stack. Note that Unix domain sockets require a larger buffer (e.g. `sockaddr_storage`). --- scope storage = new UnknownAddress; scope sockaddr = new RefAddress(storage.name, storage.nameLen); eventDriver.sockets.getLocalAddress(sock, sockaddr); --- */ bool getRemoteAddress(SocketFD sock, scope RefAddress dst); /// Sets the `TCP_NODELAY` option on a socket void setTCPNoDelay(StreamSocketFD socket, bool enable); /// Sets to `SO_KEEPALIVE` socket option on a socket. void setKeepAlive(StreamSocketFD socket, bool enable); /** Reads data from a stream socket. Note that only a single read operation is allowed at once. The caller needs to make sure that either `on_read_finish` got called, or `cancelRead` was called before issuing the next call to `read`. However, concurrent writes are legal. Waiting_for_data_availability: With the special combination of a zero-length buffer and `mode` set to either `IOMode.once` or `IOMode.all`, this function will wait until data is available on the socket without reading anything. Note that in this case the `IOStatus` parameter of the callback will not reliably reflect a passive connection close. It is necessary to actually read some data to make sure this case is detected. */ void read(StreamSocketFD socket, ubyte[] buffer, IOMode mode, IOCallback on_read_finish); /** Cancels an ongoing read operation. After this function has been called, the `IOCallback` specified in the call to `read` is guaranteed to not be called. */ void cancelRead(StreamSocketFD socket); /** Reads data from a stream socket. Note that only a single write operation is allowed at once. The caller needs to make sure that either `on_write_finish` got called, or `cancelWrite` was called before issuing the next call to `write`. However, concurrent reads are legal. */ void write(StreamSocketFD socket, const(ubyte)[] buffer, IOMode mode, IOCallback on_write_finish); /** Cancels an ongoing write operation. After this function has been called, the `IOCallback` specified in the call to `write` is guaranteed to not be called. */ void cancelWrite(StreamSocketFD socket); /** Waits for incoming data without actually reading it. */ void waitForData(StreamSocketFD socket, IOCallback on_data_available); /** Initiates a connection close. */ void shutdown(StreamSocketFD socket, bool shut_read, bool shut_write); /** Creates a connection-less datagram socket. Params: bind_address = The local bind address to use for the socket. It will be able to receive any messages sent to this address. target_address = Optional default target address. If this is specified and the target address parameter of `send` is left to `null`, it will be used instead. Returns: Returns a datagram socket handle if the socket was created successfully. Otherwise returns `DatagramSocketFD.invalid`. */ DatagramSocketFD createDatagramSocket(scope Address bind_address, scope Address target_address); /** Adopts an existing datagram socket. The socket must be properly bound before this function is called. Params: socket = Socket file descriptor to adopt Returns: Returns a socket handle corresponding to the passed socket descriptor. If the same file descriptor is already registered, `DatagramSocketFD.invalid` will be returned instead. */ DatagramSocketFD adoptDatagramSocket(int socket); /** Sets an address to use as the default target address for sent datagrams. */ void setTargetAddress(DatagramSocketFD socket, scope Address target_address); /// Sets the `SO_BROADCAST` socket option. bool setBroadcast(DatagramSocketFD socket, bool enable); /// Joins the multicast group associated with the given IP address. bool joinMulticastGroup(DatagramSocketFD socket, scope Address multicast_address, uint interface_index = 0); /// Receives a single datagram. void receive(DatagramSocketFD socket, ubyte[] buffer, IOMode mode, DatagramIOCallback on_receive_finish); /// Cancels an ongoing wait for an incoming datagram. void cancelReceive(DatagramSocketFD socket); /// Sends a single datagram. void send(DatagramSocketFD socket, const(ubyte)[] buffer, IOMode mode, Address target_address, DatagramIOCallback on_send_finish); /// Cancels an ongoing wait for an outgoing datagram. void cancelSend(DatagramSocketFD socket); /** Increments the reference count of the given socket. */ void addRef(SocketFD descriptor); /** Decrements the reference count of the given socket. Once the reference count reaches zero, all associated resources will be freed and the resource descriptor gets invalidated. Returns: Returns `false` $(I iff) the last reference was removed by this call. */ bool releaseRef(SocketFD descriptor); /** Enables or disables a socket option. */ bool setOption(DatagramSocketFD socket, DatagramSocketOption option, bool enable); /// ditto bool setOption(StreamSocketFD socket, StreamSocketOption option, bool enable); /** Retrieves a reference to a user-defined value associated with a descriptor. */ @property final ref T userData(T, FD)(FD descriptor) @trusted { import std.conv : emplace; static void init(void* ptr) { emplace(cast(T*)ptr); } static void destr(void* ptr) { destroy(*cast(T*)ptr); } return *cast(T*)rawUserData(descriptor, T.sizeof, &init, &destr); } /// Low-level user data access. Use `getUserData` instead. protected void* rawUserData(StreamSocketFD descriptor, size_t size, DataInitializer initialize, DataInitializer destroy) @system; /// ditto protected void* rawUserData(StreamListenSocketFD descriptor, size_t size, DataInitializer initialize, DataInitializer destroy) @system; /// ditto protected void* rawUserData(DatagramSocketFD descriptor, size_t size, DataInitializer initialize, DataInitializer destroy) @system; } /** Performs asynchronous DNS queries. */ interface EventDriverDNS { @safe: /*@nogc:*/ nothrow: /// Looks up addresses corresponding to the given DNS name. DNSLookupID lookupHost(string name, DNSLookupCallback on_lookup_finished); /// Cancels an ongoing DNS lookup. void cancelLookup(DNSLookupID handle); } /** Provides read/write operations on the local file system. */ interface EventDriverFiles { @safe: /*@nogc:*/ nothrow: FileFD open(string path, FileOpenMode mode); FileFD adopt(int system_file_handle); /** Disallows any reads/writes and removes any exclusive locks. Note that this function may not actually close the file handle. The handle is only guaranteed to be closed one the reference count drops to zero. However, the remaining effects of calling this function will be similar to actually closing the file. */ void close(FileFD file); ulong getSize(FileFD file); void write(FileFD file, ulong offset, const(ubyte)[] buffer, IOMode mode, FileIOCallback on_write_finish); void read(FileFD file, ulong offset, ubyte[] buffer, IOMode mode, FileIOCallback on_read_finish); void cancelWrite(FileFD file); void cancelRead(FileFD file); /** Increments the reference count of the given file. */ void addRef(FileFD descriptor); /** Decrements the reference count of the given file. Once the reference count reaches zero, all associated resources will be freed and the resource descriptor gets invalidated. Returns: Returns `false` $(I iff) the last reference was removed by this call. */ bool releaseRef(FileFD descriptor); /** Retrieves a reference to a user-defined value associated with a descriptor. */ @property final ref T userData(T)(FileFD descriptor) @trusted { import std.conv : emplace; static void init(void* ptr) { emplace(cast(T*)ptr); } static void destr(void* ptr) { destroy(*cast(T*)ptr); } return *cast(T*)rawUserData(descriptor, T.sizeof, &init, &destr); } /// Low-level user data access. Use `userData` instead. protected void* rawUserData(FileFD descriptor, size_t size, DataInitializer initialize, DataInitializer destroy) @system; } /** Cross-thread notifications "Events" can be used to wake up the event loop of a foreign thread. This is the basis for all kinds of thread synchronization primitives, such as mutexes, condition variables, message queues etc. Such primitives, in case of extended wait periods, should use events rather than traditional means to block, such as busy loops or kernel based wait mechanisms to avoid stalling the event loop. */ interface EventDriverEvents { @safe: /*@nogc:*/ nothrow: /// Creates a new cross-thread event. EventID create(); /// Triggers an event owned by the current thread. void trigger(EventID event, bool notify_all); /// Triggers an event possibly owned by a different thread. void trigger(EventID event, bool notify_all) shared; /** Waits until an event gets triggered. Multiple concurrent waits are allowed. */ void wait(EventID event, EventCallback on_event); /// Cancels an ongoing wait operation. void cancelWait(EventID event, EventCallback on_event); /** Increments the reference count of the given event. */ void addRef(EventID descriptor); /** Decrements the reference count of the given event. Once the reference count reaches zero, all associated resources will be freed and the resource descriptor gets invalidated. Returns: Returns `false` $(I iff) the last reference was removed by this call. */ bool releaseRef(EventID descriptor); /** Retrieves a reference to a user-defined value associated with a descriptor. */ @property final ref T userData(T)(EventID descriptor) @trusted { import std.conv : emplace; static void init(void* ptr) { emplace(cast(T*)ptr); } static void destr(void* ptr) { destroy(*cast(T*)ptr); } return *cast(T*)rawUserData(descriptor, T.sizeof, &init, &destr); } /// Low-level user data access. Use `userData` instead. protected void* rawUserData(EventID descriptor, size_t size, DataInitializer initialize, DataInitializer destroy) @system; } /** Handling of POSIX signals. */ interface EventDriverSignals { @safe: /*@nogc:*/ nothrow: /** Starts listening for the specified POSIX signal. Note that if a default signal handler exists for the signal, it will be disabled by using this function. Params: sig = The number of the signal to listen for on_signal = Callback that gets called whenever a matching signal gets received Returns: Returns an identifier that identifies the resource associated with the signal. Giving up ownership of this resource using `releaseRef` will re-enable the default signal handler, if any was present. For any error condition, `SignalListenID.invalid` will be returned instead. */ SignalListenID listen(int sig, SignalCallback on_signal); /** Increments the reference count of the given resource. */ void addRef(SignalListenID descriptor); /** Decrements the reference count of the given resource. Once the reference count reaches zero, all associated resources will be freed and the resource descriptor gets invalidated. Returns: Returns `false` $(I iff) the last reference was removed by this call. */ bool releaseRef(SignalListenID descriptor); } interface EventDriverTimers { @safe: /*@nogc:*/ nothrow: TimerID create(); void set(TimerID timer, Duration timeout, Duration repeat); void stop(TimerID timer); bool isPending(TimerID timer); bool isPeriodic(TimerID timer); void wait(TimerID timer, TimerCallback callback); void cancelWait(TimerID timer); /** Increments the reference count of the given resource. */ void addRef(TimerID descriptor); /** Decrements the reference count of the given resource. Once the reference count reaches zero, all associated resources will be freed and the resource descriptor gets invalidated. Returns: Returns `false` $(I iff) the last reference was removed by this call. */ bool releaseRef(TimerID descriptor); /// Determines if the given timer's reference count equals one. bool isUnique(TimerID descriptor) const; /** Retrieves a reference to a user-defined value associated with a descriptor. */ @property final ref T userData(T)(TimerID descriptor) @trusted { import std.conv : emplace; static void init(void* ptr) { emplace(cast(T*)ptr); } static void destr(void* ptr) { destroy(*cast(T*)ptr); } return *cast(T*)rawUserData(descriptor, T.sizeof, &init, &destr); } /// Low-level user data access. Use `userData` instead. protected void* rawUserData(TimerID descriptor, size_t size, DataInitializer initialize, DataInitializer destroy) @system; } interface EventDriverWatchers { @safe: /*@nogc:*/ nothrow: /// Watches a directory or a directory sub tree for changes. WatcherID watchDirectory(string path, bool recursive, FileChangesCallback callback); /** Increments the reference count of the given resource. */ void addRef(WatcherID descriptor); /** Decrements the reference count of the given resource. Once the reference count reaches zero, all associated resources will be freed and the resource descriptor gets invalidated. Returns: Returns `false` $(I iff) the last reference was removed by this call. */ bool releaseRef(WatcherID descriptor); /** Retrieves a reference to a user-defined value associated with a descriptor. */ @property final ref T userData(T)(WatcherID descriptor) @trusted { import std.conv : emplace; static void init(void* ptr) { emplace(cast(T*)ptr); } static void destr(void* ptr) { destroy(*cast(T*)ptr); } return *cast(T*)rawUserData(descriptor, T.sizeof, &init, &destr); } /// Low-level user data access. Use `userData` instead. protected void* rawUserData(WatcherID descriptor, size_t size, DataInitializer initialize, DataInitializer destroy) @system; } // Helper class to enable fully stack allocated `std.socket.Address` instances. final class RefAddress : Address { version (Posix) import core.sys.posix.sys.socket : sockaddr, socklen_t; version (Windows) import core.sys.windows.winsock2 : sockaddr, socklen_t; private { sockaddr* m_addr; socklen_t m_addrLen; } this() @safe nothrow {} this(sockaddr* addr, socklen_t addr_len) @safe nothrow { set(addr, addr_len); } override @property sockaddr* name() { return m_addr; } override @property const(sockaddr)* name() const { return m_addr; } override @property socklen_t nameLen() const { return m_addrLen; } void set(sockaddr* addr, socklen_t addr_len) @safe nothrow { m_addr = addr; m_addrLen = addr_len; } void cap(socklen_t new_len) @safe nothrow { assert(new_len <= m_addrLen, "Cannot grow size of a RefAddress."); m_addrLen = new_len; } } alias ConnectCallback = void delegate(StreamSocketFD, ConnectStatus); alias AcceptCallback = void delegate(StreamListenSocketFD, StreamSocketFD, scope RefAddress remote_address); alias IOCallback = void delegate(StreamSocketFD, IOStatus, size_t); alias DatagramIOCallback = void delegate(DatagramSocketFD, IOStatus, size_t, scope RefAddress); alias DNSLookupCallback = void delegate(DNSLookupID, DNSStatus, scope RefAddress[]); alias FileIOCallback = void delegate(FileFD, IOStatus, size_t); alias EventCallback = void delegate(EventID); alias SignalCallback = void delegate(SignalListenID, SignalStatus, int); alias TimerCallback = void delegate(TimerID); alias FileChangesCallback = void delegate(WatcherID, in ref FileChange change); @system alias DataInitializer = void function(void*); enum ExitReason { timeout, idle, outOfWaiters, exited } enum ConnectStatus { connected, refused, timeout, bindFailure, socketCreateFailure, unknownError } enum ConnectionState { initialized, connecting, connected, passiveClose, activeClose, closed } enum StreamListenOptions { defaults = 0, reusePort = 1<<0, } enum StreamSocketOption { noDelay, keepAlive } enum DatagramSocketOption { broadcast, multicastLoopback } /** Specifies how a file is manipulated on disk. */ enum FileOpenMode { /// The file is opened read-only. read, /// The file is opened for read-write random access. readWrite, /// The file is truncated if it exists or created otherwise and then opened for read-write access. createTrunc, /// The file is opened for appending data to it and created if it does not exist. append } enum IOMode { immediate, /// Process only as much as possible without waiting once, /// Process as much as possible with a single call all /// Process the full buffer } enum IOStatus { ok, /// The data has been transferred normally disconnected, /// The connection was closed before all data could be transterred error, /// An error occured while transferring the data wouldBlock /// Returned for `IOMode.immediate` when no data is readily readable/writable } enum DNSStatus { ok, error } /** Specifies the kind of change in a watched directory. */ enum FileChangeKind { /// A file or directory was added added, /// A file or directory was deleted removed, /// A file or directory was modified modified } enum SignalStatus { ok, error } /** Describes a single change in a watched directory. */ struct FileChange { /// The type of change FileChangeKind kind; /// The root directory of the watcher string baseDirectory; /// Subdirectory containing the changed file string directory; /// Name of the changed file const(char)[] name; /** Determines if the changed entity is a file or a directory. Note that depending on the platform this may not be accurate for `FileChangeKind.removed`. */ bool isDirectory; } struct Handle(string NAME, T, T invalid_value = T.init) { import std.traits : isInstanceOf; static if (isInstanceOf!(.Handle, T)) alias BaseType = T.BaseType; else alias BaseType = T; alias name = NAME; enum invalid = Handle.init; T value = invalid_value; this(BaseType value) { this.value = T(value); } U opCast(U : Handle!(V, M), V, int M)() { // TODO: verify that U derives from typeof(this)! return U(value); } U opCast(U : BaseType)() { return cast(U)value; } alias value this; } alias ThreadCallback = void function(intptr_t param) @safe nothrow; alias FD = Handle!("fd", size_t, size_t.max); alias SocketFD = Handle!("socket", FD); alias StreamSocketFD = Handle!("streamSocket", SocketFD); alias StreamListenSocketFD = Handle!("streamListen", SocketFD); alias DatagramSocketFD = Handle!("datagramSocket", SocketFD); alias FileFD = Handle!("file", FD); alias EventID = Handle!("event", FD); alias TimerID = Handle!("timer", size_t, size_t.max); alias WatcherID = Handle!("watcher", size_t, size_t.max); alias EventWaitID = Handle!("eventWait", size_t, size_t.max); alias SignalListenID = Handle!("signal", size_t, size_t.max); alias DNSLookupID = Handle!("dns", size_t, size_t.max);