-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.xml
338 lines (317 loc) · 36.8 KB
/
index.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>Ephicks's blog</title>
<link>https://fxpineau.github.io/</link>
<description>Recent content on Ephicks's blog</description>
<generator>Hugo -- gohugo.io</generator>
<language>en-us</language>
<copyright>Copyright &copy; 2020 - F.-X. Pineau</copyright>
<lastBuildDate>Wed, 01 Jul 2020 18:00:00 +0200</lastBuildDate>
<atom:link href="https://fxpineau.github.io/index.xml" rel="self" type="application/rss+xml" />
<item>
<title>Making this blog</title>
<link>https://fxpineau.github.io/posts/making_this_blog/</link>
<pubDate>Wed, 01 Jul 2020 18:00:00 +0200</pubDate>
<guid>https://fxpineau.github.io/posts/making_this_blog/</guid>
<description><h2 id="why-a-blog">Why a blog?</h2>
<ul>
<li>Because we understand more deeply something when we have to explain it</li>
<li>To possibly save time to others &ndash; and myslef &ndash; by
<ul>
<li>providing relevant links already found</li>
<li>completing available documentation depending on specific needs</li>
<li>not to have to dig into my source codes to remember how I already solved a problem</li>
</ul>
</li>
<li>To promote the usage of Rust 😆</li>
<li>To share Rust experience with others: so far most of my colleagues do not use Rust 😔</li>
</ul>
<h2 id="framework-and-hosting">Framework and Hosting</h2>
<p>From a quick search, I decided to use</p>
<ul>
<li><a href="https://gohugo.io/">hugo</a>: easy to set up and use, matches my simple needs, and fast
<ul>
<li>alternatives where e.g. <a href="https://jekyllrb.com/">Jekyll</a> and possibly <a href="https://www.gatsbyjs.org/">Gatsby</a></li>
<li>see for example <a href="https://victoria.dev/blog/hugo-vs-jekyll-an-epic-battle-of-static-site-generator-themes/">this comparison</a></li>
</ul>
</li>
<li><a href="https://github.com/">github</a>: because I already have a github account and do no pretend to target a large audience</li>
</ul>
<h2 id="setup">Setup</h2>
<p>I am running an <strong>Ubuntu 18.04.4 LTS</strong> (<code>lsb_release -a</code>) so I am going to use
the <code>snap</code> package manager. On MacOS, you can use <code>brew</code>.</p>
<h3 id="hugo-install">Hugo Install</h3>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash"><span style="color:#75715e"># First install go</span>
sudo snap install go --classic
<span style="color:#75715e"># Then install hugo</span>
sudo snap install hugo --channel<span style="color:#f92672">=</span>extended
</code></pre></div><h3 id="create-blog-site">Create blog site</h3>
<p>I decided to locally name my static website <em>blog</em> and to use the existing <a href="https://themes.gohugo.io/hugo-kiera/">hugo-kiera</a> theme:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash"><span style="color:#75715e"># Create site</span>
hugo new site blog
<span style="color:#75715e"># Install the theme in the newly created site project</span>
cd blog
git init
cd themes
git submodule add https://github.com/funkydan2/hugo-kiera.git
</code></pre></div><p>To later update the theme, simply use:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">cd themes
git submodule update --rebase --remote
</code></pre></div><p>The next step is to edit the <em>config.tom</em> file at the <em>blog</em> root. To help you:</p>
<ul>
<li>see <a href="https://gohugo.io/getting-started/configuration/">the list</a> of general parameters</li>
<li>see also <a href="https://gohugo.io/variables/site/">the list</a> of variables</li>
<li>see the <em>Configuration</em> of the <a href="https://themes.gohugo.io/hugo-kiera/">hugo-keria</a> theme</li>
<li>see the local file <code>themes/hugo-kiera/exampleSite/config.toml</code></li>
</ul>
<p>Here an example of config file used for this blog:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-text" data-lang="text">languageCode = &#34;en-us&#34;
theme = &#34;hugo-kiera&#34;
# Other params
canonifyURLs = true
paginate = 3
# Params given by hugo-keria
summaryLength = 30
enableEmoji = true
pygmentsCodeFences = true
[author]
name = &#34;F.-X. Pineau&#34;
github = &#34;fxpineau&#34;
linkedin = &#34;françois-xavier-pineau-bb31473a&#34;
twitter = &#34;@EphicksP&#34;
[params]
tagline = &#34;Self-reminders, may they also be of use to others&#34;
description = &#34;FX&#39;s blog: Self-reminders, may they also be of use to others.&#34;
customCSS = [] #Optional Customised CSS
disableComments = true
[[menu.main]]
identifier = &#34;tags&#34;
name = &#34;Tags&#34;
url = &#34;/tags&#34;
weight = 1
[[menu.main]]
identifier = &#34;categories&#34;
name = &#34;Categories&#34;
url = &#34;/categories&#34;
weight = 1
</code></pre></div><!-- raw HTML omitted -->
<!-- raw HTML omitted -->
<h2 id="create-a-new-article">Create a new article</h2>
<p>To add a new blog entry:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">hugo new posts/my_new_post.md
</code></pre></div><p>it will create the new markdown file in <code>content/posts</code>.</p>
<p>One can also use static pages like an <em>about</em> page:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">hugo new about.md
</code></pre></div><p>If you are curious, you can learn more on the <em>Hugo</em>
<a href="https://gohugo.io/getting-started/directory-structure/">directory structure</a>.</p>
<h3 id="edit-a-post-and-use-tags-and-categories">Edit a post and use <code>tags</code> and <code>categories</code></h3>
<p>Edit the newly created file:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">vim content/blog/my_new_post.md
</code></pre></div><p>And fill the <code>tag</code> and <code>category</code> header fields. E.g. :</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-txt" data-lang="txt">---
title: &#34;Rusty Cow!&#34;
date: 2020-05-15T18:00:00+02:00
tags: [rust, cow, parsing]
categories: [rust advanced]
---
</code></pre></div><p>See the list of possible <a href="https://www.webfx.com/tools/emoji-cheat-sheet/">emoji</a>
you can use in you markdow sources.</p>
<h2 id="create-a-github-page">Create a github page</h2>
<p>All information are available <a href="https://pages.github.com/">here</a>,
basically you only have to create a new github repository using the special
name <em>username</em>.github.io (of course, you must replace <em>username</em> by your username).</p>
<h2 id="build-and-deploy">Build and deploy</h2>
<h3 id="generate-the-static-files">Generate the static files</h3>
<p>Build and test on localhost (including drafts)</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">hugo server -D
</code></pre></div><p>Build the site (including drafts)</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">hugo -D
</code></pre></div><p>Build (without draft)</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">hugo
</code></pre></div><p>By default the site is created in the <code>public</code> directory, but you can change
this default by setting the a variable in <code>config.toml</code>:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-txt" data-lang="txt">publishDir = &#34;target/blog&#34;
</code></pre></div><h3 id="deploy-and-github-poor-man-approach">Deploy and github (poor man approach).</h3>
<p>First, go into the hugo generated <code>publishDir</code> (<code>public</code> by default)</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">git init
git add -A
git commit -m <span style="color:#e6db74">&#34;Commit of my blog&#34;</span>
git remote add origin https://github.com/username/username.github.io.git
git push -u origin master
</code></pre></div><p>WARNING: doing so, you keep the history of file generated by <em>hugo</em> which is not necessarily useful.
So when generating a new version of your site, you may use</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">git add -A
git commit --amend
git push --force
</code></pre></div><p>A cleaner way is to setup a github action executing hugo on your versioned sources.
To do so, see e.g.:</p>
<ul>
<li><a href="https://github.com/marketplace/actions/hugo-to-gh-pages">hugo action</a></li>
<li>or follow e.g. <a href="https://gohugo.io/hosting-and-deployment/hosting-on-github/#deployment-of-project-pages-from-your-gh-pages-branch">this tuto</a></li>
</ul>
<p>Go check the result on <code>https://username.github.io</code> :)</p>
<h2 id="links">Links</h2>
<ul>
<li>The <a href="https://github.com/avianto/hugo-kiera">hugo-kiera</a> page.</li>
<li>If formula are needed, check <a href="https://sourcethemes.com/academic/">academic</a> and <a href="https://georgecushen.com/create-your-website-with-hugo/">this academic examle</a></li>
<li>An example of hugo-keria blog (using the github <code>docs</code> directory):
<ul>
<li><a href="https://tarquin-the-brave.github.io/blog/">https://tarquin-the-brave.github.io/blog/</a></li>
<li><a href="https://github.com/tarquin-the-brave/blog">https://github.com/tarquin-the-brave/blog</a></li>
<li><a href="https://github.com/tarquin-the-brave/blog/blob/master/config.toml">https://github.com/tarquin-the-brave/blog/blob/master/config.toml</a></li>
</ul>
</li>
</ul>
</description>
</item>
<item>
<title>Rusty Cow!</title>
<link>https://fxpineau.github.io/posts/rusty_cow/</link>
<pubDate>Fri, 15 May 2020 18:00:00 +0200</pubDate>
<guid>https://fxpineau.github.io/posts/rusty_cow/</guid>
<description><p>An example use of the <em>clone-on-write</em> smart pointer in <em>Rust</em>, or <code>Cow</code> for intimates.</p>
<h2 id="problem">Problem</h2>
<p>I want to parse a <em>String</em> that may contain &ndash; in rare cases &ndash; an escaped character.
A typical use case is parsing a double quoted field containing a double quote like</p>
<blockquote>
<p>&ldquo;I want to parse this \&ldquo;kind of\&rdquo; string&rdquo;</p>
</blockquote>
<p>I expect the parser to return the token</p>
<blockquote>
<p>I want to parse this &ldquo;kind of&rdquo; string</p>
</blockquote>
<p>It means that most of the time &ndash; when no character is escaped &ndash; I do not need to edit
the String and returning a <code>&amp;str</code> is fine.<br>
But, sometimes, a string editing is needed and a <code>String</code> (or a <code>Box&lt;str&gt;</code>) has to be returned.</p>
<h2 id="simple-solution">Simple solution</h2>
<p>The problem is easy to solve: <strong>always</strong> make a copy and return a <code>String</code>.
Applying the <a href="https://en.wikipedia.org/wiki/KISS_principle">KISS</a> principle,
only the <em>string-needs-edition</em> case which also fits the trivial
<em>no-edition-needed</em> case has to be coded.</p>
<p>Assuming the starting and ending double quotes have already been parsed and
only the content is given in input of the <code>parse</code> function, we get:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-rust" data-lang="rust"><span style="color:#66d9ef">fn</span> <span style="color:#a6e22e">parse</span>(input: <span style="color:#66d9ef">&amp;</span><span style="color:#66d9ef">str</span>) -&gt; String {
input
.char_indices()
.scan(<span style="color:#66d9ef">false</span>, <span style="color:#f92672">|</span>skip, (_, c)<span style="color:#f92672">|</span> {
Some(<span style="color:#66d9ef">if</span> c <span style="color:#f92672">==</span> <span style="color:#e6db74">&#39;\\&#39;</span> <span style="color:#f92672">&amp;&amp;</span> <span style="color:#f92672">!*</span>skip {
<span style="color:#f92672">*</span>skip <span style="color:#f92672">=</span> <span style="color:#66d9ef">true</span>;
None
} <span style="color:#66d9ef">else</span> {
<span style="color:#f92672">*</span>skip <span style="color:#f92672">=</span> <span style="color:#66d9ef">false</span>;
Some(c)
})
})
.filter_map(<span style="color:#f92672">|</span>c<span style="color:#f92672">|</span> c)
.collect()
}
assert_eq<span style="color:#f92672">!</span>(<span style="color:#f92672">&amp;</span>parse(<span style="color:#e6db74">&#34;My holy cow!&#34;</span>), <span style="color:#e6db74">&#34;My holy cow&#34;</span>);
assert_eq<span style="color:#f92672">!</span>(<span style="color:#f92672">&amp;</span>parse(<span style="color:#e6db74">r#&#34;My \&#34;holy\&#34; cow!&#34;#), r#&#34;My &#34;holy&#34; cow!&#34;</span>);
</code></pre></div><p><a href="https://play.rust-lang.org/?version=stable&amp;mode=debug&amp;edition=2018&amp;code=fn%20parse(input%3A%20%26str)%20-%3E%20String%20%7B%0A%20%20%20%20input%0A%20%20%20%20%20%20%20%20.char_indices()%0A%20%20%20%20%20%20%20%20.scan(false%2C%20%7Cskip%2C%20(_%2C%20c)%7C%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20Some(if%20c%20%3D%3D%20'%5C%5C'%20%26%26%20!*skip%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20*skip%20%3D%20true%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20None%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%20else%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20*skip%20%3D%20false%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Some(c)%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D)%0A%20%20%20%20%20%20%20%20%7D)%0A%20%20%20%20%20%20%20%20.filter_map(%7Cc%7C%20c)%0A%20%20%20%20%20%20%20%20.collect()%0A%7D%0A%0Afn%20parse_v2(input%3A%20%26str)%20-%3E%20String%20%7B%0A%20%20%20%20let%20mut%20res%20%3D%20String%3A%3Awith_capacity(input.len())%3B%0A%20%20%20%20let%20mut%20skip%20%3D%20false%3B%0A%20%20%20%20for%20(_%2C%20c)%20in%20input.char_indices()%20%7B%0A%20%20%20%20%20%20%20%20if%20c%20%3D%3D%20'%5C%5C'%20%26%26%20!skip%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20skip%20%3D%20true%3B%0A%20%20%20%20%20%20%20%20%7D%20else%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20skip%20%3D%20false%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20res.push(c)%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%20%20%20%20res%0A%7D%0A%0Afn%20main()%20%7B%0A%20%20%20%20assert_eq!(%26parse(%22My%20holy%20cow!%22)%2C%20%22My%20holy%20cow%22)%3B%0A%20%20%20%20assert_eq!(%26parse(r%23%22My%20%5C%22holy%5C%22%20cow!%22%23)%2C%20r%23%22My%20%22holy%22%20cow!%22%23)%3B%0A%0A%20%20%20%20assert_eq!(%26parse_v2(%22My%20holy%20cow!%22)%2C%20%22My%20holy%20cow%22)%3B%0A%20%20%20%20assert_eq!(%26parse_v2(r%23%22My%20%5C%22holy%5C%22%20cow!%22%23)%2C%20r%23%22My%20%22holy%22%20cow!%22%23)%3B%0A%7D%0A">See in Rust Playground</a>
with an additional <em>for-loop</em> version.</p>
<!-- raw HTML omitted -->
<p>Remarks: The code is <em>Clippy</em> warning free and formatted using <em>rust-fmt</em> (exception made for the <em>two-spaces</em> indentation instead of <em>tab</em>).</p>
<h2 id="lazy-solution-for-tenacious-peoples-holy-cow">Lazy solution for tenacious peoples: holy <code>Cow</code>!</h2>
<p>Let&rsquo;s drop KISS for the benefit of reasonably optimized code (disclaimer: I am not an expert in optimization).
For performance purposes, we actually want a <em>lazy copy</em> of the string.
I.e., we want to make a copy only if the string has to be modified.
Using an <code>enum</code> is a rather classical use case in such a situation:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-rust" data-lang="rust"><span style="color:#66d9ef">enum</span> <span style="color:#a6e22e">DoubleQuotedContent</span><span style="color:#f92672">&lt;</span><span style="color:#a6e22e">&#39;a</span><span style="color:#f92672">&gt;</span> {
NoEscapedChar(<span style="color:#f92672">&amp;</span><span style="color:#a6e22e">&#39;a</span> <span style="color:#66d9ef">str</span>),
HasEscapedChar(String),
}
<span style="color:#66d9ef">fn</span> <span style="color:#a6e22e">parse</span><span style="color:#f92672">&lt;</span><span style="color:#a6e22e">&#39;a</span><span style="color:#f92672">&gt;</span>(input: <span style="color:#66d9ef">&amp;</span><span style="color:#a6e22e">&#39;a</span> <span style="color:#66d9ef">str</span>) -&gt; <span style="color:#a6e22e">DoubleQuotedContent</span><span style="color:#f92672">&lt;</span><span style="color:#a6e22e">&#39;a</span><span style="color:#f92672">&gt;</span> {
...
}
</code></pre></div><p>But wait, have a look at the <a href="https://doc.rust-lang.org/std/string/struct.String.html">String doc</a>:</p>
<blockquote>
<p>The String type [..] has a close relationship with its borrowed counterpart, the primitive str.</p>
</blockquote>
<p>and, always looking <a href="https://doc.rust-lang.org/std/primitive.str.html#impl-ToOwned">at the doc</a>,
<em>str</em> implements the <a href="https://doc.rust-lang.org/std/borrow/trait.ToOwned.html">ToOwned trait</a>
giving the example of how to get a <code>String</code> from a <code>&amp;str</code> :</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-rust" data-lang="rust"><span style="color:#66d9ef">let</span> s: <span style="color:#66d9ef">&amp;</span><span style="color:#66d9ef">str</span> <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;a&#34;</span>;
<span style="color:#66d9ef">let</span> ss: String <span style="color:#f92672">=</span> s.to_owned();
</code></pre></div><p>Our enum is thus a particular case of &ndash; and can be replaced by &ndash; the more general
<a href="https://doc.rust-lang.org/std/borrow/enum.Cow.html">Cow enum</a>:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-rust" data-lang="rust"><span style="color:#66d9ef">pub</span> <span style="color:#66d9ef">enum</span> <span style="color:#a6e22e">Cow</span><span style="color:#f92672">&lt;</span><span style="color:#a6e22e">&#39;a</span>, B<span style="color:#f92672">&gt;</span>
<span style="color:#66d9ef">where</span>
B: <span style="color:#a6e22e">&#39;a</span> <span style="color:#f92672">+</span> ToOwned <span style="color:#f92672">+</span> <span style="color:#f92672">?</span>Sized,
{
Borrowed(<span style="color:#f92672">&amp;</span><span style="color:#a6e22e">&#39;a</span> B),
Owned(<span style="color:#f92672">&lt;</span>B <span style="color:#66d9ef">as</span> ToOwned<span style="color:#f92672">&gt;</span>::Owned),
}
</code></pre></div><p>We could thus simply declare a new <em>type</em> instead of a new <code>enum</code>:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-rust" data-lang="rust"><span style="color:#66d9ef">type</span> <span style="color:#a6e22e">DoubleQuotedContent</span><span style="color:#f92672">&lt;</span><span style="color:#a6e22e">&#39;a</span><span style="color:#f92672">&gt;</span> <span style="color:#f92672">=</span> std::borrow::Cow<span style="color:#f92672">&lt;</span><span style="color:#a6e22e">&#39;a</span>, <span style="color:#66d9ef">str</span><span style="color:#f92672">&gt;</span>;
</code></pre></div><p>Now, we assume that the first <em>double quote</em> has been parsed and we continue
parsing looking for the second one.<br>
A first pass is performed to check for escaped characters.
A second pass is performed only if edition is needed, which is assumed to be rare.<br>
Although I don&rsquo;t known if it may improve of worsen performances,
I choose here to use three branches instead of two, not to uselessly reassign <em>false</em>
to the <em>skip</em> variable.<br>
Finally a basic error message is returned in case the ending <em>double quote</em> is not found.</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-rust" data-lang="rust"><span style="color:#66d9ef">use</span> std::borrow::Cow;
<span style="color:#66d9ef">type</span> <span style="color:#a6e22e">DoubleQuotedContent</span><span style="color:#f92672">&lt;</span><span style="color:#a6e22e">&#39;a</span><span style="color:#f92672">&gt;</span> <span style="color:#f92672">=</span> std::borrow::Cow<span style="color:#f92672">&lt;</span><span style="color:#a6e22e">&#39;a</span>, <span style="color:#66d9ef">str</span><span style="color:#f92672">&gt;</span>;
<span style="color:#66d9ef">fn</span> <span style="color:#a6e22e">parse</span>(input: <span style="color:#66d9ef">&amp;</span><span style="color:#66d9ef">str</span>) -&gt; Result<span style="color:#f92672">&lt;</span>DoubleQuotedContent<span style="color:#f92672">&lt;</span><span style="color:#a6e22e">&#39;_</span><span style="color:#f92672">&gt;</span>, String<span style="color:#f92672">&gt;</span> {
<span style="color:#66d9ef">let</span> <span style="color:#66d9ef">mut</span> n_escaped <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span>;
<span style="color:#66d9ef">let</span> <span style="color:#66d9ef">mut</span> skip <span style="color:#f92672">=</span> <span style="color:#66d9ef">false</span>;
<span style="color:#66d9ef">let</span> <span style="color:#66d9ef">mut</span> to <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span>;
<span style="color:#66d9ef">for</span> (i, c) <span style="color:#66d9ef">in</span> input.char_indices() {
<span style="color:#66d9ef">if</span> skip {
skip <span style="color:#f92672">=</span> <span style="color:#66d9ef">false</span>;
} <span style="color:#66d9ef">else</span> <span style="color:#66d9ef">if</span> c <span style="color:#f92672">==</span> <span style="color:#e6db74">&#39;\\&#39;</span> {
n_escaped <span style="color:#f92672">+=</span> <span style="color:#ae81ff">1</span>;
skip <span style="color:#f92672">=</span> <span style="color:#66d9ef">true</span>;
} <span style="color:#66d9ef">else</span> <span style="color:#66d9ef">if</span> c <span style="color:#f92672">==</span> <span style="color:#e6db74">&#39;&#34;&#39;</span> {
to <span style="color:#f92672">=</span> i;
<span style="color:#66d9ef">break</span>;
}
}
<span style="color:#66d9ef">if</span> to <span style="color:#f92672">==</span> <span style="color:#ae81ff">0</span> <span style="color:#f92672">&amp;&amp;</span> <span style="color:#f92672">!</span>input.is_empty() <span style="color:#f92672">&amp;&amp;</span> input.as_bytes()[<span style="color:#ae81ff">0</span>] <span style="color:#f92672">==</span> <span style="color:#e6db74">b&#39;&#34;&#39;</span> {
Err(<span style="color:#e6db74">&#34;Closing character &#39;\&#34;&#39; not found&#34;</span>.to_string())
} <span style="color:#66d9ef">else</span> <span style="color:#66d9ef">if</span> n_escaped <span style="color:#f92672">&gt;</span> <span style="color:#ae81ff">0</span> {
Ok(rm_escape_char(<span style="color:#f92672">&amp;</span>input[..to], n_escaped).into())
} <span style="color:#66d9ef">else</span> {
Ok((<span style="color:#f92672">&amp;</span>input[..to]).into())
}
}
<span style="color:#66d9ef">fn</span> <span style="color:#a6e22e">rm_escape_char</span>(input: <span style="color:#66d9ef">&amp;</span><span style="color:#66d9ef">str</span>, n_escaped: <span style="color:#66d9ef">usize</span>) -&gt; String {
<span style="color:#66d9ef">let</span> <span style="color:#66d9ef">mut</span> res <span style="color:#f92672">=</span> String::with_capacity(input.len() <span style="color:#f92672">-</span> n_escaped);
<span style="color:#66d9ef">let</span> <span style="color:#66d9ef">mut</span> skip <span style="color:#f92672">=</span> <span style="color:#66d9ef">false</span>;
<span style="color:#66d9ef">for</span> (_, ch) <span style="color:#66d9ef">in</span> input.char_indices() {
<span style="color:#66d9ef">if</span> skip {
res.push(ch);
skip <span style="color:#f92672">=</span> <span style="color:#66d9ef">false</span>;
} <span style="color:#66d9ef">else</span> <span style="color:#66d9ef">if</span> ch <span style="color:#f92672">==</span> <span style="color:#e6db74">&#39;\\&#39;</span> {
skip <span style="color:#f92672">=</span> <span style="color:#66d9ef">true</span>;
} <span style="color:#66d9ef">else</span> {
res.push(ch);
}
}
res
}
</code></pre></div><p>You can <a href="https://play.rust-lang.org/?version=stable&amp;mode=debug&amp;edition=2018&amp;code=use%20std%3A%3Aborrow%3A%3ACow%3B%0A%0Atype%20DoubleQuotedContent%3C'a%3E%20%3D%20std%3A%3Aborrow%3A%3ACow%3C'a%2C%20str%3E%3B%0A%0Afn%20parse(input%3A%20%26str)%20-%3E%20Result%3CDoubleQuotedContent%3C'_%3E%2C%20String%3E%20%7B%0A%20%20%20%20let%20mut%20n_escaped%20%3D%200%3B%0A%20%20%20%20let%20mut%20skip%20%3D%20false%3B%0A%20%20%20%20let%20mut%20to%20%3D%200%3B%0A%20%20%20%20for%20(i%2C%20c)%20in%20input.char_indices()%20%7B%0A%20%20%20%20%20%20%20%20if%20skip%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20skip%20%3D%20false%3B%0A%20%20%20%20%20%20%20%20%7D%20else%20if%20c%20%3D%3D%20'%5C%5C'%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20n_escaped%20%2B%3D%201%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20skip%20%3D%20true%3B%0A%20%20%20%20%20%20%20%20%7D%20else%20if%20c%20%3D%3D%20'%22'%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20to%20%3D%20i%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20break%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%20%20%20%20if%20to%20%3D%3D%200%20%26%26%20!input.is_empty()%20%26%26%20input.as_bytes()%5B0%5D%20%3D%3D%20b'%22'%20%7B%0A%20%20%20%20%20%20%20%20Err(%22Closing%20character%20'%5C%22'%20not%20found%22.to_string())%0A%20%20%20%20%7D%20else%20if%20n_escaped%20%3E%200%20%7B%0A%20%20%20%20%20%20%20%20Ok(rm_escape_char(%26input%5B..to%5D%2C%20n_escaped).into())%0A%20%20%20%20%7D%20else%20%7B%0A%20%20%20%20%20%20%20%20Ok((%26input%5B..to%5D).into())%0A%20%20%20%20%7D%0A%7D%0A%0Afn%20rm_escape_char(input%3A%20%26str%2C%20n_escaped%3A%20usize)%20-%3E%20String%20%7B%0A%20%20%20%20let%20mut%20res%20%3D%20String%3A%3Awith_capacity(input.len()%20-%20n_escaped)%3B%0A%20%20%20%20let%20mut%20skip%20%3D%20false%3B%0A%20%20%20%20for%20(_%2C%20ch)%20in%20input.char_indices()%20%7B%0A%20%20%20%20%20%20%20%20if%20skip%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20res.push(ch)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20skip%20%3D%20false%3B%0A%20%20%20%20%20%20%20%20%7D%20else%20if%20ch%20%3D%3D%20'%5C%5C'%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20skip%20%3D%20true%3B%0A%20%20%20%20%20%20%20%20%7D%20else%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20res.push(ch)%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%20%20%20%20res%0A%7D%0A%0Afn%20main()%20%7B%0A%20%20%20%20assert_eq!(parse(r%23%22My%20holy%20cow!%22%22%23)%2C%20Ok(Cow%3A%3Afrom(%22My%20holy%20cow!%22)))%3B%0A%20%20%20%20assert_eq!(%0A%20%20%20%20%20%20%20%20parse(r%23%22My%20%5C%22holy%5C%22%20cow!%22%22%23)%2C%0A%20%20%20%20%20%20%20%20Ok(Cow%3A%3Afrom(r%23%22My%20%22holy%22%20cow!%22%23))%0A%20%20%20%20)%3B%0A%7D%0A">test the above code</a> in <a href="https://play.rust-lang.org">Rust Playground</a>.</p>
<h2 id="disclaimer">Disclaimer</h2>
<p>Handling the <em>Cow enum</em> has an arguably small &ndash; but probably not negligible &ndash; cost.
The actual performance difference between the simple and <em>Cow</em> based version
should definitly be measured!</p>
<p>Any feedback welcome:</p>
<ul>
<li>not worth the extra complexity?</li>
<li>performances are improved &ndash; or not &ndash; in benches you performed?</li>
<li>&hellip;</li>
</ul>
<h2 id="bibliographyrelated-links">Bibliography/Related links:</h2>
<ul>
<li>Another <a href="https://jwilm.io/blog/from-str-to-cow/">blog post</a> about <code>Cow</code>.</li>
<li>An in-depth <a href="https://oribenshir.github.io/afternoon_rusting/blog/copy-on-write">blog post</a> about Copy-On-Write in general (including C++)
<ul>
<li>referencing <a href="http://www.gotw.ca/publications/optimizations.htm">this post</a></li>
</ul>
</li>
</ul>
</description>
</item>
</channel>
</rss>