diff options
author | Akshay <[email protected]> | 2023-02-12 06:43:49 +0000 |
---|---|---|
committer | Akshay <[email protected]> | 2023-02-12 06:43:49 +0000 |
commit | 366df8852f503523cc4f9046d82ba9a99dd51d7f (patch) | |
tree | 635884dd5700cdc2a22a8885031aa67816bbe1b0 /docs/posts | |
parent | 57a1fc656e05e1fcf07e4cff3dc988c6b5c2bc59 (diff) |
new art: lapse
Diffstat (limited to 'docs/posts')
27 files changed, 1816 insertions, 628 deletions
diff --git a/docs/posts/SDL2_devlog/index.html b/docs/posts/SDL2_devlog/index.html index 0e76515..e31f399 100644 --- a/docs/posts/SDL2_devlog/index.html +++ b/docs/posts/SDL2_devlog/index.html | |||
@@ -42,25 +42,60 @@ | |||
42 | SDL2 Devlog | 42 | SDL2 Devlog |
43 | </h1> | 43 | </h1> |
44 | <div class="post-text"> | 44 | <div class="post-text"> |
45 | <p>I have been working on an editor for the <a href="https://git.peppe.rs/graphics/obi/about">One Bit Image</a> file format in Rust and SDL2. This entry in my blog follows my progress on the editor. The days are listed in reverse chronological order, begin from the bottom, if this is your first time on this page.</p> | 45 | <p>I have been working on an editor for the <a |
46 | href="https://git.peppe.rs/graphics/obi/about">One Bit Image</a> file | ||
47 | format in Rust and SDL2. This entry in my blog follows my progress on | ||
48 | the editor. The days are listed in reverse chronological order, begin | ||
49 | from the bottom, if this is your first time on this page.</p> | ||
46 | <h3 id="day-20">Day 20</h3> | 50 | <h3 id="day-20">Day 20</h3> |
47 | <p>More <code>lisp</code> stuff! I added a new brush, for rectangular selections. While selection doesn’t do much on its own, the selected area can be passed onto a <code>lisp</code> procedure, for example, a procedure to draw horizontal black and white lines:</p> | 51 | <p>More <code>lisp</code> stuff! I added a new brush, for rectangular |
52 | selections. While selection doesn’t do much on its own, the selected | ||
53 | area can be passed onto a <code>lisp</code> procedure, for example, a | ||
54 | procedure to draw horizontal black and white lines:</p> | ||
48 | <figure> | 55 | <figure> |
49 | <video src="https://u.peppe.rs/frU.mp4" controls=""><a href="https://u.peppe.rs/frU.mp4">Day 20</a></video><figcaption aria-hidden="true">Day 20</figcaption> | 56 | <video src="https://u.peppe.rs/frU.mp4" controls=""><a |
57 | href="https://u.peppe.rs/frU.mp4">Day 20</a></video> | ||
58 | <figcaption aria-hidden="true">Day 20</figcaption> | ||
50 | </figure> | 59 | </figure> |
51 | <h3 id="day-19">Day 19</h3> | 60 | <h3 id="day-19">Day 19</h3> |
52 | <p>Attempted <a href="https://peppe.rs/art/conduit.png">some isometric art</a> within the editor. The angles displayed alongside the line brush are handly, however, having only a rectangular grid did not help. I implemented an isometric grid today. Isometric grids in pixel art differ in that the tangent of the isometric angle is exactly 0.5! For every pixel down, you go exactly two pixels sideways. The math works out really well in the drawing procedures too, dealing with floating points is a pain.</p> | 61 | <p>Attempted <a href="https://peppe.rs/art/conduit.png">some isometric |
62 | art</a> within the editor. The angles displayed alongside the line brush | ||
63 | are handly, however, having only a rectangular grid did not help. I | ||
64 | implemented an isometric grid today. Isometric grids in pixel art differ | ||
65 | in that the tangent of the isometric angle is exactly 0.5! For every | ||
66 | pixel down, you go exactly two pixels sideways. The math works out | ||
67 | really well in the drawing procedures too, dealing with floating points | ||
68 | is a pain.</p> | ||
53 | <figure> | 69 | <figure> |
54 | <img src="https://u.peppe.rs/1Kb.png" alt="Day 19" /><figcaption aria-hidden="true">Day 19</figcaption> | 70 | <img src="https://u.peppe.rs/1Kb.png" alt="Day 19" /> |
71 | <figcaption aria-hidden="true">Day 19</figcaption> | ||
55 | </figure> | 72 | </figure> |
56 | <h3 id="day-18">Day 18</h3> | 73 | <h3 id="day-18">Day 18</h3> |
57 | <p>I added basic support for guides, they can be added and activated from the <code>lisp</code> REPL. Another long standing improvement I wanted to make was reworking the pixmap drawing procedure. The old procedure draws a square for each pixel in the pixmap, coloured according to its value in the pixmap. Naturally, this means, for an <strong>NxN</strong> pixmap, there are <strong>N²</strong> calls to SDL! I reworked this procedure to compress each line of the pixmap using RLE (run length encoding), and call out to SDL for each run in the line. This drastically improved drawing speeds on larger grids. The following is a comparison between the two procedures, the leftmost picture is the rendered image, the middle picture is the optimized drawing procedure (draws each run instead of pixel), and the right most picture is the primitive drawing procedure (draws each pixel):</p> | 74 | <p>I added basic support for guides, they can be added and activated |
75 | from the <code>lisp</code> REPL. Another long standing improvement I | ||
76 | wanted to make was reworking the pixmap drawing procedure. The old | ||
77 | procedure draws a square for each pixel in the pixmap, coloured | ||
78 | according to its value in the pixmap. Naturally, this means, for an | ||
79 | <strong>NxN</strong> pixmap, there are <strong>N²</strong> calls to SDL! | ||
80 | I reworked this procedure to compress each line of the pixmap using RLE | ||
81 | (run length encoding), and call out to SDL for each run in the line. | ||
82 | This drastically improved drawing speeds on larger grids. The following | ||
83 | is a comparison between the two procedures, the leftmost picture is the | ||
84 | rendered image, the middle picture is the optimized drawing procedure | ||
85 | (draws each run instead of pixel), and the right most picture is the | ||
86 | primitive drawing procedure (draws each pixel):</p> | ||
58 | <figure> | 87 | <figure> |
59 | <img src="https://u.peppe.rs/U4B.png" alt="Day 18" /><figcaption aria-hidden="true">Day 18</figcaption> | 88 | <img src="https://u.peppe.rs/U4B.png" alt="Day 18" /> |
89 | <figcaption aria-hidden="true">Day 18</figcaption> | ||
60 | </figure> | 90 | </figure> |
61 | <h3 id="day-17">Day 17</h3> | 91 | <h3 id="day-17">Day 17</h3> |
62 | <p>I decided to give the text-only statusline a touch up, by adding a active color and dither level preview. Aligning the “widget” to the right of statusline involved a lot more than I thought, so I created a ghetto CSS-like rectangle placement system to position containers inside containers:</p> | 92 | <p>I decided to give the text-only statusline a touch up, by adding a |
63 | <div class="sourceCode" id="cb1"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="co">// roughly something like this</span></span> | 93 | active color and dither level preview. Aligning the “widget” to the |
94 | right of statusline involved a lot more than I thought, so I created a | ||
95 | ghetto CSS-like rectangle placement system to position containers inside | ||
96 | containers:</p> | ||
97 | <div class="sourceCode" id="cb1"><pre | ||
98 | class="sourceCode rust"><code class="sourceCode rust"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="co">// roughly something like this</span></span> | ||
64 | <span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="kw">let</span> statusline <span class="op">=</span> </span> | 99 | <span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="kw">let</span> statusline <span class="op">=</span> </span> |
65 | <span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a> <span class="pp">Container::</span>new(<span class="pp">Offset::</span>Left(<span class="dv">0</span>)<span class="op">,</span> <span class="pp">Offset::</span>Bottom(<span class="dv">40</span>))</span> | 100 | <span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a> <span class="pp">Container::</span>new(<span class="pp">Offset::</span>Left(<span class="dv">0</span>)<span class="op">,</span> <span class="pp">Offset::</span>Bottom(<span class="dv">40</span>))</span> |
66 | <span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span>width(<span class="pp">Size::</span>Max)</span> | 101 | <span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span>width(<span class="pp">Size::</span>Max)</span> |
@@ -77,14 +112,20 @@ | |||
77 | <span id="cb1-15"><a href="#cb1-15" aria-hidden="true" tabindex="-1"></a>)<span class="op">;</span></span></code></pre></div> | 112 | <span id="cb1-15"><a href="#cb1-15" aria-hidden="true" tabindex="-1"></a>)<span class="op">;</span></span></code></pre></div> |
78 | <p>The result (brush preview on the bottom right):</p> | 113 | <p>The result (brush preview on the bottom right):</p> |
79 | <figure> | 114 | <figure> |
80 | <video src="https://u.peppe.rs/OtU.mp4" controls=""><a href="https://u.peppe.rs/OtU.mp4">Day 17</a></video><figcaption aria-hidden="true">Day 17</figcaption> | 115 | <video src="https://u.peppe.rs/OtU.mp4" controls=""><a |
116 | href="https://u.peppe.rs/OtU.mp4">Day 17</a></video> | ||
117 | <figcaption aria-hidden="true">Day 17</figcaption> | ||
81 | </figure> | 118 | </figure> |
82 | <h3 id="day-16">Day 16</h3> | 119 | <h3 id="day-16">Day 16</h3> |
83 | <p>The embedded lisp is coming along nicely, users can load a custom <code>rc.lisp</code>, which is evaluated on startup. To disable to grid on start, for example:</p> | 120 | <p>The embedded lisp is coming along nicely, users can load a custom |
84 | <div class="sourceCode" id="cb2"><pre class="sourceCode scheme"><code class="sourceCode scheme"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="co">;;; rc.lisp</span></span> | 121 | <code>rc.lisp</code>, which is evaluated on startup. To disable to grid |
122 | on start, for example:</p> | ||
123 | <div class="sourceCode" id="cb2"><pre | ||
124 | class="sourceCode scheme"><code class="sourceCode scheme"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="co">;;; rc.lisp</span></span> | ||
85 | <span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a>(toggle-grid)</span></code></pre></div> | 125 | <span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a>(toggle-grid)</span></code></pre></div> |
86 | <p>Some aliases to switch between brushes:</p> | 126 | <p>Some aliases to switch between brushes:</p> |
87 | <div class="sourceCode" id="cb3"><pre class="sourceCode scheme"><code class="sourceCode scheme"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="co">;;; rc.lisp</span></span> | 127 | <div class="sourceCode" id="cb3"><pre |
128 | class="sourceCode scheme"><code class="sourceCode scheme"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="co">;;; rc.lisp</span></span> | ||
88 | <span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a>(<span class="ex">define</span><span class="fu"> </span>(brush kind)</span> | 129 | <span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a>(<span class="ex">define</span><span class="fu"> </span>(brush kind)</span> |
89 | <span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a> (<span class="kw">cond</span></span> | 130 | <span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a> (<span class="kw">cond</span></span> |
90 | <span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a> ((<span class="kw">eq?</span> kind 'f) (brush-fill))</span> | 131 | <span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a> ((<span class="kw">eq?</span> kind 'f) (brush-fill))</span> |
@@ -92,90 +133,195 @@ | |||
92 | <span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a> ((<span class="kw">eq?</span> kind 'l) (brush-line))</span> | 133 | <span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a> ((<span class="kw">eq?</span> kind 'l) (brush-line))</span> |
93 | <span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a> ((<span class="kw">eq?</span> kind 'l+) (brush-line-extend))</span> | 134 | <span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a> ((<span class="kw">eq?</span> kind 'l+) (brush-line-extend))</span> |
94 | <span id="cb3-8"><a href="#cb3-8" aria-hidden="true" tabindex="-1"></a> (<span class="kw">else</span> (brush-circle))))</span></code></pre></div> | 135 | <span id="cb3-8"><a href="#cb3-8" aria-hidden="true" tabindex="-1"></a> (<span class="kw">else</span> (brush-circle))))</span></code></pre></div> |
95 | <p>The following script draws a straight line along a given axis, at a given distance from the canvas boundary:</p> | 136 | <p>The following script draws a straight line along a given axis, at a |
137 | given distance from the canvas boundary:</p> | ||
96 | <figure> | 138 | <figure> |
97 | <video src="https://u.peppe.rs/b3i.mp4" controls=""><a href="https://u.peppe.rs/b3i.mp4">Day 16</a></video><figcaption aria-hidden="true">Day 16</figcaption> | 139 | <video src="https://u.peppe.rs/b3i.mp4" controls=""><a |
140 | href="https://u.peppe.rs/b3i.mp4">Day 16</a></video> | ||
141 | <figcaption aria-hidden="true">Day 16</figcaption> | ||
98 | </figure> | 142 | </figure> |
99 | <h3 id="day-15">Day 15</h3> | 143 | <h3 id="day-15">Day 15</h3> |
100 | <p>I began writing a standard library for the lisp, in lisp. It includes basic list operations: <code>car</code>, <code>cdr</code>, <code>null?</code>, <code>list</code>, higher order functions: <code>map</code>, <code>filter</code>, <code>fold</code>:</p> | 144 | <p>I began writing a standard library for the lisp, in lisp. It includes |
101 | <div class="sourceCode" id="cb4"><pre class="sourceCode lisp"><code class="sourceCode commonlisp"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a>(define (member? item ls)</span> | 145 | basic list operations: <code>car</code>, <code>cdr</code>, |
146 | <code>null?</code>, <code>list</code>, higher order functions: | ||
147 | <code>map</code>, <code>filter</code>, <code>fold</code>:</p> | ||
148 | <div class="sourceCode" id="cb4"><pre | ||
149 | class="sourceCode lisp"><code class="sourceCode commonlisp"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a>(define (member? item ls)</span> | ||
102 | <span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a> (fold <span class="dv">#f</span></span> | 150 | <span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a> (fold <span class="dv">#f</span></span> |
103 | <span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a> (<span class="kw">lambda</span> (acc x) (<span class="kw">or</span> acc (eq? item x)))</span> | 151 | <span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a> (<span class="kw">lambda</span> (acc x) (<span class="kw">or</span> acc (eq? item x)))</span> |
104 | <span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a> ls))</span></code></pre></div> | 152 | <span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a> ls))</span></code></pre></div> |
105 | <h3 id="day-14">Day 14</h3> | 153 | <h3 id="day-14">Day 14</h3> |
106 | <p>I attempted a <a href="https://peppe.rs/art/ramen_noodles.png">small art piece</a> using the editor, while it was largely usable, I felt a certain lack of feedback. The brushes just didn’t relay as much info as I’d have liked, for example, the approximate points of the line or the angle made by the line against the x-axis. Unfortunately, the existing infrastructure around brushes and line drawing didn’t easily allow for this either. I went ahead and reimplemented brushes, and added a new flood fill brush too:</p> | 154 | <p>I attempted a <a href="https://peppe.rs/art/ramen_noodles.png">small |
155 | art piece</a> using the editor, while it was largely usable, I felt a | ||
156 | certain lack of feedback. The brushes just didn’t relay as much info as | ||
157 | I’d have liked, for example, the approximate points of the line or the | ||
158 | angle made by the line against the x-axis. Unfortunately, the existing | ||
159 | infrastructure around brushes and line drawing didn’t easily allow for | ||
160 | this either. I went ahead and reimplemented brushes, and added a new | ||
161 | flood fill brush too:</p> | ||
107 | <figure> | 162 | <figure> |
108 | <video src="https://u.peppe.rs/8q.mp4" controls=""><a href="https://u.peppe.rs/8q.mp4">Day 14</a></video><figcaption aria-hidden="true">Day 14</figcaption> | 163 | <video src="https://u.peppe.rs/8q.mp4" controls=""><a |
164 | href="https://u.peppe.rs/8q.mp4">Day 14</a></video> | ||
165 | <figcaption aria-hidden="true">Day 14</figcaption> | ||
109 | </figure> | 166 | </figure> |
110 | <h3 id="day-13">Day 13</h3> | 167 | <h3 id="day-13">Day 13</h3> |
111 | <p>I added a few more forms to the <code>lisp</code> evaluator. It handles recursion, definitions, variable mutation and more. The prelude contains 20 subroutines so far, including comparision and logic operators. The REPL interface on the SDL side requires some UX tweaks; environment based completion, readline motions sound doable.</p> | 168 | <p>I added a few more forms to the <code>lisp</code> evaluator. It |
169 | handles recursion, definitions, variable mutation and more. The prelude | ||
170 | contains 20 subroutines so far, including comparision and logic | ||
171 | operators. The REPL interface on the SDL side requires some UX tweaks; | ||
172 | environment based completion, readline motions sound doable.</p> | ||
112 | <figure> | 173 | <figure> |
113 | <video src="https://u.peppe.rs/u3.mp4" controls=""><a href="https://u.peppe.rs/u3.mp4">Day 13</a></video><figcaption aria-hidden="true">Day 13</figcaption> | 174 | <video src="https://u.peppe.rs/u3.mp4" controls=""><a |
175 | href="https://u.peppe.rs/u3.mp4">Day 13</a></video> | ||
176 | <figcaption aria-hidden="true">Day 13</figcaption> | ||
114 | </figure> | 177 | </figure> |
115 | <h3 id="day-12">Day 12</h3> | 178 | <h3 id="day-12">Day 12</h3> |
116 | <p>I lifted most of <a href="https://github.com/murarth/ketos">murarth/ketos</a> into the editor. <code>ketos</code>’s implementation of <code>lisp</code> is too vast for my use case. For example, the editor does not need data types to handle raw strings or byte strings. I have got a basic evaluator running inside the SDL2 context (notice the <code>lisp</code> REPL at the bottom of the window). Over the following days, I intend to create a set of prelude functions to manipulate the pixmap. Users can implement their own brushes, dithering patterns, keybinds and more (hopefully).</p> | 179 | <p>I lifted most of <a |
180 | href="https://github.com/murarth/ketos">murarth/ketos</a> into the | ||
181 | editor. <code>ketos</code>’s implementation of <code>lisp</code> is too | ||
182 | vast for my use case. For example, the editor does not need data types | ||
183 | to handle raw strings or byte strings. I have got a basic evaluator | ||
184 | running inside the SDL2 context (notice the <code>lisp</code> REPL at | ||
185 | the bottom of the window). Over the following days, I intend to create a | ||
186 | set of prelude functions to manipulate the pixmap. Users can implement | ||
187 | their own brushes, dithering patterns, keybinds and more | ||
188 | (hopefully).</p> | ||
117 | <figure> | 189 | <figure> |
118 | <video src="https://u.peppe.rs/y0.mp4" controls=""><a href="https://u.peppe.rs/y0.mp4">Day 12</a></video><figcaption aria-hidden="true">Day 12</figcaption> | 190 | <video src="https://u.peppe.rs/y0.mp4" controls=""><a |
191 | href="https://u.peppe.rs/y0.mp4">Day 12</a></video> | ||
192 | <figcaption aria-hidden="true">Day 12</figcaption> | ||
119 | </figure> | 193 | </figure> |
120 | <h3 id="day-11">Day 11</h3> | 194 | <h3 id="day-11">Day 11</h3> |
121 | <p>I intend to supplement the editor with scripting language and an inbuilt REPL for the same. I began by implementing a text box widget from scratch, with history and readline like editing:</p> | 195 | <p>I intend to supplement the editor with scripting language and an |
196 | inbuilt REPL for the same. I began by implementing a text box widget | ||
197 | from scratch, with history and readline like editing:</p> | ||
122 | <figure> | 198 | <figure> |
123 | <video src="https://u.peppe.rs/Mh.mp4" controls=""><a href="https://u.peppe.rs/Mh.mp4">Day 11</a></video><figcaption aria-hidden="true">Day 11</figcaption> | 199 | <video src="https://u.peppe.rs/Mh.mp4" controls=""><a |
200 | href="https://u.peppe.rs/Mh.mp4">Day 11</a></video> | ||
201 | <figcaption aria-hidden="true">Day 11</figcaption> | ||
124 | </figure> | 202 | </figure> |
125 | <h3 id="day-10">Day 10</h3> | 203 | <h3 id="day-10">Day 10</h3> |
126 | <p>I started reading up on dithering methods and half-toning, I wanted to create a dithering brush that would automatically produce popular dithering patterns. The method that caught my eye (and also the one used most often in pixel art), was Bayer’s ordered dithering. When applied to a black and white image, each pixel, based on its intensity, is mapped to a 4x4 grid of pixels. A completely empty (completely black) 4x4 grid represents zero intensity, and a filled 4x4 grid represents full intensity. Bayer’s ordered dithering can produce 15 steps of intensity between zero and full (by switching on exactly 1 pixel more at each level), thus, being able to draw 17 “shades” from white to black. Creating a dithering brush from here was fairly trivial. Our pixmap is supposed to represent the final dithered image, it must be divided into 4x4 grids. Each grid is colored based on the intensity of the brush passing over it:</p> | 204 | <p>I started reading up on dithering methods and half-toning, I wanted |
205 | to create a dithering brush that would automatically produce popular | ||
206 | dithering patterns. The method that caught my eye (and also the one used | ||
207 | most often in pixel art), was Bayer’s ordered dithering. When applied to | ||
208 | a black and white image, each pixel, based on its intensity, is mapped | ||
209 | to a 4x4 grid of pixels. A completely empty (completely black) 4x4 grid | ||
210 | represents zero intensity, and a filled 4x4 grid represents full | ||
211 | intensity. Bayer’s ordered dithering can produce 15 steps of intensity | ||
212 | between zero and full (by switching on exactly 1 pixel more at each | ||
213 | level), thus, being able to draw 17 “shades” from white to black. | ||
214 | Creating a dithering brush from here was fairly trivial. Our pixmap is | ||
215 | supposed to represent the final dithered image, it must be divided into | ||
216 | 4x4 grids. Each grid is colored based on the intensity of the brush | ||
217 | passing over it:</p> | ||
127 | <figure> | 218 | <figure> |
128 | <img src="https://u.peppe.rs/Mn.png" alt="Day 10" /><figcaption aria-hidden="true">Day 10</figcaption> | 219 | <img src="https://u.peppe.rs/Mn.png" alt="Day 10" /> |
220 | <figcaption aria-hidden="true">Day 10</figcaption> | ||
129 | </figure> | 221 | </figure> |
130 | <h3 id="day-9">Day 9</h3> | 222 | <h3 id="day-9">Day 9</h3> |
131 | <p>I started working towards an interface. I like the idea of a largely read-only HUD, i. e., an interface that simply describes the state of the application. Changes to this state are initiated via keybinds or text commands. I am proud of the symmetry indicator; <code>-</code> for horizontal symmetry, <code>|</code> for vertical symmetry, <code>+</code> for radial symmetry.</p> | 223 | <p>I started working towards an interface. I like the idea of a largely |
224 | read-only HUD, i. e., an interface that simply describes the state of | ||
225 | the application. Changes to this state are initiated via keybinds or | ||
226 | text commands. I am proud of the symmetry indicator; <code>-</code> for | ||
227 | horizontal symmetry, <code>|</code> for vertical symmetry, | ||
228 | <code>+</code> for radial symmetry.</p> | ||
132 | <figure> | 229 | <figure> |
133 | <img src="https://u.peppe.rs/hx.png" alt="Day 9" /><figcaption aria-hidden="true">Day 9</figcaption> | 230 | <img src="https://u.peppe.rs/hx.png" alt="Day 9" /> |
231 | <figcaption aria-hidden="true">Day 9</figcaption> | ||
134 | </figure> | 232 | </figure> |
135 | <h3 id="day-8">Day 8</h3> | 233 | <h3 id="day-8">Day 8</h3> |
136 | <p>One of my favourite features of GIMP was symmetric editing. I added some coordinate geometry primitives to my pixmap abstraction, allowing for mirroring and reflecting figures about lines or points. The result was an ergonomic function that applies symmetry to any painting operation, (undo/redo works as expected):</p> | 234 | <p>One of my favourite features of GIMP was symmetric editing. I added |
137 | <div class="sourceCode" id="cb5"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="kw">let</span> line <span class="op">=</span> <span class="kw">self</span><span class="op">.</span>pixmap<span class="op">.</span>get_line(start<span class="op">,</span> end)<span class="op">;</span></span> | 235 | some coordinate geometry primitives to my pixmap abstraction, allowing |
236 | for mirroring and reflecting figures about lines or points. The result | ||
237 | was an ergonomic function that applies symmetry to any painting | ||
238 | operation, (undo/redo works as expected):</p> | ||
239 | <div class="sourceCode" id="cb5"><pre | ||
240 | class="sourceCode rust"><code class="sourceCode rust"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="kw">let</span> line <span class="op">=</span> <span class="kw">self</span><span class="op">.</span>pixmap<span class="op">.</span>get_line(start<span class="op">,</span> end)<span class="op">;</span></span> | ||
138 | <span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a><span class="kw">let</span> sym_line <span class="op">=</span> <span class="kw">self</span><span class="op">.</span>symmetry<span class="op">.</span>apply(<span class="op">&</span>line)<span class="op">;</span></span> | 241 | <span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a><span class="kw">let</span> sym_line <span class="op">=</span> <span class="kw">self</span><span class="op">.</span>symmetry<span class="op">.</span>apply(<span class="op">&</span>line)<span class="op">;</span></span> |
139 | <span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a><span class="kw">for</span> point on line<span class="op">.</span>extend(sym_line) <span class="op">{</span></span> | 242 | <span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a><span class="cf">for</span> point on line<span class="op">.</span>extend(sym_line) <span class="op">{</span></span> |
140 | <span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a> <span class="co">// draw to window</span></span> | 243 | <span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a> <span class="co">// draw to window</span></span> |
141 | <span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div> | 244 | <span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div> |
142 | <figure> | 245 | <figure> |
143 | <video src="https://u.peppe.rs/B1.mp4" controls=""><a href="https://u.peppe.rs/B1.mp4">Day 8</a></video><figcaption aria-hidden="true">Day 8</figcaption> | 246 | <video src="https://u.peppe.rs/B1.mp4" controls=""><a |
247 | href="https://u.peppe.rs/B1.mp4">Day 8</a></video> | ||
248 | <figcaption aria-hidden="true">Day 8</figcaption> | ||
144 | </figure> | 249 | </figure> |
145 | <h3 id="day-7">Day 7</h3> | 250 | <h3 id="day-7">Day 7</h3> |
146 | <p>Bresenham saves the day again! This time, I implemented his line drawing algorithm, to, well, draw lines. Each point on the line is then “buffed” based on the active brush size. Today’s changes fit in very well with the undo system and the brush size feature. Creating the right abstractions, one at a time :)</p> | 251 | <p>Bresenham saves the day again! This time, I implemented his line |
252 | drawing algorithm, to, well, draw lines. Each point on the line is then | ||
253 | “buffed” based on the active brush size. Today’s changes fit in very | ||
254 | well with the undo system and the brush size feature. Creating the right | ||
255 | abstractions, one at a time :)</p> | ||
147 | <figure> | 256 | <figure> |
148 | <video src="https://u.peppe.rs/xt.mp4" controls=""><a href="https://u.peppe.rs/xt.mp4">Day 7</a></video><figcaption aria-hidden="true">Day 7</figcaption> | 257 | <video src="https://u.peppe.rs/xt.mp4" controls=""><a |
258 | href="https://u.peppe.rs/xt.mp4">Day 7</a></video> | ||
259 | <figcaption aria-hidden="true">Day 7</figcaption> | ||
149 | </figure> | 260 | </figure> |
150 | <h3 id="day-6">Day 6</h3> | 261 | <h3 id="day-6">Day 6</h3> |
151 | <p>I extended Bresenham’s algorithm to draw not just circle outlines, but also generate their fills. Unlike Bresenham’s algorithm, this variant generates points for two quadrants at once, these points are mirrored over the dividing axis to generate the other two quadrants.</p> | 262 | <p>I extended Bresenham’s algorithm to draw not just circle outlines, |
263 | but also generate their fills. Unlike Bresenham’s algorithm, this | ||
264 | variant generates points for two quadrants at once, these points are | ||
265 | mirrored over the dividing axis to generate the other two quadrants.</p> | ||
152 | <figure> | 266 | <figure> |
153 | <img src="https://u.peppe.rs/f3.png" alt="Day 6" /><figcaption aria-hidden="true">Day 6</figcaption> | 267 | <img src="https://u.peppe.rs/f3.png" alt="Day 6" /> |
268 | <figcaption aria-hidden="true">Day 6</figcaption> | ||
154 | </figure> | 269 | </figure> |
155 | <h3 id="day-5">Day 5</h3> | 270 | <h3 id="day-5">Day 5</h3> |
156 | <p>I discovered and implemented Bresenham’s algorithm for efficient circle drawing. The algorithm allowed for sized circular brushes, something I really liked from GIMP. Very convenient that the Wikipedia page for Bresenham’s algorithm also includes a section about optimizing for integer based arithmetic. I managed to abstract out another giant component of the application, the pixmap. Any image is just a grid of pixels (a pixmap), where the pixel’s value is decided by the application (1-bit in my case). I could potentially extend the application to a 24-bit image editor!</p> | 271 | <p>I discovered and implemented Bresenham’s algorithm for efficient |
272 | circle drawing. The algorithm allowed for sized circular brushes, | ||
273 | something I really liked from GIMP. Very convenient that the Wikipedia | ||
274 | page for Bresenham’s algorithm also includes a section about optimizing | ||
275 | for integer based arithmetic. I managed to abstract out another giant | ||
276 | component of the application, the pixmap. Any image is just a grid of | ||
277 | pixels (a pixmap), where the pixel’s value is decided by the application | ||
278 | (1-bit in my case). I could potentially extend the application to a | ||
279 | 24-bit image editor!</p> | ||
157 | <figure> | 280 | <figure> |
158 | <video src="https://u.peppe.rs/Kh.mp4" controls=""><a href="https://u.peppe.rs/Kh.mp4">Day 5</a></video><figcaption aria-hidden="true">Day 5</figcaption> | 281 | <video src="https://u.peppe.rs/Kh.mp4" controls=""><a |
282 | href="https://u.peppe.rs/Kh.mp4">Day 5</a></video> | ||
283 | <figcaption aria-hidden="true">Day 5</figcaption> | ||
159 | </figure> | 284 | </figure> |
160 | <h3 id="day-4">Day 4</h3> | 285 | <h3 id="day-4">Day 4</h3> |
161 | <p>I created a generic “undo stack” data structure that allows for infinite “undos” and “redos”. Every modification operation to the grid is persisted to the application state. A couple of keybinds allow the user to revert and re-apply these operations! I expect abstracting this component will come in handy down the line.</p> | 286 | <p>I created a generic “undo stack” data structure that allows for |
287 | infinite “undos” and “redos”. Every modification operation to the grid | ||
288 | is persisted to the application state. A couple of keybinds allow the | ||
289 | user to revert and re-apply these operations! I expect abstracting this | ||
290 | component will come in handy down the line.</p> | ||
162 | <figure> | 291 | <figure> |
163 | <video src="https://u.peppe.rs/w5.mp4" controls=""><a href="https://u.peppe.rs/w5.mp4">Day 4</a></video><figcaption aria-hidden="true">Day 4</figcaption> | 292 | <video src="https://u.peppe.rs/w5.mp4" controls=""><a |
293 | href="https://u.peppe.rs/w5.mp4">Day 4</a></video> | ||
294 | <figcaption aria-hidden="true">Day 4</figcaption> | ||
164 | </figure> | 295 | </figure> |
165 | <h3 id="day-3">Day 3</h3> | 296 | <h3 id="day-3">Day 3</h3> |
166 | <p>I implemented the bare minimum required to call the program an “editor”. The application displays a grid, tracks mouse events, paints white to the canvas on left click, and black to the canvas on right click. I created a make-shift MVC architecture à la Elm in Rust.</p> | 297 | <p>I implemented the bare minimum required to call the program an |
298 | “editor”. The application displays a grid, tracks mouse events, paints | ||
299 | white to the canvas on left click, and black to the canvas on right | ||
300 | click. I created a make-shift MVC architecture à la Elm in Rust.</p> | ||
167 | <figure> | 301 | <figure> |
168 | <video src="https://u.peppe.rs/GF.mp4" controls=""><a href="https://u.peppe.rs/GF.mp4">Day 3</a></video><figcaption aria-hidden="true">Day 3</figcaption> | 302 | <video src="https://u.peppe.rs/GF.mp4" controls=""><a |
303 | href="https://u.peppe.rs/GF.mp4">Day 3</a></video> | ||
304 | <figcaption aria-hidden="true">Day 3</figcaption> | ||
169 | </figure> | 305 | </figure> |
170 | <h3 id="day-2">Day 2</h3> | 306 | <h3 id="day-2">Day 2</h3> |
171 | <p>I started figuring out event handling today. Implemented a couple of keybinds to zoom in/out of the drawing area. Conversions of SDL2 coordinates (measured in signed 32 bit integers) to my internal “drawing area” coordinates (measured in unsigned 32 bit integers) is very annoying. Hopefully the unchecked conversions won’t haunt me later.</p> | 307 | <p>I started figuring out event handling today. Implemented a couple of |
308 | keybinds to zoom in/out of the drawing area. Conversions of SDL2 | ||
309 | coordinates (measured in signed 32 bit integers) to my internal “drawing | ||
310 | area” coordinates (measured in unsigned 32 bit integers) is very | ||
311 | annoying. Hopefully the unchecked conversions won’t haunt me later.</p> | ||
172 | <figure> | 312 | <figure> |
173 | <video src="https://u.peppe.rs/L4.mp4" controls=""><a href="https://u.peppe.rs/L4.mp4">Day 2</a></video><figcaption aria-hidden="true">Day 2</figcaption> | 313 | <video src="https://u.peppe.rs/L4.mp4" controls=""><a |
314 | href="https://u.peppe.rs/L4.mp4">Day 2</a></video> | ||
315 | <figcaption aria-hidden="true">Day 2</figcaption> | ||
174 | </figure> | 316 | </figure> |
175 | <h3 id="day-1">Day 1</h3> | 317 | <h3 id="day-1">Day 1</h3> |
176 | <p>Getting started with Rust and SDL2 is very straightforward. The <code>rust-sdl2</code> library contains some detailed examples that allowed me to get all the way to drawing a grid from a <code>Vec<bool></code>:</p> | 318 | <p>Getting started with Rust and SDL2 is very straightforward. The |
319 | <code>rust-sdl2</code> library contains some detailed examples that | ||
320 | allowed me to get all the way to drawing a grid from a | ||
321 | <code>Vec<bool></code>:</p> | ||
177 | <figure> | 322 | <figure> |
178 | <img src="https://u.peppe.rs/Ma.png" alt="Day 1" /><figcaption aria-hidden="true">Day 1</figcaption> | 323 | <img src="https://u.peppe.rs/Ma.png" alt="Day 1" /> |
324 | <figcaption aria-hidden="true">Day 1</figcaption> | ||
179 | </figure> | 325 | </figure> |
180 | 326 | ||
181 | </div> | 327 | </div> |
diff --git a/docs/posts/WPA_woes/index.html b/docs/posts/WPA_woes/index.html index 55b2630..0a2e44c 100644 --- a/docs/posts/WPA_woes/index.html +++ b/docs/posts/WPA_woes/index.html | |||
@@ -28,7 +28,7 @@ | |||
28 | 12/10 — 2019 | 28 | 12/10 — 2019 |
29 | <div class="stats"> | 29 | <div class="stats"> |
30 | <span class="stats-number"> | 30 | <span class="stats-number"> |
31 | 18.37 | 31 | 18.38 |
32 | </span> | 32 | </span> |
33 | <span class="stats-unit">cm</span> | 33 | <span class="stats-unit">cm</span> |
34 |   | 34 |   |
@@ -42,8 +42,12 @@ | |||
42 | WPA Woes | 42 | WPA Woes |
43 | </h1> | 43 | </h1> |
44 | <div class="post-text"> | 44 | <div class="post-text"> |
45 | <p>I finally got around to installing Void GNU/Linux on my main computer. Rolling release, non-systemd, need I say more?</p> | 45 | <p>I finally got around to installing Void GNU/Linux on my main |
46 | <p>As with all GNU/Linux distributions, wireless networks had me in a fix. If you can see this post, it means I’ve managed to get online. It turns out, <code>wpa_supplicant</code> was detecting the wrong interface by default (does it ever select the right one?). Let us fix that:</p> | 46 | computer. Rolling release, non-systemd, need I say more?</p> |
47 | <p>As with all GNU/Linux distributions, wireless networks had me in a | ||
48 | fix. If you can see this post, it means I’ve managed to get online. It | ||
49 | turns out, <code>wpa_supplicant</code> was detecting the wrong interface | ||
50 | by default (does it ever select the right one?). Let us fix that:</p> | ||
47 | <pre><code>$ sudo rm -r /var/service/wpa_supplicant | 51 | <pre><code>$ sudo rm -r /var/service/wpa_supplicant |
48 | $ sudo killall dhcpcd</code></pre> | 52 | $ sudo killall dhcpcd</code></pre> |
49 | <p>What is the right interface though?</p> | 53 | <p>What is the right interface though?</p> |
@@ -51,7 +55,8 @@ $ sudo killall dhcpcd</code></pre> | |||
51 | ... | 55 | ... |
52 | Interface wlp2s0 | 56 | Interface wlp2s0 |
53 | ...</code></pre> | 57 | ...</code></pre> |
54 | <p>Aha! Let us run <code>wpa_supplicant</code> on that interface, as a background process:</p> | 58 | <p>Aha! Let us run <code>wpa_supplicant</code> on that interface, as a |
59 | background process:</p> | ||
55 | <pre><code>$ sudo wpa_supplicant -B -i wlp2s0 -c /etc/wpa_supplicant/wpa_supplicant.conf | 60 | <pre><code>$ sudo wpa_supplicant -B -i wlp2s0 -c /etc/wpa_supplicant/wpa_supplicant.conf |
56 | $ sudo dhcpcd -B wlp2s0 | 61 | $ sudo dhcpcd -B wlp2s0 |
57 | $ ping google.com | 62 | $ ping google.com |
diff --git a/docs/posts/a_reference_counted_afterlife/index.html b/docs/posts/a_reference_counted_afterlife/index.html index 67016a6..a796393 100644 --- a/docs/posts/a_reference_counted_afterlife/index.html +++ b/docs/posts/a_reference_counted_afterlife/index.html | |||
@@ -28,7 +28,7 @@ | |||
28 | 02/08 — 2022 | 28 | 02/08 — 2022 |
29 | <div class="stats"> | 29 | <div class="stats"> |
30 | <span class="stats-number"> | 30 | <span class="stats-number"> |
31 | 19.57 | 31 | 19.58 |
32 | </span> | 32 | </span> |
33 | <span class="stats-unit">cm</span> | 33 | <span class="stats-unit">cm</span> |
34 |   | 34 |   |
@@ -42,9 +42,11 @@ | |||
42 | A Reference Counted Afterlife | 42 | A Reference Counted Afterlife |
43 | </h1> | 43 | </h1> |
44 | <div class="post-text"> | 44 | <div class="post-text"> |
45 | <p>I took interest in the Egyptian rendition of the afterlife recently.</p> | 45 | <p>I took interest in the Egyptian rendition of the afterlife |
46 | recently.</p> | ||
46 | <h3 id="parts-of-the-soul">Parts of the Soul</h3> | 47 | <h3 id="parts-of-the-soul">Parts of the Soul</h3> |
47 | <p>Ancient Egyptians believed that the soul comprised of several components:</p> | 48 | <p>Ancient Egyptians believed that the soul comprised of several |
49 | components:</p> | ||
48 | <ul> | 50 | <ul> |
49 | <li><em>ren</em></li> | 51 | <li><em>ren</em></li> |
50 | <li><em>ka</em></li> | 52 | <li><em>ka</em></li> |
@@ -52,18 +54,34 @@ | |||
52 | <li><em>ba</em></li> | 54 | <li><em>ba</em></li> |
53 | <li><em>sheut</em></li> | 55 | <li><em>sheut</em></li> |
54 | </ul> | 56 | </ul> |
55 | <p>Egyptians emphasized on preserving the different parts of the soul. Mummification for example, served to preserve the physical part of the soul. The other components have their respective preservation strategies.</p> | 57 | <p>Egyptians emphasized on preserving the different parts of the soul. |
56 | <p>Of all of these bits, I find <em>ren</em>, which simply means <em>name</em>, to be the most interesting. <em>Ba</em>, the human-headed chicken that represents <em>personality</em>, is a close favourite.</p> | 58 | Mummification for example, served to preserve the physical part of the |
57 | <p><em>Ren</em> is the name given to a person at birth. Egyptians believed that this portion of the soul would continue to live on for as long as it was spoken. If you were someone worthy of continued existence, your name would be inscribed all over the place. If you were the type to snatch away bread from children, your name would be condemned from memory, forgotten.</p> | 59 | soul. The other components have their respective preservation |
60 | strategies.</p> | ||
61 | <p>Of all of these bits, I find <em>ren</em>, which simply means | ||
62 | <em>name</em>, to be the most interesting. <em>Ba</em>, the human-headed | ||
63 | chicken that represents <em>personality</em>, is a close favourite.</p> | ||
64 | <p><em>Ren</em> is the name given to a person at birth. Egyptians | ||
65 | believed that this portion of the soul would continue to live on for as | ||
66 | long as it was spoken. If you were someone worthy of continued | ||
67 | existence, your name would be inscribed all over the place. If you were | ||
68 | the type to snatch away bread from children, your name would be | ||
69 | condemned from memory, forgotten.</p> | ||
58 | <h3 id="garbage-collection">Garbage-collection</h3> | 70 | <h3 id="garbage-collection">Garbage-collection</h3> |
59 | <p>The concept of <em>ren</em> seems to be perfectly analogous to reference counted garbage-collection.</p> | 71 | <p>The concept of <em>ren</em> seems to be perfectly analogous to |
72 | reference counted garbage-collection.</p> | ||
60 | <ul> | 73 | <ul> |
61 | <li>A name (<em>ren</em>) is assigned to an object (person) on initialization (at birth)</li> | 74 | <li>A name (<em>ren</em>) is assigned to an object (person) on |
75 | initialization (at birth)</li> | ||
62 | <li>Names are used to refer to objects</li> | 76 | <li>Names are used to refer to objects</li> |
63 | <li>Objects go out of existence when there are no more references to them</li> | 77 | <li>Objects go out of existence when there are no more references to |
78 | them</li> | ||
64 | </ul> | 79 | </ul> |
65 | <p>The concept of <em>ren</em> seems to model human-memory. The similarity with garbage-collection is now easily explained, because garbage-collection models a program’s memory.</p> | 80 | <p>The concept of <em>ren</em> seems to model human-memory. The |
66 | <p>Perhaps some cheeky Egyptian has attained immortality by creating a <em>ren</em>-cycle.</p> | 81 | similarity with garbage-collection is now easily explained, because |
82 | garbage-collection models a program’s memory.</p> | ||
83 | <p>Perhaps some cheeky Egyptian has attained immortality by creating a | ||
84 | <em>ren</em>-cycle.</p> | ||
67 | 85 | ||
68 | </div> | 86 | </div> |
69 | 87 | ||
diff --git a/docs/posts/auto-currying_rust_functions/index.html b/docs/posts/auto-currying_rust_functions/index.html index 0d6fc77..7b05aeb 100644 --- a/docs/posts/auto-currying_rust_functions/index.html +++ b/docs/posts/auto-currying_rust_functions/index.html | |||
@@ -28,7 +28,7 @@ | |||
28 | 09/05 — 2020 | 28 | 09/05 — 2020 |
29 | <div class="stats"> | 29 | <div class="stats"> |
30 | <span class="stats-number"> | 30 | <span class="stats-number"> |
31 | 356.43 | 31 | 356.44 |
32 | </span> | 32 | </span> |
33 | <span class="stats-unit">cm</span> | 33 | <span class="stats-unit">cm</span> |
34 |   | 34 |   |
@@ -42,13 +42,22 @@ | |||
42 | Auto-currying Rust Functions | 42 | Auto-currying Rust Functions |
43 | </h1> | 43 | </h1> |
44 | <div class="post-text"> | 44 | <div class="post-text"> |
45 | <p>This post contains a gentle introduction to procedural macros in Rust and a guide to writing a procedural macro to curry Rust functions. The source code for the entire library can be found <a href="https://github.com/nerdypepper/cutlass">here</a>. It is also available on <a href="https://crates.io/crates/cutlass">crates.io</a>.</p> | 45 | <p>This post contains a gentle introduction to procedural macros in Rust |
46 | <p>The following links might prove to be useful before getting started:</p> | 46 | and a guide to writing a procedural macro to curry Rust functions. The |
47 | source code for the entire library can be found <a | ||
48 | href="https://github.com/nerdypepper/cutlass">here</a>. It is also | ||
49 | available on <a | ||
50 | href="https://crates.io/crates/cutlass">crates.io</a>.</p> | ||
51 | <p>The following links might prove to be useful before getting | ||
52 | started:</p> | ||
47 | <ul> | 53 | <ul> |
48 | <li><a href="https://doc.rust-lang.org/reference/procedural-macros.html">Procedural Macros</a></li> | 54 | <li><a |
55 | href="https://doc.rust-lang.org/reference/procedural-macros.html">Procedural | ||
56 | Macros</a></li> | ||
49 | <li><a href="https://en.wikipedia.org/wiki/Currying">Currying</a></li> | 57 | <li><a href="https://en.wikipedia.org/wiki/Currying">Currying</a></li> |
50 | </ul> | 58 | </ul> |
51 | <p>Or you can pretend you read them, because I have included a primer here :)</p> | 59 | <p>Or you can pretend you read them, because I have included a primer |
60 | here :)</p> | ||
52 | <h3 id="contents">Contents</h3> | 61 | <h3 id="contents">Contents</h3> |
53 | <ol type="1"> | 62 | <ol type="1"> |
54 | <li><a href="#currying">Currying</a><br /> | 63 | <li><a href="#currying">Currying</a><br /> |
@@ -73,7 +82,12 @@ | |||
73 | <li><a href="#conclusion">Conclusion</a></li> | 82 | <li><a href="#conclusion">Conclusion</a></li> |
74 | </ol> | 83 | </ol> |
75 | <h3 id="currying">Currying</h3> | 84 | <h3 id="currying">Currying</h3> |
76 | <p>Currying is the process of transformation of a function call like <code>f(a, b, c)</code> to <code>f(a)(b)(c)</code>. A curried function returns a concrete value only when it receives all its arguments! If it does recieve an insufficient amount of arguments, say 1 of 3, it returns a <em>curried function</em>, that returns after receiving 2 arguments.</p> | 85 | <p>Currying is the process of transformation of a function call like |
86 | <code>f(a, b, c)</code> to <code>f(a)(b)(c)</code>. A curried function | ||
87 | returns a concrete value only when it receives all its arguments! If it | ||
88 | does recieve an insufficient amount of arguments, say 1 of 3, it returns | ||
89 | a <em>curried function</em>, that returns after receiving 2 | ||
90 | arguments.</p> | ||
77 | <pre><code>curry(f(a, b, c)) = h(a)(b)(c) | 91 | <pre><code>curry(f(a, b, c)) = h(a)(b)(c) |
78 | 92 | ||
79 | h(x) = g <- curried function that takes upto 2 args (g) | 93 | h(x) = g <- curried function that takes upto 2 args (g) |
@@ -82,49 +96,86 @@ k(z) = v <- a value (v) | |||
82 | 96 | ||
83 | Keen readers will conclude the following, | 97 | Keen readers will conclude the following, |
84 | h(x)(y)(z) = g(y)(z) = k(z) = v</code></pre> | 98 | h(x)(y)(z) = g(y)(z) = k(z) = v</code></pre> |
85 | <p>Mathematically, if <code>f</code> is a function that takes two arguments <code>x</code> and <code>y</code>, such that <code>x ϵ X</code>, and <code>y ϵ Y</code> , we write it as:</p> | 99 | <p>Mathematically, if <code>f</code> is a function that takes two |
100 | arguments <code>x</code> and <code>y</code>, such that | ||
101 | <code>x ϵ X</code>, and <code>y ϵ Y</code> , we write it as:</p> | ||
86 | <pre><code>f: (X × Y) -> Z</code></pre> | 102 | <pre><code>f: (X × Y) -> Z</code></pre> |
87 | <p>where <code>×</code> denotes the Cartesian product of set <code>X</code> and <code>Y</code>, and curried <code>f</code> (denoted by <code>h</code> here) is written as:</p> | 103 | <p>where <code>×</code> denotes the Cartesian product of set |
104 | <code>X</code> and <code>Y</code>, and curried <code>f</code> (denoted | ||
105 | by <code>h</code> here) is written as:</p> | ||
88 | <pre><code>h: X -> (Y -> Z)</code></pre> | 106 | <pre><code>h: X -> (Y -> Z)</code></pre> |
89 | <h3 id="procedural-macros">Procedural Macros</h3> | 107 | <h3 id="procedural-macros">Procedural Macros</h3> |
90 | <p>These are functions that take code as input and spit out modified code as output. Powerful stuff. Rust has three kinds of proc-macros:</p> | 108 | <p>These are functions that take code as input and spit out modified |
109 | code as output. Powerful stuff. Rust has three kinds of proc-macros:</p> | ||
91 | <ul> | 110 | <ul> |
92 | <li>Function like macros<br /> | 111 | <li>Function like macros<br /> |
93 | </li> | 112 | </li> |
94 | <li>Derive macros: <code>#[derive(...)]</code>, used to automatically implement traits for structs/enums<br /> | 113 | <li>Derive macros: <code>#[derive(...)]</code>, used to automatically |
114 | implement traits for structs/enums<br /> | ||
95 | </li> | 115 | </li> |
96 | <li>and Attribute macros: <code>#[test]</code>, usually slapped onto functions</li> | 116 | <li>and Attribute macros: <code>#[test]</code>, usually slapped onto |
117 | functions</li> | ||
97 | </ul> | 118 | </ul> |
98 | <p>We will be using Attribute macros to convert a Rust function into a curried Rust function, which we should be able to call via: <code>function(arg1)(arg2)</code>.</p> | 119 | <p>We will be using Attribute macros to convert a Rust function into a |
120 | curried Rust function, which we should be able to call via: | ||
121 | <code>function(arg1)(arg2)</code>.</p> | ||
99 | <h3 id="definitions">Definitions</h3> | 122 | <h3 id="definitions">Definitions</h3> |
100 | <p>Being respectable programmers, we define the input to and the output from our proc-macro. Here’s a good non-trivial function to start out with:</p> | 123 | <p>Being respectable programmers, we define the input to and the output |
101 | <div class="sourceCode" id="cb4"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> add(x<span class="op">:</span> <span class="dt">u32</span><span class="op">,</span> y<span class="op">:</span> <span class="dt">u32</span><span class="op">,</span> z<span class="op">:</span> <span class="dt">u32</span>) <span class="op">-></span> <span class="dt">u32</span> <span class="op">{</span></span> | 124 | from our proc-macro. Here’s a good non-trivial function to start out |
102 | <span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a> <span class="kw">return</span> x <span class="op">+</span> y <span class="op">+</span> z<span class="op">;</span></span> | 125 | with:</p> |
126 | <div class="sourceCode" id="cb4"><pre | ||
127 | class="sourceCode rust"><code class="sourceCode rust"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> add(x<span class="op">:</span> <span class="dt">u32</span><span class="op">,</span> y<span class="op">:</span> <span class="dt">u32</span><span class="op">,</span> z<span class="op">:</span> <span class="dt">u32</span>) <span class="op">-></span> <span class="dt">u32</span> <span class="op">{</span></span> | ||
128 | <span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> x <span class="op">+</span> y <span class="op">+</span> z<span class="op">;</span></span> | ||
103 | <span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div> | 129 | <span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div> |
104 | <p>Hmm, what would our output look like? What should our proc-macro generate ideally? Well, if we understood currying correctly, we should accept an argument and return a function that accepts an argument and returns … you get the point. Something like this should do:</p> | 130 | <p>Hmm, what would our output look like? What should our proc-macro |
105 | <div class="sourceCode" id="cb5"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> add_curried1(x<span class="op">:</span> <span class="dt">u32</span>) <span class="op">-></span> <span class="op">?</span> <span class="op">{</span></span> | 131 | generate ideally? Well, if we understood currying correctly, we should |
106 | <span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a> <span class="kw">return</span> <span class="kw">fn</span> add_curried2 (y<span class="op">:</span> <span class="dt">u32</span>) <span class="op">-></span> <span class="op">?</span> <span class="op">{</span></span> | 132 | accept an argument and return a function that accepts an argument and |
107 | <span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a> <span class="kw">return</span> <span class="kw">fn</span> add_curried3 (z<span class="op">:</span> <span class="dt">u32</span>) <span class="op">-></span> <span class="dt">u32</span> <span class="op">{</span></span> | 133 | returns … you get the point. Something like this should do:</p> |
108 | <span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a> <span class="kw">return</span> x <span class="op">+</span> y <span class="op">+</span> z<span class="op">;</span></span> | 134 | <div class="sourceCode" id="cb5"><pre |
135 | class="sourceCode rust"><code class="sourceCode rust"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> add_curried1(x<span class="op">:</span> <span class="dt">u32</span>) <span class="op">-></span> <span class="op">?</span> <span class="op">{</span></span> | ||
136 | <span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> <span class="kw">fn</span> add_curried2 (y<span class="op">:</span> <span class="dt">u32</span>) <span class="op">-></span> <span class="op">?</span> <span class="op">{</span></span> | ||
137 | <span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> <span class="kw">fn</span> add_curried3 (z<span class="op">:</span> <span class="dt">u32</span>) <span class="op">-></span> <span class="dt">u32</span> <span class="op">{</span></span> | ||
138 | <span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> x <span class="op">+</span> y <span class="op">+</span> z<span class="op">;</span></span> | ||
109 | <span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span> | 139 | <span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span> |
110 | <span id="cb5-6"><a href="#cb5-6" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span> | 140 | <span id="cb5-6"><a href="#cb5-6" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span> |
111 | <span id="cb5-7"><a href="#cb5-7" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div> | 141 | <span id="cb5-7"><a href="#cb5-7" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div> |
112 | <p>A couple of things to note:</p> | 142 | <p>A couple of things to note:</p> |
113 | <p><strong>Return types</strong><br /> | 143 | <p><strong>Return types</strong><br /> |
114 | We have placed <code>?</code>s in place of return types. Let’s try to fix that. <code>add_curried3</code> returns the ‘value’, so <code>u32</code> is accurate. <code>add_curried2</code> returns <code>add_curried3</code>. What is the type of <code>add_curried3</code>? It is a function that takes in a <code>u32</code> and returns a <code>u32</code>. So a <code>fn(u32) -> u32</code> will do right? No, I’ll explain why in the next point, but for now, we will make use of the <code>Fn</code> trait, our return type is <code>impl Fn(u32) -> u32</code>. This basically tells the compiler that we will be returning something function-like, a.k.a, behaves like a <code>Fn</code>. Cool!</p> | 144 | We have placed <code>?</code>s in place of return types. Let’s try to |
115 | <p>If you have been following along, you should be able to tell that the return type of <code>add_curried1</code> is:</p> | 145 | fix that. <code>add_curried3</code> returns the ‘value’, so |
146 | <code>u32</code> is accurate. <code>add_curried2</code> returns | ||
147 | <code>add_curried3</code>. What is the type of | ||
148 | <code>add_curried3</code>? It is a function that takes in a | ||
149 | <code>u32</code> and returns a <code>u32</code>. So a | ||
150 | <code>fn(u32) -> u32</code> will do right? No, I’ll explain why in | ||
151 | the next point, but for now, we will make use of the <code>Fn</code> | ||
152 | trait, our return type is <code>impl Fn(u32) -> u32</code>. This | ||
153 | basically tells the compiler that we will be returning something | ||
154 | function-like, a.k.a, behaves like a <code>Fn</code>. Cool!</p> | ||
155 | <p>If you have been following along, you should be able to tell that the | ||
156 | return type of <code>add_curried1</code> is:</p> | ||
116 | <pre><code>impl Fn(u32) -> (impl Fn(u32) -> u32)</code></pre> | 157 | <pre><code>impl Fn(u32) -> (impl Fn(u32) -> u32)</code></pre> |
117 | <p>We can drop the parentheses because <code>-></code> is right associative:</p> | 158 | <p>We can drop the parentheses because <code>-></code> is right |
159 | associative:</p> | ||
118 | <pre><code>impl Fn(u32) -> impl Fn(u32) -> u32 | 160 | <pre><code>impl Fn(u32) -> impl Fn(u32) -> u32 |
119 | </code></pre> | 161 | </code></pre> |
120 | <p><strong>Accessing environment</strong><br /> | 162 | <p><strong>Accessing environment</strong><br /> |
121 | A function cannot access it’s environment. Our solution will not work. <code>add_curried3</code> attempts to access <code>x</code>, which is not allowed! A closure<a href="#fn1" class="footnote-ref" id="fnref1" role="doc-noteref"><sup>1</sup></a> however, can. If we are returning a closure, our return type must be <code>impl Fn</code>, and not <code>fn</code>. The difference between the <code>Fn</code> trait and function pointers is beyond the scope of this post.</p> | 163 | A function cannot access it’s environment. Our solution will not work. |
164 | <code>add_curried3</code> attempts to access <code>x</code>, which is | ||
165 | not allowed! A closure<a href="#fn1" class="footnote-ref" id="fnref1" | ||
166 | role="doc-noteref"><sup>1</sup></a> however, can. If we are returning a | ||
167 | closure, our return type must be <code>impl Fn</code>, and not | ||
168 | <code>fn</code>. The difference between the <code>Fn</code> trait and | ||
169 | function pointers is beyond the scope of this post.</p> | ||
122 | <h3 id="refinement">Refinement</h3> | 170 | <h3 id="refinement">Refinement</h3> |
123 | <p>Armed with knowledge, we refine our expected output, this time, employing closures:</p> | 171 | <p>Armed with knowledge, we refine our expected output, this time, |
124 | <div class="sourceCode" id="cb8"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> add(x<span class="op">:</span> <span class="dt">u32</span>) <span class="op">-></span> <span class="kw">impl</span> <span class="bu">Fn</span>(<span class="dt">u32</span>) <span class="op">-></span> <span class="kw">impl</span> <span class="bu">Fn</span>(<span class="dt">u32</span>) <span class="op">-></span> <span class="dt">u32</span> <span class="op">{</span></span> | 172 | employing closures:</p> |
125 | <span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a> <span class="kw">return</span> <span class="kw">move</span> <span class="op">|</span>y<span class="op">|</span> <span class="kw">move</span> <span class="op">|</span>z<span class="op">|</span> x <span class="op">+</span> y <span class="op">+</span> z<span class="op">;</span></span> | 173 | <div class="sourceCode" id="cb8"><pre |
174 | class="sourceCode rust"><code class="sourceCode rust"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> add(x<span class="op">:</span> <span class="dt">u32</span>) <span class="op">-></span> <span class="kw">impl</span> <span class="bu">Fn</span>(<span class="dt">u32</span>) <span class="op">-></span> <span class="kw">impl</span> <span class="bu">Fn</span>(<span class="dt">u32</span>) <span class="op">-></span> <span class="dt">u32</span> <span class="op">{</span></span> | ||
175 | <span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> <span class="kw">move</span> <span class="op">|</span>y<span class="op">|</span> <span class="kw">move</span> <span class="op">|</span>z<span class="op">|</span> x <span class="op">+</span> y <span class="op">+</span> z<span class="op">;</span></span> | ||
126 | <span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div> | 176 | <span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div> |
127 | <p>Alas, that does not compile either! It errors out with the following message:</p> | 177 | <p>Alas, that does not compile either! It errors out with the following |
178 | message:</p> | ||
128 | <pre><code>error[E0562]: `impl Trait` not allowed outside of function | 179 | <pre><code>error[E0562]: `impl Trait` not allowed outside of function |
129 | and inherent method return types | 180 | and inherent method return types |
130 | --> src/main.rs:17:37 | 181 | --> src/main.rs:17:37 |
@@ -132,21 +183,33 @@ and inherent method return types | |||
132 | | fn add(x: u32) -> impl Fn(u32) -> impl Fn(u32) -> u32 | 183 | | fn add(x: u32) -> impl Fn(u32) -> impl Fn(u32) -> u32 |
133 | | ^^^^^^^^^^^^^^^^^^^ | 184 | | ^^^^^^^^^^^^^^^^^^^ |
134 | </code></pre> | 185 | </code></pre> |
135 | <p>You are allowed to return an <code>impl Fn</code> only inside a function. We are currently returning it from another return! Or at least, that was the most I could make out of the error message.</p> | 186 | <p>You are allowed to return an <code>impl Fn</code> only inside a |
136 | <p>We are going to have to cheat a bit to fix this issue; with type aliases and a convenient nightly feature <a href="#fn2" class="footnote-ref" id="fnref2" role="doc-noteref"><sup>2</sup></a>:</p> | 187 | function. We are currently returning it from another return! Or at |
137 | <div class="sourceCode" id="cb10"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="at">#![</span>feature<span class="at">(</span>type_alias_impl_trait<span class="at">)]</span> <span class="co">// allows us to use `impl Fn` in type aliases!</span></span> | 188 | least, that was the most I could make out of the error message.</p> |
189 | <p>We are going to have to cheat a bit to fix this issue; with type | ||
190 | aliases and a convenient nightly feature <a href="#fn2" | ||
191 | class="footnote-ref" id="fnref2" | ||
192 | role="doc-noteref"><sup>2</sup></a>:</p> | ||
193 | <div class="sourceCode" id="cb10"><pre | ||
194 | class="sourceCode rust"><code class="sourceCode rust"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="at">#![</span>feature<span class="at">(</span>type_alias_impl_trait<span class="at">)]</span> <span class="co">// allows us to use `impl Fn` in type aliases!</span></span> | ||
138 | <span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a></span> | 195 | <span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a></span> |
139 | <span id="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> T0 <span class="op">=</span> <span class="dt">u32</span><span class="op">;</span> <span class="co">// the return value when zero args are to be applied</span></span> | 196 | <span id="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> T0 <span class="op">=</span> <span class="dt">u32</span><span class="op">;</span> <span class="co">// the return value when zero args are to be applied</span></span> |
140 | <span id="cb10-4"><a href="#cb10-4" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> T1 <span class="op">=</span> <span class="kw">impl</span> <span class="bu">Fn</span>(<span class="dt">u32</span>) <span class="op">-></span> T0<span class="op">;</span> <span class="co">// the return value when one arg is to be applied</span></span> | 197 | <span id="cb10-4"><a href="#cb10-4" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> T1 <span class="op">=</span> <span class="kw">impl</span> <span class="bu">Fn</span>(<span class="dt">u32</span>) <span class="op">-></span> T0<span class="op">;</span> <span class="co">// the return value when one arg is to be applied</span></span> |
141 | <span id="cb10-5"><a href="#cb10-5" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> T2 <span class="op">=</span> <span class="kw">impl</span> <span class="bu">Fn</span>(<span class="dt">u32</span>) <span class="op">-></span> T1<span class="op">;</span> <span class="co">// the return value when two args are to be applied</span></span> | 198 | <span id="cb10-5"><a href="#cb10-5" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> T2 <span class="op">=</span> <span class="kw">impl</span> <span class="bu">Fn</span>(<span class="dt">u32</span>) <span class="op">-></span> T1<span class="op">;</span> <span class="co">// the return value when two args are to be applied</span></span> |
142 | <span id="cb10-6"><a href="#cb10-6" aria-hidden="true" tabindex="-1"></a></span> | 199 | <span id="cb10-6"><a href="#cb10-6" aria-hidden="true" tabindex="-1"></a></span> |
143 | <span id="cb10-7"><a href="#cb10-7" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> add(x<span class="op">:</span> <span class="dt">u32</span>) <span class="op">-></span> T2 <span class="op">{</span></span> | 200 | <span id="cb10-7"><a href="#cb10-7" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> add(x<span class="op">:</span> <span class="dt">u32</span>) <span class="op">-></span> T2 <span class="op">{</span></span> |
144 | <span id="cb10-8"><a href="#cb10-8" aria-hidden="true" tabindex="-1"></a> <span class="kw">return</span> <span class="kw">move</span> <span class="op">|</span>y<span class="op">|</span> <span class="kw">move</span> <span class="op">|</span>z<span class="op">|</span> x <span class="op">+</span> y <span class="op">+</span> z<span class="op">;</span></span> | 201 | <span id="cb10-8"><a href="#cb10-8" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> <span class="kw">move</span> <span class="op">|</span>y<span class="op">|</span> <span class="kw">move</span> <span class="op">|</span>z<span class="op">|</span> x <span class="op">+</span> y <span class="op">+</span> z<span class="op">;</span></span> |
145 | <span id="cb10-9"><a href="#cb10-9" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div> | 202 | <span id="cb10-9"><a href="#cb10-9" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div> |
146 | <p>Drop that into a cargo project, call <code>add(4)(5)(6)</code>, cross your fingers, and run <code>cargo +nightly run</code>. You should see a 15 unless you forgot to print it!</p> | 203 | <p>Drop that into a cargo project, call <code>add(4)(5)(6)</code>, cross |
204 | your fingers, and run <code>cargo +nightly run</code>. You should see a | ||
205 | 15 unless you forgot to print it!</p> | ||
147 | <h3 id="the-in-betweens">The In-Betweens</h3> | 206 | <h3 id="the-in-betweens">The In-Betweens</h3> |
148 | <p>Let us write the magical bits that take us from function to curried function.</p> | 207 | <p>Let us write the magical bits that take us from function to curried |
149 | <p>Initialize your workspace with <code>cargo new --lib currying</code>. Proc-macro crates are libraries with exactly one export, the macro itself. Add a <code>tests</code> directory to your crate root. Your directory should look something like this:</p> | 208 | function.</p> |
209 | <p>Initialize your workspace with <code>cargo new --lib currying</code>. | ||
210 | Proc-macro crates are libraries with exactly one export, the macro | ||
211 | itself. Add a <code>tests</code> directory to your crate root. Your | ||
212 | directory should look something like this:</p> | ||
150 | <pre><code>. | 213 | <pre><code>. |
151 | ├── Cargo.toml | 214 | ├── Cargo.toml |
152 | ├── src | 215 | ├── src |
@@ -156,9 +219,11 @@ and inherent method return types | |||
156 | <h4 id="dependencies">Dependencies</h4> | 219 | <h4 id="dependencies">Dependencies</h4> |
157 | <p>We will be using a total of 3 external crates:</p> | 220 | <p>We will be using a total of 3 external crates:</p> |
158 | <ul> | 221 | <ul> |
159 | <li><a href="https://docs.rs/proc-macro2/1.0.12/proc_macro2/">proc_macro2</a></li> | 222 | <li><a |
223 | href="https://docs.rs/proc-macro2/1.0.12/proc_macro2/">proc_macro2</a></li> | ||
160 | <li><a href="https://docs.rs/syn/1.0.18/syn/index.html">syn</a></li> | 224 | <li><a href="https://docs.rs/syn/1.0.18/syn/index.html">syn</a></li> |
161 | <li><a href="https://docs.rs/quote/1.0.4/quote/index.html">quote</a></li> | 225 | <li><a |
226 | href="https://docs.rs/quote/1.0.4/quote/index.html">quote</a></li> | ||
162 | </ul> | 227 | </ul> |
163 | <p>Here’s a sample <code>Cargo.toml</code>:</p> | 228 | <p>Here’s a sample <code>Cargo.toml</code>:</p> |
164 | <pre><code># Cargo.toml | 229 | <pre><code># Cargo.toml |
@@ -173,10 +238,12 @@ features = ["full"] | |||
173 | 238 | ||
174 | [lib] | 239 | [lib] |
175 | proc-macro = true # this is important!</code></pre> | 240 | proc-macro = true # this is important!</code></pre> |
176 | <p>We will be using an external <code>proc-macro2</code> crate as well as an internal <code>proc-macro</code> crate. Not confusing at all!</p> | 241 | <p>We will be using an external <code>proc-macro2</code> crate as well |
242 | as an internal <code>proc-macro</code> crate. Not confusing at all!</p> | ||
177 | <h4 id="the-attribute-macro">The attribute macro</h4> | 243 | <h4 id="the-attribute-macro">The attribute macro</h4> |
178 | <p>Drop this into <code>src/lib.rs</code>, to get the ball rolling.</p> | 244 | <p>Drop this into <code>src/lib.rs</code>, to get the ball rolling.</p> |
179 | <div class="sourceCode" id="cb13"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true" tabindex="-1"></a><span class="co">// src/lib.rs</span></span> | 245 | <div class="sourceCode" id="cb13"><pre |
246 | class="sourceCode rust"><code class="sourceCode rust"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true" tabindex="-1"></a><span class="co">// src/lib.rs</span></span> | ||
180 | <span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a></span> | 247 | <span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a></span> |
181 | <span id="cb13-3"><a href="#cb13-3" aria-hidden="true" tabindex="-1"></a><span class="kw">use</span> <span class="pp">proc_macro::</span>TokenStream<span class="op">;</span> <span class="co">// 1</span></span> | 248 | <span id="cb13-3"><a href="#cb13-3" aria-hidden="true" tabindex="-1"></a><span class="kw">use</span> <span class="pp">proc_macro::</span>TokenStream<span class="op">;</span> <span class="co">// 1</span></span> |
182 | <span id="cb13-4"><a href="#cb13-4" aria-hidden="true" tabindex="-1"></a><span class="kw">use</span> <span class="pp">quote::</span>quote<span class="op">;</span></span> | 249 | <span id="cb13-4"><a href="#cb13-4" aria-hidden="true" tabindex="-1"></a><span class="kw">use</span> <span class="pp">quote::</span>quote<span class="op">;</span></span> |
@@ -190,17 +257,49 @@ proc-macro = true # this is important!</code></pre> | |||
190 | <span id="cb13-12"><a href="#cb13-12" aria-hidden="true" tabindex="-1"></a></span> | 257 | <span id="cb13-12"><a href="#cb13-12" aria-hidden="true" tabindex="-1"></a></span> |
191 | <span id="cb13-13"><a href="#cb13-13" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> generate_curry(parsed<span class="op">:</span> ItemFn) <span class="op">-></span> <span class="pp">proc_macro2::</span>TokenStream <span class="op">{}</span></span></code></pre></div> | 258 | <span id="cb13-13"><a href="#cb13-13" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> generate_curry(parsed<span class="op">:</span> ItemFn) <span class="op">-></span> <span class="pp">proc_macro2::</span>TokenStream <span class="op">{}</span></span></code></pre></div> |
192 | <p><strong>1. Imports</strong></p> | 259 | <p><strong>1. Imports</strong></p> |
193 | <p>A <code>Tokenstream</code> holds (hopefully valid) Rust code, this is the type of our input and output. Note that we are importing this type from <code>proc_macro</code> and not <code>proc_macro2</code>.</p> | 260 | <p>A <code>Tokenstream</code> holds (hopefully valid) Rust code, this is |
194 | <p><code>quote!</code> from the <code>quote</code> crate is a macro that allows us to quickly produce <code>TokenStream</code>s. Much like the LISP <code>quote</code> procedure, you can use the <code>quote!</code> macro for symbolic transformations.</p> | 261 | the type of our input and output. Note that we are importing this type |
195 | <p><code>ItemFn</code> from the <code>syn</code> crate holds the parsed <code>TokenStream</code> of a Rust function. <code>parse_macro_input!</code> is a helper macro provided by <code>syn</code>.</p> | 262 | from <code>proc_macro</code> and not <code>proc_macro2</code>.</p> |
263 | <p><code>quote!</code> from the <code>quote</code> crate is a macro that | ||
264 | allows us to quickly produce <code>TokenStream</code>s. Much like the | ||
265 | LISP <code>quote</code> procedure, you can use the <code>quote!</code> | ||
266 | macro for symbolic transformations.</p> | ||
267 | <p><code>ItemFn</code> from the <code>syn</code> crate holds the parsed | ||
268 | <code>TokenStream</code> of a Rust function. | ||
269 | <code>parse_macro_input!</code> is a helper macro provided by | ||
270 | <code>syn</code>.</p> | ||
196 | <p><strong>2. The lone export</strong></p> | 271 | <p><strong>2. The lone export</strong></p> |
197 | <p>Annotate the only <code>pub</code> of our crate with <code>#[proc_macro_attribute]</code>. This tells rustc that <code>curry</code> is a procedural macro, and allows us to use it as <code>#[crate_name::curry]</code> in other crates. Note the signature of the <code>curry</code> function. <code>_attr</code> is the <code>TokenStream</code> representing the attribute itself, <code>item</code> refers to the thing we slapped our macro into, in this case a function (like <code>add</code>). The return value is a modified <code>TokenStream</code>, this will contain our curried version of <code>add</code>.</p> | 272 | <p>Annotate the only <code>pub</code> of our crate with |
273 | <code>#[proc_macro_attribute]</code>. This tells rustc that | ||
274 | <code>curry</code> is a procedural macro, and allows us to use it as | ||
275 | <code>#[crate_name::curry]</code> in other crates. Note the signature of | ||
276 | the <code>curry</code> function. <code>_attr</code> is the | ||
277 | <code>TokenStream</code> representing the attribute itself, | ||
278 | <code>item</code> refers to the thing we slapped our macro into, in this | ||
279 | case a function (like <code>add</code>). The return value is a modified | ||
280 | <code>TokenStream</code>, this will contain our curried version of | ||
281 | <code>add</code>.</p> | ||
198 | <p><strong>3. The helper macro</strong></p> | 282 | <p><strong>3. The helper macro</strong></p> |
199 | <p>A <code>TokenStream</code> is a little hard to work with, which is why we have the <code>syn</code> crate, which provides types to represent Rust tokens. An <code>RArrow</code> struct to represent the return arrow on a function and so on. One of those types is <code>ItemFn</code>, that represents an entire Rust function. The <code>parse_macro_input!</code> automatically puts the input to our macro into an <code>ItemFn</code>. What a gentleman!</p> | 283 | <p>A <code>TokenStream</code> is a little hard to work with, which is |
284 | why we have the <code>syn</code> crate, which provides types to | ||
285 | represent Rust tokens. An <code>RArrow</code> struct to represent the | ||
286 | return arrow on a function and so on. One of those types is | ||
287 | <code>ItemFn</code>, that represents an entire Rust function. The | ||
288 | <code>parse_macro_input!</code> automatically puts the input to our | ||
289 | macro into an <code>ItemFn</code>. What a gentleman!</p> | ||
200 | <p><strong>4. Returning <code>TokenStream</code>s </strong></p> | 290 | <p><strong>4. Returning <code>TokenStream</code>s </strong></p> |
201 | <p>We haven’t filled in <code>generate_curry</code> yet, but we can see that it returns a <code>proc_macro2::TokenStream</code> and not a <code>proc_macro::TokenStream</code>, so drop a <code>.into()</code> to convert it.</p> | 291 | <p>We haven’t filled in <code>generate_curry</code> yet, but we can see |
202 | <p>Lets move on, and fill in <code>generate_curry</code>, I would suggest keeping the documentation for <a href="https://docs.rs/syn/1.0.19/syn/struct.ItemFn.html"><code>syn::ItemFn</code></a> and <a href="https://docs.rs/syn/1.0.19/syn/struct.Signature.html"><code>syn::Signature</code></a> open.</p> | 292 | that it returns a <code>proc_macro2::TokenStream</code> and not a |
203 | <div class="sourceCode" id="cb14"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb14-1"><a href="#cb14-1" aria-hidden="true" tabindex="-1"></a><span class="co">// src/lib.rs</span></span> | 293 | <code>proc_macro::TokenStream</code>, so drop a <code>.into()</code> to |
294 | convert it.</p> | ||
295 | <p>Lets move on, and fill in <code>generate_curry</code>, I would | ||
296 | suggest keeping the documentation for <a | ||
297 | href="https://docs.rs/syn/1.0.19/syn/struct.ItemFn.html"><code>syn::ItemFn</code></a> | ||
298 | and <a | ||
299 | href="https://docs.rs/syn/1.0.19/syn/struct.Signature.html"><code>syn::Signature</code></a> | ||
300 | open.</p> | ||
301 | <div class="sourceCode" id="cb14"><pre | ||
302 | class="sourceCode rust"><code class="sourceCode rust"><span id="cb14-1"><a href="#cb14-1" aria-hidden="true" tabindex="-1"></a><span class="co">// src/lib.rs</span></span> | ||
204 | <span id="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a></span> | 303 | <span id="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a></span> |
205 | <span id="cb14-3"><a href="#cb14-3" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> generate_curry(parsed<span class="op">:</span> ItemFn) <span class="op">-></span> <span class="pp">proc_macro2::</span>TokenStream <span class="op">{</span></span> | 304 | <span id="cb14-3"><a href="#cb14-3" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> generate_curry(parsed<span class="op">:</span> ItemFn) <span class="op">-></span> <span class="pp">proc_macro2::</span>TokenStream <span class="op">{</span></span> |
206 | <span id="cb14-4"><a href="#cb14-4" aria-hidden="true" tabindex="-1"></a> <span class="kw">let</span> fn_body <span class="op">=</span> parsed<span class="op">.</span>block<span class="op">;</span> <span class="co">// function body</span></span> | 305 | <span id="cb14-4"><a href="#cb14-4" aria-hidden="true" tabindex="-1"></a> <span class="kw">let</span> fn_body <span class="op">=</span> parsed<span class="op">.</span>block<span class="op">;</span> <span class="co">// function body</span></span> |
@@ -210,7 +309,9 @@ proc-macro = true # this is important!</code></pre> | |||
210 | <span id="cb14-8"><a href="#cb14-8" aria-hidden="true" tabindex="-1"></a> <span class="kw">let</span> fn_args <span class="op">=</span> sig<span class="op">.</span>inputs<span class="op">;</span> <span class="co">// comma separated args</span></span> | 309 | <span id="cb14-8"><a href="#cb14-8" aria-hidden="true" tabindex="-1"></a> <span class="kw">let</span> fn_args <span class="op">=</span> sig<span class="op">.</span>inputs<span class="op">;</span> <span class="co">// comma separated args</span></span> |
211 | <span id="cb14-9"><a href="#cb14-9" aria-hidden="true" tabindex="-1"></a> <span class="kw">let</span> fn_return_type <span class="op">=</span> sig<span class="op">.</span>output<span class="op">;</span> <span class="co">// return type</span></span> | 310 | <span id="cb14-9"><a href="#cb14-9" aria-hidden="true" tabindex="-1"></a> <span class="kw">let</span> fn_return_type <span class="op">=</span> sig<span class="op">.</span>output<span class="op">;</span> <span class="co">// return type</span></span> |
212 | <span id="cb14-10"><a href="#cb14-10" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div> | 311 | <span id="cb14-10"><a href="#cb14-10" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div> |
213 | <p>We are simply extracting the bits of the function, we will be reusing the original function’s visibility and name. Take a look at what <code>syn::Signature</code> can tell us about a function:</p> | 312 | <p>We are simply extracting the bits of the function, we will be reusing |
313 | the original function’s visibility and name. Take a look at what | ||
314 | <code>syn::Signature</code> can tell us about a function:</p> | ||
214 | <pre><code> .-- syn::Ident (ident) | 315 | <pre><code> .-- syn::Ident (ident) |
215 | / | 316 | / |
216 | fn add(x: u32, y: u32) -> u32 | 317 | fn add(x: u32, y: u32) -> u32 |
@@ -220,42 +321,77 @@ syn::token::Fn --' / \ (output) | |||
220 | Punctuated<FnArg, Comma> (inputs)</code></pre> | 321 | Punctuated<FnArg, Comma> (inputs)</code></pre> |
221 | <p>Enough analysis, lets produce our first bit of Rust code.</p> | 322 | <p>Enough analysis, lets produce our first bit of Rust code.</p> |
222 | <h4 id="function-body">Function Body</h4> | 323 | <h4 id="function-body">Function Body</h4> |
223 | <p>Recall that the body of a curried <code>add</code> should look like this:</p> | 324 | <p>Recall that the body of a curried <code>add</code> should look like |
224 | <div class="sourceCode" id="cb16"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb16-1"><a href="#cb16-1" aria-hidden="true" tabindex="-1"></a><span class="kw">return</span> <span class="kw">move</span> <span class="op">|</span>y<span class="op">|</span> <span class="kw">move</span> <span class="op">|</span>z<span class="op">|</span> x <span class="op">+</span> y <span class="op">+</span> z<span class="op">;</span></span></code></pre></div> | 325 | this:</p> |
326 | <div class="sourceCode" id="cb16"><pre | ||
327 | class="sourceCode rust"><code class="sourceCode rust"><span id="cb16-1"><a href="#cb16-1" aria-hidden="true" tabindex="-1"></a><span class="cf">return</span> <span class="kw">move</span> <span class="op">|</span>y<span class="op">|</span> <span class="kw">move</span> <span class="op">|</span>z<span class="op">|</span> x <span class="op">+</span> y <span class="op">+</span> z<span class="op">;</span></span></code></pre></div> | ||
225 | <p>And in general:</p> | 328 | <p>And in general:</p> |
226 | <div class="sourceCode" id="cb17"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb17-1"><a href="#cb17-1" aria-hidden="true" tabindex="-1"></a><span class="kw">return</span> <span class="kw">move</span> <span class="op">|</span>arg2<span class="op">|</span> <span class="kw">move</span> <span class="op">|</span>arg3<span class="op">|</span> <span class="op">...</span> <span class="op">|</span>argN<span class="op">|</span> <span class="op"><</span>function body here<span class="op">></span></span></code></pre></div> | 329 | <div class="sourceCode" id="cb17"><pre |
227 | <p>We already have the function’s body, provided by <code>fn_body</code>, in our <code>generate_curry</code> function. All that’s left to add is the <code>move |arg2| move |arg3| ...</code> stuff, for which we need to extract the argument identifiers (doc: <a href="https://docs.rs/syn/1.0.18/syn/punctuated/struct.Punctuated.html">Punctuated</a>, <a href="https://docs.rs/syn/1.0.18/syn/enum.FnArg.html">FnArg</a>, <a href="https://docs.rs/syn/1.0.18/syn/struct.PatType.html">PatType</a>):</p> | 330 | class="sourceCode rust"><code class="sourceCode rust"><span id="cb17-1"><a href="#cb17-1" aria-hidden="true" tabindex="-1"></a><span class="cf">return</span> <span class="kw">move</span> <span class="op">|</span>arg2<span class="op">|</span> <span class="kw">move</span> <span class="op">|</span>arg3<span class="op">|</span> <span class="op">...</span> <span class="op">|</span>argN<span class="op">|</span> <span class="op"><</span>function body here<span class="op">></span></span></code></pre></div> |
228 | <div class="sourceCode" id="cb18"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb18-1"><a href="#cb18-1" aria-hidden="true" tabindex="-1"></a><span class="co">// src/lib.rs</span></span> | 331 | <p>We already have the function’s body, provided by |
332 | <code>fn_body</code>, in our <code>generate_curry</code> function. All | ||
333 | that’s left to add is the <code>move |arg2| move |arg3| ...</code> | ||
334 | stuff, for which we need to extract the argument identifiers (doc: <a | ||
335 | href="https://docs.rs/syn/1.0.18/syn/punctuated/struct.Punctuated.html">Punctuated</a>, | ||
336 | <a href="https://docs.rs/syn/1.0.18/syn/enum.FnArg.html">FnArg</a>, <a | ||
337 | href="https://docs.rs/syn/1.0.18/syn/struct.PatType.html">PatType</a>):</p> | ||
338 | <div class="sourceCode" id="cb18"><pre | ||
339 | class="sourceCode rust"><code class="sourceCode rust"><span id="cb18-1"><a href="#cb18-1" aria-hidden="true" tabindex="-1"></a><span class="co">// src/lib.rs</span></span> | ||
229 | <span id="cb18-2"><a href="#cb18-2" aria-hidden="true" tabindex="-1"></a><span class="kw">use</span> <span class="pp">syn::punctuated::</span>Punctuated<span class="op">;</span></span> | 340 | <span id="cb18-2"><a href="#cb18-2" aria-hidden="true" tabindex="-1"></a><span class="kw">use</span> <span class="pp">syn::punctuated::</span>Punctuated<span class="op">;</span></span> |
230 | <span id="cb18-3"><a href="#cb18-3" aria-hidden="true" tabindex="-1"></a><span class="kw">use</span> <span class="pp">syn::</span><span class="op">{</span>parse_macro_input<span class="op">,</span> FnArg<span class="op">,</span> Pat<span class="op">,</span> ItemFn<span class="op">,</span> Block<span class="op">};</span></span> | 341 | <span id="cb18-3"><a href="#cb18-3" aria-hidden="true" tabindex="-1"></a><span class="kw">use</span> <span class="pp">syn::</span><span class="op">{</span>parse_macro_input<span class="op">,</span> FnArg<span class="op">,</span> Pat<span class="op">,</span> ItemFn<span class="op">,</span> Block<span class="op">};</span></span> |
231 | <span id="cb18-4"><a href="#cb18-4" aria-hidden="true" tabindex="-1"></a></span> | 342 | <span id="cb18-4"><a href="#cb18-4" aria-hidden="true" tabindex="-1"></a></span> |
232 | <span id="cb18-5"><a href="#cb18-5" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> extract_arg_idents(fn_args<span class="op">:</span> Punctuated<span class="op"><</span>FnArg<span class="op">,</span> <span class="pp">syn::token::</span>Comma<span class="op">></span>) <span class="op">-></span> <span class="dt">Vec</span><span class="op"><</span><span class="dt">Box</span><span class="op"><</span>Pat<span class="op">>></span> <span class="op">{</span> </span> | 343 | <span id="cb18-5"><a href="#cb18-5" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> extract_arg_idents(fn_args<span class="op">:</span> Punctuated<span class="op"><</span>FnArg<span class="op">,</span> <span class="pp">syn::token::</span>Comma<span class="op">></span>) <span class="op">-></span> <span class="dt">Vec</span><span class="op"><</span><span class="dt">Box</span><span class="op"><</span>Pat<span class="op">>></span> <span class="op">{</span> </span> |
233 | <span id="cb18-6"><a href="#cb18-6" aria-hidden="true" tabindex="-1"></a> <span class="kw">return</span> fn_args<span class="op">.</span>into_iter()<span class="op">.</span>map(extract_arg_pat)<span class="op">.</span><span class="pp">collect::</span><span class="op"><</span><span class="dt">Vec</span><span class="op"><</span>_<span class="op">>></span>()<span class="op">;</span></span> | 344 | <span id="cb18-6"><a href="#cb18-6" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> fn_args<span class="op">.</span>into_iter()<span class="op">.</span>map(extract_arg_pat)<span class="op">.</span><span class="pp">collect::</span><span class="op"><</span><span class="dt">Vec</span><span class="op"><</span>_<span class="op">>></span>()<span class="op">;</span></span> |
234 | <span id="cb18-7"><a href="#cb18-7" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div> | 345 | <span id="cb18-7"><a href="#cb18-7" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div> |
235 | <p>Alright, so we are iterating over function args (<code>Punctuated</code> is a collection that you can iterate over) and mapping an <code>extract_arg_pat</code> to every item. What’s <code>extract_arg_pat</code>?</p> | 346 | <p>Alright, so we are iterating over function args |
236 | <div class="sourceCode" id="cb19"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb19-1"><a href="#cb19-1" aria-hidden="true" tabindex="-1"></a><span class="co">// src/lib.rs</span></span> | 347 | (<code>Punctuated</code> is a collection that you can iterate over) and |
348 | mapping an <code>extract_arg_pat</code> to every item. What’s | ||
349 | <code>extract_arg_pat</code>?</p> | ||
350 | <div class="sourceCode" id="cb19"><pre | ||
351 | class="sourceCode rust"><code class="sourceCode rust"><span id="cb19-1"><a href="#cb19-1" aria-hidden="true" tabindex="-1"></a><span class="co">// src/lib.rs</span></span> | ||
237 | <span id="cb19-2"><a href="#cb19-2" aria-hidden="true" tabindex="-1"></a></span> | 352 | <span id="cb19-2"><a href="#cb19-2" aria-hidden="true" tabindex="-1"></a></span> |
238 | <span id="cb19-3"><a href="#cb19-3" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> extract_arg_pat(a<span class="op">:</span> FnArg) <span class="op">-></span> <span class="dt">Box</span><span class="op"><</span>Pat<span class="op">></span> <span class="op">{</span></span> | 353 | <span id="cb19-3"><a href="#cb19-3" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> extract_arg_pat(a<span class="op">:</span> FnArg) <span class="op">-></span> <span class="dt">Box</span><span class="op"><</span>Pat<span class="op">></span> <span class="op">{</span></span> |
239 | <span id="cb19-4"><a href="#cb19-4" aria-hidden="true" tabindex="-1"></a> <span class="kw">match</span> a <span class="op">{</span></span> | 354 | <span id="cb19-4"><a href="#cb19-4" aria-hidden="true" tabindex="-1"></a> <span class="cf">match</span> a <span class="op">{</span></span> |
240 | <span id="cb19-5"><a href="#cb19-5" aria-hidden="true" tabindex="-1"></a> <span class="pp">FnArg::</span>Typed(p) <span class="op">=></span> p<span class="op">.</span>pat<span class="op">,</span></span> | 355 | <span id="cb19-5"><a href="#cb19-5" aria-hidden="true" tabindex="-1"></a> <span class="pp">FnArg::</span>Typed(p) <span class="op">=></span> p<span class="op">.</span>pat<span class="op">,</span></span> |
241 | <span id="cb19-6"><a href="#cb19-6" aria-hidden="true" tabindex="-1"></a> _ <span class="op">=></span> <span class="pp">panic!</span>(<span class="st">"Not supported on types with `self`!"</span>)<span class="op">,</span></span> | 356 | <span id="cb19-6"><a href="#cb19-6" aria-hidden="true" tabindex="-1"></a> _ <span class="op">=></span> <span class="pp">panic!</span>(<span class="st">"Not supported on types with `self`!"</span>)<span class="op">,</span></span> |
242 | <span id="cb19-7"><a href="#cb19-7" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span> | 357 | <span id="cb19-7"><a href="#cb19-7" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span> |
243 | <span id="cb19-8"><a href="#cb19-8" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div> | 358 | <span id="cb19-8"><a href="#cb19-8" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div> |
244 | <p><code>FnArg</code> is an enum type as you might have guessed. The <code>Typed</code> variant encompasses args that are written as <code>name: type</code> and the other variant, <code>Reciever</code> refers to <code>self</code> types. Ignore those for now, keep it simple.</p> | 359 | <p><code>FnArg</code> is an enum type as you might have guessed. The |
245 | <p>Every <code>FnArg::Typed</code> value contains a <code>pat</code>, which is in essence, the name of the argument. The type of the arg is accessible via <code>p.ty</code> (we will be using this later).</p> | 360 | <code>Typed</code> variant encompasses args that are written as |
246 | <p>With that done, we should be able to write the codegen for the function body:</p> | 361 | <code>name: type</code> and the other variant, <code>Reciever</code> |
247 | <div class="sourceCode" id="cb20"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb20-1"><a href="#cb20-1" aria-hidden="true" tabindex="-1"></a><span class="co">// src/lib.rs</span></span> | 362 | refers to <code>self</code> types. Ignore those for now, keep it |
363 | simple.</p> | ||
364 | <p>Every <code>FnArg::Typed</code> value contains a <code>pat</code>, | ||
365 | which is in essence, the name of the argument. The type of the arg is | ||
366 | accessible via <code>p.ty</code> (we will be using this later).</p> | ||
367 | <p>With that done, we should be able to write the codegen for the | ||
368 | function body:</p> | ||
369 | <div class="sourceCode" id="cb20"><pre | ||
370 | class="sourceCode rust"><code class="sourceCode rust"><span id="cb20-1"><a href="#cb20-1" aria-hidden="true" tabindex="-1"></a><span class="co">// src/lib.rs</span></span> | ||
248 | <span id="cb20-2"><a href="#cb20-2" aria-hidden="true" tabindex="-1"></a></span> | 371 | <span id="cb20-2"><a href="#cb20-2" aria-hidden="true" tabindex="-1"></a></span> |
249 | <span id="cb20-3"><a href="#cb20-3" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> generate_body(fn_args<span class="op">:</span> <span class="op">&</span>[<span class="dt">Box</span><span class="op"><</span>Pat<span class="op">></span>]<span class="op">,</span> body<span class="op">:</span> <span class="dt">Box</span><span class="op"><</span>Block<span class="op">></span>) <span class="op">-></span> <span class="pp">proc_macro2::</span>TokenStream <span class="op">{</span></span> | 372 | <span id="cb20-3"><a href="#cb20-3" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> generate_body(fn_args<span class="op">:</span> <span class="op">&</span>[<span class="dt">Box</span><span class="op"><</span>Pat<span class="op">></span>]<span class="op">,</span> body<span class="op">:</span> <span class="dt">Box</span><span class="op"><</span>Block<span class="op">></span>) <span class="op">-></span> <span class="pp">proc_macro2::</span>TokenStream <span class="op">{</span></span> |
250 | <span id="cb20-4"><a href="#cb20-4" aria-hidden="true" tabindex="-1"></a> <span class="pp">quote!</span> <span class="op">{</span></span> | 373 | <span id="cb20-4"><a href="#cb20-4" aria-hidden="true" tabindex="-1"></a> <span class="pp">quote!</span> <span class="op">{</span></span> |
251 | <span id="cb20-5"><a href="#cb20-5" aria-hidden="true" tabindex="-1"></a> <span class="kw">return</span> #( <span class="kw">move</span> <span class="op">|</span>#fn_args<span class="op">|</span> )<span class="op">*</span> #body</span> | 374 | <span id="cb20-5"><a href="#cb20-5" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> #( <span class="kw">move</span> <span class="op">|</span>#fn_args<span class="op">|</span> )<span class="op">*</span> #body</span> |
252 | <span id="cb20-6"><a href="#cb20-6" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span> | 375 | <span id="cb20-6"><a href="#cb20-6" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span> |
253 | <span id="cb20-7"><a href="#cb20-7" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div> | 376 | <span id="cb20-7"><a href="#cb20-7" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div> |
254 | <p>That is some scary looking syntax! Allow me to explain. The <code>quote!{ ... }</code> returns a <code>proc_macro2::TokenStream</code>, if we wrote <code>quote!{ let x = 1 + 2; }</code>, it wouldn’t create a new variable <code>x</code> with value 3, it would literally produce a stream of tokens with that expression.</p> | 377 | <p>That is some scary looking syntax! Allow me to explain. The |
255 | <p>The <code>#</code> enables variable interpolation. <code>#body</code> will look for <code>body</code> in the current scope, take its value, and insert it in the returned <code>TokenStream</code>. Kinda like quasi quoting in LISPs, you have written one.</p> | 378 | <code>quote!{ ... }</code> returns a |
256 | <p>What about <code>#( move |#fn_args| )*</code>? That is repetition. <code>quote</code> iterates through <code>fn_args</code>, and drops a <code>move</code> behind each one, it then places pipes (<code>|</code>), around it.</p> | 379 | <code>proc_macro2::TokenStream</code>, if we wrote |
257 | <p>Let us test our first bit of codegen! Modify <code>generate_curry</code> like so:</p> | 380 | <code>quote!{ let x = 1 + 2; }</code>, it wouldn’t create a new variable |
258 | <div class="sourceCode" id="cb21"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb21-1"><a href="#cb21-1" aria-hidden="true" tabindex="-1"></a><span class="co">// src/lib.rs</span></span> | 381 | <code>x</code> with value 3, it would literally produce a stream of |
382 | tokens with that expression.</p> | ||
383 | <p>The <code>#</code> enables variable interpolation. <code>#body</code> | ||
384 | will look for <code>body</code> in the current scope, take its value, | ||
385 | and insert it in the returned <code>TokenStream</code>. Kinda like quasi | ||
386 | quoting in LISPs, you have written one.</p> | ||
387 | <p>What about <code>#( move |#fn_args| )*</code>? That is repetition. | ||
388 | <code>quote</code> iterates through <code>fn_args</code>, and drops a | ||
389 | <code>move</code> behind each one, it then places pipes | ||
390 | (<code>|</code>), around it.</p> | ||
391 | <p>Let us test our first bit of codegen! Modify | ||
392 | <code>generate_curry</code> like so:</p> | ||
393 | <div class="sourceCode" id="cb21"><pre | ||
394 | class="sourceCode rust"><code class="sourceCode rust"><span id="cb21-1"><a href="#cb21-1" aria-hidden="true" tabindex="-1"></a><span class="co">// src/lib.rs</span></span> | ||
259 | <span id="cb21-2"><a href="#cb21-2" aria-hidden="true" tabindex="-1"></a></span> | 395 | <span id="cb21-2"><a href="#cb21-2" aria-hidden="true" tabindex="-1"></a></span> |
260 | <span id="cb21-3"><a href="#cb21-3" aria-hidden="true" tabindex="-1"></a> <span class="kw">fn</span> generate_curry(parsed<span class="op">:</span> ItemFn) <span class="op">-></span> TokenStream <span class="op">{</span></span> | 396 | <span id="cb21-3"><a href="#cb21-3" aria-hidden="true" tabindex="-1"></a> <span class="kw">fn</span> generate_curry(parsed<span class="op">:</span> ItemFn) <span class="op">-></span> TokenStream <span class="op">{</span></span> |
261 | <span id="cb21-4"><a href="#cb21-4" aria-hidden="true" tabindex="-1"></a> <span class="kw">let</span> fn_body <span class="op">=</span> parsed<span class="op">.</span>block<span class="op">;</span></span> | 397 | <span id="cb21-4"><a href="#cb21-4" aria-hidden="true" tabindex="-1"></a> <span class="kw">let</span> fn_body <span class="op">=</span> parsed<span class="op">.</span>block<span class="op">;</span></span> |
@@ -272,10 +408,11 @@ syn::token::Fn --' / \ (output) | |||
272 | <span id="cb21-15"><a href="#cb21-15" aria-hidden="true" tabindex="-1"></a><span class="op">+</span> <span class="kw">let</span> curried_body <span class="op">=</span> generate_body(<span class="op">&</span>arg_idents[<span class="dv">1</span><span class="op">..</span>]<span class="op">,</span> fn_body<span class="op">.</span>clone())<span class="op">;</span></span> | 408 | <span id="cb21-15"><a href="#cb21-15" aria-hidden="true" tabindex="-1"></a><span class="op">+</span> <span class="kw">let</span> curried_body <span class="op">=</span> generate_body(<span class="op">&</span>arg_idents[<span class="dv">1</span><span class="op">..</span>]<span class="op">,</span> fn_body<span class="op">.</span>clone())<span class="op">;</span></span> |
273 | <span id="cb21-16"><a href="#cb21-16" aria-hidden="true" tabindex="-1"></a><span class="op">+</span> <span class="pp">println!</span>(<span class="st">"{}"</span><span class="op">,</span> curried_body)<span class="op">;</span></span> | 409 | <span id="cb21-16"><a href="#cb21-16" aria-hidden="true" tabindex="-1"></a><span class="op">+</span> <span class="pp">println!</span>(<span class="st">"{}"</span><span class="op">,</span> curried_body)<span class="op">;</span></span> |
274 | <span id="cb21-17"><a href="#cb21-17" aria-hidden="true" tabindex="-1"></a></span> | 410 | <span id="cb21-17"><a href="#cb21-17" aria-hidden="true" tabindex="-1"></a></span> |
275 | <span id="cb21-18"><a href="#cb21-18" aria-hidden="true" tabindex="-1"></a> <span class="kw">return</span> <span class="pp">TokenStream::</span>new()<span class="op">;</span></span> | 411 | <span id="cb21-18"><a href="#cb21-18" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> <span class="pp">TokenStream::</span>new()<span class="op">;</span></span> |
276 | <span id="cb21-19"><a href="#cb21-19" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span></code></pre></div> | 412 | <span id="cb21-19"><a href="#cb21-19" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span></code></pre></div> |
277 | <p>Add a little test to <code>tests/</code>:</p> | 413 | <p>Add a little test to <code>tests/</code>:</p> |
278 | <div class="sourceCode" id="cb22"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb22-1"><a href="#cb22-1" aria-hidden="true" tabindex="-1"></a><span class="co">// tests/smoke.rs</span></span> | 414 | <div class="sourceCode" id="cb22"><pre |
415 | class="sourceCode rust"><code class="sourceCode rust"><span id="cb22-1"><a href="#cb22-1" aria-hidden="true" tabindex="-1"></a><span class="co">// tests/smoke.rs</span></span> | ||
279 | <span id="cb22-2"><a href="#cb22-2" aria-hidden="true" tabindex="-1"></a></span> | 416 | <span id="cb22-2"><a href="#cb22-2" aria-hidden="true" tabindex="-1"></a></span> |
280 | <span id="cb22-3"><a href="#cb22-3" aria-hidden="true" tabindex="-1"></a><span class="at">#[</span><span class="pp">currying::</span>curry<span class="at">]</span></span> | 417 | <span id="cb22-3"><a href="#cb22-3" aria-hidden="true" tabindex="-1"></a><span class="at">#[</span><span class="pp">currying::</span>curry<span class="at">]</span></span> |
281 | <span id="cb22-4"><a href="#cb22-4" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> add(x<span class="op">:</span> <span class="dt">u32</span><span class="op">,</span> y<span class="op">:</span> <span class="dt">u32</span><span class="op">,</span> z<span class="op">:</span> <span class="dt">u32</span>) <span class="op">-></span> <span class="dt">u32</span> <span class="op">{</span></span> | 418 | <span id="cb22-4"><a href="#cb22-4" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> add(x<span class="op">:</span> <span class="dt">u32</span><span class="op">,</span> y<span class="op">:</span> <span class="dt">u32</span><span class="op">,</span> z<span class="op">:</span> <span class="dt">u32</span>) <span class="op">-></span> <span class="dt">u32</span> <span class="op">{</span></span> |
@@ -286,17 +423,23 @@ syn::token::Fn --' / \ (output) | |||
286 | <span id="cb22-9"><a href="#cb22-9" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> works() <span class="op">{</span></span> | 423 | <span id="cb22-9"><a href="#cb22-9" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> works() <span class="op">{</span></span> |
287 | <span id="cb22-10"><a href="#cb22-10" aria-hidden="true" tabindex="-1"></a> <span class="pp">assert!</span>(<span class="cn">true</span>)<span class="op">;</span></span> | 424 | <span id="cb22-10"><a href="#cb22-10" aria-hidden="true" tabindex="-1"></a> <span class="pp">assert!</span>(<span class="cn">true</span>)<span class="op">;</span></span> |
288 | <span id="cb22-11"><a href="#cb22-11" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div> | 425 | <span id="cb22-11"><a href="#cb22-11" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div> |
289 | <p>You should find something like this in the output of <code>cargo test</code>:</p> | 426 | <p>You should find something like this in the output of |
427 | <code>cargo test</code>:</p> | ||
290 | <pre><code>return move | y | move | z | { x + y + z }</code></pre> | 428 | <pre><code>return move | y | move | z | { x + y + z }</code></pre> |
291 | <p>Glorious <code>println!</code> debugging!</p> | 429 | <p>Glorious <code>println!</code> debugging!</p> |
292 | <h4 id="function-signature">Function signature</h4> | 430 | <h4 id="function-signature">Function signature</h4> |
293 | <p>This section gets into the more complicated bits of the macro, generating type aliases and the function signature. By the end of this section, we should have a full working auto-currying macro!</p> | 431 | <p>This section gets into the more complicated bits of the macro, |
294 | <p>Recall what our generated type aliases should look like, for our <code>add</code> function:</p> | 432 | generating type aliases and the function signature. By the end of this |
295 | <div class="sourceCode" id="cb24"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb24-1"><a href="#cb24-1" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> T0 <span class="op">=</span> <span class="dt">u32</span><span class="op">;</span></span> | 433 | section, we should have a full working auto-currying macro!</p> |
434 | <p>Recall what our generated type aliases should look like, for our | ||
435 | <code>add</code> function:</p> | ||
436 | <div class="sourceCode" id="cb24"><pre | ||
437 | class="sourceCode rust"><code class="sourceCode rust"><span id="cb24-1"><a href="#cb24-1" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> T0 <span class="op">=</span> <span class="dt">u32</span><span class="op">;</span></span> | ||
296 | <span id="cb24-2"><a href="#cb24-2" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> T1 <span class="op">=</span> <span class="kw">impl</span> <span class="bu">Fn</span>(<span class="dt">u32</span>) <span class="op">-></span> T0<span class="op">;</span></span> | 438 | <span id="cb24-2"><a href="#cb24-2" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> T1 <span class="op">=</span> <span class="kw">impl</span> <span class="bu">Fn</span>(<span class="dt">u32</span>) <span class="op">-></span> T0<span class="op">;</span></span> |
297 | <span id="cb24-3"><a href="#cb24-3" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> T2 <span class="op">=</span> <span class="kw">impl</span> <span class="bu">Fn</span>(<span class="dt">u32</span>) <span class="op">-></span> T1<span class="op">;</span></span></code></pre></div> | 439 | <span id="cb24-3"><a href="#cb24-3" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> T2 <span class="op">=</span> <span class="kw">impl</span> <span class="bu">Fn</span>(<span class="dt">u32</span>) <span class="op">-></span> T1<span class="op">;</span></span></code></pre></div> |
298 | <p>In general:</p> | 440 | <p>In general:</p> |
299 | <div class="sourceCode" id="cb25"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb25-1"><a href="#cb25-1" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> T0 <span class="op">=</span> <span class="op"><</span><span class="kw">return</span> <span class="kw">type</span>><span class="op">;</span></span> | 441 | <div class="sourceCode" id="cb25"><pre |
442 | class="sourceCode rust"><code class="sourceCode rust"><span id="cb25-1"><a href="#cb25-1" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> T0 <span class="op">=</span> <span class="op"><</span><span class="cf">return</span> <span class="kw">type</span>><span class="op">;</span></span> | ||
300 | <span id="cb25-2"><a href="#cb25-2" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> T1 <span class="op">=</span> <span class="kw">impl</span> <span class="bu">Fn</span>(<span class="op"><</span><span class="kw">type</span> of arg N>) -> T0<span class="op">;</span></span> | 443 | <span id="cb25-2"><a href="#cb25-2" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> T1 <span class="op">=</span> <span class="kw">impl</span> <span class="bu">Fn</span>(<span class="op"><</span><span class="kw">type</span> of arg N>) -> T0<span class="op">;</span></span> |
301 | <span id="cb25-3"><a href="#cb25-3" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> T2 <span class="op">=</span> <span class="kw">impl</span> <span class="bu">Fn</span>(<span class="op"><</span><span class="kw">type</span> of arg N - 1>) -> T1<span class="op">;</span></span> | 444 | <span id="cb25-3"><a href="#cb25-3" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> T2 <span class="op">=</span> <span class="kw">impl</span> <span class="bu">Fn</span>(<span class="op"><</span><span class="kw">type</span> of arg N - 1>) -> T1<span class="op">;</span></span> |
302 | <span id="cb25-4"><a href="#cb25-4" aria-hidden="true" tabindex="-1"></a><span class="op">.</span></span> | 445 | <span id="cb25-4"><a href="#cb25-4" aria-hidden="true" tabindex="-1"></a><span class="op">.</span></span> |
@@ -308,42 +451,59 @@ syn::token::Fn --' / \ (output) | |||
308 | <li>all our inputs (arguments)</li> | 451 | <li>all our inputs (arguments)</li> |
309 | <li>the output (the return type)</li> | 452 | <li>the output (the return type)</li> |
310 | </ul> | 453 | </ul> |
311 | <p>To fetch the types of all our inputs, we can simply reuse the bits we wrote to fetch the names of all our inputs! (doc: <a href="https://docs.rs/syn/1.0.18/syn/enum.Type.html">Type</a>)</p> | 454 | <p>To fetch the types of all our inputs, we can simply reuse the bits we |
312 | <div class="sourceCode" id="cb26"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb26-1"><a href="#cb26-1" aria-hidden="true" tabindex="-1"></a><span class="co">// src/lib.rs</span></span> | 455 | wrote to fetch the names of all our inputs! (doc: <a |
456 | href="https://docs.rs/syn/1.0.18/syn/enum.Type.html">Type</a>)</p> | ||
457 | <div class="sourceCode" id="cb26"><pre | ||
458 | class="sourceCode rust"><code class="sourceCode rust"><span id="cb26-1"><a href="#cb26-1" aria-hidden="true" tabindex="-1"></a><span class="co">// src/lib.rs</span></span> | ||
313 | <span id="cb26-2"><a href="#cb26-2" aria-hidden="true" tabindex="-1"></a></span> | 459 | <span id="cb26-2"><a href="#cb26-2" aria-hidden="true" tabindex="-1"></a></span> |
314 | <span id="cb26-3"><a href="#cb26-3" aria-hidden="true" tabindex="-1"></a><span class="kw">use</span> <span class="pp">syn::</span><span class="op">{</span>parse_macro_input<span class="op">,</span> Block<span class="op">,</span> FnArg<span class="op">,</span> ItemFn<span class="op">,</span> Pat<span class="op">,</span> ReturnType<span class="op">,</span> Type<span class="op">};</span></span> | 460 | <span id="cb26-3"><a href="#cb26-3" aria-hidden="true" tabindex="-1"></a><span class="kw">use</span> <span class="pp">syn::</span><span class="op">{</span>parse_macro_input<span class="op">,</span> Block<span class="op">,</span> FnArg<span class="op">,</span> ItemFn<span class="op">,</span> Pat<span class="op">,</span> ReturnType<span class="op">,</span> Type<span class="op">};</span></span> |
315 | <span id="cb26-4"><a href="#cb26-4" aria-hidden="true" tabindex="-1"></a></span> | 461 | <span id="cb26-4"><a href="#cb26-4" aria-hidden="true" tabindex="-1"></a></span> |
316 | <span id="cb26-5"><a href="#cb26-5" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> extract_type(a<span class="op">:</span> FnArg) <span class="op">-></span> <span class="dt">Box</span><span class="op"><</span>Type<span class="op">></span> <span class="op">{</span></span> | 462 | <span id="cb26-5"><a href="#cb26-5" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> extract_type(a<span class="op">:</span> FnArg) <span class="op">-></span> <span class="dt">Box</span><span class="op"><</span>Type<span class="op">></span> <span class="op">{</span></span> |
317 | <span id="cb26-6"><a href="#cb26-6" aria-hidden="true" tabindex="-1"></a> <span class="kw">match</span> a <span class="op">{</span></span> | 463 | <span id="cb26-6"><a href="#cb26-6" aria-hidden="true" tabindex="-1"></a> <span class="cf">match</span> a <span class="op">{</span></span> |
318 | <span id="cb26-7"><a href="#cb26-7" aria-hidden="true" tabindex="-1"></a> <span class="pp">FnArg::</span>Typed(p) <span class="op">=></span> p<span class="op">.</span>ty<span class="op">,</span> <span class="co">// notice `ty` instead of `pat`</span></span> | 464 | <span id="cb26-7"><a href="#cb26-7" aria-hidden="true" tabindex="-1"></a> <span class="pp">FnArg::</span>Typed(p) <span class="op">=></span> p<span class="op">.</span>ty<span class="op">,</span> <span class="co">// notice `ty` instead of `pat`</span></span> |
319 | <span id="cb26-8"><a href="#cb26-8" aria-hidden="true" tabindex="-1"></a> _ <span class="op">=></span> <span class="pp">panic!</span>(<span class="st">"Not supported on types with `self`!"</span>)<span class="op">,</span></span> | 465 | <span id="cb26-8"><a href="#cb26-8" aria-hidden="true" tabindex="-1"></a> _ <span class="op">=></span> <span class="pp">panic!</span>(<span class="st">"Not supported on types with `self`!"</span>)<span class="op">,</span></span> |
320 | <span id="cb26-9"><a href="#cb26-9" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span> | 466 | <span id="cb26-9"><a href="#cb26-9" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span> |
321 | <span id="cb26-10"><a href="#cb26-10" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span> | 467 | <span id="cb26-10"><a href="#cb26-10" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span> |
322 | <span id="cb26-11"><a href="#cb26-11" aria-hidden="true" tabindex="-1"></a></span> | 468 | <span id="cb26-11"><a href="#cb26-11" aria-hidden="true" tabindex="-1"></a></span> |
323 | <span id="cb26-12"><a href="#cb26-12" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> extract_arg_types(fn_args<span class="op">:</span> Punctuated<span class="op"><</span>FnArg<span class="op">,</span> <span class="pp">syn::token::</span>Comma<span class="op">></span>) <span class="op">-></span> <span class="dt">Vec</span><span class="op"><</span><span class="dt">Box</span><span class="op"><</span>Type<span class="op">>></span> <span class="op">{</span></span> | 469 | <span id="cb26-12"><a href="#cb26-12" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> extract_arg_types(fn_args<span class="op">:</span> Punctuated<span class="op"><</span>FnArg<span class="op">,</span> <span class="pp">syn::token::</span>Comma<span class="op">></span>) <span class="op">-></span> <span class="dt">Vec</span><span class="op"><</span><span class="dt">Box</span><span class="op"><</span>Type<span class="op">>></span> <span class="op">{</span></span> |
324 | <span id="cb26-13"><a href="#cb26-13" aria-hidden="true" tabindex="-1"></a> <span class="kw">return</span> fn_args<span class="op">.</span>into_iter()<span class="op">.</span>map(extract_type)<span class="op">.</span><span class="pp">collect::</span><span class="op"><</span><span class="dt">Vec</span><span class="op"><</span>_<span class="op">>></span>()<span class="op">;</span></span> | 470 | <span id="cb26-13"><a href="#cb26-13" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> fn_args<span class="op">.</span>into_iter()<span class="op">.</span>map(extract_type)<span class="op">.</span><span class="pp">collect::</span><span class="op"><</span><span class="dt">Vec</span><span class="op"><</span>_<span class="op">>></span>()<span class="op">;</span></span> |
325 | <span id="cb26-14"><a href="#cb26-14" aria-hidden="true" tabindex="-1"></a></span> | 471 | <span id="cb26-14"><a href="#cb26-14" aria-hidden="true" tabindex="-1"></a></span> |
326 | <span id="cb26-15"><a href="#cb26-15" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div> | 472 | <span id="cb26-15"><a href="#cb26-15" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div> |
327 | <p>A good reader would have looked at the docs for output member of the <code>syn::Signature</code> struct. It has the type <code>syn::ReturnType</code>. So there is no extraction to do here right? There are actually a couple of things we have to ensure here:</p> | 473 | <p>A good reader would have looked at the docs for output member of the |
474 | <code>syn::Signature</code> struct. It has the type | ||
475 | <code>syn::ReturnType</code>. So there is no extraction to do here | ||
476 | right? There are actually a couple of things we have to ensure here:</p> | ||
328 | <ol type="1"> | 477 | <ol type="1"> |
329 | <li><p>We need to ensure that the function returns! A function that does not return is pointless in this case, and I will tell you why, in the <a href="#notes">Notes</a> section.</p></li> | 478 | <li><p>We need to ensure that the function returns! A function that does |
330 | <li><p>A <code>ReturnType</code> encloses the arrow of the return as well, we need to get rid of that. Recall:</p> | 479 | not return is pointless in this case, and I will tell you why, in the <a |
331 | <div class="sourceCode" id="cb27"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb27-1"><a href="#cb27-1" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> T0 <span class="op">=</span> <span class="dt">u32</span></span> | 480 | href="#notes">Notes</a> section.</p></li> |
481 | <li><p>A <code>ReturnType</code> encloses the arrow of the return as | ||
482 | well, we need to get rid of that. Recall:</p> | ||
483 | <div class="sourceCode" id="cb27"><pre | ||
484 | class="sourceCode rust"><code class="sourceCode rust"><span id="cb27-1"><a href="#cb27-1" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> T0 <span class="op">=</span> <span class="dt">u32</span></span> | ||
332 | <span id="cb27-2"><a href="#cb27-2" aria-hidden="true" tabindex="-1"></a><span class="co">// and not</span></span> | 485 | <span id="cb27-2"><a href="#cb27-2" aria-hidden="true" tabindex="-1"></a><span class="co">// and not</span></span> |
333 | <span id="cb27-3"><a href="#cb27-3" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> T0 <span class="op">=</span> <span class="op">-></span> <span class="dt">u32</span></span></code></pre></div></li> | 486 | <span id="cb27-3"><a href="#cb27-3" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> T0 <span class="op">=</span> <span class="op">-></span> <span class="dt">u32</span></span></code></pre></div></li> |
334 | </ol> | 487 | </ol> |
335 | <p>Here is the snippet that handles extraction of the return type (doc: <a href="https://docs.rs/syn/1.0.19/syn/enum.ReturnType.html">syn::ReturnType</a>):</p> | 488 | <p>Here is the snippet that handles extraction of the return type (doc: |
336 | <div class="sourceCode" id="cb28"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb28-1"><a href="#cb28-1" aria-hidden="true" tabindex="-1"></a><span class="co">// src/lib.rs</span></span> | 489 | <a |
490 | href="https://docs.rs/syn/1.0.19/syn/enum.ReturnType.html">syn::ReturnType</a>):</p> | ||
491 | <div class="sourceCode" id="cb28"><pre | ||
492 | class="sourceCode rust"><code class="sourceCode rust"><span id="cb28-1"><a href="#cb28-1" aria-hidden="true" tabindex="-1"></a><span class="co">// src/lib.rs</span></span> | ||
337 | <span id="cb28-2"><a href="#cb28-2" aria-hidden="true" tabindex="-1"></a></span> | 493 | <span id="cb28-2"><a href="#cb28-2" aria-hidden="true" tabindex="-1"></a></span> |
338 | <span id="cb28-3"><a href="#cb28-3" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> extract_return_type(a<span class="op">:</span> ReturnType) <span class="op">-></span> <span class="dt">Box</span><span class="op"><</span>Type<span class="op">></span> <span class="op">{</span></span> | 494 | <span id="cb28-3"><a href="#cb28-3" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> extract_return_type(a<span class="op">:</span> ReturnType) <span class="op">-></span> <span class="dt">Box</span><span class="op"><</span>Type<span class="op">></span> <span class="op">{</span></span> |
339 | <span id="cb28-4"><a href="#cb28-4" aria-hidden="true" tabindex="-1"></a> <span class="kw">match</span> a <span class="op">{</span></span> | 495 | <span id="cb28-4"><a href="#cb28-4" aria-hidden="true" tabindex="-1"></a> <span class="cf">match</span> a <span class="op">{</span></span> |
340 | <span id="cb28-5"><a href="#cb28-5" aria-hidden="true" tabindex="-1"></a> <span class="pp">ReturnType::</span>Type(_<span class="op">,</span> p) <span class="op">=></span> p<span class="op">,</span></span> | 496 | <span id="cb28-5"><a href="#cb28-5" aria-hidden="true" tabindex="-1"></a> <span class="pp">ReturnType::</span>Type(_<span class="op">,</span> p) <span class="op">=></span> p<span class="op">,</span></span> |
341 | <span id="cb28-6"><a href="#cb28-6" aria-hidden="true" tabindex="-1"></a> _ <span class="op">=></span> <span class="pp">panic!</span>(<span class="st">"Not supported on functions without return types!"</span>)<span class="op">,</span></span> | 497 | <span id="cb28-6"><a href="#cb28-6" aria-hidden="true" tabindex="-1"></a> _ <span class="op">=></span> <span class="pp">panic!</span>(<span class="st">"Not supported on functions without return types!"</span>)<span class="op">,</span></span> |
342 | <span id="cb28-7"><a href="#cb28-7" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span> | 498 | <span id="cb28-7"><a href="#cb28-7" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span> |
343 | <span id="cb28-8"><a href="#cb28-8" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div> | 499 | <span id="cb28-8"><a href="#cb28-8" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div> |
344 | <p>You might notice that we are making extensive use of the <code>panic!</code> macro. Well, that is because it is a good idea to quit on receiving an unsatisfactory <code>TokenStream</code>.</p> | 500 | <p>You might notice that we are making extensive use of the |
345 | <p>With all our types ready, we can get on with generating type aliases:</p> | 501 | <code>panic!</code> macro. Well, that is because it is a good idea to |
346 | <div class="sourceCode" id="cb29"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb29-1"><a href="#cb29-1" aria-hidden="true" tabindex="-1"></a><span class="co">// src/lib.rs</span></span> | 502 | quit on receiving an unsatisfactory <code>TokenStream</code>.</p> |
503 | <p>With all our types ready, we can get on with generating type | ||
504 | aliases:</p> | ||
505 | <div class="sourceCode" id="cb29"><pre | ||
506 | class="sourceCode rust"><code class="sourceCode rust"><span id="cb29-1"><a href="#cb29-1" aria-hidden="true" tabindex="-1"></a><span class="co">// src/lib.rs</span></span> | ||
347 | <span id="cb29-2"><a href="#cb29-2" aria-hidden="true" tabindex="-1"></a></span> | 507 | <span id="cb29-2"><a href="#cb29-2" aria-hidden="true" tabindex="-1"></a></span> |
348 | <span id="cb29-3"><a href="#cb29-3" aria-hidden="true" tabindex="-1"></a><span class="kw">use</span> <span class="pp">quote::</span><span class="op">{</span>quote<span class="op">,</span> format_ident<span class="op">};</span></span> | 508 | <span id="cb29-3"><a href="#cb29-3" aria-hidden="true" tabindex="-1"></a><span class="kw">use</span> <span class="pp">quote::</span><span class="op">{</span>quote<span class="op">,</span> format_ident<span class="op">};</span></span> |
349 | <span id="cb29-4"><a href="#cb29-4" aria-hidden="true" tabindex="-1"></a></span> | 509 | <span id="cb29-4"><a href="#cb29-4" aria-hidden="true" tabindex="-1"></a></span> |
@@ -357,7 +517,7 @@ syn::token::Fn --' / \ (output) | |||
357 | <span id="cb29-12"><a href="#cb29-12" aria-hidden="true" tabindex="-1"></a> <span class="kw">let</span> <span class="kw">mut</span> type_aliases <span class="op">=</span> <span class="pp">vec!</span>[<span class="pp">quote!</span> <span class="op">{</span> <span class="kw">type</span> #type_t0 <span class="op">=</span> #fn_return_type <span class="op">}</span>]<span class="op">;</span></span> | 517 | <span id="cb29-12"><a href="#cb29-12" aria-hidden="true" tabindex="-1"></a> <span class="kw">let</span> <span class="kw">mut</span> type_aliases <span class="op">=</span> <span class="pp">vec!</span>[<span class="pp">quote!</span> <span class="op">{</span> <span class="kw">type</span> #type_t0 <span class="op">=</span> #fn_return_type <span class="op">}</span>]<span class="op">;</span></span> |
358 | <span id="cb29-13"><a href="#cb29-13" aria-hidden="true" tabindex="-1"></a></span> | 518 | <span id="cb29-13"><a href="#cb29-13" aria-hidden="true" tabindex="-1"></a></span> |
359 | <span id="cb29-14"><a href="#cb29-14" aria-hidden="true" tabindex="-1"></a> <span class="co">// 3</span></span> | 519 | <span id="cb29-14"><a href="#cb29-14" aria-hidden="true" tabindex="-1"></a> <span class="co">// 3</span></span> |
360 | <span id="cb29-15"><a href="#cb29-15" aria-hidden="true" tabindex="-1"></a> <span class="kw">for</span> (i<span class="op">,</span> t) <span class="kw">in</span> (<span class="dv">1</span><span class="op">..</span>)<span class="op">.</span>zip(fn_arg_types<span class="op">.</span>into_iter()<span class="op">.</span>rev()) <span class="op">{</span></span> | 520 | <span id="cb29-15"><a href="#cb29-15" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> (i<span class="op">,</span> t) <span class="kw">in</span> (<span class="dv">1</span><span class="op">..</span>)<span class="op">.</span>zip(fn_arg_types<span class="op">.</span>into_iter()<span class="op">.</span>rev()) <span class="op">{</span></span> |
361 | <span id="cb29-16"><a href="#cb29-16" aria-hidden="true" tabindex="-1"></a> <span class="kw">let</span> p <span class="op">=</span> <span class="pp">format_ident!</span>(<span class="st">"_{}_{}"</span><span class="op">,</span> fn_name<span class="op">,</span> <span class="pp">format!</span>(<span class="st">"T{}"</span><span class="op">,</span> i <span class="op">-</span> <span class="dv">1</span>))<span class="op">;</span></span> | 521 | <span id="cb29-16"><a href="#cb29-16" aria-hidden="true" tabindex="-1"></a> <span class="kw">let</span> p <span class="op">=</span> <span class="pp">format_ident!</span>(<span class="st">"_{}_{}"</span><span class="op">,</span> fn_name<span class="op">,</span> <span class="pp">format!</span>(<span class="st">"T{}"</span><span class="op">,</span> i <span class="op">-</span> <span class="dv">1</span>))<span class="op">;</span></span> |
362 | <span id="cb29-17"><a href="#cb29-17" aria-hidden="true" tabindex="-1"></a> <span class="kw">let</span> n <span class="op">=</span> <span class="pp">format_ident!</span>(<span class="st">"_{}_{}"</span><span class="op">,</span> fn_name<span class="op">,</span> <span class="pp">format!</span>(<span class="st">"T{}"</span><span class="op">,</span> i))<span class="op">;</span></span> | 522 | <span id="cb29-17"><a href="#cb29-17" aria-hidden="true" tabindex="-1"></a> <span class="kw">let</span> n <span class="op">=</span> <span class="pp">format_ident!</span>(<span class="st">"_{}_{}"</span><span class="op">,</span> fn_name<span class="op">,</span> <span class="pp">format!</span>(<span class="st">"T{}"</span><span class="op">,</span> i))<span class="op">;</span></span> |
363 | <span id="cb29-18"><a href="#cb29-18" aria-hidden="true" tabindex="-1"></a></span> | 523 | <span id="cb29-18"><a href="#cb29-18" aria-hidden="true" tabindex="-1"></a></span> |
@@ -366,45 +526,70 @@ syn::token::Fn --' / \ (output) | |||
366 | <span id="cb29-21"><a href="#cb29-21" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span>)<span class="op">;</span></span> | 526 | <span id="cb29-21"><a href="#cb29-21" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span>)<span class="op">;</span></span> |
367 | <span id="cb29-22"><a href="#cb29-22" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span> | 527 | <span id="cb29-22"><a href="#cb29-22" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span> |
368 | <span id="cb29-23"><a href="#cb29-23" aria-hidden="true" tabindex="-1"></a></span> | 528 | <span id="cb29-23"><a href="#cb29-23" aria-hidden="true" tabindex="-1"></a></span> |
369 | <span id="cb29-24"><a href="#cb29-24" aria-hidden="true" tabindex="-1"></a> <span class="kw">return</span> type_aliases<span class="op">;</span></span> | 529 | <span id="cb29-24"><a href="#cb29-24" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> type_aliases<span class="op">;</span></span> |
370 | <span id="cb29-25"><a href="#cb29-25" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div> | 530 | <span id="cb29-25"><a href="#cb29-25" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div> |
371 | <p><strong>1. The return value</strong><br /> | 531 | <p><strong>1. The return value</strong><br /> |
372 | We are returning a <code>Vec<proc_macro2::TokenStream></code>, i. e., a list of <code>TokenStream</code>s, where each item is a type alias.</p> | 532 | We are returning a <code>Vec<proc_macro2::TokenStream></code>, i. |
533 | e., a list of <code>TokenStream</code>s, where each item is a type | ||
534 | alias.</p> | ||
373 | <p><strong>2. Format identifier?</strong><br /> | 535 | <p><strong>2. Format identifier?</strong><br /> |
374 | I’ve got some explanation to do on this line. Clearly, we are trying to write the first type alias, and initialize our <code>TokenStream</code> vector with <code>T0</code>, because it is different from the others:</p> | 536 | I’ve got some explanation to do on this line. Clearly, we are trying to |
375 | <div class="sourceCode" id="cb30"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb30-1"><a href="#cb30-1" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> T0 <span class="op">=</span> something</span> | 537 | write the first type alias, and initialize our <code>TokenStream</code> |
538 | vector with <code>T0</code>, because it is different from the | ||
539 | others:</p> | ||
540 | <div class="sourceCode" id="cb30"><pre | ||
541 | class="sourceCode rust"><code class="sourceCode rust"><span id="cb30-1"><a href="#cb30-1" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> T0 <span class="op">=</span> something</span> | ||
376 | <span id="cb30-2"><a href="#cb30-2" aria-hidden="true" tabindex="-1"></a><span class="co">// the others are of the form</span></span> | 542 | <span id="cb30-2"><a href="#cb30-2" aria-hidden="true" tabindex="-1"></a><span class="co">// the others are of the form</span></span> |
377 | <span id="cb30-3"><a href="#cb30-3" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> Tr <span class="op">=</span> <span class="kw">impl</span> <span class="bu">Fn</span>(something) <span class="op">-></span> something</span></code></pre></div> | 543 | <span id="cb30-3"><a href="#cb30-3" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> Tr <span class="op">=</span> <span class="kw">impl</span> <span class="bu">Fn</span>(something) <span class="op">-></span> something</span></code></pre></div> |
378 | <p><code>format_ident!</code> is similar to <code>format!</code>. Instead of returning a formatted string, it returns a <code>syn::Ident</code>. Therefore, <code>type_t0</code> is actually an identifier for, in the case of our <code>add</code> function, <code>_add_T0</code>. Why is this formatting important? Namespacing.</p> | 544 | <p><code>format_ident!</code> is similar to <code>format!</code>. |
379 | <p>Picture this, we have two functions, <code>add</code> and <code>subtract</code>, that we wish to curry with our macro:</p> | 545 | Instead of returning a formatted string, it returns a |
380 | <div class="sourceCode" id="cb31"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb31-1"><a href="#cb31-1" aria-hidden="true" tabindex="-1"></a><span class="at">#[</span>curry<span class="at">]</span></span> | 546 | <code>syn::Ident</code>. Therefore, <code>type_t0</code> is actually an |
547 | identifier for, in the case of our <code>add</code> function, | ||
548 | <code>_add_T0</code>. Why is this formatting important? Namespacing.</p> | ||
549 | <p>Picture this, we have two functions, <code>add</code> and | ||
550 | <code>subtract</code>, that we wish to curry with our macro:</p> | ||
551 | <div class="sourceCode" id="cb31"><pre | ||
552 | class="sourceCode rust"><code class="sourceCode rust"><span id="cb31-1"><a href="#cb31-1" aria-hidden="true" tabindex="-1"></a><span class="at">#[</span>curry<span class="at">]</span></span> | ||
381 | <span id="cb31-2"><a href="#cb31-2" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> add(<span class="op">...</span>) <span class="op">-></span> <span class="dt">u32</span> <span class="op">{</span> <span class="op">...</span> <span class="op">}</span></span> | 553 | <span id="cb31-2"><a href="#cb31-2" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> add(<span class="op">...</span>) <span class="op">-></span> <span class="dt">u32</span> <span class="op">{</span> <span class="op">...</span> <span class="op">}</span></span> |
382 | <span id="cb31-3"><a href="#cb31-3" aria-hidden="true" tabindex="-1"></a></span> | 554 | <span id="cb31-3"><a href="#cb31-3" aria-hidden="true" tabindex="-1"></a></span> |
383 | <span id="cb31-4"><a href="#cb31-4" aria-hidden="true" tabindex="-1"></a><span class="at">#[</span>curry<span class="at">]</span></span> | 555 | <span id="cb31-4"><a href="#cb31-4" aria-hidden="true" tabindex="-1"></a><span class="at">#[</span>curry<span class="at">]</span></span> |
384 | <span id="cb31-5"><a href="#cb31-5" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> sub(<span class="op">...</span>) <span class="op">-></span> <span class="dt">u32</span> <span class="op">{</span> <span class="op">...</span> <span class="op">}</span></span></code></pre></div> | 556 | <span id="cb31-5"><a href="#cb31-5" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> sub(<span class="op">...</span>) <span class="op">-></span> <span class="dt">u32</span> <span class="op">{</span> <span class="op">...</span> <span class="op">}</span></span></code></pre></div> |
385 | <p>Here is the same but with macros expanded:</p> | 557 | <p>Here is the same but with macros expanded:</p> |
386 | <div class="sourceCode" id="cb32"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb32-1"><a href="#cb32-1" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> T0 <span class="op">=</span> <span class="dt">u32</span><span class="op">;</span></span> | 558 | <div class="sourceCode" id="cb32"><pre |
559 | class="sourceCode rust"><code class="sourceCode rust"><span id="cb32-1"><a href="#cb32-1" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> T0 <span class="op">=</span> <span class="dt">u32</span><span class="op">;</span></span> | ||
387 | <span id="cb32-2"><a href="#cb32-2" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> T1 <span class="op">=</span> <span class="kw">impl</span> <span class="bu">Fn</span>(<span class="dt">u32</span>) <span class="op">-></span> T0<span class="op">;</span></span> | 560 | <span id="cb32-2"><a href="#cb32-2" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> T1 <span class="op">=</span> <span class="kw">impl</span> <span class="bu">Fn</span>(<span class="dt">u32</span>) <span class="op">-></span> T0<span class="op">;</span></span> |
388 | <span id="cb32-3"><a href="#cb32-3" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> add( <span class="op">...</span> ) <span class="op">-></span> T1 <span class="op">{</span> <span class="op">...</span> <span class="op">}</span></span> | 561 | <span id="cb32-3"><a href="#cb32-3" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> add( <span class="op">...</span> ) <span class="op">-></span> T1 <span class="op">{</span> <span class="op">...</span> <span class="op">}</span></span> |
389 | <span id="cb32-4"><a href="#cb32-4" aria-hidden="true" tabindex="-1"></a></span> | 562 | <span id="cb32-4"><a href="#cb32-4" aria-hidden="true" tabindex="-1"></a></span> |
390 | <span id="cb32-5"><a href="#cb32-5" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> T0 <span class="op">=</span> <span class="dt">u32</span><span class="op">;</span></span> | 563 | <span id="cb32-5"><a href="#cb32-5" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> T0 <span class="op">=</span> <span class="dt">u32</span><span class="op">;</span></span> |
391 | <span id="cb32-6"><a href="#cb32-6" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> T1 <span class="op">=</span> <span class="kw">impl</span> <span class="bu">Fn</span>(<span class="dt">u32</span>) <span class="op">-></span> T0<span class="op">;</span></span> | 564 | <span id="cb32-6"><a href="#cb32-6" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> T1 <span class="op">=</span> <span class="kw">impl</span> <span class="bu">Fn</span>(<span class="dt">u32</span>) <span class="op">-></span> T0<span class="op">;</span></span> |
392 | <span id="cb32-7"><a href="#cb32-7" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> sub( <span class="op">...</span> ) <span class="op">-></span> T1 <span class="op">{</span> <span class="op">...</span> <span class="op">}</span></span></code></pre></div> | 565 | <span id="cb32-7"><a href="#cb32-7" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> sub( <span class="op">...</span> ) <span class="op">-></span> T1 <span class="op">{</span> <span class="op">...</span> <span class="op">}</span></span></code></pre></div> |
393 | <p>We end up with two definitions of <code>T0</code>! Now, if we do the little <code>format_ident!</code> dance we did up there:</p> | 566 | <p>We end up with two definitions of <code>T0</code>! Now, if we do the |
394 | <div class="sourceCode" id="cb33"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb33-1"><a href="#cb33-1" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> _add_T0 <span class="op">=</span> <span class="dt">u32</span><span class="op">;</span></span> | 567 | little <code>format_ident!</code> dance we did up there:</p> |
568 | <div class="sourceCode" id="cb33"><pre | ||
569 | class="sourceCode rust"><code class="sourceCode rust"><span id="cb33-1"><a href="#cb33-1" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> _add_T0 <span class="op">=</span> <span class="dt">u32</span><span class="op">;</span></span> | ||
395 | <span id="cb33-2"><a href="#cb33-2" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> _add_T1 <span class="op">=</span> <span class="kw">impl</span> <span class="bu">Fn</span>(<span class="dt">u32</span>) <span class="op">-></span> _add_T0<span class="op">;</span></span> | 570 | <span id="cb33-2"><a href="#cb33-2" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> _add_T1 <span class="op">=</span> <span class="kw">impl</span> <span class="bu">Fn</span>(<span class="dt">u32</span>) <span class="op">-></span> _add_T0<span class="op">;</span></span> |
396 | <span id="cb33-3"><a href="#cb33-3" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> add( <span class="op">...</span> ) <span class="op">-></span> _add_T1 <span class="op">{</span> <span class="op">...</span> <span class="op">}</span></span> | 571 | <span id="cb33-3"><a href="#cb33-3" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> add( <span class="op">...</span> ) <span class="op">-></span> _add_T1 <span class="op">{</span> <span class="op">...</span> <span class="op">}</span></span> |
397 | <span id="cb33-4"><a href="#cb33-4" aria-hidden="true" tabindex="-1"></a></span> | 572 | <span id="cb33-4"><a href="#cb33-4" aria-hidden="true" tabindex="-1"></a></span> |
398 | <span id="cb33-5"><a href="#cb33-5" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> _sub_T0 <span class="op">=</span> <span class="dt">u32</span><span class="op">;</span></span> | 573 | <span id="cb33-5"><a href="#cb33-5" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> _sub_T0 <span class="op">=</span> <span class="dt">u32</span><span class="op">;</span></span> |
399 | <span id="cb33-6"><a href="#cb33-6" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> _sub_T1 <span class="op">=</span> <span class="kw">impl</span> <span class="bu">Fn</span>(<span class="dt">u32</span>) <span class="op">-></span> _sub_T0<span class="op">;</span></span> | 574 | <span id="cb33-6"><a href="#cb33-6" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> _sub_T1 <span class="op">=</span> <span class="kw">impl</span> <span class="bu">Fn</span>(<span class="dt">u32</span>) <span class="op">-></span> _sub_T0<span class="op">;</span></span> |
400 | <span id="cb33-7"><a href="#cb33-7" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> sub( <span class="op">...</span> ) <span class="op">-></span> _sub_T1 <span class="op">{</span> <span class="op">...</span> <span class="op">}</span></span></code></pre></div> | 575 | <span id="cb33-7"><a href="#cb33-7" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> sub( <span class="op">...</span> ) <span class="op">-></span> _sub_T1 <span class="op">{</span> <span class="op">...</span> <span class="op">}</span></span></code></pre></div> |
401 | <p>Voilà! The type aliases don’t tread on each other. Remember to import <code>format_ident</code> from the <code>quote</code> crate.</p> | 576 | <p>Voilà! The type aliases don’t tread on each other. Remember to import |
577 | <code>format_ident</code> from the <code>quote</code> crate.</p> | ||
402 | <p><strong>3. The TokenStream Vector</strong></p> | 578 | <p><strong>3. The TokenStream Vector</strong></p> |
403 | <p>We iterate over our types in reverse order (<code>T0</code> is the last return, <code>T1</code> is the second last, so on), assign a number to each iteration with <code>zip</code>, generate type names with <code>format_ident</code>, push a <code>TokenStream</code> with the help of <code>quote</code> and variable interpolation.</p> | 579 | <p>We iterate over our types in reverse order (<code>T0</code> is the |
404 | <p>If you are wondering why we used <code>(1..).zip()</code> instead of <code>.enumerate()</code>, it’s because we wanted to start counting from 1 instead of 0 (we are already done with <code>T0</code>!).</p> | 580 | last return, <code>T1</code> is the second last, so on), assign a number |
581 | to each iteration with <code>zip</code>, generate type names with | ||
582 | <code>format_ident</code>, push a <code>TokenStream</code> with the help | ||
583 | of <code>quote</code> and variable interpolation.</p> | ||
584 | <p>If you are wondering why we used <code>(1..).zip()</code> instead of | ||
585 | <code>.enumerate()</code>, it’s because we wanted to start counting from | ||
586 | 1 instead of 0 (we are already done with <code>T0</code>!).</p> | ||
405 | <h4 id="getting-it-together">Getting it together</h4> | 587 | <h4 id="getting-it-together">Getting it together</h4> |
406 | <p>I promised we’d have a fully working macro by the end of last section. I lied, we have to tie everything together in our <code>generate_curry</code> function:</p> | 588 | <p>I promised we’d have a fully working macro by the end of last |
407 | <div class="sourceCode" id="cb34"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb34-1"><a href="#cb34-1" aria-hidden="true" tabindex="-1"></a><span class="co">// src/lib.rs</span></span> | 589 | section. I lied, we have to tie everything together in our |
590 | <code>generate_curry</code> function:</p> | ||
591 | <div class="sourceCode" id="cb34"><pre | ||
592 | class="sourceCode rust"><code class="sourceCode rust"><span id="cb34-1"><a href="#cb34-1" aria-hidden="true" tabindex="-1"></a><span class="co">// src/lib.rs</span></span> | ||
408 | <span id="cb34-2"><a href="#cb34-2" aria-hidden="true" tabindex="-1"></a></span> | 593 | <span id="cb34-2"><a href="#cb34-2" aria-hidden="true" tabindex="-1"></a></span> |
409 | <span id="cb34-3"><a href="#cb34-3" aria-hidden="true" tabindex="-1"></a> <span class="kw">fn</span> generate_curry(parsed<span class="op">:</span> ItemFn) <span class="op">-></span> <span class="pp">proc_macro2::</span>TokenStream <span class="op">{</span></span> | 594 | <span id="cb34-3"><a href="#cb34-3" aria-hidden="true" tabindex="-1"></a> <span class="kw">fn</span> generate_curry(parsed<span class="op">:</span> ItemFn) <span class="op">-></span> <span class="pp">proc_macro2::</span>TokenStream <span class="op">{</span></span> |
410 | <span id="cb34-4"><a href="#cb34-4" aria-hidden="true" tabindex="-1"></a> <span class="kw">let</span> fn_body <span class="op">=</span> parsed<span class="op">.</span>block<span class="op">;</span></span> | 595 | <span id="cb34-4"><a href="#cb34-4" aria-hidden="true" tabindex="-1"></a> <span class="kw">let</span> fn_body <span class="op">=</span> parsed<span class="op">.</span>block<span class="op">;</span></span> |
@@ -428,20 +613,39 @@ I’ve got some explanation to do on this line. Clearly, we are trying to write | |||
428 | <span id="cb34-22"><a href="#cb34-22" aria-hidden="true" tabindex="-1"></a></span> | 613 | <span id="cb34-22"><a href="#cb34-22" aria-hidden="true" tabindex="-1"></a></span> |
429 | <span id="cb34-23"><a href="#cb34-23" aria-hidden="true" tabindex="-1"></a><span class="op">+</span> <span class="kw">let</span> return_type <span class="op">=</span> <span class="pp">format_ident!</span>(<span class="st">"_{}_{}"</span><span class="op">,</span> <span class="op">&</span>fn_name<span class="op">,</span> <span class="pp">format!</span>(<span class="st">"T{}"</span><span class="op">,</span> type_aliases<span class="op">.</span>len() <span class="op">-</span> <span class="dv">1</span>))<span class="op">;</span></span> | 614 | <span id="cb34-23"><a href="#cb34-23" aria-hidden="true" tabindex="-1"></a><span class="op">+</span> <span class="kw">let</span> return_type <span class="op">=</span> <span class="pp">format_ident!</span>(<span class="st">"_{}_{}"</span><span class="op">,</span> <span class="op">&</span>fn_name<span class="op">,</span> <span class="pp">format!</span>(<span class="st">"T{}"</span><span class="op">,</span> type_aliases<span class="op">.</span>len() <span class="op">-</span> <span class="dv">1</span>))<span class="op">;</span></span> |
430 | <span id="cb34-24"><a href="#cb34-24" aria-hidden="true" tabindex="-1"></a></span> | 615 | <span id="cb34-24"><a href="#cb34-24" aria-hidden="true" tabindex="-1"></a></span> |
431 | <span id="cb34-25"><a href="#cb34-25" aria-hidden="true" tabindex="-1"></a><span class="op">+</span> <span class="kw">return</span> <span class="pp">quote!</span> <span class="op">{</span></span> | 616 | <span id="cb34-25"><a href="#cb34-25" aria-hidden="true" tabindex="-1"></a><span class="op">+</span> <span class="cf">return</span> <span class="pp">quote!</span> <span class="op">{</span></span> |
432 | <span id="cb34-26"><a href="#cb34-26" aria-hidden="true" tabindex="-1"></a><span class="op">+</span> #(#type_aliases)<span class="op">;*</span> <span class="op">;</span></span> | 617 | <span id="cb34-26"><a href="#cb34-26" aria-hidden="true" tabindex="-1"></a><span class="op">+</span> #(#type_aliases)<span class="op">;*</span> <span class="op">;</span></span> |
433 | <span id="cb34-27"><a href="#cb34-27" aria-hidden="true" tabindex="-1"></a><span class="op">+</span> #vis <span class="kw">fn</span> #fn_name (#first_ident<span class="op">:</span> #first_type) <span class="op">-></span> #return_type <span class="op">{</span></span> | 618 | <span id="cb34-27"><a href="#cb34-27" aria-hidden="true" tabindex="-1"></a><span class="op">+</span> #vis <span class="kw">fn</span> #fn_name (#first_ident<span class="op">:</span> #first_type) <span class="op">-></span> #return_type <span class="op">{</span></span> |
434 | <span id="cb34-28"><a href="#cb34-28" aria-hidden="true" tabindex="-1"></a><span class="op">+</span> #curried_body <span class="op">;</span></span> | 619 | <span id="cb34-28"><a href="#cb34-28" aria-hidden="true" tabindex="-1"></a><span class="op">+</span> #curried_body <span class="op">;</span></span> |
435 | <span id="cb34-29"><a href="#cb34-29" aria-hidden="true" tabindex="-1"></a><span class="op">+</span> <span class="op">}</span></span> | 620 | <span id="cb34-29"><a href="#cb34-29" aria-hidden="true" tabindex="-1"></a><span class="op">+</span> <span class="op">}</span></span> |
436 | <span id="cb34-30"><a href="#cb34-30" aria-hidden="true" tabindex="-1"></a><span class="op">+</span> <span class="op">};</span></span> | 621 | <span id="cb34-30"><a href="#cb34-30" aria-hidden="true" tabindex="-1"></a><span class="op">+</span> <span class="op">};</span></span> |
437 | <span id="cb34-31"><a href="#cb34-31" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span></code></pre></div> | 622 | <span id="cb34-31"><a href="#cb34-31" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span></code></pre></div> |
438 | <p>Most of the additions are self explanatory, I’ll go through the return statement with you. We are returning a <code>quote!{ ... }</code>, so a <code>proc_macro2::TokenStream</code>. We are iterating through the <code>type_aliases</code> variable, which you might recall, is a <code>Vec<TokenStream></code>. You might notice the sneaky semicolon before the <code>*</code>. This basically tells <code>quote</code>, to insert an item, then a semicolon, and then the next one, another semicolon, and so on. The semicolon is a separator. We need to manually insert another semicolon at the end of it all, <code>quote</code> doesn’t insert a separator at the end of the iteration.</p> | 623 | <p>Most of the additions are self explanatory, I’ll go through the |
439 | <p>We retain the visibility and name of our original function. Our curried function takes as args, just the first argument of our original function. The return type of our curried function is actually, the last type alias we create. If you think back to our manually curried <code>add</code> function, we returned <code>T2</code>, which was in fact, the last type alias we created.</p> | 624 | return statement with you. We are returning a |
440 | <p>I am sure, at this point, you are itching to test this out, but before that, let me introduce you to some good methods of debugging proc-macro code.</p> | 625 | <code>quote!{ ... }</code>, so a <code>proc_macro2::TokenStream</code>. |
626 | We are iterating through the <code>type_aliases</code> variable, which | ||
627 | you might recall, is a <code>Vec<TokenStream></code>. You might | ||
628 | notice the sneaky semicolon before the <code>*</code>. This basically | ||
629 | tells <code>quote</code>, to insert an item, then a semicolon, and then | ||
630 | the next one, another semicolon, and so on. The semicolon is a | ||
631 | separator. We need to manually insert another semicolon at the end of it | ||
632 | all, <code>quote</code> doesn’t insert a separator at the end of the | ||
633 | iteration.</p> | ||
634 | <p>We retain the visibility and name of our original function. Our | ||
635 | curried function takes as args, just the first argument of our original | ||
636 | function. The return type of our curried function is actually, the last | ||
637 | type alias we create. If you think back to our manually curried | ||
638 | <code>add</code> function, we returned <code>T2</code>, which was in | ||
639 | fact, the last type alias we created.</p> | ||
640 | <p>I am sure, at this point, you are itching to test this out, but | ||
641 | before that, let me introduce you to some good methods of debugging | ||
642 | proc-macro code.</p> | ||
441 | <h3 id="debugging-and-testing">Debugging and Testing</h3> | 643 | <h3 id="debugging-and-testing">Debugging and Testing</h3> |
442 | <p>Install <code>cargo-expand</code> via:</p> | 644 | <p>Install <code>cargo-expand</code> via:</p> |
443 | <pre><code>cargo install cargo-expand</code></pre> | 645 | <pre><code>cargo install cargo-expand</code></pre> |
444 | <p><code>cargo-expand</code> is a neat little tool that expands your macro in places where it is used, and lets you view the generated code! For example:</p> | 646 | <p><code>cargo-expand</code> is a neat little tool that expands your |
647 | macro in places where it is used, and lets you view the generated code! | ||
648 | For example:</p> | ||
445 | <pre class="shell"><code># create a bin package hello | 649 | <pre class="shell"><code># create a bin package hello |
446 | $ cargo new hello | 650 | $ cargo new hello |
447 | 651 | ||
@@ -463,10 +667,18 @@ fn main() { | |||
463 | )); | 667 | )); |
464 | }; | 668 | }; |
465 | }</code></pre> | 669 | }</code></pre> |
466 | <p>Writing proc-macros without <code>cargo-expand</code> is tantamount to driving a vehicle without rear view mirrors! Keep an eye on what is going on behind your back.</p> | 670 | <p>Writing proc-macros without <code>cargo-expand</code> is tantamount |
467 | <p>Now, your macro won’t always compile, you might just recieve the bee movie script as an error. <code>cargo-expand</code> will not work in such cases. I would suggest printing out your variables to inspect them. <code>TokenStream</code> implements <code>Display</code> as well as <code>Debug</code>. We don’t always have to be respectable programmers. Just print it.</p> | 671 | to driving a vehicle without rear view mirrors! Keep an eye on what is |
672 | going on behind your back.</p> | ||
673 | <p>Now, your macro won’t always compile, you might just recieve the bee | ||
674 | movie script as an error. <code>cargo-expand</code> will not work in | ||
675 | such cases. I would suggest printing out your variables to inspect them. | ||
676 | <code>TokenStream</code> implements <code>Display</code> as well as | ||
677 | <code>Debug</code>. We don’t always have to be respectable programmers. | ||
678 | Just print it.</p> | ||
468 | <p>Enough of that, lets get testing:</p> | 679 | <p>Enough of that, lets get testing:</p> |
469 | <div class="sourceCode" id="cb37"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb37-1"><a href="#cb37-1" aria-hidden="true" tabindex="-1"></a><span class="co">// tests/smoke.rs</span></span> | 680 | <div class="sourceCode" id="cb37"><pre |
681 | class="sourceCode rust"><code class="sourceCode rust"><span id="cb37-1"><a href="#cb37-1" aria-hidden="true" tabindex="-1"></a><span class="co">// tests/smoke.rs</span></span> | ||
470 | <span id="cb37-2"><a href="#cb37-2" aria-hidden="true" tabindex="-1"></a></span> | 682 | <span id="cb37-2"><a href="#cb37-2" aria-hidden="true" tabindex="-1"></a></span> |
471 | <span id="cb37-3"><a href="#cb37-3" aria-hidden="true" tabindex="-1"></a><span class="at">#![</span>feature<span class="at">(</span>type_alias_impl_trait<span class="at">)]</span></span> | 683 | <span id="cb37-3"><a href="#cb37-3" aria-hidden="true" tabindex="-1"></a><span class="at">#![</span>feature<span class="at">(</span>type_alias_impl_trait<span class="at">)]</span></span> |
472 | <span id="cb37-4"><a href="#cb37-4" aria-hidden="true" tabindex="-1"></a></span> | 684 | <span id="cb37-4"><a href="#cb37-4" aria-hidden="true" tabindex="-1"></a></span> |
@@ -479,55 +691,81 @@ fn main() { | |||
479 | <span id="cb37-11"><a href="#cb37-11" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> works() <span class="op">{</span></span> | 691 | <span id="cb37-11"><a href="#cb37-11" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> works() <span class="op">{</span></span> |
480 | <span id="cb37-12"><a href="#cb37-12" aria-hidden="true" tabindex="-1"></a> <span class="pp">assert_eq!</span>(<span class="dv">15</span><span class="op">,</span> add(<span class="dv">4</span>)(<span class="dv">5</span>)(<span class="dv">6</span>))<span class="op">;</span></span> | 692 | <span id="cb37-12"><a href="#cb37-12" aria-hidden="true" tabindex="-1"></a> <span class="pp">assert_eq!</span>(<span class="dv">15</span><span class="op">,</span> add(<span class="dv">4</span>)(<span class="dv">5</span>)(<span class="dv">6</span>))<span class="op">;</span></span> |
481 | <span id="cb37-13"><a href="#cb37-13" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div> | 693 | <span id="cb37-13"><a href="#cb37-13" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div> |
482 | <p>Run <code>cargo +nightly test</code>. You should see a pleasing message:</p> | 694 | <p>Run <code>cargo +nightly test</code>. You should see a pleasing |
695 | message:</p> | ||
483 | <pre><code>running 1 test | 696 | <pre><code>running 1 test |
484 | test tests::works ... ok</code></pre> | 697 | test tests::works ... ok</code></pre> |
485 | <p>Take a look at the expansion for our curry macro, via <code>cargo +nightly expand --tests smoke</code>:</p> | 698 | <p>Take a look at the expansion for our curry macro, via |
486 | <div class="sourceCode" id="cb39"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb39-1"><a href="#cb39-1" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> _add_T0 <span class="op">=</span> <span class="dt">u32</span><span class="op">;</span></span> | 699 | <code>cargo +nightly expand --tests smoke</code>:</p> |
700 | <div class="sourceCode" id="cb39"><pre | ||
701 | class="sourceCode rust"><code class="sourceCode rust"><span id="cb39-1"><a href="#cb39-1" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> _add_T0 <span class="op">=</span> <span class="dt">u32</span><span class="op">;</span></span> | ||
487 | <span id="cb39-2"><a href="#cb39-2" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> _add_T1 <span class="op">=</span> <span class="kw">impl</span> <span class="bu">Fn</span>(<span class="dt">u32</span>) <span class="op">-></span> _add_T0<span class="op">;</span></span> | 702 | <span id="cb39-2"><a href="#cb39-2" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> _add_T1 <span class="op">=</span> <span class="kw">impl</span> <span class="bu">Fn</span>(<span class="dt">u32</span>) <span class="op">-></span> _add_T0<span class="op">;</span></span> |
488 | <span id="cb39-3"><a href="#cb39-3" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> _add_T2 <span class="op">=</span> <span class="kw">impl</span> <span class="bu">Fn</span>(<span class="dt">u32</span>) <span class="op">-></span> _add_T1<span class="op">;</span></span> | 703 | <span id="cb39-3"><a href="#cb39-3" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> _add_T2 <span class="op">=</span> <span class="kw">impl</span> <span class="bu">Fn</span>(<span class="dt">u32</span>) <span class="op">-></span> _add_T1<span class="op">;</span></span> |
489 | <span id="cb39-4"><a href="#cb39-4" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> add(x<span class="op">:</span> <span class="dt">u32</span>) <span class="op">-></span> _add_T2 <span class="op">{</span></span> | 704 | <span id="cb39-4"><a href="#cb39-4" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> add(x<span class="op">:</span> <span class="dt">u32</span>) <span class="op">-></span> _add_T2 <span class="op">{</span></span> |
490 | <span id="cb39-5"><a href="#cb39-5" aria-hidden="true" tabindex="-1"></a> <span class="kw">return</span> (<span class="kw">move</span> <span class="op">|</span>y<span class="op">|</span> <span class="op">{</span></span> | 705 | <span id="cb39-5"><a href="#cb39-5" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> (<span class="kw">move</span> <span class="op">|</span>y<span class="op">|</span> <span class="op">{</span></span> |
491 | <span id="cb39-6"><a href="#cb39-6" aria-hidden="true" tabindex="-1"></a> <span class="kw">move</span> <span class="op">|</span>z<span class="op">|</span> <span class="op">{</span></span> | 706 | <span id="cb39-6"><a href="#cb39-6" aria-hidden="true" tabindex="-1"></a> <span class="kw">move</span> <span class="op">|</span>z<span class="op">|</span> <span class="op">{</span></span> |
492 | <span id="cb39-7"><a href="#cb39-7" aria-hidden="true" tabindex="-1"></a> <span class="kw">return</span> x <span class="op">+</span> y <span class="op">+</span> z<span class="op">;</span></span> | 707 | <span id="cb39-7"><a href="#cb39-7" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> x <span class="op">+</span> y <span class="op">+</span> z<span class="op">;</span></span> |
493 | <span id="cb39-8"><a href="#cb39-8" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span> | 708 | <span id="cb39-8"><a href="#cb39-8" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span> |
494 | <span id="cb39-9"><a href="#cb39-9" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span>)<span class="op">;</span></span> | 709 | <span id="cb39-9"><a href="#cb39-9" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span>)<span class="op">;</span></span> |
495 | <span id="cb39-10"><a href="#cb39-10" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span> | 710 | <span id="cb39-10"><a href="#cb39-10" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span> |
496 | <span id="cb39-11"><a href="#cb39-11" aria-hidden="true" tabindex="-1"></a></span> | 711 | <span id="cb39-11"><a href="#cb39-11" aria-hidden="true" tabindex="-1"></a></span> |
497 | <span id="cb39-12"><a href="#cb39-12" aria-hidden="true" tabindex="-1"></a><span class="co">// a bunch of other stuff generated by #[test] and assert_eq!</span></span></code></pre></div> | 712 | <span id="cb39-12"><a href="#cb39-12" aria-hidden="true" tabindex="-1"></a><span class="co">// a bunch of other stuff generated by #[test] and assert_eq!</span></span></code></pre></div> |
498 | <p>A sight for sore eyes.</p> | 713 | <p>A sight for sore eyes.</p> |
499 | <p>Here is a more complex example that generates ten multiples of the first ten natural numbers:</p> | 714 | <p>Here is a more complex example that generates ten multiples of the |
500 | <div class="sourceCode" id="cb40"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb40-1"><a href="#cb40-1" aria-hidden="true" tabindex="-1"></a><span class="at">#[</span>curry<span class="at">]</span></span> | 715 | first ten natural numbers:</p> |
716 | <div class="sourceCode" id="cb40"><pre | ||
717 | class="sourceCode rust"><code class="sourceCode rust"><span id="cb40-1"><a href="#cb40-1" aria-hidden="true" tabindex="-1"></a><span class="at">#[</span>curry<span class="at">]</span></span> | ||
501 | <span id="cb40-2"><a href="#cb40-2" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> product(x<span class="op">:</span> <span class="dt">u32</span><span class="op">,</span> y<span class="op">:</span> <span class="dt">u32</span>) <span class="op">-></span> <span class="dt">u32</span> <span class="op">{</span></span> | 718 | <span id="cb40-2"><a href="#cb40-2" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> product(x<span class="op">:</span> <span class="dt">u32</span><span class="op">,</span> y<span class="op">:</span> <span class="dt">u32</span>) <span class="op">-></span> <span class="dt">u32</span> <span class="op">{</span></span> |
502 | <span id="cb40-3"><a href="#cb40-3" aria-hidden="true" tabindex="-1"></a> x <span class="op">*</span> y</span> | 719 | <span id="cb40-3"><a href="#cb40-3" aria-hidden="true" tabindex="-1"></a> x <span class="op">*</span> y</span> |
503 | <span id="cb40-4"><a href="#cb40-4" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span> | 720 | <span id="cb40-4"><a href="#cb40-4" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span> |
504 | <span id="cb40-5"><a href="#cb40-5" aria-hidden="true" tabindex="-1"></a></span> | 721 | <span id="cb40-5"><a href="#cb40-5" aria-hidden="true" tabindex="-1"></a></span> |
505 | <span id="cb40-6"><a href="#cb40-6" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> multiples() <span class="op">-></span> <span class="dt">Vec</span><span class="op"><</span><span class="dt">Vec</span><span class="op"><</span><span class="dt">u32</span><span class="op">>>{</span></span> | 722 | <span id="cb40-6"><a href="#cb40-6" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> multiples() <span class="op">-></span> <span class="dt">Vec</span><span class="op"><</span><span class="dt">Vec</span><span class="op"><</span><span class="dt">u32</span><span class="op">>>{</span></span> |
506 | <span id="cb40-7"><a href="#cb40-7" aria-hidden="true" tabindex="-1"></a> <span class="kw">let</span> v <span class="op">=</span> (<span class="dv">1</span><span class="op">..=</span><span class="dv">10</span>)<span class="op">.</span>map(product)<span class="op">;</span></span> | 723 | <span id="cb40-7"><a href="#cb40-7" aria-hidden="true" tabindex="-1"></a> <span class="kw">let</span> v <span class="op">=</span> (<span class="dv">1</span><span class="op">..=</span><span class="dv">10</span>)<span class="op">.</span>map(product)<span class="op">;</span></span> |
507 | <span id="cb40-8"><a href="#cb40-8" aria-hidden="true" tabindex="-1"></a> <span class="kw">return</span> (<span class="dv">1</span><span class="op">..=</span><span class="dv">10</span>)</span> | 724 | <span id="cb40-8"><a href="#cb40-8" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> (<span class="dv">1</span><span class="op">..=</span><span class="dv">10</span>)</span> |
508 | <span id="cb40-9"><a href="#cb40-9" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span>map(<span class="op">|</span>x<span class="op">|</span> v<span class="op">.</span>clone()<span class="op">.</span>map(<span class="op">|</span>f<span class="op">|</span> f(x))<span class="op">.</span>collect())</span> | 725 | <span id="cb40-9"><a href="#cb40-9" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span>map(<span class="op">|</span>x<span class="op">|</span> v<span class="op">.</span>clone()<span class="op">.</span>map(<span class="op">|</span>f<span class="op">|</span> f(x))<span class="op">.</span>collect())</span> |
509 | <span id="cb40-10"><a href="#cb40-10" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span>collect()<span class="op">;</span></span> | 726 | <span id="cb40-10"><a href="#cb40-10" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span>collect()<span class="op">;</span></span> |
510 | <span id="cb40-11"><a href="#cb40-11" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div> | 727 | <span id="cb40-11"><a href="#cb40-11" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div> |
511 | <h3 id="notes">Notes</h3> | 728 | <h3 id="notes">Notes</h3> |
512 | <p>I didn’t quite explain why we use <code>move |arg|</code> in our closure. This is because we want to take ownership of the variable supplied to us. Take a look at this example:</p> | 729 | <p>I didn’t quite explain why we use <code>move |arg|</code> in our |
513 | <div class="sourceCode" id="cb41"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb41-1"><a href="#cb41-1" aria-hidden="true" tabindex="-1"></a><span class="kw">let</span> v <span class="op">=</span> add(<span class="dv">5</span>)<span class="op">;</span></span> | 730 | closure. This is because we want to take ownership of the variable |
731 | supplied to us. Take a look at this example:</p> | ||
732 | <div class="sourceCode" id="cb41"><pre | ||
733 | class="sourceCode rust"><code class="sourceCode rust"><span id="cb41-1"><a href="#cb41-1" aria-hidden="true" tabindex="-1"></a><span class="kw">let</span> v <span class="op">=</span> add(<span class="dv">5</span>)<span class="op">;</span></span> | ||
514 | <span id="cb41-2"><a href="#cb41-2" aria-hidden="true" tabindex="-1"></a><span class="kw">let</span> g<span class="op">;</span></span> | 734 | <span id="cb41-2"><a href="#cb41-2" aria-hidden="true" tabindex="-1"></a><span class="kw">let</span> g<span class="op">;</span></span> |
515 | <span id="cb41-3"><a href="#cb41-3" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span> | 735 | <span id="cb41-3"><a href="#cb41-3" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span> |
516 | <span id="cb41-4"><a href="#cb41-4" aria-hidden="true" tabindex="-1"></a> <span class="kw">let</span> x <span class="op">=</span> <span class="dv">5</span><span class="op">;</span></span> | 736 | <span id="cb41-4"><a href="#cb41-4" aria-hidden="true" tabindex="-1"></a> <span class="kw">let</span> x <span class="op">=</span> <span class="dv">5</span><span class="op">;</span></span> |
517 | <span id="cb41-5"><a href="#cb41-5" aria-hidden="true" tabindex="-1"></a> g <span class="op">=</span> v(x)<span class="op">;</span></span> | 737 | <span id="cb41-5"><a href="#cb41-5" aria-hidden="true" tabindex="-1"></a> g <span class="op">=</span> v(x)<span class="op">;</span></span> |
518 | <span id="cb41-6"><a href="#cb41-6" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span> | 738 | <span id="cb41-6"><a href="#cb41-6" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span> |
519 | <span id="cb41-7"><a href="#cb41-7" aria-hidden="true" tabindex="-1"></a><span class="pp">println!</span>(<span class="st">"{}"</span><span class="op">,</span> g(<span class="dv">2</span>))<span class="op">;</span></span></code></pre></div> | 739 | <span id="cb41-7"><a href="#cb41-7" aria-hidden="true" tabindex="-1"></a><span class="pp">println!</span>(<span class="st">"{}"</span><span class="op">,</span> g(<span class="dv">2</span>))<span class="op">;</span></span></code></pre></div> |
520 | <p>Variable <code>x</code> goes out of scope before <code>g</code> can return a concrete value. If we take ownership of <code>x</code> by <code>move</code>ing it into our closure, we can expect this to work reliably. In fact, rustc understands this, and forces you to use <code>move</code>.</p> | 740 | <p>Variable <code>x</code> goes out of scope before <code>g</code> can |
521 | <p>This usage of <code>move</code> is exactly why <strong>a curried function without a return is useless</strong>. Every variable we pass to our curried function gets moved into its local scope. Playing with these variables cannot cause a change outside this scope. Returning is our only method of interaction with anything beyond this function.</p> | 741 | return a concrete value. If we take ownership of <code>x</code> by |
742 | <code>move</code>ing it into our closure, we can expect this to work | ||
743 | reliably. In fact, rustc understands this, and forces you to use | ||
744 | <code>move</code>.</p> | ||
745 | <p>This usage of <code>move</code> is exactly why <strong>a curried | ||
746 | function without a return is useless</strong>. Every variable we pass to | ||
747 | our curried function gets moved into its local scope. Playing with these | ||
748 | variables cannot cause a change outside this scope. Returning is our | ||
749 | only method of interaction with anything beyond this function.</p> | ||
522 | <h3 id="conclusion">Conclusion</h3> | 750 | <h3 id="conclusion">Conclusion</h3> |
523 | <p>Currying may not seem to be all that useful. Curried functions are unwieldy in Rust because the standard library is not built around currying. If you enjoy the possibilities posed by currying, consider taking a look at Haskell or Scheme.</p> | 751 | <p>Currying may not seem to be all that useful. Curried functions are |
524 | <p>My original intention with <a href="https://peppe.rs">peppe.rs</a> was to post condensed articles, a micro blog, but this one turned out extra long.</p> | 752 | unwieldy in Rust because the standard library is not built around |
753 | currying. If you enjoy the possibilities posed by currying, consider | ||
754 | taking a look at Haskell or Scheme.</p> | ||
755 | <p>My original intention with <a href="https://peppe.rs">peppe.rs</a> | ||
756 | was to post condensed articles, a micro blog, but this one turned out | ||
757 | extra long.</p> | ||
525 | <p>Perhaps I should call it a ‘macro’ blog :)</p> | 758 | <p>Perhaps I should call it a ‘macro’ blog :)</p> |
526 | <section class="footnotes" role="doc-endnotes"> | 759 | <section id="footnotes" class="footnotes footnotes-end-of-document" |
760 | role="doc-endnotes"> | ||
527 | <hr /> | 761 | <hr /> |
528 | <ol> | 762 | <ol> |
529 | <li id="fn1" role="doc-endnote"><p><a href="https://doc.rust-lang.org/book/ch13-01-closures.html">https://doc.rust-lang.org/book/ch13-01-closures.html</a><a href="#fnref1" class="footnote-back" role="doc-backlink">↩︎</a></p></li> | 763 | <li id="fn1"><p><a |
530 | <li id="fn2" role="doc-endnote"><p><a href="https://caniuse.rs">caniuse.rs</a> contains an indexed list of features and their status.<a href="#fnref2" class="footnote-back" role="doc-backlink">↩︎</a></p></li> | 764 | href="https://doc.rust-lang.org/book/ch13-01-closures.html">https://doc.rust-lang.org/book/ch13-01-closures.html</a><a |
765 | href="#fnref1" class="footnote-back" role="doc-backlink">↩︎</a></p></li> | ||
766 | <li id="fn2"><p><a href="https://caniuse.rs">caniuse.rs</a> contains an | ||
767 | indexed list of features and their status.<a href="#fnref2" | ||
768 | class="footnote-back" role="doc-backlink">↩︎</a></p></li> | ||
531 | </ol> | 769 | </ol> |
532 | </section> | 770 | </section> |
533 | 771 | ||
diff --git a/docs/posts/bash_harder_with_vim/index.html b/docs/posts/bash_harder_with_vim/index.html index 099733a..96210d5 100644 --- a/docs/posts/bash_harder_with_vim/index.html +++ b/docs/posts/bash_harder_with_vim/index.html | |||
@@ -28,7 +28,7 @@ | |||
28 | 31/07 — 2019 | 28 | 31/07 — 2019 |
29 | <div class="stats"> | 29 | <div class="stats"> |
30 | <span class="stats-number"> | 30 | <span class="stats-number"> |
31 | 24.37 | 31 | 24.38 |
32 | </span> | 32 | </span> |
33 | <span class="stats-unit">cm</span> | 33 | <span class="stats-unit">cm</span> |
34 |   | 34 |   |
@@ -42,18 +42,26 @@ | |||
42 | Bash Harder With Vim | 42 | Bash Harder With Vim |
43 | </h1> | 43 | </h1> |
44 | <div class="post-text"> | 44 | <div class="post-text"> |
45 | <p>Bash is tricky, don’t let your editor get in your way. Here’s a couple of neat additions you could make to your <code>vimrc</code> for a better shell programming experience.</p> | 45 | <p>Bash is tricky, don’t let your editor get in your way. Here’s a |
46 | couple of neat additions you could make to your <code>vimrc</code> for a | ||
47 | better shell programming experience.</p> | ||
46 | <h3 id="man-pages-inside-vim">Man pages inside vim</h3> | 48 | <h3 id="man-pages-inside-vim">Man pages inside vim</h3> |
47 | <p>Source this script to get started:</p> | 49 | <p>Source this script to get started:</p> |
48 | <pre><code>runtime ftplugin/man.vim</code></pre> | 50 | <pre><code>runtime ftplugin/man.vim</code></pre> |
49 | <p>Now, you can open manpages inside vim with <code>:Man</code>! It adds nicer syntax highlighting and the ability to jump around with <code>Ctrl-]</code> and <code>Ctrl-T</code>.</p> | 51 | <p>Now, you can open manpages inside vim with <code>:Man</code>! It adds |
50 | <p>By default, the manpage is opened in a horizontal split, I prefer using a new tab:</p> | 52 | nicer syntax highlighting and the ability to jump around with |
53 | <code>Ctrl-]</code> and <code>Ctrl-T</code>.</p> | ||
54 | <p>By default, the manpage is opened in a horizontal split, I prefer | ||
55 | using a new tab:</p> | ||
51 | <pre><code>let g:ft_man_open_mode = 'tab'</code></pre> | 56 | <pre><code>let g:ft_man_open_mode = 'tab'</code></pre> |
52 | <h3 id="scratchpad-to-test-your-commands">Scratchpad to test your commands</h3> | 57 | <h3 id="scratchpad-to-test-your-commands">Scratchpad to test your |
53 | <p>I often test my <code>sed</code> substitutions, here is a sample from the script used to generate this site:</p> | 58 | commands</h3> |
59 | <p>I often test my <code>sed</code> substitutions, here is a sample from | ||
60 | the script used to generate this site:</p> | ||
54 | <pre><code># a substitution to convert snake_case to Title Case With Spaces | 61 | <pre><code># a substitution to convert snake_case to Title Case With Spaces |
55 | echo "$1" | sed -E -e "s/\..+$//g" -e "s/_(.)/ \u\1/g" -e "s/^(.)/\u\1/g"</code></pre> | 62 | echo "$1" | sed -E -e "s/\..+$//g" -e "s/_(.)/ \u\1/g" -e "s/^(.)/\u\1/g"</code></pre> |
56 | <p>Instead of dropping into a new shell, just test it out directly from vim!</p> | 63 | <p>Instead of dropping into a new shell, just test it out directly from |
64 | vim!</p> | ||
57 | <ul> | 65 | <ul> |
58 | <li>Yank the line into a register:</li> | 66 | <li>Yank the line into a register:</li> |
59 | </ul> | 67 | </ul> |
diff --git a/docs/posts/bye_bye_BDFs/index.html b/docs/posts/bye_bye_BDFs/index.html index 4b2682c..8b9584f 100644 --- a/docs/posts/bye_bye_BDFs/index.html +++ b/docs/posts/bye_bye_BDFs/index.html | |||
@@ -42,12 +42,30 @@ | |||
42 | Bye Bye BDFs | 42 | Bye Bye BDFs |
43 | </h1> | 43 | </h1> |
44 | <div class="post-text"> | 44 | <div class="post-text"> |
45 | <p>Glyph Bitmap Distribution Format is no more, as the creators of <a href="https://pango.org">Pango</a>, one of the most widely used text rendering libraries, <a href="https://blogs.gnome.org/mclasen/2019/05/25/pango-future-directions/">announced</a> their plans for Pango 1.44.</p> | 45 | <p>Glyph Bitmap Distribution Format is no more, as the creators of <a |
46 | <p>Until recently, Pango used FreeType to draw fonts. They will be moving over to <a href="https://harfbuzz.org">Harfbuzz</a>, an evolution of FreeType.</p> | 46 | href="https://pango.org">Pango</a>, one of the most widely used text |
47 | rendering libraries, <a | ||
48 | href="https://blogs.gnome.org/mclasen/2019/05/25/pango-future-directions/">announced</a> | ||
49 | their plans for Pango 1.44.</p> | ||
50 | <p>Until recently, Pango used FreeType to draw fonts. They will be | ||
51 | moving over to <a href="https://harfbuzz.org">Harfbuzz</a>, an evolution | ||
52 | of FreeType.</p> | ||
47 | <p><em>Why?</em></p> | 53 | <p><em>Why?</em></p> |
48 | <p>In short, FreeType was hard to work with. It required complex logic, and provided no advantage over Harfbuzz (other than being able to fetch opentype metrics with ease).</p> | 54 | <p>In short, FreeType was hard to work with. It required complex logic, |
49 | <p>Upgrading to Pango v1.44 will break your GTK applications (if you use a <code>bdf</code>/<code>pcf</code> bitmap font). Harfbuzz <em>does</em> support bitmap-only OpenType fonts, <code>otb</code>s. Convert your existing fonts over to <code>otb</code>s using <a href="https://fontforge.github.io">FontForge</a>. It is to be noted that applications such as <code>xterm</code> and <code>rxvt</code> use <code>xft</code> (X FreeType) to render fonts, and will remain unaffected by the update.</p> | 55 | and provided no advantage over Harfbuzz (other than being able to fetch |
50 | <p>Both <a href="https://github.com/nerdypepper/scientifica">scientifica</a> and <a href="https://github.com/nerdypepper/curie">curie</a> will soon ship with bitmap-only OpenType font formats.</p> | 56 | opentype metrics with ease).</p> |
57 | <p>Upgrading to Pango v1.44 will break your GTK applications (if you use | ||
58 | a <code>bdf</code>/<code>pcf</code> bitmap font). Harfbuzz <em>does</em> | ||
59 | support bitmap-only OpenType fonts, <code>otb</code>s. Convert your | ||
60 | existing fonts over to <code>otb</code>s using <a | ||
61 | href="https://fontforge.github.io">FontForge</a>. It is to be noted that | ||
62 | applications such as <code>xterm</code> and <code>rxvt</code> use | ||
63 | <code>xft</code> (X FreeType) to render fonts, and will remain | ||
64 | unaffected by the update.</p> | ||
65 | <p>Both <a | ||
66 | href="https://github.com/nerdypepper/scientifica">scientifica</a> and <a | ||
67 | href="https://github.com/nerdypepper/curie">curie</a> will soon ship | ||
68 | with bitmap-only OpenType font formats.</p> | ||
51 | 69 | ||
52 | </div> | 70 | </div> |
53 | 71 | ||
diff --git a/docs/posts/call_to_ARMs/index.html b/docs/posts/call_to_ARMs/index.html index 3331107..1b13213 100644 --- a/docs/posts/call_to_ARMs/index.html +++ b/docs/posts/call_to_ARMs/index.html | |||
@@ -33,7 +33,7 @@ | |||
33 | <span class="stats-unit">cm</span> | 33 | <span class="stats-unit">cm</span> |
34 |   | 34 |   |
35 | <span class="stats-number"> | 35 | <span class="stats-number"> |
36 | 2.2 | 36 | 2.3 |
37 | </span> | 37 | </span> |
38 | <span class="stats-unit">min</span> | 38 | <span class="stats-unit">min</span> |
39 | </div> | 39 | </div> |
@@ -42,37 +42,60 @@ | |||
42 | Call To ARMs | 42 | Call To ARMs |
43 | </h1> | 43 | </h1> |
44 | <div class="post-text"> | 44 | <div class="post-text"> |
45 | <p>My 4th semester involves ARM programming. And proprietary tooling (Keil C). But we don’t do that here.</p> | 45 | <p>My 4th semester involves ARM programming. And proprietary tooling |
46 | (Keil C). But we don’t do that here.</p> | ||
46 | <h3 id="building">Building</h3> | 47 | <h3 id="building">Building</h3> |
47 | <p>Assembling and linking ARM binaries on non-ARM architecture devices is fairly trivial. I went along with the GNU cross bare metal toolchain binutils, which provides <code>arm-as</code> and <code>arm-ld</code> (among a bunch of other utils that I don’t care about for now).</p> | 48 | <p>Assembling and linking ARM binaries on non-ARM architecture devices |
49 | is fairly trivial. I went along with the GNU cross bare metal toolchain | ||
50 | binutils, which provides <code>arm-as</code> and <code>arm-ld</code> | ||
51 | (among a bunch of other utils that I don’t care about for now).</p> | ||
48 | <p>Assemble <code>.s</code> files with:</p> | 52 | <p>Assemble <code>.s</code> files with:</p> |
49 | <pre class="shell"><code>arm-none-eabi-as main.s -g -march=armv8.1-a -o main.out</code></pre> | 53 | <pre class="shell"><code>arm-none-eabi-as main.s -g -march=armv8.1-a -o main.out</code></pre> |
50 | <p>The <code>-g</code> flag generates extra debugging information that <code>gdb</code> picks up. The <code>-march</code> option establishes target architecture.</p> | 54 | <p>The <code>-g</code> flag generates extra debugging information that |
55 | <code>gdb</code> picks up. The <code>-march</code> option establishes | ||
56 | target architecture.</p> | ||
51 | <p>Link <code>.o</code> files with:</p> | 57 | <p>Link <code>.o</code> files with:</p> |
52 | <pre class="shell"><code>arm-none-eabi-ld main.out -o main</code></pre> | 58 | <pre class="shell"><code>arm-none-eabi-ld main.out -o main</code></pre> |
53 | <h3 id="running-and-debugging">Running (and Debugging)</h3> | 59 | <h3 id="running-and-debugging">Running (and Debugging)</h3> |
54 | <p>Things get interesting here. <code>gdb</code> on your x86 machine cannot read nor execute binaries compiled for ARM. So, we simulate an ARM processor using <code>qemu</code>. Now qemu allows you to run <code>gdbserver</code> on startup. Connecting our local <code>gdb</code> instance to <code>gdbserver</code> gives us a view into the program’s execution. Easy!</p> | 60 | <p>Things get interesting here. <code>gdb</code> on your x86 machine |
55 | <p>Run <code>qemu</code>, with <code>gdbserver</code> on port <code>1234</code>, with our ARM binary, <code>main</code>:</p> | 61 | cannot read nor execute binaries compiled for ARM. So, we simulate an |
62 | ARM processor using <code>qemu</code>. Now qemu allows you to run | ||
63 | <code>gdbserver</code> on startup. Connecting our local <code>gdb</code> | ||
64 | instance to <code>gdbserver</code> gives us a view into the program’s | ||
65 | execution. Easy!</p> | ||
66 | <p>Run <code>qemu</code>, with <code>gdbserver</code> on port | ||
67 | <code>1234</code>, with our ARM binary, <code>main</code>:</p> | ||
56 | <pre class="shell"><code>qemu-arm -singlestep -g 1234 main</code></pre> | 68 | <pre class="shell"><code>qemu-arm -singlestep -g 1234 main</code></pre> |
57 | <p>Start up <code>gdb</code> on your machine, and connect to <code>qemu</code>’s <code>gdbserver</code>:</p> | 69 | <p>Start up <code>gdb</code> on your machine, and connect to |
70 | <code>qemu</code>’s <code>gdbserver</code>:</p> | ||
58 | <pre><code>(gdb) set architecture armv8-a | 71 | <pre><code>(gdb) set architecture armv8-a |
59 | (gdb) target remote localhost:1234 | 72 | (gdb) target remote localhost:1234 |
60 | (gdb) file main | 73 | (gdb) file main |
61 | Reading symbols from main... # yay!</code></pre> | 74 | Reading symbols from main... # yay!</code></pre> |
62 | <h3 id="gdb-enhanced">GDB Enhanced</h3> | 75 | <h3 id="gdb-enhanced">GDB Enhanced</h3> |
63 | <p><code>gdb</code> is cool, but it’s not nearly as comfortable as well fleshed out emulators/IDEs like Keil. Watching registers, CPSR and memory chunks update <em>is</em> pretty fun.</p> | 76 | <p><code>gdb</code> is cool, but it’s not nearly as comfortable as well |
64 | <p>I came across <code>gdb</code>’s TUI mode (hit <code>C-x C-a</code> or type <code>tui enable</code> at the prompt). TUI mode is a godsend. It highlights the current line of execution, shows you disassembly outputs, updated registers, active breakpoints and more.</p> | 77 | fleshed out emulators/IDEs like Keil. Watching registers, CPSR and |
78 | memory chunks update <em>is</em> pretty fun.</p> | ||
79 | <p>I came across <code>gdb</code>’s TUI mode (hit <code>C-x C-a</code> | ||
80 | or type <code>tui enable</code> at the prompt). TUI mode is a godsend. | ||
81 | It highlights the current line of execution, shows you disassembly | ||
82 | outputs, updated registers, active breakpoints and more.</p> | ||
65 | <p><em>But</em>, it is an absolute eyesore.</p> | 83 | <p><em>But</em>, it is an absolute eyesore.</p> |
66 | <p>Say hello to <a href="https://github.com/hugsy/gef">GEF</a>! “GDB Enhanced Features” teaches our old dog some cool new tricks. Here are some additions that made my ARM debugging experience loads better:</p> | 84 | <p>Say hello to <a href="https://github.com/hugsy/gef">GEF</a>! “GDB |
85 | Enhanced Features” teaches our old dog some cool new tricks. Here are | ||
86 | some additions that made my ARM debugging experience loads better:</p> | ||
67 | <ul> | 87 | <ul> |
68 | <li>Memory watches</li> | 88 | <li>Memory watches</li> |
69 | <li>Register watches, with up to 7 levels of deref (overkill, I agree)</li> | 89 | <li>Register watches, with up to 7 levels of deref (overkill, I |
90 | agree)</li> | ||
70 | <li>Stack tracing</li> | 91 | <li>Stack tracing</li> |
71 | </ul> | 92 | </ul> |
72 | <p>And it’s pretty! See for yourself:</p> | 93 | <p>And it’s pretty! See for yourself:</p> |
73 | <p><a href="https://u.peppe.rs/wq.png"><img src="https://u.peppe.rs/wq.png" /></a></p> | 94 | <p><a href="https://u.peppe.rs/wq.png"><img |
95 | src="https://u.peppe.rs/wq.png" /></a></p> | ||
74 | <h3 id="editing">Editing</h3> | 96 | <h3 id="editing">Editing</h3> |
75 | <p>Vim, with <code>syntax off</code> because it dosen’t handle GNU ARM syntax too well.</p> | 97 | <p>Vim, with <code>syntax off</code> because it dosen’t handle GNU ARM |
98 | syntax too well.</p> | ||
76 | 99 | ||
77 | </div> | 100 | </div> |
78 | 101 | ||
diff --git a/docs/posts/color_conundrum/index.html b/docs/posts/color_conundrum/index.html index 6c493c2..eeba49b 100644 --- a/docs/posts/color_conundrum/index.html +++ b/docs/posts/color_conundrum/index.html | |||
@@ -33,7 +33,7 @@ | |||
33 | <span class="stats-unit">cm</span> | 33 | <span class="stats-unit">cm</span> |
34 |   | 34 |   |
35 | <span class="stats-number"> | 35 | <span class="stats-number"> |
36 | 1.3 | 36 | 1.4 |
37 | </span> | 37 | </span> |
38 | <span class="stats-unit">min</span> | 38 | <span class="stats-unit">min</span> |
39 | </div> | 39 | </div> |
@@ -42,14 +42,32 @@ | |||
42 | Color Conundrum | 42 | Color Conundrum |
43 | </h1> | 43 | </h1> |
44 | <div class="post-text"> | 44 | <div class="post-text"> |
45 | <p>This piece aims to highlight (pun intended) some of the reasons behind my <a href="https://u.peppe.rs/bF.png">color free</a> editor setup.</p> | 45 | <p>This piece aims to highlight (pun intended) some of the reasons |
46 | <p>Imagine highlighting an entire book because <em>all</em> of it is important. That is exactly what (most) syntax highlighting does. It is difficult for the human eye to filter out noise in rainbow barf. Use color to draw attention, not diverge it.</p> | 46 | behind my <a href="https://u.peppe.rs/bF.png">color free</a> editor |
47 | <p>At the same time, a book devoid of color is <em>boring!</em> What is the takeaway from this 10 line paragraph? What are the technical terms used?</p> | 47 | setup.</p> |
48 | <p>Prose and code are certainly different, but the fickle minded human eye is the same. The eye constantly looks for a frame of reference, a focal point. It grows tired when it can’t find one.</p> | 48 | <p>Imagine highlighting an entire book because <em>all</em> of it is |
49 | <p>The following comparison does a better job of explaining (none, ample and over-the-top highlighting, from left to right):</p> | 49 | important. That is exactly what (most) syntax highlighting does. It is |
50 | <p><a href="https://u.peppe.rs/lt.png"><img src="https://u.peppe.rs/lt.png" /></a></p> | 50 | difficult for the human eye to filter out noise in rainbow barf. Use |
51 | <p>Without highlighting (far left), it is hard to differentiate between comments and code! The florid color scheme (far right) is no good either, it contains too many attention grabbers. The center sample is a healthy balance of both. Function calls and constants stand out, and repetitive keywords and other noise (<code>let</code>, <code>as</code>) are mildly dimmed out. Comments and non-code text (sign column, status text) are dimmed further.</p> | 51 | color to draw attention, not diverge it.</p> |
52 | <p>I’ll stop myself before I rant about color contrast and combinations.</p> | 52 | <p>At the same time, a book devoid of color is <em>boring!</em> What is |
53 | the takeaway from this 10 line paragraph? What are the technical terms | ||
54 | used?</p> | ||
55 | <p>Prose and code are certainly different, but the fickle minded human | ||
56 | eye is the same. The eye constantly looks for a frame of reference, a | ||
57 | focal point. It grows tired when it can’t find one.</p> | ||
58 | <p>The following comparison does a better job of explaining (none, ample | ||
59 | and over-the-top highlighting, from left to right):</p> | ||
60 | <p><a href="https://u.peppe.rs/lt.png"><img | ||
61 | src="https://u.peppe.rs/lt.png" /></a></p> | ||
62 | <p>Without highlighting (far left), it is hard to differentiate between | ||
63 | comments and code! The florid color scheme (far right) is no good | ||
64 | either, it contains too many attention grabbers. The center sample is a | ||
65 | healthy balance of both. Function calls and constants stand out, and | ||
66 | repetitive keywords and other noise (<code>let</code>, <code>as</code>) | ||
67 | are mildly dimmed out. Comments and non-code text (sign column, status | ||
68 | text) are dimmed further.</p> | ||
69 | <p>I’ll stop myself before I rant about color contrast and | ||
70 | combinations.</p> | ||
53 | 71 | ||
54 | </div> | 72 | </div> |
55 | 73 | ||
diff --git a/docs/posts/curing_a_case_of_git-UX/index.html b/docs/posts/curing_a_case_of_git-UX/index.html index 9c4761c..140436a 100644 --- a/docs/posts/curing_a_case_of_git-UX/index.html +++ b/docs/posts/curing_a_case_of_git-UX/index.html | |||
@@ -33,7 +33,7 @@ | |||
33 | <span class="stats-unit">cm</span> | 33 | <span class="stats-unit">cm</span> |
34 |   | 34 |   |
35 | <span class="stats-number"> | 35 | <span class="stats-number"> |
36 | 9.5 | 36 | 9.6 |
37 | </span> | 37 | </span> |
38 | <span class="stats-unit">min</span> | 38 | <span class="stats-unit">min</span> |
39 | </div> | 39 | </div> |
@@ -42,51 +42,86 @@ | |||
42 | Curing A Case Of Git-UX | 42 | Curing A Case Of Git-UX |
43 | </h1> | 43 | </h1> |
44 | <div class="post-text"> | 44 | <div class="post-text"> |
45 | <p>Git worktrees are great, but they fall behind the venerable <code>git checkout</code> sometimes. I attempted to fix that with <a href="https://github.com/junegunn/fzf">fzf</a> and a bit of bash.</p> | 45 | <p>Git worktrees are great, but they fall behind the venerable |
46 | <p><a href="https://asciinema.org/a/D297ztKRzpE4gAHbPTPmkqYps"><img src="https://asciinema.org/a/D297ztKRzpE4gAHbPTPmkqYps.svg" /></a></p> | 46 | <code>git checkout</code> sometimes. I attempted to fix that with <a |
47 | <p>Fear not if you haven’t heard of “worktrees”, I have included a primer here.<br /> | 47 | href="https://github.com/junegunn/fzf">fzf</a> and a bit of bash.</p> |
48 | <p><a href="https://asciinema.org/a/D297ztKRzpE4gAHbPTPmkqYps"><img | ||
49 | src="https://asciinema.org/a/D297ztKRzpE4gAHbPTPmkqYps.svg" /></a></p> | ||
50 | <p>Fear not if you haven’t heard of “worktrees”, I have included a | ||
51 | primer here.<br /> | ||
48 | <a href="#what-makes-them-clunky">Skip the primer -></a>.</p> | 52 | <a href="#what-makes-them-clunky">Skip the primer -></a>.</p> |
49 | <h3 id="why-worktrees">Why Worktrees?</h3> | 53 | <h3 id="why-worktrees">Why Worktrees?</h3> |
50 | <p>Picture this. You are whacking away on a feature branch. Halfway there, in fact. Your friend asks you fix something urgently. You proceed to do one of three things:</p> | 54 | <p>Picture this. You are whacking away on a feature branch. Halfway |
55 | there, in fact. Your friend asks you fix something urgently. You proceed | ||
56 | to do one of three things:</p> | ||
51 | <ul> | 57 | <ul> |
52 | <li>create a temporary branch, make a WIP commit, begin working on the fix</li> | 58 | <li>create a temporary branch, make a WIP commit, begin working on the |
59 | fix</li> | ||
53 | <li>stash away your changes, begin working on the fix</li> | 60 | <li>stash away your changes, begin working on the fix</li> |
54 | <li>unfriend said friend for disturbing your flow</li> | 61 | <li>unfriend said friend for disturbing your flow</li> |
55 | </ul> | 62 | </ul> |
56 | <p>All of these options are … subpar. With the temporary branch, you are forced to create a partial, non-working commit, and then reset said commit once done with the fix. With the stash approach, you are required to now keep a mental model of the stash, be aware of untracked files that don’t get stashed by default, etc. Why won’t git just let you work on two things at the same time without <em>thinking</em> so much?</p> | 63 | <p>All of these options are … subpar. With the temporary branch, you are |
57 | <p>That is exactly what worktrees let you do. Worktrees let you have more than one checkout at a time, each checkout in a separate directory. Like creating a new clone, but safer (it disallows checking out the same branch twice) and a lot more space efficient (the new working tree is “linked” to the “main” worktree, and a good amount of stuff is shared). When your friend asks you to make the fix, you proceed like so:</p> | 64 | forced to create a partial, non-working commit, and then reset said |
65 | commit once done with the fix. With the stash approach, you are required | ||
66 | to now keep a mental model of the stash, be aware of untracked files | ||
67 | that don’t get stashed by default, etc. Why won’t git just let you work | ||
68 | on two things at the same time without <em>thinking</em> so much?</p> | ||
69 | <p>That is exactly what worktrees let you do. Worktrees let you have | ||
70 | more than one checkout at a time, each checkout in a separate directory. | ||
71 | Like creating a new clone, but safer (it disallows checking out the same | ||
72 | branch twice) and a lot more space efficient (the new working tree is | ||
73 | “linked” to the “main” worktree, and a good amount of stuff is shared). | ||
74 | When your friend asks you to make the fix, you proceed like so:</p> | ||
58 | <ol type="1"> | 75 | <ol type="1"> |
59 | <li>Create a new working tree with:</li> | 76 | <li>Create a new working tree with:</li> |
60 | </ol> | 77 | </ol> |
61 | <div class="sourceCode" id="cb1"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="co"># git worktree add -b <branch-name> <path> <from></span></span> | 78 | <div class="sourceCode" id="cb1"><pre |
79 | class="sourceCode bash"><code class="sourceCode bash"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="co"># git worktree add -b <branch-name> <path> <from></span></span> | ||
62 | <span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="fu">git</span> worktree add <span class="at">-b</span> fix-stuff /path/to/tree master</span></code></pre></div> | 80 | <span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="fu">git</span> worktree add <span class="at">-b</span> fix-stuff /path/to/tree master</span></code></pre></div> |
63 | <ol start="2" type="1"> | 81 | <ol start="2" type="1"> |
64 | <li><code>cd</code> into <code>/path/to/tree</code></li> | 82 | <li><code>cd</code> into <code>/path/to/tree</code></li> |
65 | <li>Fix, test, commit, push, party</li> | 83 | <li>Fix, test, commit, push, party</li> |
66 | <li>Go back to your work, <code>cd -</code></li> | 84 | <li>Go back to your work, <code>cd -</code></li> |
67 | </ol> | 85 | </ol> |
68 | <p>Easy as cake. You didn’t have to settle for a partially working commit, you didn’t to deal with this “stash” thing, <em>and</em> you didn’t have to unfriend your friend. Treating each branch as a directory just <em>feels</em> more intuitive, more UNIX-y.</p> | 86 | <p>Easy as cake. You didn’t have to settle for a partially working |
69 | <p>A few weeks later, you find yourself singing in praise of worktrees, working on several things simultaneously. And at the same time, cursing them for being a little … clunky.</p> | 87 | commit, you didn’t to deal with this “stash” thing, <em>and</em> you |
88 | didn’t have to unfriend your friend. Treating each branch as a directory | ||
89 | just <em>feels</em> more intuitive, more UNIX-y.</p> | ||
90 | <p>A few weeks later, you find yourself singing in praise of worktrees, | ||
91 | working on several things simultaneously. And at the same time, cursing | ||
92 | them for being a little … clunky.</p> | ||
70 | <h3 id="what-makes-them-clunky">What makes them clunky?</h3> | 93 | <h3 id="what-makes-them-clunky">What makes them clunky?</h3> |
71 | <p>Worktrees are great at what they claim to do. They stay out of the way when you need a checkout posthaste. However, as you start using them regularly, you realize they are not as flexible as <code>git checkout</code> or <code>git switch</code>.</p> | 94 | <p>Worktrees are great at what they claim to do. They stay out of the |
95 | way when you need a checkout posthaste. However, as you start using them | ||
96 | regularly, you realize they are not as flexible as | ||
97 | <code>git checkout</code> or <code>git switch</code>.</p> | ||
72 | <h4 id="branch-hopping">Branch-hopping</h4> | 98 | <h4 id="branch-hopping">Branch-hopping</h4> |
73 | <p>You can <code>git checkout <branch></code> from anywhere within a git repository. You can’t “jump” to a worktree in the same fashion. The closest you can get, is to run <code>git worktree list</code>, copy the path corresponding to your branch, and <code>cd</code> into it.</p> | 99 | <p>You can <code>git checkout <branch></code> from anywhere within |
100 | a git repository. You can’t “jump” to a worktree in the same fashion. | ||
101 | The closest you can get, is to run <code>git worktree list</code>, copy | ||
102 | the path corresponding to your branch, and <code>cd</code> into it.</p> | ||
74 | <p>Branch-hopping with the good ol’ git-checkout:</p> | 103 | <p>Branch-hopping with the good ol’ git-checkout:</p> |
75 | <div class="sourceCode" id="cb2"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="co"># anywhere, anytime</span></span> | 104 | <div class="sourceCode" id="cb2"><pre |
105 | class="sourceCode bash"><code class="sourceCode bash"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="co"># anywhere, anytime</span></span> | ||
76 | <span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="ex">λ</span> git checkout feature/is-ascii-octdigit</span></code></pre></div> | 106 | <span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="ex">λ</span> git checkout feature/is-ascii-octdigit</span></code></pre></div> |
77 | <p>Meanwhile, in worktree world:</p> | 107 | <p>Meanwhile, in worktree world:</p> |
78 | <div class="sourceCode" id="cb3"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="co"># keeping these paths in your head is hard</span></span> | 108 | <div class="sourceCode" id="cb3"><pre |
109 | class="sourceCode bash"><code class="sourceCode bash"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="co"># keeping these paths in your head is hard</span></span> | ||
79 | <span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a><span class="ex">λ</span> git worktree list</span> | 110 | <span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a><span class="ex">λ</span> git worktree list</span> |
80 | <span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a><span class="ex">~/worktrees/rustc/master</span> eac6c33bc63 [master]</span> | 111 | <span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a><span class="ex">~/worktrees/rustc/master</span> eac6c33bc63 <span class="pp">[</span><span class="ss">master</span><span class="pp">]</span></span> |
81 | <span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a><span class="ex">~/worktrees/rustc/improve-std-char-docs</span> 94cba88553e [improve-std-char-docs]</span> | 112 | <span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a><span class="ex">~/worktrees/rustc/improve-std-char-docs</span> 94cba88553e <span class="pp">[</span><span class="ss">improve</span><span class="pp">-</span><span class="ss">std</span><span class="pp">-</span><span class="ss">char</span><span class="pp">-</span><span class="ss">docs</span><span class="pp">]</span></span> |
82 | <span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a><span class="ex">~/worktrees/rustc/is-ascii-octdigit</span> bc57be3af7a [feature/is-ascii-octdigit]</span> | 113 | <span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a><span class="ex">~/worktrees/rustc/is-ascii-octdigit</span> bc57be3af7a <span class="pp">[</span><span class="ss">feature/is</span><span class="pp">-</span><span class="ss">ascii</span><span class="pp">-</span><span class="ss">octdigit</span><span class="pp">]</span></span> |
83 | <span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a><span class="ex">~/my/other/path/oh/god</span> op57or3ns7n [fix/some-error]</span> | 114 | <span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a><span class="ex">~/my/other/path/oh/god</span> op57or3ns7n <span class="pp">[</span><span class="ss">fix/some</span><span class="pp">-</span><span class="ss">error</span><span class="pp">]</span></span> |
84 | <span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a></span> | 115 | <span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a></span> |
85 | <span id="cb3-8"><a href="#cb3-8" aria-hidden="true" tabindex="-1"></a><span class="ex">λ</span> cd ~/worktrees/rustc/is-ascii-octdigit</span></code></pre></div> | 116 | <span id="cb3-8"><a href="#cb3-8" aria-hidden="true" tabindex="-1"></a><span class="ex">λ</span> cd ~/worktrees/rustc/is-ascii-octdigit</span></code></pre></div> |
86 | <h4 id="branch-previewing">Branch-previewing</h4> | 117 | <h4 id="branch-previewing">Branch-previewing</h4> |
87 | <p>You can “preview” branches with <code>git branch -v</code>. However, to get an idea of what “recent activity” on a worktree looks like, you might need some juggling. You can’t glean much info about a worktree in a jiffy.</p> | 118 | <p>You can “preview” branches with <code>git branch -v</code>. However, |
119 | to get an idea of what “recent activity” on a worktree looks like, you | ||
120 | might need some juggling. You can’t glean much info about a worktree in | ||
121 | a jiffy.</p> | ||
88 | <p>Branch-previewing with the good ol’ git-branch:</p> | 122 | <p>Branch-previewing with the good ol’ git-branch:</p> |
89 | <div class="sourceCode" id="cb4"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="ex">λ</span> git branch <span class="at">-v</span></span> | 123 | <div class="sourceCode" id="cb4"><pre |
124 | class="sourceCode bash"><code class="sourceCode bash"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="ex">λ</span> git branch <span class="at">-v</span></span> | ||
90 | <span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a><span class="ex">+</span> feature/is-ascii-octdigit bc57be3af7a introduce {char, u8}::is_ ...</span> | 125 | <span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a><span class="ex">+</span> feature/is-ascii-octdigit bc57be3af7a introduce {char, u8}::is_ ...</span> |
91 | <span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a><span class="ex">+</span> improve-std-char-docs 94cba88553e add whitespace in assert ...</span> | 126 | <span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a><span class="ex">+</span> improve-std-char-docs 94cba88553e add whitespace in assert ...</span> |
92 | <span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a><span class="ex">*</span> master eac6c33bc63 Auto merge of <span class="co">#100869 - n ...</span></span></code></pre></div> | 127 | <span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a><span class="ex">*</span> master eac6c33bc63 Auto merge of <span class="co">#100869 - n ...</span></span></code></pre></div> |
@@ -105,41 +140,60 @@ aa857eb953e Auto merge of #100537 - petrochenkov:pic ... | |||
105 | 140 | ||
106 | # extra work to make the branch <-> worktree correspondence</code></pre> | 141 | # extra work to make the branch <-> worktree correspondence</code></pre> |
107 | <h4 id="shell-completions">Shell completions</h4> | 142 | <h4 id="shell-completions">Shell completions</h4> |
108 | <p>Lastly, you can bank on shell completions to fill in your branch whilst using <code>git checkout</code>. Worktrees have no such conveniences.</p> | 143 | <p>Lastly, you can bank on shell completions to fill in your branch |
144 | whilst using <code>git checkout</code>. Worktrees have no such | ||
145 | conveniences.</p> | ||
109 | <p>We can mend these minor faults with fzf.</p> | 146 | <p>We can mend these minor faults with fzf.</p> |
110 | <h3 id="unclunkifying-worktrees">Unclunkifying worktrees</h3> | 147 | <h3 id="unclunkifying-worktrees">Unclunkifying worktrees</h3> |
111 | <p>I’d suggest looking up <a href="https://github.com/junegunn/fzf">fzf</a> (or <a href="https://github.com/lotabout/skim">skim</a> or <a href="https://github.com/jhawthorn/fzy">fzy</a>). These things make it cake-easy to add interactivity to your shell. Onto fixing the first minor fault, the inability to “jump” to a worktree from anywhere within a git repository.</p> | 148 | <p>I’d suggest looking up <a |
112 | <p>I have a little function called <code>gwj</code> which stands for “git worktree jump”. The idea is to list all the worktrees, select one with fzf, and <code>cd</code> to it upon selection:</p> | 149 | href="https://github.com/junegunn/fzf">fzf</a> (or <a |
113 | <div class="sourceCode" id="cb6"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="fu">gwj ()</span> <span class="kw">{</span></span> | 150 | href="https://github.com/lotabout/skim">skim</a> or <a |
151 | href="https://github.com/jhawthorn/fzy">fzy</a>). These things make it | ||
152 | cake-easy to add interactivity to your shell. Onto fixing the first | ||
153 | minor fault, the inability to “jump” to a worktree from anywhere within | ||
154 | a git repository.</p> | ||
155 | <p>I have a little function called <code>gwj</code> which stands for | ||
156 | “git worktree jump”. The idea is to list all the worktrees, select one | ||
157 | with fzf, and <code>cd</code> to it upon selection:</p> | ||
158 | <div class="sourceCode" id="cb6"><pre | ||
159 | class="sourceCode bash"><code class="sourceCode bash"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="fu">gwj ()</span> <span class="kw">{</span></span> | ||
114 | <span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a> <span class="bu">local</span> <span class="va">out</span></span> | 160 | <span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a> <span class="bu">local</span> <span class="va">out</span></span> |
115 | <span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a> <span class="va">out</span><span class="op">=</span><span class="va">$(</span><span class="fu">git</span> worktree list <span class="kw">|</span> <span class="ex">fzf</span> <span class="kw">|</span> <span class="fu">awk</span> <span class="st">'{print $1}'</span><span class="va">)</span></span> | 161 | <span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a> <span class="va">out</span><span class="op">=</span><span class="va">$(</span><span class="fu">git</span> worktree list <span class="kw">|</span> <span class="ex">fzf</span> <span class="kw">|</span> <span class="fu">awk</span> <span class="st">'{print $1}'</span><span class="va">)</span></span> |
116 | <span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a> <span class="bu">cd</span> <span class="va">$out</span></span> | 162 | <span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a> <span class="bu">cd</span> <span class="va">$out</span></span> |
117 | <span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a><span class="kw">}</span></span></code></pre></div> | 163 | <span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a><span class="kw">}</span></span></code></pre></div> |
118 | <p>That is all of it really. Head into a git repository:</p> | 164 | <p>That is all of it really. Head into a git repository:</p> |
119 | <div class="sourceCode" id="cb7"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="co"># here, "master" is a directory, which contains my main</span></span> | 165 | <div class="sourceCode" id="cb7"><pre |
166 | class="sourceCode bash"><code class="sourceCode bash"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="co"># here, "master" is a directory, which contains my main</span></span> | ||
120 | <span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a><span class="co"># worktree: a checkout of the master branch on rust-lang/rust </span></span> | 167 | <span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a><span class="co"># worktree: a checkout of the master branch on rust-lang/rust </span></span> |
121 | <span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a><span class="ex">λ</span> cd ~/worktrees/rustc/master/library/core/src</span> | 168 | <span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a><span class="ex">λ</span> cd ~/worktrees/rustc/master/library/core/src</span> |
122 | <span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a><span class="ex">λ</span> <span class="co"># hack away</span></span></code></pre></div> | 169 | <span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a><span class="ex">λ</span> <span class="co"># hack away</span></span></code></pre></div> |
123 | <p>Preferably one with a few worktrees:</p> | 170 | <p>Preferably one with a few worktrees:</p> |
124 | <div class="sourceCode" id="cb8"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="ex">λ</span> git worktree list</span> | 171 | <div class="sourceCode" id="cb8"><pre |
125 | <span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a><span class="ex">~/worktrees/rustc/master</span> eac6c33bc63 [master]</span> | 172 | class="sourceCode bash"><code class="sourceCode bash"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="ex">λ</span> git worktree list</span> |
126 | <span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a><span class="ex">~/worktrees/rustc/improve-std-char-docs</span> 94cba88553e [improve-std-char-docs]</span> | 173 | <span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a><span class="ex">~/worktrees/rustc/master</span> eac6c33bc63 <span class="pp">[</span><span class="ss">master</span><span class="pp">]</span></span> |
127 | <span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a><span class="ex">~/worktrees/rustc/is-ascii-octdigit</span> bc57be3af7a [feature/is-ascii-octdigit]</span></code></pre></div> | 174 | <span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a><span class="ex">~/worktrees/rustc/improve-std-char-docs</span> 94cba88553e <span class="pp">[</span><span class="ss">improve</span><span class="pp">-</span><span class="ss">std</span><span class="pp">-</span><span class="ss">char</span><span class="pp">-</span><span class="ss">docs</span><span class="pp">]</span></span> |
128 | <p>And hit <code>gwj</code> (pretend that the pipe, |, is your cursor):</p> | 175 | <span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a><span class="ex">~/worktrees/rustc/is-ascii-octdigit</span> bc57be3af7a <span class="pp">[</span><span class="ss">feature/is</span><span class="pp">-</span><span class="ss">ascii</span><span class="pp">-</span><span class="ss">octdigit</span><span class="pp">]</span></span></code></pre></div> |
129 | <div class="sourceCode" id="cb9"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a><span class="ex">λ</span> gwj</span> | 176 | <p>And hit <code>gwj</code> (pretend that the pipe, |, is your |
177 | cursor):</p> | ||
178 | <div class="sourceCode" id="cb9"><pre | ||
179 | class="sourceCode bash"><code class="sourceCode bash"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a><span class="ex">λ</span> gwj</span> | ||
130 | <span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a><span class="op">></span> <span class="kw">|</span></span> | 180 | <span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a><span class="op">></span> <span class="kw">|</span></span> |
131 | <span id="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a> <span class="ex">4/4</span></span> | 181 | <span id="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a> <span class="ex">4/4</span></span> |
132 | <span id="cb9-4"><a href="#cb9-4" aria-hidden="true" tabindex="-1"></a><span class="op">></span> ~/worktrees/rustc/master <span class="ex">eac6c33bc63</span> [master]</span> | 182 | <span id="cb9-4"><a href="#cb9-4" aria-hidden="true" tabindex="-1"></a><span class="op">></span> ~/worktrees/rustc/master <span class="ex">eac6c33bc63</span> <span class="pp">[</span><span class="ss">master</span><span class="pp">]</span></span> |
133 | <span id="cb9-5"><a href="#cb9-5" aria-hidden="true" tabindex="-1"></a> <span class="ex">~/worktrees/rustc/improve-std-char-docs</span> 94cba88553e [improve-std-char-docs]</span> | 183 | <span id="cb9-5"><a href="#cb9-5" aria-hidden="true" tabindex="-1"></a> <span class="ex">~/worktrees/rustc/improve-std-char-docs</span> 94cba88553e <span class="pp">[</span><span class="ss">improve</span><span class="pp">-</span><span class="ss">std</span><span class="pp">-</span><span class="ss">char</span><span class="pp">-</span><span class="ss">docs</span><span class="pp">]</span></span> |
134 | <span id="cb9-6"><a href="#cb9-6" aria-hidden="true" tabindex="-1"></a> <span class="ex">~/worktrees/rustc/is-ascii-octdigit</span> bc57be3af7a [feature/is-ascii-octdigit]</span></code></pre></div> | 184 | <span id="cb9-6"><a href="#cb9-6" aria-hidden="true" tabindex="-1"></a> <span class="ex">~/worktrees/rustc/is-ascii-octdigit</span> bc57be3af7a <span class="pp">[</span><span class="ss">feature/is</span><span class="pp">-</span><span class="ss">ascii</span><span class="pp">-</span><span class="ss">octdigit</span><span class="pp">]</span></span></code></pre></div> |
135 | <p>Approximately type in your branch of choice:</p> | 185 | <p>Approximately type in your branch of choice:</p> |
136 | <div class="sourceCode" id="cb10"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="ex">λ</span> gwj</span> | 186 | <div class="sourceCode" id="cb10"><pre |
187 | class="sourceCode bash"><code class="sourceCode bash"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="ex">λ</span> gwj</span> | ||
137 | <span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a><span class="op">></span> docs<span class="kw">|</span></span> | 188 | <span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a><span class="op">></span> docs<span class="kw">|</span></span> |
138 | <span id="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a> <span class="ex">4/4</span></span> | 189 | <span id="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a> <span class="ex">4/4</span></span> |
139 | <span id="cb10-4"><a href="#cb10-4" aria-hidden="true" tabindex="-1"></a><span class="op">></span> ~/worktrees/rustc/improve-std-char-docs <span class="ex">94cba88553e</span> [improve-std-char-docs]</span></code></pre></div> | 190 | <span id="cb10-4"><a href="#cb10-4" aria-hidden="true" tabindex="-1"></a><span class="op">></span> ~/worktrees/rustc/improve-std-char-docs <span class="ex">94cba88553e</span> <span class="pp">[</span><span class="ss">improve</span><span class="pp">-</span><span class="ss">std</span><span class="pp">-</span><span class="ss">char</span><span class="pp">-</span><span class="ss">docs</span><span class="pp">]</span></span></code></pre></div> |
140 | <p>And hit enter. You should find yourself in the selected worktree.</p> | 191 | <p>And hit enter. You should find yourself in the selected worktree.</p> |
141 | <p>Onward, to the next fault, lack of preview-bility. We can utilize fzf’s aptly named <code>--preview</code> flag, to, well, preview our worktree before performing a selection:</p> | 192 | <p>Onward, to the next fault, lack of preview-bility. We can utilize |
142 | <div class="sourceCode" id="cb11"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a><span class="fu">gwj ()</span> <span class="kw">{</span></span> | 193 | fzf’s aptly named <code>--preview</code> flag, to, well, preview our |
194 | worktree before performing a selection:</p> | ||
195 | <div class="sourceCode" id="cb11"><pre | ||
196 | class="sourceCode bash"><code class="sourceCode bash"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a><span class="fu">gwj ()</span> <span class="kw">{</span></span> | ||
143 | <span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a> <span class="bu">local</span> <span class="va">out</span></span> | 197 | <span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a> <span class="bu">local</span> <span class="va">out</span></span> |
144 | <span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a> <span class="va">out</span><span class="op">=</span><span class="va">$(</span></span> | 198 | <span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a> <span class="va">out</span><span class="op">=</span><span class="va">$(</span></span> |
145 | <span id="cb11-4"><a href="#cb11-4" aria-hidden="true" tabindex="-1"></a> <span class="fu">git</span> worktree list <span class="kw">|</span></span> | 199 | <span id="cb11-4"><a href="#cb11-4" aria-hidden="true" tabindex="-1"></a> <span class="fu">git</span> worktree list <span class="kw">|</span></span> |
@@ -148,8 +202,10 @@ aa857eb953e Auto merge of #100537 - petrochenkov:pic ... | |||
148 | <span id="cb11-7"><a href="#cb11-7" aria-hidden="true" tabindex="-1"></a> <span class="va">)</span></span> | 202 | <span id="cb11-7"><a href="#cb11-7" aria-hidden="true" tabindex="-1"></a> <span class="va">)</span></span> |
149 | <span id="cb11-8"><a href="#cb11-8" aria-hidden="true" tabindex="-1"></a> <span class="bu">cd</span> <span class="va">$out</span></span> | 203 | <span id="cb11-8"><a href="#cb11-8" aria-hidden="true" tabindex="-1"></a> <span class="bu">cd</span> <span class="va">$out</span></span> |
150 | <span id="cb11-9"><a href="#cb11-9" aria-hidden="true" tabindex="-1"></a><span class="kw">}</span></span></code></pre></div> | 204 | <span id="cb11-9"><a href="#cb11-9" aria-hidden="true" tabindex="-1"></a><span class="kw">}</span></span></code></pre></div> |
151 | <p>Once again, hit <code>gwj</code> inside a git repository with linked worktrees:</p> | 205 | <p>Once again, hit <code>gwj</code> inside a git repository with linked |
152 | <div class="sourceCode" id="cb12"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb12-1"><a href="#cb12-1" aria-hidden="true" tabindex="-1"></a><span class="ex">λ</span> gwj</span> | 206 | worktrees:</p> |
207 | <div class="sourceCode" id="cb12"><pre | ||
208 | class="sourceCode bash"><code class="sourceCode bash"><span id="cb12-1"><a href="#cb12-1" aria-hidden="true" tabindex="-1"></a><span class="ex">λ</span> gwj</span> | ||
153 | <span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a><span class="ex">╭─────────────────────────────────────────────────────────╮</span></span> | 209 | <span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a><span class="ex">╭─────────────────────────────────────────────────────────╮</span></span> |
154 | <span id="cb12-3"><a href="#cb12-3" aria-hidden="true" tabindex="-1"></a><span class="ex">│</span> eac6c33bc63 Auto merge of 100869 nnethercote:replace... │</span> | 210 | <span id="cb12-3"><a href="#cb12-3" aria-hidden="true" tabindex="-1"></a><span class="ex">│</span> eac6c33bc63 Auto merge of 100869 nnethercote:replace... │</span> |
155 | <span id="cb12-4"><a href="#cb12-4" aria-hidden="true" tabindex="-1"></a><span class="ex">│</span> b32223fec10 Auto merge of 100707 dzvon:fix-typo, r=d... │</span> | 211 | <span id="cb12-4"><a href="#cb12-4" aria-hidden="true" tabindex="-1"></a><span class="ex">│</span> b32223fec10 Auto merge of 100707 dzvon:fix-typo, r=d... │</span> |
@@ -167,9 +223,16 @@ aa857eb953e Auto merge of #100537 - petrochenkov:pic ... | |||
167 | <span id="cb12-16"><a href="#cb12-16" aria-hidden="true" tabindex="-1"></a><span class="op">></span> /home/np/worktrees/compiler/master <span class="ex">eac6c...</span></span> | 223 | <span id="cb12-16"><a href="#cb12-16" aria-hidden="true" tabindex="-1"></a><span class="op">></span> /home/np/worktrees/compiler/master <span class="ex">eac6c...</span></span> |
168 | <span id="cb12-17"><a href="#cb12-17" aria-hidden="true" tabindex="-1"></a> <span class="ex">/home/np/worktrees/compiler/improve-std-char-docs</span> 94cba...</span> | 224 | <span id="cb12-17"><a href="#cb12-17" aria-hidden="true" tabindex="-1"></a> <span class="ex">/home/np/worktrees/compiler/improve-std-char-docs</span> 94cba...</span> |
169 | <span id="cb12-18"><a href="#cb12-18" aria-hidden="true" tabindex="-1"></a> <span class="ex">/home/np/worktrees/compiler/is-ascii-octdigit</span> bc57b...</span></code></pre></div> | 225 | <span id="cb12-18"><a href="#cb12-18" aria-hidden="true" tabindex="-1"></a> <span class="ex">/home/np/worktrees/compiler/is-ascii-octdigit</span> bc57b...</span></code></pre></div> |
170 | <p>A fancy preview of the last 10 commits on the branch that the selected worktree corresponds to. In other words, sight for sore eyes. Our little script is already shaping up to be useful, you hit <code>gwj</code>, browse through your worktrees, preview each one and automatically <code>cd</code> to your selection. But we are not done yet.</p> | 226 | <p>A fancy preview of the last 10 commits on the branch that the |
171 | <p>The last fault was lack shell completions. A quick review of what a shell completion really does:</p> | 227 | selected worktree corresponds to. In other words, sight for sore eyes. |
172 | <div class="sourceCode" id="cb13"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true" tabindex="-1"></a><span class="ex">λ</span> git checkout f<span class="op"><</span>tab<span class="op">></span></span> | 228 | Our little script is already shaping up to be useful, you hit |
229 | <code>gwj</code>, browse through your worktrees, preview each one and | ||
230 | automatically <code>cd</code> to your selection. But we are not done | ||
231 | yet.</p> | ||
232 | <p>The last fault was lack shell completions. A quick review of what a | ||
233 | shell completion really does:</p> | ||
234 | <div class="sourceCode" id="cb13"><pre | ||
235 | class="sourceCode bash"><code class="sourceCode bash"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true" tabindex="-1"></a><span class="ex">λ</span> git checkout f<span class="op"><</span>tab<span class="op">></span></span> | ||
173 | <span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a><span class="ex">feature/is-ascii-octdigit</span></span> | 236 | <span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a><span class="ex">feature/is-ascii-octdigit</span></span> |
174 | <span id="cb13-3"><a href="#cb13-3" aria-hidden="true" tabindex="-1"></a><span class="ex">fix/some-error</span></span> | 237 | <span id="cb13-3"><a href="#cb13-3" aria-hidden="true" tabindex="-1"></a><span class="ex">fix/some-error</span></span> |
175 | <span id="cb13-4"><a href="#cb13-4" aria-hidden="true" tabindex="-1"></a><span class="ex">format-doc-tests</span></span> | 238 | <span id="cb13-4"><a href="#cb13-4" aria-hidden="true" tabindex="-1"></a><span class="ex">format-doc-tests</span></span> |
@@ -177,16 +240,22 @@ aa857eb953e Auto merge of #100537 - petrochenkov:pic ... | |||
177 | <span id="cb13-6"><a href="#cb13-6" aria-hidden="true" tabindex="-1"></a><span class="ex">λ</span> git checkout feat<span class="op"><</span>tab<span class="op">></span></span> | 240 | <span id="cb13-6"><a href="#cb13-6" aria-hidden="true" tabindex="-1"></a><span class="ex">λ</span> git checkout feat<span class="op"><</span>tab<span class="op">></span></span> |
178 | <span id="cb13-7"><a href="#cb13-7" aria-hidden="true" tabindex="-1"></a></span> | 241 | <span id="cb13-7"><a href="#cb13-7" aria-hidden="true" tabindex="-1"></a></span> |
179 | <span id="cb13-8"><a href="#cb13-8" aria-hidden="true" tabindex="-1"></a><span class="ex">λ</span> git checkout feature/is-ascii-octdigit</span></code></pre></div> | 242 | <span id="cb13-8"><a href="#cb13-8" aria-hidden="true" tabindex="-1"></a><span class="ex">λ</span> git checkout feature/is-ascii-octdigit</span></code></pre></div> |
180 | <p>Each time you hit “tab”, the shell produces a few “completion candidates”, and once you have just a single candidate left, the shell inserts that for you directly into your edit line. Of course, this process varies from shell to shell.</p> | 243 | <p>Each time you hit “tab”, the shell produces a few “completion |
181 | <p>fzf narrows down your options as you type into the prompt, but you still have to:</p> | 244 | candidates”, and once you have just a single candidate left, the shell |
245 | inserts that for you directly into your edit line. Of course, this | ||
246 | process varies from shell to shell.</p> | ||
247 | <p>fzf narrows down your options as you type into the prompt, but you | ||
248 | still have to:</p> | ||
182 | <ol type="1"> | 249 | <ol type="1"> |
183 | <li>Type <code>gwj</code></li> | 250 | <li>Type <code>gwj</code></li> |
184 | <li>Hit enter</li> | 251 | <li>Hit enter</li> |
185 | <li>Type out a query and narrow down your search</li> | 252 | <li>Type out a query and narrow down your search</li> |
186 | <li>Hit enter</li> | 253 | <li>Hit enter</li> |
187 | </ol> | 254 | </ol> |
188 | <p>We can speed that up a bit, have fzf narrow down the candidates on startup, just like our shell does:</p> | 255 | <p>We can speed that up a bit, have fzf narrow down the candidates on |
189 | <div class="sourceCode" id="cb14"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb14-1"><a href="#cb14-1" aria-hidden="true" tabindex="-1"></a><span class="fu">gwj ()</span> <span class="kw">{</span></span> | 256 | startup, just like our shell does:</p> |
257 | <div class="sourceCode" id="cb14"><pre | ||
258 | class="sourceCode bash"><code class="sourceCode bash"><span id="cb14-1"><a href="#cb14-1" aria-hidden="true" tabindex="-1"></a><span class="fu">gwj ()</span> <span class="kw">{</span></span> | ||
190 | <span id="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a> <span class="bu">local</span> <span class="va">out</span> <span class="va">query</span></span> | 259 | <span id="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a> <span class="bu">local</span> <span class="va">out</span> <span class="va">query</span></span> |
191 | <span id="cb14-3"><a href="#cb14-3" aria-hidden="true" tabindex="-1"></a> <span class="va">query</span><span class="op">=</span><span class="st">"</span><span class="va">${1</span><span class="op">:-</span> <span class="va">}</span><span class="st">"</span></span> | 260 | <span id="cb14-3"><a href="#cb14-3" aria-hidden="true" tabindex="-1"></a> <span class="va">query</span><span class="op">=</span><span class="st">"</span><span class="va">${1</span><span class="op">:-</span> <span class="va">}</span><span class="st">"</span></span> |
192 | <span id="cb14-4"><a href="#cb14-4" aria-hidden="true" tabindex="-1"></a> <span class="va">out</span><span class="op">=</span><span class="va">$(</span></span> | 261 | <span id="cb14-4"><a href="#cb14-4" aria-hidden="true" tabindex="-1"></a> <span class="va">out</span><span class="op">=</span><span class="va">$(</span></span> |
@@ -196,8 +265,12 @@ aa857eb953e Auto merge of #100537 - petrochenkov:pic ... | |||
196 | <span id="cb14-8"><a href="#cb14-8" aria-hidden="true" tabindex="-1"></a> <span class="va">)</span></span> | 265 | <span id="cb14-8"><a href="#cb14-8" aria-hidden="true" tabindex="-1"></a> <span class="va">)</span></span> |
197 | <span id="cb14-9"><a href="#cb14-9" aria-hidden="true" tabindex="-1"></a> <span class="bu">cd</span> <span class="va">$out</span></span> | 266 | <span id="cb14-9"><a href="#cb14-9" aria-hidden="true" tabindex="-1"></a> <span class="bu">cd</span> <span class="va">$out</span></span> |
198 | <span id="cb14-10"><a href="#cb14-10" aria-hidden="true" tabindex="-1"></a><span class="kw">}</span></span></code></pre></div> | 267 | <span id="cb14-10"><a href="#cb14-10" aria-hidden="true" tabindex="-1"></a><span class="kw">}</span></span></code></pre></div> |
199 | <p>The change is extremely tiny, blink-and-you’ll-miss-it kinda tiny. We added a little <code>--query</code> flag, that allows you to prefill the prompt, and the <code>-1</code> flag, that avoids the interactive finder if only one match exists on startup:</p> | 268 | <p>The change is extremely tiny, blink-and-you’ll-miss-it kinda tiny. We |
200 | <div class="sourceCode" id="cb15"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb15-1"><a href="#cb15-1" aria-hidden="true" tabindex="-1"></a><span class="co"># skip through the fzf prompt:</span></span> | 269 | added a little <code>--query</code> flag, that allows you to prefill the |
270 | prompt, and the <code>-1</code> flag, that avoids the interactive finder | ||
271 | if only one match exists on startup:</p> | ||
272 | <div class="sourceCode" id="cb15"><pre | ||
273 | class="sourceCode bash"><code class="sourceCode bash"><span id="cb15-1"><a href="#cb15-1" aria-hidden="true" tabindex="-1"></a><span class="co"># skip through the fzf prompt:</span></span> | ||
201 | <span id="cb15-2"><a href="#cb15-2" aria-hidden="true" tabindex="-1"></a><span class="ex">λ</span> gwj master</span> | 274 | <span id="cb15-2"><a href="#cb15-2" aria-hidden="true" tabindex="-1"></a><span class="ex">λ</span> gwj master</span> |
202 | <span id="cb15-3"><a href="#cb15-3" aria-hidden="true" tabindex="-1"></a><span class="co"># cd -- ~/worktrees/rustc/master</span></span> | 275 | <span id="cb15-3"><a href="#cb15-3" aria-hidden="true" tabindex="-1"></a><span class="co"># cd -- ~/worktrees/rustc/master</span></span> |
203 | <span id="cb15-4"><a href="#cb15-4" aria-hidden="true" tabindex="-1"></a></span> | 276 | <span id="cb15-4"><a href="#cb15-4" aria-hidden="true" tabindex="-1"></a></span> |
@@ -212,8 +285,11 @@ aa857eb953e Auto merge of #100537 - petrochenkov:pic ... | |||
212 | <span id="cb15-13"><a href="#cb15-13" aria-hidden="true" tabindex="-1"></a> <span class="ex">2/2</span></span> | 285 | <span id="cb15-13"><a href="#cb15-13" aria-hidden="true" tabindex="-1"></a> <span class="ex">2/2</span></span> |
213 | <span id="cb15-14"><a href="#cb15-14" aria-hidden="true" tabindex="-1"></a><span class="op">></span> /home/np/worktrees/compiler/improve-const-perf <span class="ex">eac6c...</span></span> | 286 | <span id="cb15-14"><a href="#cb15-14" aria-hidden="true" tabindex="-1"></a><span class="op">></span> /home/np/worktrees/compiler/improve-const-perf <span class="ex">eac6c...</span></span> |
214 | <span id="cb15-15"><a href="#cb15-15" aria-hidden="true" tabindex="-1"></a> <span class="ex">/home/np/worktrees/compiler/improve-std-char-docs</span> 94cba...</span></code></pre></div> | 287 | <span id="cb15-15"><a href="#cb15-15" aria-hidden="true" tabindex="-1"></a> <span class="ex">/home/np/worktrees/compiler/improve-std-char-docs</span> 94cba...</span></code></pre></div> |
215 | <p>Throw some error handling in there, hook up a similar script to improve the UX of <code>git worktree remove</code>, go wild. A few more helpers I’ve got:</p> | 288 | <p>Throw some error handling in there, hook up a similar script to |
216 | <div class="sourceCode" id="cb16"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb16-1"><a href="#cb16-1" aria-hidden="true" tabindex="-1"></a><span class="co"># gwa /path/to/branch-name</span></span> | 289 | improve the UX of <code>git worktree remove</code>, go wild. A few more |
290 | helpers I’ve got:</p> | ||
291 | <div class="sourceCode" id="cb16"><pre | ||
292 | class="sourceCode bash"><code class="sourceCode bash"><span id="cb16-1"><a href="#cb16-1" aria-hidden="true" tabindex="-1"></a><span class="co"># gwa /path/to/branch-name</span></span> | ||
217 | <span id="cb16-2"><a href="#cb16-2" aria-hidden="true" tabindex="-1"></a><span class="co"># creates a new branch and "switches" to it</span></span> | 293 | <span id="cb16-2"><a href="#cb16-2" aria-hidden="true" tabindex="-1"></a><span class="co"># creates a new branch and "switches" to it</span></span> |
218 | <span id="cb16-3"><a href="#cb16-3" aria-hidden="true" tabindex="-1"></a><span class="kw">function</span><span class="fu"> gwa ()</span> <span class="kw">{</span></span> | 294 | <span id="cb16-3"><a href="#cb16-3" aria-hidden="true" tabindex="-1"></a><span class="kw">function</span><span class="fu"> gwa ()</span> <span class="kw">{</span></span> |
219 | <span id="cb16-4"><a href="#cb16-4" aria-hidden="true" tabindex="-1"></a> <span class="fu">git</span> worktree add <span class="st">"</span><span class="va">$1</span><span class="st">"</span> <span class="kw">&&</span> <span class="bu">cd</span> <span class="st">"</span><span class="va">$1</span><span class="st">"</span></span> | 295 | <span id="cb16-4"><a href="#cb16-4" aria-hidden="true" tabindex="-1"></a> <span class="fu">git</span> worktree add <span class="st">"</span><span class="va">$1</span><span class="st">"</span> <span class="kw">&&</span> <span class="bu">cd</span> <span class="st">"</span><span class="va">$1</span><span class="st">"</span></span> |
diff --git a/docs/posts/font_size_fallacies/index.html b/docs/posts/font_size_fallacies/index.html index 9577376..51f5b4b 100644 --- a/docs/posts/font_size_fallacies/index.html +++ b/docs/posts/font_size_fallacies/index.html | |||
@@ -28,12 +28,12 @@ | |||
28 | 17/03 — 2020 | 28 | 17/03 — 2020 |
29 | <div class="stats"> | 29 | <div class="stats"> |
30 | <span class="stats-number"> | 30 | <span class="stats-number"> |
31 | 32.36 | 31 | 32.37 |
32 | </span> | 32 | </span> |
33 | <span class="stats-unit">cm</span> | 33 | <span class="stats-unit">cm</span> |
34 |   | 34 |   |
35 | <span class="stats-number"> | 35 | <span class="stats-number"> |
36 | 3.2 | 36 | 3.3 |
37 | </span> | 37 | </span> |
38 | <span class="stats-unit">min</span> | 38 | <span class="stats-unit">min</span> |
39 | </div> | 39 | </div> |
@@ -42,34 +42,75 @@ | |||
42 | Font Size Fallacies | 42 | Font Size Fallacies |
43 | </h1> | 43 | </h1> |
44 | <div class="post-text"> | 44 | <div class="post-text"> |
45 | <p>I am not an expert with fonts, but I do have some experience <a href="#fn1" class="footnote-ref" id="fnref1" role="doc-noteref"><sup>1</sup></a>, and common sense. This post aims to debunk some misconceptions about font sizes!</p> | 45 | <p>I am not an expert with fonts, but I do have some experience <a |
46 | <p>11 px on your display is <em>probably not</em> 11 px on my display. Let’s do some quick math. I have two displays, 1366x768 @ 21" and another with 1920x1080 @ 13", call them <code>A</code> and <code>B</code> for now.</p> | 46 | href="#fn1" class="footnote-ref" id="fnref1" |
47 | <p>Display <code>A</code> has 1,049,088 pixels. A pixel is a square, of side say, <code>s</code> cm. The total area covered by my 21" display is about 1,066 cm^2 (41x26). Thus,</p> | 47 | role="doc-noteref"><sup>1</sup></a>, and common sense. This post aims to |
48 | debunk some misconceptions about font sizes!</p> | ||
49 | <p>11 px on your display is <em>probably not</em> 11 px on my display. | ||
50 | Let’s do some quick math. I have two displays, 1366x768 @ 21” and | ||
51 | another with 1920x1080 @ 13”, call them <code>A</code> and | ||
52 | <code>B</code> for now.</p> | ||
53 | <p>Display <code>A</code> has 1,049,088 pixels. A pixel is a square, of | ||
54 | side say, <code>s</code> cm. The total area covered by my 21” display is | ||
55 | about 1,066 cm^2 (41x26). Thus,</p> | ||
48 | <pre><code>Display A | 56 | <pre><code>Display A |
49 | Dimensions: 1366x768 @ 21" (41x26 sq. cm) | 57 | Dimensions: 1366x768 @ 21" (41x26 sq. cm) |
50 | 1,049,088 s^2 = 1066 | 58 | 1,049,088 s^2 = 1066 |
51 | s = 0.0318 cm (side of a pixel on Display A)</code></pre> | 59 | s = 0.0318 cm (side of a pixel on Display A)</code></pre> |
52 | <p>Bear with me, as I repeat the number crunching for Display <code>B</code>:</p> | 60 | <p>Bear with me, as I repeat the number crunching for Display |
61 | <code>B</code>:</p> | ||
53 | <pre><code>Display B | 62 | <pre><code>Display B |
54 | Dimensions: 1920x1080 @ 13" (29.5x16.5 sq. cm) | 63 | Dimensions: 1920x1080 @ 13" (29.5x16.5 sq. cm) |
55 | 2,073,600 s^2 = 486.75 | 64 | 2,073,600 s^2 = 486.75 |
56 | s = 0.0153 cm (side of a pixel on Display B)</code></pre> | 65 | s = 0.0153 cm (side of a pixel on Display B)</code></pre> |
57 | <p>The width of a pixel on Display <code>A</code> is <em>double</em> the width of a pixel on Display <code>B</code>. The area occupied by a pixel on Display <code>A</code> is <em>4 times</em> the area occupied by a pixel on Display <code>B</code>.</p> | 66 | <p>The width of a pixel on Display <code>A</code> is <em>double</em> the |
67 | width of a pixel on Display <code>B</code>. The area occupied by a pixel | ||
68 | on Display <code>A</code> is <em>4 times</em> the area occupied by a | ||
69 | pixel on Display <code>B</code>.</p> | ||
58 | <p><em>The size of a pixel varies from display to display!</em></p> | 70 | <p><em>The size of a pixel varies from display to display!</em></p> |
59 | <p>A 5x11 bitmap font on Display <code>A</code> would be around 4 mm tall whereas the same bitmap font on Display <code>B</code> would be around 1.9 mm tall. A 11 px tall character on <code>B</code> is visually equivalent to a 5 px character on <code>A</code>. When you view a screenshot of Display <code>A</code> on Display <code>B</code>, the contents are shrunk down by a factor of 2!</p> | 71 | <p>A 5x11 bitmap font on Display <code>A</code> would be around 4 mm |
60 | <p>So screen resolution is not enough, how else do we measure size? Pixel Density! Keen readers will realize that the 5^th grade math problem we solved up there showcases pixel density, or, pixels per cm (PPCM). Usually we deal with pixels per inch (PPI).</p> | 72 | tall whereas the same bitmap font on Display <code>B</code> would be |
61 | <p><strong>Note:</strong> PPI is not to be confused with DPI <a href="#fn2" class="footnote-ref" id="fnref2" role="doc-noteref"><sup>2</sup></a> (dots per inch). DPI is defined for printers.</p> | 73 | around 1.9 mm tall. A 11 px tall character on <code>B</code> is visually |
62 | <p>In our example, <code>A</code> is a 75 ppi display and <code>B</code> is around 165 ppi <a href="#fn3" class="footnote-ref" id="fnref3" role="doc-noteref"><sup>3</sup></a>. A low ppi display appears to be ‘pixelated’, because the pixels are more prominent, much like Display <code>A</code>. A higher ppi usually means you can view larger images and render crispier fonts. The average desktop display can stuff 100-200 pixels per inch. Smart phones usually fall into the 400-600 ppi (XXXHDPI) category. The human eye fails to differentiate detail past 300 ppi.</p> | 74 | equivalent to a 5 px character on <code>A</code>. When you view a |
63 | <p><em>So … streaming an 8K video on a 60" TV provides the same clarity as a HD video on a smart phone?</em></p> | 75 | screenshot of Display <code>A</code> on Display <code>B</code>, the |
64 | <p>Absolutely. Well, clarity is subjective, but the amount of detail you can discern on mobile displays has always been limited. Salty consumers of the Xperia 1 <a href="#fn4" class="footnote-ref" id="fnref4" role="doc-noteref"><sup>4</sup></a> will say otherwise.</p> | 76 | contents are shrunk down by a factor of 2!</p> |
65 | <p>Maybe I will talk about font rendering in another post, but thats all for now. Don’t judge a font size by its screenshot.</p> | 77 | <p>So screen resolution is not enough, how else do we measure size? |
66 | <section class="footnotes" role="doc-endnotes"> | 78 | Pixel Density! Keen readers will realize that the 5^th grade math |
79 | problem we solved up there showcases pixel density, or, pixels per cm | ||
80 | (PPCM). Usually we deal with pixels per inch (PPI).</p> | ||
81 | <p><strong>Note:</strong> PPI is not to be confused with DPI <a | ||
82 | href="#fn2" class="footnote-ref" id="fnref2" | ||
83 | role="doc-noteref"><sup>2</sup></a> (dots per inch). DPI is defined for | ||
84 | printers.</p> | ||
85 | <p>In our example, <code>A</code> is a 75 ppi display and <code>B</code> | ||
86 | is around 165 ppi <a href="#fn3" class="footnote-ref" id="fnref3" | ||
87 | role="doc-noteref"><sup>3</sup></a>. A low ppi display appears to be | ||
88 | ‘pixelated’, because the pixels are more prominent, much like Display | ||
89 | <code>A</code>. A higher ppi usually means you can view larger images | ||
90 | and render crispier fonts. The average desktop display can stuff 100-200 | ||
91 | pixels per inch. Smart phones usually fall into the 400-600 ppi | ||
92 | (XXXHDPI) category. The human eye fails to differentiate detail past 300 | ||
93 | ppi.</p> | ||
94 | <p><em>So … streaming an 8K video on a 60” TV provides the same clarity | ||
95 | as a HD video on a smart phone?</em></p> | ||
96 | <p>Absolutely. Well, clarity is subjective, but the amount of detail you | ||
97 | can discern on mobile displays has always been limited. Salty consumers | ||
98 | of the Xperia 1 <a href="#fn4" class="footnote-ref" id="fnref4" | ||
99 | role="doc-noteref"><sup>4</sup></a> will say otherwise.</p> | ||
100 | <p>Maybe I will talk about font rendering in another post, but thats all | ||
101 | for now. Don’t judge a font size by its screenshot.</p> | ||
102 | <section id="footnotes" class="footnotes footnotes-end-of-document" | ||
103 | role="doc-endnotes"> | ||
67 | <hr /> | 104 | <hr /> |
68 | <ol> | 105 | <ol> |
69 | <li id="fn1" role="doc-endnote"><p>https://github.com/nerdypepper/scientifica<a href="#fnref1" class="footnote-back" role="doc-backlink">↩︎</a></p></li> | 106 | <li id="fn1"><p>https://github.com/nerdypepper/scientifica<a |
70 | <li id="fn2" role="doc-endnote"><p>https://en.wikipedia.org/wiki/Dots_per_inch<a href="#fnref2" class="footnote-back" role="doc-backlink">↩︎</a></p></li> | 107 | href="#fnref1" class="footnote-back" role="doc-backlink">↩︎</a></p></li> |
71 | <li id="fn3" role="doc-endnote"><p>https://www.sven.de/dpi/<a href="#fnref3" class="footnote-back" role="doc-backlink">↩︎</a></p></li> | 108 | <li id="fn2"><p>https://en.wikipedia.org/wiki/Dots_per_inch<a |
72 | <li id="fn4" role="doc-endnote"><p>https://en.wikipedia.org/wiki/Sony_Xperia_1<a href="#fnref4" class="footnote-back" role="doc-backlink">↩︎</a></p></li> | 109 | href="#fnref2" class="footnote-back" role="doc-backlink">↩︎</a></p></li> |
110 | <li id="fn3"><p>https://www.sven.de/dpi/<a href="#fnref3" | ||
111 | class="footnote-back" role="doc-backlink">↩︎</a></p></li> | ||
112 | <li id="fn4"><p>https://en.wikipedia.org/wiki/Sony_Xperia_1<a | ||
113 | href="#fnref4" class="footnote-back" role="doc-backlink">↩︎</a></p></li> | ||
73 | </ol> | 114 | </ol> |
74 | </section> | 115 | </section> |
75 | 116 | ||
diff --git a/docs/posts/get_better_at_yanking_and_putting_in_vim/index.html b/docs/posts/get_better_at_yanking_and_putting_in_vim/index.html index 469afe5..c6d3368 100644 --- a/docs/posts/get_better_at_yanking_and_putting_in_vim/index.html +++ b/docs/posts/get_better_at_yanking_and_putting_in_vim/index.html | |||
@@ -28,7 +28,7 @@ | |||
28 | 30/07 — 2019 | 28 | 30/07 — 2019 |
29 | <div class="stats"> | 29 | <div class="stats"> |
30 | <span class="stats-number"> | 30 | <span class="stats-number"> |
31 | 10.78 | 31 | 10.79 |
32 | </span> | 32 | </span> |
33 | <span class="stats-unit">cm</span> | 33 | <span class="stats-unit">cm</span> |
34 |   | 34 |   |
@@ -44,7 +44,8 @@ | |||
44 | <div class="post-text"> | 44 | <div class="post-text"> |
45 | <p>a couple of nifty tricks to help you copy-paste better:</p> | 45 | <p>a couple of nifty tricks to help you copy-paste better:</p> |
46 | <ol type="1"> | 46 | <ol type="1"> |
47 | <li><p>reselecting previously selected text (i use this to fix botched selections):</p> | 47 | <li><p>reselecting previously selected text (i use this to fix botched |
48 | selections):</p> | ||
48 | <pre><code>gv " :h gv for more | 49 | <pre><code>gv " :h gv for more |
49 | " you can use `o` in visual mode to go to the `Other` end of the selection | 50 | " you can use `o` in visual mode to go to the `Other` end of the selection |
50 | " use a motion to fix the selection</code></pre></li> | 51 | " use a motion to fix the selection</code></pre></li> |
diff --git a/docs/posts/gripes_with_go/index.html b/docs/posts/gripes_with_go/index.html index 1551fe6..74d6995 100644 --- a/docs/posts/gripes_with_go/index.html +++ b/docs/posts/gripes_with_go/index.html | |||
@@ -28,7 +28,7 @@ | |||
28 | 01/08 — 2020 | 28 | 01/08 — 2020 |
29 | <div class="stats"> | 29 | <div class="stats"> |
30 | <span class="stats-number"> | 30 | <span class="stats-number"> |
31 | 76.71 | 31 | 76.72 |
32 | </span> | 32 | </span> |
33 | <span class="stats-unit">cm</span> | 33 | <span class="stats-unit">cm</span> |
34 |   | 34 |   |
@@ -42,17 +42,24 @@ | |||
42 | Gripes With Go | 42 | Gripes With Go |
43 | </h1> | 43 | </h1> |
44 | <div class="post-text"> | 44 | <div class="post-text"> |
45 | <p>You’ve read a lot of posts about the shortcomings of the Go programming language, so what’s one more.</p> | 45 | <p>You’ve read a lot of posts about the shortcomings of the Go |
46 | programming language, so what’s one more.</p> | ||
46 | <ol type="1"> | 47 | <ol type="1"> |
47 | <li><a href="#lack-of-sum-types">Lack of sum types</a></li> | 48 | <li><a href="#lack-of-sum-types">Lack of sum types</a></li> |
48 | <li><a href="#type-assertions">Type assertions</a></li> | 49 | <li><a href="#type-assertions">Type assertions</a></li> |
49 | <li><a href="#date-and-time">Date and Time</a></li> | 50 | <li><a href="#date-and-time">Date and Time</a></li> |
50 | <li><a href="#statements-over-expressions">Statements over Expressions</a></li> | 51 | <li><a href="#statements-over-expressions">Statements over |
51 | <li><a href="#erroring-out-on-unused-variables">Erroring out on unused variables</a></li> | 52 | Expressions</a></li> |
53 | <li><a href="#erroring-out-on-unused-variables">Erroring out on unused | ||
54 | variables</a></li> | ||
52 | <li><a href="#error-handling">Error handling</a></li> | 55 | <li><a href="#error-handling">Error handling</a></li> |
53 | </ol> | 56 | </ol> |
54 | <h3 id="lack-of-sum-types">Lack of Sum types</h3> | 57 | <h3 id="lack-of-sum-types">Lack of Sum types</h3> |
55 | <p>A “Sum” type is a data type that can hold one of many states at a given time, similar to how a boolean can hold a true or a false, not too different from an <code>enum</code> type in C. Go lacks <code>enum</code> types unfortunately, and you are forced to resort to crafting your own substitute.</p> | 58 | <p>A “Sum” type is a data type that can hold one of many states at a |
59 | given time, similar to how a boolean can hold a true or a false, not too | ||
60 | different from an <code>enum</code> type in C. Go lacks | ||
61 | <code>enum</code> types unfortunately, and you are forced to resort to | ||
62 | crafting your own substitute.</p> | ||
56 | <p>A type to represent gender for example:</p> | 63 | <p>A type to represent gender for example:</p> |
57 | <div class="sourceCode" id="cb1"><pre class="sourceCode go"><code class="sourceCode go"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> Gender <span class="dt">int</span></span> | 64 | <div class="sourceCode" id="cb1"><pre class="sourceCode go"><code class="sourceCode go"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> Gender <span class="dt">int</span></span> |
58 | <span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a></span> | 65 | <span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a></span> |
@@ -67,17 +74,18 @@ | |||
67 | <span id="cb1-11"><a href="#cb1-11" aria-hidden="true" tabindex="-1"></a><span class="co">// Oops! We have to implement String() for Gender ...</span></span> | 74 | <span id="cb1-11"><a href="#cb1-11" aria-hidden="true" tabindex="-1"></a><span class="co">// Oops! We have to implement String() for Gender ...</span></span> |
68 | <span id="cb1-12"><a href="#cb1-12" aria-hidden="true" tabindex="-1"></a></span> | 75 | <span id="cb1-12"><a href="#cb1-12" aria-hidden="true" tabindex="-1"></a></span> |
69 | <span id="cb1-13"><a href="#cb1-13" aria-hidden="true" tabindex="-1"></a><span class="kw">func</span> <span class="op">(</span>g Gender<span class="op">)</span> String<span class="op">()</span> <span class="dt">string</span> <span class="op">{</span></span> | 76 | <span id="cb1-13"><a href="#cb1-13" aria-hidden="true" tabindex="-1"></a><span class="kw">func</span> <span class="op">(</span>g Gender<span class="op">)</span> String<span class="op">()</span> <span class="dt">string</span> <span class="op">{</span></span> |
70 | <span id="cb1-14"><a href="#cb1-14" aria-hidden="true" tabindex="-1"></a> <span class="kw">switch</span> <span class="op">(</span>g<span class="op">)</span> <span class="op">{</span></span> | 77 | <span id="cb1-14"><a href="#cb1-14" aria-hidden="true" tabindex="-1"></a> <span class="cf">switch</span> <span class="op">(</span>g<span class="op">)</span> <span class="op">{</span></span> |
71 | <span id="cb1-15"><a href="#cb1-15" aria-hidden="true" tabindex="-1"></a> <span class="kw">case</span> <span class="dv">0</span><span class="op">:</span> <span class="kw">return</span> <span class="st">"Male"</span></span> | 78 | <span id="cb1-15"><a href="#cb1-15" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> <span class="dv">0</span><span class="op">:</span> <span class="cf">return</span> <span class="st">"Male"</span></span> |
72 | <span id="cb1-16"><a href="#cb1-16" aria-hidden="true" tabindex="-1"></a> <span class="kw">case</span> <span class="dv">1</span><span class="op">:</span> <span class="kw">return</span> <span class="st">"Female"</span></span> | 79 | <span id="cb1-16"><a href="#cb1-16" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> <span class="dv">1</span><span class="op">:</span> <span class="cf">return</span> <span class="st">"Female"</span></span> |
73 | <span id="cb1-17"><a href="#cb1-17" aria-hidden="true" tabindex="-1"></a> <span class="kw">default</span><span class="op">:</span> <span class="kw">return</span> <span class="st">"Other"</span></span> | 80 | <span id="cb1-17"><a href="#cb1-17" aria-hidden="true" tabindex="-1"></a> <span class="cf">default</span><span class="op">:</span> <span class="cf">return</span> <span class="st">"Other"</span></span> |
74 | <span id="cb1-18"><a href="#cb1-18" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span> | 81 | <span id="cb1-18"><a href="#cb1-18" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span> |
75 | <span id="cb1-19"><a href="#cb1-19" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span> | 82 | <span id="cb1-19"><a href="#cb1-19" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span> |
76 | <span id="cb1-20"><a href="#cb1-20" aria-hidden="true" tabindex="-1"></a></span> | 83 | <span id="cb1-20"><a href="#cb1-20" aria-hidden="true" tabindex="-1"></a></span> |
77 | <span id="cb1-21"><a href="#cb1-21" aria-hidden="true" tabindex="-1"></a><span class="co">// You can accidentally do stupid stuff like:</span></span> | 84 | <span id="cb1-21"><a href="#cb1-21" aria-hidden="true" tabindex="-1"></a><span class="co">// You can accidentally do stupid stuff like:</span></span> |
78 | <span id="cb1-22"><a href="#cb1-22" aria-hidden="true" tabindex="-1"></a>gender <span class="op">:=</span> Male <span class="op">+</span> <span class="dv">1</span></span></code></pre></div> | 85 | <span id="cb1-22"><a href="#cb1-22" aria-hidden="true" tabindex="-1"></a>gender <span class="op">:=</span> Male <span class="op">+</span> <span class="dv">1</span></span></code></pre></div> |
79 | <p>The Haskell equivalent of the same:</p> | 86 | <p>The Haskell equivalent of the same:</p> |
80 | <div class="sourceCode" id="cb2"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Gender</span> <span class="ot">=</span> <span class="dt">Male</span></span> | 87 | <div class="sourceCode" id="cb2"><pre |
88 | class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Gender</span> <span class="ot">=</span> <span class="dt">Male</span></span> | ||
81 | <span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span> <span class="dt">Female</span></span> | 89 | <span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span> <span class="dt">Female</span></span> |
82 | <span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span> <span class="dt">Other</span></span> | 90 | <span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span> <span class="dt">Other</span></span> |
83 | <span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a> <span class="kw">deriving</span> (<span class="dt">Show</span>)</span> | 91 | <span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a> <span class="kw">deriving</span> (<span class="dt">Show</span>)</span> |
@@ -88,7 +96,7 @@ | |||
88 | <p>Type assertions in Go allow you to do:</p> | 96 | <p>Type assertions in Go allow you to do:</p> |
89 | <div class="sourceCode" id="cb3"><pre class="sourceCode go"><code class="sourceCode go"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="kw">var</span> x <span class="kw">interface</span><span class="op">{}</span> <span class="op">=</span> <span class="dv">7</span></span> | 97 | <div class="sourceCode" id="cb3"><pre class="sourceCode go"><code class="sourceCode go"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="kw">var</span> x <span class="kw">interface</span><span class="op">{}</span> <span class="op">=</span> <span class="dv">7</span></span> |
90 | <span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a>y<span class="op">,</span> goodToGo <span class="op">:=</span> x<span class="op">.(</span><span class="dt">int</span><span class="op">)</span></span> | 98 | <span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a>y<span class="op">,</span> goodToGo <span class="op">:=</span> x<span class="op">.(</span><span class="dt">int</span><span class="op">)</span></span> |
91 | <span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a><span class="kw">if</span> goodToGo <span class="op">{</span></span> |