speice.io/2018/01/captains-cookbook-part-2/index.html

75 lines
76 KiB
HTML
Raw Permalink Normal View History

<!doctype html><html lang=en dir=ltr class="blog-wrapper blog-post-page plugin-blog plugin-id-default" data-has-hydrated=false><meta charset=UTF-8><meta name=generator content="Docusaurus v3.6.0"><title data-rh=true>Captain's Cookbook: Practical usage | The Old Speice Guy</title><meta data-rh=true name=viewport content="width=device-width,initial-scale=1.0"><meta data-rh=true name=twitter:card content=summary_large_image><meta data-rh=true property=og:url content=https://speice.io/2018/01/captains-cookbook-part-2><meta data-rh=true property=og:locale content=en><meta data-rh=true name=docusaurus_locale content=en><meta data-rh=true name=docusaurus_tag content=default><meta data-rh=true name=docsearch:language content=en><meta data-rh=true name=docsearch:docusaurus_tag content=default><meta data-rh=true property=og:title content="Captain's Cookbook: Practical usage | The Old Speice Guy"><meta data-rh=true name=description content="A look at more practical usages of Cap'N Proto"><meta data-rh=true property=og:description content="A look at more practical usages of Cap'N Proto"><meta data-rh=true property=og:type content=article><meta data-rh=true property=article:published_time content=2018-01-16T13:00:00.000Z><link data-rh=true rel=icon href=/img/favicon.ico><link data-rh=true rel=canonical href=https://speice.io/2018/01/captains-cookbook-part-2><link data-rh=true rel=alternate href=https://speice.io/2018/01/captains-cookbook-part-2 hreflang=en><link data-rh=true rel=alternate href=https://speice.io/2018/01/captains-cookbook-part-2 hreflang=x-default><script data-rh=true type=application/ld+json>{"@context":"https://schema.org","@id":"https://speice.io/2018/01/captains-cookbook-part-2","@type":"BlogPosting","author":{"@type":"Person","name":"Bradlee Speice"},"dateModified":"2024-11-10T01:23:31.000Z","datePublished":"2018-01-16T13:00:00.000Z","description":"A look at more practical usages of Cap'N Proto","headline":"Captain's Cookbook: Practical usage","isPartOf":{"@id":"https://speice.io/","@type":"Blog","name":"Blog"},"keywords":[],"mainEntityOfPage":"https://speice.io/2018/01/captains-cookbook-part-2","name":"Captain's Cookbook: Practical usage","url":"https://speice.io/2018/01/captains-cookbook-part-2"}</script><link rel=alternate type=application/rss+xml href=/rss.xml title="The Old Speice Guy RSS Feed"><link rel=alternate type=application/atom+xml href=/atom.xml title="The Old Speice Guy Atom Feed"><link rel=stylesheet href=https://cdn.jsdelivr.net/npm/katex@0.13.24/dist/katex.min.css integrity=sha384-odtC+0UGzzFL/6PNoE8rX/SPcQDXBJ+uRepguP4QkPCm2LBxH3FA3y+fKSiJ+AmM crossorigin><link rel=stylesheet href=/assets/css/styles.ae6ff4a3.css><script src=/assets/js/runtime~main.751b419d.js defer></script><script src=/assets/js/main.62ce6156.js defer></script><body class=navigation-with-keyboard><script>!function(){var t,e=function(){try{return new URLSearchParams(window.location.search).get("docusaurus-theme")}catch(t){}}()||function(){try{return window.localStorage.getItem("theme")}catch(t){}}();t=null!==e?e:"light",document.documentElement.setAttribute("data-theme",t)}(),function(){try{for(var[t,e]of new URLSearchParams(window.location.search).entries())if(t.startsWith("docusaurus-data-")){var a=t.replace("docusaurus-data-","data-");document.documentElement.setAttribute(a,e)}}catch(t){}}()</script><div id=__docusaurus><div role=region aria-label="Skip to main content"><a class=skipToContent_fXgn href=#__docusaurus_skipToContent_fallback>Skip to main content</a></div><nav aria-label=Main class="navbar navbar--fixed-top"><div class=navbar__inner><div class=navbar__items><button aria-label="Toggle navigation bar" aria-expanded=false class="navbar__toggle clean-btn" type=button><svg width=30 height=30 viewBox="0 0 30 30" aria-hidden=true><path stroke=currentColor stroke-linecap=round stroke-miterlimit=10 stroke-width=2 d="M4 7h22M4 15h22M4 23h22"/></svg></button><a class=navbar__brand href=/><div class=navbar__logo><img src=/img/logo.svg alt="Sierpinski Gasket" class="themedComponent_mlkZ themedComponent--light_NVdE"><img src=
<p><a href=/2018/01/captains-cookbook-part-1>Part 1</a> of this series took a look at a basic starting project
with Cap'N Proto. In this section, we're going to take the (admittedly basic) schema and look at how we can add a pretty
basic feature - sending Cap'N Proto messages between threads. It's nothing complex, but I want to make sure that there's
some documentation surrounding practical usage of the library.</p>
<p>As a quick refresher, we build a Cap'N Proto message and go through the serialization/deserialization steps
<a href=https://github.com/bspeice/capnp_cookbook_1/blob/master/src/main.rs target=_blank rel="noopener noreferrer">here</a>. Our current example is going to build on
the code we wrote there; after the deserialization step, we'll try and send the <code>point_reader</code> to a separate thread
for verification.</p>
<p>I'm going to walk through the attempts as I made them and my thinking throughout.
If you want to skip to the final project, check out the code available <a href=https://github.com/bspeice/capnp_cookbook_2 target=_blank rel="noopener noreferrer">here</a></p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id=attempt-1-move-the-reference>Attempt 1: Move the reference<a href=#attempt-1-move-the-reference class=hash-link aria-label="Direct link to Attempt 1: Move the reference" title="Direct link to Attempt 1: Move the reference"></a></h2>
<p>As a first attempt, we're going to try and let Rust move the reference. Our code will look something like:</p>
<div class="language-rust codeBlockContainer_Ckt0 theme-code-block" style="--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)"><div class=codeBlockContent_biex><pre tabindex=0 class="prism-code language-rust codeBlock_bY9V thin-scrollbar" style="background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)"><code class=codeBlockLines_e6Vv><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token keyword" style="color:hsl(301, 63%, 40%)">fn</span><span class="token plain"> </span><span class="token function-definition function" style="color:hsl(221, 87%, 60%)">main</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">(</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">{</span><span class="token plain"></span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain" style=display:inline-block></span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain"> </span><span class="token comment" style="color:hsl(230, 4%, 64%)">// ...assume that we own a `buffer: Vec&lt;u8>` containing the binary message content from</span><span class="token plain"></span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain"> </span><span class="token comment" style="color:hsl(230, 4%, 64%)">// somewhere else</span><span class="token plain"></span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain" style=display:inline-block></span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain"> </span><span class="token keyword" style="color:hsl(301, 63%, 40%)">let</span><span class="token plain"> deserialized </span><span class="token operator" style="color:hsl(221, 87%, 60%)">=</span><span class="token plain"> </span><span class="token namespace">capnp</span><span class="token namespace punctuation" style="color:hsl(119, 34%, 47%)">::</span><span class="token namespace">serialize</span><span class="token namespace punctuation" style="color:hsl(119, 34%, 47%)">::</span><span class="token function" style="color:hsl(221, 87%, 60%)">read_message</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">(</span><span class="token plain"></span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain"> </span><span class="token operator" style="color:hsl(221, 87%, 60%)">&</span><span class="token keyword" style="color:hsl(301, 63%, 40%)">mut</span><span class="token plain"> buffer</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">.</span><span class="token function" style="color:hsl(221, 87%, 60%)">as_slice</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">(</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">)</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">,</span><span class="token plain"></span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain"> </span><span class="token namespace">capnp</span><span class="token namespace punctuation" style="color:hsl(119, 34%, 47%)">::</span><span class="token namespace">message</span><span class="token namespace punctuation" style="color:hsl(119, 34%, 47%)">::</span><span class="token class-name" style="color:hsl(35, 99%, 36%)">ReaderOptions</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">::</span><span class="token function" style="color:hsl(221, 87%, 60%)">new</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">(</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">)</span><span class="token plain"></span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain"> </span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">)</span><span class="token punctuat
<p>Well, the Rust compiler doesn't really like this. We get four distinct errors back:</p>
<div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)"><div class=codeBlockContent_biex><pre tabindex=0 class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)"><code class=codeBlockLines_e6Vv><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain">error[E0277]: the trait bound `*const u8: std::marker::Send` is not satisfied in `[closure@src/main.rs:31:37: 36:6 point_reader:point_capnp::point::Reader&lt;'_>]` </span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain"> --> src/main.rs:31:18 </span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain"> | </span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain">31 | let handle = std::thread::spawn(move || { </span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain"> | ^^^^^^^^^^^^^^^^^^ `*const u8` cannot be sent between threads safely </span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain"> | </span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain" style=display:inline-block></span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain">error[E0277]: the trait bound `*const capnp::private::layout::WirePointer: std::marker::Send` is not satisfied in `[closure@src/main.rs:31:37: 36:6 point_reader:point_capnp::point::Reader&lt;'_>]` </span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain"> --> src/main.rs:31:18 </span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain"> | </span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain">31 | let handle = std::thread::spawn(move || { </span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain"> | ^^^^^^^^^^^^^^^^^^ `*const capnp::private::layout::WirePointer` cannot be sent between threads safely </span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain"> | </span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain" style=display:inline-block></span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain">error[E0277]: the trait bound `capnp::private::arena::ReaderArena: std::marker::Sync` is not satisfied </span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain"> --> src/main.rs:31:18 </span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain"> | </span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain">31 | let handle = std::thread::spawn(move || { </span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain"> | ^^^^^^^^^^^^^^^^^^ `capnp::private::arena::ReaderArena` cannot be shared between threads safely
<p>Note, I've removed the help text for brevity, but suffice to say that these errors are intimidating.
Pay attention to the text that keeps on getting repeated though: <code>XYZ cannot be sent between threads safely</code>.</p>
<p>This is a bit frustrating: we own the <code>buffer</code> from which all the content was derived, and we don't have any
unsafe accesses in our code. We guarantee that we wait for the child thread to stop first, so there's no possibility
of the pointer becoming invalid because the original thread exits before the child thread does. So why is Rust
preventing us from doing something that really should be legal?</p>
<p>This is what is known as <a href=https://doc.rust-lang.org/1.8.0/book/references-and-borrowing.html target=_blank rel="noopener noreferrer">fighting the borrow checker</a>.
Let our crusade begin.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id=attempt-2-put-the-reader-in-a-box>Attempt 2: Put the <code>Reader</code> in a <code>Box</code><a href=#attempt-2-put-the-reader-in-a-box class=hash-link aria-label="Direct link to attempt-2-put-the-reader-in-a-box" title="Direct link to attempt-2-put-the-reader-in-a-box"></a></h2>
<p>The <a href=https://doc.rust-lang.org/std/boxed/struct.Box.html target=_blank rel="noopener noreferrer"><code>Box</code></a> type allows us to convert a pointer we have
(in our case the <code>point_reader</code>) into an "owned" value, which should be easier to send across threads.
Our next attempt looks something like this:</p>
<div class="language-rust codeBlockContainer_Ckt0 theme-code-block" style="--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)"><div class=codeBlockContent_biex><pre tabindex=0 class="prism-code language-rust codeBlock_bY9V thin-scrollbar" style="background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)"><code class=codeBlockLines_e6Vv><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token keyword" style="color:hsl(301, 63%, 40%)">fn</span><span class="token plain"> </span><span class="token function-definition function" style="color:hsl(221, 87%, 60%)">main</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">(</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">{</span><span class="token plain"></span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain" style=display:inline-block></span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain"> </span><span class="token comment" style="color:hsl(230, 4%, 64%)">// ...assume that we own a `buffer: Vec&lt;u8>` containing the binary message content</span><span class="token plain"></span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain"> </span><span class="token comment" style="color:hsl(230, 4%, 64%)">// from somewhere else</span><span class="token plain"></span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain" style=display:inline-block></span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain"> </span><span class="token keyword" style="color:hsl(301, 63%, 40%)">let</span><span class="token plain"> deserialized </span><span class="token operator" style="color:hsl(221, 87%, 60%)">=</span><span class="token plain"> </span><span class="token namespace">capnp</span><span class="token namespace punctuation" style="color:hsl(119, 34%, 47%)">::</span><span class="token namespace">serialize</span><span class="token namespace punctuation" style="color:hsl(119, 34%, 47%)">::</span><span class="token function" style="color:hsl(221, 87%, 60%)">read_message</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">(</span><span class="token plain"></span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain"> </span><span class="token operator" style="color:hsl(221, 87%, 60%)">&</span><span class="token keyword" style="color:hsl(301, 63%, 40%)">mut</span><span class="token plain"> buffer</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">.</span><span class="token function" style="color:hsl(221, 87%, 60%)">as_slice</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">(</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">)</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">,</span><span class="token plain"></span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain"> </span><span class="token namespace">capnp</span><span class="token namespace punctuation" style="color:hsl(119, 34%, 47%)">::</span><span class="token namespace">message</span><span class="token namespace punctuation" style="color:hsl(119, 34%, 47%)">::</span><span class="token class-name" style="color:hsl(35, 99%, 36%)">ReaderOptions</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">::</span><span class="token function" style="color:hsl(221, 87%, 60%)">new</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">(</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">)</span><span class="token plain"></span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain"> </span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">)</span><span class="token punctuat
<p>Spoiler alert: still doesn't work. Same errors still show up.</p>
<div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)"><div class=codeBlockContent_biex><pre tabindex=0 class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)"><code class=codeBlockLines_e6Vv><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain">error[E0277]: the trait bound `*const u8: std::marker::Send` is not satisfied in `point_capnp::point::Reader&lt;'_>` </span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain"> --> src/main.rs:33:18 </span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain"> | </span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain">33 | let handle = std::thread::spawn(move || { </span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain"> | ^^^^^^^^^^^^^^^^^^ `*const u8` cannot be sent between threads safely </span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain"> | </span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain" style=display:inline-block></span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain">error[E0277]: the trait bound `*const capnp::private::layout::WirePointer: std::marker::Send` is not satisfied in `point_capnp::point::Reader&lt;'_>` </span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain"> --> src/main.rs:33:18 </span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain"> | </span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain">33 | let handle = std::thread::spawn(move || { </span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain"> | ^^^^^^^^^^^^^^^^^^ `*const capnp::private::layout::WirePointer` cannot be sent between threads safely </span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain"> | </span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain" style=display:inline-block></span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain">error[E0277]: the trait bound `capnp::private::arena::ReaderArena: std::marker::Sync` is not satisfied </span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain"> --> src/main.rs:33:18 </span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain"> | </span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain">33 | let handle = std::thread::spawn(move || { </span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain"> | ^^^^^^^^^^^^^^^^^^ `capnp::private::arena::ReaderArena` cannot be shared between threads safely </span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain"> |
<p>Let's be a little bit smarter about the exceptions this time though. What is that
<a href=https://doc.rust-lang.org/std/marker/trait.Send.html target=_blank rel="noopener noreferrer"><code>std::marker::Send</code></a> thing the compiler keeps telling us about?</p>
<p>The documentation is pretty clear; <code>Send</code> is used to denote:</p>
<blockquote>
<p>Types that can be transferred across thread boundaries.</p>
</blockquote>
<p>In our case, we are seeing the error messages for two reasons:</p>
<ol>
<li>
<p>Pointers (<code>*const u8</code>) are not safe to send across thread boundaries. While we're nice in our code
making sure that we wait on the child thread to finish before closing down, the Rust compiler can't make
that assumption, and so complains that we're not using this in a safe manner.</p>
</li>
<li>
<p>The <code>point_capnp::point::Reader</code> type is itself not safe to send across threads because it doesn't
implement the <code>Send</code> trait. Which is to say, the things that make up a <code>Reader</code> are themselves not thread-safe,
so the <code>Reader</code> is also not thread-safe.</p>
</li>
</ol>
<p>So, how are we to actually transfer a parsed Cap'N Proto message between threads?</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id=attempt-3-the-typedreader>Attempt 3: The <code>TypedReader</code><a href=#attempt-3-the-typedreader class=hash-link aria-label="Direct link to attempt-3-the-typedreader" title="Direct link to attempt-3-the-typedreader"></a></h2>
<p>The <code>TypedReader</code> is a new API implemented in the Cap'N Proto <a href=https://crates.io/crates/capnp/0.8.14 target=_blank rel="noopener noreferrer">Rust code</a>.
We're interested in it here for two reasons:</p>
<ol>
<li>
<p>It allows us to define an object where the <em>object</em> owns the underlying data. In previous attempts,
the current context owned the data, but the <code>Reader</code> itself had no such control.</p>
</li>
<li>
<p>We can compose the <code>TypedReader</code> using objects that are safe to <code>Send</code> across threads, guaranteeing
that we can transfer parsed messages across threads.</p>
</li>
</ol>
<p>The actual type info for the <a href=https://github.com/capnproto/capnproto-rust/blob/f0efc35d7e9bd8f97ca4fdeb7c57fd7ea348e303/src/message.rs#L181 target=_blank rel="noopener noreferrer"><code>TypedReader</code></a>
is a bit complex. And to be honest, I'm still really not sure what the whole point of the
<a href=https://doc.rust-lang.org/std/marker/struct.PhantomData.html target=_blank rel="noopener noreferrer"><code>PhantomData</code></a> thing is either.
My impression is that it lets us enforce type safety when we know what the underlying Cap'N Proto
message represents. That is, technically the only thing we're storing is the untyped binary message;
<code>PhantomData</code> just enforces the principle that the binary represents some specific object that has been parsed.</p>
<p>Either way, we can carefully construct something which is safe to move between threads:</p>
<div class="language-rust codeBlockContainer_Ckt0 theme-code-block" style="--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)"><div class=codeBlockContent_biex><pre tabindex=0 class="prism-code language-rust codeBlock_bY9V thin-scrollbar" style="background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)"><code class=codeBlockLines_e6Vv><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token keyword" style="color:hsl(301, 63%, 40%)">fn</span><span class="token plain"> </span><span class="token function-definition function" style="color:hsl(221, 87%, 60%)">main</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">(</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">{</span><span class="token plain"></span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain" style=display:inline-block></span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain"> </span><span class="token comment" style="color:hsl(230, 4%, 64%)">// ...assume that we own a `buffer: Vec&lt;u8>` containing the binary message content from somewhere else</span><span class="token plain"></span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain" style=display:inline-block></span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain"> </span><span class="token keyword" style="color:hsl(301, 63%, 40%)">let</span><span class="token plain"> deserialized </span><span class="token operator" style="color:hsl(221, 87%, 60%)">=</span><span class="token plain"> </span><span class="token namespace">capnp</span><span class="token namespace punctuation" style="color:hsl(119, 34%, 47%)">::</span><span class="token namespace">serialize</span><span class="token namespace punctuation" style="color:hsl(119, 34%, 47%)">::</span><span class="token function" style="color:hsl(221, 87%, 60%)">read_message</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">(</span><span class="token plain"></span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain"> </span><span class="token operator" style="color:hsl(221, 87%, 60%)">&</span><span class="token keyword" style="color:hsl(301, 63%, 40%)">mut</span><span class="token plain"> buffer</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">.</span><span class="token function" style="color:hsl(221, 87%, 60%)">as_slice</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">(</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">)</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">,</span><span class="token plain"></span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain"> </span><span class="token namespace">capnp</span><span class="token namespace punctuation" style="color:hsl(119, 34%, 47%)">::</span><span class="token namespace">message</span><span class="token namespace punctuation" style="color:hsl(119, 34%, 47%)">::</span><span class="token class-name" style="color:hsl(35, 99%, 36%)">ReaderOptions</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">::</span><span class="token function" style="color:hsl(221, 87%, 60%)">new</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">(</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">)</span><span class="token plain"></span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain"> </span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">)</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">.</span><span class="token function" style="color:hsl(221, 87%, 60%)">unwrap</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">(</span><span class
<p>And while we've left Rust to do the dirty work of actually moving the <code>point_reader</code> into the new thread,
we could also use things like <a href=https://doc.rust-lang.org/std/sync/mpsc/index.html target=_blank rel="noopener noreferrer"><code>mpsc</code> channels</a> to achieve a similar effect.</p>
<p>So now we're able to define basic Cap'N Proto messages, and send them all around our programs.</div></article><nav class="pagination-nav docusaurus-mt-lg" aria-label="Blog post page navigation"><a class="pagination-nav__link pagination-nav__link--prev" href=/2018/01/captains-cookbook-part-1><div class=pagination-nav__sublabel>Older post</div><div class=pagination-nav__label>Captain's Cookbook: Project setup</div></a><a class="pagination-nav__link pagination-nav__link--next" href=/2018/05/hello><div class=pagination-nav__sublabel>Newer post</div><div class=pagination-nav__label>Hello!</div></a></nav></main><div class="col col--2"><div class="tableOfContents_bqdL thin-scrollbar"><ul class="table-of-contents table-of-contents__left-border"><li><a href=#attempt-1-move-the-reference class="table-of-contents__link toc-highlight">Attempt 1: Move the reference</a><li><a href=#attempt-2-put-the-reader-in-a-box class="table-of-contents__link toc-highlight">Attempt 2: Put the <code>Reader</code> in a <code>Box</code></a><li><a href=#attempt-3-the-typedreader class="table-of-contents__link toc-highlight">Attempt 3: The <code>TypedReader</code></a></ul></div></div></div></div></div><footer class=footer><div class="container container-fluid"><div class="footer__bottom text--center"><div class=footer__copyright>Copyright © 2024 Bradlee Speice</div></div></div></footer></div>