1
0
Fork 0
cl-sites/guile.html_node/Low_002dLevel-Custom-Ports.html

245 lines
16 KiB
HTML
Raw Normal View History

2024-12-17 12:49:28 +01:00
<!DOCTYPE html>
<html>
<!-- Created by GNU Texinfo 7.1, https://www.gnu.org/software/texinfo/ -->
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<!-- This manual documents Guile version 3.0.10.
Copyright (C) 1996-1997, 2000-2005, 2009-2023 Free Software Foundation,
Inc.
Copyright (C) 2021 Maxime Devos
Copyright (C) 2024 Tomas Volf
Permission is granted to copy, distribute and/or modify this document
under the terms of the GNU Free Documentation License, Version 1.3 or
any later version published by the Free Software Foundation; with no
Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A
copy of the license is included in the section entitled "GNU Free
Documentation License." -->
<title>Low-Level Custom Ports (Guile Reference Manual)</title>
<meta name="description" content="Low-Level Custom Ports (Guile Reference Manual)">
<meta name="keywords" content="Low-Level Custom Ports (Guile Reference Manual)">
<meta name="resource-type" content="document">
<meta name="distribution" content="global">
<meta name="Generator" content=".texi2any-real">
<meta name="viewport" content="width=device-width,initial-scale=1">
<link href="index.html" rel="start" title="Top">
<link href="Concept-Index.html" rel="index" title="Concept Index">
<link href="index.html#SEC_Contents" rel="contents" title="Table of Contents">
<link href="Port-Types.html" rel="up" title="Port Types">
<link href="Low_002dLevel-Custom-Ports-in-C.html" rel="next" title="Low-Level Custom Ports in C">
<link href="Void-Ports.html" rel="prev" title="Void Ports">
<style type="text/css">
<!--
a.copiable-link {visibility: hidden; text-decoration: none; line-height: 0em}
div.example {margin-left: 3.2em}
span:hover a.copiable-link {visibility: visible}
strong.def-name {font-family: monospace; font-weight: bold; font-size: larger}
-->
</style>
<link rel="stylesheet" type="text/css" href="https://www.gnu.org/software/gnulib/manual.css">
</head>
<body lang="en">
<div class="subsubsection-level-extent" id="Low_002dLevel-Custom-Ports">
<div class="nav-panel">
<p>
Next: <a href="Low_002dLevel-Custom-Ports-in-C.html" accesskey="n" rel="next">Low-Level Custom Ports in C</a>, Previous: <a href="Void-Ports.html" accesskey="p" rel="prev">Void Ports</a>, Up: <a href="Port-Types.html" accesskey="u" rel="up">Types of Port</a> &nbsp; [<a href="index.html#SEC_Contents" title="Table of contents" rel="contents">Contents</a>][<a href="Concept-Index.html" title="Index" rel="index">Index</a>]</p>
</div>
<hr>
<h4 class="subsubsection" id="Low_002dLevel-Custom-Ports-1"><span>6.12.10.7 Low-Level Custom Ports<a class="copiable-link" href="#Low_002dLevel-Custom-Ports-1"> &para;</a></span></h4>
<p>This section describes how to implement a new kind of port using Guile&rsquo;s
lowest-level, most primitive interfaces. First, load the <code class="code">(ice-9
custom-ports)</code> module:
</p>
<div class="example">
<pre class="example-preformatted">(use-modules (ice-9 custom-ports))
</pre></div>
<p>Then to make a new port, call <code class="code">make-custom-port</code>:
</p>
<dl class="first-deffn">
<dt class="deffn" id="index-make_002dcustom_002dport"><span class="category-def">Scheme Procedure: </span><span><strong class="def-name">make-custom-port</strong> <var class="def-var-arguments">[#:read] [#:write] [#:read-wait-fd] [#:write-wait-fd] [#:input-waiting?] [#:seek] [#:random-access?] [#:get-natural-buffer-sizes] [#:id] [#:print] [#:close] [#:close-on-gc?] [#:truncate] [#:encoding] [#:conversion-strategy]</var><a class="copiable-link" href="#index-make_002dcustom_002dport"> &para;</a></span></dt>
<dd><p>Make a new custom port.
</p>
<p>See <a class="xref" href="Encoding.html">Encoding</a>, for more on <code class="code">#:encoding</code> and
<code class="code">#:conversion-strategy</code>.
</p></dd></dl>
<p>A port has a number of associated procedures and properties which
collectively implement its behavior. Creating a new custom port mostly
involves writing these procedures, which are passed as keyword arguments
to <code class="code">make-custom-port</code>.
</p>
<dl class="first-deffn">
<dt class="deffn" id="index-_0023_003aread"><span class="category-def">Scheme Port Method: </span><span><strong class="def-name">#:read</strong> <var class="def-var-arguments">port dst start count</var><a class="copiable-link" href="#index-_0023_003aread"> &para;</a></span></dt>
<dd><p>A port&rsquo;s <code class="code">#:read</code> implementation fills read buffers. It should
copy bytes to the supplied bytevector <var class="var">dst</var>, starting at offset
<var class="var">start</var> and continuing for <var class="var">count</var> bytes, and return the number
of bytes that were read, or <code class="code">#f</code> to indicate that reading any bytes
would block.
</p></dd></dl>
<dl class="first-deffn">
<dt class="deffn" id="index-_0023_003awrite"><span class="category-def">Scheme Port Method: </span><span><strong class="def-name">#:write</strong> <var class="def-var-arguments">port src start count</var><a class="copiable-link" href="#index-_0023_003awrite"> &para;</a></span></dt>
<dd><p>A port&rsquo;s <code class="code">#:write</code> implementation flushes write buffers to the
mutable store. It should write out bytes from the supplied bytevector
<var class="var">src</var>, starting at offset <var class="var">start</var> and continuing for <var class="var">count</var>
bytes, and return the number of bytes that were written, or <code class="code">#f</code> to
indicate writing any bytes would block.
</p></dd></dl>
<p>If <code class="code">make-custom-port</code> is passed a <code class="code">#:read</code> argument, the port
will be an input port. Passing a <code class="code">#:write</code> argument will make an
output port, and passing both will make an input-output port.
</p>
<dl class="first-deffn">
<dt class="deffn" id="index-_0023_003aread_002dwait_002dfd"><span class="category-def">Scheme Port Method: </span><span><strong class="def-name">#:read-wait-fd</strong> <var class="def-var-arguments">port</var><a class="copiable-link" href="#index-_0023_003aread_002dwait_002dfd"> &para;</a></span></dt>
<dt class="deffnx def-cmd-deffn" id="index-_0023_003awrite_002dwait_002dfd"><span class="category-def">Scheme Port Method: </span><span><strong class="def-name">#:write-wait-fd</strong> <var class="def-var-arguments">port</var><a class="copiable-link" href="#index-_0023_003awrite_002dwait_002dfd"> &para;</a></span></dt>
<dd><p>If a port&rsquo;s <code class="code">#:read</code> or <code class="code">#:write</code> method returns <code class="code">#f</code>,
that indicates that reading or writing would block, and that Guile
should instead <code class="code">poll</code> on the file descriptor returned by the port&rsquo;s
<code class="code">#:read-wait-fd</code> or <code class="code">#:write-wait-fd</code> method, respectively,
until the operation can complete. See <a class="xref" href="Non_002dBlocking-I_002fO.html">Non-Blocking I/O</a>, for a more
in-depth discussion.
</p>
<p>These methods must be implemented if the <code class="code">#:read</code> or <code class="code">#:write</code>
method can return <code class="code">#f</code>, and should return a non-negative integer
file descriptor. However they may be called explicitly by a user, for
example to determine if a port may eventually be readable or writable.
If there is no associated file descriptor with the port, they should
return <code class="code">#f</code>. The default implementation returns <code class="code">#f</code>.
</p></dd></dl>
<dl class="first-deffn">
<dt class="deffn" id="index-_0023_003ainput_002dwaiting_003f"><span class="category-def">Scheme Port Method: </span><span><strong class="def-name">#:input-waiting?</strong> <var class="def-var-arguments">port</var><a class="copiable-link" href="#index-_0023_003ainput_002dwaiting_003f"> &para;</a></span></dt>
<dd><p>In rare cases it is useful to be able to know whether data can be read
from a port. For example, if the user inputs <code class="code">1 2 3</code> at the
interactive console, after reading and evaluating <code class="code">1</code> the console
shouldn&rsquo;t then print another prompt before reading and evaluating
<code class="code">2</code> because there is input already waiting. If the port can look
ahead, then it should implement the <code class="code">#:input-waiting?</code> method,
which returns <code class="code">#t</code> if input is available, or <code class="code">#f</code> reading the
next byte would block. The default implementation returns <code class="code">#t</code>.
</p></dd></dl>
<dl class="first-deffn">
<dt class="deffn" id="index-_0023_003aseek"><span class="category-def">Scheme Port Method: </span><span><strong class="def-name">#:seek</strong> <var class="def-var-arguments">port offset whence</var><a class="copiable-link" href="#index-_0023_003aseek"> &para;</a></span></dt>
<dd><p>Set or get the current byte position of the port. Guile will flush read
and/or write buffers before seeking, as appropriate. The <var class="var">offset</var>
and <var class="var">whence</var> parameters are as for the <code class="code">seek</code> procedure;
See <a class="xref" href="Random-Access.html">Random Access</a>.
</p>
<p>The <code class="code">#:seek</code> method returns the byte position after seeking. To
query the current position, <code class="code">#:seek</code> will be called with an
<var class="var">offset</var> of 0 and <code class="code">SEEK_CUR</code> for <var class="var">whence</var>. Other values of
<var class="var">offset</var> and/or <var class="var">whence</var> will actually perform the seek. The
<code class="code">#:seek</code> method should throw an error if the port is not seekable,
which is what the default implementation does.
</p></dd></dl>
<dl class="first-deffn">
<dt class="deffn" id="index-_0023_003atruncate"><span class="category-def">Scheme Port Method: </span><span><strong class="def-name">#:truncate</strong> <var class="def-var-arguments">port</var><a class="copiable-link" href="#index-_0023_003atruncate"> &para;</a></span></dt>
<dd><p>Truncate the port data to be specified length. Guile will flush buffers
beforehand, as appropriate. The default implementation throws an error,
indicating that truncation is not supported for this port.
</p></dd></dl>
<dl class="first-deffn">
<dt class="deffn" id="index-_0023_003arandom_002daccess_003f"><span class="category-def">Scheme Port Method: </span><span><strong class="def-name">#:random-access?</strong> <var class="def-var-arguments">port</var><a class="copiable-link" href="#index-_0023_003arandom_002daccess_003f"> &para;</a></span></dt>
<dd><p>Return <code class="code">#t</code> if <var class="var">port</var> is open for random access, or <code class="code">#f</code>
otherwise.
</p>
<a class="index-entry-id" id="index-random-access"></a>
<p>Seeking on a random-access port with buffered input, or switching to
writing after reading, will cause the buffered input to be discarded and
Guile will seek the port back the buffered number of bytes. Likewise
seeking on a random-access port with buffered output, or switching to
reading after writing, will flush pending bytes with a call to the
<code class="code">write</code> procedure. See <a class="xref" href="Buffering.html">Buffering</a>.
</p>
<p>Indicate to Guile that your port needs this behavior by returning true
from your <code class="code">#:random-access?</code> method. The default implementation of
this function returns <code class="code">#t</code> if the port has a <code class="code">#:seek</code>
implementation.
</p></dd></dl>
<dl class="first-deffn">
<dt class="deffn" id="index-_0023_003aget_002dnatural_002dbuffer_002dsizes"><span class="category-def">Scheme Port Method: </span><span><strong class="def-name">#:get-natural-buffer-sizes</strong> <var class="def-var-arguments">read-buf-size write-buf-size</var><a class="copiable-link" href="#index-_0023_003aget_002dnatural_002dbuffer_002dsizes"> &para;</a></span></dt>
<dd><p>Guile will internally attach buffers to ports. An input port always has
a read buffer, and an output port always has a write buffer.
See <a class="xref" href="Buffering.html">Buffering</a>. A port buffer consists of a bytevector, along with
some cursors into that bytevector denoting where to get and put data.
</p>
<p>Port implementations generally don&rsquo;t have to be concerned with
buffering: a port&rsquo;s <code class="code">#:read</code> or <code class="code">#:write</code> method will receive
the buffer&rsquo;s bytevector as an argument, along with an offset and a
length into that bytevector, and should then either fill or empty that
bytevector. However in some cases, port implementations may be able to
provide an appropriate default buffer size to Guile. For example file
ports implement <code class="code">#:get-natural-buffer-sizes</code> to let the operating
system inform Guile about the appropriate buffer sizes for the
particular file opened by the port.
</p>
<p>This method returns two values, corresponding to the natural read and
write buffer sizes for the ports. The two parameters
<var class="var">read-buf-size</var> and <var class="var">write-buf-size</var> are Guile&rsquo;s guesses for
what sizes might be good. A custom <code class="code">#:get-natural-buffer-sizes</code>
method could override Guile&rsquo;s choices, or just pass them on, as the
default implementation does.
</p></dd></dl>
<dl class="first-deffn">
<dt class="deffn" id="index-_0023_003aprint"><span class="category-def">Scheme Port Method: </span><span><strong class="def-name">#:print</strong> <var class="def-var-arguments">port out</var><a class="copiable-link" href="#index-_0023_003aprint"> &para;</a></span></dt>
<dd><p>Called when the port <var class="var">port</var> is written to <var class="var">out</var>, e.g. via
<code class="code">(write port out)</code>.
</p>
<p>If <code class="code">#:print</code> is not explicitly supplied, the default implementation
prints something like <code class="code">#&lt;<var class="var">mode</var>:<var class="var">id</var> <var class="var">address</var>&gt;</code>, where
<var class="var">mode</var> is either <code class="code">input</code>, <code class="code">output</code>, or
<code class="code">input-output</code>, <var class="var">id</var> comes from the <code class="code">#:id</code> keyword
argument (defaulting to <code class="code">&quot;custom-port&quot;</code>), and <var class="var">address</var> is a
unique integer associated with the port.
</p></dd></dl>
<dl class="first-deffn">
<dt class="deffn" id="index-_0023_003aclose"><span class="category-def">Scheme Port Method: </span><span><strong class="def-name">#:close</strong> <var class="def-var-arguments">port</var><a class="copiable-link" href="#index-_0023_003aclose"> &para;</a></span></dt>
<dd><p>Called when <var class="var">port</var> is closed. It should release any
explicitly-managed resources used by the port.
</p></dd></dl>
<p>By default, ports that are garbage collected just go away without
closing or flushing any buffered output. If your port needs to release
some external resource like a file descriptor, or needs to make sure
that its internal buffers are flushed even if the port is collected
while it was open, then pass <code class="code">#:close-on-gc? #t</code> to
<code class="code">make-custom-port</code>. Note that in that case, the <code class="code">#:close</code>
method will probably be called on a separate thread.
</p>
<p>Note that calls to all of these methods can proceed in parallel and
concurrently and from any thread up until the point that the port is
closed. The call to <code class="code">close</code> will happen when no other method is
running, and no method will be called after the <code class="code">close</code> method is
called. If your port implementation needs mutual exclusion to prevent
concurrency, it is responsible for locking appropriately.
</p>
</div>
<hr>
<div class="nav-panel">
<p>
Next: <a href="Low_002dLevel-Custom-Ports-in-C.html">Low-Level Custom Ports in C</a>, Previous: <a href="Void-Ports.html">Void Ports</a>, Up: <a href="Port-Types.html">Types of Port</a> &nbsp; [<a href="index.html#SEC_Contents" title="Table of contents" rel="contents">Contents</a>][<a href="Concept-Index.html" title="Index" rel="index">Index</a>]</p>
</div>
</body>
</html>