00001 /******************************************************************************* 00002 00003 @file IConduit.d 00004 00005 Copyright (c) 2004 Kris Bell 00006 00007 This software is provided 'as-is', without any express or implied 00008 warranty. In no event will the authors be held liable for damages 00009 of any kind arising from the use of this software. 00010 00011 Permission is hereby granted to anyone to use this software for any 00012 purpose, including commercial applications, and to alter it and/or 00013 redistribute it freely, subject to the following restrictions: 00014 00015 1. The origin of this software must not be misrepresented; you must 00016 not claim that you wrote the original software. If you use this 00017 software in a product, an acknowledgment within documentation of 00018 said product would be appreciated but is not required. 00019 00020 2. Altered source versions must be plainly marked as such, and must 00021 not be misrepresented as being the original software. 00022 00023 3. This notice may not be removed or altered from any distribution 00024 of the source. 00025 00026 4. Derivative works are permitted, but they must carry this notice 00027 in full and credit the original source. 00028 00029 00030 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 00031 00032 00033 @version Initial version, March 2004 00034 @author Kris 00035 00036 00037 *******************************************************************************/ 00038 00039 module mango.io.model.IConduit; 00040 00041 /******************************************************************************* 00042 00043 Conduits provide virtualized access to external content, and 00044 represent things like files or Internet connections. Conduits 00045 are modelled by mango.io.model.IConduit, and implemented via 00046 classes FileConduit and SocketConduit. 00047 00048 Additional kinds of conduit are easy to construct: one either 00049 subclasses mango.io.Conduit, or implements mango.io.model.IConduit. 00050 A conduit typically reads and writes from/to an IBuffer in large 00051 chunks, typically the entire buffer. Alternatively, one can invoke 00052 read(dst[]) and/or write(src[]) directly. 00053 00054 *******************************************************************************/ 00055 00056 interface IConduit 00057 { 00058 /*********************************************************************** 00059 00060 Declare the End Of File identifer 00061 00062 ***********************************************************************/ 00063 00064 enum {Eof = uint.max}; 00065 00066 /*********************************************************************** 00067 00068 read from conduit into a target array 00069 00070 ***********************************************************************/ 00071 00072 abstract uint read (void[] dst); 00073 00074 /*********************************************************************** 00075 00076 write to conduit from a source array 00077 00078 ***********************************************************************/ 00079 00080 abstract uint write (void[] src); 00081 00082 /*********************************************************************** 00083 00084 flush provided content to the conduit 00085 00086 ***********************************************************************/ 00087 00088 abstract bool flush (void[] src); 00089 00090 /*********************************************************************** 00091 00092 Transfer the content of this conduit to another one. 00093 Returns true if all content was successfully copied. 00094 00095 ***********************************************************************/ 00096 00097 abstract IConduit copy (IConduit source); 00098 00099 /*********************************************************************** 00100 00101 Attach a filter to this conduit: see IConduitFilter 00102 00103 ***********************************************************************/ 00104 00105 abstract void attach (IConduitFilter filter); 00106 00107 /*********************************************************************** 00108 00109 Return a preferred size for buffering conduit I/O 00110 00111 ***********************************************************************/ 00112 00113 abstract uint bufferSize (); 00114 00115 /*********************************************************************** 00116 00117 Returns true is this conduit can be read from 00118 00119 ***********************************************************************/ 00120 00121 abstract bool isReadable (); 00122 00123 /*********************************************************************** 00124 00125 Returns true if this conduit can be written to 00126 00127 ***********************************************************************/ 00128 00129 abstract bool isWritable (); 00130 00131 /*********************************************************************** 00132 00133 Returns true if this conduit is seekable (whether it 00134 implements ISeekable) 00135 00136 ***********************************************************************/ 00137 00138 abstract bool isSeekable (); 00139 00140 /*********************************************************************** 00141 00142 Returns true if this conduit is text-based 00143 00144 ***********************************************************************/ 00145 00146 bool isTextual (); 00147 00148 /*********************************************************************** 00149 00150 Release external resources 00151 00152 ***********************************************************************/ 00153 00154 abstract void close (); 00155 } 00156 00157 00158 /******************************************************************************* 00159 00160 Define a conduit filter base-class. The filter is invoked 00161 via its reader() method whenever a block of content is 00162 being read, and by its writer() method whenever content is 00163 being written. 00164 00165 The filter should return the number of bytes it has actually 00166 produced: less than or equal to the length of the provided 00167 array. 00168 00169 Filters are chained together such that the last filter added 00170 is the first one invoked. It is the responsibility of each 00171 filter to invoke the next link in the chain; for example: 00172 00173 @code 00174 class MungingFilter : ConduitFilter 00175 { 00176 int reader (void[] dst) 00177 { 00178 // read the next X bytes 00179 int count = next.reader (dst); 00180 00181 // set everything to '*' ! 00182 dst[0..count] = '*'; 00183 00184 // say how many we read 00185 return count; 00186 } 00187 00188 int writer (void[] src) 00189 { 00190 byte[] tmp = new byte[src.length]; 00191 00192 // set everything to '*' 00193 tmp = '*'; 00194 00195 // write the munged output 00196 return next.writer (tmp); 00197 } 00198 } 00199 @endcode 00200 00201 Notice how this filter invokes the 'next' instance before 00202 munging the content ... the far end of the chain is where 00203 the original IConduit reader is attached, so it will get 00204 invoked eventually assuming each filter invokes 'next'. 00205 If the next reader fails it will return IConduit.Eof, as 00206 should your filter (or throw an IOException). From a client 00207 perspective, filters are attached like this: 00208 00209 @code 00210 FileConduit fc = new FileConduit (...); 00211 00212 fc.attach (new ZipFilter); 00213 fc.attach (new MungingFilter); 00214 @endcode 00215 00216 Again, the last filter attached is the first one invoked 00217 when a block of content is actually read. Each filter has 00218 two additional methods that it may use to control behavior: 00219 00220 @code 00221 class ConduitFilter : IConduitFilter 00222 { 00223 protected IConduitFilter next; 00224 00225 void bind (IConduit conduit, IConduitFilter next) 00226 { 00227 this.next = next; 00228 } 00229 00230 void unbind () 00231 { 00232 } 00233 } 00234 @endcode 00235 00236 The first method is invoked when the filter is attached to a 00237 conduit, while the second is invoked just before the conduit 00238 is closed. Both of these may be overridden by the filter for 00239 whatever purpose desired. 00240 00241 Note that a conduit filter can choose to sidestep reading from 00242 the conduit (per the usual case), and produce its input from 00243 somewhere else entirely. This mechanism supports the notion 00244 of 'piping' between multiple conduits, or between a conduit 00245 and something else entirely; it's a bridging mechanism. 00246 00247 *******************************************************************************/ 00248 00249 interface IConduitFilter 00250 { 00251 /*********************************************************************** 00252 00253 filter-specific reader 00254 00255 ***********************************************************************/ 00256 00257 abstract uint reader (void[] dst); 00258 00259 /*********************************************************************** 00260 00261 filter-specific writer 00262 00263 ***********************************************************************/ 00264 00265 abstract uint writer (void[] dst); 00266 00267 /*********************************************************************** 00268 00269 ***********************************************************************/ 00270 00271 abstract void bind (IConduit conduit, IConduitFilter next); 00272 00273 /*********************************************************************** 00274 00275 ***********************************************************************/ 00276 00277 abstract void unbind (); 00278 } 00279 00280 00281 /******************************************************************************* 00282 00283 Models the ability to seek within a conduit. 00284 00285 *******************************************************************************/ 00286 00287 interface ISeekable 00288 { 00289 /*********************************************************************** 00290 00291 The anchor positions supported by ISeekable 00292 00293 ***********************************************************************/ 00294 00295 enum SeekAnchor { 00296 Begin = 0, 00297 Current = 1, 00298 End = 2, 00299 }; 00300 00301 /*********************************************************************** 00302 00303 Return the current conduit position (such as file position) 00304 00305 ***********************************************************************/ 00306 00307 abstract ulong getPosition (); 00308 00309 /*********************************************************************** 00310 00311 Move the file position to the given offset from the provided 00312 anchor point, and return the adjusted position. 00313 00314 ***********************************************************************/ 00315 00316 abstract ulong seek (ulong offset, SeekAnchor anchor=SeekAnchor.Begin); 00317 } 00318 00319 00320 /******************************************************************************* 00321 00322 Defines how a Conduit should be opened. This is typically subsumed 00323 by another structure 00324 00325 *******************************************************************************/ 00326 00327 struct ConduitStyle 00328 { 00329 align(1): 00330 00331 struct Bits 00332 { 00333 Access access; // access rights 00334 } 00335 00336 /*********************************************************************** 00337 00338 ***********************************************************************/ 00339 00340 enum Access : ubyte { 00341 Read = 0x01, // is readable 00342 Write = 0x02, // is writable 00343 ReadWrite = 0x03, // both 00344 Mask = 0x7f, // ignore Text flag! 00345 Text = 0x80, 00346 }; 00347 00348 /*********************************************************************** 00349 00350 Setup common instances of conduit styles 00351 00352 ***********************************************************************/ 00353 00354 const Bits Read = {Access.Read}; 00355 const Bits Write = {Access.Write}; 00356 const Bits ReadWrite = {Access.ReadWrite}; 00357 00358 const Bits ReadText = {Access.Read + Access.Text}; 00359 const Bits WriteText = {Access.Write + Access.Text}; 00360 const Bits ReadWriteText = {Access.ReadWrite + Access.Text}; 00361 } 00362 00363