<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>binarycat</title>
    <link>https://paper.wf/binarycat/</link>
    <description>blog about programming and general tech stuff</description>
    <pubDate>Tue, 28 Apr 2026 09:51:07 +0000</pubDate>
    <item>
      <title>git: How to fetch a remote branch</title>
      <link>https://paper.wf/binarycat/git-how-to-fetch-a-remote-branch</link>
      <description>&lt;![CDATA[Yet Another Guide because existing ones don&#39;t work with shallow clones.&#xA;!--more--&#xA;&#xA;To fetch a specific remote branch and associate it with a local branch, use&#xA;git fetch REMOTENAME REMOTEBRANCH:LOCAL_BRANCH.&#xA;&#xA;This should work with all repos, including shallow repos.&#xA;&#xA;-----&#xA;&#xA;#git #tutorial&#xA;&#xA;--------&#xD;&#xA;&#xD;&#xA;You can follow this blog via its RSS feed or by searching for @binarycat@paper.wf on your Mastodon/ActivityPub instance.]]&gt;</description>
      <content:encoded><![CDATA[<p>Yet Another Guide because existing ones don&#39;t work with shallow clones.
</p>

<p>To fetch a specific remote branch and associate it with a local branch, use
<code>git fetch REMOTE_NAME REMOTE_BRANCH:LOCAL_BRANCH</code>.</p>

<p>This should work with all repos, including shallow repos.</p>

<hr>

<p><a href="/binarycat/tag:git" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">git</span></a> <a href="/binarycat/tag:tutorial" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">tutorial</span></a></p>

<hr>

<p>You can follow this blog <a href="https://paper.wf/binarycat/feed/" rel="nofollow">via its RSS feed</a> or by searching for <a href="https://paper.wf/@/binarycat@paper.wf" class="u-url mention" rel="nofollow">@<span>binarycat@paper.wf</span></a> on your Mastodon/ActivityPub instance.</p>
]]></content:encoded>
      <guid>https://paper.wf/binarycat/git-how-to-fetch-a-remote-branch</guid>
      <pubDate>Tue, 27 May 2025 21:00:54 +0000</pubDate>
    </item>
    <item>
      <title>Safe Delayed Initialization for Lifetime Extension</title>
      <link>https://paper.wf/binarycat/safe-delayed-initialization-for-lifetime-extension</link>
      <description>&lt;![CDATA[A niche programming pattern to satisfy the borrow checker.&#xA;!--more--&#xA;&#xA;Many Rust programmers don&#39;t know the exact semantics of let:&#xA;&#xA;A variable in let must be assigned at least once in each control-flow path it is used in (exactly once if it is not declared mut).&#xA;&#xA;This means we don&#39;t have to initialize variables if we don&#39;t use them:&#xA;&#xA;fn main() {&#xA;    let x: u8; // never assigned a value&#xA;}&#xA;&#xA;On its own, this isn&#39;t very helpful, but it gets slightly less useless when we combine it with conditional control flow:&#xA;&#xA;use rand;&#xA;&#xA;fn main() {&#xA;    let x: u8; &#xA;    &#xA;    if rand::random::bool() {&#xA;        x = rand::random();&#xA;        // the borrow checker knows that&#xA;        // x is always assigned before&#xA;        // it is read.&#xA;        println!(&#34;x is {x}&#34;);&#xA;    }&#xA;}&#xA;&#xA;Ok, still not very useful yet.  Where this gets actually useful is when we have a reference that we want to sometimes point to some data we allocated on the heap.&#xA;&#xA;use rand;&#xA;&#xA;fn main() {&#xA;    let xstring: String; &#xA;    let mut x = &#34;nothing&#34;;&#xA;    &#xA;    if rand::random::bool() {&#xA;        let n: u8 = rand::random();&#xA;        xstring = n.tostring();&#xA;        // because xstring is declared&#xA;        // in the same scope as x,&#xA;        // we can do this.&#xA;        // if xstring was&#xA;        // declared within this if block,&#xA;        // it would not live long enough.&#xA;        x = &amp;xstring;&#xA;    }&#xA;    &#xA;    // pretend this is really complicated code&#xA;    // that we don&#39;t want to repeat.&#xA;    println!(&#34;x is {x}&#34;);&#xA;}&#xA;&#xA;Many less-experienced Rust programmers would just use &#34;nothing&#34;.tostring() here, always storing x on the heap, but this has the downside of a needless allocation.&#xA;&#xA;Of course, in this example, we could just initialize xstring with a dummy value and make it mut, like let mut xstring = String::new(), but this has a few issues:&#xA;it implies the string may be mutated several times in-place.&#xA;if we forget the x_string = line, the compiler won&#39;t warn us, and we&#39;ll end up printing the empty string.&#xA;not all types have such a cheap/easy way to create a dummy value like this.&#xA;&#xA;Another alternative would be using MaybeUninit, which may be necessary if your control flow is significantly more complex, but this should be avoided if possible due to the potential to cause Undefined Behavior.&#xA;&#xA;If you&#39;re interested in a more real-world example of this pattern, rustdoc uses this in several places, such as in Type::attributes.&#xA;&#xA;-------&#xA;&#xA;#rust #programming&#xA;&#xA;--------&#xD;&#xA;&#xD;&#xA;You can follow this blog via its RSS feed or by searching for @binarycat@paper.wf on your Mastodon/ActivityPub instance.]]&gt;</description>
      <content:encoded><![CDATA[<p>A niche programming pattern to satisfy the borrow checker.
</p>

<p>Many Rust programmers don&#39;t know the exact semantics of <code>let</code>:</p>

<p>A variable in <code>let</code> must be assigned at least once in each control-flow path it is used in (exactly once if it is not declared <code>mut</code>).</p>

<p>This means we don&#39;t have to initialize variables if we don&#39;t use them:</p>

<pre><code class="language-rust">fn main() {
    let _x: u8; // never assigned a value
}
</code></pre>

<p>On its own, this isn&#39;t very helpful, but it gets slightly less useless when we combine it with conditional control flow:</p>

<pre><code class="language-rust">use rand;

fn main() {
    let x: u8; 
    
    if rand::random::&lt;bool&gt;() {
        x = rand::random();
        // the borrow checker knows that
        // `x` is always assigned before
        // it is read.
        println!(&#34;x is {x}&#34;);
    }
}
</code></pre>

<p>Ok, still not very useful yet.  Where this gets <em>actually</em> useful is when we have a reference that we want to <em>sometimes</em> point to some data we allocated on the heap.</p>

<pre><code class="language-rust">use rand;

fn main() {
    let x_string: String; 
    let mut x = &#34;nothing&#34;;
    
    if rand::random::&lt;bool&gt;() {
        let n: u8 = rand::random();
        x_string = n.to_string();
        // because `x_string` is declared
        // in the same scope as `x`,
        // we can do this.
        // if `x_string` was
        // declared within this `if` block,
        // it would not live long enough.
        x = &amp;x_string;
    }
    
    // pretend this is really complicated code
    // that we don&#39;t want to repeat.
    println!(&#34;x is {x}&#34;);
}
</code></pre>

<p>Many less-experienced Rust programmers would just use <code>&#34;nothing&#34;.to_string()</code> here, always storing <code>x</code> on the heap, but this has the downside of a needless allocation.</p>

<p>Of course, in this example, we could just initialize <code>x_string</code> with a dummy value and make it <code>mut</code>, like <code>let mut x_string = String::new()</code>, but this has a few issues:
1. it implies the string may be mutated several times in-place.
2. if we forget the <code>x_string =</code> line, the compiler won&#39;t warn us, and we&#39;ll end up printing the empty string.
3. not all types have such a cheap/easy way to create a dummy value like this.</p>

<p>Another alternative would be using <code>MaybeUninit</code>, which may be necessary if your control flow is significantly more complex, but this should be avoided if possible due to the potential to cause Undefined Behavior.</p>

<p>If you&#39;re interested in a more real-world example of this pattern, rustdoc uses this in several places, such as in <a href="https://github.com/rust-lang/rust/blob/a4a11aca5ecf24dfff3c00715641026809951305/src/librustdoc/clean/types.rs#L759" rel="nofollow"><code>Type::attributes</code></a>.</p>

<hr>

<p><a href="/binarycat/tag:rust" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">rust</span></a> <a href="/binarycat/tag:programming" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">programming</span></a></p>

<hr>

<p>You can follow this blog <a href="https://paper.wf/binarycat/feed/" rel="nofollow">via its RSS feed</a> or by searching for <a href="https://paper.wf/@/binarycat@paper.wf" class="u-url mention" rel="nofollow">@<span>binarycat@paper.wf</span></a> on your Mastodon/ActivityPub instance.</p>
]]></content:encoded>
      <guid>https://paper.wf/binarycat/safe-delayed-initialization-for-lifetime-extension</guid>
      <pubDate>Fri, 21 Mar 2025 18:51:05 +0000</pubDate>
    </item>
    <item>
      <title>stop calling things transparent</title>
      <link>https://paper.wf/binarycat/stop-calling-things-transparent</link>
      <description>&lt;![CDATA[in the context of programming, transpernt is a contranym&#xA;&#xA;it can either mean that a system is hard to see (like a pane of glass) or easy to see into (like a transparent gameboy).&#xA;!--more--&#xA;&#xA;these two meanings are pretty much exact opposites, and it&#39;s frequently difficult to know which one is being spoken about.&#xA;&#xA;FORTH systems often pride themselves as following &#34;radical transparency&#34; due to their lack of encapsulation allowing powerful language extensions to be written in user code, while other programming languages advertising &#34;transparent abstractions&#34; that you can barely notice due to strong encapsulation.&#xA;&#xA;it&#39;s also a metaphor, and as a general rule, metaphors should be avoided in technical writing, due to their potential for being misinterpreted.&#xA;&#xA;-------&#xA;&#xA;#programming #terminology&#xA;&#xA;--------&#xD;&#xA;&#xD;&#xA;You can follow this blog via its RSS feed or by searching for @binarycat@paper.wf on your Mastodon/ActivityPub instance.]]&gt;</description>
      <content:encoded><![CDATA[<p>in the context of programming, transpernt is a <a href="https://en.wiktionary.org/wiki/contranym" rel="nofollow">contranym</a></p>

<p>it can either mean that a system is <em>hard to see</em> (like a pane of glass) or <em>easy to see into</em> (like a transparent gameboy).
</p>

<p>these two meanings are pretty much exact opposites, and it&#39;s frequently difficult to know which one is being spoken about.</p>

<p>FORTH systems often pride themselves as following “radical transparency” due to their lack of encapsulation allowing powerful language extensions to be written in user code, while other programming languages advertising “transparent abstractions” that you can barely notice due to strong encapsulation.</p>

<p>it&#39;s also a <em>metaphor</em>, and as a general rule, metaphors should be avoided in technical writing, due to their potential for being misinterpreted.</p>

<hr>

<p><a href="/binarycat/tag:programming" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">programming</span></a> <a href="/binarycat/tag:terminology" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">terminology</span></a></p>

<hr>

<p>You can follow this blog <a href="https://paper.wf/binarycat/feed/" rel="nofollow">via its RSS feed</a> or by searching for <a href="https://paper.wf/@/binarycat@paper.wf" class="u-url mention" rel="nofollow">@<span>binarycat@paper.wf</span></a> on your Mastodon/ActivityPub instance.</p>
]]></content:encoded>
      <guid>https://paper.wf/binarycat/stop-calling-things-transparent</guid>
      <pubDate>Mon, 11 Nov 2024 00:50:29 +0000</pubDate>
    </item>
    <item>
      <title>Reliable Immutable Transfer Protocol</title>
      <link>https://paper.wf/binarycat/reliable-immutable-transfer-protocol</link>
      <description>&lt;![CDATA[an incredibly simple protocol for reliably and correctly downloading large immutable files.&#xA;!--more--&#xA;&#xA;(this is a follow-up and successor to my RTP proposal)&#xA;&#xA;the ritp url scheme will be described in a follow-up post.&#xA;&#xA;Problem Statement&#xA;Downloading large files is hard.  Networks are messy, and while there are plenty of protocols that aim to abstract away this messiness, they all have their own problems.&#xA;&#xA;HTTP&#xA;If implemented properly, HTTP can handle essentially anything you throw at it... however, to my knowledge, there is no full http implementation that correctly implements every corner-case of error handling. (wget is probably the closest)&#xA;&#xA;The main difficulty of HTTP is that it&#39;s too flexible for its own good: all the error recovery and detection mechanisms are optional headers, so a complete implementation has to have several layers of fallbacks, and testing all these rarely used code paths is a significant challenge.  RITP addresses this complexity by limiting its scope and choosing a small number of mandatory fields that all servers must support.&#xA;&#xA;One problem with http is that of mid-air collisions: it is entirely possible for a server to implement Range but not provide a Last-Modified or ETag field.  RITP solves this by not allowing files/resources to be modified.&#xA;&#xA;Gemini&#xA;the gemini protocol is essentially a response to the complexity of http, but it limits its scope to &#34;serving small markup files&#34;, and explicitly recommends using another protocol to handle large downloads.&#xA;&#xA;RITP can be used with gemini as this &#34;protocol for large file downloads&#34;.  this especially works well with gemini&#39;s cross-protocol redirects, giving a layer of mutable identifiers above the immutable RITP.&#xA;&#xA;BitTorrent&#xA;BitTorrent is a great protocol at what it does, but it has one major downside: poor single-peer performance.  Currently it solves this with webseeds, but then you have to deal with the issues of HTTP.&#xA;&#xA;RITP can be used with BitTorrent as an alternative protocol for webseeds, reducing the overhead of all the http headers.&#xA;&#xA;9p&#xA;The main problem with 9p is poor performance over high-latency links.&#xA;&#xA;Core Protocol Description&#xA;RITP is a stateful request/response protocol, similar to 9p.&#xA;&#xA;all messages (both requests and responses) start with the same fields:&#xA;a 32 bit length field that stores the length of the entire message, including the length field itself&#xA;an 8 bit type field that identifies the type of message&#xA;a 24 bit token field that identifies the message batch the message belongs to.  this is described in further detail in the batches section.  the token is unique within the connection.&#xA;&#xA;whenever a field specifies a length or offset of/within a file, this length/offset is in units of bytes.&#xA;&#xA;message types&#xA;the high bit (0x80) of the type field marks a message as a response (server-sent).&#xA;&#xA;depending on the type of a message, a message has any number of fixed-size fields, followed by a variable-length &#34;tail field&#34;, which consists of all following bytes of the message.  the interpretation of the tail field depends on the type of the message.  if no special interpretation of tail field is specified, it should be ignored.  the tail field takes advantage of the fact that messages already describe their total length.&#xA;&#xA;Requests&#xA;&#xA;0x01 OPEN&#xA;the remaining bytes (tail field) of the message are interpreted as a multihash, which is then looked up by the server and the corresponding file is associated with the message batch.&#xA;&#xA;if the batch id has been used before, the previous batch is closed and replaced.&#xA;&#xA;0x02 READ&#xA;fixed-size fields:&#xA;(64 bits) offset&#xA;(32 bits) length&#xA;&#xA;requests a byte slice of the file associated with the message batch.&#xA;&#xA;Responses&#xA;&#xA;0x80 ERROR&#xA;fixed-size fields:&#xA;(8 bits) code: an error code, possible values listed in the errors section.&#xA;&#xA;tail field:&#xA;description: a human readable utf8 string providing a description of the error&#xA;&#xA;when an error response is given, all future messages sent to that batch are canceled, and will not be given a response.&#xA;&#xA;0x81 OPENED&#xA;used to indicate that an OPEN request has been successful.&#xA;&#xA;fixed-width fields:&#xA;(64 bits) length: the total length of the file that is now associated with this batch.&#xA;&#xA;0x82 DATA&#xA;given in response to a READ.&#xA;&#xA;fixed-size fields:&#xA;(64 bits) offset: the offset field of the corresponding READ request.&#xA;&#xA;tail fields:&#xA;payload: a substring of the overall file, starting at offset.&#xA;&#xA;the payload should be the empty string if (and only if) offset is greater than or equal to the length of the associated file.  this mirrors the UNIX method of signaling end-of-file.&#xA;&#xA;Errors&#xA;0x00 other error: an error occured that cannot be accurately described by any of the other error codes.&#xA;0x01 not found: no file with the given hash is stored on the server.  this error code is also used if the hash is malformed or uses an unsupported hash algorithm. &#xA;0x02 unknown request type: the type was not recognized by the server.  this allows the protocol to be extended in the future by adding message types. &#xA;0x03 batch does not exist: the type was recognized, and the batch unexpectedly does not exist.&#xA;&#xA;Additional Explanation&#xA;&#xA;Batches&#xA;&#xA;A batch is a group of messages that represent operations on a single file. A batch is identified by it&#39;s token.&#xA;&#xA;A batch begins with an OPEN request and is followed by any number of READ requests.&#xA;&#xA;If the OPEN request encounters an error, other requests with the same batch token will be ignored.&#xA;&#xA;If other message types are introduced in the future, they will be specified as either introducing a new batch (like OPEN) or being part of an existing batch (like READ).&#xA;&#xA;Future Compatibility&#xA;future versions of this specification may define new message types.&#xA;&#xA;clients may attempt to use these new message types with any servers, and servers that do not support them MUST respond with error 0x03 unknown request type.&#xA;&#xA;servers MUST NOT respond with new response codes unless the client previously sent a request that indicates that response code is supported (what requests imply support for what responses will be defined in future specifications)&#xA;&#xA;Rationale&#xA;&#34;batch does not exist&#34; errors are only returned for recognized message types to potentially allow adding new message types that create a batch.&#xA;&#xA;batch tokens are client-assigned so that a client can &#34;pipeline&#34; an OPEN and a READ in a single transmission, reducing round-trip delays.&#xA; &#xA;errors cancel a batch to prevent an error in a large pipelined batch from causing a bunch of error responses.&#xA;&#xA;there is no need to identify which request in a batch caused the error, as properly formed (i.e. part of an OPENed batch) READ requests are infallible.  if they were not infallible, a READ ERROR response would exist, which would contain the offset of the read that caused the error.&#xA;&#xA;the server is allowed to respond with short reads to allow for servers that use fixed-size buffers or have limited memory.&#xA;&#xA;OPEN requests originally used urns, but this was changed to multihash after discovering that sha256 and md5 are not actually in the list of urn namespaces &#xA;&#xA;messages describe their total length to allow new request codes to be added.&#xA;&#xA;Errata 2024-11-08&#xA;ERROR responses are now encoded as 0x80 instead of 0x83.&#xA;clarify tokens are unique within a connection, not across connections.&#xA;&#xA;Addendum 2025-01-10&#xA;All clients and servers are RECOMMENDED to support at least sha2-256.&#xA;&#xA;Before a connection is initiated, both the server address(es) and the hash of the file to download are communicated to the client out-of-band, such as through a magnet: url or similar.  The exact nature of this communication is left up to future specifications.&#xA;&#xA;-------&#xA;&#xA;networking&#xA;&#xA;--------&#xD;&#xA;&#xD;&#xA;You can follow this blog via its RSS feed or by searching for @binarycat@paper.wf on your Mastodon/ActivityPub instance.]]&gt;</description>
      <content:encoded><![CDATA[<p>an incredibly simple protocol for reliably and correctly downloading large immutable files.
</p>

<p>(this is a follow-up and successor to my <a href="https://paper.wf/binarycat/rtp" rel="nofollow">RTP</a> proposal)</p>

<p>the <code>ritp</code> url scheme will be described in a follow-up post.</p>

<h1 id="problem-statement" id="problem-statement">Problem Statement</h1>

<p>Downloading large files is hard.  Networks are messy, and while there are plenty of protocols that aim to abstract away this messiness, they all have their own problems.</p>

<h2 id="http" id="http">HTTP</h2>

<p>If implemented properly, HTTP can handle essentially anything you throw at it... however, to my knowledge, there is no full http implementation that correctly implements every corner-case of error handling. (wget is probably the closest)</p>

<p>The main difficulty of HTTP is that it&#39;s too flexible for its own good: all the error recovery and detection mechanisms are <em>optional</em> headers, so a complete implementation has to have several layers of fallbacks, and testing all these rarely used code paths is a significant challenge.  RITP addresses this complexity by limiting its scope and choosing a small number of mandatory fields that all servers must support.</p>

<p>One problem with http is that of <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETag#avoiding_mid-air_collisions" rel="nofollow">mid-air collisions</a>: it is entirely possible for a server to implement <code>Range</code> but not provide a <code>Last-Modified</code> or <code>ETag</code> field.  RITP solves this by not allowing files/resources to be modified.</p>

<h2 id="gemini" id="gemini">Gemini</h2>

<p><a href="https://geminiprotocol.net/" rel="nofollow">the gemini protocol</a> is essentially a response to the complexity of http, but it limits its scope to “serving small markup files”, and explicitly recommends using another protocol to handle large downloads.</p>

<p>RITP can be used with gemini as this “protocol for large file downloads”.  this especially works well with gemini&#39;s cross-protocol redirects, giving a layer of mutable identifiers above the immutable RITP.</p>

<h2 id="bittorrent" id="bittorrent">BitTorrent</h2>

<p>BitTorrent is a great protocol at what it does, but it has one major downside: poor single-peer performance.  Currently it solves this with webseeds, but then you have to deal with the issues of HTTP.</p>

<p>RITP can be used with BitTorrent as an alternative protocol for webseeds, reducing the overhead of all the http headers.</p>

<h2 id="9p" id="9p">9p</h2>

<p>The main problem with 9p is poor performance over high-latency links.</p>

<h1 id="core-protocol-description" id="core-protocol-description">Core Protocol Description</h1>

<p>RITP is a stateful request/response protocol, similar to 9p.</p>

<p>all messages (both requests and responses) start with the same fields:
* a 32 bit <code>length</code> field that stores the length of the <em>entire</em> message, including the length field itself
* an 8 bit <code>type</code> field that identifies the type of message
* a 24 bit <code>token</code> field that identifies the message batch the message belongs to.  this is described in further detail in the <a href="#batches" rel="nofollow">batches</a> section.  the token is unique within the connection.</p>

<p>whenever a field specifies a <code>length</code> or <code>offset</code> of/within a file, this length/offset is in units of bytes.</p>

<h2 id="message-types" id="message-types">message types</h2>

<p>the high bit (0x80) of the <code>type</code> field marks a message as a response (server-sent).</p>

<p>depending on the type of a message, a message has any number of fixed-size fields, followed by a variable-length “tail field”, which consists of all following bytes of the message.  the interpretation of the tail field depends on the type of the message.  if no special interpretation of tail field is specified, it should be ignored.  the tail field takes advantage of the fact that messages already describe their total length.</p>

<h3 id="requests" id="requests">Requests</h3>

<h4 id="0x01-open" id="0x01-open">0x01 OPEN</h4>

<p>the remaining bytes (tail field) of the message are interpreted as a <a href="https://www.multiformats.io/multihash/" rel="nofollow">multihash</a>, which is then looked up by the server and the corresponding file is associated with the message batch.</p>

<p>if the batch id has been used before, the previous batch is closed and replaced.</p>

<h4 id="0x02-read" id="0x02-read">0x02 READ</h4>

<p>fixed-size fields:
* (64 bits) <code>offset</code>
* (32 bits) <code>length</code></p>

<p>requests a byte slice of the file associated with the message batch.</p>

<h3 id="responses" id="responses">Responses</h3>

<h4 id="0x80-error" id="0x80-error">0x80 ERROR</h4>

<p>fixed-size fields:
* (8 bits) <code>code</code>: an error code, possible values listed in the <a href="#errors" rel="nofollow">errors</a> section.</p>

<p>tail field:
* <code>description</code>: a human readable utf8 string providing a description of the error</p>

<p>when an error response is given, all future messages sent to that batch are canceled, and will not be given a response.</p>

<h4 id="0x81-opened" id="0x81-opened">0x81 OPENED</h4>

<p>used to indicate that an <code>OPEN</code> request has been successful.</p>

<p>fixed-width fields:
* (64 bits) <code>length</code>: the total length of the file that is now associated with this batch.</p>

<h4 id="0x82-data" id="0x82-data">0x82 DATA</h4>

<p>given in response to a <code>READ</code>.</p>

<p>fixed-size fields:
* (64 bits) <code>offset</code>: the offset field of the corresponding <code>READ</code> request.</p>

<p>tail fields:
* <code>payload</code>: a substring of the overall file, starting at <code>offset</code>.</p>

<p>the <code>payload</code> should be the empty string if (and only if) <code>offset</code> is greater than or equal to the length of the associated file.  this mirrors the UNIX method of signaling end-of-file.</p>

<h2 id="errors" id="errors">Errors</h2>
<ul><li>0x00 <code>other error</code>: an error occured that cannot be accurately described by any of the other error codes.</li>
<li>0x01 <code>not found</code>: no file with the given hash is stored on the server.  this error code is also used if the hash is malformed or uses an unsupported hash algorithm.</li>
<li>0x02 <code>unknown request type</code>: the <code>type</code> was not recognized by the server.  this allows the protocol to be extended in the future by adding message types.</li>
<li>0x03 <code>batch does not exist</code>: the <code>type</code> was recognized, and the batch unexpectedly does not exist.</li></ul>

<h1 id="additional-explanation" id="additional-explanation">Additional Explanation</h1>

<h2 id="batches" id="batches">Batches</h2>

<p>A batch is a group of messages that represent operations on a single file. A batch is identified by it&#39;s <code>token</code>.</p>

<p>A batch begins with an <code>OPEN</code> request and is followed by any number of <code>READ</code> requests.</p>

<p>If the <code>OPEN</code> request encounters an error, other requests with the same batch token will be ignored.</p>

<p>If other message types are introduced in the future, they will be specified as either introducing a new batch (like <code>OPEN</code>) or being part of an existing batch (like <code>READ</code>).</p>

<h2 id="future-compatibility" id="future-compatibility">Future Compatibility</h2>

<p>future versions of this specification may define new message types.</p>

<p>clients may attempt to use these new message types with any servers, and servers that do not support them MUST respond with error 0x03 <code>unknown request type</code>.</p>

<p>servers MUST NOT respond with new response codes unless the client previously sent a request that indicates that response code is supported (what requests imply support for what responses will be defined in future specifications)</p>

<h1 id="rationale" id="rationale">Rationale</h1>

<p>“batch does not exist” errors are only returned for recognized message types to potentially allow adding new message types that create a batch.</p>

<p>batch tokens are client-assigned so that a client can “pipeline” an <code>OPEN</code> and a <code>READ</code> in a single transmission, reducing round-trip delays.</p>

<p>errors cancel a batch to prevent an error in a large pipelined batch from causing a bunch of error responses.</p>

<p>there is no need to identify which request in a batch caused the error, as properly formed (i.e. part of an <code>OPEN</code>ed batch) <code>READ</code> requests are infallible.  if they were not infallible, a <code>READ ERROR</code> response would exist, which would contain the offset of the read that caused the error.</p>

<p>the server is allowed to respond with short reads to allow for servers that use fixed-size buffers or have limited memory.</p>

<p><code>OPEN</code> requests originally used <code>urn</code>s, but this was changed to multihash after discovering that <code>sha256</code> and <code>md5</code> are not actually in <a href="https://www.iana.org/assignments/urn-namespaces/urn-namespaces.xhtml" rel="nofollow">the list of urn namespaces</a></p>

<p>messages describe their total length to allow new request codes to be added.</p>

<h1 id="errata-2024-11-08" id="errata-2024-11-08">Errata 2024-11-08</h1>
<ul><li>ERROR responses are now encoded as 0x80 instead of 0x83.</li>
<li>clarify tokens are unique within a connection, not across connections.</li></ul>

<h1 id="addendum-2025-01-10" id="addendum-2025-01-10">Addendum 2025-01-10</h1>

<p>All clients and servers are RECOMMENDED to support at least sha2-256.</p>

<p>Before a connection is initiated, both the server address(es) and the hash of the file to download are communicated to the client out-of-band, such as through a <code>magnet:</code> url or similar.  The exact nature of this communication is left up to future specifications.</p>

<hr>

<p><a href="/binarycat/tag:networking" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">networking</span></a></p>

<hr>

<p>You can follow this blog <a href="https://paper.wf/binarycat/feed/" rel="nofollow">via its RSS feed</a> or by searching for <a href="https://paper.wf/@/binarycat@paper.wf" class="u-url mention" rel="nofollow">@<span>binarycat@paper.wf</span></a> on your Mastodon/ActivityPub instance.</p>
]]></content:encoded>
      <guid>https://paper.wf/binarycat/reliable-immutable-transfer-protocol</guid>
      <pubDate>Tue, 05 Nov 2024 20:52:46 +0000</pubDate>
    </item>
    <item>
      <title>Un-Deprecate big</title>
      <link>https://paper.wf/binarycat/un-deprecate-big</link>
      <description>&lt;![CDATA[My Plea to the W3C:&#xA;Giving a semantic meaning to an &#34;Obsolete&#34; element.&#xA;!--more--&#xA;&#xA;I&#39;ll cut right to the chase, here&#39;s my proposal:&#xA;&#xA;span style=&#34;font-size-adjust:0.7;&#34;The big element can be used to represent the &#34;big idea&#34; of a document or section, ie. text that should still be read when skimming through a document/span&#xA;&#xA;Rationale&#xA;&#xA;Why do we make text big?&#xA;&#xA;Well, to answer that, it helps to look at when we make text big.&#xA;&#xA;The vast majority of the time, big text is used as part of a header.&#xA;&#xA;Why do we have headers? well, several reasons, but a big part of it is skimming: looking through a document without reading it fully.  Headers allow you to skim through a document until you find the relevant section.&#xA;&#xA;So, the purpose of font size within prose seems clear: it makes text harder to ignore.  this can also be seen within news articles, where important quotes are often shown as much larger than the surrounding text.&#xA;&#xA;This is similar, yet distinct, from strong and em, which usually convey emphasis within a sentence or paragraph, but which will not do much to grab the attention of someone skimming over an entire document or page.&#xA;&#xA;Parity with small&#xA;&#xA;Unlike big, small was never deprecated.  This seems to be because W3C was able to come up with a semantic meaning for it.&#xA;&#xA;Well, here&#39;s a semantic meaning for big.  Do with it what you will.&#xA;&#xA;-----&#xA;#html #web&#xA;&#xA;--------&#xD;&#xA;&#xD;&#xA;You can follow this blog via its RSS feed or by searching for @binarycat@paper.wf on your Mastodon/ActivityPub instance.]]&gt;</description>
      <content:encoded><![CDATA[<p>My Plea to the W3C:
Giving a semantic meaning to an “Obsolete” element.
</p>

<p>I&#39;ll cut right to the chase, here&#39;s my proposal:</p>

<p><span style="font-size-adjust:0.7;">The <code>&lt;big&gt;</code> element can be used to represent the “big idea” of a document or section, ie. text that should still be read when skimming through a document</span></p>

<h2 id="rationale" id="rationale">Rationale</h2>

<h3 id="why-do-we-make-text-big" id="why-do-we-make-text-big">Why do we make text big?</h3>

<p>Well, to answer that, it helps to look at <em>when</em> we make text big.</p>

<p>The vast majority of the time, big text is used as part of a <em>header</em>.</p>

<p>Why do we have headers? well, several reasons, but a big part of it is <em>skimming</em>: looking through a document without reading it fully.  Headers allow you to skim through a document until you find the relevant section.</p>

<p>So, the purpose of font size within prose seems clear: it makes text harder to ignore.  this can also be seen within news articles, where important quotes are often shown as much larger than the surrounding text.</p>

<p>This is similar, yet distinct, from <code>&lt;strong&gt;</code> and <code>&lt;em&gt;</code>, which usually convey emphasis <em>within</em> a sentence or paragraph, but which will not do much to grab the attention of someone skimming over an entire document or page.</p>

<h3 id="parity-with-small" id="parity-with-small">Parity with <code>&lt;small&gt;</code></h3>

<p>Unlike <code>&lt;big&gt;</code>, <code>&lt;small&gt;</code> was never deprecated.  This seems to be because W3C was able to come up with a semantic meaning for it.</p>

<p>Well, here&#39;s a semantic meaning for <code>&lt;big&gt;</code>.  Do with it what you will.</p>

<hr>

<p><a href="/binarycat/tag:html" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">html</span></a> <a href="/binarycat/tag:web" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">web</span></a></p>

<hr>

<p>You can follow this blog <a href="https://paper.wf/binarycat/feed/" rel="nofollow">via its RSS feed</a> or by searching for <a href="https://paper.wf/@/binarycat@paper.wf" class="u-url mention" rel="nofollow">@<span>binarycat@paper.wf</span></a> on your Mastodon/ActivityPub instance.</p>
]]></content:encoded>
      <guid>https://paper.wf/binarycat/un-deprecate-big</guid>
      <pubDate>Mon, 28 Oct 2024 22:21:36 +0000</pubDate>
    </item>
    <item>
      <title>WriteFreely Draft Blogs</title>
      <link>https://paper.wf/binarycat/writefreely-draft-blogs</link>
      <description>&lt;![CDATA[One simple trick to fix the worst part of the platform.&#xA;!--more--&#xA;WriteFreely has a built in &#34;drafts&#34; feature (write.as calls them &#34;anonymous posts&#34;), but there&#39;s several problems with it:&#xA;when you save a draft and go to the &#34;preview&#34;, it will not use your custom css&#xA;hashtags are inert when used on drafts, which means there&#39;s no way to organize your drafts&#xA;the preview logic is different, so if you use !--more-- to display a &#34;read more&#34; banner, you won&#39;t be able to preview how that looks&#xA;if anyone gains access to the draft url, they can read and share that draft without your permission (this includes webscrapers for search indexes)&#xA;you cannot edit the &#34;slug&#34; of a post while it is a draft&#xA;&#xA;Luckily, WriteFreely also has another feature: private blogs.  Private blogs do not suffer any most (update: this software is a janky mess) of the above problems.&#xA;&#xA;These blogs are only viewable by you, and only when you&#39;re logged in.  As long as your instance allows you to create multiple blogs, you can create a myblog-drafts blog, go to &#34;customize&#34;, select &#34;Private&#34;, then &#34;Save changes&#34;.  After this is done, you can go to you &#34;Drafts&#34; page and move all of your drafts to your draft blog (unfortunately this has to be done one by one).  Any new drafts should be &#34;published&#34; to your draft blog via the dropdown menu in the editor.&#xA;&#xA;Syncing custom css between your main and draft blog&#xA;The simplest solution is to just periodically copy/paste the css from your main blog to your draft blog, but if you want a permanent solution, you can host the stylesheet externally and and use css @import.&#xA;&#xA;Here&#39;s one way to do this using codeberg pages:&#xA;&#xA;create a new repo, let&#39;s call it codeberg.org/myusername/blog-css (you can use any name you want, just make sure to adjust the following steps accordingly).  set the default branch name to pages (technically it doesn&#39;t have to be the default branch, but it will make things easier.).&#xA;either via a local clone or the web ui, create two files in this repo: index.html, which can contain anything but must exist for codeberg pages to activate, and style.css, which contains the custom css for your blog.&#xA;replace the custom css for both blogs with @import url(&#34;https://myusername.codeberg.page/blog-css/style.css&#34;);.  you need to use the codeberg pages url, and not the raw url, otherwise codeberg will serve the file as text/plain instead of text/css.&#xA;save your changes and reload the blogs, they should now be using the same stylesheet.  any future changes to the pages branch will show up on both blogs.&#xA;&#xA;------&#xA;#writefreely #tips #guide&#xA;&#xA;--------&#xD;&#xA;&#xD;&#xA;You can follow this blog via its RSS feed or by searching for @binarycat@paper.wf on your Mastodon/ActivityPub instance.]]&gt;</description>
      <content:encoded><![CDATA[<p>One simple trick to fix the worst part of the platform.

WriteFreely has a built in “drafts” feature (write.as calls them “anonymous posts”), but there&#39;s several problems with it:
1. when you save a draft and go to the “preview”, it will not use your custom css
2. hashtags are inert when used on drafts, which means there&#39;s no way to organize your drafts
3. the preview logic is different, so if you use <code>&lt;!--more--&gt;</code> to display a “read more” banner, you won&#39;t be able to preview how that looks
4. if anyone gains access to the draft url, they can read and share that draft without your permission (this includes webscrapers for search indexes)
5. you cannot edit the “slug” of a post while it is a draft</p>

<p>Luckily, WriteFreely also has another feature: private blogs.  Private blogs do not suffer <del>any</del> <em>most</em> (update: <a href="https://github.com/writefreely/writefreely/issues/1132" rel="nofollow">this software is a janky mess</a>) of the above problems.</p>

<p>These blogs are <em>only</em> viewable by you, and only when you&#39;re logged in.  As long as your instance allows you to create multiple blogs, you can create a <code>myblog-drafts</code> blog, go to “customize”, select “Private”, then “Save changes”.  After this is done, you can go to you “Drafts” page and move all of your drafts to your draft blog (unfortunately this has to be done one by one).  Any new drafts should be “published” to your draft blog via the dropdown menu in the editor.</p>

<h2 id="syncing-custom-css-between-your-main-and-draft-blog" id="syncing-custom-css-between-your-main-and-draft-blog">Syncing custom css between your main and draft blog</h2>

<p>The simplest solution is to just periodically copy/paste the css from your main blog to your draft blog, but if you want a permanent solution, you can host the stylesheet externally and and use css <code>@import</code>.</p>

<p>Here&#39;s one way to do this using <a href="//codeberg.page" rel="nofollow">codeberg pages</a>:</p>
<ol><li>create a new repo, let&#39;s call it <code>codeberg.org/myusername/blog-css</code> (you can use any name you want, just make sure to adjust the following steps accordingly).  set the default branch name to <code>pages</code> (technically it doesn&#39;t have to be the default branch, but it will make things easier.).</li>
<li>either via a local clone or the web ui, create two files in this repo: <code>index.html</code>, which can contain anything but must exist for codeberg pages to activate, and <code>style.css</code>, which contains the custom css for your blog.</li>
<li>replace the custom css for both blogs with <code>@import url(&#34;https://myusername.codeberg.page/blog-css/style.css&#34;);</code>.  you need to use the codeberg pages url, and not the <code>raw</code> url, otherwise codeberg will serve the file as <code>text/plain</code> instead of <code>text/css</code>.</li>
<li>save your changes and reload the blogs, they should now be using the same stylesheet.  any future changes to the <code>pages</code> branch will show up on both blogs.</li></ol>

<hr>

<p><a href="/binarycat/tag:writefreely" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">writefreely</span></a> <a href="/binarycat/tag:tips" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">tips</span></a> <a href="/binarycat/tag:guide" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">guide</span></a></p>

<hr>

<p>You can follow this blog <a href="https://paper.wf/binarycat/feed/" rel="nofollow">via its RSS feed</a> or by searching for <a href="https://paper.wf/@/binarycat@paper.wf" class="u-url mention" rel="nofollow">@<span>binarycat@paper.wf</span></a> on your Mastodon/ActivityPub instance.</p>
]]></content:encoded>
      <guid>https://paper.wf/binarycat/writefreely-draft-blogs</guid>
      <pubDate>Sat, 26 Oct 2024 16:38:00 +0000</pubDate>
    </item>
    <item>
      <title>RTP</title>
      <link>https://paper.wf/binarycat/rtp</link>
      <description>&lt;![CDATA[refining the ideas behind HTTP, BitTorrent, Gemini, and 9p to create a simple protocol for reliably transferring large immutable files.&#xA;!--more--&#xA;(this document is a first draft, and is not intended to be implemented in its current form)&#xA;&#xA;NOTE: this document has been obsolesced by RITP&#xA;&#xA;Goals&#xA;as simple as possible without sacrificing our other goals (less complex than http)&#xA;performs well under poor network conditions, even when payloads are large (unlike gemini)&#xA;performs well under high latency (unlike 9p)&#xA;good single-source performance (unlike BitTorrent)&#xA;&#xA;Non-Goals&#xA;content negotiation (http Accept headers)&#xA;mutable identifiers&#xA;version negotiation&#xA;&#xA;all of these can be trivially handled via an outer protocol (eg. mutable identifiers can be handled with gemini cross-protocol redirects)&#xA;&#xA;Strategies&#xA;a stateful request/response protocol similar to 9p, but with hash-identified urls similar to magnet links (these encode length and content hash)&#xA;&#xA;streams are encoded over tcp, tcp/tls, or quic to ensure reliable delivery.&#xA;&#xA;Notation&#xA;each request has a number of fields.  each field is marked either as a fixed number of bits, or as a &#34;string&#34; field.&#xA;&#xA;&#34;string&#34; fields consist of a 64 bit length value, followed by that many bytes.&#xA;&#xA;&#34;string&#34; fields do not have to be valid utf-8 unless specified.&#xA;&#xA;all integers are little-endian.  note that tokens are not integers, they are opaque client chosen identifiers with a length of 63 bits (followed by a 1 bit flag, which takes the place of the LSB of the final bytes).  servers must take to mask the correct bit.&#xA;&#xA;Requests and Responses&#xA;&#xA;there are 2 request types:&#xA;OPEN&#xA;READ&#xA;&#xA;there are 2 response types:&#xA;OK&#xA;ERROR&#xA;&#xA;each request has the following structure:&#xA;(63 bits) newtoken: a token identifying the results of the request&#xA;(1 bit) requesttype: integer representing type of request&#xA;(n bits) type-dependent fields&#xA;&#xA;each response has the following structure:&#xA;(63 bits) requesttoken: the client-chosen token found in the request that generated this responce&#xA;(1 bit) iserror: set if the corresponding request generated an error (such as the server being unable to find the requested resource)&#xA;(string) payload: if iserror is set, then a human and machine readable UTF-8 string representing an error.  otherwise, its interpretation depends on the type of the request.&#xA;&#xA;OPEN request&#xA;open requests one extra &#34;string&#34; field:&#xA;(string) uri: this field represents the uri of the resource to be downloaded.  what schemes are supported depends on the server, but it is recommended to support at least urn:sha256:* uris.&#xA;&#xA;the payload of non-error responses to OPEN requests is ignored, and SHOULD be empty.&#xA;&#xA;READ request&#xA;read requests have two extra fields:&#xA;(64 bits) offset: at what point to begin reading&#xA;(64 bits) length: the maximum number of payload bytes the server is allowed respond with.&#xA;&#xA;the payload of non-error responses to READ requests MUST be the empty string if and only if offset is greater than or equal to the total number of bytes in the resource, or if length is 0.  if neither of these conditions are met, the payload MUST NOT be the empty string.&#xA;&#xA;when the server generates an error in response to a token, all further READ requests targeted at that token are canceled.  this allows a client to begin sending READ requests before it has received a response to the OPEN request.&#xA;&#xA;URL schemes&#xA;&#xA;rtp&#xA;much like the magnet url scheme, the rtp scheme consists entirly of predefined query parameters:&#xA;&#xA;(one or more) u: the uri/urn of the underlying resource.  can be specified multiple times to specify multiple hashes for the resource (the client is expected to verify the hash, so specifying multiple u allows slowly migrating to a new hash algo).  if multiple values are specified, they must correspond to the same resource.&#xA;(up to one) l: the length of the resource&#xA;(one or more) s: the server(s) that the resource can be retrieved from.  if specified multiple times, the client may choose one, or perform a swarm download from several at once.  these servers take the form of proto!addr!port, for example, tcp!example.com!7777.  (this is based off of plan9 dial strings, since it seems to be the only well-specified way of specifying a method of transport)&#xA;(zero or more) t: list of mime types that the resource may be interpreted as.  clients MAY ignore values other than the first.&#xA;(up to one) v: protocol version.  if not specified, it defaults to version 1, which is the version specified in this document.  clients MUST reject urls with an unrecognized version.&#xA;&#xA;it is RECOMMENDED that every value of u is recognized by every server s.  if a client encounters an error when downloading from one server, it SHOULD try downloading from another server. &#xA;&#xA;clients SHOULD NOT use rtp urls in OPEN requests, instead they should choose a value listed in u.&#xA;&#xA;unrecognized fields SHOULD be ignored.&#xA;&#xA;gemini+rtp&#xA;use the Gemini Protocol in order to implement mutable identifiers.&#xA;&#xA;gemini is used in &#34;proxy mode&#34;, that is, the sent url has a scheme of gemini+rtp and not gemini.  the gemini server then uses a cross-protocol redirect to return an rtp url. &#xA;&#xA;Rationale&#xA;READ.length is defined as a maximum so that clients that do not know the length of the resource they are downloading can use a value of 2^64 - 1 to request as much of the rest of the resource as the server is able to provide.&#xA;&#xA;READ.offset exists both so that downloads can be resumed, and also to allow seeking within complex formats (eg. allowing you do download just one file out of a zip archive).  It also allows doing swarm downloads from multiple equally trusted sources.&#xA;&#xA;Appendix A: error strings&#xA;an error string consists of a machine readable string representing the kind of error, optionally followed by a colon, and then a human-readable string further clarifying the error.&#xA;&#xA;the following predefined error strings:&#xA;error: a generic error kind usable when nothing else is applicaple&#xA;not found: no resource with the given uri is known to the server.&#xA;unsupported scheme: the given uri or urn scheme is not supported&#xA;&#xA;Errata 2024-10-28&#xA;READ needs an additional field, opentoken, which corresponds to the the request_token of an OPEN request.&#xA;RTP is commonly used as an abbreviation for the Real-time Transport Protocol, and is not descriptive enough.&#xA;this is a protocol for reliably downloading large files.  it is not designed to be a drop in replacement for http or BitTorrent.&#xA;&#xA;I am currently drafting a successor proposal that addresses these issues.&#xA;&#xA;-----&#xA;#networking #programming&#xA;&#xA;--------&#xD;&#xA;&#xD;&#xA;You can follow this blog via its RSS feed or by searching for @binarycat@paper.wf on your Mastodon/ActivityPub instance.]]&gt;</description>
      <content:encoded><![CDATA[<p>refining the ideas behind HTTP, BitTorrent, Gemini, and 9p to create a simple protocol for reliably transferring large immutable files.

(this document is a first draft, and is not intended to be implemented in its current form)</p>

<p>NOTE: this document has been obsolesced by <a href="https://paper.wf/binarycat/reliable-immutable-transfer-protocol" rel="nofollow">RITP</a></p>

<h1 id="goals" id="goals">Goals</h1>
<ol><li>as simple as possible without sacrificing our other goals (less complex than http)</li>
<li>performs well under poor network conditions, even when payloads are large (unlike gemini)</li>
<li>performs well under high latency (unlike 9p)</li>
<li>good single-source performance (unlike BitTorrent)</li></ol>

<h1 id="non-goals" id="non-goals">Non-Goals</h1>
<ol><li>content negotiation (http Accept headers)</li>
<li>mutable identifiers</li>
<li>version negotiation</li></ol>

<p>all of these can be trivially handled via an outer protocol (eg. mutable identifiers can be handled with gemini cross-protocol redirects)</p>

<h1 id="strategies" id="strategies">Strategies</h1>

<p>a stateful request/response protocol similar to 9p, but with hash-identified urls similar to magnet links (these encode length and content hash)</p>

<p>streams are encoded over tcp, tcp/tls, or quic to ensure reliable delivery.</p>

<h1 id="notation" id="notation">Notation</h1>

<p>each request has a number of fields.  each field is marked either as a fixed number of bits, or as a “string” field.</p>

<p>“string” fields consist of a 64 bit length value, followed by that many bytes.</p>

<p>“string” fields do not have to be valid utf-8 unless specified.</p>

<p>all integers are little-endian.  note that tokens are <em>not</em> integers, they are opaque client chosen identifiers with a length of 63 bits (followed by a 1 bit flag, which takes the place of the LSB of the final bytes).  servers must take to mask the correct bit.</p>

<h1 id="requests-and-responses" id="requests-and-responses">Requests and Responses</h1>

<p>there are 2 request types:
* OPEN
* READ</p>

<p>there are 2 response types:
* OK
* ERROR</p>

<p>each request has the following structure:
* (63 bits) <code>new_token</code>: a token identifying the results of the request
* (1 bit) <code>request_type</code>: integer representing type of request
* (n bits) type-dependent fields</p>

<p>each response has the following structure:
* (63 bits) <code>request_token</code>: the client-chosen token found in the request that generated this responce
* (1 bit) <code>is_error</code>: set if the corresponding request generated an error (such as the server being unable to find the requested resource)
* (string) <code>payload</code>: if <code>is_error</code> is set, then a human and machine readable UTF-8 string representing an error.  otherwise, its interpretation depends on the type of the request.</p>

<h2 id="open-request" id="open-request">OPEN request</h2>

<p>open requests one extra “string” field:
* (string) <code>uri</code>: this field represents the uri of the resource to be downloaded.  what schemes are supported depends on the server, but it is recommended to support at least <code>urn:sha256:*</code> uris.</p>

<p>the <code>payload</code> of non-error responses to OPEN requests is ignored, and SHOULD be empty.</p>

<h2 id="read-request" id="read-request">READ request</h2>

<p>read requests have two extra fields:
* (64 bits) offset: at what point to begin reading
* (64 bits) length: the maximum number of payload bytes the server is allowed respond with.</p>

<p>the <code>payload</code> of non-error responses to <code>READ</code> requests MUST be the empty string if and only if <code>offset</code> is greater than or equal to the total number of bytes in the resource, or if <code>length</code> is 0.  if neither of these conditions are met, the <code>payload</code> MUST NOT be the empty string.</p>

<p>when the server generates an error in response to a token, all further <code>READ</code> requests targeted at that token are canceled.  this allows a client to begin sending READ requests before it has received a response to the OPEN request.</p>

<h2 id="url-schemes" id="url-schemes">URL schemes</h2>

<h2 id="rtp" id="rtp"><code>rtp</code></h2>

<p>much like the <code>magnet</code> url scheme, the <code>rtp</code> scheme consists entirly of predefined query parameters:</p>
<ul><li>(one or more) <code>u</code>: the uri/urn of the underlying resource.  can be specified multiple times to specify multiple hashes for the resource (the client is expected to verify the hash, so specifying multiple <code>u</code> allows slowly migrating to a new hash algo).  if multiple values are specified, they must correspond to the same resource.</li>
<li>(up to one) <code>l</code>: the length of the resource</li>
<li>(one or more) <code>s</code>: the server(s) that the resource can be retrieved from.  if specified multiple times, the client may choose one, or perform a swarm download from several at once.  these servers take the form of <code>proto!addr!port</code>, for example, <code>tcp!example.com!7777</code>.  (this is based off of plan9 dial strings, since it seems to be the only well-specified way of specifying a method of transport)</li>
<li>(zero or more) <code>t</code>: list of mime types that the resource may be interpreted as.  clients MAY ignore values other than the first.</li>
<li>(up to one) <code>v</code>: protocol version.  if not specified, it defaults to version <code>1</code>, which is the version specified in this document.  clients MUST reject urls with an unrecognized version.</li></ul>

<p>it is RECOMMENDED that every value of <code>u</code> is recognized by every server <code>s</code>.  if a client encounters an error when downloading from one server, it SHOULD try downloading from another server.</p>

<p>clients SHOULD NOT use <code>rtp</code> urls in <code>OPEN</code> requests, instead they should choose a value listed in <code>u</code>.</p>

<p>unrecognized fields SHOULD be ignored.</p>

<h2 id="gemini-rtp" id="gemini-rtp"><code>gemini+rtp</code></h2>

<p>use the <a href="https://geminiprotocol.net/" rel="nofollow">Gemini Protocol</a> in order to implement mutable identifiers.</p>

<p>gemini is used in “proxy mode”, that is, the sent url has a scheme of <code>gemini+rtp</code> and not <code>gemini</code>.  the gemini server then uses a cross-protocol redirect to return an <code>rtp</code> url.</p>

<h2 id="rationale" id="rationale">Rationale</h2>

<p><code>READ.length</code> is defined as a maximum so that clients that do not know the length of the resource they are downloading can use a value of <code>2^64 - 1</code> to request as much of the rest of the resource as the server is able to provide.</p>

<p><code>READ.offset</code> exists both so that downloads can be resumed, and also to allow seeking within complex formats (eg. allowing you do download just one file out of a zip archive).  It also allows doing swarm downloads from multiple equally trusted sources.</p>

<h1 id="appendix-a-error-strings" id="appendix-a-error-strings">Appendix A: error strings</h1>

<p>an error string consists of a machine readable string representing the kind of error, optionally followed by a colon, and then a human-readable string further clarifying the error.</p>

<p>the following predefined error strings:
* <code>error</code>: a generic error kind usable when nothing else is applicaple
* <code>not found</code>: no resource with the given uri is known to the server.
* <code>unsupported scheme</code>: the given uri or urn scheme is not supported</p>

<h1 id="errata-2024-10-28" id="errata-2024-10-28">Errata 2024-10-28</h1>
<ol><li><code>READ</code> needs an additional field, <code>open_token</code>, which corresponds to the the <code>request_token</code> of an <code>OPEN</code> request.</li>
<li><code>RTP</code> is commonly used as an abbreviation for the Real-time Transport Protocol, and is not descriptive enough.</li>
<li>this is a protocol for reliably downloading large files.  it is not designed to be a drop in replacement for http or BitTorrent.</li></ol>

<p>I am currently drafting a successor proposal that addresses these issues.</p>

<hr>

<p><a href="/binarycat/tag:networking" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">networking</span></a> <a href="/binarycat/tag:programming" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">programming</span></a></p>

<hr>

<p>You can follow this blog <a href="https://paper.wf/binarycat/feed/" rel="nofollow">via its RSS feed</a> or by searching for <a href="https://paper.wf/@/binarycat@paper.wf" class="u-url mention" rel="nofollow">@<span>binarycat@paper.wf</span></a> on your Mastodon/ActivityPub instance.</p>
]]></content:encoded>
      <guid>https://paper.wf/binarycat/rtp</guid>
      <pubDate>Fri, 25 Oct 2024 18:47:59 +0000</pubDate>
    </item>
    <item>
      <title>Bookmark Keywords</title>
      <link>https://paper.wf/binarycat/bookmark-keywords</link>
      <description>&lt;![CDATA[Firefox&#39;s best-kept secret feature.&#xA;&#xA;When you bookmark a page, firefox opens an editor with the following options:&#xA;Name&#xA;Location&#xA;Tags&#xA;&#xA;But there&#39;s actually a secret fourth field...&#xA;!--more--&#xA;&#xA;The Other &#34;Edit Bookmark&#34; menu&#xA;there are two ways of editing a bookmark:&#xA;going to the bookmarked page and clicking the star icon (this is the same menu that shows up when you first create a bookmark)&#xA;the &#34;Edit Bookmark...&#34; context menu option (this has the same fields as the &#34;Manage Bookmarks&#34; view)&#xA;&#xA;turns out, there&#39;s actually some fields that are exclusive to one or the other&#xA;&#xA;Location&#xA;Turns out, this is only shows up in the first menu, I guess because you&#39;re expected to drag and drop bookmarks to move them around otherwise&#xA;&#xA;Confusingly, in the &#34;Manage Bookmarks&#34; view, the URL column is labeled as &#34;Location&#34;.&#xA;&#xA;URL&#xA;Only available in the second menu, allows you to change the specific page that is bookmarked.&#xA;&#xA;Keyword&#xA;This is the exciting one, and its hidden behind the second menu.&#xA;&#xA;If you give a bookmark a keyword, you can navigate to the bookmarked page just by typing that keyword into the navigation bar and hitting enter.&#xA;&#xA;This is useful if you have certain pages you access very often, especially if they are not at the domain root.  For example, I have &#34;ns&#34; set to link to The Nightly Rust Standard Library Documentation, which is otherwise annoyingly requires typing out the domain name, and two path elements. &#xA;&#xA;-----&#xA;&#xA;#firefox #tips&#xA;&#xA;--------&#xD;&#xA;&#xD;&#xA;You can follow this blog via its RSS feed or by searching for @binarycat@paper.wf on your Mastodon/ActivityPub instance.]]&gt;</description>
      <content:encoded><![CDATA[<p>Firefox&#39;s best-kept secret feature.</p>

<p>When you bookmark a page, firefox opens an editor with the following options:
* Name
* Location
* Tags</p>

<p>But there&#39;s actually a secret fourth field...
</p>

<h1 id="the-other-edit-bookmark-menu" id="the-other-edit-bookmark-menu">The Other “Edit Bookmark” menu</h1>

<p>there are two ways of editing a bookmark:
1. going to the bookmarked page and clicking the star icon (this is the same menu that shows up when you first create a bookmark)
2. the “Edit Bookmark...” context menu option (this has the same fields as the “Manage Bookmarks” view)</p>

<p>turns out, there&#39;s actually some fields that are exclusive to one or the other</p>

<h2 id="location" id="location">Location</h2>

<p>Turns out, this is only shows up in the first menu, I guess because you&#39;re expected to drag and drop bookmarks to move them around otherwise</p>

<p>Confusingly, in the “Manage Bookmarks” view, the URL column is labeled as “Location”.</p>

<h2 id="url" id="url">URL</h2>

<p>Only available in the second menu, allows you to change the specific page that is bookmarked.</p>

<h2 id="keyword" id="keyword">Keyword</h2>

<p>This is the exciting one, and its hidden behind the second menu.</p>

<p>If you give a bookmark a keyword, you can navigate to the bookmarked page just by typing that keyword into the navigation bar and hitting enter.</p>

<p>This is useful if you have certain pages you access very often, especially if they are not at the domain root.  For example, I have “ns” set to link to <a href="https://doc.rust-lang.org/nightly/std/" rel="nofollow">The Nightly Rust Standard Library Documentation</a>, which is otherwise annoyingly requires typing out the domain name, and two path elements.</p>

<hr>

<p><a href="/binarycat/tag:firefox" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">firefox</span></a> <a href="/binarycat/tag:tips" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">tips</span></a></p>

<hr>

<p>You can follow this blog <a href="https://paper.wf/binarycat/feed/" rel="nofollow">via its RSS feed</a> or by searching for <a href="https://paper.wf/@/binarycat@paper.wf" class="u-url mention" rel="nofollow">@<span>binarycat@paper.wf</span></a> on your Mastodon/ActivityPub instance.</p>
]]></content:encoded>
      <guid>https://paper.wf/binarycat/bookmark-keywords</guid>
      <pubDate>Thu, 24 Oct 2024 15:12:03 +0000</pubDate>
    </item>
    <item>
      <title>a protocol for reliable notifications over a 1 bit fallible connection.</title>
      <link>https://paper.wf/binarycat/a-protocol-for-reliable-notifications-over-a-1-bit-fallible-connection</link>
      <description>&lt;![CDATA[What&#xA;&#xA;imagine you have two devices, a client and a server, connected in a peculiar way:&#xA;&#xA;the server cannot send messages to the client without the client asking for them&#xA;there are two channels, a request on one channel can only be responded to on the same channel&#xA;the first channel has infinite bandwith and is perfectly reliable, but each message is obscenely expensive.&#xA;the second channel is free, but can only send messages with a single payload bit, and the message has a 50% chance of being dropped&#xA;&#xA;You&#39;ve just been tasked with building a layer on top of this so that the server can send messages to the client, what do you do?&#xA;&#xA;!--more--&#xA;[DISCLAIMER: read the errata section before you go out and implement this]&#xA;How&#xA;&#xA;Informal&#xA;&#xA;the client sends 1-bit tokens.  when the server receives that token, if it has generated new messages since it last sent that token, it responds with the boolean negation of that token.&#xA;&#xA;the client always sends the last token it received.  when it receives a token that is different from the one it sent, it retrieves a message from the side channel. &#xA;&#xA;Formal&#xA;&#xA;When the system start up, the devices initialize themselves to the following state:&#xA;the client sets it&#39;s clienttoken variable to false.&#xA;the server has an empty message queue&#xA;the server sets its servertoken to false, and newmessages to false.&#xA;&#xA;the client periodically sends its clienttoken value along the unreliable channel.&#xA;&#xA;when the server receives clienttoken, it performs the following operation:&#xA;&#xA;if clienttoken = servertoken then&#xA;  set newmessages false&#xA;end if&#xA;&#xA;it then responds with servertoken.&#xA;&#xA;whenever the server generates a new message, it performs the following operation:&#xA;&#xA;if not newmessages then&#xA;  set servertoken (not servertoken)&#xA;  set newmessages true&#xA;end if&#xA;&#xA;when the client receives servertoken, it performs the following operation:&#xA;&#xA;if servertoken ≠ clienttoken then&#xA;  pull messages&#xA;  set clienttoken servertoken&#xA;&#xA;Why&#xA;&#xA;turns out this absurd hypothetical isn&#39;t actually that far off of how TCP+TLS and UDP behave, especially in the context of mobile and embedded devices.&#xA;&#xA;this system also has the nice property that the 1-bit messages don&#39;t depend on the side-channel messages, useful if there are actually multiple clients, and perhaps multiple secure servers the client wants to be able to receive messages from, and the presence of new messages is multiplexed through a single unsecured server.&#xA;&#xA;Errata 2024-10-25: one bit isn&#39;t enough, but two is&#xA;as shown here, using a single bit means the server can&#39;t tell the difference between a client sending the previous token and the next token.&#xA;&#xA;however, if you replace the 1-bit bools with 2-bit unsigned integers, and replace the negation with a wrapping increment, the protocol works as intended.&#xA;&#xA;additionally, i should have added a timing requirement to the infallible channel, otherwise long polling is a simpler and equally valid solution to the posed problem.&#xA;&#xA;------------&#xA;&#xA;#networking #programming&#xA;&#xA;--------&#xD;&#xA;&#xD;&#xA;You can follow this blog via its RSS feed or by searching for @binarycat@paper.wf on your Mastodon/ActivityPub instance.]]&gt;</description>
      <content:encoded><![CDATA[<h2 id="what" id="what">What</h2>

<p>imagine you have two devices, a client and a server, connected in a peculiar way:</p>
<ol><li>the server cannot send messages to the client without the client asking for them</li>
<li>there are two channels, a request on one channel can only be responded to on the same channel</li>
<li>the first channel has infinite bandwith and is perfectly reliable, but each message is obscenely expensive.</li>
<li>the second channel is free, but can only send messages with a single payload bit, and the message has a 50% chance of being dropped</li></ol>

<p>You&#39;ve just been tasked with building a layer on top of this so that the server can send messages to the client, what do you do?</p>



<p>[DISCLAIMER: read the errata section before you go out and implement this]</p>

<h2 id="how" id="how">How</h2>

<h3 id="informal" id="informal">Informal</h3>

<p>the client sends 1-bit tokens.  when the server receives that token, if it has generated new messages since it last sent that token, it responds with the boolean negation of that token.</p>

<p>the client always sends the last token it received.  when it receives a token that is different from the one it sent, it retrieves a message from the side channel.</p>

<h3 id="formal" id="formal">Formal</h3>

<p>When the system start up, the devices initialize themselves to the following state:
1. the client sets it&#39;s <code>client_token</code> variable to <code>false</code>.
2. the server has an empty message queue
3. the server sets its <code>server_token</code> to false, and <code>new_messages</code> to false.</p>

<p>the client periodically sends its <code>client_token</code> value along the unreliable channel.</p>

<p>when the server receives <code>client_token</code>, it performs the following operation:</p>

<pre><code>if client_token = server_token then
  set new_messages false
end if
</code></pre>

<p>it then responds with <code>server_token</code>.</p>

<p>whenever the server generates a new message, it performs the following operation:</p>

<pre><code>if not new_messages then
  set server_token (not server_token)
  set new_messages true
end if
</code></pre>

<p>when the client receives <code>server_token</code>, it performs the following operation:</p>

<pre><code>if server_token ≠ client_token then
  pull messages
  set client_token server_token
</code></pre>

<h2 id="why" id="why">Why</h2>

<p>turns out this absurd hypothetical isn&#39;t actually that far off of how TCP+TLS and UDP behave, especially in the context of mobile and embedded devices.</p>

<p>this system also has the nice property that the 1-bit messages don&#39;t depend on the side-channel messages, useful if there are actually multiple clients, and perhaps multiple secure servers the client wants to be able to receive messages from, and the presence of new messages is multiplexed through a single unsecured server.</p>

<h1 id="errata-2024-10-25-one-bit-isn-t-enough-but-two-is" id="errata-2024-10-25-one-bit-isn-t-enough-but-two-is">Errata 2024-10-25: one bit isn&#39;t enough, but two is</h1>

<p>as shown <a href="https://pastebin.com/0Zs1pRfR" rel="nofollow">here</a>, using a single bit means the server can&#39;t tell the difference between a client sending the previous token and the next token.</p>

<p>however, if you replace the 1-bit bools with 2-bit unsigned integers, and replace the negation with a wrapping increment, the protocol works as intended.</p>

<p>additionally, i should have added a timing requirement to the infallible channel, otherwise long polling is a simpler and equally valid solution to the posed problem.</p>

<hr>

<p><a href="/binarycat/tag:networking" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">networking</span></a> <a href="/binarycat/tag:programming" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">programming</span></a></p>

<hr>

<p>You can follow this blog <a href="https://paper.wf/binarycat/feed/" rel="nofollow">via its RSS feed</a> or by searching for <a href="https://paper.wf/@/binarycat@paper.wf" class="u-url mention" rel="nofollow">@<span>binarycat@paper.wf</span></a> on your Mastodon/ActivityPub instance.</p>
]]></content:encoded>
      <guid>https://paper.wf/binarycat/a-protocol-for-reliable-notifications-over-a-1-bit-fallible-connection</guid>
      <pubDate>Fri, 04 Oct 2024 03:20:45 +0000</pubDate>
    </item>
    <item>
      <title>Cursed Rust</title>
      <link>https://paper.wf/binarycat/cursed-rust</link>
      <description>&lt;![CDATA[Rust is a language with a lot of features.  Sometimes those features have rough edges.  Sometimes those rough edges are funny.  Let&#39;s look at some.&#xA;!--more--&#xA;&#xA;Copy and Clone can diverge&#xA;&#xA;[derive(Debug)]&#xA;struct OhNo(u32);&#xA;&#xA;impl Clone for OhNo {&#xA;    fn clone(&amp;self) -  Self {&#xA;        OhNo(self.0 + 1)&#xA;    }&#xA;}&#xA;&#xA;impl Copy for OhNo { }&#xA;&#xA;fn main() {&#xA;    let oh = OhNo(3);&#xA;    dbg!(oh.clone());&#xA;    dbg!(oh);&#xA;}&#xA;&#xA;Even worse, according to the docs, this isn&#39;t even a logic error, unlike inconsistent implementations of PartialOrd and Ord&#xA;&#xA;Really long place expression&#xA;&#xA;a place expression is an expression you can take the address of.&#xA;&#xA;turns out if statements are place expressions.  this is so obscure that not even the reference knows this, despite it being true since rust 1.0&#xA;&#xA;fn main() {&#xA;    let arr = [10, 20];&#xA;    let arrref = &amp;if true {&#xA;        arr[0]&#xA;    } else {&#xA;        arr[1]&#xA;    };&#xA;    dbg!(arrref)&#xA;}&#xA;&#xA;krate vs crate&#xA;t-compiler says to use krate, t-style says to use crate&#xA;&#xA;sidenote: how many of you have actually read the style guide? how many actually know that it exists?&#xA;&#xA;Rust has reference variables! kinda..&#xA;&#xA;use std::cell::Cell;&#xA;&#xA;fn main() {&#xA;    let x = Cell::new(1);&#xA;    let ref y = x;&#xA;    x.set(2);&#xA;    let ref z = x;&#xA;    asserteq!(y, z);&#xA;}&#xA;&#xA;This is mostly just silly.&#xA;&#xA;&amp; is actually useful&#xA;previous entries are here because they are weird and obscure. &amp; is here because it is actually useful and meaningful, despite the fact that it would be a very silly no-op in most languages.&#xA;&#xA;invoking Deref without importing the trait&#xA;reborrowing a mutable reference as shared&#xA;turning raw pointers into references&#xA;&#xA;Addendum: it&#39;s not just if&#xA;A reader asked me if a loop + break could also be a place expression.  I thought do myself &#34;well obviously that won&#39;t work&#34;, before testing it out and realizing in horror that it does:&#xA;&#xA;fn main() {&#xA;    let arr = [10, 20];&#xA;    let arrref = &amp;loop { break arr[0]; };&#xA;    dbg!(arrref);&#xA;}&#xA;&#xA;now this is weird.&#xA;&#xA;Errata 2024-10-08: temporary lifetime extension is complicated&#xA;&#xA;if is not a place expression. I was under the impression that the previous examples would not work unless it was, but actually my understanding of temporary lifetime extension is simply incomplete.&#xA;&#xA;Addendum 2024-11-05: + is overloaded on strings&#xA;rust typically avoids C++ style operator overloading, favoring the haskell style of always having operators represent the same semantic operation.&#xA;&#xA;nonetheless, you can use + for string concatenation, and you can use += as an alternative to pushstr.&#xA;&#xA;Addendum 2024-11-08: Calling methods of unnameable traits &#xA;Ever wanted an api that&#39;s impossible to use without glob imports? well now you can!&#xA;&#xA;mod greetext {&#xA;    mod inner {&#xA;        pub trait GreetExt {&#xA;            fn greet(&amp;self);&#xA;        }&#xA;        &#xA;        implT GreetExt for T {&#xA;            fn greet(&amp;self) {&#xA;                println!(&#34;hello, world!&#34;);&#xA;            }&#xA;        }&#xA;    }&#xA;    pub use inner::GreetExt as ;&#xA;}&#xA;&#xA;pub use greet_ext::*;&#xA;&#xA;fn main() {&#xA;    1.greet();&#xA;}&#xA;&#xA;-----&#xA;&#xA;#rust #programming&#xA;&#xA;--------&#xD;&#xA;&#xD;&#xA;You can follow this blog via its RSS feed or by searching for @binarycat@paper.wf on your Mastodon/ActivityPub instance.]]&gt;</description>
      <content:encoded><![CDATA[<p>Rust is a language with a lot of features.  Sometimes those features have rough edges.  Sometimes those rough edges are funny.  Let&#39;s look at some.
</p>

<h2 id="copy-and-clone-can-diverge" id="copy-and-clone-can-diverge"><code>Copy</code> and <code>Clone</code> can diverge</h2>

<pre><code class="language-rust">#[derive(Debug)]
struct OhNo(u32);

impl Clone for OhNo {
    fn clone(&amp;self) -&gt; Self {
        OhNo(self.0 + 1)
    }
}

impl Copy for OhNo { }

fn main() {
    let oh = OhNo(3);
    dbg!(oh.clone());
    dbg!(oh);
}
</code></pre>

<p>Even worse, <a href="https://doc.rust-lang.org/1.81.0/std/marker/trait.Copy.html" rel="nofollow">according to the docs</a>, this isn&#39;t even a logic error, unlike inconsistent implementations of <a href="https://doc.rust-lang.org/1.81.0/std/cmp/trait.PartialOrd.html" rel="nofollow"><code>PartialOrd</code></a> and <a href="https://doc.rust-lang.org/1.81.0/std/cmp/trait.Ord.html" rel="nofollow"><code>Ord</code></a></p>

<h2 id="really-long-place-expression" id="really-long-place-expression">Really long <del>place</del> expression</h2>

<p>a <a href="https://doc.rust-lang.org/reference/expressions.html#place-expressions-and-value-expressions" rel="nofollow">place expression</a> is an expression you can take the address of.</p>

<p><del>turns out <code>if</code> statements are place expressions.  this is so obscure that not even the reference knows this, despite it being true since rust 1.0</del></p>

<pre><code class="language-rust">fn main() {
    let arr = [10, 20];
    let arr_ref = &amp;if true {
        arr[0]
    } else {
        arr[1]
    };
    dbg!(arr_ref)
}
</code></pre>

<h2 id="krate-vs-crate" id="krate-vs-crate">krate vs crate_</h2>

<p><a href="https://rustc-dev-guide.rust-lang.org/conventions.html" rel="nofollow">t-compiler says to use <code>krate</code></a>, <a href="https://doc.rust-lang.org/stable/style-guide/items.html" rel="nofollow">t-style says to use <code>crate_</code></a></p>

<p>sidenote: how many of you have actually read the style guide? how many actually know that it exists?</p>

<h2 id="rust-has-reference-variables-kinda" id="rust-has-reference-variables-kinda">Rust has reference variables! kinda..</h2>

<pre><code class="language-rust">use std::cell::Cell;

fn main() {
    let x = Cell::new(1);
    let ref y = x;
    x.set(2);
    let ref z = x;
    assert_eq!(y, z);
}
</code></pre>

<p>This is mostly just silly.</p>

<h2 id="is-actually-useful" id="is-actually-useful"><code>&amp;*</code> is actually useful</h2>

<p>previous entries are here because they are weird and obscure. <code>&amp;*</code> is here because it is actually useful and meaningful, despite the fact that it would be a very silly no-op in most languages.</p>
<ul><li>invoking <code>Deref</code> without importing the trait</li>
<li>reborrowing a mutable reference as shared</li>
<li>turning raw pointers into references</li></ul>

<h2 id="addendum-it-s-not-just-if" id="addendum-it-s-not-just-if">Addendum: it&#39;s not just if</h2>

<p>A reader asked me if a <code>loop</code> + <code>break</code> could also be a place expression.  I thought do myself “well obviously <em>that</em> won&#39;t work”, before testing it out and realizing in horror that it does:</p>

<pre><code class="language-rust">fn main() {
    let arr = [10, 20];
    let arr_ref = &amp;loop { break arr[0]; };
    dbg!(arr_ref);
}
</code></pre>

<p>now this is weird.</p>

<h2 id="errata-2024-10-08-temporary-lifetime-extension-is-complicated" id="errata-2024-10-08-temporary-lifetime-extension-is-complicated">Errata 2024-10-08: temporary lifetime extension is complicated</h2>

<p><code>if</code> is not a place expression. I was under the impression that the previous examples would not work unless it was, but actually my understanding of temporary lifetime extension is simply incomplete.</p>

<h2 id="addendum-2024-11-05-is-overloaded-on-strings" id="addendum-2024-11-05-is-overloaded-on-strings">Addendum 2024-11-05: + is overloaded on strings</h2>

<p>rust typically avoids C++ style operator overloading, favoring the haskell style of always having operators represent the same semantic operation.</p>

<p>nonetheless, <a href="https://doc.rust-lang.org/nightly/std/string/struct.String.html#method.add" rel="nofollow">you can use <code>+</code> for string concatenation</a>, and you can use <code>+=</code> as an alternative to <code>push_str</code>.</p>

<h2 id="addendum-2024-11-08-calling-methods-of-unnameable-traits" id="addendum-2024-11-08-calling-methods-of-unnameable-traits">Addendum 2024-11-08: Calling methods of unnameable traits</h2>

<p>Ever wanted an api that&#39;s <em>impossible</em> to use without glob imports? well now you can!</p>

<pre><code>mod greet_ext {
    mod inner {
        pub trait GreetExt {
            fn greet(&amp;self);
        }
        
        impl&lt;T&gt; GreetExt for T {
            fn greet(&amp;self) {
                println!(&#34;hello, world!&#34;);
            }
        }
    }
    pub use inner::GreetExt as _;
}

pub use greet_ext::*;

fn main() {
    1.greet();
}
</code></pre>

<hr>

<p><a href="/binarycat/tag:rust" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">rust</span></a> <a href="/binarycat/tag:programming" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">programming</span></a></p>

<hr>

<p>You can follow this blog <a href="https://paper.wf/binarycat/feed/" rel="nofollow">via its RSS feed</a> or by searching for <a href="https://paper.wf/@/binarycat@paper.wf" class="u-url mention" rel="nofollow">@<span>binarycat@paper.wf</span></a> on your Mastodon/ActivityPub instance.</p>
]]></content:encoded>
      <guid>https://paper.wf/binarycat/cursed-rust</guid>
      <pubDate>Thu, 03 Oct 2024 21:04:57 +0000</pubDate>
    </item>
  </channel>
</rss>