Main Page | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Class Members | File Members | Related Pages

Conduit.d

Go to the documentation of this file.
00001 /*******************************************************************************
00002 
00003         @file Conduit.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.Conduit;
00040 
00041 private import  mango.io.Buffer,
00042                 mango.io.Exception;
00043 
00044 public  import  mango.io.model.IConduit;
00045 
00046 /*******************************************************************************
00047 
00048         Conduit abstract base-class, implementing interface IConduit. 
00049         Only the conduit-specific read, write, and buffer-factory 
00050         need to be implemented for a concrete conduit implementation. 
00051         See FileConduit for an example.
00052        
00053         Conduits provide virtualized access to external content, and 
00054         represent things like files or Internet connections. Conduits 
00055         are modelled by mango.io.model.IConduit, and implemented via 
00056         classes FileConduit and SocketConduit. 
00057         
00058         Additional kinds of conduit are easy to construct: one either 
00059         subclasses mango.io.Conduit, or implements mango.io.model.IConduit. 
00060         A conduit typically reads and writes from/to an IBuffer in large 
00061         chunks, typically the entire buffer. Alternatively, one can invoke 
00062         read(dst[]) and/or write(src[]) directly.
00063 
00064 *******************************************************************************/
00065 
00066 class Conduit : IConduit, IConduitFilter
00067 {
00068         private ConduitStyle.Bits       style;
00069         private IConduitFilter          filter;
00070         private bool                    seekable;
00071 
00072         /***********************************************************************
00073         
00074                 Return a preferred size for buffering conduit I/O
00075 
00076         ***********************************************************************/
00077 
00078         abstract uint bufferSize (); 
00079                      
00080         /***********************************************************************
00081         
00082                 conduit-specific reader
00083 
00084         ***********************************************************************/
00085 
00086         protected abstract uint reader (void[] dst);               
00087 
00088         /***********************************************************************
00089         
00090                 conduit-specific writer
00091 
00092         ***********************************************************************/
00093 
00094         protected abstract uint writer (void[] src);               
00095 
00096            
00097         /***********************************************************************
00098         
00099                 Construct a conduit with the given style and seek abilities. 
00100                 Conduits are either seekable or non-seekable.
00101 
00102         ***********************************************************************/
00103 
00104         this (ConduitStyle.Bits style, bool seekable)
00105         {
00106                 filter = this;
00107                 this.style = style;
00108                 this.seekable = seekable;
00109         }
00110 
00111         /***********************************************************************
00112         
00113                 Method to close the filters. This is invoked from the 
00114                 Resource base-class when the resource is being closed.
00115                 You should ensure that a subclass invokes this as part
00116                 of its closure mechanics.
00117 
00118         ***********************************************************************/
00119 
00120         void close ()
00121         {
00122                 filter.unbind ();
00123                 filter = this;
00124         }
00125 
00126         /***********************************************************************
00127         
00128                 flush provided content to the conduit
00129 
00130         ***********************************************************************/
00131 
00132         bool flush (void[] src)
00133         {
00134                 int len = src.length;
00135 
00136                 for (int i, written; written < len;)
00137                      if ((i = write (src[written..len])) != Eof)
00138                           written += i;
00139                      else
00140                         return false;
00141                 return true;
00142         }
00143 
00144         /***********************************************************************
00145         
00146                 Please refer to IConduit.attach for details
00147 
00148         ***********************************************************************/
00149 
00150         void attach (IConduitFilter filter)
00151         {
00152                 filter.bind (this, this.filter);
00153         }
00154 
00155         /***********************************************************************
00156         
00157         ***********************************************************************/
00158 
00159         protected void bind (IConduit conduit, IConduitFilter next)
00160         {
00161         }
00162 
00163         /***********************************************************************
00164         
00165         ***********************************************************************/
00166 
00167         protected void unbind ()
00168         {
00169         }
00170 
00171         /***********************************************************************
00172          
00173                 read from conduit into a target buffer
00174 
00175         ***********************************************************************/
00176 
00177         uint read (void[] dst)
00178         {
00179                 return filter.reader (dst);
00180         }              
00181 
00182         /***********************************************************************
00183         
00184                 write to conduit from a source buffer
00185 
00186         ***********************************************************************/
00187 
00188         uint write (void [] src)
00189         {
00190                 return filter.writer (src);
00191         }              
00192 
00193         /***********************************************************************
00194         
00195                 Returns true if this conduit is seekable (whether it 
00196                 implements ISeekable)
00197 
00198         ***********************************************************************/
00199 
00200         bool isSeekable ()
00201         {
00202                 return seekable;
00203         }               
00204 
00205         /***********************************************************************
00206         
00207                 Returns true is this conduit can be read from
00208 
00209         ***********************************************************************/
00210 
00211         bool isReadable ()
00212         {
00213                 return cast(bool) ((style.access & ConduitStyle.Access.Read) != 0);
00214         }               
00215 
00216         /***********************************************************************
00217         
00218                 Returns true if this conduit can be written to
00219 
00220         ***********************************************************************/
00221 
00222         bool isWritable ()
00223         {
00224                 return cast(bool) ((style.access & ConduitStyle.Access.Write) != 0);
00225         }               
00226 
00227         /***********************************************************************
00228         
00229                 Returns true if this conduit is text-based
00230 
00231         ***********************************************************************/
00232 
00233         bool isTextual ()
00234         {
00235                 return cast(bool) ((style.access & ConduitStyle.Access.Text) != 0);
00236         }               
00237 
00238         /***********************************************************************
00239 
00240                 Transfer the content of another conduit to this one. Returns 
00241                 a reference to this class, and throws IOException on failure.
00242         
00243         ***********************************************************************/
00244 
00245         IConduit copy (IConduit source)
00246         {
00247                 Buffer buffer = new Buffer (this);
00248 
00249                 while (buffer.fill (source) != Eof)
00250                        if (buffer.drain () == Eof)
00251                            throw new IOException ("Eof while copying conduit");
00252 
00253                 // flush any remains into the target
00254                 buffer.flush ();
00255                 return this;
00256         }               
00257 
00258         /***********************************************************************
00259         
00260                 Return the style used when creating this conduit
00261 
00262         ***********************************************************************/
00263 
00264         ConduitStyle.Bits getStyle ()
00265         {
00266                 return style;
00267         }    
00268 
00269         /***********************************************************************
00270         
00271                 Is the application terminating?
00272 
00273         ***********************************************************************/
00274 
00275         static bool isHalting ()
00276         {
00277                 return halting;
00278         }
00279 }
00280 
00281 
00282 /*******************************************************************************
00283         
00284         Define a conduit filter base-class. The filter is invoked
00285         via its reader() method whenever a block of content is 
00286         being read, and by its writer() method whenever content is
00287         being written. 
00288 
00289         The filter should return the number of bytes it has actually
00290         produced: less than or equal to the length of the provided 
00291         array. 
00292 
00293         Filters are chained together such that the last filter added
00294         is the first one invoked. It is the responsibility of each
00295         filter to invoke the next link in the chain; for example:
00296 
00297         @code
00298         class MungingFilter : ConduitFilter
00299         {
00300                 int reader (void[] dst)
00301                 {
00302                         // read the next X bytes
00303                         int count = next.reader (dst);
00304 
00305                         // set everything to '*' !
00306                         dst[0..count] = '*';
00307 
00308                         // say how many we read
00309                         return count;
00310                 }
00311 
00312                 int writer (void[] src)
00313                 {
00314                         byte[] tmp = new byte[src.length];
00315 
00316                         // set everything to '*'
00317                         tmp = '*';
00318 
00319                         // write the munged output
00320                         return next.writer (tmp);
00321                 }
00322         }
00323         @endcode
00324 
00325         Notice how this filter invokes the 'next' instance before 
00326         munging the content ... the far end of the chain is where
00327         the original IConduit reader is attached, so it will get
00328         invoked eventually assuming each filter invokes 'next'. 
00329         If the next reader fails it will return IConduit.Eof, as
00330         should your filter (or throw an IOException). From a client 
00331         perspective, filters are attached like this:
00332 
00333         @code
00334         FileConduit fc = new FileConduit (...);
00335 
00336         fc.attach (new ZipFilter);
00337         fc.attach (new MungingFilter);
00338         @endcode
00339 
00340         Again, the last filter attached is the first one invoked 
00341         when a block of content is actually read. Each filter has
00342         two additional methods that it may use to control behavior:
00343 
00344         @code
00345         class ConduitFilter : IConduitFilter
00346         {
00347                 protected IConduitFilter next;
00348 
00349                 void bind (IConduit conduit, IConduitFilter next)
00350                 {
00351                         this.next = next;
00352                 }
00353 
00354                 void unbind ()
00355                 {
00356                 }
00357         }
00358         @endcode
00359 
00360         The first method is invoked when the filter is attached to a 
00361         conduit, while the second is invoked just before the conduit 
00362         is closed. Both of these may be overridden by the filter for
00363         whatever purpose desired.
00364 
00365         Note that a conduit filter can choose to sidestep reading from 
00366         the conduit (per the usual case), and produce its input from 
00367         somewhere else entirely. This mechanism supports the notion
00368         of 'piping' between multiple conduits, or between a conduit 
00369         and something else entirely; it's a bridging mechanism.
00370 
00371 
00372 *******************************************************************************/
00373 
00374 class ConduitFilter : IConduitFilter
00375 {
00376         protected IConduitFilter next;
00377 
00378         /***********************************************************************
00379         
00380         ***********************************************************************/
00381 
00382         uint reader (void[] dst)
00383         {
00384                 return next.reader (dst);
00385         }
00386 
00387         /***********************************************************************
00388         
00389         ***********************************************************************/
00390 
00391         uint writer (void[] src)
00392         {
00393                 return next.writer (src);
00394         }
00395 
00396         /***********************************************************************
00397         
00398         ***********************************************************************/
00399 
00400         protected void bind (IConduit conduit, IConduitFilter next)
00401         {
00402                 this.next = next;
00403         }
00404 
00405         /***********************************************************************
00406         
00407         ***********************************************************************/
00408 
00409         protected void unbind ()
00410         {
00411                 next.unbind ();
00412         }
00413 
00414         /***********************************************************************
00415         
00416         ***********************************************************************/
00417 
00418         protected final void error (char[] msg)
00419         {
00420                 throw new IOException (msg);
00421         }
00422 }
00423 
00424 
00425 /*******************************************************************************
00426 
00427         Set a flag when the application is halting. This is used to avoid
00428         closure mechanics while the object pool may be in a state of flux.
00429 
00430 *******************************************************************************/
00431 
00432 private static bool halting;
00433 
00434 private static ~this()
00435 {
00436         halting = true;
00437 }
00438 

Generated on Sat Dec 24 17:28:32 2005 for Mango by  doxygen 1.4.0