<br><div class="gmail_quote">On Wed, Nov 10, 2010 at 10:38 AM, Taylor R Campbell <span dir="ltr"><<a href="mailto:campbell%2Bracket@mumble.net">campbell+racket@mumble.net</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">
<br>The documentation describes the contract of MAKE-INPUT-PORT and<br>
MAKE-OUTPUT-PORT. That doesn't tell me how the pieces fit together,<br>
though, or say what one can do with them, or give any guidance on how<br>
to make them. For example, given the pieces of an input port, how do<br>
I implement PEEK-BYTE or READ-BYTE? Conversely, suppose I have a file<br>
descriptor and some way to do a non-blocking read on it, or an<br>
asynchronous (aio) read on it; how do I make the pieces of an input<br>
port?<br></blockquote><div><br></div><div>make-input-port & make-output-port creates custom port types - this is only needed if your port needs are not satisfied with what's provided. Since it provides the hooks to the underlying port system it is quite complex. I have made a few such ports but only know enough to do what I needed to do. Again it might be easier to help if you share more details. </div>
<div><br></div><div>There is another way to create custom ports - and that is through the use of struct property prop:input-port and prop:output-port. If all you need to do is to wrap a couple of objects with ports, then this is probably what you need. (when I first started I did not realize that and implemented all custom ports via make-input-port & make-output-port, but I made the migration and found out that only a few truly need either, most of needs I found can be addressed through wrapper ports). </div>
<div><br></div><div>Below are what I've learned through my own trial/error. Maybe this can be a starting collaboration point for a better guide. </div><div><br></div><div>make-input-port requires at least 4 arguments (I've not used beyond the required arguments so others will have to chime in beyond this). The first one is the name of the port, and the second is a procedure for reading from the underlying source. The third is for peeking instead of reading, and fourth is to close the source. </div>
<div><br></div><div>Basically - open, read, peek, and close are the main operation that one would do with an input-port. make-input-port itself does the open, and hence you'll need to customize the read, peek, and the close operations. </div>
<div><br></div><div>And since these hooks all need to have access to the underlying source, you will need to make the read, peek, and close a closure over the source port (let's call it <font class="Apple-style-span" face="'courier new', monospace">IN</font>). </div>
<div><br></div><div>The read-in hook is the key hook to implement - this is how others will read data from your port. read-in takes in a mutable bytes (the caller holds the reference so changes are visible to the caller), so your procedure should mutate the bytes with the source you read from. And you should return the # of bytes read, or eof in the usual circumstances. So the simplest read proc will look like the following: </div>
<div><br></div></div><blockquote class="webkit-indent-blockquote" style="margin: 0 0 0 40px; border: none; padding: 0px;"><div class="gmail_quote"><div><span class="Apple-style-span" style="font-family: 'courier new', monospace; ">;; *read-bytes!* is the custom read-bytes! that works with your source. If your source is a regular scheme port, then it's the same as read-bytes!</span></div>
</div><div class="gmail_quote"><div><font class="Apple-style-span" face="'courier new', monospace">(lambda (bytes) </font></div></div><div class="gmail_quote"><div><font class="Apple-style-span" face="'courier new', monospace"> (*read-bytes!* bytes IN 0 (bytes-length bytes))) </font></div>
</div></blockquote><div class="gmail_quote"><div><br></div><div>the peek hook allows others to peek data from your port. It takes in a mutable byte, the # of bytes to skip, and a "get-progress-evt" to indicate whether or not we are in a "get-progress". This will be #f if the fifth arg to make-input-port is #f, in which case below is the simplest peek: </div>
<div><br></div></div><blockquote class="webkit-indent-blockquote" style="margin: 0 0 0 40px; border: none; padding: 0px;"><div class="gmail_quote"><div><font class="Apple-style-span" face="'courier new', monospace">;; *peek-bytes* is your custom peek-bytes that works with your source, it will be the same as the default peek-bytes! if you have a regular scheme port </font></div>
</div><div class="gmail_quote"><div><font class="Apple-style-span" face="'courier new', monospace">(lambda (bytes skip evt) </font></div></div><div class="gmail_quote"><div><font class="Apple-style-span" face="'courier new', monospace"> (*peek-bytes!* bytes skip IN 0 (bytes-length bytes))) </font></div>
</div></blockquote><div class="gmail_quote"><div><br></div><div>Make sure do not implement peek with a read to the underlying source since peek is not supposed to consume bytes. peek returns either # of bytes read, or eof. If you have a get-progress-evt it might also produce a #f, which indicates that no bytes are peeked. </div>
<div><br></div><div>the close hook allows you to close the underlying source. The same logic above applies. </div></div><blockquote class="webkit-indent-blockquote" style="margin: 0 0 0 40px; border: none; padding: 0px;">
<div class="gmail_quote"><div><font class="Apple-style-span" face="'courier new', monospace">;; *close-input-port* is the custom *close-input-port* that works with your source - it will be the same as the default close-input-port if you have a regular scheme port. </font></div>
</div><div class="gmail_quote"><div><font class="Apple-style-span" face="'courier new', monospace">(lambda () </font></div></div><div class="gmail_quote"><div><font class="Apple-style-span" face="'courier new', monospace"> (*close-input-port* IN)) </font></div>
</div></blockquote><div class="gmail_quote"><div><br></div><div>To put the above together, below is a procedure that will make such a basic custom input-port: </div><div><br></div></div><blockquote class="webkit-indent-blockquote" style="margin: 0 0 0 40px; border: none; padding: 0px;">
<div class="gmail_quote"><div><div><font class="Apple-style-span" face="'courier new', monospace">(define (make-basic-custom-input-port IN </font></div></div></div><div class="gmail_quote"><div><div><font class="Apple-style-span" face="'courier new', monospace"> (*object-name object-name) </font></div>
</div></div><div class="gmail_quote"><div><div><font class="Apple-style-span" face="'courier new', monospace"> (*read-bytes!* read-bytes!) </font></div></div></div><div class="gmail_quote">
<div><div><font class="Apple-style-span" face="'courier new', monospace"> (*peek-bytes!* peek-bytes!) </font></div></div></div><div class="gmail_quote"><div><div><font class="Apple-style-span" face="'courier new', monospace"> (*close-input-port* close-input-port)) </font></div>
</div></div><div class="gmail_quote"><div><div><font class="Apple-style-span" face="'courier new', monospace"> (make-input-port (*object-name* name) </font></div></div></div><div class="gmail_quote"><div><div><font class="Apple-style-span" face="'courier new', monospace"> (lambda (bytes) </font></div>
</div></div><div class="gmail_quote"><div><div><font class="Apple-style-span" face="'courier new', monospace"> (*read-bytes!* bytes IN 0 (bytes-length bytes))) </font></div></div></div><div class="gmail_quote">
<div><div><font class="Apple-style-span" face="'courier new', monospace"> (lambda (bytes skip evt) </font></div></div></div><div class="gmail_quote"><div><div><font class="Apple-style-span" face="'courier new', monospace"> (*peek-bytes!* bytes skip IN 0 (bytes-length bytes))) </font></div>
</div></div><div class="gmail_quote"><div><div><font class="Apple-style-span" face="'courier new', monospace"> (lambda () </font></div></div></div><div class="gmail_quote"><div><div><font class="Apple-style-span" face="'courier new', monospace"> (*close-input-port* IN))))</font></div>
</div></div></blockquote><div class="gmail_quote"><div><br></div><div>The above should provide a basic sketch on how it works, and the rest is to fill out the details on what's specific to your port. Obviously <font class="Apple-style-span" face="'courier new', monospace">IN</font> does not actually have to be a true scheme port - it can be anything that will produce the bytes. </div>
<div><br></div><div>I will leave make-output-port as an exercise, at least until others have further questions. </div><div><br></div><div>HTH. Cheers,</div><div>yc</div><div><br></div><div><br></div></div>