Main Page | Class Hierarchy | Alphabetical List | Class List | 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 
00027                         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
00028 
00029 
00030         @version        Initial version, March 2004      
00031         @author         Kris
00032 
00033 
00034 *******************************************************************************/
00035 
00036 module mango.io.Conduit;
00037 
00038 private import  mango.io.Resource,
00039                 mango.io.Exception,
00040                 mango.io.ConduitStyle;
00041 
00042 private import  mango.io.model.IBuffer;
00043 
00044 public  import  mango.io.model.IConduit;
00045 
00046 /*******************************************************************************
00047 
00048         Conduit abstract base-class, implementing interface IConduit. 
00049         Only the conduit-specific reader, writer, 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 reads and writes from/to an IBuffer in large chunks, 
00061         typically the entire buffer.
00062 
00063 *******************************************************************************/
00064 
00065 class Conduit : Resource, IConduit
00066 {
00067         private ConduitStyle    style;
00068         private IConduitSource  input;
00069         private IConduitSink    output;
00070         private bool            seekable;
00071 
00072         /***********************************************************************
00073         
00074                 Construct a conduit with the given style and seek abilities. 
00075                 Conduits are either seekable or non-seekable.
00076 
00077         ***********************************************************************/
00078 
00079         this (ConduitStyle style, bool seekable)
00080         {
00081                 input = this;
00082                 output = this;
00083                 this.style = style;
00084                 this.seekable = seekable;
00085         }
00086 
00087         /***********************************************************************
00088         
00089                 Create a Buffer of a conduit-specific size
00090 
00091         ***********************************************************************/
00092 
00093         abstract IBuffer createBuffer (); 
00094                      
00095         /***********************************************************************
00096         
00097                 conduit-specific reader
00098 
00099         ***********************************************************************/
00100 
00101         protected abstract int reader (void[] dst);               
00102 
00103         /***********************************************************************
00104         
00105                 conduit-specific writer
00106 
00107         ***********************************************************************/
00108 
00109         protected abstract int writer (void[] src);               
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         protected override void closure ()
00121         {       
00122                 input.unbind ();
00123                 output.unbind ();
00124         }    
00125                    
00126         /***********************************************************************
00127         
00128                 Please refer to IConduit.attach for details
00129 
00130         ***********************************************************************/
00131 
00132         void attach (IConduitSource input)
00133         {
00134                 input.bind (this.input);
00135                 this.input = input;
00136         }
00137 
00138         /***********************************************************************
00139         
00140                 Please refer to IConduit.attach for details
00141 
00142         ***********************************************************************/
00143 
00144         void attach (IConduitSink output)
00145         {
00146                 output.bind (this.output);
00147                 this.output = output;
00148         }
00149 
00150         /***********************************************************************
00151         
00152         ***********************************************************************/
00153 
00154         protected void bind (IConduitSink next)
00155         {
00156         }
00157                               
00158         /***********************************************************************
00159         
00160         ***********************************************************************/
00161 
00162         protected void bind (IConduitSource next)
00163         {
00164         }
00165                               
00166         /***********************************************************************
00167         
00168         ***********************************************************************/
00169 
00170         protected void unbind ()
00171         {
00172         }
00173 
00174         /***********************************************************************
00175          
00176                 read from conduit into a target buffer
00177 
00178         ***********************************************************************/
00179 
00180         int read (IBuffer target)
00181         in {
00182            assert (target);
00183            }
00184         body
00185         {
00186                 return target.write (&input.reader);
00187         }              
00188 
00189         /***********************************************************************
00190         
00191                 write to conduit from a source buffer
00192 
00193         ***********************************************************************/
00194 
00195         int write (IBuffer source)
00196         in {
00197            assert (source);
00198            }
00199         body
00200         {
00201                 int count = source.read (&output.writer);
00202 
00203                 // if we didn't write everything, move remaining content
00204                 // to front of buffer for a subsequent write
00205                 source.compress ();
00206                 return count;
00207         }              
00208 
00209         /***********************************************************************
00210         
00211                 Returns true if this conduit is seekable (whether it 
00212                 implements ISeekable)
00213 
00214         ***********************************************************************/
00215 
00216         bool isSeekable ()
00217         {
00218                 return seekable;
00219         }               
00220 
00221         /***********************************************************************
00222         
00223                 Returns true is this conduit can be read from
00224 
00225         ***********************************************************************/
00226 
00227         bool isReadable ()
00228         {
00229                 return (style.access & ConduitStyle.Access.Read) != 0;
00230         }               
00231 
00232         /***********************************************************************
00233         
00234                 Returns true if this conduit can be written to
00235 
00236         ***********************************************************************/
00237 
00238         bool isWritable ()
00239         {
00240                 return (style.access & ConduitStyle.Access.Write) != 0;
00241         }               
00242 
00243         /***********************************************************************
00244 
00245                 Transfer the content of another conduit to this one. Returns 
00246                 a reference to this class, and throws IOException on failure.
00247         
00248         ***********************************************************************/
00249 
00250         IConduit copy (IConduit source)
00251         {
00252                 IBuffer buffer = createBuffer;
00253 
00254                 while (source.read (buffer) != Eof)
00255                        if (write (buffer) == Eof)
00256                            throw new IOException ("Eof while copying conduit");
00257 
00258                 // flush any remains into the target
00259                 return flush (buffer);
00260         }               
00261 
00262         /***********************************************************************
00263         
00264                 Flush buffer content out to this conduit.
00265 
00266                 Throws an IOException if flushing results in an Eof condition.
00267                         
00268         ***********************************************************************/
00269 
00270         IConduit flush (IBuffer source)
00271         {
00272                 while (source.readable)
00273                        if (write (source) == Eof)
00274                            throw new IOException ("Eof while flushing conduit");
00275                 return this;
00276         }               
00277 
00278         /***********************************************************************
00279         
00280                 Return the style used when creating this conduit
00281 
00282         ***********************************************************************/
00283 
00284         ConduitStyle getStyle ()
00285         {
00286                 return style;
00287         }    
00288 }
00289 
00290 
00291 
00292 /*******************************************************************************
00293         
00294         Defines an input filter base-class. The filter is invoked
00295         via its reader(void[]) method whenever a block of content is 
00296         being read; the void[] array represents content destination.
00297         The filter should return the number of bytes it has actually
00298         produced: less than or equal to the length of the provided 
00299         array. 
00300 
00301         Filters are chained together such that the last filter added
00302         is the first one invoked. It is the responsibility of each
00303         filter to invoke the next link in the chain; for example:
00304 
00305         @code
00306         class MungingInputFilter : FilterInput
00307         {
00308                 int reader (void[] dst)
00309                 {
00310                         // read the next X bytes
00311                         int count = next.reader (dst);
00312 
00313                         // set everything to '*' !
00314                         dst[0..count] = '*';
00315 
00316                         // say how many we read
00317                         return count;
00318                 }
00319         }
00320         @endcode
00321 
00322         Notice how this filter invokes the 'next' instance before 
00323         munging the content ... the far end of the chain is where
00324         the original IConduit reader is attached, so it will get
00325         invoked eventually assuming each filter invokes 'next'. 
00326         If the next reader fails it will return IConduit.Eof, as
00327         should your filter (or throw an IOException). From a client 
00328         perspective, filters are attached like this:
00329 
00330         @code
00331         FileConduit fc = new FileConduit (...);
00332 
00333         fc.attach (new ZipInputFilter);
00334         fc.attach (new MungingInputFilter);
00335         @endcode
00336 
00337         Again, the last filter attached is the first one invoked 
00338         when a block of content is actually read. Each filter has
00339         two additional methods that it may use to control behavior:
00340 
00341         @code
00342         class FilterInput : IFilterInput
00343         {
00344                 protected IFilterInput next;
00345 
00346                 void bind (IFilterInput next)
00347                 {
00348                         this.next = next;
00349                 }
00350 
00351                 void unbind ()
00352                 {
00353                 }
00354         }
00355         @endcode
00356 
00357         The first method is invoked when the filter is attached to a 
00358         conduit, while the second is invoked just before the conduit 
00359         is closed. Both of these may be overridden by the filter for
00360         whatever purpose desired.
00361 
00362         Note that an input filter can choose to sidestep reading from 
00363         the conduit (per the usual case), and produce its input from 
00364         somewhere else entirely. This mechanism supports the notion
00365         of 'piping' between multiple conduits, or between a conduit 
00366         and something else entirely; it's a bridging mechanism.
00367 
00368 *******************************************************************************/
00369 
00370 class ConduitSource : IConduitSource
00371 {
00372         protected IConduitSource next;
00373 
00374         /***********************************************************************
00375         
00376         ***********************************************************************/
00377 
00378         abstract int reader (void[] dst);
00379 
00380         /***********************************************************************
00381         
00382         ***********************************************************************/
00383 
00384         protected void bind (IConduitSource next)
00385         {
00386                 //printf ("bind input\n");
00387                 this.next = next;
00388         }
00389 
00390         /***********************************************************************
00391         
00392         ***********************************************************************/
00393 
00394         protected void unbind ()
00395         {
00396                 //printf ("unbind input\n");
00397                 next.unbind ();
00398         }
00399 }
00400 
00401 
00402 /*******************************************************************************
00403 
00404         Defines an output filter base-class. The filter is invoked
00405         via its writer(void[]) method whenever a block of content is 
00406         being written; the void[] array supplies writeable content.
00407         The filter should return the number of bytes it has actually
00408         consumed: less than or equal to the length of the provided 
00409         array. 
00410 
00411         Filters are chained together such that the last filter added
00412         is the first one invoked. It is the responsibility of each
00413         filter to invoke the next link in the chain; for example:
00414 
00415         @code
00416         class MungingOutputFilter : FilterOutput
00417         {
00418                 int writer (void[] src)
00419                 {
00420                         char[src.length] tmp;
00421 
00422                         // set everything to '*'
00423                         tmp = '*';
00424 
00425                         // write the munged output
00426                         return next.writer (tmp);
00427                 }
00428         }
00429         @endcode
00430 
00431         Notice how the filter invokes the 'next' instance after 
00432         munging the content ... the far end of the chain is where
00433         the original IConduit writer is attached, so it will get
00434         invoked eventually assuming each filter invokes 'next'.
00435         If the next writer fails it will return IConduit.Eof, as
00436         should your filter (or throw an IOException). At the client 
00437         level, filters are attached like this:
00438 
00439         @code
00440         FileConduit fc = new FileConduit (...);
00441 
00442         fc.attach (new ZipOutputFilter);
00443         fc.attach (new MungingOutputFilter);
00444         @endcode
00445 
00446         Again, the last filter attached is the first one invoked 
00447         when a block of content is actually written. Each filter has
00448         two additional methods that it may use to control behavior:
00449 
00450         @code
00451         class FilterOutput : IFilterOutput
00452         {
00453                 protected IFilterOutput next;
00454 
00455                 void bind (IFilterOutput next)
00456                 {
00457                         this.next = next;
00458                 }
00459 
00460                 void unbind ()
00461                 {
00462                 }
00463         }
00464         @endcode
00465 
00466         The first method is invoked when the filter is attached to a 
00467         conduit, while the second is invoked just before the conduit 
00468         is closed. Both of these may be overridden by the filter for
00469         whatever purpose desired.
00470 
00471         Note that an output filter can choose to sidestep writing to 
00472         the conduit (per the usual case), and direct its output to 
00473         somewhere else entirely. This mechanism supports the notion
00474         of 'piping' between multiple conduits, or between a conduit 
00475         and something else entirely; as with the input-filter case,
00476         this is a bridging mechanism.
00477 
00478 *******************************************************************************/
00479 
00480 class ConduitSink : IConduitSink
00481 {
00482         protected IConduitSink next;
00483 
00484         /***********************************************************************
00485         
00486         ***********************************************************************/
00487 
00488         abstract int writer (void[] src);
00489 
00490         /***********************************************************************
00491         
00492         ***********************************************************************/
00493 
00494         protected void bind (IConduitSink next)
00495         {
00496                 //printf ("bind output\n");
00497                 this.next = next;
00498         }
00499 
00500         /***********************************************************************
00501         
00502         ***********************************************************************/
00503 
00504         protected void unbind ()
00505         {
00506                 //printf ("unbind output\n");
00507                 next.unbind ();
00508         }
00509 }

Generated on Sun Nov 7 19:06:50 2004 for Mango by doxygen 1.3.6