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

Generated on Sun Mar 6 00:30:56 2005 for Mango by doxygen 1.3.6