1 /******************************************************************************
2 
3     Simple POSIX I/O device interfaces and base classes, significantly
4     influenced by Tango's Conduit.
5 
6     An input device is merely an ISelectable (a file descriptor) with a read()
7     method and an output an ISelectable device wih a write() method. read() and
8     write() wrap the POSIX function with the same name.
9 
10     Copyright:
11         Copyright (c) 2009-2016 dunnhumby Germany GmbH.
12         All rights reserved.
13 
14     License:
15         Boost Software License Version 1.0. See LICENSE_BOOST.txt for details.
16         Alternatively, this file may be distributed under the terms of the Tango
17         3-Clause BSD License (see LICENSE_BSD.txt for details).
18 
19  ******************************************************************************/
20 
21 module ocean.io.device.IODevice;
22 
23 
24 import ocean.meta.types.Qualifiers;
25 
26 import ocean.io.model.IConduit: ISelectable;
27 
28 import core.sys.posix.unistd: read, write;
29 import core.sys.posix.sys.types: ssize_t;
30 
31 /******************************************************************************
32 
33     Input device interface
34 
35  ******************************************************************************/
36 
37 interface IInputDevice : ISelectable
38 {
39     /**************************************************************************
40 
41         Convenience type alias for subclasses/interfaces
42 
43      **************************************************************************/
44 
45     alias .ssize_t ssize_t;
46 
47     /**************************************************************************
48 
49         read()  attempts  to  read  up  to  dst.length  bytes  from  the  device
50         associated with the file descriptor of this instance into dst.
51 
52         If dst.length is zero, read() returns zero and has no other results.  If
53         count is greater than SSIZE_MAX, the result is unspecified.
54 
55         Params:
56             dst = destination buffer
57 
58         Returns:
59             On success, the number of bytes read is returned (zero indicates end
60             of file), and the file position is advanced by this number.   It  is
61             not  an  error  if  this  number is smaller than the number of bytes
62             requested; this may happen for example because fewer bytes are actu‐
63             ally  available  right  now  (maybe because we were close to end-of-
64             file, or because we are reading from a pipe, or from a terminal), or
65             because  read()  was  interrupted  by  a  signal.   On  error, -1 is
66             returned, and errno is set appropriately.  In this case it  is  left
67             unspecified whether the file position (if any) changes.
68 
69         Errors:
70 
71             EAGAIN The  file  descriptor fd refers to a file other than a socket
72                    and has been marked nonblocking (O_NONBLOCK),  and  the  read
73                    would block.
74 
75             EAGAIN or EWOULDBLOCK
76                    The file descriptor fd refers to a socket and has been marked
77                    nonblocking  (O_NONBLOCK),  and   the   read   would   block.
78                    POSIX.1-2001  allows  either  error  to  be returned for this
79                    case, and does not require these constants to have  the  same
80                    value, so a portable application should check for both possi‐
81                    bilities.
82 
83             EBADF  fd is not a valid file descriptor or is not open for reading.
84 
85             EFAULT dst is outside your accessible address space.
86 
87             EINTR  The call was interrupted by a  signal  before  any  data  was
88                    read; see signal(7).
89 
90             EINVAL fd  is attached to an object which is unsuitable for reading;
91                    or the file was opened with the O_DIRECT flag, and either the
92                    address  specified  in  dst, the value specified in count, or
93                    the current file offset is not suitably aligned.
94 
95             EINVAL fd was created via a call to timerfd_create(2) and the  wrong
96                    size  buffer  was  given to read(); see timerfd_create(2) for
97                    further information.
98 
99             EIO    I/O error.  This will happen for example when the process  is
100                    in  a  background  process group, tries to read from its con‐
101                    trolling tty, and either it is ignoring or  blocking  SIGTTIN
102                    or  its  process  group  is orphaned.  It may also occur when
103                    there is a low-level I/O error while reading from a  disk  or
104                    tape.
105 
106             EISDIR fd refers to a directory.
107 
108             Other  errors  may  occur,  depending on the object connected to fd.
109             POSIX allows a read() that is interrupted after reading some data to
110             return -1 (with errno set to EINTR) or to return the number of bytes
111             already read.
112 
113      **************************************************************************/
114 
115     ssize_t read ( void[] dst );
116 }
117 
118 /******************************************************************************
119 
120     Output device interface
121 
122  ******************************************************************************/
123 
124 interface IOutputDevice : ISelectable
125 {
126     /**************************************************************************
127 
128         Convenience type alias for subclasses/interfaces
129 
130      **************************************************************************/
131 
132     alias .ssize_t ssize_t;
133 
134     /**************************************************************************
135 
136         write() writes up to count bytes from the buffer pointed buf to the file
137         referred to by the file descriptor fd.
138 
139         The number of bytes written may be less  than  count  if,  for  example,
140         there  is  insufficient  space on the underlying physical medium, or the
141         RLIMIT_FSIZE resource limit is encountered (see  setrlimit(2)),  or  the
142         call  was interrupted by a signal handler after having written less than
143         count bytes.  (See also pipe(7).)
144 
145         For a seekable file (i.e., one to which lseek(2)  may  be  applied,  for
146         example, a regular file) writing takes place at the current file offset,
147         and the file offset is incremented by the number of bytes actually writ‐
148         ten.   If the file was open(2)ed with O_APPEND, the file offset is first
149         set to the end of the file before writing.  The adjustment of  the  file
150         offset and the write operation are performed as an atomic step.
151 
152         POSIX  requires  that  a  read(2)  which  can be proved to occur after a
153         write() has returned returns the new data.  Note that not all file  sys‐
154         tems are POSIX conforming.
155 
156         Returns:
157             On success, the number of bytes written is returned (zero  indicates
158             nothing  was  written).   On error, -1 is returned, and errno is set
159             appropriately.
160 
161             If count is zero and fd refers to a regular file, then  write()  may
162             return  a failure status if one of the errors below is detected.  If
163             no errors are detected, 0 will be returned without causing any other
164             effect.  If count is zero and fd refers to a file other than a regu‐
165             lar file, the results are not specified.
166 
167 
168             write()  writes up to count bytes from the buffer pointed buf to the
169             file referred to by the file descriptor fd.
170 
171             The number of bytes written may be less than count if, for  example,
172             there  is  insufficient  space on the underlying physical medium, or
173             the RLIMIT_FSIZE resource limit is encountered  (see  setrlimit(2)),
174             or the call was interrupted by a signal handler after having written
175             less than count bytes.  (See also pipe(7).)
176 
177             For a seekable file (i.e., one to which lseek(2) may be applied, for
178             example,  a  regular  file)  writing takes place at the current file
179             offset, and the file offset is incremented by the  number  of  bytes
180             actually written.  If the file was open(2)ed with O_APPEND, the file
181             offset is first set to the end of  the  file  before  writing.   The
182             adjustment  of the file offset and the write operation are performed
183             as an atomic step.
184 
185             POSIX requires that a read(2) which can be proved to occur  after  a
186             write()  has  returned returns the new data.  Note that not all file
187             systems are POSIX conforming.
188 
189         Errors:
190             EAGAIN The file descriptor fd refers to a file other than  a  socket
191                    and  has  been marked nonblocking (O_NONBLOCK), and the write
192                    would block.
193 
194             EAGAIN or EWOULDBLOCK
195                    The file descriptor fd refers to a socket and has been marked
196                    nonblocking   (O_NONBLOCK),   and   the  write  would  block.
197                    POSIX.1-2001 allows either error  to  be  returned  for  this
198                    case,  and  does not require these constants to have the same
199                    value, so a portable application should check for both possi‐
200                    bilities.
201 
202             EBADF  fd is not a valid file descriptor or is not open for writing.
203 
204             EDESTADDRREQ
205                    fd  refers  to a datagram socket for which a peer address has
206                    not been set using connect(2).
207 
208             EFAULT buf is outside your accessible address space.
209 
210             EFBIG  An attempt was made to write a file that exceeds  the  imple‐
211                    mentation-defined  maximum  file  size  or the process's file
212                    size limit, or to  write  at  a  position  past  the  maximum
213                    allowed offset.
214 
215             EINTR  The  call  was  interrupted  by  a signal before any data was
216                    written; see signal(7).
217 
218             EINVAL fd is attached to an object which is unsuitable for  writing;
219                    or the file was opened with the O_DIRECT flag, and either the
220                    address specified in buf, the value specified  in  count,  or
221                    the current file offset is not suitably aligned.
222 
223             EIO    A low-level I/O error occurred while modifying the inode.
224 
225             ENOSPC The  device containing the file referred to by fd has no room
226                    for the data.
227 
228             EPIPE  fd is connected to a pipe or  socket  whose  reading  end  is
229                    closed.   When  this  happens  the  writing process will also
230                    receive a SIGPIPE signal.  (Thus, the write return  value  is
231                    seen only if the program catches, blocks or ignores this sig‐
232                    nal.)
233 
234             Other errors may occur, depending on the object connected to fd.
235 
236      **************************************************************************/
237 
238     ssize_t write ( const(void)[] dst );
239 }
240 
241 /******************************************************************************
242 
243     Input device base class, may be used to conveniently implement an
244     IInputDevice.
245 
246  ******************************************************************************/
247 
248 abstract class InputDevice : IInputDevice
249 {
250     /**************************************************************************
251 
252         Attempts to read dst.length bytes, see IInputDevice.read()
253         documentation.
254 
255         Params:
256             dst = destination data buffer
257 
258         Returns
259             the number of bytes read and stored in dst on success, 0 on end-of-
260             file condition or -1 on error. On error errno is set appropriately.
261 
262      **************************************************************************/
263 
264     public ssize_t read ( void[] dst )
265     {
266         return .read(this.fileHandle(), dst.ptr, dst.length);
267     }
268 }
269 
270 /******************************************************************************
271 
272     IODevice device base class, may be used to conveniently implement an I/O
273     class that is both an IInputDevice and IOutputDevice.
274 
275  ******************************************************************************/
276 
277 abstract class IODevice : InputDevice, IOutputDevice
278 {
279     /**************************************************************************
280 
281         Attempts to write src.length bytes, see IOutputDevice.write()
282         documentation.
283 
284         Params:
285             src = source data buffer
286 
287         Returns
288             the number of bytes written on success or -1 on error. On error
289             errno is set appropriately.
290 
291      **************************************************************************/
292 
293     abstract public ssize_t write ( const(void)[] src );
294 }