00001 /******************************************************************************* 00002 00003 @file IBuffer.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.IBuffer; 00040 00041 private import mango.io.model.IConduit; 00042 00043 /******************************************************************************* 00044 00045 The basic premise behind this IO package is as follows: 00046 00047 1) the central concept is that of a buffer. The buffer acts 00048 as a queue (line) where items are removed from the front 00049 and new items are added to the back. Buffers are modeled 00050 by this interface, and mango.io.Buffer exposes a concrete 00051 implementation. 00052 00053 2) buffers can be written to directly, but a Reader and/or 00054 Writer are typically used to read & write formatted data. 00055 These readers & writers are bound to a specific buffer; 00056 often the same buffer. It's also perfectly legitimate to 00057 bind multiple writers to the same buffer; they will all 00058 behave serially as one would expect. The same applies to 00059 multiple readers on the same buffer. Readers and writers 00060 support two styles of IO: put/get, and the C++ style << 00061 and >> operators. All such operations can be chained. 00062 00063 3) Any class can be made compatable with the reader/writer 00064 framework by implementing the IReadable and/or IWritable 00065 interfaces. Each of these specify just a single method. 00066 00067 4) Buffers may also be tokenized. This is handy when one is 00068 dealing with text input, and/or the content suits a more 00069 fluid format than most typical readers & writers support. 00070 Tokens are mapped directly onto buffer content, so there 00071 is only minor overhead in using them. Tokens can be read 00072 and written by reader/writers also, using a more relaxed 00073 set of rules than those applied to integral IO. 00074 00075 5) buffers are sometimes memory-only, in which case there 00076 is nothing left to do when a reader (or tokenizer) hits 00077 end of buffer conditions. Other buffers are themselves 00078 bound to a Conduit. When this is the case, a reader will 00079 eventually cause the buffer to reload via its associated 00080 conduit. Previous buffer content will thus be lost. The 00081 same concept is applied to writers, whereby they flush 00082 the content of a full buffer to a bound conduit before 00083 continuing. 00084 00085 6) conduits provide virtualized access to external content, 00086 and represent things like files or Internet connections. 00087 They are just a different kind of stream. Conduits are 00088 modelled by mango.io.model.IConduit, and implemented via 00089 classes FileConduit and SocketConduit. Additional kinds 00090 of conduit are easy to construct: one either subclasses 00091 mango.io.Conduit, or implements mango.io.model.IConduit. A 00092 conduit reads and writes from/to a buffer in big chunks 00093 (typically the entire buffer). 00094 00095 *******************************************************************************/ 00096 00097 abstract class IBuffer // could be an interface, but that causes poor codegen 00098 { 00099 typedef uint delegate (void* dst, uint count, uint type) Converter; 00100 00101 private typedef byte Style; 00102 00103 const Style Mixed = 0, 00104 Binary = 1, 00105 Text = 2; 00106 00107 /*********************************************************************** 00108 00109 Return the backing array 00110 00111 ***********************************************************************/ 00112 00113 abstract void[] getContent (); 00114 00115 /*********************************************************************** 00116 00117 Return a char[] slice of the buffer up to the limit of 00118 valid content. 00119 00120 ***********************************************************************/ 00121 00122 abstract char[] toString (); 00123 00124 /*********************************************************************** 00125 00126 Set the backing array with all content readable. Writing 00127 to this will either flush it to an associated conduit, or 00128 raise an Eof condition. Use IBuffer.clear() to reset the 00129 content (make it all writable). 00130 00131 ***********************************************************************/ 00132 00133 abstract IBuffer setValidContent (void[] data); 00134 00135 /*********************************************************************** 00136 00137 Set the backing array with some content readable. Writing 00138 to this will either flush it to an associated conduit, or 00139 raise an Eof condition. Use IBuffer.clear() to reset the 00140 content (make it all writable). 00141 00142 ***********************************************************************/ 00143 00144 abstract IBuffer setContent (void[] data, uint readable); 00145 00146 /*********************************************************************** 00147 00148 Write an array of data into this buffer, and flush to the 00149 conduit as necessary. Returns a chaining reference if all 00150 data was written; throws an IOException indicating eof or 00151 eob if not. 00152 00153 This is often used in lieu of a Writer. 00154 00155 ***********************************************************************/ 00156 00157 abstract IBuffer append (void[] content); 00158 00159 /*********************************************************************** 00160 00161 Read a chunk of data from the buffer, loading from the 00162 conduit as necessary. The requested number of bytes are 00163 loaded into the buffer, and marked as having been read 00164 when the 'eat' parameter is set true. When 'eat' is set 00165 false, the read position is not adjusted. 00166 00167 Returns the corresponding buffer slice when successful, 00168 or null if there's not enough data available (Eof; Eob). 00169 00170 ***********************************************************************/ 00171 00172 abstract void[] get (uint size, bool eat = true); 00173 00174 /*********************************************************************** 00175 00176 Exposes the raw data buffer at the current write position, 00177 The delegate is provided with a void[] representing space 00178 available within the buffer at the current write position. 00179 00180 The delegate should return the approriate number of bytes 00181 if it writes valid content, or IConduit.Eof on error. 00182 00183 Returns whatever the delegate returns. 00184 00185 ***********************************************************************/ 00186 00187 abstract uint write (uint delegate (void[]) writer); 00188 00189 /*********************************************************************** 00190 00191 Exposes the raw data buffer at the current read position. The 00192 delegate is provided with a void[] representing the available 00193 data, and should return zero to leave the current read position 00194 intact. 00195 00196 If the delegate consumes data, it should return the number of 00197 bytes consumed; or IConduit.Eof to indicate an error. 00198 00199 Returns whatever the delegate returns. 00200 00201 ***********************************************************************/ 00202 00203 abstract uint read (uint delegate (void[]) reader); 00204 00205 /*********************************************************************** 00206 00207 If we have some data left after an export, move it to 00208 front-of-buffer and set position to be just after the 00209 remains. This is for supporting certain conduits which 00210 choose to write just the initial portion of a request. 00211 00212 Limit is set to the amount of data remaining. Position 00213 is always reset to zero. 00214 00215 ***********************************************************************/ 00216 00217 abstract IBuffer compress (); 00218 00219 /*********************************************************************** 00220 00221 Skip ahead by the specified number of bytes, streaming from 00222 the associated conduit as necessary. 00223 00224 Can also reverse the read position by 'size' bytes. This may 00225 be used to support lookahead-type operations. 00226 00227 Returns true if successful, false otherwise. 00228 00229 ***********************************************************************/ 00230 00231 abstract bool skip (int size); 00232 00233 /*********************************************************************** 00234 00235 Try to fill the available buffer with content from the 00236 specified conduit. In particular, we will never ask to 00237 read less than 32 bytes. This permits conduit-filters 00238 to operate within a known environment. 00239 00240 Returns the number of bytes read, or throws an underflow 00241 error if there nowhere to read from 00242 00243 ***********************************************************************/ 00244 00245 abstract uint fill (); 00246 00247 /*********************************************************************** 00248 00249 Try to fill the available buffer with content from the 00250 specified conduit. In particular, we will never ask to 00251 read less than 32 bytes. This permits conduit-filters 00252 to operate within a known environment. 00253 00254 Returns the number of bytes read, or Conduit.Eof 00255 00256 ***********************************************************************/ 00257 00258 abstract uint fill (IConduit conduit); 00259 00260 /*********************************************************************** 00261 00262 Write as much of the buffer that the associated conduit 00263 can consume. 00264 00265 Returns the number of bytes written, or Conduit.Eof 00266 00267 ***********************************************************************/ 00268 00269 abstract uint drain (); 00270 00271 /*********************************************************************** 00272 00273 flush the contents of this buffer to the related conduit. 00274 Throws an IOException on premature eof. 00275 00276 ***********************************************************************/ 00277 00278 abstract void flush (); 00279 00280 /*********************************************************************** 00281 00282 Reset position and limit to zero. 00283 00284 ***********************************************************************/ 00285 00286 abstract IBuffer clear (); 00287 00288 /*********************************************************************** 00289 00290 return count of readable bytes remaining in buffer. This is 00291 calculated simply as limit() - position() 00292 00293 ***********************************************************************/ 00294 00295 abstract uint readable (); 00296 00297 /*********************************************************************** 00298 00299 Return count of writable bytes available in buffer. This is 00300 calculated simply as capacity() - limit() 00301 00302 ***********************************************************************/ 00303 00304 abstract uint writable (); 00305 00306 /*********************************************************************** 00307 00308 returns the limit of readable content within this buffer 00309 00310 ***********************************************************************/ 00311 00312 abstract uint getLimit (); 00313 00314 /*********************************************************************** 00315 00316 returns the total capacity of this buffer 00317 00318 ***********************************************************************/ 00319 00320 abstract uint getCapacity (); 00321 00322 /*********************************************************************** 00323 00324 returns the current position within this buffer 00325 00326 ***********************************************************************/ 00327 00328 abstract uint getPosition (); 00329 00330 /*********************************************************************** 00331 00332 Overridable method to grow the buffer size when it becomes 00333 full. Default is to not grow at all. 00334 00335 ***********************************************************************/ 00336 00337 abstract bool grow (uint size); 00338 00339 /*********************************************************************** 00340 00341 make some room in the buffer 00342 00343 ***********************************************************************/ 00344 00345 abstract void makeRoom (int space); 00346 00347 /*********************************************************************** 00348 00349 Returns the conduit associated with this buffer. Returns 00350 null if the buffer is purely memory based; that is, it's 00351 not backed by some external conduit. 00352 00353 Buffers do not require a conduit to operate, but it can 00354 be convenient to associate one. For example, the IReader 00355 and IWriter classes use this to import/export content as 00356 necessary. 00357 00358 ***********************************************************************/ 00359 00360 abstract IConduit getConduit (); 00361 00362 /*********************************************************************** 00363 00364 Sets the external conduit associated with this buffer. 00365 00366 Buffers do not require an external conduit to operate, but 00367 it can be convenient to associate one. For example, methods 00368 read and write use it to import/export content as necessary. 00369 00370 ***********************************************************************/ 00371 00372 abstract void setConduit (IConduit conduit); 00373 00374 /*********************************************************************** 00375 00376 Return style of buffer 00377 00378 ***********************************************************************/ 00379 00380 abstract Style getStyle (); 00381 00382 /*********************************************************************** 00383 00384 Throw an exception with the provided message 00385 00386 ***********************************************************************/ 00387 00388 abstract void error (char[] msg); 00389 } 00390 00391 00392 /******************************************************************************* 00393 00394 Any class implementing IDecoder can be bound to a reader using 00395 the setDecoder() method. 00396 00397 *******************************************************************************/ 00398 00399 abstract class AbstractDecoder 00400 { 00401 alias decoder opCall; 00402 00403 abstract uint type (); 00404 00405 abstract void bind (IBuffer buffer); 00406 00407 abstract uint decoder (void* x, uint bytes, uint type); 00408 } 00409 00410 00411 /******************************************************************************* 00412 00413 Any class implementing IEncoder can be bound to a writer using 00414 the bind() method. 00415 00416 *******************************************************************************/ 00417 00418 abstract class AbstractEncoder 00419 { 00420 alias encoder opCall; 00421 00422 abstract uint type (); 00423 00424 abstract void bind (IBuffer buffer); 00425 00426 abstract uint encoder (void* x, uint bytes, uint type); 00427 } 00428