Introduction
Introduction Statistics Contact Development Disclaimer Help
people.gnome.org_federico.atom.xml - sfeed_tests - sfeed tests and RSS and Atom…
git clone git://git.codemadness.org/sfeed_tests
Log
Files
Refs
README
LICENSE
---
people.gnome.org_federico.atom.xml (1402111B)
---
1 <?xml version="1.0" encoding="utf-8"?>
2 <feed xmlns="http://www.w3.org/2005/Atom"><title>Federico's Blog</title>…
3 terms. Technically there are a lot of incomplete moving parts;
4 socially there is a lot of missing documentation to be written, a lot
5 of miscommunication and mismatched expectations.&lt;/p&gt;
6 &lt;p&gt;The following is a brief and incomplete, but hopefully encourag…
7 summary …&lt;/p&gt;</summary><content type="html">&lt;p&gt;"Themes in …
8 terms. Technically there are a lot of incomplete moving parts;
9 socially there is a lot of missing documentation to be written, a lot
10 of miscommunication and mismatched expectations.&lt;/p&gt;
11 &lt;p&gt;The following is a brief and incomplete, but hopefully encourag…
12 summary of the status of themes in GNOME. I want to give you an
13 overall picture of the status of things, and more importantly, an idea
14 of how you can help. This is not a problem that can be solved by a
15 small team of platform developers.&lt;/p&gt;
16 &lt;p&gt;I wish to thank Alexander Mikhaylenko for providing most of the
17 knowledge in this post.&lt;/p&gt;
18 &lt;h1&gt;Frame of reference&lt;/h1&gt;
19 &lt;p&gt;First, I urge you to read Cassidy James Blaede's comprehensiv…
20 Need for a FreeDesktop Dark Style
21 Preference&lt;/a&gt;".
22 That gives an excellent, well-researched introduction to the "dark
23 style" problem, the status quo on other platforms, and exploratory
24 plans for GNOME and Elementary from 2019.&lt;/p&gt;
25 &lt;p&gt;Go ahead, read it. It's very good.&lt;/p&gt;
26 &lt;p&gt;There is also a &lt;a href="https://www.youtube.com/watch?v=gi_…
27 research&lt;/a&gt;
28 if you prefer to watch a video.&lt;/p&gt;
29 &lt;p&gt;Two key take-aways from this: First, about this being a
30 &lt;strong&gt;preference&lt;/strong&gt;, not a system-enforced setting:&…
31 &lt;blockquote&gt;
32 &lt;p&gt;I’m explicitly using the language “Dark Style Preference”…
33 reason! As you’ll read further on, it’s important that this is
34 treated as a user “preference,” not an explicit “mode” or
35 strictly-enforced “setting.” It’s also not a “theme” in the se…
36 that it just swaps out some assets, but is a way for the OS to
37 support a user expressing a preference, and apps to respond to that
38 preference.&lt;/p&gt;
39 &lt;/blockquote&gt;
40 &lt;p&gt;Second, about the &lt;strong&gt;accessibility&lt;/strong&gt; im…
41 &lt;blockquote&gt;
42 &lt;p&gt;Clearly there’s an accessibility and usability angle here. An…
43 with other accessibility efforts, it’s important to not relegate a
44 dark style preference to a buried “Universal Access” or
45 “Accessibility” feature, as that makes it less discoverable, less
46 tested, and less likely to be used by folks who could greatly
47 benefit, but don’t consider themselves “disabled.”&lt;/p&gt;
48 &lt;/blockquote&gt;
49 &lt;h1&gt;Libadwaita and the rest of the ecosystem&lt;/h1&gt;
50 &lt;p&gt;Read the &lt;a href="https://discourse.gnome.org/t/libadwaita-1…
51 roadmap&lt;/a&gt;;
52 it is very short, but links to very interesting issues on gitlab.&lt;/p&…
53 &lt;p&gt;For example, this merge request is for an &lt;a href="https://g…
54 and high-contrast
55 preferences&lt;/a&gt;.
56 It has links to pending work in other parts of the platform: libhandy,
57 gsettings schemas, portals so that containerized applications can
58 query those preferences.&lt;/p&gt;
59 &lt;p&gt;As far as I understand it, applications that just use GTK3 or l…
60 can opt in to supporting the dark style preference — it is opt-in
61 because doing that unconditionally in GTK/libhandy right now would
62 break existing applications.. If your app uses libadwaita, it is
63 assumed that you have opted into supporting that preference, since
64 libadwaita's widgets already make that assumption, and it is not
65 API-stable yet — so it can make that assumption from the beginning.&lt…
66 &lt;p&gt;There is discussion of the accessibility implications in &lt;a …
67 mockups&lt;/a&gt;.&lt;/p&gt;
68 &lt;h1&gt;CSS parity across implementations&lt;/h1&gt;
69 &lt;p&gt;In GNOME we have three implementations of CSS:&lt;/p&gt;
70 &lt;ul&gt;
71 &lt;li&gt;
72 &lt;p&gt;librsvg uses servo's engine for CSS selector matching, and micr…
73 &lt;/li&gt;
74 &lt;li&gt;
75 &lt;p&gt;GTK has its own CSS parser and processor.&lt;/p&gt;
76 &lt;/li&gt;
77 &lt;li&gt;
78 &lt;p&gt;Gnome-shell uses an embedded version of libcroco for parsing, b…
79 does most of the selector matching and cascading with gnome-shell's
80 own Shell Toolkit code.&lt;/p&gt;
81 &lt;/li&gt;
82 &lt;/ul&gt;
83 &lt;p&gt;None of those implementations supports &lt;code&gt;@media&lt;/c…
84 properties with &lt;code&gt;var()&lt;/code&gt;. That is, unlike in the …
85 applications cannot have this in their CSS:&lt;/p&gt;
86 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
87 &lt;span class="c"&gt;/* styles for dark style */&lt;/span&gt;
88 &lt;span class="p"&gt;}&lt;/span&gt;
89
90 &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="k"&gt;media&lt;/span…
91 &lt;span class="c"&gt;/* styles for light style */&lt;/span&gt;
92 &lt;span class="p"&gt;}&lt;/span&gt;
93 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
94
95 &lt;p&gt;Or even declaring colors in a civilized fashion:&lt;/p&gt;
96 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
97 &lt;span class="nv"&gt;--main-bg-color&lt;/span&gt;&lt;span class="p"&…
98 &lt;span class="p"&gt;}&lt;/span&gt;
99
100 &lt;span class="nt"&gt;some_widget&lt;/span&gt; &lt;span class="p"&gt;{&…
101 &lt;span class="k"&gt;background-color&lt;/span&gt;&lt;span class="p"&…
102 &lt;span class="p"&gt;}&lt;/span&gt;
103 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
104
105 &lt;p&gt;Or combining the two:&lt;/p&gt;
106 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
107 &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nd"&gt;root&lt;/sp…
108 &lt;span class="nv"&gt;--main-bg-color&lt;/span&gt;&lt;span class="p…
109 &lt;span class="nv"&gt;--main-fg-color&lt;/span&gt;&lt;span class="p…
110 &lt;span class="p"&gt;}&lt;/span&gt;
111 &lt;span class="p"&gt;}&lt;/span&gt;
112
113 &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="k"&gt;media&lt;/span…
114 &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nd"&gt;root&lt;/sp…
115 &lt;span class="nv"&gt;--main-bg-color&lt;/span&gt;&lt;span class="p…
116 &lt;span class="nv"&gt;--main-fg-color&lt;/span&gt;&lt;span class="p…
117 &lt;span class="p"&gt;}&lt;/span&gt;
118 &lt;span class="p"&gt;}&lt;/span&gt;
119
120 &lt;span class="nt"&gt;some_widget&lt;/span&gt; &lt;span class="p"&gt;{&…
121 &lt;span class="k"&gt;background-color&lt;/span&gt;&lt;span class="p"&…
122 &lt;span class="p"&gt;}&lt;/span&gt;
123 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
124
125 &lt;p&gt;Boom. I think this would remove some workarounds we have right…
126 &lt;ul&gt;
127 &lt;li&gt;
128 &lt;p&gt;Just like GTK, libadwaita generates four variants of the system…
129 stylesheet using scss (regular, dark, high-contrast,
130 high-contrast-dark). This would be obviated with &lt;a href="https://…
131 queries&lt;/a&gt;
132 for &lt;code&gt;prefers-color-scheme&lt;/code&gt;, &lt;code&gt;prefers…
133 in the web platform.&lt;/p&gt;
134 &lt;/li&gt;
135 &lt;li&gt;
136 &lt;p&gt;GTK has a custom &lt;code&gt;@define-color&lt;/code&gt; keyword…
137 nor librsvg support that. This would be obviated with &lt;a href="htt…
138 properties&lt;/a&gt; -
139 the &lt;code&gt;var()&lt;/code&gt; mechanism. (I don't know if some "…
140 would be better done as
141 &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/env()"&gt…
142 but none of the three implementations support that, either.)&lt;/p&gt;
143 &lt;/li&gt;
144 &lt;/ul&gt;
145 &lt;h1&gt;Accent colors&lt;/h1&gt;
146 &lt;p&gt;They are currently implemented with GTK's &lt;code&gt;@define-c…
147 not ideal if the colors have to trickle down from GTK to SVG icons,
148 since librsvg doesn't do &lt;code&gt;@define-color&lt;/code&gt; - it wou…
149 &lt;a href="https://gitlab.gnome.org/GNOME/librsvg/-/issues/459"&gt;&lt;…
150 instead&lt;/a&gt;.&lt;/p&gt;
151 &lt;p&gt;Of course, gnome-shell's libcroco doesn't do &lt;code&gt;@defin…
152 &lt;p&gt;Look for &lt;code&gt;@accent_color&lt;/code&gt;, &lt;code&gt;@a…
153 stylesheet&lt;/a&gt;,
154 or better yet, &lt;strong&gt;write documentation!&lt;/strong&gt;&lt;/p&g…
155 &lt;p&gt;The default style:&lt;/p&gt;
156 &lt;p&gt;&lt;img alt="Default blue style" src="https://people.gnome.org/…
157 &lt;p&gt;Accent color set to orange (e.g. tweak it in GTK's CSS inspecto…
158 &lt;p&gt;&lt;img alt="Orange accents for widgets" src="https://people.gn…
159 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
160 &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="k"&gt;define-color&l…
161
162 &lt;span class="c"&gt;/* background+text pair */&lt;/span&gt;
163 &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="k"&gt;define-color&l…
164 &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="k"&gt;define-color&l…
165 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
166
167 &lt;h1&gt;Custom widgets&lt;/h1&gt;
168 &lt;p&gt;Again, your app's custom stylesheet for its custom widgets can …
169 colors defined through &lt;code&gt;@define-color&lt;/code&gt; from the s…
170 &lt;h1&gt;Recoloring styles&lt;/h1&gt;
171 &lt;p&gt;You will be able to do this after it gets merged into the main …
172 e.g. recolor everything to sepia:&lt;/p&gt;
173 &lt;p&gt;&lt;img alt="Adwaita recolored to sepia" src="https://people.gn…
174 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
175 &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="k"&gt;define-color&l…
176
177 &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="k"&gt;define-color&l…
178 &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="k"&gt;define-color&l…
179
180 &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="k"&gt;define-color&l…
181
182 &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="k"&gt;define-color&l…
183 &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="k"&gt;define-color&l…
184 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
185
186 &lt;p&gt;Of course &lt;code&gt;shade()&lt;/code&gt; is not web-platform …
187 it, or redo it by implementing &lt;a href="https://developer.mozilla.org…
188 function&lt;/a&gt; for
189 color values.&lt;/p&gt;
190 &lt;h1&gt;Recoloring icons&lt;/h1&gt;
191 &lt;p&gt;Currently GTK takes some defined colors and &lt;a href="https:/…
192 inject into SVG for
193 icons&lt;/a&gt;.
194 This has &lt;a href="https://gitlab.gnome.org/GNOME/gtk/-/issues/2314"&g…
195 problems&lt;/a&gt;.&lt;/p&gt;
196 &lt;p&gt;There is also some discussion about &lt;a href="https://gitlab.…
197 icons&lt;/a&gt; across
198 desktop environments.&lt;/p&gt;
199 &lt;h1&gt;How you can help&lt;/h1&gt;
200 &lt;p&gt;Implement support for &lt;a href="https://developer.mozilla.org…
201 queries&lt;/a&gt;
202 in our three CSS implementations (librsvg, gnome-shell, GTK). Decide
203 how CSS media features like &lt;code&gt;prefers-color-scheme&lt;/code&gt…
204 &lt;code&gt;prefers-contrast&lt;/code&gt;, &lt;code&gt;inverted-colors&l…
205 themes and accessibility, and decide if we should use them for
206 familiarity with the web platform, or if we need media features with
207 different names.&lt;/p&gt;
208 &lt;p&gt;Implement support for &lt;a href="https://developer.mozilla.org…
209 &lt;code&gt;var()&lt;/code&gt;&lt;/a&gt;
210 in our three CSS implementations. Decide if we should replace the
211 current &lt;code&gt;@define-color&lt;/code&gt; with that (note that &lt;…
212 in GTK, but not in librsvg or gnome-shell).&lt;/p&gt;
213 &lt;p&gt;See the &lt;a href="https://discourse.gnome.org/t/libadwaita-1-…
214 roadmap&lt;/a&gt;
215 and help out!&lt;/p&gt;
216 &lt;p&gt;Port applications to use the proposed APIs for querying the dar…
217 preference. There are a bunch of hacky ways of doing it right now;
218 they need to be migrated to the new system.&lt;/p&gt;
219 &lt;p&gt;Personally I would love help with finishing to &lt;a href="http…
220 styles to
221 Rust&lt;/a&gt; -
222 this is part of unifying librsvg's and gnome-shell's CSS machinery.&lt;/…
223 Mark Wielaard. In 2019 I started maintaining an &lt;a href="https://gi…
224 repository in GitLab&lt;/a&gt;, with the intention of updating
225 the build system and starting a Rust port of bzip2. Unfortunately I
226 have left this project slip by.&lt;/p&gt;
227 &lt;p&gt;The new maintainer of the &lt;a href="https://gitlab.com/bzip2/…
228 Mark Wielaard. In 2019 I started maintaining an &lt;a href="https://gi…
229 repository in GitLab&lt;/a&gt;, with the intention of updating
230 the build system and starting a Rust port of bzip2. Unfortunately I
231 have left this project slip by.&lt;/p&gt;
232 &lt;p&gt;The new maintainer of the &lt;a href="https://gitlab.com/bzip2/…
233 Bzip2 is Micah Snyder. Thanks, Micah, for picking it up!&lt;/p&gt;</co…
234 code&lt;/a&gt;. Around the same time, Linux distributions
235 started shipping the first versions of Firefox that also required
236 Rust. I unashamedly wanted to ride that wave: distros would &lt;em&gt;h…
237 integrate a new language in their build infrastructure, or they would �…
238 code&lt;/a&gt;. Around the same time, Linux distributions
239 started shipping the first versions of Firefox that also required
240 Rust. I unashamedly wanted to ride that wave: distros would &lt;em&gt;h…
241 integrate a new language in their build infrastructure, or they would
242 be left without Firefox. I was hoping that having a working Rust
243 toolchain would make it easier for the rustified librsvg to get into
244 distros.&lt;/p&gt;
245 &lt;p&gt;Two years after that, &lt;a href="https://lwn.net/Articles/7713…
246 that this made it hard or impossible to build librsvg (and all the
247 software that depends on it, which is A Lot) on all the architectures
248 that Debian builds on — specifically, on things like HP PA-RISC or
249 Alpha, which &lt;a href="https://www.debian.org/ports/"&gt;even Debian m…
250 &lt;p&gt;Recently there was a similar kerfuffle, this time from &lt;a hr…
251 Gentoo&lt;/a&gt;, specifically about how Python's cryptography
252 package now requires Rust. So, it doesn't build for platforms that
253 Rust/LLVM don't support, like hppa, alpha, and Itanium. It also
254 doesn't build for platforms for which there are no Rust packages from
255 Gentoo yet (mips, s390x, riscv among them).&lt;/p&gt;
256 &lt;h2&gt;Memories of discontinued architectures&lt;/h2&gt;
257 &lt;p&gt;Let me reminisce about a couple of discontinued architectures. …
258 reading &lt;a href="https://en.wikipedia.org/wiki/DEC_Alpha"&gt;Wikipedi…
259 developed in 2001, and HP, who purchased Compaq, who purchased DEC,
260 stopped selling Alpha systems in 2007. Notably, Compaq phased out the
261 Alpha in favor of the Itanium, which stopped being developed in 2017.&lt…
262 &lt;p&gt;I &lt;em&gt;used&lt;/em&gt; an Alpha machine in 1997-1998, back…
263 &lt;a href="https://twitter.com/migueldeicaza/"&gt;Miguel&lt;/a&gt; kind…
264 where he worked, and the computer lab there got an Alpha box to let
265 the scientists run mathematical models on a machine with really fast
266 floating-point. This was a time when people actually regularly ssh'ed
267 into machines to run X11 applications remotely — in their case, I
268 think it was Matlab and Mathematica. Good times.&lt;/p&gt;
269 &lt;p&gt;The Alpha had fast floating point, much faster than Intel x86 C…
270 and I was delighted to do graphics work on it. That was the first
271 64-bit machine I used, and it let me learn how to fix code that only
272 assumed 32 bits. It had a really picky floating-point unit. Whereas
273 x86 would happily throw you a NaN if you used uninitialized memory as
274 floats, the Alpha would properly fault and crash the program. I fixed
275 so many bugs thanks to that!&lt;/p&gt;
276 &lt;p&gt;I also have fond memories of the 32-bit SPARC
277 boxes at the University and their flat-screen fixed-frequency CRT
278 displays, but you know, I haven't &lt;em&gt;seen&lt;/em&gt; one of those…
279 1998. Because I was doing graphics work, I used the single SPARC
280 machine in the computer lab at the Institute that had 24-bit graphics,
281 with a humongous 21" CRT display. PCs at the time still had 8-bit video
282 cards and shitty little monitors.&lt;/p&gt;
283 &lt;p&gt;At about the same time that the Institute got its Alpha, it als…
284 one of the first 64-bit UltraSPARCs from Sun — a very expensive
285 machine definitely not targeted to hobbyists. I think it had two CPUs!
286 Multicore did not exist!&lt;/p&gt;
287 &lt;p&gt;I think I saw a single Itanium machine in my life, probably aro…
288 2002-2005. The Ximian/Novell office in Mexico City got one, for QA
289 purposes — an incredibly loud and unstable machine. I don't think we
290 ever did any actual development on that box; it was a "can you
291 reproduce this bug there" kind of thing. I think Ximian/Novell had a
292 contract with HP to test the distro there, I don't remember.&lt;/p&gt;
293 &lt;h2&gt;Unsupported architectures at the LLVM level&lt;/h2&gt;
294 &lt;p&gt;Platforms like the Alpha and Itanium that Rust/LLVM don't suppo…
295 those platforms are dead in the water. The compiler cannot target
296 them, as Rust generates machine code via LLVM, and LLVM doesn't
297 support them.&lt;/p&gt;
298 &lt;p&gt;I don't know why distributions maintained by volunteers give
299 themselves the responsibility to keep their software running on
300 platforms that have not been manufactured for years, and that were
301 never even hobbyist machines.&lt;/p&gt;
302 &lt;p&gt;I read the other day, and now I regret not keeping the link, so…
303 like this: don't assume that your hobby computing entitles you to free
304 labor on the part of compiler writers, software maintainers, and
305 distro volunteers. (If someone helps me find the source, I'll happily
306 link to it and quote it properly.)&lt;/p&gt;
307 &lt;h2&gt;Non-tier-1 platforms and "$distro does not build Rust there ye…
308 &lt;p&gt;I think people are discovering these once again:&lt;/p&gt;
309 &lt;ul&gt;
310 &lt;li&gt;
311 &lt;p&gt;Writing and supporting a compiler for a certain architecture ta…
312 &lt;/li&gt;
313 &lt;li&gt;
314 &lt;p&gt;Supporting a distro for a certain architecture takes Real Work.…
315 &lt;/li&gt;
316 &lt;li&gt;
317 &lt;p&gt;Fixing software to work on a certain architecture takes Real Wo…
318 &lt;/li&gt;
319 &lt;/ul&gt;
320 &lt;p&gt;Rust divides its support for different platforms into &lt;a hre…
321 from tier 1, the most supported, to tier 3, the least supported. Or,
322 I should say, &lt;em&gt;taken care of&lt;/em&gt;, which is a combination…
323 actually have the hardware in question, and whether the general CI and
324 build tooling is prepared to deal with them as effectively as it does
325 for tier 1 platforms.&lt;/p&gt;
326 &lt;p&gt;In other words: there are more people capable of paying attenti…
327 testing things on, x86_64 PCs than there are for
328 &lt;code&gt;sparc-unknown-linux-gnu&lt;/code&gt;.&lt;/p&gt;
329 &lt;h2&gt;Some anecdotes from Suse&lt;/h2&gt;
330 &lt;p&gt;At Suse we actually support IBM's s390x big iron; those mainfr…
331 Suse Linux Enterprise Server. You have to pay a lot of money to get a
332 machine like that and support for it. It's a room-sized beast that
333 requires professional babysitting.&lt;/p&gt;
334 &lt;p&gt;When librsvg and Firefox started getting rustified, there was of
335 course concern about getting Rust to work properly on the s390x.
336 I worked sporadically with the people who made the distro work there,
337 and who had to deal with building Rust and Firefox on it (librsvg
338 was a non-issue after getting Rust and Firefox to work).&lt;/p&gt;
339 &lt;p&gt;I think all the LLVM work for the s390x was done at IBM. There…
340 probably a couple of miscompilations that affected Firefox; they got fix…
341 &lt;p&gt;One would expect bugs in software for IBM mainframes to be fixe…
342 IBM or its contractors, not by volunteers maintaining a distro in
343 their spare time.&lt;/p&gt;
344 &lt;p&gt;Giving computing time on mainframes to volunteers in distros co…
345 like a good samaritan move, or a trap to extract free labor from
346 unsuspecting people.&lt;/p&gt;
347 &lt;h3&gt;Endianness bugs&lt;/h3&gt;
348 &lt;p&gt;Firefox's problems on the s390x were more around big-endian bug…
349 anything. You see, all the common architectures these days (x86_64
350 and arm64) are little-endian. However, s390x is &lt;a href="https://en.…
351 which means that all multi-byte numbers in memory are stored backwards
352 from what most software expects.&lt;/p&gt;
353 &lt;p&gt;It is not a problem to write software that assumes little-endia…
354 big-endian all the time, but it takes a little care to write software
355 that works on either.&lt;/p&gt;
356 &lt;p&gt;Most of the software that volunteers and paid people write assu…
357 little-endian CPUs, because that is likely what they are targeting.
358 It is a pain in the ass to encounter code that works incorrectly on
359 big-endian — a pain because &lt;em&gt;knowing where to look&lt;/em&gt;…
360 bugs is tricky, and &lt;em&gt;fixing existing code&lt;/em&gt; to work wi…
361 endianness can be either very simple, or a major adventure in
362 refactoring and testing.&lt;/p&gt;
363 &lt;p&gt;Two cases in point:&lt;/p&gt;
364 &lt;p&gt;&lt;strong&gt;Firefox.&lt;/strong&gt; When Suse started dealin…
365 s390x, there were endianness bugs in the graphics code in Firefox that
366 deals with pixel formats. Whether pixels get stored in memory as
367 ARGB/ABGR/RGBA/etc. is a platform-specific thing, and is generally a
368 combination of the graphics hardware for that platform, plus the
369 actual CPU architecture. At that time, it looked like the C++ code in
370 Firefox that deals with pixels had been rewritten/refactored, and had
371 lost big-endian support along the way. I don't know the current
372 status (not a single big-endian CPU in my vincinity), but I haven't
373 seen related bugs come in the Suse bug tracker? Maybe it's fixed now?&l…
374 &lt;p&gt;&lt;strong&gt;Librsvg&lt;/strong&gt; had &lt;a href="https://gi…
375 big-endian&lt;/a&gt;. One was in the old code for SVG
376 filter effects that was written in C; &lt;a href="https://gitlab.gnome.o…
377 initial port to Rust inherited the same bug (think of a line-by-line
378 port, althought it wasn't exactly like that), but it got fixed when my
379 Summer of Code intern Ivan Molodetskikh refactored the code to have a
380 &lt;code&gt;Pixel&lt;/code&gt; abstraction that works for little-endian …
381 wraps Cairo's funky requirements.&lt;/p&gt;
382 &lt;p&gt;The other endian-related bug in librsvg was when &lt;a href="ht…
383 masks&lt;/a&gt;. Again, a little refactoring with that &lt;code&gt;Pixe…
384 abstraction fixed it.&lt;/p&gt;
385 &lt;p&gt;I knew that the original C code for SVG filter effects didn't w…
386 big-endian. But even back then, at Suse we never got
387 reports of it producing incorrect results on the s390x... maybe people d…
388 their mainframes to run &lt;code&gt;rsvg-convert&lt;/code&gt;? I was ho…
389 Rust of that code would automatically fix that bug, and it kind of
390 happened that way through Ivan's careful work.&lt;/p&gt;
391 &lt;p&gt;And the code for masks? There were two bugs reported with that…
392 root cause: &lt;a href="https://gitlab.gnome.org/GNOME/librsvg/-/issues/…
393 Debian&lt;/a&gt; as a
394 failure in librsvg's test suite (yay, it caught that bug!), and one
395 from &lt;a href="https://gitlab.gnome.org/GNOME/librsvg/-/issues/322"&gt…
396 G4&lt;/a&gt; with a MATE
397 desktop and seeing incorrectly-rendered SVG icons.&lt;/p&gt;
398 &lt;p&gt;And you know what? I am &lt;strong&gt;delighted&lt;/strong&gt;…
399 those lovely machines alive. A laptop that doesn't get warm enough to
400 burn your thighs, what a concept. A perfectly serviceable 32-bit
401 laptop with a maximum of about 1 GB of RAM and a 40 GB hard drive (it
402 didn't have HDMI!)... But you know, it's the same kind of delight I
403 feel when people talk about doing film photography on a
404 &lt;a href="https://en.wikipedia.org/wiki/Rollei_35"&gt;Rollei 35&lt;/a…
405 nostalgia for hardware of days past, and a lot of mixed feelings about
406 not throwing out working things and creating more trash.&lt;/p&gt;
407 &lt;p&gt;As a graphics programmer I feel the responsibility to write cod…
408 works on little-endian and big-endian, but you know, it's not exactly
409 an everyday concern anymore. The last big-endian machine I used on an
410 everyday basis was the SPARCs in the university, more than 20 years
411 ago.&lt;/p&gt;
412 &lt;h3&gt;Who gets paid to fix this?&lt;/h3&gt;
413 &lt;p&gt;That's the question. Suse got paid to support Firefox on the s…
414 suppose IBM has an interest in fixing LLVM there; both actually have
415 people and hardware and money to that effect.&lt;/p&gt;
416 &lt;p&gt;Within Suse, I am by default responsible for keeping librsvg
417 working for the s390x as well — it gets built as part of the distro,
418 after all. I have never gotten an endianness bug report from the Suse
419 side of things.&lt;/p&gt;
420 &lt;p&gt;Which leads me to suspect that, probably similar to Debian and …
421 we &lt;em&gt;build&lt;/em&gt; a lot of software because it's in the buil…
422 don't &lt;em&gt;run&lt;/em&gt; it to its fullest extent. Do people run …
423 s390x virtual machines? Maybe? Did they not notice endianness bugs
424 &lt;strong&gt;because they were not in the code path that most GNOME ico…
425 actually use&lt;/strong&gt;? Who knows!&lt;/p&gt;
426 &lt;p&gt;I'm thankful to Simon from the Debian bug for pointing out
427 the failure in librsvg's test case for masks, and to Mingcong for
428 actually showing a screenshot of a MATE desktop running on a PPC
429 PowerBook. Those were useful things for them to do.&lt;/p&gt;
430 &lt;p&gt;Also — they were kind about it. It was a pleasure to interac…
431 &lt;p&gt;The librsvg 2.40.x series is the last "C only" version of the l…
432 it was deprecated in 2017.&lt;/p&gt;
433 &lt;p&gt;During the port to Rust, I rewrote the path parser to be
434 spec-compliant, and …&lt;/p&gt;</summary><content type="html">&lt;p&gt…
435 &lt;p&gt;The librsvg 2.40.x series is the last "C only" version of the l…
436 it was deprecated in 2017.&lt;/p&gt;
437 &lt;p&gt;During the port to Rust, I rewrote the path parser to be
438 spec-compliant, and fixed a few cases that the C version did not
439 handle. One of this cases is for compact Arc data.&lt;/p&gt;
440 &lt;p&gt;The &lt;a href="https://www.w3.org/TR/SVG11/paths.html#PathData…
441 one to remove whitespace between numbers if the next number starts
442 with a sign. For example, &lt;code&gt;23-45&lt;/code&gt; gets parsed as…
443 -45&lt;/code&gt;.&lt;/p&gt;
444 &lt;p&gt;In addition, the arguments of the Arc commands have two flags i…
445 middle of a bunch of numbers. The flags can be &lt;code&gt;0&lt;/code&g…
446 may be no whitespace between the flags and the next number. For
447 example, &lt;code&gt;A1.98 1.98 0 0015 13.96&lt;/code&gt; gets parsed as…
448 13.96&lt;/code&gt; — note the two &lt;code&gt;0 0&lt;/code&gt; flags b…
449 &lt;p&gt;Librsvg 2.40.x does not parse this correctly.
450 Adwaita-icon-theme-3.36, and possibly earlier versions, uses minimized
451 SVG files with compressed whitespace, and will not render correctly
452 with the C-only version of librsvg.&lt;/p&gt;
453 &lt;p&gt;This is &lt;code&gt;help-contents-symbolic.svg&lt;/code&gt; ren…
454 &lt;p&gt;&lt;img alt="icon rendered incorrectly" src="https://people.gno…
455 &lt;p&gt;And this is &lt;code&gt;help-contents-symbolic.svg&lt;/code&gt;…
456 &lt;p&gt;&lt;img alt="icon rendered correctly" src="https://people.gnome…
457 &lt;p&gt;This is not the only icon with compact Arc commands; there are …
458 others that will also be mis-rendered in 2.40.x.&lt;/p&gt;
459 &lt;p&gt;I don't know when Adwaita started using SVGs with compressed
460 whitespace; probably it didn't when librsvg 2.40.x was the latest
461 version, or everyone would have noticed mis-rendered icons.&lt;/p&gt;
462 &lt;p&gt;&lt;strong&gt;Background:&lt;/strong&gt; Someone recently filed…
463 &lt;a href="https://gitlab.gnome.org/GNOME/librsvg/-/issues/654"&gt;bug&…
464 memory unsafety in librsvg 2.40.x's path parser, which mysteriously
465 enough only manifests itself in big-endian platforms. I wouldn't be
466 surprised if this had latent bugs on little-endian as well.&lt;/p&gt;
467 &lt;p&gt;Please use at least librsvg 2.48.x; any earlier versions are n…
468 supported. Generally I keep an eye on the last two stable release
469 sets (2.48.x and 2.50.x as of this writing), but only commit fixes to
470 the latest stable series (2.50.x currently).&lt;/p&gt;</content><categor…
471 &lt;h2&gt;Changes to continuous integration&lt;/h2&gt;
472 &lt;p&gt;Some days ago, &lt;a href="https://gitlab.gnome.org/GNOME/librs…
473 scripts&lt;/a&gt; to be much faster. A complete pipeline used to take
474 about 90 minutes to run, now it takes about 15 minutes on average.&lt;…
475 &lt;p&gt;&lt;img alt="Graph with pipeline timings, which shrink drastica…
476 &lt;p&gt;The &lt;a href="https://gitlab.gnome.org/GNOME/librsvg/-/merge_…
477 &lt;h2&gt;Changes to continuous integration&lt;/h2&gt;
478 &lt;p&gt;Some days ago, &lt;a href="https://gitlab.gnome.org/GNOME/librs…
479 scripts&lt;/a&gt; to be much faster. A complete pipeline used to take
480 about 90 minutes to run, now it takes about 15 minutes on average.&lt;…
481 &lt;p&gt;&lt;img alt="Graph with pipeline timings, which shrink drastica…
482 &lt;p&gt;The &lt;a href="https://gitlab.gnome.org/GNOME/librsvg/-/merge_…
483 &lt;ul&gt;
484 &lt;li&gt;
485 &lt;p&gt;Move the &lt;code&gt;cargo check&lt;/code&gt; stage to the begi…
486 "does this even have a chance of compiling?".&lt;/p&gt;
487 &lt;/li&gt;
488 &lt;li&gt;
489 &lt;p&gt;Have the code style and formatting tests, &lt;code&gt;cargo cli…
490 fmt&lt;/code&gt;, run in parallel with the unit tests. These lints ca…
491 but they are easy to fix after one is finished modifying the main
492 code.&lt;/p&gt;
493 &lt;/li&gt;
494 &lt;li&gt;
495 &lt;p&gt;Run the unit tests and the smoke tests in debug mode, so they c…
496 quickly.&lt;/p&gt;
497 &lt;/li&gt;
498 &lt;li&gt;
499 &lt;p&gt;Run the complete integration test suite in release mode. This …
500 longer to compile, but there are some slow tests that benefit a lot
501 from faster execution.&lt;/p&gt;
502 &lt;/li&gt;
503 &lt;li&gt;
504 &lt;p&gt;Move the release tests until the end, and only run them once a …
505 — or whenever, by hand. These take a good amount of time to run,
506 because they do a full &lt;code&gt;make distcheck&lt;/code&gt; and aut…
507 then, now these tests take 30-40 minutes, instead of the 90 from
508 before.&lt;/p&gt;
509 &lt;/li&gt;
510 &lt;li&gt;
511 &lt;p&gt;Between each stage of the pipeline, don't cache what doesn't he…
512 reduce compilation time. It seems that keeping around a big cache,
513 with the whole build &lt;code&gt;target&lt;/code&gt;, between each pip…
514 worse than not having one at all.&lt;/p&gt;
515 &lt;/li&gt;
516 &lt;/ul&gt;
517 &lt;p&gt;&lt;img alt="Complete pipeline with all the stages" src="https:…
518 &lt;h2&gt;Test suite in Rust&lt;/h2&gt;
519 &lt;p&gt;Beteen Sven Neumann, Dunja Lalic, and myself we have finally …
520 the test suite to Rust&lt;/a&gt;: all of librsvg's tests are
521 now in Rust, except for the C API tests. We had to do a few things:&lt;…
522 &lt;ul&gt;
523 &lt;li&gt;
524 &lt;p&gt;Review the old tests and remove some obsolete ones.&lt;/p&gt;
525 &lt;/li&gt;
526 &lt;li&gt;
527 &lt;p&gt;Port each of the test modules to Rust. They are small, but eac…
528 has special little things — test for crashes in the XML loading
529 code, test for crashes during rendering, test the library's security
530 limits.&lt;/p&gt;
531 &lt;/li&gt;
532 &lt;li&gt;
533 &lt;p&gt;Fix the small tests that come as part of the documentation.&lt;…
534 &lt;/li&gt;
535 &lt;li&gt;
536 &lt;p&gt;Untangle the reference tests and port them to Rust.&lt;/p&gt;
537 &lt;/li&gt;
538 &lt;li&gt;
539 &lt;p&gt;Move little chunks of code around so the unit tests and integra…
540 tests can share utilities to compare images, compute file paths for
541 test fixtures, etc.&lt;/p&gt;
542 &lt;/li&gt;
543 &lt;/ul&gt;
544 &lt;p&gt;The most complicated thing to port was the reference tests. Th…
545 the most important ones; each test loads an SVG document, renders it,
546 and compares the result to a reference PNG image. There are some
547 complications in the tests; they have to create a special
548 configuration for Fontconfig and Pango, so as to have reproducible
549 font rendering. The pango-rs bindings do not cover this part of
550 Pango, so we had to do some things by hand.&lt;/p&gt;
551 &lt;p&gt;Anyway, &lt;a href="https://gitlab.gnome.org/GNOME/librsvg/-/tr…
552 now the tests run automatically in parallel, across all CPU cores, so
553 we save on total testing time.&lt;/p&gt;
554 &lt;h2&gt;What's next: cargo-c and publish to crates.io&lt;/h2&gt;
555 &lt;p&gt;We want to be able to &lt;a href="https://gitlab.gnome.org/GNOM…
556 normal crate; this implies being able to compile, test, and publish
557 entirely from Cargo. The compilation and testing part is done.&lt;/p&gt;
558 &lt;p&gt;Now, we have to reorganize the code so it can be published to
559 crates.io. Librsvg comes in three parts, &lt;code&gt;rsvg_internals&lt;…
560 implementation of the library, &lt;code&gt;librsvg&lt;/code&gt; with the…
561 and &lt;code&gt;librsvg_crate&lt;/code&gt; with the Rust API. However, …
562 API to crates.io, it would be more convenient to have a single crate
563 instead of one with the internals and one with the API.&lt;/p&gt;
564 &lt;p&gt;The next step is thus to reorganize the code:&lt;/p&gt;
565 &lt;ul&gt;
566 &lt;li&gt;
567 &lt;p&gt;Make it possible to implement the C API as a compile-time optio…
568 top of the normal Rust code. We want to &lt;a href="https://gitlab.gn…
569 compile the traditional shared library &lt;code&gt;librsvg.so&lt;/code…
570 depending on C tools for compiling and linking.&lt;/p&gt;
571 &lt;/li&gt;
572 &lt;li&gt;
573 &lt;p&gt;Combine &lt;code&gt;rsvg_internals&lt;/code&gt; and &lt;code&gt…
574 publish them together. Crates.io has a 10 MB limit per crate; now
575 that the test suite lives in a separate &lt;code&gt;tests&lt;/code&gt;…
576 shouldn't be a problem.&lt;/p&gt;
577 &lt;/li&gt;
578 &lt;li&gt;
579 &lt;p&gt;I would like to &lt;a href="https://gitlab.gnome.org/GNOME/libr…
580 publishing the Rust API; right now they expose some implementation
581 details that are of no interest to callers of the library.&lt;/p&gt;
582 &lt;/li&gt;
583 &lt;/ul&gt;
584 &lt;h2&gt;What remains to be ported to Rust?&lt;/h2&gt;
585 &lt;p&gt;Only two things, which amount to less than 900 lines of C code…
586 &lt;ul&gt;
587 &lt;li&gt;
588 &lt;p&gt;&lt;a href="https://gitlab.gnome.org/GNOME/librsvg/-/issues/534…
589 convert SVG to PNG and other formats. Fortunately, Sven Neumann
590 wrote some &lt;a href="https://gitlab.gnome.org/GNOME/librsvg/-/blob/m…
591 as it is like an API that we need to keep stable: if we change the
592 command-line options or the program's behavior, we would break
593 everyone's scripts.&lt;/p&gt;
594 &lt;/li&gt;
595 &lt;li&gt;
596 &lt;p&gt;The gdk-pixbuf module for loading SVG. Alberto Ruiz &lt;a hre…
597 porting it to Rust&lt;/a&gt;. The generic part of this code
598 could later serve to wrap other Rust image codecs and plug them to
599 gdk-pixbuf.&lt;/p&gt;
600 &lt;/li&gt;
601 &lt;/ul&gt;</content><category term="misc"></category><category term="li…
602 in the December 2020 / March 2021 round:&lt;/p&gt;
603 &lt;ul&gt;
604 &lt;li&gt;
605 &lt;p&gt;&lt;strong&gt;Revamp the text engine&lt;/strong&gt; - Do you kn…
606 layout? Can you read a right-to-left language, or do you write in a
607 language that requires complex shaping? Would you like to implement �…
608 in the December 2020 / March 2021 round:&lt;/p&gt;
609 &lt;ul&gt;
610 &lt;li&gt;
611 &lt;p&gt;&lt;strong&gt;Revamp the text engine&lt;/strong&gt; - Do you kn…
612 layout? Can you read a right-to-left language, or do you write in a
613 language that requires complex shaping? Would you like to implement
614 the &lt;a href="https://www.w3.org/TR/SVG2/text.html"&gt;SVG 2 text sp…
615 base&lt;/a&gt;? This project requires someone who can write Rust
616 comfortably; it will require reading and refactoring some
617 existing code. You don't need to be an expert in exotic lifetimes
618 and trait bounds and such; the code doesn't use them.&lt;/p&gt;
619 &lt;/li&gt;
620 &lt;li&gt;
621 &lt;p&gt;&lt;strong&gt;Implement SVG2/CSS3 features&lt;/strong&gt; - Are…
622 features&lt;/a&gt; in Inkscape, and would like to add support for them
623 in librsvg? Would you like to do small changes to many parts of the
624 code to implement small features, one at a time? Do you like
625 test-driven development? This project requires someone who can
626 write Rust code at a medium level; you'll learn a lot by
627 cutting&amp;amp;pasting from existing code and refactoring things to
628 implement SVG2 features.&lt;/p&gt;
629 &lt;/li&gt;
630 &lt;/ul&gt;
631 &lt;p&gt;&lt;strong&gt;Important:&lt;/strong&gt; Outreachy's December 20…
632 for students in the Southern hemisphere&lt;/a&gt;. People in the
633 Northern hemisphere can wait until the 2021 mid-year round.&lt;/p&gt;
634 &lt;p&gt;You can see &lt;a href="https://www.outreachy.org/apply/project…
635 &lt;strong&gt;The deadline for initial contributions and project applica…
636 October 31, 2020 at 16:00 UTC.&lt;/strong&gt;&lt;/p&gt;</content><catego…
637 time on C libraries) express concerns along the following lines:&lt;/p&g…
638 &lt;ol&gt;
639 &lt;li&gt;Compiled Rust code doesn't have a stable ABI (application bina…
640 &lt;li&gt;So, we can't have shared libraries in the traditional fashion …
641 Linux distributions.&lt;/li&gt;
642 &lt;li&gt;Also Rust bundles …&lt;/li&gt;&lt;/ol&gt;</summary><content …
643 time on C libraries) express concerns along the following lines:&lt;/p&g…
644 &lt;ol&gt;
645 &lt;li&gt;Compiled Rust code doesn't have a stable ABI (application bina…
646 &lt;li&gt;So, we can't have shared libraries in the traditional fashion …
647 Linux distributions.&lt;/li&gt;
648 &lt;li&gt;Also Rust bundles its entire standard library with every binar…
649 &lt;/ol&gt;
650 &lt;p&gt;These are extremely valid concerns to be addressed by people li…
651 myself who propose that chunks of infrastructural libraries
652 should be done in Rust.&lt;/p&gt;
653 &lt;p&gt;So, let's begin.&lt;/p&gt;
654 &lt;p&gt;The first part of this article is a super-quick introduction to…
655 libraries and how Linux distributions use them. If you already know
656 those things, feel free to skip to the "&lt;a href="#rust_does_not_have_…
657 ABI&lt;/a&gt;" section.&lt;/p&gt;
658 &lt;h2&gt;How do distributions use shared libraries?&lt;/h2&gt;
659 &lt;p&gt;If several programs run at the same time and use the same share…
660 (say, &lt;code&gt;libgtk-3.so&lt;/code&gt;), the operating system can lo…
661 the library in memory and share the read-only parts of the code/data
662 through the magic of virtual memory.&lt;/p&gt;
663 &lt;p&gt;&lt;em&gt;In theory&lt;/em&gt;, if a library gets a bugfix but …
664 interface, one can just recompile the library, stick the new &lt;code&gt…
665 &lt;code&gt;/usr/lib&lt;/code&gt; or whatever, and be done with it. Pro…
666 the library do not need to be recompiled.&lt;/p&gt;
667 &lt;p&gt;If libraries limit their public interface to a plain C ABI
668 (application binary interface), they are relatively easy to consume
669 from other programming languages. Those languages don't have to deal
670 with name mangling of C++ symbols, exception handlers, constructors,
671 and all that complexity. Pretty much every language has some form of
672 C FFI (foreign function interface), which roughly means "call C
673 functions without too much trouble".&lt;/p&gt;
674 &lt;p&gt;For the purposes of a library, what's an
675 &lt;a href="https://en.wikipedia.org/wiki/Application_binary_interface"&…
676 Wikipedia says, "An ABI defines how data structures or computational
677 routines are accessed in machine code [...] A common aspect of an
678 ABI is the calling convention", which means that to call a function in
679 machine code you need to frob the call and stack pointers, pass some
680 function arguments in registers or push some others to the stack, etc.
681 Really low-level stuff. Each machine architecture or operating system
682 usually defines a C standard ABI.&lt;/p&gt;
683 &lt;p&gt;For libraries, we commonly understand an ABI to mean the machin…
684 implications of their programming interface. Which functions are
685 available as public symbols in the &lt;code&gt;.so&lt;/code&gt; file? T…
686 values do C enum values correspond, so that they can be passed to
687 those functions? What is the exact order and type of arguments that
688 the functions take? What are the struct sizes, and the order and
689 types and padding of the fields that those functions take? Does one
690 pass arguments in CPU registers or on the stack? Does the caller or
691 the callee clean up the stack after a function call?&lt;/p&gt;
692 &lt;h2&gt;Bug fixes and security fixes&lt;/h2&gt;
693 &lt;p&gt;Linux distributions generally try &lt;em&gt;really hard&lt;/em&…
694 version of each shared library installed in the system: a single
695 &lt;code&gt;libjpeg.so&lt;/code&gt;, a single &lt;code&gt;libpng.so&lt;/…
696 &lt;p&gt;This is helpful when there needs to be an update to fix a bug,
697 security-related or not: users can just download the updated package
698 for the library, which when installed will just stick in a new &lt;code&…
699 in the right place, and the calling software won't need to be updated.&l…
700 &lt;p&gt;This is possible only if the bug &lt;em&gt;really only changes …
701 code&lt;/em&gt; without changing behavior or interface. If a bug fix re…
702 part of the public API or ABI to change, then you are screwed; all
703 calling software needs to be recompiled. "Irresponsible" library
704 authors either learn really fast when distros complain loudly about
705 this sort of change, or they don't learn and get forever marked by
706 distros as "that irresponsible library" which always requires special
707 handling in order not to break other software.&lt;/p&gt;
708 &lt;p&gt;Sidenote: sometimes it's more complicated. Poppler (the PDF
709 rendering library) ships at least two stable APIs, one Glib-based in
710 C, and one Qt-based in C++. However, some software like texlive uses
711 Poppler's internals library directly, which of course does not have a
712 stable API, and thus texlive breaks frequently as Poppler evolves.
713 Someone should extend the public, stable API so that texlive doesn't
714 have to use the library's internals!&lt;/p&gt;
715 &lt;h2&gt;Bundled libraries&lt;/h2&gt;
716 &lt;p&gt;Sometimes it is not irresponsible authors of libraries, but rat…
717 that people who use the libraries find out that over time the behavior
718 of the library changes subtly, maybe without breaking the API or ABI,
719 and they are better off bundling a specific version of the library
720 with their software. That version is what they test their software
721 against, and they try to learn its quirks.&lt;/p&gt;
722 &lt;p&gt;Distros inevitably complain about this, and either patch the ca…
723 software by hand to force it to use the system's shared library, or
724 succeed in getting patches accepted by the software so that they have
725 a &lt;code&gt;--use-system-libjpeg&lt;/code&gt; option or similar.&lt;/p…
726 &lt;p&gt;This doesn't work very well if the bundled version of the libra…
727 extra patches that are not in a distro's usual patches. Or
728 vice-versa; it may actually work better to use the distro's version of
729 the library, if it has extra fixes that the bundled library doesn't.
730 Who knows! It's a case-by-case situation.&lt;/p&gt;
731 &lt;h2 id="rust_does_not_have_a_stable_abi"&gt;Rust does not have a stab…
732 &lt;p&gt;By default indeed it doesn't, because the compiler team wants t…
733 the freedom to change the data layout and Rust-to-Rust calling
734 conventions, often for performance reasons, at any time. For example,
735 it is not guaranteed that struct fields will be laid out in memory in
736 the same order as they are written in the code:&lt;/p&gt;
737 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
738 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;bar&lt;/spa…
739 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;baz&lt;/spa…
740 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;beep&lt;/sp…
741 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qux&lt;/spa…
742 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
743 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
744
745 &lt;p&gt;The compiler is free to rearrange the struct fields in memory a…
746 sees fit. Maybe it decides to put the two &lt;code&gt;bool&lt;/code&gt;…
747 other to save on inter-field padding due to alignment requirements;
748 maybe it does static analysis or profile-guided optimizations and
749 picks an optmal ordering.&lt;/p&gt;
750 &lt;p&gt;But we can override this! Let's look at data layout first, and…
751 calling conventions.&lt;/p&gt;
752 &lt;h3&gt;Data layout for C versus Rust&lt;/h3&gt;
753 &lt;p&gt;The following is the same struct as above, but with an extra &l…
754 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
755 &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;Foo&lt;…
756 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;bar&lt;/spa…
757 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;baz&lt;/spa…
758 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;beep&lt;/sp…
759 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qux&lt;/spa…
760 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
761 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
762
763 &lt;p&gt;With that attribute, the struct will be laid out just as this C…
764 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
765 &lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&am…
766
767 &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;Foo&lt;…
768 &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;bar&l…
769 &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;baz…
770 &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;beep&…
771 &lt;span class="kt"&gt;int32_t&lt;/span&gt; &lt;span class="n"&gt;qu…
772 &lt;span class="p"&gt;}&lt;/span&gt;
773 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
774
775 &lt;p&gt;(Aside: it is unfortunate that &lt;a href="https://people.gnome…
776 but that's because &lt;code&gt;gboolean&lt;/code&gt; predates C99, and c…
777 20 years ago are &lt;em&gt;too new&lt;/em&gt; to use. (Aside aside: sin…
778 other post, Rust's repr(C) for bool is actually defined as C99's bool;
779 it's no longer undefined.))&lt;/p&gt;
780 &lt;p&gt;Even Rust's data-carrying enums can be laid out in a manner fri…
781 to C and C++:&lt;/p&gt;
782 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
783 &lt;span class="k"&gt;enum&lt;/span&gt; &lt;span class="nc"&gt;MyEnum&lt…
784 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;A&lt;/span&…
785 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;B&lt;/span&…
786 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
787 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
788
789 &lt;p&gt;This means, use C layout, and a &lt;code&gt;u8&lt;/code&gt; for…
790 will be laid out like this:&lt;/p&gt;
791 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
792 &lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&am…
793
794 &lt;span class="k"&gt;enum&lt;/span&gt; &lt;span class="n"&gt;MyEnumTag&…
795 &lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="p"&gt;,&lt;/…
796 &lt;span class="n"&gt;B&lt;/span&gt;
797 &lt;span class="p"&gt;};&lt;/span&gt;
798
799 &lt;span class="k"&gt;typedef&lt;/span&gt; &lt;span class="kt"&gt;uint32…
800
801 &lt;span class="k"&gt;typedef&lt;/span&gt; &lt;span class="k"&gt;struct&…
802 &lt;span class="kt"&gt;float&lt;/span&gt; &lt;span class="n"&gt;…
803 &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;y…
804 &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="n"&gt;MyEnumPayload…
805
806 &lt;span class="k"&gt;typedef&lt;/span&gt; &lt;span class="k"&gt;union&l…
807 &lt;span class="n"&gt;MyEnumPayloadA&lt;/span&gt; &lt;span class…
808 &lt;span class="n"&gt;MyEnumPayloadB&lt;/span&gt; &lt;span class…
809 &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="n"&gt;MyEnumPayload…
810
811 &lt;span class="k"&gt;typedef&lt;/span&gt; &lt;span class="k"&gt;struct&…
812 &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&g…
813 &lt;span class="n"&gt;MyEnumPayload&lt;/span&gt; &lt;span class=…
814 &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="n"&gt;MyEnum&lt;/sp…
815 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
816
817 &lt;p&gt;The gory details of data layout are in the &lt;a href="https://…
818 Rustonomicon&lt;/a&gt; and
819 the &lt;a href="https://rust-lang.github.io/unsafe-code-guidelines/intro…
820 Guidelines&lt;/a&gt;.&lt;/p&gt;
821 &lt;h3&gt;Calling conventions&lt;/h3&gt;
822 &lt;p&gt;An ABI's calling conventions detail things like how to call fun…
823 in machine code, and how to lay out function arguments in registers or
824 the stack. &lt;a href="https://en.wikipedia.org/wiki/X86_calling_conven…
825 conventions&lt;/a&gt;
826 has a good cheat-sheet, useful when you are looking at assembly code
827 and registers in a low-level debugger.&lt;/p&gt;
828 &lt;p&gt;I've already written about how it is possible to write Rust cod…
829 export functions callable from C; one uses the &lt;code&gt;extern "C"&lt…
830 function definition and a &lt;code&gt;#[no_mangle]&lt;/code&gt; attribut…
831 name pristine. This is how librsvg is able to have the following:&lt;/p…
832 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
833 &lt;span class="k"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&g…
834 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;filename&lt…
835 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;error&lt;/s…
836 &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;…
837 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// ...&lt;…
838 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
839 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
840
841 &lt;p&gt;Which compiles to what a C compiler would produce for this:&lt;…
842 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
843 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
844
845 &lt;p&gt;(Aside: librsvg &lt;a href="https://gitlab.gnome.org/GNOME/libr…
846 stubs&lt;/a&gt; that just
847 call the Rust-exported functions, but there is now &lt;a href="https://g…
848 directly from
849 Rust&lt;/a&gt; which I
850 just haven't had time to investigate. Help is appreciated!)&lt;/p&gt;
851 &lt;h3&gt;Summary of ABI so far&lt;/h3&gt;
852 &lt;p&gt;It is &lt;em&gt;one's decision&lt;/em&gt; to export a stable C …
853 There is some awkwardness in how types are laid out in C, because the
854 Rust type system is richer, but things can be made to work well with a
855 little thought. Certainly no more thought than the burden of
856 designing and maintaining a stable API/ABI in plain C.&lt;/p&gt;
857 &lt;p&gt;I'll fold the second concern into here — "we can't have shared
858 libraries in traditional distro fashion". Yes, we can, API/ABI-wise,
859 but read on.&lt;/p&gt;
860 &lt;h2&gt;Rust bundles its entire standard library with Rust-built .so's…
861 &lt;p&gt;I.e. it statically links all the Rust dependencies. This produ…
862 large .so:&lt;/p&gt;
863 &lt;ul&gt;
864 &lt;li&gt;librsvg-2.so (version 2.40.21, C only) - 1408840 bytes&lt;/li…
865 &lt;li&gt;librsvg-2.so (version 2.49.3, Rust only) - 9899120 bytes&lt;/…
866 &lt;/ul&gt;
867 &lt;p&gt;Holy crap! What's all that?&lt;/p&gt;
868 &lt;p&gt;(And I'm cheating: this is both with link-time optimization tur…
869 and by running &lt;code&gt;strip(1)&lt;/code&gt; on the .so. If you jus…
870 it will be bigger.)&lt;/p&gt;
871 &lt;p&gt;This has Rust's standard library statically linked (or at least…
872 bits of that librsvg actually uses), plus all the Rust dependencies
873 (cssparser, selectors, nalgebra, glib-rs, cairo-rs, locale_config,
874 rayon, xml5ever, and an assload of crates). I could explain why each
875 one is needed:&lt;/p&gt;
876 &lt;ul&gt;
877 &lt;li&gt;cssparser - librsvg needs to parse CSS.&lt;/li&gt;
878 &lt;li&gt;selectors - librsvg needs to run the CSS selector matching
879 algorithm.&lt;/li&gt;
880 &lt;li&gt;nalgebra - the code for SVG filter effects uses vectors and
881 matrices.&lt;/li&gt;
882 &lt;li&gt;glib-rs, cairo-rs - draw to Cairo and export GObject types.&lt…
883 &lt;li&gt;locale_config - so that localized SVG files can work.&lt;/li&g…
884 &lt;li&gt;rayon - so filters can use all your CPU cores instead of proce…
885 one pixel at a time.&lt;/li&gt;
886 &lt;li&gt;Etcetera. SVG is big and requires a lot of helper code!&lt;/l…
887 &lt;/ul&gt;
888 &lt;p&gt;Is this a problem?&lt;/p&gt;
889 &lt;p&gt;Or more exactly, why does this happen, and why do people percei…
890 as a problem?&lt;/p&gt;
891 &lt;h3&gt;Stable APIs/ABIs and distros&lt;/h3&gt;
892 &lt;p&gt;Many Linux distributions have worked &lt;em&gt;really hard&lt;/…
893 there is a single copy of "system libraries" in an installation.
894 There is Just One Copy of &lt;code&gt;/usr/lib/libc.so&lt;/code&gt;, &lt…
895 etc., and packages are compiled with special options to tell them to
896 really use the sytem libraries instead of their bundled versions, or
897 patched to do so if they don't provide build-time options for that.&lt;/…
898 &lt;p&gt;In a way, this works well for distros:&lt;/p&gt;
899 &lt;ul&gt;
900 &lt;li&gt;
901 &lt;p&gt;A bug in a library can be fixed in a single place, and all
902 applications that use it get the fix automatically.&lt;/p&gt;
903 &lt;/li&gt;
904 &lt;li&gt;
905 &lt;p&gt;A security bug can be patched in a single place, and in theory
906 applications don't need to be audited further.&lt;/p&gt;
907 &lt;/li&gt;
908 &lt;/ul&gt;
909 &lt;p&gt;If you maintain a library that is shipped in Linux distros, and…
910 break the ABI, you'll get complaints from distros very quickly.&lt;/p&gt;
911 &lt;p&gt;This is good because it creates responsible maintainers for lib…
912 that can be depended on. It's how Inkscape/GIMP can have a stable
913 toolkit to be written in.&lt;/p&gt;
914 &lt;p&gt;This is bad because it encourages stagnation in the long term. …
915 how we get a horrible, unsafe, error-prone API in libjpeg that can
916 never ever be improved because it would requires changes in tons of
917 software; it's why &lt;code&gt;gboolean&lt;/code&gt; is still a 32-bit &…
918 twenty-something years, even though everything else close to C has
919 decided that booleans are 1 byte. It's how Inkscape/GIMP take many
920 years to move from GTK2 to GTK3 (okay, that's lack of paid developers
921 to do the grunt work, but it is enabled by having forever-stable APIs).&…
922 &lt;p&gt;However, a long-term stable API/ABI has a &lt;strong&gt;lot of …
923 the Windows API is the crown jewels; it is why people can rely on glib
924 and glibc to not break their code for many years and take them for grant…
925 &lt;h3&gt;But we only have a single stable ABI anyway&lt;/h3&gt;
926 &lt;p&gt;And that is the C ABI. Even C++ libraries have trouble with th…
927 people sometimes write the internals of a library in C++ for
928 convenience, but export a stable C API/ABI from it.&lt;/p&gt;
929 &lt;p&gt;High level languages like Python have &lt;em&gt;real trouble&lt…
930 precisely because of ABI issues.&lt;/p&gt;
931 &lt;h3&gt;Actually, in GNOME we have gone further than that&lt;/h3&gt;
932 &lt;p&gt;In GNOME we have constructed a sweet little universe where &lt;…
933 Introspection&lt;/a&gt; is
934 basically a C ABI with a ton of machine-generated annotations to make
935 it friendly to language bindings.&lt;/p&gt;
936 &lt;p&gt;Still, we rely on a C ABI underneath. See &lt;a href="https://…
937 thread on advancing the C ABI from Rust&lt;/a&gt; for
938 lots of food for thought.&lt;/p&gt;
939 &lt;h3&gt;Single copies of libraries with a C ABI&lt;/h3&gt;
940 &lt;p&gt;Okay, let's go back to this. What price do we pay for single c…
941 of libraries that, by necessity, must export a C ABI?&lt;/p&gt;
942 &lt;ul&gt;
943 &lt;li&gt;
944 &lt;p&gt;Code that can be conveniently called from C, maybe from C++, and
945 moderately to very inconvently from ANYTHING ELSE. With most new
946 application code being written definitely not in C, maybe we should
947 reconsider our priorities here.&lt;/p&gt;
948 &lt;/li&gt;
949 &lt;li&gt;
950 &lt;p&gt;No language facilities like generics or field visibility, which…
951 not even "modern language" features. Even C++ templates get
952 compiled and statically linked into the calling code, because
953 there's no way to pass information like the size of &lt;code&gt;T&lt;/…
954 &lt;code&gt;Array&amp;lt;T&amp;gt;&lt;/code&gt; across a C ABI. You w…
955 public and some private? You are out of luck.&lt;/p&gt;
956 &lt;/li&gt;
957 &lt;li&gt;
958 &lt;p&gt;No knowledge of data ownership except by careful reading of the…
959 function's documentation. Does the function free its arguments?
960 How - with &lt;code&gt;free()&lt;/code&gt; or &lt;code&gt;g_free()&lt;…
961 caller just lend it a reference? Can the data be copied bit-by-bit
962 or must a special function be called to make a copy?
963 GObject-Introspection carries this information in its annotations,
964 while the C ABI has no idea and just ships raw pointers around.&lt;/p&…
965 &lt;/li&gt;
966 &lt;/ul&gt;
967 &lt;p&gt;More food for thought note: &lt;a href="https://twitter.com/hsi…
968 thread&lt;/a&gt; says
969 this about the C++ ABI: "Also, the ABI matters for whether the actual
970 level of practicality of complying with LGPL matches the level of
971 practicality intended years ago when some project picked LGPL as its
972 license. Of course, the standard does not talk about LGPL, either.
973 LGPL has rather different implications for Rust and Go than it does
974 for C and Java. It was obviously written with C in mind."&lt;/p&gt;
975 &lt;h2&gt;Monomorphization and template bloat&lt;/h2&gt;
976 &lt;p&gt;While C++ had the problem of "lots of template code in header f…
977 Rust has the problem that &lt;a href="https://pingcap.com/blog/generics-…
978 of compiled
979 code&lt;/a&gt;.
980 There are tricks to avoid this and they are all the decision of the
981 library/crate author. Both share the root cause that templated or
982 generic code must be recompiled for every specific use, and thus
983 cannot live in a shared library.&lt;/p&gt;
984 &lt;p&gt;Also, see this wonderful &lt;a href="https://thume.ca/2019/07/1…
985 generics&lt;/a&gt;,
986 and think that a plain C ABI means we have NOTHING of the sort.&lt;/p&gt;
987 &lt;p&gt;Also, see &lt;a href="https://gankra.github.io/blah/swift-abi/"…
988 Couldn't&lt;/a&gt; for more food for
989 thought. This is extremely roughly equivalent to GObject's boxed
990 types; callers keep values on the heap but know the type layout via
991 annotation magic, while the library's actual implementation
992 is free to have the values on the stack or wherever for its own use.&lt;…
993 &lt;h2&gt;Should all libraries export APIs with generics and exotic type…
994 &lt;p&gt;No!&lt;/p&gt;
995 &lt;p&gt;You probably want something like a low-level array of values,
996 &lt;code&gt;Vec&amp;lt;T&amp;gt;&lt;/code&gt;, to be inlined everywhere …
997 type of the vector's elements. Element accesses can be inlined to a
998 single machine instruction in the best case.&lt;/p&gt;
999 &lt;p&gt;But not everything requires this absolute raw performance with
1000 everything inlined everywhere. It is fine to pass references or
1001 pointers to things and do dynamic dispatch from a vtable if you are
1002 not in a super-tight loop, as we love to do in the GObject world.&lt;/p&…
1003 &lt;h2&gt;Library sizes&lt;/h2&gt;
1004 &lt;p&gt;I don't have a good answer to librsvg's compiled size. If gnom…
1005 merges my branch to rustify the CSS code, it will also grow its binary
1006 size by quite a bit.&lt;/p&gt;
1007 &lt;p&gt;It is my intention to have a Rust crate that both librsvg and
1008 gnome-shell share for their CSS styling needs, but right now I have no
1009 idea if this would be a shared library or just a normal Rust crate.
1010 Maybe it's possible to have a very general CSS library, and the
1011 application registers which properties it can parse and how? Is it
1012 possible to do this as a shared library without essentially
1013 reinventing libcroco? I don't know yet. We'll see.&lt;/p&gt;
1014 &lt;h2&gt;A metaphor which I haven't fully explored&lt;/h2&gt;
1015 &lt;p&gt;If every application or end-user package is kind of like a livi…
1016 organism, with its own cycles and behaviors and organs (dependent
1017 libraries) that make it possible...&lt;/p&gt;
1018 &lt;p&gt;Why do distros expect all the living organisms on your machine …
1019 share The World's Single Lungs Service, and The World's Single Stomach
1020 Service, and The World's Single Liver Service?&lt;/p&gt;
1021 &lt;p&gt;You know, instead of letting every organism have its own slight…
1022 different version of those organs, customized for it? We humans know
1023 how to do vaccination campaigns and everything; maybe we need better
1024 tools to apply bug fixes where they are needed?&lt;/p&gt;
1025 &lt;p&gt;I know this metaphor is extremely imperfect and not how things …
1026 software, but it makes me wonder.&lt;/p&gt;</content><category term="mis…
1027 &lt;p&gt;The GNOME Foundation's &lt;a href="https://mail.gnome.org/archi…
1028 up, and we are looking for candidates. Of the 7 directors, we are
1029 replacing 4, and the 3 remaining positions remain for another year.
1030 You …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I forgot to wri…
1031 &lt;p&gt;The GNOME Foundation's &lt;a href="https://mail.gnome.org/archi…
1032 up, and we are looking for candidates. Of the 7 directors, we are
1033 replacing 4, and the 3 remaining positions remain for another year.
1034 You could be one of those four.&lt;/p&gt;
1035 &lt;p&gt;I would like it very much if there were candidates and director…
1036 fall outside the box of "white male programmer"; it is unfortunate
1037 that for the current Board we ended up with all dudes. GNOME has a
1038 &lt;a href="https://wiki.gnome.org/Foundation/CodeOfConduct"&gt;Code of …
1039 &lt;p&gt;Allan Day wrote a &lt;a href="https://blogs.gnome.org/aday/2020…
1040 year&lt;/a&gt;. We are moving from a model where the Board does a
1041 little bit of everything, to one with a more strategic role — now that
1042 the Foundation has full-time employees, they take care of most of the
1043 executive work.&lt;/p&gt;
1044 &lt;p&gt;&lt;strong&gt;The call-for-candidates is open until May 29, so …
1045 &lt;ul&gt;
1046 &lt;li&gt;&lt;a href="https://blogs.gnome.org/aday/2020/05/26/gnome-foun…
1047 &lt;li&gt;&lt;a href="https://mail.gnome.org/archives/foundation-announc…
1048 &lt;/ul&gt;</content><category term="misc"></category><category term="gn…
1049 that by now has a lot of accumulated crap. It is such an old configurat…
1050 it didn't even use the modern convention of &lt;code&gt;~/.emacs.d/init.…
1051 like a newer Emacs …&lt;/p&gt;</summary><content type="html">&lt;p&gt;…
1052 that by now has a lot of accumulated crap. It is such an old configurat…
1053 it didn't even use the modern convention of &lt;code&gt;~/.emacs.d/init.…
1054 like a newer Emacs version will allow &lt;code&gt;.config/emacs&lt;/code…
1055 standard... at last).&lt;/p&gt;
1056 &lt;p&gt;I have wanted to change my Emacs configuration for some time, a…
1057 the pretty and modern toys.&lt;/p&gt;
1058 &lt;p&gt;The things that matter the most to me:&lt;/p&gt;
1059 &lt;ul&gt;
1060 &lt;li&gt;Not have a random dumpster in &lt;code&gt;~/.emacs&lt;/code&gt…
1061 &lt;li&gt;Pretty colors.&lt;/li&gt;
1062 &lt;li&gt;Magit.&lt;/li&gt;
1063 &lt;li&gt;Rust-mode or whatever the new thing is for rust-analyzer and t…
1064 &lt;/ul&gt;
1065 &lt;p&gt;After looking at several examples of configurations that mentio…
1066 as a unified way of loading packages and configuring them, I found &lt;a…
1067 configuration&lt;/a&gt; which is extremely well
1068 documented. The author does literate programming with org-mode and elis…
1069 something which I'm casually interested in, but not just now — but tha…
1070 everything ends up very well explained and easy to read.&lt;/p&gt;
1071 &lt;p&gt;I extracted bits of that configuration and ended up with the fo…
1072 &lt;h2&gt;Everything in &lt;code&gt;~/.emacs/init.el&lt;/code&gt; and wi…
1073 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
1074
1075 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;require&lt;/s…
1076
1077 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;setq&lt;/span&…
1078 &lt;span class="o"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;…
1079 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;q…
1080 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;q…
1081
1082 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;package-initi…
1083 &lt;span class="c1"&gt;;(package-refresh-contents)&lt;/span&gt;
1084
1085 &lt;span class="c1"&gt;;; Use-package for civilized configuration&lt;/sp…
1086
1087 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;unless&lt;/sp…
1088 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;package-ins…
1089 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;require&lt;/s…
1090
1091 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;setq&lt;/span&…
1092 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
1093
1094 &lt;h2&gt;&lt;code&gt;~/.emacs.d/custom.el&lt;/code&gt; for &lt;code&gt;…
1095 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
1096 &lt;span class="c1"&gt;;; my init files.&lt;/span&gt;
1097
1098 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;setq&lt;/span&…
1099 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span…
1100 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
1101
1102 &lt;h2&gt;Which-key to get hints when typing command prefixes&lt;/h2&gt;
1103 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
1104
1105 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;use-package&l…
1106 &lt;span class="nb"&gt;:diminish&lt;/span&gt;
1107 &lt;span class="nb"&gt;:config&lt;/span&gt;
1108 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;which-key-m…
1109 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;which-key-s…
1110 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;setq&lt;/spa…
1111 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
1112
1113 &lt;h2&gt;Don't pollute the modeline with common modes&lt;/h2&gt;
1114 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
1115
1116 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;use-package&l…
1117 &lt;span class="nb"&gt;:defer&lt;/span&gt; &lt;span class="mi"&gt;5&lt…
1118 &lt;span class="nb"&gt;:config&lt;/span&gt;
1119 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;diminish&lt…
1120 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
1121
1122 &lt;h2&gt;Magit to use git in a civilized fashion&lt;/h2&gt;
1123 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
1124
1125 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;use-package&l…
1126 &lt;span class="nb"&gt;:config&lt;/span&gt;
1127 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;global-set-…
1128 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
1129
1130 &lt;h2&gt;Move between windows with Shift-arrows&lt;/h2&gt;
1131 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
1132 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;windmove-defa…
1133 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
1134
1135 &lt;h2&gt;Pretty colors&lt;/h2&gt;
1136 &lt;p&gt;I was using &lt;code&gt;solarized-dark&lt;/code&gt; but I like …
1137 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
1138
1139 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;use-package&l…
1140 &lt;span class="nb"&gt;:config&lt;/span&gt;
1141 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;custom-them…
1142 &lt;span class="o"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;(&l…
1143 &lt;span class="o"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;(&l…
1144 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
1145
1146 &lt;h2&gt;Nyan cat instead of scrollbars&lt;/h2&gt;
1147 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
1148 &lt;span class="c1"&gt;;; scroll-bar-mode is turned off in custom.el&lt;…
1149
1150 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;use-package&l…
1151 &lt;span class="nb"&gt;:config&lt;/span&gt;
1152 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;nyan-mode&l…
1153 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
1154
1155 &lt;h2&gt;Move buffers to adjacent windows&lt;/h2&gt;
1156 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
1157
1158 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;use-package&l…
1159 &lt;span class="nb"&gt;:config&lt;/span&gt;
1160 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;global-set-…
1161 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;global-set-…
1162 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;global-set-…
1163 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;global-set-…
1164 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
1165
1166 &lt;h2&gt;Change buffer names for files with the same name&lt;/h2&gt;
1167 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
1168 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;require&lt;/s…
1169 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;setq&lt;/span&…
1170 &lt;span class="nv"&gt;uniquify-buffer-name-style&lt;/span&gt; &lt…
1171 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
1172
1173 &lt;h2&gt;Helm to auto-complete in grand style&lt;/h2&gt;
1174 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
1175 &lt;span class="nb"&gt;:diminish&lt;/span&gt;
1176 &lt;span class="nb"&gt;:init&lt;/span&gt; &lt;span class="p"&gt;(&lt;/s…
1177 &lt;span class="nb"&gt;:bind&lt;/span&gt; &lt;span class="p"&gt;((&lt;/…
1178 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;q…
1179 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;q…
1180 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;q…
1181 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;q…
1182 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;q…
1183 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;q…
1184 &lt;span class="c1"&gt;;; Look at what was cut recently &amp;amp…
1185 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;q…
1186
1187 &lt;span class="nb"&gt;:map&lt;/span&gt; &lt;span class="nv"&gt;…
1188 &lt;span class="c1"&gt;;; We can list ‘actions’ on the curre…
1189 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;q…
1190 &lt;span class="c1"&gt;;; Let&amp;#39;s keep tab-completetion an…
1191 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;q…
1192 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;q…
1193 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
1194
1195 &lt;h2&gt;Ripgrep to search in grand style&lt;/h2&gt;
1196 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
1197
1198 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;use-package&l…
1199 &lt;span class="nb"&gt;:config&lt;/span&gt;
1200 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;global-set-…
1201 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;global-set-…
1202
1203 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;use-package&l…
1204 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
1205
1206 &lt;h2&gt;Rust mode and Language Server&lt;/h2&gt;
1207 &lt;p&gt;Now that RLS is in the process of being deprecated, it's gettin…
1208 with rust-analyzer. Also, rust-mode goes away in favor of rustic.&lt;/p…
1209 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
1210
1211 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;use-package&l…
1212
1213 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;use-package&l…
1214
1215 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;use-package&l…
1216
1217 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;use-package&l…
1218 &lt;span class="nb"&gt;:config&lt;/span&gt;
1219 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;define-key&…
1220 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
1221
1222 &lt;h2&gt;Performatively not get distracted&lt;/h2&gt;
1223 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
1224
1225 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;setq&lt;/span&…
1226 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/spa…
1227 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;…
1228
1229 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;defun&lt;/span…
1230 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt…
1231 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&…
1232 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;…
1233 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;…
1234 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;…
1235 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;statu…
1236 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
1237
1238 &lt;h2&gt;Stuff from custom.el&lt;/h2&gt;
1239 &lt;p&gt;The interesting bits here are making LSP work; everything else …
1240 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
1241 &lt;span class="c1"&gt;;; custom-set-variables was added by Custom.&lt;…
1242 &lt;span class="c1"&gt;;; If you edit it by hand, you could mess it up,…
1243 &lt;span class="c1"&gt;;; Your init file should contain only one such i…
1244 &lt;span class="c1"&gt;;; If there is more than one, they won&amp;#39;t…
1245 &lt;span class="o"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;(&lt;…
1246 &lt;span class="o"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;(&lt;…
1247 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;quote&lt;/s…
1248 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;…
1249 &lt;span class="o"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;(&lt;…
1250 &lt;span class="o"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;(&lt;…
1251 &lt;span class="o"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;(&lt;…
1252 &lt;span class="o"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;(&lt;…
1253 &lt;span class="o"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;(&lt;…
1254 &lt;span class="o"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;(&lt;…
1255 &lt;span class="o"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;(&lt;…
1256 &lt;span class="o"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;(&lt;…
1257 &lt;span class="o"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;(&lt;…
1258 &lt;span class="o"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;(&lt;…
1259 &lt;span class="o"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;(&lt;…
1260 &lt;span class="o"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;(&lt;…
1261 &lt;span class="o"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;(&lt;…
1262 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;quote&lt;/s…
1263 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;helm-lsp&…
1264 &lt;span class="o"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;(&lt;…
1265 &lt;span class="o"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;(&lt;…
1266 &lt;span class="o"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;(&lt;…
1267 &lt;span class="o"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;(&lt;…
1268 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;custom-set-fa…
1269 &lt;span class="c1"&gt;;; custom-set-faces was added by Custom.&lt;/spa…
1270 &lt;span class="c1"&gt;;; If you edit it by hand, you could mess it up,…
1271 &lt;span class="c1"&gt;;; Your init file should contain only one such i…
1272 &lt;span class="c1"&gt;;; If there is more than one, they won&amp;#39;t…
1273 &lt;span class="p"&gt;)&lt;/span&gt;
1274 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
1275
1276 &lt;h2&gt;Results&lt;/h2&gt;
1277 &lt;p&gt;I am very happy with rustic / rust-analyzer and the Language Se…
1278 documentation on each thing when one moves the cursor around code is som…
1279 that I never thought would work well in Emacs. I haven't decided if I l…
1280 lsp-rust-analyzer-inlay-hints-mode&lt;/code&gt; or if it drives me nuts;…
1281 names of function arguments and inferred types among the code. I suppos…
1282 turn it off and on as needed.&lt;/p&gt;
1283 &lt;p&gt;Some days ago, before using helm, I had projectile-mode to work…
1284 checkouts and I was quite liking it. I haven't found how to configure
1285 helm-projectile to work; I'll have to keep experimenting.&lt;/p&gt;</con…
1286 map extracted from OpenStreetMap.&lt;/p&gt;
1287 &lt;p&gt;According to &lt;a href="https://valgrind.org/docs/manual/ms-ma…
1288 the following point during the execution of rsvg-convert. I pasted
1289 only the part that refers to Bézier paths:&lt;/p&gt;
1290 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
1291 &lt;span class="nt"&gt;n&lt;/span&gt; &lt;span class="nt"&g…
1292 map extracted from OpenStreetMap.&lt;/p&gt;
1293 &lt;p&gt;According to &lt;a href="https://valgrind.org/docs/manual/ms-ma…
1294 the following point during the execution of rsvg-convert. I pasted
1295 only the part that refers to Bézier paths:&lt;/p&gt;
1296 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
1297 &lt;span class="nt"&gt;n&lt;/span&gt; &lt;span class="nt"&g…
1298 &lt;span class="nt"&gt;---------------------------------------------…
1299 &lt;span class="nt"&gt;1&lt;/span&gt; &lt;span class="nt"&gt;33&lt;/s…
1300 &lt;span class="nt"&gt;2&lt;/span&gt; &lt;span class="nt"&gt;-&lt;/spa…
1301 &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nt"&gt;-&lt;/sp…
1302 &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nt"&gt;-&lt;/…
1303 &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nt"&gt;-&lt…
1304 &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nt"&gt;-&…
1305 &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nt"&gt;…
1306 &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nt"&g…
1307 &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nt"…
1308 &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n…
1309 &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class=…
1310 &lt;span class="nt"&gt;3&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span…
1311 &lt;span class="o"&gt;|&lt;/span&gt;
1312 &lt;span class="nt"&gt;4&lt;/span&gt; &lt;span class="nt"&gt;-&lt;/spa…
1313 &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nt"&gt;-&lt;/sp…
1314 &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nt"&gt;-&lt;/…
1315 &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nt"&gt;-&lt…
1316 &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nt"&gt;-&…
1317 &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nt"&gt;…
1318 &lt;span class="nt"&gt;5&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span…
1319 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
1320
1321 &lt;p&gt;Line 1 has the totals, and we see that at that point the progr…
1322 1,329,943,212 bytes on the heap.&lt;/p&gt;
1323 &lt;p&gt;Lines 3 and 5 give us a hint that &lt;code&gt;into_path&lt;/…
1324 the function that converts a temporary/mutable &lt;code&gt;PathBuilder&l…
1325 permanent/immutable &lt;code&gt;Path&lt;/code&gt;.&lt;/p&gt;
1326 &lt;p&gt;Lines 2 and 4 indicate that the arrays of &lt;code&gt;PathCo…
1327 inside those immutable &lt;code&gt;Path&lt;/code&gt;s, use 24.88% + 3.…
1328 program's memory; between both they use
1329 352,523,448 + 50,990,328 = 403,513,776 bytes.&lt;/p&gt;
1330 &lt;p&gt;That is about 400 MB of &lt;code&gt;PathCommand&lt;/code&gt;. …
1331 &lt;h2&gt;What is in a PathCommand?&lt;/h2&gt;
1332 &lt;p&gt;A &lt;code&gt;Path&lt;/code&gt; is a list of commands similar t…
1333 in SVG to draw Bézier paths. It is a flat array of &lt;code&gt;PathCom…
1334 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
1335 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;path_comman…
1336 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
1337
1338 &lt;span class="k"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&g…
1339 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MoveTo&lt;/…
1340 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;LineTo&lt;/…
1341 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CurveTo&lt;…
1342 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Arc&lt;/spa…
1343 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ClosePath&l…
1344 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
1345 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
1346
1347 &lt;p&gt;Let's see the variants of &lt;code&gt;PathCommand&lt;/code&gt;:…
1348 &lt;ul&gt;
1349 &lt;li&gt;&lt;code&gt;MoveTo&lt;/code&gt;: 2 double-precision floating-p…
1350 &lt;li&gt;&lt;code&gt;LineTo&lt;/code&gt;: same.&lt;/li&gt;
1351 &lt;li&gt;&lt;code&gt;CurveTo&lt;/code&gt;: 6 double-precision floating-…
1352 &lt;li&gt;&lt;code&gt;EllipticalArc&lt;/code&gt;: 7 double-precision flo…
1353 flags (see below).&lt;/li&gt;
1354 &lt;li&gt;&lt;code&gt;ClosePath&lt;/code&gt;: no extra data.&lt;/li&gt;
1355 &lt;/ul&gt;
1356 &lt;p&gt;These variants vary a lot in terms of size, and each element of…
1357 &lt;code&gt;Path.path_commands&lt;/code&gt; array occupies the maximum o…
1358 (i.e. &lt;code&gt;sizeof::&amp;lt;EllipticalArc&amp;gt;&lt;/code&gt;).&l…
1359 &lt;h2&gt;A more compact representation&lt;/h2&gt;
1360 &lt;p&gt;Ideally, each command in the array would only occupy as much sp…
1361 it needs.&lt;/p&gt;
1362 &lt;p&gt;We can represent a &lt;code&gt;Path&lt;/code&gt; in a different…
1363 &lt;ul&gt;
1364 &lt;li&gt;A very compact array of commands without coordinates.&lt;/li&g…
1365 &lt;li&gt;An array with coordinates only.&lt;/li&gt;
1366 &lt;/ul&gt;
1367 &lt;p&gt;That is, the following:&lt;/p&gt;
1368 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
1369 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;commands&lt…
1370 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;coords&lt;/…
1371 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
1372 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
1373
1374 &lt;p&gt;The &lt;code&gt;coords&lt;/code&gt; array is obvious; it is jus…
1375 coordinates in the &lt;code&gt;Path&lt;/code&gt; in the order in which t…
1376 &lt;p&gt;And the &lt;code&gt;commands&lt;/code&gt; array?&lt;/p&gt;
1377 &lt;h3&gt;PackedCommand&lt;/h3&gt;
1378 &lt;p&gt;We saw above that the biggest variant in &lt;code&gt;PathComman…
1379 &lt;code&gt;Arc(EllipticalArc)&lt;/code&gt;. Let's look inside it:&lt;/…
1380 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
1381 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;pub&lt;/spa…
1382 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;pub&lt;/spa…
1383 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;pub&lt;/spa…
1384 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;pub&lt;/spa…
1385 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;pub&lt;/spa…
1386 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;pub&lt;/spa…
1387 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
1388 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
1389
1390 &lt;p&gt;There are 7 &lt;code&gt;f64&lt;/code&gt; floating-point number…
1391 &lt;code&gt;large_arc&lt;/code&gt; and &lt;code&gt;sweep&lt;/code&gt;, a…
1392 with two variants, with pretty names instead of just &lt;code&gt;true&lt…
1393 &lt;code&gt;false&lt;/code&gt;).&lt;/p&gt;
1394 &lt;p&gt;Thus, we have 7 doubles and two flags. Between the two flag…
1395 are 4 possibilities.&lt;/p&gt;
1396 &lt;p&gt;Since no other &lt;code&gt;PathCommand&lt;/code&gt; variant has…
1397 following enum, which fits in a single byte:&lt;/p&gt;
1398 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
1399 &lt;span class="k"&gt;enum&lt;/span&gt; &lt;span class="nc"&gt;PackedCom…
1400 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MoveTo&lt;/…
1401 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;LineTo&lt;/…
1402 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CurveTo&lt;…
1403 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ArcSmallNeg…
1404 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ArcSmallPos…
1405 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ArcLargeNeg…
1406 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ArcLargePos…
1407 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ClosePath&l…
1408 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
1409 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
1410
1411 &lt;p&gt;That is, simple values for &lt;code&gt;MoveTo&lt;/code&gt;/etc.…
1412 the different types of &lt;code&gt;Arc&lt;/code&gt;.&lt;/p&gt;
1413 &lt;h2&gt;Packing a PathCommand into a PackedCommand&lt;/h2&gt;
1414 &lt;p&gt;In order to pack the array of &lt;code&gt;PathCommand&lt;/code&…
1415 many coordinates each of its variants will produce:&lt;/p&gt;
1416 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
1417 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span…
1418 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;match&l…
1419 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Pat…
1420 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Pat…
1421 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Pat…
1422 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Pat…
1423 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Pat…
1424 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/s…
1425 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&…
1426 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
1427 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
1428
1429 &lt;p&gt;Then, we need to convert each &lt;code&gt;PathCommand&lt;/code&…
1430 write its coordinates into an array:&lt;/p&gt;
1431 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
1432 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span…
1433 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;match&l…
1434 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Pat…
1435 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt…
1436 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt…
1437 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt…
1438 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&l…
1439
1440 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;//…
1441
1442 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Pat…
1443 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/s…
1444 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&…
1445 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
1446 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
1447
1448 &lt;p&gt;Let's look at that &lt;code&gt;to_packed_and_coords&lt;/code&gt…
1449 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
1450 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span…
1451 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;coords&…
1452 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;coords&…
1453 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;coords&…
1454 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;coords&…
1455 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;coords&…
1456 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;coords&…
1457 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;coords&…
1458
1459 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;match&l…
1460 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&l…
1461 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&l…
1462 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&l…
1463 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&l…
1464 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/s…
1465 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&…
1466 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
1467 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
1468
1469 &lt;h2&gt;Creating the compact Path&lt;/h2&gt;
1470 &lt;p&gt;Let's look at &lt;code&gt;PathBuilder::into_path&lt;/code&gt; l…
1471 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
1472 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;pub&lt;/spa…
1473 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;let&lt…
1474 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;let&lt…
1475 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&l…
1476 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&l…
1477 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&l…
1478 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
1479
1480 &lt;p&gt;First we compute the total number of coordinates using &lt;code…
1481 each command &lt;code&gt;cmd&lt;/code&gt; its &lt;code&gt;num_coordinate…
1482 accumulator.&lt;/p&gt;
1483 &lt;p&gt;Now we know how much memory to allocate:&lt;/p&gt;
1484 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
1485 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;let&lt…
1486 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
1487
1488 &lt;p&gt;We use &lt;code&gt;Vec::with_capacity&lt;/code&gt; to allocate …
1489 need for the &lt;code&gt;packed_commands&lt;/code&gt;; adding elements w…
1490 &lt;code&gt;realloc()&lt;/code&gt;, since we already know how many eleme…
1491 &lt;p&gt;We use the &lt;code&gt;vec!&lt;/code&gt; macro to create an arr…
1492 &lt;code&gt;num_coords&lt;/code&gt; times; that macro uses &lt;code&gt;w…
1493 array we will use to store the coordinates for all the commands.&lt;/p&g…
1494 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
1495 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
1496
1497 &lt;p&gt;We get a mutable slice out of the whole array of coordinates.&l…
1498 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
1499 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;le…
1500 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pac…
1501 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;coo…
1502 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/s…
1503 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
1504
1505 &lt;p&gt;For each command, we see how many coordinates it will generate …
1506 put that number in &lt;code&gt;n&lt;/code&gt;. We get a mutable sub-sli…
1507 &lt;code&gt;coords_slice&lt;/code&gt; with only that number of elements,…
1508 &lt;code&gt;to_packed&lt;/code&gt; for each command.&lt;/p&gt;
1509 &lt;p&gt;At the end of each iteration we move the mutable slice to where…
1510 next command's coordinates will go.&lt;/p&gt;
1511 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
1512 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;com…
1513 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;coo…
1514 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/s…
1515 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&…
1516 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
1517
1518 &lt;p&gt;At the end, we create the final and immutable &lt;code&gt;Path&…
1519 each array &lt;code&gt;into_boxed_slice&lt;/code&gt; like the last time.…
1520 the two arrays, the one with &lt;code&gt;PackedCommand&lt;/code&gt;s and…
1521 coordinates, occupy the minimum space they need.&lt;/p&gt;
1522 &lt;h2&gt;An iterator for Path&lt;/h2&gt;
1523 &lt;p&gt;This is all very well, but we also want it to be easy to iterat…
1524 that compact representation; the &lt;code&gt;PathCommand&lt;/code&gt; en…
1525 beginning are very convenient to use and that's what the rest of the
1526 code already uses. Let's make an iterator that unpacks what is inside
1527 a &lt;code&gt;Path&lt;/code&gt; and produces a &lt;code&gt;PathCommand&l…
1528 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
1529 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;commands&lt…
1530 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;coords&lt;/…
1531 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
1532 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
1533
1534 &lt;p&gt;We need an iterator over the array of &lt;code&gt;PackedCommand…
1535 each command. However, to get elements of &lt;code&gt;coords&lt;/code&g…
1536 use a slice of &lt;code&gt;f64&lt;/code&gt; instead of an iterator.&lt;/…
1537 &lt;p&gt;Let's look at the implementation of the iterator:&lt;/p&gt;
1538 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
1539 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;type&lt;/sp…
1540
1541 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span…
1542 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/…
1543 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;le…
1544 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;le…
1545 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="bp"&gt;se…
1546 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;So…
1547 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/s…
1548 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;No…
1549 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/s…
1550 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&…
1551 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
1552 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
1553
1554 &lt;p&gt;Since we want each iteration to produce a &lt;code&gt;PathComma…
1555 as having the associated &lt;code&gt;type Item =  PathCommand&lt;/cod…
1556 &lt;p&gt;If the &lt;code&gt;self.commands&lt;/code&gt; iterator has anot…
1557 another &lt;code&gt;PackedCommand&lt;/code&gt; available.&lt;/p&gt;
1558 &lt;p&gt;We call &lt;code&gt;PathCommand::from_packed&lt;/code&gt; with …
1559 unpack a command and its coordinates. We see how many coordinates the
1560 command consumed and re-slice &lt;code&gt;self.coords&lt;/code&gt; accor…
1561 commands, so that it now points to the coordinates for the next
1562 command.&lt;/p&gt;
1563 &lt;p&gt;We return &lt;code&gt;Some(cmd)&lt;/code&gt; if there was an el…
1564 iterator is empty.&lt;/p&gt;
1565 &lt;p&gt;The implementation of &lt;code&gt;from_packed&lt;/code&gt; is o…
1566 bit from it:&lt;/p&gt;
1567 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
1568 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span…
1569 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;match&l…
1570 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Pac…
1571 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&g…
1572 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&g…
1573 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt…
1574 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&l…
1575
1576 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;//…
1577
1578 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Pac…
1579 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt…
1580 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt…
1581 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt…
1582 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)),…
1583
1584 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Pac…
1585
1586 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Pac…
1587
1588 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Pac…
1589 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/s…
1590 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&…
1591 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
1592 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
1593
1594 &lt;h2&gt;Results&lt;/h2&gt;
1595 &lt;p&gt;Before the changes (this is the same Massif heading as above):&…
1596 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
1597 &lt;span class="c"&gt; n time(i) total(B) useful&lt;/s…
1598 &lt;span class="nb"&gt;-------------------------------------------------…
1599 &lt;span class="c"&gt; 33 24&lt;/span&gt;&lt;span class="nt"&gt;,&lt;/sp…
1600 &lt;span class="c"&gt; ^^^^^^^^^^^…
1601 &lt;span class="c"&gt; boo&lt;…
1602 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
1603
1604 &lt;p&gt;After:&lt;/p&gt;
1605 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
1606 &lt;span class="c"&gt; n time(i) total(B) useful&lt;/s…
1607 &lt;span class="nb"&gt;-------------------------------------------------…
1608 &lt;span class="c"&gt; 28 26&lt;/span&gt;&lt;span class="nt"&gt;,&lt;/sp…
1609 &lt;span class="c"&gt; ^^^^^^^^^^^…
1610 &lt;span class="c"&gt; oh yeah&…
1611 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
1612
1613 &lt;p&gt;We went from using 1,329,943,212 bytes down to 1,023,147,907 …
1614 that is, we knocked it down by 300 MB.&lt;/p&gt;
1615 &lt;p&gt;However, that is for the whole program. Above we saw that &lt;…
1616 occupies 403,513,776 bytes; how about now?&lt;/p&gt;
1617 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
1618 &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;…
1619 &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&l…
1620 &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;…
1621 &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="o"&gt;-&amp;g…
1622 &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="o"&gt;-&amp…
1623 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
1624
1625 &lt;p&gt;Perfect. We went from occupying 403,513,776 bytes to just
1626 81,525,328 bytes. Instead of &lt;code&gt;Path&lt;/code&gt; data amount…
1627 heap, it is just 7.45%.&lt;/p&gt;
1628 &lt;p&gt;I think we can stop worrying about &lt;code&gt;Path&lt;/code&gt…
1629 this turned out without having to use &lt;code&gt;unsafe&lt;/code&gt;.&l…
1630 &lt;h2&gt;References&lt;/h2&gt;
1631 &lt;ul&gt;
1632 &lt;li&gt;&lt;a href="https://gitlab.gnome.org/GNOME/librsvg/-/commit/e9…
1633 &lt;li&gt;&lt;a href="https://gitlab.gnome.org/GNOME/librsvg/-/commit/cb…
1634 &lt;li&gt;&lt;a href="https://gitlab.gnome.org/GNOME/librsvg/-/commit/b1…
1635 &lt;/ul&gt;</content><category term="misc"></category><category term="li…
1636 OpenStreetMap, and it has about 600,000 elements. Most of them are
1637 &lt;code&gt;&amp;lt;path&amp;gt;&lt;/code&gt;, that is, specifications f…
1638 &lt;p&gt;A &lt;code&gt;&amp;lt;path&amp;gt;&lt;/code&gt; can look like t…
1639 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
1640 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
1641
1642 &lt;p&gt;The …&lt;/p&gt;</summary><content type="html">&lt;p&gt;We got…
1643 OpenStreetMap, and it has about 600,000 elements. Most of them are
1644 &lt;code&gt;&amp;lt;path&amp;gt;&lt;/code&gt;, that is, specifications f…
1645 &lt;p&gt;A &lt;code&gt;&amp;lt;path&amp;gt;&lt;/code&gt; can look like t…
1646 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
1647 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
1648
1649 &lt;p&gt;The &lt;code&gt;d&lt;/code&gt; attribute contains a &lt;a href=…
1650 create a Bézier path, very similar to PostScript's operators. Librsvg
1651 has the following to represent those commands:&lt;/p&gt;
1652 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
1653 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MoveTo&lt;/…
1654 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;LineTo&lt;/…
1655 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CurveTo&lt;…
1656 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Arc&lt;/spa…
1657 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ClosePath&l…
1658 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
1659 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
1660
1661 &lt;p&gt;Those commands get stored in an array, a &lt;code&gt;Vec&lt;/co…
1662 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
1663 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;path_comman…
1664 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
1665 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
1666
1667 &lt;p&gt;Librsvg translates each of the commands inside a &lt;code&gt;&a…
1668 into a &lt;code&gt;PathCommand&lt;/code&gt; and pushes it into the &lt;c…
1669 &lt;code&gt;PathBuilder&lt;/code&gt;. When it is done parsing the attri…
1670 &lt;code&gt;PathBuilder&lt;/code&gt; remains as the final version of the…
1671 &lt;p&gt;To let a &lt;code&gt;Vec&lt;/code&gt; grow efficiently as items…
1672 it, Rust makes the &lt;code&gt;Vec&lt;/code&gt; grow by powers of 2. …
1673 the &lt;em&gt;capacity&lt;/em&gt; of the &lt;code&gt;Vec&lt;/code&gt; is…
1674 twice its capacity. That way there are only O(log₂n) calls to
1675 &lt;code&gt;realloc()&lt;/code&gt;, where &lt;code&gt;n&lt;/code&gt; is …
1676 &lt;p&gt;However, this means that once we are done adding items to the &…
1677 there may still be some free space in it: &lt;em&gt;the capacity exceed…
1678 length of the array&lt;/em&gt;. The invariant is that
1679 &lt;code&gt;vec.capacity() &amp;gt;= vec.len()&lt;/code&gt;.&lt;/p&gt;
1680 &lt;p&gt;First I wanted to shrink the &lt;code&gt;PathBuilder&lt;/code&g…
1681 capacity in the end.&lt;/p&gt;
1682 &lt;h2&gt;First step: convert to Box&amp;lt;[T]&amp;gt;&lt;/h2&gt;
1683 &lt;p&gt;A "boxed slice" is a contiguous array in the heap, that cannot …
1684 shrink. That is, it has no extra capacity, only a length.&lt;/p&gt;
1685 &lt;p&gt;&lt;code&gt;Vec&lt;/code&gt; has a method &lt;a href="https://d…
1686 eactly that: it consumes the vector and converts it into a boxed
1687 slice without extra capacity. In its innards, it does a &lt;code&gt;rea…
1688 on the &lt;code&gt;Vec&lt;/code&gt;'s buffer to match its length.&lt;/p&…
1689 &lt;p&gt;Let's see the numbers that Massif reports:&lt;/p&gt;
1690 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
1691 &lt;span class="c"&gt; n time(i) total(B) useful&lt;/s…
1692 &lt;span class="nb"&gt;-------------------------------------------------…
1693 &lt;span class="c"&gt; 23 22&lt;/span&gt;&lt;span class="nt"&gt;,&lt;/sp…
1694 &lt;span class="c"&gt; ^^^^^^^^^^^…
1695 &lt;span class="c"&gt; before&…
1696
1697 &lt;span class="c"&gt; 30 22&lt;/span&gt;&lt;span class="nt"&gt;,&lt;/sp…
1698 &lt;span class="c"&gt; ^^^^^^^^^^^…
1699 &lt;span class="c"&gt; after&l…
1700 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
1701
1702 &lt;p&gt;That is, we went from using 1,493,746,540 bytes on the heap to…
1703 1,329,943,324 bytes. Simply removing extra capacity from the path
1704 commands saves about 159 MB for this particular file.&lt;/p&gt;
1705 &lt;h2&gt;Second step: make the allocator do less work&lt;/h2&gt;
1706 &lt;p&gt;However, the &lt;code&gt;extra-heap&lt;/code&gt; column in that…
1707 like: there are 223,637,748 bytes in &lt;code&gt;malloc()&lt;/code&gt;…
1708 space in the heap.&lt;/p&gt;
1709 &lt;p&gt;I suppose that so many calls to &lt;code&gt;realloc()&lt;/code&…
1710 fragmented.&lt;/p&gt;
1711 &lt;p&gt;It would be good to be able to read most of the &lt;code&gt;&am…
1712 temporary buffers that don't need so many calls to &lt;code&gt;realloc()…
1713 that in the end get copied to exact-sized buffers, without extra
1714 capacity.&lt;/p&gt;
1715 &lt;p&gt;We can do just that with the &lt;a href="https://docs.rs/smallv…
1716 same API as &lt;code&gt;Vec&lt;/code&gt;, but it can store small arrays …
1717 stack, without an extra heap allocation. Once the capacity is full,
1718 the stack buffer "spills" into a heap buffer automatically.&lt;/p&gt;
1719 &lt;p&gt;Most of the &lt;code&gt;d&lt;/code&gt; attributes in the huge f…
1720 fewer than 32 commands. That is, if we use the following:&lt;/p&gt;
1721 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
1722 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;path_comman…
1723 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
1724 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
1725
1726 &lt;p&gt;We are saying that there can be up to 32 items in the &lt;code…
1727 without causing a heap allocation; once that is exceeded, it will work
1728 like a normal &lt;code&gt;Vec&lt;/code&gt;.&lt;/p&gt;
1729 &lt;p&gt;At the end we still do &lt;code&gt;into_boxed_slice&lt;/code&gt…
1730 independent heap allocation with an exact size.&lt;/p&gt;
1731 &lt;p&gt;This reduces the &lt;code&gt;extra-heap&lt;/code&gt; quite a bi…
1732 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
1733 &lt;span class="c"&gt; n time(i) total(B) useful&lt;/s…
1734 &lt;span class="nb"&gt;-------------------------------------------------…
1735 &lt;span class="c"&gt; 33 24&lt;/span&gt;&lt;span class="nt"&gt;,&lt;/sp…
1736 &lt;span class="c"&gt; …
1737 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
1738
1739 &lt;p&gt;Also, the total bytes shrink from 1,553,581,072 to
1740 1,416,831,176 — we have a smaller heap because there is not so much
1741 work for the allocator, and there are a lot fewer temporary blocks
1742 when parsing the &lt;code&gt;d&lt;/code&gt; attributes.&lt;/p&gt;
1743 &lt;h2&gt;Making the code prettier&lt;/h2&gt;
1744 &lt;p&gt;I put in the following:&lt;/p&gt;
1745 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
1746 &lt;span class="k"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&g…
1747 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;path_comman…
1748 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
1749
1750 &lt;span class="sd"&gt;/// This one is immutable&lt;/span&gt;
1751 &lt;span class="k"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&g…
1752 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;path_comman…
1753 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
1754
1755 &lt;span class="k"&gt;impl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&…
1756 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sd"&gt;/// Consum…
1757 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;pub&lt;/spa…
1758 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Path&lt…
1759 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pat…
1760 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/s…
1761 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&…
1762 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
1763 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
1764
1765 &lt;p&gt;With that, &lt;code&gt;PathBuilder&lt;/code&gt; is just a tempo…
1766 immutable &lt;code&gt;Path&lt;/code&gt; once we are done feeding it. &l…
1767 slice of the exact size, without any extra capacity.&lt;/p&gt;
1768 &lt;h2&gt;Next steps&lt;/h2&gt;
1769 &lt;p&gt;All the coordinates in librsvg are stored as &lt;code&gt;f64&lt…
1770 floating point numbers. The SVG/CSS spec says that single-precision
1771 floats are enough, and that 64-bit floats should be used only for
1772 geometric transformations.&lt;/p&gt;
1773 &lt;p&gt;I'm a bit scared to make that change; I'll have to look closely…
1774 results of the test suite to see if rendered files change very much.
1775 I suppose even big maps require only as much precision as &lt;code&gt;f3…
1776 after all, that is what OpenStreetMap uses.&lt;/p&gt;
1777 &lt;h2&gt;References&lt;/h2&gt;
1778 &lt;ul&gt;
1779 &lt;li&gt;&lt;a href="https://gitlab.gnome.org/GNOME/librsvg/-/commit/fc…
1780 Box&amp;lt;[T]&amp;gt;&lt;/a&gt;&lt;/li&gt;
1781 &lt;li&gt;&lt;a href="https://gitlab.gnome.org/GNOME/librsvg/-/commit/ee…
1782 &lt;/ul&gt;</content><category term="misc"></category><category term="li…
1783 librsvg's DOM nodes smaller in memory. Since that time, there have
1784 been some changes to the code; that is why in this post some of the
1785 type names are different from last time's.&lt;/p&gt;
1786 &lt;p&gt;Every SVG element is represented with …&lt;/p&gt;</summary><c…
1787 librsvg's DOM nodes smaller in memory. Since that time, there have
1788 been some changes to the code; that is why in this post some of the
1789 type names are different from last time's.&lt;/p&gt;
1790 &lt;p&gt;Every SVG element is represented with this struct:&lt;/p&gt;
1791 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
1792 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;element_typ…
1793 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;element_nam…
1794 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span…
1795 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;class&lt;/s…
1796 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;specified_v…
1797 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;important_s…
1798 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;result&lt;/…
1799 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;transform&l…
1800 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;values&lt;/…
1801 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cond&lt;/sp…
1802 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;style_attr&…
1803 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;element_imp…
1804 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
1805 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
1806
1807 &lt;p&gt;The two biggest fields are the ones with types &lt;code&gt;Spec…
1808 &lt;code&gt;ComputedValues&lt;/code&gt;. These are the sizes of the who…
1809 and those two types:&lt;/p&gt;
1810 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
1811 sizeof SpecifiedValues: 824
1812 sizeof ComputedValues: 704
1813 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
1814
1815 &lt;p&gt;In this post, we'll reduce the size of &lt;code&gt;SpecifiedVal…
1816 &lt;h2&gt;What is SpecifiedValues?&lt;/h2&gt;
1817 &lt;p&gt;If we have an element like this:&lt;/p&gt;
1818 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
1819 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
1820
1821 &lt;p&gt;The values of the style properties &lt;code&gt;stroke-width&lt;…
1822 stored in a &lt;code&gt;SpecifiedValues&lt;/code&gt; struct. This struc…
1823 fields, one for each possible style property:&lt;/p&gt;
1824 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
1825 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;baseline_sh…
1826 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;clip_path&l…
1827 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;clip_rule&l…
1828 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sd"&gt;/// ...&lt…
1829 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stroke&lt;/…
1830 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stroke_widt…
1831 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sd"&gt;/// ...&lt…
1832 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
1833 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
1834
1835 &lt;p&gt;Each field is a &lt;code&gt;SpecifiedValue&amp;lt;T&amp;gt;&lt;…
1836 CSS/SVG, a style property can be unspecified, or it can have an
1837 &lt;code&gt;inherit&lt;/code&gt; value to force the property to be copie…
1838 parent, or it can actually have a specified value. Librsvg represents
1839 these as follows:&lt;/p&gt;
1840 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
1841 &lt;span class="k"&gt;where&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&…
1842 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&…
1843 &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
1844 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Unspecified…
1845 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Inherit&lt;…
1846 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Specified&l…
1847 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
1848 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
1849
1850 &lt;p&gt;Now, &lt;code&gt;SpecifiedValues&lt;/code&gt; has a bunch of fi…
1851 one for each of the style properties that librsvg supports. That is
1852 why &lt;code&gt;SpecifiedValues&lt;/code&gt; has a size of 824 bytes; i…
1853 sub-structure within &lt;code&gt;Element&lt;/code&gt;, and it would be g…
1854 size.&lt;/p&gt;
1855 &lt;h2&gt;Not all properties are specified&lt;/h2&gt;
1856 &lt;p&gt;Let's go back to the chunk of SVG from above:&lt;/p&gt;
1857 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
1858 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
1859
1860 &lt;p&gt;Here we only have two specified properties, so the &lt;code&gt;…
1861 &lt;code&gt;stroke&lt;/code&gt; fields of &lt;code&gt;SpecifiedValues&lt…
1862 &lt;code&gt;SpecifiedValue::Specified(something)&lt;/code&gt; and all th…
1863 be left as &lt;code&gt;SpecifiedValue::Unspecified&lt;/code&gt;.&lt;/p&g…
1864 &lt;p&gt;It would be good to store only complete values for the properti…
1865 are specified, and just a small flag for unset properties.&lt;/p&gt;
1866 &lt;h2&gt;Another way to represent the set of properties&lt;/h2&gt;
1867 &lt;p&gt;Since there is a maximum of 47 properties per element (or more…
1868 librsvg adds support for extra ones), we can have a small array of
1869 47 bytes. Each byte contains the index within another array that
1870 contains only the values of specified properties, or a sentinel value
1871 for properties that are unset.&lt;/p&gt;
1872 &lt;p&gt;First, I made an enum that fits in a &lt;code&gt;u8&lt;/code&gt…
1873 the sentinel value, which also gives us the total number of
1874 properties. The &lt;code&gt;#[repr(u8)]&lt;/code&gt; guarantees that th…
1875 byte.&lt;/p&gt;
1876 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
1877 &lt;span class="k"&gt;enum&lt;/span&gt; &lt;span class="nc"&gt;PropertyI…
1878 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;BaselineShi…
1879 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ClipPath&lt…
1880 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ClipRule&lt…
1881 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Color&lt;/s…
1882 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// ...&lt;…
1883 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;WritingMode…
1884 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;XmlLang&lt;…
1885 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;XmlSpace&lt…
1886 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;UnsetProper…
1887 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
1888 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
1889
1890 &lt;p&gt;Also, since before these changes there was the following monste…
1891 represent "which property is this" plus the property's value:&lt;/p&gt;
1892 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
1893 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;BaselineShi…
1894 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ClipPath&lt…
1895 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ClipRule&lt…
1896 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Color&lt;/s…
1897 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// ...&lt;…
1898 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
1899 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
1900
1901 &lt;p&gt;I changed the definition of &lt;code&gt;SpecifiedValues&lt;/cod…
1902 to store which properties are specified, and another only with the
1903 values for the properties that are actually specified:&lt;/p&gt;
1904 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
1905 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;indices&lt;…
1906 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;props&lt;/s…
1907 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
1908 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
1909
1910 &lt;p&gt;There is a thing that is awkward in Rust, or which I haven't fo…
1911 to solve in a nicer way: given a &lt;code&gt;ParsedProperty&lt;/code&gt…
1912 corresponding &lt;code&gt;PropertyId&lt;/code&gt; for its discriminant. …
1913 thing:&lt;/p&gt;
1914 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
1915 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span…
1916 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;use&lt;…
1917
1918 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;match&l…
1919 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Bas…
1920 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Cli…
1921 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Cli…
1922 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Col…
1923 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;//…
1924 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/s…
1925 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&…
1926 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
1927 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
1928
1929 &lt;h2&gt;Initialization&lt;/h2&gt;
1930 &lt;p&gt;First, we want to initialize an empty &lt;code&gt;SpecifiedValu…
1931 element of the the &lt;code&gt;indices&lt;/code&gt; array is set to the …
1932 means that the corresponding property is not set:&lt;/p&gt;
1933 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
1934 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span…
1935 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Specifi…
1936 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ind…
1937 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pro…
1938 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/s…
1939 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&…
1940 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
1941 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
1942
1943 &lt;p&gt;That sets the &lt;code&gt;indices&lt;/code&gt; field to an arra…
1944 &lt;code&gt;PropertyId::UnsetProperty&lt;/code&gt; sentinel value. Also…
1945 is empty; it hasn't even had a block of memory allocated for it yet.
1946 That way, SVG elements without style properties don't use any extra
1947 memory.&lt;/p&gt;
1948 &lt;h2&gt;Which properties are specified and what are their indices?&lt;…
1949 &lt;p&gt;Second, we want a function that will give us the index in &lt;c…
1950 some property, or that will tell us if the property has not been set
1951 yet:&lt;/p&gt;
1952 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
1953 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span…
1954 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;let&lt…
1955
1956 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/…
1957 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;No…
1958 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/s…
1959 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;So…
1960 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/s…
1961 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&…
1962 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
1963 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
1964
1965 &lt;p&gt;(If someone passes &lt;code&gt;id = PropertyId::UnsetProperty&l…
1966 to &lt;code&gt;indices&lt;/code&gt; will panic, which is what we want, s…
1967 valid property id.)&lt;/p&gt;
1968 &lt;h2&gt;Change a property's value&lt;/h2&gt;
1969 &lt;p&gt;Third, we want to set the value of a property that has not been…
1970 or change the value of one that was already specified:&lt;/p&gt;
1971 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
1972 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span…
1973 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;let&lt…
1974
1975 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/…
1976 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="bp"&gt;se…
1977 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/s…
1978 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="bp"&gt;se…
1979 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;le…
1980 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="bp"&gt;se…
1981 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/s…
1982 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&…
1983 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
1984 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
1985
1986 &lt;p&gt;In the first case in the &lt;code&gt;if&lt;/code&gt;, the prope…
1987 just replace its value. In the second case, the property was not set;
1988 we add it to the &lt;code&gt;props&lt;/code&gt; array and store its resu…
1989 &lt;code&gt;indices&lt;/code&gt;.&lt;/p&gt;
1990 &lt;h2&gt;Results&lt;/h2&gt;
1991 &lt;p&gt;Before:&lt;/p&gt;
1992 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
1993 sizeof SpecifiedValues: 824
1994 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
1995
1996 &lt;p&gt;After:&lt;/p&gt;
1997 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
1998 sizeof SpecifiedValues: 72
1999 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
2000
2001 &lt;p&gt;The pathological file &lt;a href="https://gitlab.gnome.org/GNOM…
2002 463,412,720 bytes in memory before these changes. After the changes,
2003 it uses 314,526,136 bytes.&lt;/p&gt;
2004 &lt;p&gt;I also measured memory consumption for a normal file, in this c…
2005 &lt;a href="https://gitlab.gnome.org/Teams/Design/icon-development-kit/-…
2006 uses 17 MB; the new version only 13 MB.&lt;/p&gt;
2007 &lt;h2&gt;How to keep fine-tuning this&lt;/h2&gt;
2008 &lt;p&gt;For now, I am satisfied with &lt;code&gt;SpecifiedValues&lt;/co…
2009 still be made smaller:&lt;/p&gt;
2010 &lt;ul&gt;
2011 &lt;li&gt;
2012 &lt;p&gt;The crate &lt;a href="https://lib.rs/crates/tagged-box"&gt;tagg…
2013 an enum-of-boxes, and codifies the enum's discriminant into the
2014 box's pointer. This way each variant occupies the minimum possible
2015 memory, although in a separately-allocated block, and the container
2016 itself uses only a pointer. I am not sure if this is worth it; each
2017 &lt;code&gt;ParsedProperty&lt;/code&gt; is 64 bytes, but the flat arr…
2018 Vec&amp;lt;ParsedProperty&amp;gt;&lt;/code&gt; is very appealing in a …
2019 I have not checked the sizes of each individual property to see if
2020 they vary a lot among them.&lt;/p&gt;
2021 &lt;/li&gt;
2022 &lt;li&gt;
2023 &lt;p&gt;Look for a crate that lets us have the properties in a single m…
2024 block, a kind of arena with variable types. This can be implemented
2025 with a bit of &lt;code&gt;unsafe&lt;/code&gt;, but one has to be caref…
2026 of different types.&lt;/p&gt;
2027 &lt;/li&gt;
2028 &lt;li&gt;
2029 &lt;p&gt;The crate &lt;a href="https://lib.rs/crates/enum_set2"&gt;enum_…
2030 compact bit array. If we changed the representation of
2031 &lt;code&gt;SpecifiedValue&lt;/code&gt;, this would reduce the &lt;cod…
2032 minimum.&lt;/p&gt;
2033 &lt;/li&gt;
2034 &lt;/ul&gt;
2035 &lt;p&gt;If someone wants to dedicate some time to implement and measure…
2036 I would be very grateful.&lt;/p&gt;
2037 &lt;h2&gt;Next steps&lt;/h2&gt;
2038 &lt;p&gt;According to Massif, the next thing is to keep making &lt;code&…
2039 smaller. The next thing to shrink is &lt;code&gt;ComputedValues&lt;/cod…
2040 route is to do exactly the same as I did for &lt;code&gt;SpecifiedValues…
2041 not sure if it would be better to try to &lt;a href="https://gitlab.gnom…
2042 structs&lt;/a&gt; between elements.&lt;/p&gt;</content><category term="m…
2043 willing to mentor the following project for librsvg.&lt;/p&gt;
2044 &lt;h2&gt;Project: Revamp the text engine in librsvg&lt;/h2&gt;
2045 &lt;p&gt;Librsvg supports only a few features of the &lt;a href="https:/…
2046 specification&lt;/a&gt;. It requires
2047 extra features to be really useful:&lt;/p&gt;
2048 &lt;ul&gt;
2049 &lt;li&gt;
2050 &lt;p&gt;&lt;strong&gt;Proper bidirectional support …&lt;/strong&gt;&l…
2051 willing to mentor the following project for librsvg.&lt;/p&gt;
2052 &lt;h2&gt;Project: Revamp the text engine in librsvg&lt;/h2&gt;
2053 &lt;p&gt;Librsvg supports only a few features of the &lt;a href="https:/…
2054 specification&lt;/a&gt;. It requires
2055 extra features to be really useful:&lt;/p&gt;
2056 &lt;ul&gt;
2057 &lt;li&gt;
2058 &lt;p&gt;&lt;strong&gt;Proper bidirectional support.&lt;/strong&gt; Lib…
2059 &lt;code&gt;unicode-bidi&lt;/code&gt; properties for text elements, amon…
2060 very rudimentary fashion. It just translates those properties to
2061 Pango terminology and asks &lt;code&gt;PangoLayout&lt;/code&gt; to lay o…
2062 really wants finer control of that, for which...&lt;/p&gt;
2063 &lt;/li&gt;
2064 &lt;li&gt;
2065 &lt;p&gt;... ideally you would make librsvg &lt;strong&gt;use Harfbuzz d…
2066 wrapper that is close to its level of operation. Pango is a bit too high
2067 level for the needs of SVG.&lt;/p&gt;
2068 &lt;/li&gt;
2069 &lt;li&gt;
2070 &lt;p&gt;Manual layout of text glyphs. After a text engine like Harfbuzz
2071 does the shaping, librsvg would need to lay out the produced glyphs in
2072 the way of the SVG attributes &lt;code&gt;dx, dy, x, y&lt;/code&gt;, etc…
2073 specification has the algorithms for this.&lt;/p&gt;
2074 &lt;/li&gt;
2075 &lt;li&gt;
2076 &lt;p&gt;The cherry on top: text-on-a-path. Again, the spec has the det…
2077 You would make Wikimedia content creators very happy with this!&lt;/p&gt;
2078 &lt;/li&gt;
2079 &lt;/ul&gt;
2080 &lt;p&gt;&lt;strong&gt;Requirements:&lt;/strong&gt; Rust for programming…
2081 Unicode concepts and text layout. Familiarity with Cairo and Harfbuzz
2082 would help a lot. Preference will be given to people who can write a
2083 right-to-left human language, &lt;strong&gt;or&lt;/strong&gt; a language…
2084 shaping.&lt;/p&gt;
2085 &lt;p&gt;&lt;a href="https://wiki.gnome.org/Outreach/SummerOfCode/Studen…
2086 use cases, which is basically rendering icons. But for SVG files with
2087 thousands of elements, it could do a lot better.&lt;/p&gt;
2088 &lt;h2&gt;Memory consumption in the DOM&lt;/h2&gt;
2089 &lt;p&gt;Librsvg shares some common problems with web browsers: it must
2090 construct a …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Librsvg…
2091 use cases, which is basically rendering icons. But for SVG files with
2092 thousands of elements, it could do a lot better.&lt;/p&gt;
2093 &lt;h2&gt;Memory consumption in the DOM&lt;/h2&gt;
2094 &lt;p&gt;Librsvg shares some common problems with web browsers: it must
2095 construct a DOM tree in memory with SVG elements, and keep a bunch of
2096 information for each of the tree's nodes. For example, each SVG
2097 element may have an &lt;code&gt;id&lt;/code&gt; attribute, or a &lt;code…
2098 transformation matrix; etc.&lt;/p&gt;
2099 &lt;p&gt;Apart from the tree node metadata (pointers to sibling and pare…
2100 nodes), each node has this:&lt;/p&gt;
2101 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
2102 &lt;span class="k"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&g…
2103 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;node_type&l…
2104 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;element_nam…
2105 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span…
2106 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;class&lt;/s…
2107 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;specified_v…
2108 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;important_s…
2109 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;result&lt;/…
2110 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;transform&l…
2111 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;values&lt;/…
2112 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cond&lt;/sp…
2113 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;style_attr&…
2114
2115 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;node_impl&l…
2116 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
2117 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
2118
2119 &lt;p&gt;On a 64-bit box, that &lt;code&gt;NodeData&lt;/code&gt; struct …
2120 are the &lt;code&gt;SpecifiedValues&lt;/code&gt; (824 bytes) and &lt;c…
2121 &lt;p&gt;Librsvg represents &lt;em&gt;all&lt;/em&gt; tree nodes with tha…
2122 like this:&lt;/p&gt;
2123 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
2124 &lt;span class="nt"&gt;&amp;lt;rect&lt;/span&gt; &lt;span class="na"&g…
2125 &lt;span class="nt"&gt;&amp;lt;path&lt;/span&gt; &lt;span class="na"&g…
2126 &lt;span class="nt"&gt;&amp;lt;text&lt;/span&gt; &lt;span class="na"&g…
2127 &lt;span class="c"&gt;&amp;lt;!-- etc --&amp;gt;&lt;/span&gt;
2128 &lt;span class="nt"&gt;&amp;lt;/svg&amp;gt;&lt;/span&gt;
2129 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
2130
2131 &lt;p&gt;There are 4 elements in that file. However, there are also tr…
2132 for the XML text nodes, that is, the whitespace between tags and the
2133 "&lt;code&gt;Hello&lt;/code&gt;" inside the &lt;code&gt;&amp;lt;text&amp…
2134 &lt;p&gt;The contents of each of those text nodes is tiny (a newline and…
2135 a couple of spaces), but each node still takes up at least 1808 bytes
2136 from the &lt;code&gt;NodeData&lt;/code&gt; struct, plus the size of the …
2137 &lt;p&gt;Let's refactor this to make it easier to remove that overhead.&…
2138 &lt;h2&gt;First step: separate text nodes from element nodes&lt;/h2&gt;
2139 &lt;p&gt;Internally, librsvg represents XML text nodes with a &lt;code&g…
2140 which is basically a string with some extra stuff. All the concrete
2141 structs for tree node types must implement a trait called &lt;code&gt;No…
2142 and &lt;code&gt;NodeChars&lt;/code&gt; is no exception:&lt;/p&gt;
2143 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
2144 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// a string…
2145 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
2146
2147 &lt;span class="k"&gt;impl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&…
2148 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// a mostly…
2149 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
2150 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
2151
2152 &lt;p&gt;You don't see it in the definition of &lt;code&gt;NodeData&lt;/…
2153 section, but for a text node, the &lt;code&gt;NodeData.node_impl&lt;/cod…
2154 point to a heap-allocated &lt;code&gt;NodeChars&lt;/code&gt; (it can do …
2155 &lt;code&gt;NodeChars&lt;/code&gt; implements &lt;code&gt;NodeTrait&lt;/…
2156 Box&amp;lt;dyn NodeTrait&amp;gt;&lt;/code&gt;).&lt;/p&gt;
2157 &lt;p&gt;First, I turned the &lt;code&gt;NodeData&lt;/code&gt; struct in…
2158 and moved all of its previous fields to an &lt;code&gt;Element&lt;/code&…
2159 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
2160 &lt;span class="k"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&g…
2161 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Element&lt;…
2162 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Text&lt;/sp…
2163 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
2164
2165 &lt;span class="c1"&gt;// This is the old struct with a different name&l…
2166 &lt;span class="k"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&g…
2167 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;node_type&l…
2168 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;element_nam…
2169 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span…
2170 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;class&lt;/s…
2171 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;specified_v…
2172 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;important_s…
2173 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;result&lt;/…
2174 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;transform&l…
2175 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;values&lt;/…
2176 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cond&lt;/sp…
2177 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;style_attr&…
2178 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;node_impl&l…
2179 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
2180 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
2181
2182 &lt;p&gt;The size of a Rust enum is the maximum of the sizes of its vari…
2183 plus a little extra for the discriminant (you can think of a C struct
2184 with an int for the discriminant, and a union of variants).&lt;/p&gt;
2185 &lt;p&gt;The code &lt;a href="https://gitlab.gnome.org/GNOME/librsvg/-/c…
2186 changes&lt;/a&gt;
2187 to split &lt;code&gt;NodeData&lt;/code&gt; in this way, by adding access…
2188 functions to each of the &lt;code&gt;Element&lt;/code&gt; or &lt;code&gt…
2189 is one of those refactors where you can just change the declaration,
2190 and walk down the compiler's errors to make each case use the accesors
2191 instead of whatever was done before.&lt;/p&gt;
2192 &lt;h2&gt;Second step: move the Element variant to a separate allocation…
2193 &lt;p&gt;Now, &lt;a href="https://gitlab.gnome.org/GNOME/librsvg/-/commi…
2194 this&lt;/a&gt;:&lt;/p&gt;
2195 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
2196 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Element&lt;…
2197 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Text&lt;/sp…
2198 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
2199 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
2200
2201 &lt;p&gt;That way, the &lt;code&gt;Element&lt;/code&gt; variant is the s…
2202 pointer to the heap-allocated &lt;code&gt;Box&lt;/code&gt;), and the &lt…
2203 as &lt;code&gt;NodeChars&lt;/code&gt; as usual.&lt;/p&gt;
2204 &lt;p&gt;This means that &lt;code&gt;Element&lt;/code&gt; nodes are just…
2205 extra pointer, plus an extra heap allocation.&lt;/p&gt;
2206 &lt;p&gt;However, the &lt;code&gt;Text&lt;/code&gt; nodes get a lot smal…
2207 &lt;ul&gt;
2208 &lt;li&gt;Before: &lt;code&gt;sizeof::&amp;lt;NodeData&amp;gt;() = 1808&…
2209 &lt;li&gt;After: &lt;code&gt;sizeof::&amp;lt;NodeData&amp;gt;() = 72&lt;…
2210 &lt;/ul&gt;
2211 &lt;p&gt;By making the &lt;code&gt;Element&lt;/code&gt; variant a lot sm…
2212 which is just a pointer), it has no extra overhead on the &lt;code&gt;Te…
2213 variant.&lt;/p&gt;
2214 &lt;p&gt;This means that in the SVG file, all the whitespace between XML
2215 elements now takes a lot less memory.&lt;/p&gt;
2216 &lt;h2&gt;Some numbers from a pathological file&lt;/h2&gt;
2217 &lt;p&gt;&lt;a href="https://gitlab.gnome.org/GNOME/librsvg/issues/42"&g…
2218 an SVG file that is just a &lt;code&gt;&amp;lt;use&amp;gt;&lt;/code&gt; …
2219 per line:&lt;/p&gt;
2220 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
2221 &lt;span class="nt"&gt;&amp;lt;defs&amp;gt;&lt;/span&gt;
2222 &lt;span class="nt"&gt;&amp;lt;symbol&lt;/span&gt; &lt;span class="n…
2223 &lt;span class="c"&gt;&amp;lt;!-- a few elements here --&amp;gt;&l…
2224 &lt;span class="nt"&gt;&amp;lt;/symbol&amp;gt;&lt;/span&gt;
2225 &lt;span class="nt"&gt;&amp;lt;/defs&amp;gt;&lt;/span&gt;
2226
2227 &lt;span class="nt"&gt;&amp;lt;use&lt;/span&gt; &lt;span class="na"&gt…
2228 &lt;span class="nt"&gt;&amp;lt;use&lt;/span&gt; &lt;span class="na"&gt…
2229 &lt;span class="nt"&gt;&amp;lt;use&lt;/span&gt; &lt;span class="na"&gt…
2230 &lt;span class="c"&gt;&amp;lt;!-- about 196,000 similar lines --&amp;g…
2231 &lt;span class="nt"&gt;&amp;lt;/svg&amp;gt;&lt;/span&gt;
2232 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
2233
2234 &lt;p&gt;So we have around 196,000 elements. According to &lt;a href="h…
2235 tool&lt;/a&gt;, this makes &lt;code&gt;rsvg-convert&lt;/code&gt; allocat…
2236 old version, versus 463,412,720 bytes in the new version, or about 60%
2237 of the space.&lt;/p&gt;
2238 &lt;h2&gt;Next steps&lt;/h2&gt;
2239 &lt;p&gt;There is a lot of repetition in the text nodes of a typical SVG…
2240 For example, in that pathological file above, most of the whitespace is
2241 identical: between each element there is a newline and two spaces.
2242 Instead of having thousands of little allocations, all with the same
2243 string, there could be a pool of shared strings. Files with "real"
2244 indentation could get benefits from sharing the whitespace-only text
2245 nodes.&lt;/p&gt;
2246 &lt;p&gt;Real browser engines are very careful to share the style structs
2247 across elements if possible. Look for "style struct sharing" in
2248 &lt;a href="https://hacks.mozilla.org/2017/08/inside-a-super-fast-css-en…
2249 going to take some good work in librsvg, but we can get there
2250 gradually.&lt;/p&gt;
2251 &lt;h2&gt;References&lt;/h2&gt;
2252 &lt;ul&gt;
2253 &lt;li&gt;&lt;a href="https://gitlab.gnome.org/GNOME/librsvg/-/merge_req…
2254 refactoring&lt;/a&gt;&lt;/li&gt;
2255 &lt;li&gt;&lt;a href="https://gitlab.gnome.org/GNOME/librsvg/-/commit/74…
2256 Text&lt;/a&gt;&lt;/li&gt;
2257 &lt;li&gt;&lt;a href="https://gitlab.gnome.org/GNOME/librsvg/-/commit/83…
2258 smaller&lt;/a&gt;.
2259 The commit message has parts of the massif log with all the
2260 interesting numbers.&lt;/li&gt;
2261 &lt;li&gt;&lt;a href="https://gitlab.gnome.org/GNOME/librsvg/issues/528"…
2262 consumption&lt;/a&gt;&lt;/li&gt;
2263 &lt;/ul&gt;</content><category term="misc"></category><category term="li…
2264 to other languages through &lt;a href="https://people.gnome.org/~federic…
2265 &lt;p&gt;You could call this a use of the &lt;a href="https://en.wikiped…
2266 &lt;a href="https://gnome.pages.gitlab.gnome.org/librsvg/doc/rsvg_intern…
2267 implementation of librsvg, and exports an …&lt;/p&gt;</summary><conten…
2268 to other languages through &lt;a href="https://people.gnome.org/~federic…
2269 &lt;p&gt;You could call this a use of the &lt;a href="https://en.wikiped…
2270 &lt;a href="https://gnome.pages.gitlab.gnome.org/librsvg/doc/rsvg_intern…
2271 implementation of librsvg, and exports an interface with many knobs
2272 that are not exposed from the public APIs. The knobs are to allow for
2273 the variations in each of those APIs.&lt;/p&gt;
2274 &lt;p&gt;This post is about some interesting things that have come up du…
2275 the creation/separation of those public APIs, and the implications of
2276 having an internals library that implements both.&lt;/p&gt;
2277 &lt;h2&gt;Initial code organization&lt;/h2&gt;
2278 &lt;p&gt;When librsvg was being ported to Rust, it just had an &lt;code&…
2279 crate that compiled as a &lt;code&gt;staticlib&lt;/code&gt; to a &lt;cod…
2280 later linked into the final &lt;code&gt;librsvg.so&lt;/code&gt;.&lt;/p&g…
2281 &lt;p&gt;Eventually the code got to the point where it was feasible to p…
2282 toplevel C API to Rust. This was relatively easy to do, since
2283 everything else underneath was already in Rust. At that point I
2284 became interested &lt;a href="https://people.gnome.org/~federico/blog/a-…
2285 first to port the test suite to Rust and be able to run tests in
2286 parallel, and then to actually have a public API in Rust with more
2287 modern idioms than the historical, GObject-based API in C.&lt;/p&gt;
2288 &lt;p&gt;Version &lt;a href="https://gitlab.gnome.org/GNOME/librsvg/-/ta…
2289 a C API.&lt;/p&gt;
2290 &lt;p&gt;Most of the C API of librsvg is in the &lt;code&gt;RsvgHandle&l…
2291 &lt;code&gt;RsvgHandle&lt;/code&gt; gets loaded with SVG data from a fil…
2292 then gets rendered to a Cairo context. The naming of Rust source
2293 files more or less matched the C source files, so where there was
2294 &lt;code&gt;rsvg-handle.c&lt;/code&gt; initially, later we had &lt;code&…
2295 part of that code.&lt;/p&gt;
2296 &lt;p&gt;So, &lt;code&gt;handle.rs&lt;/code&gt; had the Rust internals o…
2297 a bunch of &lt;code&gt;extern "C"&lt;/code&gt; functions callable from C…
2298 this function in the public C API:&lt;/p&gt;
2299 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
2300 &lt;span class="n"&gt;GFile&lt;/span&gt…
2301 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
2302
2303 &lt;p&gt;The corresponding Rust implementation &lt;a href="https://gitla…
2304 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
2305 &lt;span class="k"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&g…
2306 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;raw_handle&…
2307 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;raw_gfile&l…
2308 &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;…
2309 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/sp…
2310
2311 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="fm"&gt;assert!&lt…
2312 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/sp…
2313
2314 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rhandle&lt;…
2315 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
2316 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
2317
2318 &lt;ol&gt;
2319 &lt;li&gt;Get the Rust struct corresponding to the C GObject.&lt;/li&gt;
2320 &lt;li&gt;Check the arguments.&lt;/li&gt;
2321 &lt;li&gt;Convert from C GObject reference to Rust reference.&lt;/li&gt;
2322 &lt;li&gt;Call the actual implementation of &lt;code&gt;set_base_gfile&l…
2323 struct.&lt;/li&gt;
2324 &lt;/ol&gt;
2325 &lt;p&gt;You can see that this function takes in arguments with C types,…
2326 converts them to Rust types. It's basically just glue between the C
2327 code and the actual implementation.&lt;/p&gt;
2328 &lt;p&gt;Then, the actual implementation of &lt;code&gt;set_base_gfile&l…
2329 this&lt;/a&gt;:&lt;/p&gt;
2330 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
2331 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span…
2332 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/…
2333 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="bp"&gt;se…
2334 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/s…
2335 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rsv…
2336 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/s…
2337 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&…
2338 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
2339 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
2340
2341 &lt;p&gt;This is an actual method for a Rust &lt;code&gt;Handle&lt;/code…
2342 types as arguments — no conversions are necessary here. However,
2343 there is a pesky call to &lt;code&gt;rsvg_g_warning&lt;/code&gt;, about …
2344 &lt;p&gt;I found it cleanest, although not the shortest code, to structu…
2345 things like this:&lt;/p&gt;
2346 &lt;ul&gt;
2347 &lt;li&gt;
2348 &lt;p&gt;C code: bunch of stub functions where &lt;code&gt;rsvg_blah&lt;…
2349 corresponding &lt;code&gt;rsvg_rust_blah&lt;/code&gt;.&lt;/p&gt;
2350 &lt;/li&gt;
2351 &lt;li&gt;
2352 &lt;p&gt;Toplevel Rust code: bunch of &lt;code&gt;#[no_mangle] unsafe ex…
2353 convert from C argument types to Rust types, and call safe Rust
2354 functions — for librsvg, these happened to be methods for a struct.
2355 Before returning, the toplevel functions convert Rust return values
2356 to C return values, and do things like converting the &lt;code&gt;Err(…
2357 &lt;code&gt;Result&amp;lt;&amp;gt;&lt;/code&gt; into a &lt;code&gt;GEr…
2358 C API required.&lt;/p&gt;
2359 &lt;/li&gt;
2360 &lt;/ul&gt;
2361 &lt;p&gt;In the very first versions of the code where the public API was
2362 implemented in Rust, the &lt;code&gt;extern "C"&lt;/code&gt; functions a…
2363 their implementation. However, after some refactoring, it turned out
2364 to be cleaner to leave those functions just with the task of
2365 converting C to Rust types and vice-versa, and put the actual
2366 implementation in very Rust-y code. This made it easier to keep the
2367 &lt;code&gt;unsafe&lt;/code&gt; conversion code (unsafe because it deals…
2368 coming from C) only in the toplevel functions.&lt;/p&gt;
2369 &lt;h2&gt;Growing out a Rust API&lt;/h2&gt;
2370 &lt;p&gt;&lt;a href="https://gitlab.gnome.org/GNOME/librsvg/commit/cd848…
2371 started. That commit just created a &lt;a href="https://doc.rust-lang.o…
2372 with two crates; the &lt;code&gt;rsvg_internals&lt;/code&gt; crate that …
2373 &lt;code&gt;librsvg_crate&lt;/code&gt; with the public Rust API.&lt;/p&g…
2374 &lt;p&gt;The commits over the subsequent couple of months are of intense
2375 refactoring:&lt;/p&gt;
2376 &lt;ul&gt;
2377 &lt;li&gt;
2378 &lt;p&gt;&lt;a href="https://gitlab.gnome.org/GNOME/librsvg/commit/d01f7…
2379 functions to a separate &lt;code&gt;c_api.rs&lt;/code&gt; source file.…
2380 &lt;code&gt;handle.rs&lt;/code&gt; with only the safe Rust implementat…
2381 API, and &lt;code&gt;c_api.rs&lt;/code&gt; with the unsafe entry point…
2382 convert argument types, return values, and errors.&lt;/p&gt;
2383 &lt;/li&gt;
2384 &lt;li&gt;
2385 &lt;p&gt;The API primitives get expanded to allow for a public Rust API …
2386 is "hard to misuse" unlike the C API, which needs to be called
2387 in a certain order.&lt;/p&gt;
2388 &lt;/li&gt;
2389 &lt;/ul&gt;
2390 &lt;h2&gt;Needing to call a C macro&lt;/h2&gt;
2391 &lt;p&gt;However, there was a little problem. The Rust code cannot call
2392 &lt;a href="https://developer.gnome.org/glib/stable/glib-Message-Logging…
2393 stderr or uses structured logging. Librsvg used that to signal
2394 conditions where something went (recoverably) wrong, but there was no
2395 way to return a proper error code to the caller — it's mainly used as
2396 a debugging aid.&lt;/p&gt;
2397 &lt;p&gt;This is what the &lt;code&gt;rsvg_internals&lt;/code&gt; used t…
2398 &lt;p&gt;First, the C code exports a function that just calls the macro:…
2399 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
2400 &lt;span class="cm"&gt; * since glib-rs doesn&amp;#39;t bind the g_log f…
2401 &lt;span class="cm"&gt; */&lt;/span&gt;
2402 &lt;span class="kt"&gt;void&lt;/span&gt;
2403 &lt;span class="nf"&gt;rsvg_g_warning_from_c&lt;/span&gt;&lt;span class=…
2404 &lt;span class="p"&gt;{&lt;/span&gt;
2405 &lt;span class="n"&gt;g_warning&lt;/span&gt; &lt;span class="p"&gt;(…
2406 &lt;span class="p"&gt;}&lt;/span&gt;
2407 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
2408
2409 &lt;p&gt;Second, the Rust code binds that function to be callable from R…
2410 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
2411 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;extern&lt;/…
2412 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/…
2413 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&…
2414
2415 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;unsafe&lt;/…
2416 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rsvg_g_…
2417 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&…
2418 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
2419 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
2420
2421 &lt;p&gt;However! Since the standalone &lt;code&gt;librsvg_crate&lt;/co…
2422 code from the public &lt;code&gt;librsvg.so&lt;/code&gt;, the helper &lt…
2423 is not available!&lt;/p&gt;
2424 &lt;h3&gt;A configuration feature for the internals library&lt;/h3&gt;
2425 &lt;p&gt;And yet! Those warnings are only meaningful for the C API, whi…
2426 not able to return error codes from all situations. However, the Rust
2427 API &lt;em&gt;is&lt;/em&gt; able to do that, and so doesn't need the war…
2428 stderr. My first solution was to add a build-time option for whether
2429 the &lt;code&gt;rsvg_internals&lt;/code&gt; library is being build for t…
2430 the Rust one.&lt;/p&gt;
2431 &lt;p&gt;In case we are building for the C library, the code calls
2432 &lt;code&gt;rsvg_g_warning_from_c&lt;/code&gt; as usual.&lt;/p&gt;
2433 &lt;p&gt;But in case we are building for the Rust library, that code is a
2434 no-op.&lt;/p&gt;
2435 &lt;p&gt;This is the &lt;a href="https://gitlab.gnome.org/GNOME/librsvg/…
2436 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
2437 &lt;span class="c1"&gt;# Enables calling g_warning() when built as part …
2438 &lt;span class="n"&gt;c-library&lt;/span&gt; &lt;span class="o"&gt;=&lt;…
2439 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
2440
2441 &lt;p&gt;And &lt;a href="https://gitlab.gnome.org/GNOME/librsvg/blob/4df…
2442 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
2443 &lt;span class="k"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&g…
2444 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;unsafe&lt;/…
2445 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;extern&…
2446 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;fn&…
2447 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/s…
2448
2449 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rsvg_g_…
2450 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&…
2451 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
2452
2453 &lt;span class="cp"&gt;#[cfg(not(feature = &lt;/span&gt;&lt;span class="…
2454 &lt;span class="k"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&g…
2455 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// The onl…
2456 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// are cal…
2457 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// meaning…
2458 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// g_warni…
2459 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
2460 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
2461
2462 &lt;p&gt;The first function is the one that is compiled when the &lt;cod…
2463 feature is enabled; this happens when building &lt;code&gt;rsvg_internal…
2464 link into &lt;code&gt;librsvg.so&lt;/code&gt;.&lt;/p&gt;
2465 &lt;p&gt;The second function does nothing; it is what is compiled when
2466 &lt;code&gt;rsvg_internals&lt;/code&gt; is being used just from the &lt;…
2467 with the Rust API.&lt;/p&gt;
2468 &lt;p&gt;While this worked well, it meant that &lt;strong&gt;the interna…
2469 built twice&lt;/strong&gt; on each compilation run of the whole librsvg …
2470 once for &lt;code&gt;librsvg.so&lt;/code&gt;, and once for &lt;code&gt;l…
2471 &lt;h2&gt;Making programming errors a &lt;code&gt;g_critical&lt;/code&gt…
2472 &lt;p&gt;While &lt;code&gt;g_warning()&lt;/code&gt; means "something wen…
2473 continue", &lt;code&gt;g_critical()&lt;/code&gt; means "there is a progr…
2474 historical reasons Glib does not abort when &lt;code&gt;g_critical()&lt;…
2475 except by setting &lt;a href="https://developer.gnome.org/glib/stable/gl…
2476 running a development version of Glib.&lt;/p&gt;
2477 &lt;p&gt;&lt;a href="https://gitlab.gnome.org/GNOME/librsvg/commit/9d26e…
2478 C API was called out of order, by using a similar
2479 &lt;code&gt;rsvg_g_critical_from_c()&lt;/code&gt; wrapper for a C macro.…
2480 &lt;h2&gt;Separating the C-callable code into yet another crate&lt;/h2&g…
2481 &lt;p&gt;To recapitulate, at that point we had this:&lt;/p&gt;
2482 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
2483 &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nv"&gt;Cargo&lt;/s…
2484 &lt;span class="o"&gt;|&lt;/span&gt;
2485 &lt;span class="o"&gt;+-&lt;/span&gt; &lt;span class="nv"&gt;rsvg_intern…
2486 &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&g…
2487 &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="o"&gt;+-&lt;/span&…
2488 &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nv"&gt;c_api&…
2489 &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nv"&gt;handle…
2490 &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="o"&gt;*&lt;/s…
2491 &lt;span class="o"&gt;|&lt;/span&gt;
2492 &lt;span class="o"&gt;+-&lt;/span&gt; &lt;span class="nv"&gt;librsvg&lt;…
2493 &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span…
2494 &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nv"&gt;rsvg&lt;/…
2495 &lt;span class="o"&gt;|&lt;/span&gt;
2496 &lt;span class="o"&gt;+-&lt;/span&gt; &lt;span class="nv"&gt;librsvg_cra…
2497 &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nv"&gt;Cargo&lt…
2498 &lt;span class="o"&gt;+-&lt;/span&gt; &lt;span class="nv"&gt;src&lt;/…
2499 &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nv"&gt;lib&lt…
2500 &lt;span class="o"&gt;+-&lt;/span&gt; &lt;span class="nv"&gt;tests&lt…
2501 &lt;span class="o"&gt;*&lt;/span&gt;.&lt;span class="nv"&gt;rs&l…
2502 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
2503
2504 &lt;p&gt;At this point &lt;code&gt;c_api.rs&lt;/code&gt; with all the &l…
2505 place. That code is only relevant to &lt;code&gt;librsvg.so&lt;/code&gt…
2506 —, not to the Rust API in &lt;code&gt;librsvg_crate&lt;/code&gt;.&lt;/…
2507 &lt;p&gt;I started moving the C API glue to a separate &lt;a href="https…
2508 along with the C stubs:&lt;/p&gt;
2509 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
2510 | *.c - stub functions that call into Rust
2511 | rsvg-base.c - contains rsvg_g_warning_from_c() among others
2512 | Cargo.toml
2513 | c_api.rs - what we had before
2514 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
2515
2516 &lt;p&gt;This made the dependencies look like the following:&lt;/p&gt;
2517 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
2518 ^ ^
2519 | \
2520 | \
2521 librsvg_crate librsvg_c_api
2522 (Rust API) ^
2523 |
2524 librsvg.so
2525 (C API)
2526 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
2527
2528 &lt;p&gt;And also, this made it possible to &lt;a href="https://gitlab.g…
2529 for &lt;code&gt;rsvg_internals&lt;/code&gt;, since the code that calls
2530 &lt;code&gt;rsvg_g_warning_from_c&lt;/code&gt; now lives in &lt;code&gt;…
2531 &lt;p&gt;With that, &lt;code&gt;rsvg_internals&lt;/code&gt; is compiled …
2532 &lt;p&gt;This also helped clean up some code in the internals library.
2533 Deprecated functions that render SVGs directly to &lt;code&gt;GdkPixbuf&…
2534 in &lt;code&gt;librsvg_c_api&lt;/code&gt; and don't clutter the &lt;code…
2535 All the GObject boilerplate is there as well now; &lt;code&gt;rsvg_inter…
2536 mostly safe code except for the glue to libxml2.&lt;/p&gt;
2537 &lt;h2&gt;Summary&lt;/h2&gt;
2538 &lt;p&gt;It was useful to move all the code that dealt with incoming C t…
2539 our outgoing C return values and errors, into the same place, and
2540 separate it from the "pure Rust" code.&lt;/p&gt;
2541 &lt;p&gt;This took gradual refactoring and was not done in a single step…
2542 it left the resulting Rust code rather nice and clean.&lt;/p&gt;
2543 &lt;p&gt;When we added a new public Rust API, we had to shuffle some code
2544 around that could only be linked in the context of a C library.&lt;/p&gt;
2545 &lt;p&gt;Compile-time configuration features are useful (like &lt;code&g…
2546 world), but they do cause double compilation if you need a C-internals
2547 and a Rust-internals library from the same code.&lt;/p&gt;
2548 &lt;p&gt;Having proper error reporting throughout the Rust code is a lot…
2549 work, but pretty much invaluable. The glue code to C can then convert
2550 and expose those errors as needed.&lt;/p&gt;
2551 &lt;p&gt;If you need both C and Rust APIs into the same code base, you m…
2552 up naturally using a facade pattern for each. It helps to gradually
2553 refactor the internals to be as "pure idiomatic Rust" as possible,
2554 while letting API idiosyncrasies bubble up to each individual facade.&lt…
2555 &lt;a href="https://blog.ometer.com/2006/10/14/text-layout-that-works-pr…
2556 a CSS-aware canvas from around 2006. It uses libcroco to parse CSS,
2557 and implements selector matching by hand in C.&lt;/p&gt;
2558 &lt;p&gt;This code is getting rather dated, and libcroco is unmaintained…
2559 &lt;p&gt;I've been reading the code for
2560 &lt;a href="https://gitlab.gnome.org/GNOME/gnome-shell/blob/66fc5c07/src…
2561 and
2562 &lt;a href="https://gitlab.gnome.org/GNOME/gnome-shell/blob/66fc5c07/src…
2563 and it …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Gnome-shell …
2564 &lt;a href="https://blog.ometer.com/2006/10/14/text-layout-that-works-pr…
2565 a CSS-aware canvas from around 2006. It uses libcroco to parse CSS,
2566 and implements selector matching by hand in C.&lt;/p&gt;
2567 &lt;p&gt;This code is getting rather dated, and libcroco is unmaintained…
2568 &lt;p&gt;I've been reading the code for
2569 &lt;a href="https://gitlab.gnome.org/GNOME/gnome-shell/blob/66fc5c07/src…
2570 and
2571 &lt;a href="https://gitlab.gnome.org/GNOME/gnome-shell/blob/66fc5c07/src…
2572 and it looks very feasible to port it gradually to Rust, by using the
2573 same crates that librsvg uses, and eventually removing libcroco
2574 altogether: &lt;strong&gt;gnome-shell is the last module that uses libc…
2575 distro packages&lt;/strong&gt;.&lt;/p&gt;
2576 &lt;h2&gt;Strategy&lt;/h2&gt;
2577 &lt;p&gt;&lt;code&gt;StTheme&lt;/code&gt; and &lt;code&gt;StThemeNode&lt…
2578 keep them in memory. The values of individual properties are just
2579 tokenized and kept around as a linked list of &lt;code&gt;CRTerm&lt;/cod…
2580 represents a single token.&lt;/p&gt;
2581 &lt;p&gt;Later, the drawing code uses functions like
2582 &lt;code&gt;st_theme_node_lookup_color(node, "property_name")&lt;/code&g…
2583 &lt;code&gt;st_theme_node_lookup_length()&lt;/code&gt; to query the vari…
2584 it needs. It is &lt;em&gt;then&lt;/em&gt; that the type of each propert…
2585 determined: prior to that step, property values are just tokenized,
2586 not parsed into usable values.&lt;/p&gt;
2587 &lt;p&gt;I am going to start by porting the individual parsers to Rust, …
2588 to what Paolo and I did for librsvg. It turns out that there's some
2589 code we can share.&lt;/p&gt;
2590 &lt;p&gt;So far I have the &lt;a href="https://gitlab.gnome.org/federico…
2591 colors&lt;/a&gt;
2592 implemented in Rust. This &lt;a href="https://gitlab.gnome.org/federico…
2593 code&lt;/a&gt;
2594 from the C parsers, and replaces it with a little Rust code, since the
2595 cssparser crate can already parse CSS colors with alpha with no extra
2596 work — libcroco didn't support alpha.&lt;/p&gt;
2597 &lt;p&gt;As a bonus, this supports &lt;code&gt;hsl()&lt;/code&gt; colors…
2598 out of the box!&lt;/p&gt;
2599 &lt;p&gt;After all the parsers are done, the next step would be to conve…
2600 representation of complete stylesheets into pure Rust code.&lt;/p&gt;
2601 &lt;h2&gt;What can we expect?&lt;/h2&gt;
2602 &lt;p&gt;&lt;strong&gt;A well-maintained CSS stack.&lt;/strong&gt; Fire…
2603 crates in question, so librsvg and gnome-shell should get maintenance
2604 of a robust CSS stack "for free", for the foreseeable future.&lt;/p&gt;
2605 &lt;p&gt;&lt;strong&gt;Speed.&lt;/strong&gt; Caveat: I have no profile …
2606 know how much time it spends doing CSS parsing and cascading, but it
2607 looks like the Rust version has a good chance of being more efficient.&l…
2608 &lt;p&gt;The &lt;a href="https://docs.rs/selectors/"&gt;selectors crate&…
2609 interesting
2610 &lt;a href="https://hacks.mozilla.org/2017/08/inside-a-super-fast-css-en…
2611 from Mozilla Servo, and it is also now used in Firefox. It supports
2612 doing selector matching using Bloom filters, and can also avoid
2613 re-cascading child nodes if a change to a parent would not cause its
2614 children to change.&lt;/p&gt;
2615 &lt;p&gt;All the parsing is done with zero-copy parsers thanks to Rust's…
2616 slices; without so many &lt;code&gt;malloc()&lt;/code&gt; calls in the p…
2617 the parsing stage should really fly.&lt;/p&gt;
2618 &lt;p&gt;&lt;strong&gt;More CSS features.&lt;/strong&gt; The selectors c…
2619 basically all kinds of selectors as defined by recent CSS specs; one
2620 just has to provide the correct hooks into the calling code's
2621 representation of the DOM tree. The kind of matching that &lt;code&gt;S…
2622 can do is somewhat limited; the rustification should make it match
2623 much more closely to what people expect from CSS engines in web
2624 browsers.&lt;/p&gt;
2625 &lt;p&gt;&lt;strong&gt;A well-defined model of property inheritance.&lt;…
2626 model for CSS property inheritance is a bit ad-hoc and inconsistent.
2627 I haven't quite tested it, but from looking at the code, it seems that
2628 not all properties get inherited in the same way. I hope to move it
2629 to something closer to what librsvg already does, which should make it
2630 match people's expectations from the web.&lt;/p&gt;
2631 &lt;h2&gt;In the meantime&lt;/h2&gt;
2632 &lt;p&gt;I have a merge request ready to simply move the libcroco source…
2633 directly inside gnome-shell's source tree. This should let distros
2634 remove their libcroco package as soon as possible. That MR does not
2635 require Rust yet.&lt;/p&gt;
2636 &lt;p&gt;My playground is here:&lt;/p&gt;
2637 &lt;ul&gt;
2638 &lt;li&gt;&lt;a href="https://gitlab.gnome.org/federico/gnome-shell/comm…
2639 styles&lt;/a&gt;&lt;/li&gt;
2640 &lt;li&gt;&lt;a href="https://gitlab.gnome.org/federico/stylish"&gt;Styl…
2641 library that will implement gnome-shell's styling code.&lt;/li&gt;
2642 &lt;/ul&gt;
2643 &lt;p&gt;This does not compile yet! I'll plug things together tomorrow.…
2644 &lt;p&gt;(Oh, yes, the project to redo Firefox's CSS stack in Rust used …
2645 called Stylo. I'm calling this Stylish, as in Styles for the Shell.)&lt…
2646 or &lt;code&gt;6px&lt;/code&gt;. Sometimes the unit is a &lt;strong&gt;…
2647 says that lengths with percentage units should be resolved with
2648 respect to a certain rectangle. For example, consider this circle
2649 element:&lt;/p&gt;
2650 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
2651 or &lt;code&gt;6px&lt;/code&gt;. Sometimes the unit is a &lt;strong&gt;…
2652 says that lengths with percentage units should be resolved with
2653 respect to a certain rectangle. For example, consider this circle
2654 element:&lt;/p&gt;
2655 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
2656 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
2657
2658 &lt;p&gt;This means, draw a solid black circle whose center is at 50% of…
2659 width and 75% of the height of the current viewport. The circle
2660 should have a 4-pixel radius.&lt;/p&gt;
2661 &lt;p&gt;The process of converting that kind of units into absolute pixe…
2662 the final drawing is called &lt;strong&gt;normalization&lt;/strong&gt;. …
2663 units sometimes need to be normalized with respect to the current
2664 viewport (a local coordinate system), or with respect to the size of
2665 another object (e.g. when a clipping path is used to cut the current
2666 shape in half).&lt;/p&gt;
2667 &lt;p&gt;One detail about normalization is that it can be with respect t…
2668 horizontal dimension of the current viewport, the vertical dimension,
2669 or both. Keep this in mind: at normalization time, we need to be able
2670 to distinguish between those three modes.&lt;/p&gt;
2671 &lt;h2&gt;The original C version&lt;/h2&gt;
2672 &lt;p&gt;I have &lt;a href="https://people.gnome.org/~federico/news-2016…
2673 following is a small summary.&lt;/p&gt;
2674 &lt;p&gt;The original C code had &lt;a href="https://gitlab.gnome.org/GN…
2675 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
2676 &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;len…
2677 &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;facto…
2678 &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="n"&gt;RsvgLength&lt…
2679 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
2680
2681 &lt;p&gt;The &lt;a href="https://gitlab.gnome.org/GNOME/librsvg/blob/ef7…
2682 character depending on the length's unit: &lt;code&gt;'p'&lt;/code&gt; …
2683 for inches, etc., and &lt;code&gt;'\0'&lt;/code&gt; for the default unit…
2684 &lt;p&gt;Along with that, the &lt;a href="https://gitlab.gnome.org/GNOME…
2685 the direction (horizontal, vertical, both) to which the length in
2686 question refers. It did this by taking another character as an
2687 argument to the normalization function:&lt;/p&gt;
2688 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
2689 &lt;span class="nf"&gt;_rsvg_css_normalize_length&lt;/span&gt; &lt;span …
2690 &lt;span class="p"&gt;{&lt;/span&gt;
2691 &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/sp…
2692 &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;…
2693 &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;…
2694 &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt…
2695 &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"…
2696 &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt…
2697 &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"…
2698 &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt…
2699 &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"…
2700 &lt;span class…
2701 &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/…
2702 &lt;span class="p"&gt;}&lt;/span&gt;
2703 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
2704
2705 &lt;p&gt;&lt;a href="https://people.gnome.org/~federico/news-2016-11.htm…
2706 how the directions are identified at normalization time. The function
2707 above expects one of &lt;code&gt;'h'/'v'/'o'&lt;/code&gt; for horizontal…
2708 two places in the code passed the wrong character.&lt;/p&gt;
2709 &lt;h2&gt;Making the C version cleaner&lt;/h2&gt;
2710 &lt;p&gt;Before converting that code to Rust, I &lt;a href="https://gitl…
2711 characters&lt;/a&gt; and made the code use proper enums to
2712 identify a length's units.&lt;/p&gt;
2713 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
2714 &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;LENGTH_UNI…
2715 &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;LENGTH_UNI…
2716 &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;LENGTH_UNI…
2717 &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;LENGTH_UNI…
2718 &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;LENGTH_UNI…
2719 &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;LENGTH_UNI…
2720 &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;LENGTH_UNI…
2721 &lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;…
2722 &lt;span class="o"&gt;+&lt;/span&gt;
2723 &lt;span class="k"&gt;typedef&lt;/span&gt; &lt;span class="k"&gt;struct…
2724 &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;le…
2725 &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/…
2726 &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;LengthUnit…
2727 &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="n"&gt;RsvgLength&l…
2728 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
2729
2730 &lt;p&gt;Then, &lt;a href="https://gitlab.gnome.org/GNOME/librsvg/commit…
2731 direction in which to normalize as an enum instead of a char.&lt;/p&gt;
2732 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
2733 &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;LENGTH_DIR…
2734 &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;LENGTH_DIR…
2735 &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;LENGTH_DIR…
2736 &lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;…
2737
2738 &lt;span class="kt"&gt;double&lt;/span&gt;
2739 &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;_rsvg_css_norm…
2740 &lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;_rsvg_css_norm…
2741 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
2742
2743 &lt;h2&gt;Making the C version easier to get right&lt;/h2&gt;
2744 &lt;p&gt;While doing the last change above, I found a place in the code …
2745 used the wrong direction by mistake, probably due to a cut&amp;amp;paste
2746 error. Part of the problem here is that the code was specifying the
2747 direction at normalization time.&lt;/p&gt;
2748 &lt;p&gt;I decided to change it so that &lt;a href="https://gitlab.gnome…
2749 direction since initialization&lt;/a&gt;, so that subsequent
2750 code wouldn't have to worry about that. Hopefully, initializing a
2751 &lt;code&gt;width&lt;/code&gt; field should make it obvious that it need…
2752 &lt;code&gt;LENGTH_DIR_HORIZONTAL&lt;/code&gt;.&lt;/p&gt;
2753 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
2754 &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;le…
2755 &lt;span class="n"&gt;LengthUnit&lt;/span&gt; &lt;span class="n"&gt…
2756 &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;LengthDir&…
2757 &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="n"&gt;RsvgLength&l…
2758 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
2759
2760 &lt;p&gt;That is, so that instead of&lt;/p&gt;
2761 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
2762 &lt;span class="n"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span…
2763
2764 &lt;span class="p"&gt;...&lt;/span&gt;
2765
2766 &lt;span class="cm"&gt;/* at rendering time */&lt;/span&gt;
2767 &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;final…
2768 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
2769
2770 &lt;p&gt;we would instead do this:&lt;/p&gt;
2771 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
2772 &lt;span class="n"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span…
2773
2774 &lt;span class="p"&gt;...&lt;/span&gt;
2775
2776 &lt;span class="cm"&gt;/* at rendering time */&lt;/span&gt;
2777 &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;final…
2778 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
2779
2780 &lt;p&gt;This made the drawing code, which deals with a lot of coordinat…
2781 the same time, a lot less noisy.&lt;/p&gt;
2782 &lt;h2&gt;Initial port to Rust&lt;/h2&gt;
2783 &lt;p&gt;To recap, this was the state of the structs after the initial
2784 refactoring in C:&lt;/p&gt;
2785 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
2786 &lt;span class="n"&gt;LENGTH_UNIT_DEFAULT&lt;/span&gt;&lt;span class…
2787 &lt;span class="n"&gt;LENGTH_UNIT_PERCENT&lt;/span&gt;&lt;span class…
2788 &lt;span class="n"&gt;LENGTH_UNIT_FONT_EM&lt;/span&gt;&lt;span class…
2789 &lt;span class="n"&gt;LENGTH_UNIT_FONT_EX&lt;/span&gt;&lt;span class…
2790 &lt;span class="n"&gt;LENGTH_UNIT_INCH&lt;/span&gt;&lt;span class="p…
2791 &lt;span class="n"&gt;LENGTH_UNIT_RELATIVE_LARGER&lt;/span&gt;&lt;sp…
2792 &lt;span class="n"&gt;LENGTH_UNIT_RELATIVE_SMALLER&lt;/span&gt;
2793 &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="n"&gt;LengthUnit&lt…
2794
2795 &lt;span class="k"&gt;typedef&lt;/span&gt; &lt;span class="k"&gt;enum&lt…
2796 &lt;span class="n"&gt;LENGTH_DIR_HORIZONTAL&lt;/span&gt;&lt;span cla…
2797 &lt;span class="n"&gt;LENGTH_DIR_VERTICAL&lt;/span&gt;&lt;span class…
2798 &lt;span class="n"&gt;LENGTH_DIR_BOTH&lt;/span&gt;
2799 &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="n"&gt;LengthDir&lt;…
2800
2801 &lt;span class="k"&gt;typedef&lt;/span&gt; &lt;span class="k"&gt;struct&…
2802 &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;len…
2803 &lt;span class="n"&gt;LengthUnit&lt;/span&gt; &lt;span class="n"&gt;…
2804 &lt;span class="n"&gt;LengthDir&lt;/span&gt; &lt;span class="n"&gt;d…
2805 &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="n"&gt;RsvgLength&lt…
2806 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
2807
2808 &lt;p&gt;This &lt;a href="https://gitlab.gnome.org/GNOME/librsvg/commit/…
2809 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
2810 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Default&lt…
2811 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Percent&lt;…
2812 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FontEm&lt;/…
2813 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FontEx&lt;/…
2814 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Inch&lt;/sp…
2815 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RelativeLar…
2816 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RelativeSma…
2817 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
2818
2819 &lt;span class="k"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&g…
2820 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Horizontal&…
2821 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Vertical&lt…
2822 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Both&lt;/sp…
2823 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
2824
2825 &lt;span class="k"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&g…
2826 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;length&lt;/…
2827 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;unit&lt;/sp…
2828 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dir&lt;/spa…
2829 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
2830 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
2831
2832 &lt;p&gt;It &lt;a href="https://gitlab.gnome.org/GNOME/librsvg/commit/82…
2833 direction and produced an &lt;code&gt;RsvgLength&lt;/code&gt;:&lt;/p&gt;
2834 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
2835 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;pub&lt;/spa…
2836 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
2837 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
2838
2839 &lt;p&gt;(This was &lt;a href="https://gitlab.gnome.org/GNOME/librsvg/co…
2840 C code did very little error checking!)&lt;/p&gt;
2841 &lt;h2&gt;The initial Parse trait&lt;/h2&gt;
2842 &lt;p&gt;It was at that point that it seemed convenient to &lt;a href="h…
2843 trait&lt;/a&gt;, which all CSS value types would implement to
2844 parse themselves from string.&lt;/p&gt;
2845 &lt;p&gt;However, parsing an &lt;code&gt;RsvgLength&lt;/code&gt; also ne…
2846 the &lt;code&gt;LengthDir&lt;/code&gt;. My initial version of the &lt;c…
2847 associated called &lt;code&gt;Data&lt;/code&gt;, through which one could…
2848 of data during parsing/initialization:&lt;/p&gt;
2849 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
2850 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;type&lt;/sp…
2851 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;type&lt;/sp…
2852
2853 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span…
2854 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
2855 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
2856
2857 &lt;p&gt;This was explicitly to be able to &lt;a href="https://gitlab.gn…
2858 &lt;code&gt;RsvgLength&lt;/code&gt;:&lt;/p&gt;
2859 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
2860 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;type&lt;/sp…
2861 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;type&lt;/sp…
2862
2863 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span…
2864 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
2865 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
2866
2867 &lt;p&gt;This was okay for lengths, but &lt;em&gt;very noisy&lt;/em&gt; …
2868 didn't require an extra bit of data. In the rest of the code, the
2869 helper type was &lt;code&gt;Data = ()&lt;/code&gt; and there was a pair …
2870 in every place that &lt;code&gt;parse()&lt;/code&gt; was called.&lt;/p&g…
2871 &lt;h2&gt;Removing the helper Data type&lt;/h2&gt;
2872 &lt;h3&gt;Introducing one type per direction&lt;/h3&gt;
2873 &lt;p&gt;Over a year later, that &lt;code&gt;()&lt;/code&gt; bit of data…
2874 nuts. I started refactoring the &lt;code&gt;Length&lt;/code&gt; module …
2875 &lt;p&gt;First, I &lt;a href="https://gitlab.gnome.org/GNOME/librsvg/com…
2876 their direction at the same time:&lt;/p&gt;
2877 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
2878 &lt;span class="k"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&g…
2879 &lt;span class="k"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&g…
2880 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
2881
2882 &lt;p&gt;This was &lt;a href="https://gitlab.gnome.org/GNOME/librsvg/com…
2883 needed to know the relevant &lt;code&gt;LengthDir&lt;/code&gt;.&lt;/p&gt;
2884 &lt;p&gt;Now, for example, the declaration for the &lt;code&gt;&amp;lt;c…
2885 like this:&lt;/p&gt;
2886 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
2887 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cx&lt;/span…
2888 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cy&lt;/span…
2889 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&…
2890 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
2891 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
2892
2893 &lt;p&gt;(Ignore the &lt;code&gt;Cell&lt;/code&gt; everywhere; we got ri…
2894 &lt;h3&gt;Removing the &lt;code&gt;dir&lt;/code&gt; field&lt;/h3&gt;
2895 &lt;p&gt;Since now the information about the length's direction is embod…
2896 the &lt;code&gt;LengthHorizontal/LengthVertical/LengthBoth&lt;/code&gt; …
2897 possible to &lt;a href="https://gitlab.gnome.org/GNOME/librsvg/commit/78…
2898 &lt;code&gt;Length&lt;/code&gt; struct.&lt;/p&gt;
2899 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
2900 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;length&lt;…
2901 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;unit&lt;/s…
2902 &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&…
2903 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;…
2904
2905 &lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="k"&gt;pub&lt;/span&g…
2906 &lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="k"&gt;pub&lt;/span&g…
2907 &lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="k"&gt;pub&lt;/span&g…
2908 &lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
2909 &lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;define_length_…
2910 &lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;define_length_…
2911 &lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;define_length_…
2912 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
2913
2914 &lt;p&gt;Note the use of a &lt;code&gt;define_length_type!&lt;/code&gt; …
2915 those three newtypes.&lt;/p&gt;
2916 &lt;h3&gt;Removing the &lt;code&gt;Data&lt;/code&gt; associated type&lt;…
2917 &lt;p&gt;And finally, this made it possible to &lt;a href="https://gitla…
2918 type&lt;/a&gt; from the &lt;code&gt;Parse&lt;/code&gt; trait.&lt;/p&gt;
2919 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
2920 &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&…
2921 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;type&lt;/s…
2922
2923 &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&…
2924 &lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&…
2925 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;…
2926 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
2927
2928 &lt;p&gt;The resulting mega-commit removed a bunch of stray parentheses …
2929 from all calls to &lt;code&gt;parse()&lt;/code&gt;, and the code ended u…
2930 read.&lt;/p&gt;
2931 &lt;h2&gt;Removing the newtypes&lt;/h2&gt;
2932 &lt;p&gt;This was fine for a while. Recently, however, I figured out th…
2933 would be possible to embody the information for a length's direction
2934 in a different way.&lt;/p&gt;
2935 &lt;p&gt;But to get there, I first needed a temporary refactor.&lt;/p&gt;
2936 &lt;h3&gt;Replacing the macro with a trait with a default implementation…
2937 &lt;p&gt;Deep in the guts of &lt;code&gt;length.rs&lt;/code&gt;, the key…
2938 different based on &lt;code&gt;LengthDir&lt;/code&gt; is its &lt;code&gt…
2939 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
2940 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Horizontal&…
2941 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Vertical&lt…
2942 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Both&lt;/sp…
2943 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
2944
2945 &lt;span class="k"&gt;impl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&…
2946 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span…
2947 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;match&l…
2948 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Len…
2949 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Len…
2950 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Len…
2951 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/s…
2952 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&…
2953 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
2954 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
2955
2956 &lt;p&gt;That method gets passed, for example, the &lt;code&gt;width/hei…
2957 current viewport for the &lt;code&gt;x/y&lt;/code&gt; arguments. The me…
2958 to use the width, height, or a combination of both.&lt;/p&gt;
2959 &lt;p&gt;And of course, the interesting part of the &lt;code&gt;define_l…
2960 was to generate code for calling &lt;code&gt;LengthDir::Horizontal::scal…
2961 appropriate depending on the &lt;code&gt;LengthDir&lt;/code&gt; in quest…
2962 &lt;p&gt;First I made a trait called &lt;code&gt;Orientation&lt;/code&gt…
2963 method, and three zero-sized types that implement that trait. Note
2964 how each of these three implementations corresponds to one of the
2965 &lt;code&gt;match&lt;/code&gt; arms above:&lt;/p&gt;
2966 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
2967 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span…
2968 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
2969
2970 &lt;span class="k"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&g…
2971 &lt;span class="k"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&g…
2972 &lt;span class="k"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&g…
2973
2974 &lt;span class="k"&gt;impl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&…
2975 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span…
2976 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/s…
2977 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&…
2978 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
2979
2980 &lt;span class="k"&gt;impl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&…
2981 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span…
2982 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;y&lt;/s…
2983 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&…
2984 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
2985
2986 &lt;span class="k"&gt;impl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&…
2987 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span…
2988 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;viewpor…
2989 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&…
2990 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
2991 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
2992
2993 &lt;p&gt;Now most of the contents of the &lt;code&gt;define_length_type!…
2994 the &lt;a href="https://gitlab.gnome.org/GNOME/librsvg/commit/21a40f4ef8…
2995 &lt;code&gt;LengthTrait&lt;/code&gt;&lt;/a&gt;. Crucially, this trait h…
2996 &lt;code&gt;Orientation&lt;/code&gt; associated type, &lt;strong&gt;whic…
2997 Orientation trait&lt;/strong&gt;:&lt;/p&gt;
2998 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
2999 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;type&lt;/sp…
3000
3001 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;..&lt;/span…
3002
3003 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span…
3004 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;match&l…
3005 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Len…
3006
3007 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Len…
3008 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="bp"&g…
3009 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt…
3010 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&l…
3011
3012 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;..&…
3013 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&…
3014 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
3015 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
3016
3017 &lt;p&gt;Note that the incantation is
3018 &lt;code&gt;&amp;lt;Self::Orientation&amp;gt;::scaling_factor(...)&lt;/c…
3019 associated type.&lt;/p&gt;
3020 &lt;p&gt;Now the &lt;code&gt;define_length_type!&lt;/code&gt; macro is s…
3021 interesting part being just this:&lt;/p&gt;
3022 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
3023 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&…
3024 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;pub&lt;…
3025
3026 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;impl&lt…
3027 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;typ…
3028 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/s…
3029 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&…
3030 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
3031
3032 &lt;span class="n"&gt;define_length_type&lt;/span&gt;&lt;span class="o"&…
3033 &lt;span class="n"&gt;define_length_type&lt;/span&gt;&lt;span class="o"&…
3034 &lt;span class="n"&gt;define_length_type&lt;/span&gt;&lt;span class="o"&…
3035 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
3036
3037 &lt;p&gt;We moved from having three newtypes of length-with-LengthDir to…
3038 newtypes with dir-as-associated-type.&lt;/p&gt;
3039 &lt;h3&gt;Removing the newtypes and the macro&lt;/h3&gt;
3040 &lt;p&gt;After that temporary refactoring, we had the &lt;code&gt;Orient…
3041 the three zero-sized types &lt;code&gt;Horizontal&lt;/code&gt;, &lt;code…
3042 &lt;p&gt;I figured out that one can use &lt;a href="https://doc.rust-lan…
3043 around the type that &lt;code&gt;Length&lt;/code&gt; needs to normalize …
3044 using an associated type in an extra &lt;code&gt;LengthTrait&lt;/code&gt…
3045 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
3046 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;pub&lt;/spa…
3047 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;pub&lt;/spa…
3048 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;orientation…
3049 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
3050
3051 &lt;span class="k"&gt;impl&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt…
3052 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;pub&lt;/spa…
3053 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;match&l…
3054 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Len…
3055
3056 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Len…
3057 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="bp"&g…
3058 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o…
3059 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&l…
3060
3061 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;..&…
3062 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/s…
3063 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&…
3064 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
3065 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
3066
3067 &lt;p&gt;Now the incantation is &lt;code&gt;&amp;lt;O as Orientation&amp…
3068 the method on the generic type; it is no longer an associated type in
3069 a trait.&lt;/p&gt;
3070 &lt;p&gt;With that, users of lengths look like this; here, our &lt;code&…
3071 element from before:&lt;/p&gt;
3072 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
3073 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cx&lt;/span…
3074 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cy&lt;/span…
3075 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&…
3076 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
3077 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
3078
3079 &lt;p&gt;I'm very happy with the readability of all the code now. I use…
3080 think of &lt;code&gt;PhantomData&lt;/code&gt; as a way to deal with &lt;…
3081 C&lt;/a&gt;, but it turns out that it is also useful to keep a generic
3082 type around should one need it.&lt;/p&gt;
3083 &lt;p&gt;The final &lt;code&gt;Length&lt;/code&gt; struct is this:&lt;/p…
3084 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
3085 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;pub&lt;/spa…
3086 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;pub&lt;/spa…
3087 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;orientation…
3088 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
3089 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
3090
3091 &lt;p&gt;And it only takes up as much space as its &lt;code&gt;length&lt…
3092 &lt;code&gt;PhantomData&lt;/code&gt; is zero-sized after all.&lt;/p&gt;
3093 &lt;p&gt;(Later, we renamed &lt;code&gt;Orientation&lt;/code&gt; to &lt;…
3094 structure remained the same.)&lt;/p&gt;
3095 &lt;h2&gt;Summary&lt;/h2&gt;
3096 &lt;p&gt;Over a couple of years, librsvg's type that represents CSS leng…
3097 went from a C representation along the lines of "all data in the world
3098 is an int", to a Rust representation that uses some interesting type
3099 trickery:&lt;/p&gt;
3100 &lt;ul&gt;
3101 &lt;li&gt;
3102 &lt;p&gt;C struct with &lt;code&gt;char&lt;/code&gt; for units.&lt;/p&gt;
3103 &lt;/li&gt;
3104 &lt;li&gt;
3105 &lt;p&gt;C struct with a &lt;code&gt;LengthUnits&lt;/code&gt; enum.&lt;/…
3106 &lt;/li&gt;
3107 &lt;li&gt;
3108 &lt;p&gt;C struct without an embodied direction; each place that needs to
3109 normalize needs to get the orientation right.&lt;/p&gt;
3110 &lt;/li&gt;
3111 &lt;li&gt;
3112 &lt;p&gt;C struct with a built-in direction as an extra field, done at
3113 initialization time.&lt;/p&gt;
3114 &lt;/li&gt;
3115 &lt;li&gt;
3116 &lt;p&gt;Same struct but in Rust.&lt;/p&gt;
3117 &lt;/li&gt;
3118 &lt;li&gt;
3119 &lt;p&gt;An ugly but workable &lt;code&gt;Parse&lt;/code&gt; trait so th…
3120 at parse/initialization time.&lt;/p&gt;
3121 &lt;/li&gt;
3122 &lt;li&gt;
3123 &lt;p&gt;Three newtypes &lt;code&gt;LengthHorizontal&lt;/code&gt;, &lt;c…
3124 &lt;code&gt;LengthBoth&lt;/code&gt; with a common core. A cleaned-up …
3125 macro to generate those newtypes.&lt;/p&gt;
3126 &lt;/li&gt;
3127 &lt;li&gt;
3128 &lt;p&gt;Replace the &lt;code&gt;LengthDir&lt;/code&gt; enum with an &lt…
3129 trait, and three zero-sized types &lt;code&gt;Horizontal/Vertical/Both…
3130 implement the trait.&lt;/p&gt;
3131 &lt;/li&gt;
3132 &lt;li&gt;
3133 &lt;p&gt;Replace most of the macro with a helper trait &lt;code&gt;Lengt…
3134 an &lt;code&gt;Orientation&lt;/code&gt; associated type.&lt;/p&gt;
3135 &lt;/li&gt;
3136 &lt;li&gt;
3137 &lt;p&gt;Replace the helper trait with a single &lt;code&gt;Length&amp;l…
3138 type, which puts the orientation as a generic parameter. The macro
3139 disappears and there is a single implementation for everything.&lt;/p&…
3140 &lt;/li&gt;
3141 &lt;/ul&gt;
3142 &lt;p&gt;Refactoring never ends!&lt;/p&gt;</content><category term="misc…
3143 refactoring&lt;/a&gt;,
3144 librsvg now does all CSS parsing and matching in Rust, &lt;strong&gt;wit…
3145 libcroco&lt;/strong&gt;. In addition, the CSS engine comes from Mozilla …
3146 it should be able to handle much more complex CSS than librsvg ever
3147 could before.&lt;/p&gt;
3148 &lt;p&gt;This is the story of …&lt;/p&gt;</summary><content type="html…
3149 refactoring&lt;/a&gt;,
3150 librsvg now does all CSS parsing and matching in Rust, &lt;strong&gt;wit…
3151 libcroco&lt;/strong&gt;. In addition, the CSS engine comes from Mozilla …
3152 it should be able to handle much more complex CSS than librsvg ever
3153 could before.&lt;/p&gt;
3154 &lt;p&gt;This is the story of CSS support in librsvg.&lt;/p&gt;
3155 &lt;h2&gt;Introduction&lt;/h2&gt;
3156 &lt;p&gt;The &lt;a href="https://gitlab.gnome.org/GNOME/librsvg/commit/c…
3157 parsing&lt;/a&gt;
3158 in librsvg dates from 2002. It was as minimal as possible, written to
3159 support a small subset of what was then
3160 &lt;a href="https://www.w3.org/TR/1998/REC-CSS2-19980512/"&gt;CSS2&lt;/a…
3161 &lt;p&gt;Librsvg handled CSS stylesheets more "piecing them apart" than
3162 "parsing them". You know, when &lt;code&gt;g_strsplit()&lt;/code&gt; is…
3163 The basic parsing algorithm was to turn a stylesheet like this:&lt;/p&gt;
3164 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
3165
3166 &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;classname&lt;…
3167 &lt;span class="n"&gt;fill&lt;/span&gt;&lt;span class="p"&gt;:&lt;/s…
3168 &lt;span class="n"&gt;stroke-width&lt;/span&gt;&lt;span class="p"&gt…
3169 &lt;span class="p"&gt;}&lt;/span&gt;
3170 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
3171
3172 &lt;p&gt;Into a hash table whose keys are strings like &lt;code&gt;rect&…
3173 and whose values are everything inside curly braces.&lt;/p&gt;
3174 &lt;p&gt;The selector matching phase was equally simple. The code only …
3175 a few possible match types as follows. If it wanted to match a
3176 certain kind of CSS selector, it would say, "what would this selector
3177 look like in CSS syntax", it would make up a string with that syntax,
3178 and compare it to the key strings it had stored in the hash table from
3179 above.&lt;/p&gt;
3180 &lt;p&gt;So, to match an &lt;strong&gt;element name selector&lt;/strong&…
3181 element-&amp;gt;name)&lt;/code&gt;, obtain something like &lt;code&gt;re…
3182 table had such a key.&lt;/p&gt;
3183 &lt;p&gt;To match a &lt;strong&gt;class selector&lt;/strong&gt;, it woul…
3184 element-&amp;gt;class)&lt;/code&gt;, obtain something like &lt;code&gt;.…
3185 in the hash table.&lt;/p&gt;
3186 &lt;p&gt;This scheme supported only a few combinations. It handled &lt;…
3187 &lt;code&gt;.class&lt;/code&gt;, &lt;code&gt;tag.class&lt;/code&gt;, and…
3188 This was enough to support very simple stylesheets.&lt;/p&gt;
3189 &lt;p&gt;The value corresponding to each key in the hash table was the s…
3190 between curly braces in the stylesheet, so the second rule from the
3191 example above would contain &lt;code&gt;fill: green; stroke-width: 4;&lt…
3192 librsvg decided that an SVG element matched that CSS rule, it would
3193 re-parse the string with the CSS properties and apply them to the
3194 element's style.&lt;/p&gt;
3195 &lt;p&gt;I'm amazed that so little code was enough to deal with a good n…
3196 of SVG files with stylesheets. I suspect that this was due to a few
3197 things:&lt;/p&gt;
3198 &lt;ul&gt;
3199 &lt;li&gt;
3200 &lt;p&gt;While people were using complex CSS in HTML all the time, it was
3201 less common for SVG...&lt;/p&gt;
3202 &lt;/li&gt;
3203 &lt;li&gt;
3204 &lt;p&gt;... because CSS2 was somewhat new, and the SVG spec was still b…
3205 written...&lt;/p&gt;
3206 &lt;/li&gt;
3207 &lt;li&gt;
3208 &lt;p&gt;... and SVGs created with illustration programs don't really use
3209 stylesheets; they include the full style information inside each
3210 element instead of symbolically referencing it from a stylesheet.&lt;/…
3211 &lt;/li&gt;
3212 &lt;/ul&gt;
3213 &lt;p&gt;From the kinds of bugs that librsvg has gotten around "CSS supp…
3214 too limited", it feels like SVGs which use CSS features are either
3215 hand-written, or machine-generated from custom programs like data
3216 plotting software. Illustration programs tend to list all style
3217 properties explicitly in each SVG element, and don't use CSS.&lt;/p&gt;
3218 &lt;h2&gt;Libcroco appears&lt;/h2&gt;
3219 &lt;p&gt;The first commit to &lt;a href="https://gitlab.gnome.org/GNOME/…
3220 libcroco&lt;/a&gt;
3221 was to do CSS parsing, from March 2003.&lt;/p&gt;
3222 &lt;p&gt;At the same time, libcroco was introducing code to do CSS match…
3223 However, this code never got used in librsvg; it still kept its simple
3224 string-based matcher. Maybe libcroco's API was not ready?&lt;/p&gt;
3225 &lt;p&gt;Libcroco fell out of maintainership around the first half of 20…
3226 volunteers have kept fixing it since then.&lt;/p&gt;
3227 &lt;h2&gt;Problems with librsvg's string matcher for CSS&lt;/h2&gt;
3228 &lt;p&gt;The C implementation of CSS matching in librsvg remained basica…
3229 untouched until 2018, when Paolo Borelli and I started porting the
3230 surrounding code to Rust.&lt;/p&gt;
3231 &lt;p&gt;I had a lot of trouble figuring out the concepts from the code.…
3232 didn't know all the &lt;a href="https://gnome.pages.gitlab.gnome.org/lib…
3233 implementations&lt;/a&gt;,
3234 and librsvg didn't use it, either.&lt;/p&gt;
3235 &lt;p&gt;I think that librsvg's code suffered from what the refactoring
3236 literature calls &lt;a href="https://refactoring.guru/smells/primitive-o…
3237 obsession&lt;/strong&gt;&lt;/a&gt;.
3238 Instead of having a parsed representation of CSS selectors, librsvg
3239 just stored a stringified version of them. So, a selector like
3240 &lt;code&gt;rect#classname&lt;/code&gt; really was stored with a string …
3241 an actual decomposition into structs.&lt;/p&gt;
3242 &lt;p&gt;Moreover, things were misnamed. This is the field that stored
3243 stylesheet data inside an RsvgHandle:&lt;/p&gt;
3244 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
3245 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
3246
3247 &lt;p&gt;From just looking at the field declaration, this doesn't tell me
3248 anything about what kind of data is stored there. One has to grep the
3249 source code for where that field is used:&lt;/p&gt;
3250 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
3251 &lt;span class="nf"&gt;rsvg_css_define_style&lt;/span&gt; &lt;span class…
3252 &lt;span class="k"&gt;const&lt;/span&gt; &lt;span…
3253 &lt;span class="k"&gt;const&lt;/span&gt; &lt;span…
3254 &lt;span class="k"&gt;const&lt;/span&gt; &lt;span…
3255 &lt;span class="n"&gt;gboolean&lt;/span&gt; &lt;s…
3256 &lt;span class="p"&gt;{&lt;/span&gt;
3257 &lt;span class="n"&gt;GHashTable&lt;/span&gt; &lt;span class="o"&gt;…
3258
3259 &lt;span class="n"&gt;styles&lt;/span&gt; &lt;span class="o"&gt;=&lt…
3260 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
3261
3262 &lt;p&gt;Okay, it looks up a &lt;code&gt;selector&lt;/code&gt; by name i…
3263 gives back... another hash table &lt;code&gt;styles&lt;/code&gt;? What'…
3264 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
3265 &lt;span class="n"&gt;g_strdup&lt;/span&gt;…
3266 &lt;span class="n"&gt;style_value_data_new&…
3267 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
3268
3269 &lt;p&gt;Another string key called &lt;code&gt;style_name&lt;/code&gt;, …
3270 &lt;code&gt;StyleValueData&lt;/code&gt;; what's in it?&lt;/p&gt;
3271 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
3272 &lt;span class="n"&gt;gchar&lt;/span&gt; &lt;span class="o"&gt;*&lt;…
3273 &lt;span class="n"&gt;gboolean&lt;/span&gt; &lt;span class="n"&gt;im…
3274 &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="n"&gt;StyleValueDat…
3275 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
3276
3277 &lt;p&gt;The &lt;code&gt;value&lt;/code&gt; is another string. Strings …
3278 &lt;p&gt;At the time, I didn't really figure out what each level of nest…
3279 tables was supposed to mean. I didn't understand why we handled style
3280 properties in a completely different part of the code, and yet this
3281 part had a &lt;code&gt;css_props&lt;/code&gt; field that didn't seem to …
3282 &lt;p&gt;It took a while to realize that &lt;code&gt;css_props&lt;/code&…
3283 storing a mapping of selector names to properties; it was storing a
3284 mapping of selector names to &lt;strong&gt;declaration lists&lt;/strong&…
3285 property/value pairs.&lt;/p&gt;
3286 &lt;p&gt;So, when I started &lt;a href="https://gitlab.gnome.org/GNOME/l…
3287 Rust&lt;/a&gt;,
3288 I started to create real types with for each concept.&lt;/p&gt;
3289 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
3290 &lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="nc"&gt;Declarati…
3291
3292 &lt;span class="k"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&g…
3293 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;selectors_t…
3294 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
3295 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
3296
3297 &lt;p&gt;Even though the keys of those HashMaps are still strings, becau…
3298 librsvg didn't have a better way to represent their corresponding
3299 concepts, at least those declarations let one see what the hell is
3300 being stored without grepping the rest of the code. This is a part of
3301 the code that I didn't really touch very much, so it was nice to have
3302 that reminder.&lt;/p&gt;
3303 &lt;p&gt;The &lt;a href="https://gitlab.gnome.org/GNOME/librsvg/commit/1…
3304 Rust&lt;/a&gt;
3305 kept the same algorithm as the C code, the one that created strings
3306 with &lt;code&gt;element.class&lt;/code&gt; and compared them to the sto…
3307 Ugly, but it still worked in the same limited fashion.&lt;/p&gt;
3308 &lt;h2&gt;Rustifying the CSS parsers&lt;/h2&gt;
3309 &lt;p&gt;It turns out that CSS parsing is divided in two parts. One can…
3310 &lt;code&gt;style&lt;/code&gt; attribute inside an element, for example&…
3311 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
3312 &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;&a…
3313 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
3314
3315 &lt;p&gt;This is a plain declaration list which is not associated to any
3316 selectors, and which is applied directly to just the element in which it
3317 appears.&lt;/p&gt;
3318 &lt;p&gt;Then, there is the &lt;code&gt;&amp;lt;style&amp;gt;&lt;/code&g…
3319 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
3320 rect {
3321 fill: green;
3322 stroke: magenta;
3323 stroke-width: 4;
3324 }
3325 &lt;span class="nt"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;
3326 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
3327
3328 &lt;p&gt;This means that all &lt;code&gt;&amp;lt;rect&amp;gt;&lt;/code&g…
3329 &lt;p&gt;I started to look for existing Rust crates to parse and handle …
3330 data. The &lt;a href="https://docs.rs/cssparser/"&gt;cssparser&lt;/a&gt…
3331 &lt;a href="https://docs.rs/selectors/"&gt;selectors&lt;/a&gt; crates co…
3332 I thought they should do a pretty good job of things.&lt;/p&gt;
3333 &lt;p&gt;And they do! Except that they are not a drop-in replacement for
3334 anything. They are what gets used in Mozilla's Servo browser engine,
3335 so they are optimized to hell, and the code can be pretty intimidating.&…
3336 &lt;p&gt;Out of the box, cssparser provides a CSS tokenizer, but it does
3337 not know how to handle any properties/values in particular. One must
3338 use the tokenizer to implement a parser for each kind of CSS property
3339 one wants to support — Servo has mountains of code for all of HTML's
3340 style properties, and librsvg had to provide a smaller mountain of code
3341 for SVG style properties.&lt;/p&gt;
3342 &lt;p&gt;Thus started the big task of porting librsvg's string-based par…
3343 for CSS properties into ones based on cssparser tokens. Cssparser
3344 provides a &lt;code&gt;Parser&lt;/code&gt; struct, which extracts tokens…
3345 stream. Out of this, librsvg defines a &lt;code&gt;Parse&lt;/code&gt; t…
3346 things:&lt;/p&gt;
3347 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
3348
3349 &lt;span class="k"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&g…
3350 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;type&lt;/sp…
3351
3352 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span…
3353 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
3354 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
3355
3356 &lt;p&gt;What's with those two default lifetimes in &lt;code&gt;Parser&a…
3357 Cssparser tries very hard to be a zero-copy tokenizer. One of the
3358 lifetimes refers to the input string which is wrapped in a
3359 &lt;code&gt;Tokenizer&lt;/code&gt;, which is wrapped in a &lt;code&gt;Pa…
3360 is for the &lt;code&gt;ParserInput&lt;/code&gt; itself.&lt;/p&gt;
3361 &lt;p&gt;In the actual implementation of that trait, the &lt;code&gt;Err…
3362 the lifetime that refers to the input string. For example, there is a
3363 &lt;code&gt;BasicParseErrorKind::UnexpectedToken(Token&amp;lt;'i&amp;gt;…
3364 when there is an unexpected token. And to avoid copying the substring
3365 into the error, one returns a slice reference into the original
3366 string, thus the lifetime.&lt;/p&gt;
3367 &lt;p&gt;I was more of a Rust newbie back then, and it was very hard to …
3368 sense of how cssparser was meant to be used.&lt;/p&gt;
3369 &lt;p&gt;The process was more or less this:&lt;/p&gt;
3370 &lt;ul&gt;
3371 &lt;li&gt;
3372 &lt;p&gt;Port the C parsers to Rust; implement types for each CSS proper…
3373 &lt;/li&gt;
3374 &lt;li&gt;
3375 &lt;p&gt;Port the &lt;code&gt;&amp;amp;str&lt;/code&gt;-based parsers in…
3376 &lt;/li&gt;
3377 &lt;li&gt;
3378 &lt;p&gt;Fix the error handling scheme to match what cssparser's high-le…
3379 traits expect.&lt;/p&gt;
3380 &lt;/li&gt;
3381 &lt;/ul&gt;
3382 &lt;p&gt;This last point was... hard. Again, I wasn't comfortable enoug…
3383 Rust lifetimes and nested generics; in the end it was all right.&lt;/p&g…
3384 &lt;h2&gt;Moving declaration lists to Rust&lt;/h2&gt;
3385 &lt;p&gt;With the individual parsers for CSS properties done, and with t…
3386 already using a different type for each property, the next thing was
3387 to implement cssparser's traits to parse declaration lists.&lt;/p&gt;
3388 &lt;p&gt;Again, a declaration list looks like this:&lt;/p&gt;
3389 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
3390 &lt;span class="nt"&gt;stroke-width&lt;/span&gt;&lt;span class="o"&gt;:&…
3391 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
3392
3393 &lt;p&gt;It's essentially a key/value list.&lt;/p&gt;
3394 &lt;p&gt;The trait that cssparser wants us to implement is this:&lt;/p&g…
3395 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
3396 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;type&lt;/sp…
3397 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;type&lt;/sp…
3398
3399 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span…
3400 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;am…
3401 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;name&lt…
3402 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;input&l…
3403 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&…
3404 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
3405 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
3406
3407 &lt;p&gt;That is, define a type for a &lt;code&gt;Declaration&lt;/code&g…
3408 &lt;code&gt;parse_value()&lt;/code&gt; method that takes a &lt;code&gt;n…
3409 a &lt;code&gt;Declaration&lt;/code&gt; or an error.&lt;/p&gt;
3410 &lt;p&gt;What this &lt;em&gt;really&lt;/em&gt; means is that the type yo…
3411 &lt;code&gt;Declaration&lt;/code&gt; needs to be able to represent all t…
3412 that you care about. Thus, a struct plus a big enum like this:&lt;/p&gt;
3413 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
3414 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;pub&lt;/spa…
3415 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;pub&lt;/spa…
3416 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;pub&lt;/spa…
3417 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
3418
3419 &lt;span class="k"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&g…
3420 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;BaselineShi…
3421 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ClipPath&lt…
3422 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ClipRule&lt…
3423 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Color&lt;/s…
3424 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ColorInterp…
3425 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Direction&l…
3426 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;..&lt;/span…
3427 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
3428 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
3429
3430 &lt;p&gt;This gives us declaration lists (the stuff inside curly braces …
3431 CSS stylesheet), but it doesn't give us qualified rules, which are
3432 composed of selector names plus a declaration list.&lt;/p&gt;
3433 &lt;h2&gt;Refactoring towards real CSS concepts&lt;/h2&gt;
3434 &lt;p&gt;Paolo Borelli has been steadily refactoring librsvg and fixing …
3435 like the primitive obsession I mentioned above. We now have real
3436 concepts like a Document, Stylesheet, QualifiedRule, Rule, AtRule.&lt;/p…
3437 &lt;p&gt;This refactoring took a long time, because it involved redoing …
3438 loading code and its interaction with the CSS parser a few times.&lt;/p&…
3439 &lt;h2&gt;Implementing traits from the selectors crate&lt;/h2&gt;
3440 &lt;p&gt;The &lt;a href="https://docs.rs/selectors"&gt;selectors&lt;/a&g…
3441 contains Servo's code for parsing CSS selectors and doing matching.
3442 However, it is &lt;em&gt;extremely&lt;/em&gt; generic. Using it involve…
3443 good number of concepts.&lt;/p&gt;
3444 &lt;p&gt;For example, this &lt;code&gt;SelectorImpl&lt;/code&gt; trait h…
3445 collection of types that refer to your implementation of an element
3446 tree. How do you represent an attribute/value? How do you represent
3447 an identifier? How do you represent a namespace and a local name?&lt;/p…
3448 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
3449 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;type&lt;/sp…
3450 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;type&lt;/sp…
3451 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;type&lt;/sp…
3452 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;type&lt;/sp…
3453 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;type&lt;/sp…
3454 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;type&lt;/sp…
3455 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;type&lt;/sp…
3456 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;type&lt;/sp…
3457 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;type&lt;/sp…
3458 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;type&lt;/sp…
3459 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;type&lt;/sp…
3460 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;type&lt;/sp…
3461 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
3462 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
3463
3464 &lt;p&gt;A lot of those can be &lt;code&gt;String&lt;/code&gt;, but Serv…
3465 I ended up using the &lt;a href="https://docs.rs/markup5ever"&gt;&lt;cod…
3466 interning framework for markup and XML concepts like a &lt;code&gt;Local…
3467 &lt;code&gt;Namespace&lt;/code&gt;, etc. This reduces memory consumptio…
3468 storing string copies of element names everywhere, one just stores
3469 tokens for interned strings.&lt;/p&gt;
3470 &lt;p&gt;(In the meantime I had to implement support for XML namespaces,…
3471 the selectors code really wants, but which librsvg never supported.)&lt;…
3472 &lt;p&gt;Then, the selectors crate wants you to say how your code implem…
3473 element tree. It has a monster trait &lt;code&gt;Element&lt;/code&gt;:&…
3474 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
3475 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;type&lt;/sp…
3476
3477 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span…
3478
3479 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span…
3480
3481 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span…
3482
3483 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;..&lt;/span…
3484
3485 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span…
3486 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span…
3487
3488 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span…
3489 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;am…
3490 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;local_n…
3491 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&…
3492
3493 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span…
3494 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;am…
3495 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;id&lt;/…
3496 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;case_se…
3497 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&…
3498
3499 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;..&lt;/span…
3500 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
3501 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
3502
3503 &lt;p&gt;That is, when you provide an implementation of &lt;code&gt;Elem…
3504 &lt;code&gt;SelectorImpl&lt;/code&gt;, the selectors crate will know how…
3505 element tree and ask it questions like, "does this element have the id
3506 &lt;code&gt;#foo&lt;/code&gt;?"; "does this element have the name &lt;co…
3507 sense in the end, but it is quite intimidating when you are not 100%
3508 comfortable with webs of traits and associated types and generics with
3509 a bunch of trait bounds!&lt;/p&gt;
3510 &lt;p&gt;I tried implementing that trait twice in the last year, and fai…
3511 It turns out that its API &lt;a href="https://github.com/servo/servo/iss…
3512 fix&lt;/a&gt; that landed last
3513 June, but I didn't notice until a couple of weeks ago.&lt;/p&gt;
3514 &lt;h2&gt;So?&lt;/h2&gt;
3515 &lt;p&gt;Two days ago, Paolo and I committed the &lt;a href="https://git…
3516 completely replace
3517 libcroco&lt;/a&gt;.&lt;/p&gt;
3518 &lt;p&gt;And, after implementing CSS &lt;a href="https://gitlab.gnome.or…
3519 have real CSS concepts and a good pipeline for the CSS cascade), a
3520 bunch of very old bugs started falling down
3521 (&lt;a href="https://gitlab.gnome.org/GNOME/librsvg/issues/336"&gt;1&lt;…
3522 &lt;a href="https://gitlab.gnome.org/GNOME/librsvg/issues/466"&gt;2&lt;/…
3523 &lt;a href="https://gitlab.gnome.org/GNOME/librsvg/issues/428"&gt;3&lt;/…
3524 &lt;a href="https://gitlab.gnome.org/GNOME/librsvg/issues/167"&gt;4&lt;/…
3525 &lt;a href="https://gitlab.gnome.org/GNOME/librsvg/issues/79"&gt;5&lt;/a…
3526 &lt;a href="https://gitlab.gnome.org/GNOME/librsvg/issues/441"&gt;6&lt;/…
3527 &lt;p&gt;Now it is going to be easy to implement things like &lt;a href=…
3528 application specify a user
3529 stylesheet&lt;/a&gt;. In
3530 particular, this should let GTK remove the &lt;a href="https://gitlab.gn…
3531 hack&lt;/a&gt;
3532 it has to recolor SVG icons while using librsvg indirectly.&lt;/p&gt;
3533 &lt;h2&gt;Conclusion&lt;/h2&gt;
3534 &lt;p&gt;This will appear in librsvg 2.47.1 — that version will no lon…
3535 require libcroco.&lt;/p&gt;
3536 &lt;p&gt;As far as I know, the only module that still depends on libcroc…
3537 GNOME or otherwise) is &lt;strong&gt;gnome-shell&lt;/strong&gt;. It use…
3538 and get the basic structure of selectors so it can implement matching
3539 by hand.&lt;/p&gt;
3540 &lt;p&gt;Gnome-shell has some code which looks awfully similar to what l…
3541 had when it was written in C:&lt;/p&gt;
3542 &lt;ul&gt;
3543 &lt;li&gt;
3544 &lt;p&gt;&lt;a href="https://gitlab.gnome.org/GNOME/gnome-shell/blob/66f…
3545 has the high-level CSS stylesheet parser and the selector matching cod…
3546 &lt;/li&gt;
3547 &lt;li&gt;
3548 &lt;p&gt;&lt;a href="https://gitlab.gnome.org/GNOME/gnome-shell/blob/66f…
3549 has the low-level CSS property parsers.&lt;/p&gt;
3550 &lt;/li&gt;
3551 &lt;/ul&gt;
3552 &lt;p&gt;... and it turns out that those files come all the way from
3553 &lt;a href="https://blog.ometer.com/2006/10/14/text-layout-that-works-pr…
3554 the CSS-aware canvas that Mugshot used! Mugshot was a circa-2006
3555 pre-Facebook aggregator for social media data like blogs, Flickr
3556 pictures, etc. HippoCanvas also got used in Sugar, the GUI for
3557 One Laptop Per Child. Yes, our code is &lt;em&gt;that&lt;/em&gt; old…
3558 &lt;p&gt;Libcroco is unmaintained, and has outstanding CVEs. I would be…
3559 happy to assist someone in porting gnome-shell's CSS code to Rust :)&lt;…
3560 see if the gripes from my &lt;a href="https://people.gnome.org/~federico…
3561 things where it is not obvious how to proceed, I've started taking
3562 more detailed notes in a &lt;a href="https://gitlab.gnome.org/federico/g…
3563 &lt;p&gt;Today I was looking at which &lt;a href="https://gitlab.gnome.o…
3564 see if the gripes from my &lt;a href="https://people.gnome.org/~federico…
3565 things where it is not obvious how to proceed, I've started taking
3566 more detailed notes in a &lt;a href="https://gitlab.gnome.org/federico/g…
3567 &lt;p&gt;Today I was looking at which &lt;a href="https://gitlab.gnome.o…
3568 implemented by third parties, that is, which external projects provide
3569 their own image codecs pluggable into gdk-pixbuf.&lt;/p&gt;
3570 &lt;p&gt;And there are not that many!&lt;/p&gt;
3571 &lt;p&gt;The only four that I found are &lt;strong&gt;libheif, libopenra…
3572 librsvg&lt;/strong&gt; (this last one, of course).&lt;/p&gt;
3573 &lt;p&gt;&lt;em&gt;Update 2019/Sep/12&lt;/em&gt; - Added &lt;strong&gt;a…
3574 &lt;p&gt;All of those use the gdk-pixbuf module API in a remarkably simi…
3575 fashion. Did they cut&amp;amp;paste each other's code? Did they do the
3576 simplest thing that didn't crash in gdk-pixbuf's checks for buggy
3577 loaders, which happens to be exactly what they do? Who knows! Either
3578 way, this makes future API changes in the modules a lot easier, since
3579 they all do the same right now.&lt;/p&gt;
3580 &lt;p&gt;I'm trying to decide between these:&lt;/p&gt;
3581 &lt;ul&gt;
3582 &lt;li&gt;
3583 &lt;p&gt;Keep modules as they are; find a way to sandbox them from gdk-p…
3584 itself. This is hard because the API is "chatty"; modules and
3585 calling code go back and forth peeking at each other's structures.&lt;…
3586 &lt;/li&gt;
3587 &lt;li&gt;
3588 &lt;p&gt;Decide that third-party modules are only useful for thumbnailer…
3589 modify them to &lt;em&gt;be&lt;/em&gt; thumbnailers instead of generic…
3590 modules. This would mean that those formats would stop working
3591 automatically in gdk-pixbuf based viewers like EOG.&lt;/p&gt;
3592 &lt;/li&gt;
3593 &lt;li&gt;
3594 &lt;p&gt;Have "blessed" codecs inside gdk-pixbuf which are not modules so
3595 their no longer have API/ABI stability constraints. Keep
3596 third-party modules separate. Sandbox the internal ones with a
3597 non-chatty API.&lt;/p&gt;
3598 &lt;/li&gt;
3599 &lt;li&gt;
3600 &lt;p&gt;If all third-party modules work indeed as &lt;a href="https://g…
3601 module API can be simplified quite a lot since no third-party
3602 modules implement animations or saving. If so, simplify the module
3603 API and the gdk-pixbuf internals rather drastically.&lt;/p&gt;
3604 &lt;/li&gt;
3605 &lt;/ul&gt;
3606 &lt;p&gt;Do you know any other image formats which provide &lt;a href="h…
3607 modules&lt;/a&gt;? &lt;a href="mailto:[email protected]"&gt;Mail me, p…
3608 vulnerability&lt;/a&gt; in the code that processes &lt;code&gt;.desktop&…
3609 &lt;code&gt;.directory&lt;/code&gt; files, through which an attacker cou…
3610 file that causes shell command execution (&lt;a href="https://paper.seeb…
3611 full disclosure, where KDE didn't even get a chance of fixing the …&lt…
3612 vulnerability&lt;/a&gt; in the code that processes &lt;code&gt;.desktop&…
3613 &lt;code&gt;.directory&lt;/code&gt; files, through which an attacker cou…
3614 file that causes shell command execution (&lt;a href="https://paper.seeb…
3615 full disclosure, where KDE didn't even get a chance of fixing the bug
3616 before it was published.&lt;/p&gt;
3617 &lt;p&gt;There are many protocols for &lt;a href="https://en.wikipedia.o…
3618 coordinated, responsible fashion&lt;/a&gt;, but the gist of them is this…
3619 &lt;ol&gt;
3620 &lt;li&gt;
3621 &lt;p&gt;Someone finds a vulnerability in some software through studying
3622 some code, or some other mechanism.&lt;/p&gt;
3623 &lt;/li&gt;
3624 &lt;li&gt;
3625 &lt;p&gt;They report the vulnerability to the software's author through …
3626 private channel. For free softare in particular, researchers can
3627 use &lt;a href="https://oss-security.openwall.org/wiki/disclosure/res…
3628 researchers&lt;/a&gt;, which includes &lt;strong&gt;notifying the
3629 author/maintainer and distros and security groups.&lt;/strong&gt; Fr…
3630 software projects can &lt;a href="https://alexgaynor.net/2013/oct/19/…
3631 &lt;/li&gt;
3632 &lt;li&gt;
3633 &lt;p&gt;The author and reporter agree on a deadline for releasing a pub…
3634 report of the vulnerability, or in semi-automated systems like
3635 Google Zero, a deadline is automatically established.&lt;/p&gt;
3636 &lt;/li&gt;
3637 &lt;li&gt;
3638 &lt;p&gt;The author works on fixing the vulnerability.&lt;/p&gt;
3639 &lt;/li&gt;
3640 &lt;li&gt;
3641 &lt;p&gt;The deadline is reached; the patch has been publically released,
3642 the appropriate people have been notified, systems have been
3643 patched. If there is no patch, the author and reporter can agree
3644 on postponing the date, or the reporter can publish the
3645 vulnerability report, thus creating public pressure for a fix.&lt;/p&…
3646 &lt;/li&gt;
3647 &lt;/ol&gt;
3648 &lt;p&gt;The steps above gloss over many practicalities and issues from …
3649 real world, but the idea is basically this: the author or maintainer
3650 of the software is given a chance to fix a security bug before
3651 information on the vulnerability is released to the hostile world.
3652 The idea is to &lt;strong&gt;keep harm from being done&lt;/strong&gt; by…
3653 unpatched vulnerabilities until there is a fix for them (... or until
3654 the deadline expires).&lt;/p&gt;
3655 &lt;h2&gt;What happened instead&lt;/h2&gt;
3656 &lt;p&gt;Around the beginning of July, the reporter &lt;a href="https://…
3657 bugs in KDE&lt;/a&gt;.&lt;/p&gt;
3658 &lt;p&gt;On &lt;a href="https://twitter.com/zer0pwn/status/1156312405472…
3659 &lt;p&gt;On August 3, he &lt;a href="https://twitter.com/zer0pwn/status/…
3660 vulnerability.&lt;/p&gt;
3661 &lt;p&gt;On August 4, he &lt;a href="https://twitter.com/zer0pwn/status/…
3662 &lt;p&gt;KDE is left with having to patch this in emergency mode. On Au…
3663 KDE releases a &lt;a href="https://kde.org/info/security/advisory-201908…
3664 &lt;ul&gt;
3665 &lt;li&gt;
3666 &lt;p&gt;Description of exactly what causes the vulnerability.&lt;/p&gt;
3667 &lt;/li&gt;
3668 &lt;li&gt;
3669 &lt;p&gt;Description of how it was solved.&lt;/p&gt;
3670 &lt;/li&gt;
3671 &lt;li&gt;
3672 &lt;p&gt;Instructions on what to do for users of various versions of KDE
3673 libraries.&lt;/p&gt;
3674 &lt;/li&gt;
3675 &lt;li&gt;
3676 &lt;p&gt;Links to easy-to-cherry-pick patches for distro vendors.&lt;/p&…
3677 &lt;/li&gt;
3678 &lt;/ul&gt;
3679 &lt;p&gt;Now, distro vendors are, in turn, in emergency mode, as they mu…
3680 apply the patch, run it through QA, release their own advisories,
3681 etc.&lt;/p&gt;
3682 &lt;h2&gt;What if this had been done with coordinated disclosure?&lt;/h2…
3683 &lt;p&gt;The bug would have been fixed, probably in the same way, &lt;em…
3684 not be in emergency mode&lt;/em&gt;. &lt;a href="https://kde.org/info/s…
3685 &lt;blockquote&gt;
3686 &lt;p&gt;Thanks to Dominik Penner for finding and documenting this issue…
3687 have contacted us before making the issue public) and to David Faure for…
3688 &lt;/blockquote&gt;
3689 &lt;p&gt;This is an extremely gracious way of thanking the reporter.&lt;…
3690 &lt;h2&gt;I am not an infosec person...&lt;/h2&gt;
3691 &lt;p&gt;... but some behaviors in the infosec sphere are deeply uncomfo…
3692 to me. I don't like it when security "research" is hard to tell from
3693 vandalism. "Excuse me, you left your car door unlocked" vs. "Hey
3694 everyone, this car is unlocked, have at it".&lt;/p&gt;
3695 &lt;p&gt;I don't know the details of the discourse in the infosec sphere…
3696 full disclosure against irresponsible vendors of proprietary software or
3697 services. However, &lt;strong&gt;KDE is free software&lt;/strong&gt;! …
3698 an asshole to them.&lt;/p&gt;</content><category term="misc"></category>…
3699 &lt;ul&gt;
3700 &lt;li&gt;
3701 &lt;p&gt;From a constructor, calling a method on a partially-constructed
3702 object is dangerous.&lt;/p&gt;
3703 &lt;/li&gt;
3704 &lt;li&gt;
3705 &lt;p&gt;A constructor needs to set up "not quite initialized" values in…
3706 instance struct until a construct-time property is set.&lt;/p&gt;
3707 &lt;/li&gt;
3708 &lt;li&gt;
3709 &lt;p&gt;You actually need to override &lt;code&gt;GObjectClass::constru…
3710 &lt;ul&gt;
3711 &lt;li&gt;
3712 &lt;p&gt;From a constructor, calling a method on a partially-constructed
3713 object is dangerous.&lt;/p&gt;
3714 &lt;/li&gt;
3715 &lt;li&gt;
3716 &lt;p&gt;A constructor needs to set up "not quite initialized" values in…
3717 instance struct until a construct-time property is set.&lt;/p&gt;
3718 &lt;/li&gt;
3719 &lt;li&gt;
3720 &lt;p&gt;You actually need to override &lt;code&gt;GObjectClass::constru…
3721 &lt;code&gt;::constructor&lt;/code&gt;?) to take care of construct-onl…
3722 need to be considered together, not individually.&lt;/p&gt;
3723 &lt;/li&gt;
3724 &lt;li&gt;
3725 &lt;p&gt;Constructors can't report an error, unless you derive from
3726 &lt;code&gt;GInitable&lt;/code&gt;, which is not in gobject, but in gi…
3727 why does &lt;em&gt;that&lt;/em&gt; force the constructor to take a &lt…
3728 &lt;/li&gt;
3729 &lt;li&gt;
3730 &lt;p&gt;You need more than one constructor, but that needs to be done w…
3731 helper functions.&lt;/p&gt;
3732 &lt;/li&gt;
3733 &lt;/ul&gt;
3734 &lt;p&gt;This article, &lt;a href="https://matklad.github.io/2019/07/16/…
3735 Constructors&lt;/a&gt;,
3736 explains all of these problems very well. It is not centered on
3737 GObject, but rather on constructors in object-oriented languages in
3738 general.&lt;/p&gt;
3739 &lt;p&gt;(Spoiler: Rust does not have constructors or partially-initiali…
3740 these problems don't really exist there.)&lt;/p&gt;
3741 &lt;p&gt;(Addendum: &lt;em&gt;that&lt;/em&gt; makes it somewhat awkward …
3742 C to Rust, but librsvg was able to solve it nicely with
3743 &lt;code&gt;&amp;lt;buzzword&amp;gt;&lt;/code&gt;&lt;a href="http://clif…
3744 very nice tutorial on &lt;a href="https://nora.codes/tutorial/speedy-des…
3745 Rust&lt;/a&gt;.
3746 It covers prototyping a dice roller app with Glade, writing the code with
3747 Rust and the gtk-rs bindings, and integrating the app into the desktop w…
3748 a &lt;code&gt;.desktop&lt;/code&gt; file.&lt;/p&gt;</content><category t…
3749 the rsvg-view-3 program.&lt;/strong&gt;&lt;/p&gt;
3750 &lt;h2&gt;History of rsvg-view&lt;/h2&gt;
3751 &lt;p&gt;Rsvg-view &lt;a href="https://gitlab.gnome.org/GNOME/librsvg/bl…
3752 out&lt;/a&gt;
3753 as a 71-line C program to aid development of librsvg. It would just
3754 render an SVG file to a pixbuf, stick that pixbuf in a &lt;code&gt;GtkIm…
3755 widget …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I am prepari…
3756 the rsvg-view-3 program.&lt;/strong&gt;&lt;/p&gt;
3757 &lt;h2&gt;History of rsvg-view&lt;/h2&gt;
3758 &lt;p&gt;Rsvg-view &lt;a href="https://gitlab.gnome.org/GNOME/librsvg/bl…
3759 out&lt;/a&gt;
3760 as a 71-line C program to aid development of librsvg. It would just
3761 render an SVG file to a pixbuf, stick that pixbuf in a &lt;code&gt;GtkIm…
3762 widget, and show a window with that.&lt;/p&gt;
3763 &lt;p&gt;Over time, it slowly acquired most of the command-line options …
3764 &lt;code&gt;rsvg-convert&lt;/code&gt; supports. And I suppose, as a way…
3765 Cairo-ification of librsvg, it also got the ability to print SVG files
3766 to a &lt;code&gt;GtkPrintContext&lt;/code&gt;. At last count, it was a …
3767 that is not really the best code in the world.&lt;/p&gt;
3768 &lt;h2&gt;What makes rsvg-view awkward?&lt;/h2&gt;
3769 &lt;p&gt;Rsvg-view requires GTK. But GTK requires librsvg, indirectly, …
3770 gdk-pixbuf! There is not a hard circular dependency because GTK goes,
3771 "gdk-pixbuf, load me this SVG file" without knowing how it will be
3772 loaded. In turn, gdk-pixbuf initializes the SVG loader provided by
3773 librsvg, and that loader reads/renders the SVG file.&lt;/p&gt;
3774 &lt;p&gt;Ideally librsvg would only depend on gdk-pixbuf, so it would be…
3775 to provide the SVG loader.&lt;/p&gt;
3776 &lt;p&gt;The rsvg-view source code still has a few calls to GTK function…
3777 are now deprecated. The program emits GTK warnings during normal use.&l…
3778 &lt;p&gt;Rsvg-view is... not a very good SVG viewer. It doesn't even st…
3779 with the window scaled properly to the SVG's dimensions! If used for
3780 quick testing during development, it cannot even aid in viewing the
3781 transparent background regions which the SVG does not cover. It just
3782 sticks a lousy custom widget inside a &lt;code&gt;GtkScrolledWindow&lt;/…
3783 not have the conventional niceties to view images like zooming with
3784 the scroll wheel.&lt;/p&gt;
3785 &lt;p&gt;&lt;a href="https://wiki.gnome.org/Apps/EyeOfGnome/"&gt;EOG&lt;…
3786 invest effort in making it pleasant to use.&lt;/p&gt;
3787 &lt;h2&gt;Removal of rsvg-view&lt;/h2&gt;
3788 &lt;p&gt;So, the next version of librsvg will not provide the &lt;code&g…
3789 binary. Please update your packages accordingly. Distros may be able to
3790 move the compilation of librsvg to a more sensible place in the
3791 platform stack, now that it doesn't depend on GTK being available.&lt;/p…
3792 &lt;p&gt;What can you use instead? Any other image viewer. &lt;a href=…
3793 there are dozens of other good viewers, too.&lt;/p&gt;</content><categor…
3794 slight change of plans since &lt;a href="https://people.gnome.org/~feder…
3795 &lt;ul&gt;
3796 &lt;li&gt;
3797 &lt;p&gt;The 1.0.x series is in strict maintenance mode and will not cha…
3798 build systems. &lt;strong&gt;This is targeted towards embedded use&lt…
3799 projects which already embed the …&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;</…
3800 slight change of plans since &lt;a href="https://people.gnome.org/~feder…
3801 &lt;ul&gt;
3802 &lt;li&gt;
3803 &lt;p&gt;The 1.0.x series is in strict maintenance mode and will not cha…
3804 build systems. &lt;strong&gt;This is targeted towards embedded use&lt…
3805 projects which already embed the bzip2-1.0.6 sources and undoubtedly
3806 patch the build system. Right now this series, and the tagged 1.0.7
3807 release, live in the &lt;a href="https://sourceware.org/git/?p=bzip2.g…
3808 &lt;/li&gt;
3809 &lt;li&gt;
3810 &lt;p&gt;The 1.1.x series has Meson and CMake build systems, and a coupl…
3811 extra changes to modernize the C code but which were not fit for the
3812 1.0.7 release. &lt;strong&gt;This is targeted towards operating system
3813 distributions&lt;/strong&gt;. This lives in the master branch of the …
3814 repository for bzip2&lt;/a&gt;.&lt;/p&gt;
3815 &lt;/li&gt;
3816 &lt;/ul&gt;
3817 &lt;p&gt;&lt;strong&gt;Distros and embedded users&lt;/strong&gt; should …
3818 immediately. The patches they already have for the bzip2's
3819 traditional build system should still apply. The release includes bug
3820 fixes and security fixes that have accumulated over the years,
3821 including the new &lt;a href="https://gitlab.com/federicomenaquintero/bz…
3822 &lt;p&gt;Once 1.1.0 is released, distributions should be able to remove …
3823 patches to the build system and just start using Meson or CMake. You
3824 may want to monitor the &lt;a href="https://gitlab.com/federicomenaquint…
3825 appreciated fixing the issues there so we can make the first release
3826 with the new build systems!&lt;/p&gt;</content><category term="misc"></c…
3827 &lt;p&gt;I am preparing a bzip2-1.0.7 release. You can see the &lt;a hr…
3828 notes&lt;/a&gt;, which should be of interest:&lt;/p&gt;
3829 &lt;ul&gt;
3830 &lt;li&gt;
3831 &lt;p&gt;Many historical patches from various distributions are integrat…
3832 now.&lt;/p&gt;
3833 &lt;/li&gt;
3834 &lt;li&gt;
3835 &lt;p&gt;We have a new fix for the just-published &lt;a href="https://cv…
3836 &lt;p&gt;I am preparing a bzip2-1.0.7 release. You can see the &lt;a hr…
3837 notes&lt;/a&gt;, which should be of interest:&lt;/p&gt;
3838 &lt;ul&gt;
3839 &lt;li&gt;
3840 &lt;p&gt;Many historical patches from various distributions are integrat…
3841 now.&lt;/p&gt;
3842 &lt;/li&gt;
3843 &lt;li&gt;
3844 &lt;p&gt;We have a new fix for the just-published &lt;a href="https://cv…
3845 Albert Astals Cid.&lt;/p&gt;
3846 &lt;/li&gt;
3847 &lt;li&gt;
3848 &lt;p&gt;&lt;strong&gt;Bzip2 has moved to Meson&lt;/strong&gt; for its p…
3849 courtesy of Dylan Baker. For special situations, a CMake build
3850 system is also provided, courtesy of Micah Snyder.&lt;/p&gt;
3851 &lt;/li&gt;
3852 &lt;/ul&gt;
3853 &lt;h2&gt;What's with the soname?&lt;/h2&gt;
3854 &lt;p&gt;From bzip2-1.0.1 (from the year 2000), until bzip2-1.0.6 (from …
3855 release tarballs came with a special
3856 &lt;a href="https://gitlab.com/federicomenaquintero/bzip2/blob/962d60610…
3857 instead of a static one.&lt;/p&gt;
3858 &lt;p&gt;This never used libtool or anything; it specified linker flags …
3859 hand. Various distributions either patched this special makefile, or
3860 replaced it by another one, or outright replaced the complete build
3861 system for a different one.&lt;/p&gt;
3862 &lt;p&gt;Some things to note:&lt;/p&gt;
3863 &lt;ul&gt;
3864 &lt;li&gt;
3865 &lt;p&gt;This hand-written &lt;a href="https://gitlab.com/federicomenaqu…
3866 line like &lt;code&gt;$(CC) -shared -Wl,-soname -Wl,libbz2.so.1.0 -o
3867 libbz2.so.1.0.6&lt;/code&gt;. This means, make the DT_SONAME field in…
3868 ELF file be &lt;code&gt;libbz2.so.1.0&lt;/code&gt; (note the two digit…
3869 the filename of the shared library be &lt;code&gt;libbz2.so.1.0.6&lt;/…
3870 &lt;/li&gt;
3871 &lt;li&gt;
3872 &lt;p&gt;Fedora patched the soname in a patch called "saneso" to just be
3873 &lt;code&gt;libbz2.so.1&lt;/code&gt;.&lt;/p&gt;
3874 &lt;/li&gt;
3875 &lt;li&gt;
3876 &lt;p&gt;Stanislav Brabec, from openSUSE, &lt;a href="https://gitlab.com…
3877 makefiles with autotools&lt;/a&gt;, which meant using libtool. It
3878 has this interesting note:&lt;/p&gt;
3879 &lt;/li&gt;
3880 &lt;/ul&gt;
3881 &lt;blockquote&gt;
3882 &lt;p&gt;Incompatible changes:&lt;/p&gt;
3883 &lt;p&gt;soname change. Libtool has no support for two parts soname suff…
3884 libbz2.so.1.0). It must be a single number (e. g. libbz2.so.1). That is
3885 why soname must change. But I see not a big problem with it. Several
3886 distributions already use the new number instead of the non-standard
3887 number from Makefile-libbz2_so.&lt;/p&gt;
3888 &lt;/blockquote&gt;
3889 &lt;p&gt;(In fact, if I do &lt;code&gt;objdump -x /usr/lib64/*.so | grep…
3890 that most libraries have single-digit sonames.)&lt;/p&gt;
3891 &lt;p&gt;In my experience, both Fedora and openSUSE are very strict, and
3892 correct, about obscure things like library sonames.&lt;/p&gt;
3893 &lt;p&gt;With the switch to Meson, bzip2 no longer uses libtool. It wil…
3894 a single-digit soname — this is not in the &lt;code&gt;meson.build&lt;…
3895 expect it to be there within the next couple of days.&lt;/p&gt;
3896 &lt;p&gt;I don't know what distros which decided to preserve the &lt;cod…
3897 will need to do; maybe they will need to patch &lt;code&gt;meson.build&l…
3898 own.&lt;/p&gt;
3899 &lt;p&gt;Fortunately, &lt;strong&gt;the API/ABI are still exactly the sa…
3900 preserve the old soname which your distro was using and linking libbz2
3901 will probably keep working as usual.&lt;/p&gt;
3902 &lt;p&gt;(This is a C-only release as usual. The Rust branch is still
3903 experimental.)&lt;/p&gt;</content><category term="misc"></category><cate…
3904 &lt;p&gt;&lt;a href="https://gitlab.com/federicomenaquintero/bzip2/blob/…
3905 numbers. This table is used by &lt;a href="https://gitlab.com/federicom…
3906 bzlib_private.h&lt;/a&gt;:&lt;/p&gt;
3907 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
3908
3909 &lt;span class="cp"&gt;#define BZ_RAND_DECLS \&…
3910 &lt;span class="cp"&gt; Int32 rNToGo; \&…
3911 &lt;span class="cp"&gt; Int32 rTPos \&…
3912
3913 &lt;span class="cp"&gt;#define BZ_RAND_INIT_MASK \&…
3914 &lt;span class="cp"&gt; s-&amp;gt;rNToGo = 0; …
3915 &lt;span class="cp"&gt; s-&amp;gt;rTPos = 0 …
3916
3917 &lt;span class="cp"&gt;#define BZ_RAND_MASK ((s- …&lt;/span&gt;&lt;/co…
3918 &lt;p&gt;&lt;a href="https://gitlab.com/federicomenaquintero/bzip2/blob/…
3919 numbers. This table is used by &lt;a href="https://gitlab.com/federicom…
3920 bzlib_private.h&lt;/a&gt;:&lt;/p&gt;
3921 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
3922
3923 &lt;span class="cp"&gt;#define BZ_RAND_DECLS \&…
3924 &lt;span class="cp"&gt; Int32 rNToGo; \&…
3925 &lt;span class="cp"&gt; Int32 rTPos \&…
3926
3927 &lt;span class="cp"&gt;#define BZ_RAND_INIT_MASK \&…
3928 &lt;span class="cp"&gt; s-&amp;gt;rNToGo = 0; …
3929 &lt;span class="cp"&gt; s-&amp;gt;rTPos = 0 …
3930
3931 &lt;span class="cp"&gt;#define BZ_RAND_MASK ((s-&amp;gt;rNToGo == 1) ? 1…
3932
3933 &lt;span class="cp"&gt;#define BZ_RAND_UPD_MASK \&…
3934 &lt;span class="cp"&gt; if (s-&amp;gt;rNToGo == 0) { …
3935 &lt;span class="cp"&gt; s-&amp;gt;rNToGo = BZ2_rNums[s-&amp;gt;rTPo…
3936 &lt;span class="cp"&gt; s-&amp;gt;rTPos++; …
3937 &lt;span class="cp"&gt; if (s-&amp;gt;rTPos == 512) s-&amp;gt;rTPos…
3938 &lt;span class="cp"&gt; } \&…
3939 &lt;span class="cp"&gt; s-&amp;gt;rNToGo--;&lt;/span&gt;
3940 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
3941
3942 &lt;p&gt;Here, &lt;code&gt;BZ_RAND_DECLS&lt;/code&gt; is used to declare…
3943 &lt;code&gt;rTPos&lt;/code&gt;, into two structs (&lt;a href="https://gi…
3944 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
3945 &lt;span class="p"&gt;...&lt;/span&gt;
3946 &lt;span class="n"&gt;Bool&lt;/span&gt; &lt;span class="n"&gt;blo…
3947 &lt;span class="n"&gt;BZ_RAND_DECLS&lt;/span&gt;
3948 &lt;span class="p"&gt;...&lt;/span&gt;
3949 &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="n"&gt;DState&lt;/sp…
3950 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
3951
3952 &lt;p&gt;Then, the code that needs to initialize those fields calls
3953 &lt;code&gt;BZ_RAND_INIT_MASK&lt;/code&gt;, which expands into code to s…
3954 zero.&lt;/p&gt;
3955 &lt;p&gt;At several points in the code, &lt;code&gt;BZ_RAND_UPD_MASK&lt;…
3956 expands into code that updates the randomization state, or something
3957 like that, and uses &lt;code&gt;BZ_RAND_MASK&lt;/code&gt; to get a usefu…
3958 randomization state.&lt;/p&gt;
3959 &lt;p&gt;I have no idea yet what the state is about, but let's port it
3960 directly.&lt;/p&gt;
3961 &lt;h2&gt;Give things a name&lt;/h2&gt;
3962 &lt;p&gt;It's interesting to see that &lt;strong&gt;no code except for t…
3963 the fields &lt;code&gt;rNToGo&lt;/code&gt; and &lt;code&gt;rTPos&lt;/cod…
3964 &lt;code&gt;BZ_RAND_DECLS&lt;/code&gt;. So, let's make up a &lt;strong&…
3965 Since I have no better name for it, I shall call it just
3966 &lt;a href="https://gitlab.com/federicomenaquintero/bzip2/commit/7bd2dc3…
3967 and replaced the macro-which-creates-struct-fields with a
3968 &lt;code&gt;RandState&lt;/code&gt;-typed field:&lt;/p&gt;
3969 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
3970 - Int32 rNToGo; \
3971 - Int32 rTPos \
3972 +typedef struct {
3973 + Int32 rNToGo;
3974 + Int32 rTPos;
3975 +} RandState;
3976
3977 ...
3978
3979 - BZ_RAND_DECLS;
3980 + RandState rand;
3981 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
3982
3983 &lt;p&gt;Since the fields now live inside a sub-struct, I changed the ot…
3984 macros to use &lt;code&gt;s-&amp;gt;rand.rNToGo&lt;/code&gt; instead of …
3985 for the other field.&lt;/p&gt;
3986 &lt;h2&gt;Turn macros into functions&lt;/h2&gt;
3987 &lt;p&gt;Now, three commits (&lt;a href="https://gitlab.com/federicomena…
3988 macros &lt;code&gt;BZ_RAND_INIT_MASK&lt;/code&gt;, &lt;code&gt;BZ_RAND_M…
3989 into functions.&lt;/p&gt;
3990 &lt;p&gt;And now that the functions live in the same C source file as the
3991 lookup table they reference, &lt;a href="https://gitlab.com/federicomena…
3992 avoid having it as read/write unshared data in the linked binary.&lt;/p&…
3993 &lt;p&gt;Premature optimization concern: doesn't de-inlining those macr…
3994 cause performance problems? At first, we will get the added overhead
3995 from a function call. When the whole code is ported to Rust, the Rust
3996 compiler will probably be able to figure out that those tiny functions
3997 can be inlined (or we can &lt;code&gt;#[inline]&lt;/code&gt; them by han…
3998 or if we have more hubris than faith in LLVM).&lt;/p&gt;
3999 &lt;h2&gt;Port functions and table to Rust&lt;/h2&gt;
4000 &lt;p&gt;The functions are so tiny, and the table so cut-and-pasteable, …
4001 it's easy to &lt;a href="https://gitlab.com/federicomenaquintero/bzip2/c…
4002 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
4003 &lt;span class="k"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&g…
4004 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RandState&l…
4005 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rNToGo&…
4006 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rTPos&l…
4007 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&…
4008 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
4009
4010 &lt;span class="cp"&gt;#[no_mangle]&lt;/span&gt;&lt;span class="w"&gt;&l…
4011 &lt;span class="k"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&g…
4012 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span…
4013 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/…
4014 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&…
4015 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/…
4016 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&…
4017 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
4018
4019 &lt;span class="cp"&gt;#[no_mangle]&lt;/span&gt;&lt;span class="w"&gt;&l…
4020 &lt;span class="k"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&g…
4021 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span…
4022 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;r&lt;/s…
4023 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;r&lt;/s…
4024 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/…
4025 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;r&l…
4026 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/s…
4027 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&…
4028 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&…
4029 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
4030 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
4031
4032 &lt;p&gt;Also, we define the &lt;code&gt;RandState&lt;/code&gt; type as …
4033 &lt;a href="https://gitlab.com/federicomenaquintero/bzip2/blob/dc01d95a7…
4034 as the C struct. &lt;strong&gt;This is what allows us to have a &lt;cod…
4035 the C struct&lt;/strong&gt;, while in reality the C code doesn't access …
4036 directly; it is just used as a struct field.&lt;/p&gt;
4037 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
4038 &lt;span class="cp"&gt;#[repr(C)]&lt;/span&gt;&lt;span class="w"&gt;&lt;…
4039 &lt;span class="k"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&g…
4040 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rNToGo&lt;/…
4041 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rTPos&lt;/s…
4042 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
4043 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
4044
4045 &lt;p&gt;&lt;a href="https://gitlab.com/federicomenaquintero/bzip2/commi…
4046 declarations in &lt;code&gt;bzlib_private.h&lt;/code&gt;. With those fu…
4047 ported to Rust, we can remove &lt;code&gt;randtable.c&lt;/code&gt;. Yay…
4048 &lt;h2&gt;A few cleanups&lt;/h2&gt;
4049 &lt;p&gt;After moving to another house one throws away useless boxes; we…
4050 to do some cleanup in the Rust code after the initial port, too.&lt;/p&g…
4051 &lt;p&gt;Rust prefers snake_case fields rather than camelCase ones, and I
4052 agree. I &lt;a href="https://gitlab.com/federicomenaquintero/bzip2/comm…
4053 &lt;p&gt;Then, I discovered that the &lt;code&gt;EState&lt;/code&gt; str…
4054 fields for the randomization state. I just &lt;a href="https://gitlab.c…
4055 &lt;h2&gt;Exegesis&lt;/h2&gt;
4056 &lt;p&gt;What is that randomization state all about?&lt;/p&gt;
4057 &lt;p&gt;And why does &lt;code&gt;DState&lt;/code&gt; (the struct used d…
4058 randomization state, but &lt;code&gt;EState&lt;/code&gt; (used during co…
4059 need it?&lt;/p&gt;
4060 &lt;p&gt;I found &lt;a href="https://gitlab.com/federicomenaquintero/bzi…
4061 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
4062 &lt;span class="cm"&gt; Now a single bit indicating (non-)random…
4063 &lt;span class="cm"&gt; As of version 0.9.5, we use a better sor…
4064 &lt;span class="cm"&gt; which makes randomisation unnecessary. …
4065 &lt;span class="cm"&gt; the randomised bit to &amp;#39;no&amp;#3…
4066 &lt;span class="cm"&gt; still needs to be able to handle randomi…
4067 &lt;span class="cm"&gt; so as to maintain backwards compatibilit…
4068 &lt;span class="cm"&gt; older versions of bzip2.&lt;/span&gt;
4069 &lt;span class="cm"&gt; --*/&lt;/span&gt;
4070 &lt;span class="n"&gt;bsW&lt;/span&gt;&lt;span class="p"&gt;(&lt;/…
4071 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
4072
4073 &lt;p&gt;Okay! So &lt;em&gt;compression&lt;/em&gt; no longer uses rando…
4074 &lt;em&gt;decompression&lt;/em&gt; has to support files which were compr…
4075 randomization. Here, &lt;code&gt;bsW(s,1,0)&lt;/code&gt; always writes …
4076 &lt;p&gt;However, the decompression code &lt;a href="https://gitlab.com/…
4077 bit&lt;/a&gt; from the file so that it can see whether it is
4078 dealing with an old-format file:&lt;/p&gt;
4079 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
4080 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
4081
4082 &lt;p&gt;Later in the code, this &lt;code&gt;s-&amp;gt;blockRandomised&l…
4083 the bit is on, the code calls &lt;code&gt;BZ2_rand_update_mask()&lt;/cod…
4084 appropriate. If one is using files compressed with Bzip2 0.9.5 or
4085 later, those randomization functions are not even called.&lt;/p&gt;
4086 &lt;p&gt;Talk about preserving compatibility with the past.&lt;/p&gt;
4087 &lt;h2&gt;Explanation, or building my headcanon&lt;/h2&gt;
4088 &lt;p&gt;Bzip2's compression starts by running a &lt;a href="https://en.…
4089 Transform&lt;/a&gt; on a block of data to compress, which is a wonderful
4090 algorithm that I'm trying to fully understand. Part of the BWT
4091 involves sorting all the string rotations of the block in question.&lt;/…
4092 &lt;p&gt;Per &lt;a href="https://gitlab.com/federicomenaquintero/bzip2/b…
4093 randomization helper to make sorting perform well in extreme cases,
4094 but not-so-old versions fixed this.&lt;/p&gt;
4095 &lt;p&gt;This explains why the decompression struct &lt;code&gt;DState&l…
4096 &lt;code&gt;blockRandomised&lt;/code&gt; bit, but the compression struct…
4097 need one. The fields that the original macro was pasting into
4098 &lt;code&gt;EState&lt;/code&gt; were just a vestige from 1999, which is …
4099 released.&lt;/p&gt;</content><category term="misc"></category><category …
4100 &lt;p&gt;Perhaps the most exciting thing is that Dylan Baker made a mer…
4101 request to add &lt;a href="https://gitlab.com/federicomenaquintero/bzip2…
4102 merged now into the master branch.&lt;/p&gt;
4103 &lt;p&gt;The current status is this:&lt;/p&gt;
4104 &lt;ul&gt;
4105 &lt;li&gt;Both Meson and Autotools are …&lt;/li&gt;&lt;/ul&gt;</summar…
4106 &lt;p&gt;Perhaps the most exciting thing is that Dylan Baker made a mer…
4107 request to add &lt;a href="https://gitlab.com/federicomenaquintero/bzip2…
4108 merged now into the master branch.&lt;/p&gt;
4109 &lt;p&gt;The current status is this:&lt;/p&gt;
4110 &lt;ul&gt;
4111 &lt;li&gt;Both Meson and Autotools are supported.&lt;/li&gt;
4112 &lt;li&gt;We have CI runs for both build systems.&lt;/li&gt;
4113 &lt;/ul&gt;
4114 &lt;h2&gt;A plea for help: add CI runners for other platforms!&lt;/h2&gt;
4115 &lt;p&gt;Do you use *BSD / Windows / Solaris / etc. and know how to make
4116 Gitlab's CI work for them?&lt;/p&gt;
4117 &lt;p&gt;The only runners we have now for bzip2 are for well-known Linux
4118 distros. I would really like to keep bzip2 working on non-Linux
4119 platforms. If you know how to make Gitlab CI runners for other
4120 systems, &lt;a href="https://gitlab.com/federicomenaquintero/bzip2/merge…
4121 &lt;h2&gt;Why two build systems?&lt;/h2&gt;
4122 &lt;p&gt;Mainly uncertainty on my part. I haven't used Meson extensivel…
4123 people tell me that it works better than Autotools out of the box for
4124 Windows.&lt;/p&gt;
4125 &lt;p&gt;Bzip2 runs on all sorts of ancient systems, and I don't know wh…
4126 Meson or Autotools will be a better fit for them. Time will tell.
4127 Hopefully in the future we can have only a single supported build
4128 system for bzip2.&lt;/p&gt;</content><category term="misc"></category><c…
4129 branch&lt;/a&gt;, which means that if you had a previous clone of this
4130 repository, you'll have to re-fetch it and rebase any changes you may
4131 have on top.&lt;/p&gt;
4132 &lt;p&gt;I apologize for the inconvenience!&lt;/p&gt;
4133 &lt;p&gt;But I have a good excuse: Julian …&lt;/p&gt;</summary><conte…
4134 branch&lt;/a&gt;, which means that if you had a previous clone of this
4135 repository, you'll have to re-fetch it and rebase any changes you may
4136 have on top.&lt;/p&gt;
4137 &lt;p&gt;I apologize for the inconvenience!&lt;/p&gt;
4138 &lt;p&gt;But I have a good excuse: Julian Seward pointed me to a &lt;a…
4139 at sourceware&lt;/a&gt; where Mark Wielaard reconstructed a commit
4140 history for bzip2, based on the historical tarballs starting from
4141 bzip2-0.1. Bzip2 was never maintained under revision control, so the
4142 reconstructed repository should be used mostly for historical
4143 reference (go look for &lt;code&gt;bzip2.exe&lt;/code&gt; in the initial…
4144 &lt;p&gt;I have rebased all the post-1.0.6 commits on top of Mark's repo…
4145 this is what is in the &lt;a href="https://gitlab.com/federicomenaquinte…
4146 &lt;p&gt;There is a new &lt;a href="https://gitlab.com/federicomenaquint…
4147 where I will do the gradual port to Rust.&lt;/p&gt;
4148 &lt;p&gt;I foresee no other force-pushes to the master branch in the fut…
4149 Apologies again if this disrupts your workflow.&lt;/p&gt;
4150 &lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; &lt;a href="https://gitlab…
4151 weave the histories together, I'll do another force-push, the very
4152 last one, I promise. If you send merge requests, I'll rebase them
4153 myself if that happens.&lt;/p&gt;</content><category term="misc"></categ…
4154 and &lt;a href="http://valgrind.org/"&gt;Valgrind&lt;/a&gt; fame. Julia…
4155 to cede the maintainership of &lt;a href="https://sourceware.org/bzip2/"…
4156 to me.&lt;/p&gt;
4157 &lt;p&gt;Bzip2 has not had a release since 2010. In the meantime, Linux
4158 distros have accumulated a number of bug/security fixes for it …&lt;/p…
4159 and &lt;a href="http://valgrind.org/"&gt;Valgrind&lt;/a&gt; fame. Julia…
4160 to cede the maintainership of &lt;a href="https://sourceware.org/bzip2/"…
4161 to me.&lt;/p&gt;
4162 &lt;p&gt;Bzip2 has not had a release since 2010. In the meantime, Linux
4163 distros have accumulated a number of bug/security fixes for it.
4164 Seemingly every distributor of bzip2 patches its build system. The
4165 documentation generation step is a bit creaky. There is no source
4166 control repository, nor bug tracker. I hope to fix these things
4167 gradually.&lt;/p&gt;
4168 &lt;p&gt;This is the new &lt;a href="https://gitlab.com/federicomenaquin…
4169 &lt;p&gt;Ways in which you can immediately help by submitting merge requ…
4170 &lt;ul&gt;
4171 &lt;li&gt;
4172 &lt;p&gt;Look at the &lt;a href="https://gitlab.com/federicomenaquintero…
4173 version number.&lt;/p&gt;
4174 &lt;/li&gt;
4175 &lt;li&gt;
4176 &lt;p&gt;Create a basic &lt;a href="https://gitlab.com/help/ci/README.md…
4177 builds the code and runs the tests.&lt;/p&gt;
4178 &lt;/li&gt;
4179 &lt;li&gt;
4180 &lt;p&gt;Test the autotools setup, courtesy of Stanislav Brabec, and imp…
4181 it as you see fit.&lt;/p&gt;
4182 &lt;/li&gt;
4183 &lt;/ul&gt;
4184 &lt;p&gt;The &lt;a href="https://people.gnome.org/~federico/blog/bzip2-i…
4185 until the Autotools setup settles down.&lt;/p&gt;
4186 &lt;p&gt;I hope to have a 1.0.7 release soon, but this really needs &lt;…
4187 help. Let's revive this awesome little project.&lt;/p&gt;</content><cat…
4188 &lt;a href="https://sourceware.org/bzip2/"&gt;bzip2/bzlib&lt;/a&gt; to R…
4189 serve to refresh bzip2, which had its last release in 2010 and has
4190 been nominally unmaintained for years.&lt;/p&gt;
4191 &lt;p&gt;I hope to make several posts detailing how this port is done �…
4192 &lt;a href="https://sourceware.org/bzip2/"&gt;bzip2/bzlib&lt;/a&gt; to R…
4193 serve to refresh bzip2, which had its last release in 2010 and has
4194 been nominally unmaintained for years.&lt;/p&gt;
4195 &lt;p&gt;I hope to make several posts detailing how this port is done. …
4196 post, I'll talk about setting up a Rust infrastructure for bzip2 and
4197 my experiments in replacing the C code that does CRC32 computations.&lt;…
4198 &lt;h2&gt;Super-quick summary of how librsvg was ported to Rust&lt;/h2&g…
4199 &lt;ul&gt;
4200 &lt;li&gt;
4201 &lt;p&gt;Add the necessary autotools infrastructure to build a Rust
4202 sub-library that gets linked into the main public library.&lt;/p&gt;
4203 &lt;/li&gt;
4204 &lt;li&gt;
4205 &lt;p&gt;Port bit by bit to Rust. Add unit tests as appropriate. Refac…
4206 endlessly.&lt;/p&gt;
4207 &lt;/li&gt;
4208 &lt;li&gt;
4209 &lt;p&gt;&lt;strong&gt;MAINTAIN THE PUBLIC API/ABI AT ALL COSTS&lt;/stro…
4210 notice that the library is being rewritten under their feet.&lt;/p&gt;
4211 &lt;/li&gt;
4212 &lt;/ul&gt;
4213 &lt;p&gt;I have no idea of how bzip2 works internally, but I do know how…
4214 maintain ABIs, so let's get started.&lt;/p&gt;
4215 &lt;h2&gt;Bzip2's source tree&lt;/h2&gt;
4216 &lt;p&gt;As a very small project that just builds a library and couple of
4217 executables, bzip2 was structured with all the source files directly
4218 under a toplevel directory.&lt;/p&gt;
4219 &lt;p&gt;The only tests in there are three reference files that get comp…
4220 then uncompressed, and then compared to the original ones.&lt;/p&gt;
4221 &lt;p&gt;As the rustification proceeds, I'll move the files around to be…
4222 places. The scheme from librsvg worked well in this respect, so I'll
4223 probably be copying many of the techniques and organization from
4224 there.&lt;/p&gt;
4225 &lt;h2&gt;Deciding what to port first&lt;/h2&gt;
4226 &lt;p&gt;I looked a bit at the bzip2 sources, and the code to do CRC32
4227 computations seemed isolated enough from the rest of the code to port
4228 easily.&lt;/p&gt;
4229 &lt;p&gt;The CRC32 code was arranged like this. First, a lookup table in
4230 &lt;code&gt;crc32table.c&lt;/code&gt;:&lt;/p&gt;
4231 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
4232 &lt;span class="mh"&gt;0x00000000L&lt;/span&gt;&lt;span class="p"&gt;…
4233 &lt;span class="mh"&gt;0x130476dcL&lt;/span&gt;&lt;span class="p"&gt;…
4234 &lt;span class="p"&gt;...&lt;/span&gt;
4235 &lt;span class="p"&gt;}&lt;/span&gt;
4236 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
4237
4238 &lt;p&gt;And then, three macros in &lt;code&gt;bzlib_private.h&lt;/code&…
4239 CRC32 code in the library:&lt;/p&gt;
4240 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
4241
4242 &lt;span class="cp"&gt;#define BZ_INITIALISE_CRC(crcVar) \&…
4243 &lt;span class="cp"&gt;{ \&…
4244 &lt;span class="cp"&gt; crcVar = 0xffffffffL; \&…
4245 &lt;span class="cp"&gt;}&lt;/span&gt;
4246
4247 &lt;span class="cp"&gt;#define BZ_FINALISE_CRC(crcVar) \&…
4248 &lt;span class="cp"&gt;{ \&…
4249 &lt;span class="cp"&gt; crcVar = ~(crcVar); \&…
4250 &lt;span class="cp"&gt;}&lt;/span&gt;
4251
4252 &lt;span class="cp"&gt;#define BZ_UPDATE_CRC(crcVar,cha) \&…
4253 &lt;span class="cp"&gt;{ \&…
4254 &lt;span class="cp"&gt; crcVar = (crcVar &amp;lt;&amp;lt; 8) ^ …
4255 &lt;span class="cp"&gt; BZ2_crc32Table[(crcVar &amp;gt;&amp;g…
4256 &lt;span class="cp"&gt; ((UChar)cha)]; \&…
4257 &lt;span class="cp"&gt;}&lt;/span&gt;
4258 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
4259
4260 &lt;p&gt;Initially I wanted to just remove this code and replace it with…
4261 the existing Rust crates to do CRC32 computations, but first I needed
4262 to know which variant of CRC32 this is.&lt;/p&gt;
4263 &lt;h2&gt;Preparing the CRC32 port so it will not break&lt;/h2&gt;
4264 &lt;p&gt;I needed to set up tests for the CRC32 code so the replacement …
4265 would compute exactly the same values as the original:&lt;/p&gt;
4266 &lt;ul&gt;
4267 &lt;li&gt;&lt;a href="https://gitlab.com/federicomenaquintero/bzip2/comm…
4268 crc32.c&lt;/a&gt; -
4269 that file is going to hold all the CRC32 code, not only the lookup tab…
4270 &lt;li&gt;&lt;a href="https://gitlab.com/federicomenaquintero/bzip2/comm…
4271 functions&lt;/a&gt; -
4272 so I can move them to Rust and have the C code call them.&lt;/li&gt;
4273 &lt;/ul&gt;
4274 &lt;p&gt;Then I needed a test that computed the CRC32 values of several
4275 strings, so I could capture the results and make them part of the
4276 test.&lt;/p&gt;
4277 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
4278 &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;const&lt…
4279 &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;const&lt…
4280 &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;const&lt…
4281
4282 &lt;span class="kt"&gt;int&lt;/span&gt;
4283 &lt;span class="nf"&gt;main&lt;/span&gt; &lt;span class="p"&gt;(&lt;/spa…
4284 &lt;span class="p"&gt;{&lt;/span&gt;
4285 &lt;span class="n"&gt;printf&lt;/span&gt; &lt;span class="p"&gt;(&lt…
4286 &lt;span class="n"&gt;printf&lt;/span&gt; &lt;span class="p"&gt;(&lt…
4287 &lt;span class="n"&gt;printf&lt;/span&gt; &lt;span class="p"&gt;(&lt…
4288 &lt;span class="n"&gt;printf&lt;/span&gt; &lt;span class="p"&gt;(&lt…
4289 &lt;span class="c1"&gt;// ...&lt;/span&gt;
4290 &lt;span class="p"&gt;}&lt;/span&gt;
4291 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
4292
4293 &lt;p&gt;This computes the CRC32 values of some strings using the origin…
4294 algorithm, and prints their results. Then I could cut&amp;amp;paste tho…
4295 results, and turn the &lt;code&gt;printf&lt;/code&gt; into &lt;code&gt;a…
4296 test.&lt;/p&gt;
4297 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
4298 &lt;span class="nf"&gt;main&lt;/span&gt; &lt;span class="p"&gt;(&lt;/spa…
4299 &lt;span class="p"&gt;{&lt;/span&gt;
4300 &lt;span class="n"&gt;assert&lt;/span&gt; &lt;span class="p"&gt;(&lt…
4301 &lt;span class="n"&gt;assert&lt;/span&gt; &lt;span class="p"&gt;(&lt…
4302 &lt;span class="n"&gt;assert&lt;/span&gt; &lt;span class="p"&gt;(&lt…
4303 &lt;span class="n"&gt;assert&lt;/span&gt; &lt;span class="p"&gt;(&lt…
4304 &lt;span class="c1"&gt;// ...&lt;/span&gt;
4305 &lt;span class="p"&gt;}&lt;/span&gt;
4306 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
4307
4308 &lt;h2&gt;Setting up a Rust infrastructure for bzip2&lt;/h2&gt;
4309 &lt;p&gt;Two things made this reasonably easy:&lt;/p&gt;
4310 &lt;ul&gt;
4311 &lt;li&gt;A patch from Stanislav Brabec, from Suse, to &lt;a href="https…
4312 framework to bzip2&lt;/a&gt;&lt;/li&gt;
4313 &lt;li&gt;The existing &lt;a href="https://people.gnome.org/~federico/bl…
4314 &lt;/ul&gt;
4315 &lt;p&gt;I.e. "copy and paste from somewhere that I know works well".
4316 Wonderful!&lt;/p&gt;
4317 &lt;p&gt;This is the &lt;a href="https://gitlab.com/federicomenaquintero…
4318 bzip2&lt;/a&gt;. It does the following:&lt;/p&gt;
4319 &lt;ol&gt;
4320 &lt;li&gt;Create a Cargo workspace (a &lt;code&gt;Cargo.toml&lt;/code&gt…
4321 single member, a &lt;code&gt;bzlib_rust&lt;/code&gt; directory where …
4322 of the code will live.&lt;/li&gt;
4323 &lt;li&gt;Create &lt;code&gt;bzlib_rust/Cargo.toml&lt;/code&gt; and &lt;…
4324 sources. This will generate a &lt;code&gt;staticlib&lt;/code&gt; for…
4325 can be linked into the main &lt;code&gt;libbz2.la&lt;/code&gt;.&lt;/l…
4326 &lt;li&gt;Puts in automake hooks so that &lt;code&gt;make clean&lt;/code…
4327 do what you expect for the Rust part.&lt;/li&gt;
4328 &lt;/ol&gt;
4329 &lt;p&gt;As a side benefit, librsvg's Autotools+Rust infrastructure alre…
4330 handled things like cross-compilation correctly, so I have high hopes
4331 that this will be good enough for bzip2.&lt;/p&gt;
4332 &lt;h2&gt;Can I use a Rust crate for CRC32?&lt;/h2&gt;
4333 &lt;p&gt;There are &lt;a href="https://crates.io/search?q=crc&amp;amp;so…
4334 hoping especially to be able to use &lt;a href="https://github.com/srijs…
4335 SIMD-accelerated.&lt;/p&gt;
4336 &lt;p&gt;I wrote a Rust version of the "CRC me a buffer" test from above…
4337 if crc32fast produced the same values as the C code, and of course it
4338 didn't. Eventually, after &lt;a href="https://mstdn.mx/@federicomena/10…
4339 out&lt;/a&gt; what variant of CRC32 is being used in the original
4340 code.&lt;/p&gt;
4341 &lt;p&gt;It turns out that this is directly doable in Rust with the &lt;…
4342 of the &lt;code&gt;crc&lt;/code&gt; crate&lt;/a&gt;. This crate lets on…
4343 polynomial and the mode of computation; there are &lt;a href="https://gi…
4344 CRC32&lt;/a&gt; and I wasn't fully aware of them.&lt;/p&gt;
4345 &lt;p&gt;The magic incantation is this:&lt;/p&gt;
4346 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
4347 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
4348
4349 &lt;p&gt;With that, &lt;a href="https://gitlab.com/federicomenaquintero/…
4350 test&lt;/a&gt;
4351 produces the same values as the C code. Yay!&lt;/p&gt;
4352 &lt;h2&gt;But it can't be that easy&lt;/h2&gt;
4353 &lt;p&gt;Bzlib stores its internal state in the &lt;a href="https://gitl…
4354 struct&lt;/a&gt;,
4355 defined in
4356 &lt;a href="https://gitlab.com/federicomenaquintero/bzip2/blob/60be65f9/…
4357 &lt;p&gt;That struct stores several running CRC32 computations, and the …
4358 for each one of those is a single &lt;code&gt;UInt32&lt;/code&gt; value.…
4359 just replace those struct fields with something that comes from Rust,
4360 since the C code does not know the size of a &lt;code&gt;crc32::Digest&l…
4361 Rust.&lt;/p&gt;
4362 &lt;p&gt;The normal way to do this (say, like in librsvg) would be to tu…
4363 &lt;code&gt;UInt32 some_crc&lt;/code&gt; into &lt;code&gt;void *some_crc…
4364 Rust side, with whatever size it needs.&lt;/p&gt;
4365 &lt;p&gt;&lt;strong&gt;However!&lt;/strong&gt;&lt;/p&gt;
4366 &lt;p&gt;It turns out that bzlib lets the caller &lt;a href="https://git…
4367 allocator&lt;/a&gt;
4368 so that bzlib doesn't use plain &lt;code&gt;malloc()&lt;/code&gt; by def…
4369 &lt;p&gt;Rust lets one define a &lt;a href="https://doc.rust-lang.org/al…
4370 However, bzlib's concept of a custom allocator includes a bit of
4371 context:&lt;/p&gt;
4372 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
4373 &lt;span class="c1"&gt;// ...&lt;/span&gt;
4374
4375 &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;…
4376 &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="p"&gt;(&lt;…
4377 &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;…
4378 &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="n"&gt;bz_stream&lt;…
4379 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
4380
4381 &lt;p&gt;The caller sets up &lt;code&gt;bzalloc/bzfree&lt;/code&gt; call…
4382 context for the allocator. However, Rust's &lt;code&gt;GlobalAlloc&lt;/…
4383 compilation time, and we can't pass that context in a good,
4384 thread-safe fashion to it.&lt;/p&gt;
4385 &lt;h2&gt;Who uses the bzlib custom allocator, anyway?&lt;/h2&gt;
4386 &lt;p&gt;If one sets &lt;code&gt;bzalloc/bzfree&lt;/code&gt; to &lt;code…
4387 plain &lt;code&gt;malloc()/free()&lt;/code&gt; by default. Most softwar…
4388 &lt;p&gt;I am looking in &lt;a href="https://codesearch.debian.net/searc…
4389 gets set, hoping that I can figure out if that software really needs a
4390 custom allocator, or if they are just dressing up &lt;code&gt;malloc()&l…
4391 logging code or similar (ImageMagick seems to do this; Python seems to
4392 have a genuine concern about the Global Interpreter Lock). Debian's
4393 codesearch is a fantastic tool!&lt;/p&gt;
4394 &lt;h2&gt;The first rustified code&lt;/h2&gt;
4395 &lt;p&gt;I &lt;a href="https://gitlab.com/federicomenaquintero/bzip2/com…
4396 table&lt;/a&gt;
4397 and fixed it up for Rust's syntax, and also ported the CRC32
4398 computation functions. I gave them the same names as the original C
4399 ones, and exported them, e.g.&lt;/p&gt;
4400 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
4401 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x00000000&…
4402 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&…
4403 &lt;span class="p"&gt;};&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
4404
4405 &lt;span class="cp"&gt;#[no_mangle]&lt;/span&gt;&lt;span class="w"&gt;&l…
4406 &lt;span class="k"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&g…
4407 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&…
4408 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
4409 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
4410
4411 &lt;p&gt;This is a straight port of the C code. Rust is very strict abo…
4412 integer sizes, and arrays can only be indexed with a &lt;code&gt;usize&l…
4413 random integer — hence the explicit conversions.&lt;/p&gt;
4414 &lt;p&gt;And with this, &lt;a href="https://gitlab.com/federicomenaquint…
4415 linkage&lt;/a&gt;,
4416 the tests pass!&lt;/p&gt;
4417 &lt;p&gt;First pass at rustifying CRC32: &lt;strong&gt;done&lt;/strong&g…
4418 &lt;h2&gt;But that does one byte at a time&lt;/h2&gt;
4419 &lt;p&gt;Indeed; the original C code to do CRC32 only handled one byte a…
4420 time. If I replace this with a SIMD-enabled Rust crate, it will want
4421 to process whole buffers at once. I hope the code in bzlib can be
4422 refactored to do that. We'll see!&lt;/p&gt;
4423 &lt;h2&gt;How to use an existing Rust crate for this&lt;/h2&gt;
4424 &lt;p&gt;I just found out that one does not in fact need to use a comple…
4425 &lt;code&gt;crc32::Digest&lt;/code&gt; to do equivalent computations; on…
4426 &lt;a href="https://docs.rs/crc/1.8.1/crc/crc32/fn.update.html"&gt;crc32…
4427 by hand and maintain a single &lt;code&gt;u32&lt;/code&gt; state, just l…
4428 &lt;code&gt;UInt32&lt;/code&gt; from the C code.&lt;/p&gt;
4429 &lt;p&gt;So, I may not need to mess around with a custom allocator just …
4430 Stay tuned.&lt;/p&gt;
4431 &lt;p&gt;In the meantime, I've &lt;a href="https://github.com/srijs/rust…
4432 crc32fast&lt;/a&gt; to make
4433 it possible to use a custom polynomial and order and still get the
4434 benefits of SIMD.&lt;/p&gt;</content><category term="misc"></category><c…
4435 instantiate a GObject and then change its state via method calls.
4436 Sometimes this is expected and desired; a &lt;code&gt;GtkCheckButton&lt;…
4437 certainly can change its internal state from pressed to not pressed,
4438 for example.&lt;/p&gt;
4439 &lt;p&gt;Other times, objects are mutable while they are being …&lt;/p…
4440 instantiate a GObject and then change its state via method calls.
4441 Sometimes this is expected and desired; a &lt;code&gt;GtkCheckButton&lt;…
4442 certainly can change its internal state from pressed to not pressed,
4443 for example.&lt;/p&gt;
4444 &lt;p&gt;Other times, objects are mutable while they are being "assemble…
4445 "configured", and only yield a final immutable result until later.
4446 This is the case for &lt;code&gt;RsvgHandle&lt;/code&gt; from librsvg.&l…
4447 &lt;p&gt;Please bear with me while I write about the history of the
4448 &lt;code&gt;RsvgHandle&lt;/code&gt; API and why it ended up with differe…
4449 same thing.&lt;/p&gt;
4450 &lt;h2&gt;The traditional RsvgHandle API&lt;/h2&gt;
4451 &lt;p&gt;The final purpose of an &lt;code&gt;RsvgHandle&lt;/code&gt; is …
4452 loaded in memory. Once it is loaded, the SVG document does not
4453 change, as librsvg does not support animation or creating/removing SVG
4454 elements; it is a static renderer.&lt;/p&gt;
4455 &lt;p&gt;However, before an &lt;code&gt;RsvgHandle&lt;/code&gt; achieves…
4456 to be loaded first. Loading can be done in two ways:&lt;/p&gt;
4457 &lt;ul&gt;
4458 &lt;li&gt;The historical/deprecated way, using the &lt;a href="https://d…
4459 &lt;code&gt;rsvg_handle_close()&lt;/code&gt; APIs. Plenty of code in …
4460 &lt;code&gt;write/close&lt;/code&gt; idiom before GLib got a good abst…
4461 streams; you can see another example in &lt;a href="https://developer.…
4462 The idea is that applications do this:&lt;/li&gt;
4463 &lt;/ul&gt;
4464 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
4465 &lt;span class="n"&gt;handle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/sp…
4466
4467 &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/spa…
4468 &lt;span class="n"&gt;rsvg_handle_write&lt;/span&gt;&lt;span class="p…
4469 &lt;span class="p"&gt;}&lt;/span&gt;
4470
4471 &lt;span class="n"&gt;rsvg_handle_close&lt;/span&gt; &lt;span class="p"&…
4472
4473 &lt;span class="o"&gt;//&lt;/span&gt; &lt;span class="n"&gt;now&lt;/span…
4474
4475 &lt;span class="n"&gt;rsvg_handle_render&lt;/span&gt; &lt;span class="p"…
4476 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
4477
4478 &lt;ul&gt;
4479 &lt;li&gt;The streaming way, with &lt;a href="https://developer.gnome.or…
4480 which takes a &lt;a href="https://developer.gnome.org/gio/unstable/GIn…
4481 which take a &lt;a href="https://developer.gnome.org/gio/unstable/GFil…
4482 &lt;/ul&gt;
4483 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
4484 &lt;span class="n"&gt;stream&lt;/span&gt; &lt;span class="o"&gt;=&lt;/sp…
4485 &lt;span class="n"&gt;handle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/sp…
4486
4487 &lt;span class="n"&gt;rsvg_handle_read_stream_sync&lt;/span&gt; &lt;span…
4488
4489 &lt;span class="o"&gt;//&lt;/span&gt; &lt;span class="n"&gt;now&lt;/span…
4490
4491 &lt;span class="n"&gt;rsvg_handle_render&lt;/span&gt; &lt;span class="p"…
4492 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
4493
4494 &lt;h2&gt;A bit of history&lt;/h2&gt;
4495 &lt;p&gt;Let's consider a few of &lt;code&gt;RsvgHandle&lt;/code&gt;'s f…
4496 &lt;p&gt;&lt;strong&gt;Constructors:&lt;/strong&gt;&lt;/p&gt;
4497 &lt;ul&gt;
4498 &lt;li&gt;&lt;code&gt;rsvg_handle_new()&lt;/code&gt;&lt;/li&gt;
4499 &lt;li&gt;&lt;code&gt;rsvg_handle_new_with_flags()&lt;/code&gt;&lt;/li&g…
4500 &lt;/ul&gt;
4501 &lt;p&gt;&lt;strong&gt;Configure the handle for loading:&lt;/strong&gt;&…
4502 &lt;ul&gt;
4503 &lt;li&gt;&lt;code&gt;rsvg_handle_set_base_uri()&lt;/code&gt;&lt;/li&gt;
4504 &lt;li&gt;&lt;code&gt;rsvg_handle_set_base_gfile()&lt;/code&gt;&lt;/li&g…
4505 &lt;/ul&gt;
4506 &lt;p&gt;&lt;strong&gt;Deprecated loading API:&lt;/strong&gt;&lt;/p&gt;
4507 &lt;ul&gt;
4508 &lt;li&gt;&lt;code&gt;rsvg_handle_write()&lt;/code&gt;&lt;/li&gt;
4509 &lt;li&gt;&lt;code&gt;rsvg_handle_close()&lt;/code&gt;&lt;/li&gt;
4510 &lt;/ul&gt;
4511 &lt;p&gt;&lt;strong&gt;Streaming API:&lt;/strong&gt;&lt;/p&gt;
4512 &lt;ul&gt;
4513 &lt;li&gt;&lt;code&gt;rsvg_handle_read_stream_sync()&lt;/code&gt;&lt;/li…
4514 &lt;/ul&gt;
4515 &lt;p&gt;When librsvg first acquired the concept of an &lt;code&gt;RsvgH…
4516 had &lt;code&gt;rsvg_handle_new()&lt;/code&gt; with no arguments. About…
4517 got &lt;code&gt;rsvg_handle_new_with_flags()&lt;/code&gt; to allow more …
4518 another 2 years to actually add some usable flags — the first one was
4519 to configure the parsing limits in the underlying calls to libxml2.&lt;/…
4520 &lt;p&gt;About 3 years after &lt;code&gt;RsvgHandle&lt;/code&gt; appear…
4521 &lt;code&gt;rsvg_handle_set_base_uri()&lt;/code&gt; to configure the "ba…
4522 relative references in the SVG document get resolved. For example, if
4523 you are reading &lt;code&gt;/foo/bar.svg&lt;/code&gt; and it contains an…
4524 xlink:ref="smiley.png"/&amp;gt;&lt;/code&gt;, then librsvg needs to be a…
4525 the path &lt;code&gt;/foo/smiley.png&lt;/code&gt; and that is done relat…
4526 (The base URI is implicit when reading from a specific SVG file, but
4527 it needs to be provided when reading from an arbitrary stream that may
4528 not even come from a file.)&lt;/p&gt;
4529 &lt;p&gt;Initially &lt;code&gt;RsvgHandle&lt;/code&gt; had the &lt;code&…
4530 it got the streaming functions once GIO appeared. Eventually the
4531 streaming API would be the preferred one, instead of just being a
4532 convenience for those brave new apps that started using GIO.&lt;/p&gt;
4533 &lt;p&gt;A summary of librsvg's API may be something like:&lt;/p&gt;
4534 &lt;ul&gt;
4535 &lt;li&gt;
4536 &lt;p&gt;librsvg gets written initially; it doesn't even have an
4537 &lt;code&gt;RsvgHandle&lt;/code&gt;, and just provides a single functi…
4538 &lt;code&gt;FILE *&lt;/code&gt; and renders it to a &lt;code&gt;GdkPix…
4539 &lt;/li&gt;
4540 &lt;li&gt;
4541 &lt;p&gt;That gets replaced with &lt;code&gt;RsvgHandle&lt;/code&gt;, it…
4542 constructor, and the &lt;code&gt;write/close&lt;/code&gt; API to feed …
4543 progressively.&lt;/p&gt;
4544 &lt;/li&gt;
4545 &lt;li&gt;
4546 &lt;p&gt;GIO appears, we get the first widespread streaming APIs in GNOM…
4547 and &lt;code&gt;RsvgHandle&lt;/code&gt; gets the ability to read from …
4548 &lt;/li&gt;
4549 &lt;li&gt;
4550 &lt;p&gt;&lt;code&gt;RsvgHandle&lt;/code&gt; gets &lt;code&gt;rsvg_handl…
4551 may want to configure extra stuff for libxml2.&lt;/p&gt;
4552 &lt;/li&gt;
4553 &lt;li&gt;
4554 &lt;p&gt;When Cairo appears and librsvg is ported to it, &lt;code&gt;Rsv…
4555 extra flag so that SVGs rendered to PDF can embed image data
4556 efficiently.&lt;/p&gt;
4557 &lt;/li&gt;
4558 &lt;/ul&gt;
4559 &lt;p&gt;It's a convoluted history, but &lt;code&gt;git log -- rsvg.h&lt…
4560 &lt;h2&gt;Where is the mutability?&lt;/h2&gt;
4561 &lt;p&gt;An &lt;code&gt;RsvgHandle&lt;/code&gt; gets created, with flags…
4562 doesn't know if it will be given data with the &lt;code&gt;write/close&l…
4563 with the streaming API. Also, someone may call &lt;code&gt;set_base_uri…
4564 it. So, the handle must remain mutable while it is being populated
4565 with data. After that, it can say, "no more changes, I'm done".&lt;/p&g…
4566 &lt;p&gt;In C, this doesn't even have a name. Everything is mutable by …
4567 all the time. This monster was the private data of &lt;code&gt;RsvgHand…
4568 before it got ported to Rust:&lt;/p&gt;
4569 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
4570 &lt;span class="c1"&gt;// set during construction&lt;/span&gt;
4571 &lt;span class="n"&gt;RsvgHandleFlags&lt;/span&gt; &lt;span class="n…
4572
4573 &lt;span class="c1"&gt;// GObject-ism&lt;/span&gt;
4574 &lt;span class="n"&gt;gboolean&lt;/span&gt; &lt;span class="n"&gt;is…
4575
4576 &lt;span class="c1"&gt;// Extra crap for a deprecated API&lt;/span&g…
4577 &lt;span class="n"&gt;RsvgSizeFunc&lt;/span&gt; &lt;span class="n"&g…
4578 &lt;span class="n"&gt;gpointer&lt;/span&gt; &lt;span class="n"&gt;us…
4579 &lt;span class="n"&gt;GDestroyNotify&lt;/span&gt; &lt;span class="n"…
4580
4581 &lt;span class="c1"&gt;// Data only used while parsing an SVG&lt;/sp…
4582 &lt;span class="n"&gt;RsvgHandleState&lt;/span&gt; &lt;span class="n…
4583 &lt;span class="n"&gt;RsvgDefs&lt;/span&gt; &lt;span class="o"&gt;*&…
4584 &lt;span class="n"&gt;guint&lt;/span&gt; &lt;span class="n"&gt;nest_…
4585 &lt;span class="n"&gt;RsvgNode&lt;/span&gt; &lt;span class="o"&gt;*&…
4586 &lt;span class="n"&gt;RsvgNode&lt;/span&gt; &lt;span class="o"&gt;*&…
4587 &lt;span class="n"&gt;GHashTable&lt;/span&gt; &lt;span class="o"&gt;…
4588 &lt;span class="n"&gt;RsvgSaxHandler&lt;/span&gt; &lt;span class="o"…
4589 &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;handle…
4590 &lt;span class="n"&gt;GHashTable&lt;/span&gt; &lt;span class="o"&gt;…
4591 &lt;span class="n"&gt;xmlParserCtxtPtr&lt;/span&gt; &lt;span class="…
4592 &lt;span class="n"&gt;GError&lt;/span&gt; &lt;span class="o"&gt;**&l…
4593 &lt;span class="n"&gt;GCancellable&lt;/span&gt; &lt;span class="o"&g…
4594 &lt;span class="n"&gt;GInputStream&lt;/span&gt; &lt;span class="o"&g…
4595
4596 &lt;span class="c1"&gt;// Data only used while rendering&lt;/span&gt;
4597 &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;dpi…
4598 &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;dpi…
4599
4600 &lt;span class="c1"&gt;// The famous base URI, set before loading&lt…
4601 &lt;span class="n"&gt;gchar&lt;/span&gt; &lt;span class="o"&gt;*&lt;…
4602 &lt;span class="n"&gt;GFile&lt;/span&gt; &lt;span class="o"&gt;*&lt;…
4603
4604 &lt;span class="c1"&gt;// Some internal stuff&lt;/span&gt;
4605 &lt;span class="n"&gt;gboolean&lt;/span&gt; &lt;span class="n"&gt;in…
4606 &lt;span class="n"&gt;gboolean&lt;/span&gt; &lt;span class="n"&gt;is…
4607 &lt;span class="p"&gt;};&lt;/span&gt;
4608 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
4609
4610 &lt;p&gt;"Single responsibility principle"? This is a horror show. That
4611 &lt;code&gt;RsvgHandlePrivate&lt;/code&gt; struct has all of these:&lt;/…
4612 &lt;ul&gt;
4613 &lt;li&gt;Data only settable during construction (flags)&lt;/li&gt;
4614 &lt;li&gt;Data set after construction, but which may only be set before
4615 loading (base URI)&lt;/li&gt;
4616 &lt;li&gt;Highly mutable data used only during the loading stage: state
4617 machines, XML parsers, a stack of XML elements, CSS properties...&lt;/…
4618 &lt;li&gt;The DPI (dots per inch) values only used during rendering.&lt;…
4619 &lt;li&gt;Assorted fields used at various stages of the handle's life.&l…
4620 &lt;/ul&gt;
4621 &lt;p&gt;It took a lot of refactoring to get the code to a point where i…
4622 clear that an &lt;code&gt;RsvgHandle&lt;/code&gt; in fact has distinct s…
4623 lifetime, and that some of that data should only live during a
4624 particular stage. Before, everything seemed a jumble of fields, used
4625 at various unclear points in the code (for the struct listing above,
4626 I've grouped related fields together — they were somewhat shuffled in
4627 the original code!).&lt;/p&gt;
4628 &lt;h2&gt;What would a better separation look like?&lt;/h2&gt;
4629 &lt;p&gt;In the &lt;a href="https://gitlab.gnome.org/GNOME/librsvg/"&gt;…
4630 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
4631 &lt;span class="sd"&gt;/// from the C API.&lt;/span&gt;
4632 &lt;span class="k"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&g…
4633 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dpi&lt;/spa…
4634 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;load_flags&…
4635
4636 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;base_url&lt…
4637 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// needed …
4638 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;base_url_cs…
4639
4640 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;size_callba…
4641 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;is_testing&…
4642 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;load_state&…
4643 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
4644 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
4645
4646 &lt;p&gt;Internally, that &lt;code&gt;CHandle&lt;/code&gt; struct is now…
4647 public &lt;code&gt;RsvgHandle&lt;/code&gt; object. Note that all of &lt…
4648 &lt;code&gt;Cell&amp;lt;&amp;gt;&lt;/code&gt; or &lt;code&gt;RefCell&amp…
4649 allow for "interior mutability" in the &lt;code&gt;CHandle&lt;/code&gt; …
4650 modified after intialization.&lt;/p&gt;
4651 &lt;p&gt;The last field's cell, &lt;code&gt;load_state&lt;/code&gt;, con…
4652 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
4653 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Start&lt;/s…
4654
4655 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// Being l…
4656 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Loading&lt;…
4657
4658 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// Fully l…
4659 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ClosedOk&lt…
4660
4661 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ClosedError…
4662 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
4663 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
4664
4665 &lt;p&gt;A &lt;code&gt;CHandle&lt;/code&gt; starts in the &lt;code&gt;St…
4666 will be loaded with a stream, or with the legacy write/close API.&lt;/p&…
4667 &lt;p&gt;If the caller uses the write/close API, the handle moves to the
4668 &lt;code&gt;Loading&lt;/code&gt; state, which has a &lt;code&gt;buffer&l…
4669 being fed to it.&lt;/p&gt;
4670 &lt;p&gt;But if the caller uses the stream API, the handle tries to pars…
4671 SVG document from the stream, and it moves either to the &lt;code&gt;Clo…
4672 state, or to the &lt;code&gt;ClosedError&lt;/code&gt; state if there is …
4673 &lt;p&gt;Correspondingly, when using the write/close API, when the caller
4674 finally calls &lt;code&gt;rsvg_handle_close()&lt;/code&gt;, the handle c…
4675 the &lt;code&gt;buffer&lt;/code&gt;, parses it, and also gets either int…
4676 &lt;code&gt;ClosedError&lt;/code&gt; state.&lt;/p&gt;
4677 &lt;p&gt;If you look at the variant &lt;code&gt;ClosedOk { handle: Handl…
4678 a fully loaded &lt;code&gt;Handle&lt;/code&gt; inside, which right now i…
4679 around a reference-counted &lt;code&gt;Svg&lt;/code&gt; object:&lt;/p&gt;
4680 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
4681 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;svg&lt;/spa…
4682 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
4683 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
4684
4685 &lt;p&gt;The reason why &lt;code&gt;LoadState::ClosedOk&lt;/code&gt; doe…
4686 directly, and instead wraps it with a &lt;code&gt;Handle&lt;/code&gt;, i…
4687 the first pass at refactoring. Also, &lt;code&gt;Handle&lt;/code&gt; co…
4688 API-level logic which I'm not completely sure makes sense as a
4689 lower-level &lt;code&gt;Svg&lt;/code&gt; object. We'll see.&lt;/p&gt;
4690 &lt;h2&gt;Couldn't you move more of &lt;code&gt;CHandle&lt;/code&gt;'s f…
4691 &lt;p&gt;Sort of, kind of, but the public API still lets one do things l…
4692 call &lt;code&gt;rsvg_handle_get_base_uri()&lt;/code&gt; after the handl…
4693 even though its result will be of little value. So, the fields that
4694 hold the &lt;code&gt;base_uri&lt;/code&gt; information are kept in the l…
4695 &lt;code&gt;CHandle&lt;/code&gt;, not in the individual variants of &lt;…
4696 &lt;h2&gt;How does this look from the Rust API?&lt;/h2&gt;
4697 &lt;p&gt;&lt;code&gt;CHandle&lt;/code&gt; implements the public C API of…
4698 &lt;code&gt;Handle&lt;/code&gt; implements the basic "load from stream",…
4699 an SVG element", and "render to a Cairo context" functionality.&lt;/p&gt;
4700 &lt;p&gt;This basic functionality gets exported in a cleaner way through…
4701 &lt;a href="https://gitlab.gnome.org/GNOME/librsvg/blob/master/librsvg_c…
4702 interior mutability in there at all; that API uses a builder pattern
4703 to gradually configure an SVG loader, which returns a fully loaded
4704 &lt;code&gt;SvgHandle&lt;/code&gt;, out of which you can create a &lt;co…
4705 &lt;p&gt;In fact, it may be possible to refactor all of this a bit and
4706 implement &lt;code&gt;CHandle&lt;/code&gt; directly in terms of the new …
4707 use &lt;code&gt;CHandle&lt;/code&gt; as the "holding space" while the SV…
4708 configured, and later turned into a fully loaded &lt;code&gt;SvgHandle&l…
4709 internally.&lt;/p&gt;
4710 &lt;h2&gt;Conclusion&lt;/h2&gt;
4711 &lt;p&gt;The C version of &lt;code&gt;RsvgHandle&lt;/code&gt;'s private …
4712 of fields. Without knowing the code, it was hard to know that they
4713 belonged in groups, and each group corresponded roughtly to a stage in
4714 the handle's lifetime.&lt;/p&gt;
4715 &lt;p&gt;It took plenty of refactoring to get the fields split up cleanl…
4716 librsvg's internals. The process of refactoring &lt;code&gt;RsvgHandle&…
4717 and ensuring that the various states of a handle are consistent, in
4718 fact exposed a few bugs where the state was not being checked
4719 appropriately. The public C API remains the same as always, but has
4720 better internal checks now.&lt;/p&gt;
4721 &lt;p&gt;GObject APIs tend to allow for a lot of mutability via methods …
4722 change the internal state of objects. For &lt;code&gt;RsvgHandle&lt;/co…
4723 to change this into a single &lt;code&gt;CHandle&lt;/code&gt; that maint…
4724 in a contained fashion, and later translates it internally into an
4725 immutable &lt;code&gt;Handle&lt;/code&gt; that represents a fully-loaded…
4726 scheme ties in well with the new Rust API for librsvg, which keeps
4727 everything immutable after creation.&lt;/p&gt;</content><category term="…
4728 librsvg's main library, I wanted to start porting the high-level test
4729 suite to Rust. This is mainly to be able to run tests in parallel,
4730 which &lt;code&gt;cargo test&lt;/code&gt; does automatically in order to…
4731 However, this meant that librsvg needed …&lt;/p&gt;</summary><content …
4732 librsvg's main library, I wanted to start porting the high-level test
4733 suite to Rust. This is mainly to be able to run tests in parallel,
4734 which &lt;code&gt;cargo test&lt;/code&gt; does automatically in order to…
4735 However, this meant that librsvg needed a Rust API that would exercise
4736 the same code paths as the C entry points.&lt;/p&gt;
4737 &lt;p&gt;At the same time, I wanted the Rust API to make it impossible to
4738 misuse the library. From the viewpoint of the C API, an &lt;code&gt;Rsv…
4739 has different stages:&lt;/p&gt;
4740 &lt;ul&gt;
4741 &lt;li&gt;Just initialized&lt;/li&gt;
4742 &lt;li&gt;Loading&lt;/li&gt;
4743 &lt;li&gt;Loaded, or in an error state after a failed load&lt;/li&gt;
4744 &lt;li&gt;Ready to render&lt;/li&gt;
4745 &lt;/ul&gt;
4746 &lt;p&gt;To ensure consistency, the public API checks that you cannot re…
4747 &lt;code&gt;RsvgHandle&lt;/code&gt; that is not completely loaded yet, o…
4748 in a loading error. But wouldn't it be nice if it were impossible to
4749 call the API functions in the wrong order?&lt;/p&gt;
4750 &lt;p&gt;This is exactly what &lt;a href="https://gitlab.gnome.org/GNOME…
4751 to which you give a filename or a stream, and it will return a
4752 fully-loaded &lt;code&gt;SvgHandle&lt;/code&gt; or an error. Then, you …
4753 &lt;code&gt;CairoRenderer&lt;/code&gt; if you have an &lt;code&gt;SvgHan…
4754 &lt;p&gt;For historical reasons, the C API in librsvg is not perfectly
4755 consistent. For example, some functions which return an error will
4756 actually return a proper &lt;a href="https://developer.gnome.org/glib/st…
4757 return a &lt;code&gt;gboolean&lt;/code&gt; with no further explanation o…
4758 In contrast, all the Rust API functions that can fail will actually
4759 return a &lt;a href="https://doc.rust-lang.org/std/result/index.html"&gt…
4760 error value. In the Rust API, there is no "wrong order" in which the
4761 various API functions and methods can be called; it tries to do the
4762 whole "make invalid states unrepresentable".&lt;/p&gt;
4763 &lt;p&gt;To implement &lt;a href="https://gitlab.gnome.org/GNOME/librsvg…
4764 &lt;a href="https://gitlab.gnome.org/GNOME/librsvg/blob/master/rsvg_inte…
4765 realize that librsvg could be a lot easier to use. The C API has
4766 always forced you to call it in this fashion:&lt;/p&gt;
4767 &lt;ol&gt;
4768 &lt;li&gt;Ask the SVG for its dimensions, or how big it is.&lt;/li&gt;
4769 &lt;li&gt;Based on that, scale your Cairo context to the size you actual…
4770 want.&lt;/li&gt;
4771 &lt;li&gt;Render the SVG to that context's current transformation matrix…
4772 &lt;/ol&gt;
4773 &lt;p&gt;But first, (1) gives you inadequate information because
4774 &lt;code&gt;rsvg_handle_get_dimensions()&lt;/code&gt; returns &lt;a href…
4775 structure&lt;/a&gt; with &lt;code&gt;int&lt;/code&gt; fields for the wid…
4776 height. The API is similar to gdk-pixbuf's in that it always wants to
4777 think in whole pixels. However, an SVG is not necessarily
4778 integer-sized.&lt;/p&gt;
4779 &lt;p&gt;Then, (2) forces you to calculate some geometry in almost all c…
4780 as most apps want to render SVG content scaled proportionally to a
4781 certain size. This is not hard to do, but it's an inconvenience.&lt;/p&…
4782 &lt;h2&gt;SVG dimensions&lt;/h2&gt;
4783 &lt;p&gt;Let's look at (1) again. The question, "how big is the SVG" is…
4784 meaningless when we consider that SVGs &lt;strong&gt;can be scaled to an…
4785 that's the whole point of them!&lt;/p&gt;
4786 &lt;p&gt;When you ask &lt;code&gt;RsvgHandle&lt;/code&gt; how big it is,…
4787 you and whisper in your ear, "how big do you want it to be?".&lt;/p&gt;
4788 &lt;p&gt;And that's the thing. The HTML/CSS/SVG model is that one embeds
4789 content into &lt;strong&gt;viewports&lt;/strong&gt; of a given size. Th…
4790 responsible for scaling the content to fit into that viewport.&lt;/p&gt;
4791 &lt;p&gt;In the end, what we want is a rendering function that takes a C…
4792 context and a Rectangle for a viewport, and that's it. The function
4793 should take care of fitting the SVG's contents within that viewport.&lt;…
4794 &lt;p&gt;There is now &lt;a href="https://gitlab.gnome.org/GNOME/librsvg…
4795 the end, programs should just have to load their SVG handle, and
4796 directly ask it to render at whatever size they need, instead of doing
4797 the size computations by hand.&lt;/p&gt;
4798 &lt;h2&gt;When will this be available?&lt;/h2&gt;
4799 &lt;p&gt;I'm in the middle of a &lt;a href="https://gitlab.gnome.org/fed…
4800 to make this &lt;em&gt;viewport&lt;/em&gt; concept really work. So far …
4801 &lt;ul&gt;
4802 &lt;li&gt;
4803 &lt;p&gt;Defining APIs that take a viewport.&lt;/p&gt;
4804 &lt;/li&gt;
4805 &lt;li&gt;
4806 &lt;p&gt;Refactoring all the geometry computation to support the semanti…
4807 C API, plus the new &lt;code&gt;with_viewport&lt;/code&gt; semantics.&…
4808 &lt;/li&gt;
4809 &lt;li&gt;
4810 &lt;p&gt;Fixing the code that kept track of an internal offset for all
4811 temporary images.&lt;/p&gt;
4812 &lt;/li&gt;
4813 &lt;li&gt;
4814 &lt;p&gt;Refactoring all the code that mucks around with the Cairo conte…
4815 affine transformation matrix, which is a big mutable mess.&lt;/p&gt;
4816 &lt;/li&gt;
4817 &lt;li&gt;
4818 &lt;p&gt;Tests, examples, documentation.&lt;/p&gt;
4819 &lt;/li&gt;
4820 &lt;/ul&gt;
4821 &lt;p&gt;I want to make the Rust API available for the 2.46 release, whi…
4822 hopefully not too far off. It should be ready for the next GNOME
4823 release. In the meantime, you can check out the open bugs for the
4824 &lt;a href="https://gitlab.gnome.org/GNOME/librsvg/milestones/20"&gt;2.4…
4825 for the first 3.33 tarballs is approximately one month from now!&lt;/str…
4826 with Rust and Cargo is Cargo's use of build scripts, i.e. the
4827 &lt;code&gt;build.rs&lt;/code&gt; that many Rust programs use for doing …
4828 main build. This post is about my exploration of what &lt;code&gt;build…
4829 with Rust and Cargo is Cargo's use of build scripts, i.e. the
4830 &lt;code&gt;build.rs&lt;/code&gt; that many Rust programs use for doing …
4831 main build. This post is about my exploration of what &lt;code&gt;build…
4832 does.&lt;/p&gt;
4833 &lt;p&gt;Thanks to &lt;a href="https://nirbheek.in/"&gt;Nirbheek Chauhan…
4834 and additions to a draft of this article!&lt;/p&gt;
4835 &lt;p&gt;TL;DR: &lt;code&gt;build.rs&lt;/code&gt; is pretty ad-hoc and s…
4836 compared to Meson's very nice, high-level patterns for build-time
4837 things.&lt;/p&gt;
4838 &lt;p&gt;I have the intuition that giving names to the things that are
4839 usually done in &lt;code&gt;build.rs&lt;/code&gt; scripts, and creating …
4840 them, can make it easier later to implement those abstractions in
4841 terms of Meson. Maybe we can eliminate &lt;code&gt;build.rs&lt;/code&gt…
4842 Maybe Cargo can acquire higher-level concepts that plug well to Meson?&l…
4843 &lt;p&gt;(That is... I think we can refactor our way out of this mess.)&…
4844 &lt;h2&gt;What does &lt;code&gt;build.rs&lt;/code&gt; do?&lt;/h2&gt;
4845 &lt;p&gt;The first paragraph in the &lt;a href="https://doc.rust-lang.or…
4846 scripts&lt;/a&gt; tells us this:&lt;/p&gt;
4847 &lt;blockquote&gt;
4848 &lt;p&gt;Some packages need to compile third-party non-Rust code, for ex…
4849 C libraries. Other packages need to link to C libraries which can
4850 either be located on the system or possibly need to be built from
4851 source. Others still need facilities for functionality such as code
4852 generation before building (think parser generators).&lt;/p&gt;
4853 &lt;/blockquote&gt;
4854 &lt;p&gt;That is,&lt;/p&gt;
4855 &lt;ul&gt;
4856 &lt;li&gt;
4857 &lt;p&gt;Compiling third-party non-Rust code. For example, maybe there …
4858 C sub-library that the Rust crate needs.&lt;/p&gt;
4859 &lt;/li&gt;
4860 &lt;li&gt;
4861 &lt;p&gt;Link to C libraries... located on the system... or built from
4862 source. For example, in &lt;a href="https://gtk-rs.org"&gt;gtk-rs&lt;…
4863 &lt;code&gt;libgtk-3.so&lt;/code&gt;, &lt;code&gt;libcairo.so&lt;/code…
4864 those libraries with &lt;code&gt;pkg-config&lt;/code&gt;.&lt;/p&gt;
4865 &lt;/li&gt;
4866 &lt;li&gt;
4867 &lt;p&gt;Code generation. In the C world this could be generating a par…
4868 with &lt;code&gt;yacc&lt;/code&gt;; in the Rust world there are many u…
4869 code that is later used in your actual program.&lt;/p&gt;
4870 &lt;/li&gt;
4871 &lt;/ul&gt;
4872 &lt;p&gt;In the next sections I'll look briefly at each of these cases, …
4873 a different order.&lt;/p&gt;
4874 &lt;h2&gt;Code generation&lt;/h2&gt;
4875 &lt;p&gt;Here is an example, in &lt;a href="https://gitlab.gnome.org/GNO…
4876 for a couple of things that get autogenerated before compiling the
4877 main library:&lt;/p&gt;
4878 &lt;ul&gt;
4879 &lt;li&gt;A perfect hash function (PHF) of attributes and CSS property n…
4880 &lt;li&gt;A pair of lookup tables for SRGB linearization and un-lineariz…
4881 &lt;/ul&gt;
4882 &lt;p&gt;For example, this is &lt;code&gt;main()&lt;/code&gt; in &lt;cod…
4883 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
4884 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;generate_ph…
4885 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;generate_sr…
4886 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
4887 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
4888
4889 &lt;p&gt;And this is the first few lines of of the first function:&lt;/p…
4890 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
4891 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/sp…
4892 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/sp…
4893
4894 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="fm"&gt;writeln!&l…
4895
4896 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// ... etc…
4897 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
4898 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
4899
4900 &lt;p&gt;Generate a path like &lt;code&gt;$OUT_DIR/attributes-codegen.rs…
4901 with that name, a &lt;code&gt;BufWriter&lt;/code&gt; for the file, and s…
4902 to it.&lt;/p&gt;
4903 &lt;p&gt;Similarly, the second function:&lt;/p&gt;
4904 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
4905 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/sp…
4906 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/sp…
4907
4908 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/sp…
4909 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/sp…
4910
4911 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// ...&lt;…
4912
4913 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;print_table…
4914 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;print_table…
4915 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
4916 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
4917
4918 &lt;p&gt;Compute two lookup tables, create a file named
4919 &lt;code&gt;$OUT_DIR/srgb-codegen.rs&lt;/code&gt;, and write the lookup …
4920 &lt;p&gt;Later in the actual librsvg code, the generated files get inclu…
4921 into the source code using the &lt;code&gt;include!&lt;/code&gt; macro. …
4922 where &lt;a href="https://gitlab.gnome.org/GNOME/librsvg/blob/a5c8a9ca/r…
4923 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
4924
4925 &lt;span class="k"&gt;extern&lt;/span&gt;&lt;span class="w"&gt; &lt;/spa…
4926
4927 &lt;span class="c1"&gt;// the generated file has the declaration for enu…
4928 &lt;span class="fm"&gt;include!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/…
4929 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
4930
4931 &lt;p&gt;One thing to note here is that the generated source files
4932 (&lt;code&gt;attributes-codegen.rs&lt;/code&gt;, &lt;code&gt;srgb-codege…
4933 directory that Cargo creates for the compilation artifacts. The files &…
4934 not&lt;/strong&gt; get put into the original source directories with the…
4935 the library's code; the idea is to keep the source directories
4936 pristine.&lt;/p&gt;
4937 &lt;p&gt;At least in those terms, Meson and Cargo agree that source dire…
4938 should be kept clean of autogenerated files.&lt;/p&gt;
4939 &lt;p&gt;The &lt;a href="https://doc.rust-lang.org/cargo/reference/build…
4940 &lt;blockquote&gt;
4941 &lt;p&gt;In general, build scripts should not modify any files outside of
4942 OUT_DIR. It may seem fine on the first blush, but it does cause
4943 problems when you use such crate as a dependency, because there's an
4944 implicit invariant that sources in .cargo/registry should be
4945 immutable. cargo won't allow such scripts when packaging.&lt;/p&gt;
4946 &lt;/blockquote&gt;
4947 &lt;p&gt;Now, some things to note here:&lt;/p&gt;
4948 &lt;ul&gt;
4949 &lt;li&gt;
4950 &lt;p&gt;Both the &lt;code&gt;build.rs&lt;/code&gt; program and the actu…
4951 the &lt;code&gt;$OUT_DIR&lt;/code&gt; environment variable for the loc…
4952 generated sources.&lt;/p&gt;
4953 &lt;/li&gt;
4954 &lt;li&gt;
4955 &lt;p&gt;The Cargo docs say that if the code generator needs input files…
4956 can look for them based on its current directory, which will be the
4957 toplevel of your source package (i.e. your toplevel &lt;code&gt;Cargo.…
4958 &lt;/li&gt;
4959 &lt;/ul&gt;
4960 &lt;p&gt;&lt;strong&gt;Meson hates this scheme of things&lt;/strong&gt;.…
4961 systematic about where it finds input files and sources, and where
4962 things like code generators are allowed to place their output.&lt;/p&gt;
4963 &lt;p&gt;The way Meson communicates these paths to code generators is via
4964 command-line arguments to &lt;a href="https://mesonbuild.com/Reference-m…
4965 &lt;a href="https://github.com/mesonbuild/meson/blob/master/test%20cases…
4966 documentation:&lt;/p&gt;
4967 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
4968
4969 &lt;span class="n"&gt;outputs&lt;/span&gt;&lt;span class="w"&gt; &lt;/sp…
4970 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;output&lt;/sp…
4971 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;command&lt;/s…
4972 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&…
4973 &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
4974 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
4975
4976 &lt;p&gt;This defines a target named &lt;code&gt;'generated'&lt;/code&gt…
4977 &lt;code&gt;generator.py&lt;/code&gt; program to output two files, &lt;c…
4978 Python program will get called with &lt;code&gt;@OUTDIR@&lt;/code&gt; as…
4979 argument; in effect, meson will call
4980 &lt;code&gt;/full/path/to/generator.py @OUTDIR@&lt;/code&gt; explicitly…
4981 passed through environment variables.&lt;/p&gt;
4982 &lt;p&gt;If this looks similar to what Cargo does above with &lt;code&gt…
4983 because it &lt;strong&gt;is&lt;/strong&gt; similar. It's just that &lt;…
4984 the concept of generating code at build time (Meson's name for this is
4985 a &lt;strong&gt;custom target&lt;/strong&gt;), and provides a mechanism …
4986 the generator, which files it is expected to generate, and how to call
4987 the program with appropriate arguments to put files in the right
4988 place.&lt;/p&gt;
4989 &lt;p&gt;In contrast, Cargo assumes that all of that information can be
4990 inferred from an environment variable.&lt;/p&gt;
4991 &lt;p&gt;In addition, if the custom target takes other files as input (s…
4992 it can call &lt;code&gt;yacc my-grammar.y&lt;/code&gt;), the &lt;code&gt…
4993 take an &lt;code&gt;input:&lt;/code&gt; argument. This way, Meson can a…
4994 those input files, so that the appropriate things will be rebuilt if
4995 the input files change.&lt;/p&gt;
4996 &lt;p&gt;Now, Cargo could very well provide a small utility crate that b…
4997 scripts could use to figure out all that information. Meson would
4998 tell Cargo to use its scheme of things, and pass it down to build
4999 scripts via that utility crate. I.e. to have&lt;/p&gt;
5000 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
5001
5002 &lt;span class="k"&gt;extern&lt;/span&gt;&lt;span class="w"&gt; &lt;/spa…
5003
5004 &lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&…
5005 &lt;span class="c1"&gt;// ^^^^^^^^^^^^^^^^^^^^^^^^^^…
5006
5007 &lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&…
5008
5009 &lt;span class="c1"&gt;// let the build system know about generated depe…
5010 &lt;span class="n"&gt;cargo_high_level&lt;/span&gt;::&lt;span class="n"&…
5011 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
5012
5013 &lt;p&gt;A similar mechanism could be used for the way Meson likes to pa…
5014 command-line arguments to the programs that deal with custom targets.&lt…
5015 &lt;h2&gt;Linking to C libraries on the system&lt;/h2&gt;
5016 &lt;p&gt;Some Rust crates need to link to lower-level C libraries that a…
5017 do the work. For example, in &lt;a href="https://gtk-rs.org"&gt;gtk-rs&…
5018 crates called &lt;code&gt;gtk&lt;/code&gt;, &lt;code&gt;gdk&lt;/code&gt;…
5019 called &lt;code&gt;gtk-sys&lt;/code&gt;, &lt;code&gt;gdk-sys&lt;/code&gt…
5020 just direct wrappers on top of the C functions of the respective
5021 system libraries: &lt;code&gt;gtk-sys&lt;/code&gt; makes almost every f…
5022 &lt;code&gt;libgtk-3.so&lt;/code&gt; available as a Rust-callable functi…
5023 &lt;p&gt;System libraries sometimes live in a well-known part of the fil…
5024 (&lt;code&gt;/usr/lib64&lt;/code&gt;, for example); other times, like in…
5025 they could be anywhere. To find that location plus other related
5026 metadata (include paths for C header files, library version), many
5027 system libraries use &lt;a href="https://www.freedesktop.org/wiki/Softwa…
5028 level, one can run &lt;code&gt;pkg-config&lt;/code&gt; on the command li…
5029 scripts, to query some things about libraries. For example:&lt;/p&gt;
5030 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
5031 $ &lt;span class="nv"&gt;pkg&lt;/span&gt;&lt;span class="o"&gt;-&lt;/spa…
5032 &lt;span class="mi"&gt;3&lt;/span&gt;.&lt;span class="mi"&gt;24&lt;/span…
5033
5034 # &lt;span class="nv"&gt;what&lt;/span&gt; &lt;span class="nv"&gt;compil…
5035 $ &lt;span class="nv"&gt;pkg&lt;/span&gt;&lt;span class="o"&gt;-&lt;/spa…
5036 &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;pthread&lt;/s…
5037
5038 # &lt;span class="nv"&gt;and&lt;/span&gt; &lt;span class="nv"&gt;which&l…
5039 $ &lt;span class="nv"&gt;pkg&lt;/span&gt;&lt;span class="o"&gt;-&lt;/spa…
5040 &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;lgtk&lt;/span…
5041 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
5042
5043 &lt;p&gt;There is a &lt;a href="https://docs.rs/pkg-config/0.3.14/pkg_co…
5044 use to call this, and communicate that information to Cargo. The
5045 example in the crate's documentation is for asking pkg-config for the
5046 &lt;code&gt;foo&lt;/code&gt; package, with version at least &lt;code&gt;…
5047 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
5048
5049 &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/sp…
5050 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pkg_config&…
5051 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
5052 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
5053
5054 &lt;p&gt;And the documentation says,&lt;/p&gt;
5055 &lt;blockquote&gt;
5056 &lt;p&gt;After running pkg-config all appropriate Cargo metadata will be
5057 printed on stdout if the search was successful.&lt;/p&gt;
5058 &lt;/blockquote&gt;
5059 &lt;p&gt;Wait, what?&lt;/p&gt;
5060 &lt;p&gt;Indeed, printing specially-formated stuff on stdout is how &lt;…
5061 scripts communicate back to Cargo about their findings. To quote &lt;a …
5062 on build scripts&lt;/a&gt;; the following is talking
5063 about the stdout of &lt;code&gt;build.rs&lt;/code&gt;:&lt;/p&gt;
5064 &lt;blockquote&gt;
5065 &lt;p&gt;Any line that starts with cargo: is interpreted directly by
5066 Cargo. This line must be of the form cargo:key=value, like the
5067 examples below:&lt;/p&gt;
5068 &lt;/blockquote&gt;
5069 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
5070 &lt;span class="nv"&gt;cargo&lt;/span&gt;:&lt;span class="nv"&gt;rustc&l…
5071 &lt;span class="nv"&gt;cargo&lt;/span&gt;:&lt;span class="nv"&gt;rustc&l…
5072 &lt;span class="nv"&gt;cargo&lt;/span&gt;:&lt;span class="nv"&gt;rustc&l…
5073 &lt;span class="nv"&gt;cargo&lt;/span&gt;:&lt;span class="nv"&gt;rustc&l…
5074 # &lt;span class="nv"&gt;arbitrary&lt;/span&gt; &lt;span class="nv"&gt;u…
5075 &lt;span class="nv"&gt;cargo&lt;/span&gt;:&lt;span class="nv"&gt;root&lt…
5076 &lt;span class="nv"&gt;cargo&lt;/span&gt;:&lt;span class="nv"&gt;libdir&…
5077 &lt;span class="nv"&gt;cargo&lt;/span&gt;:&lt;span class="k"&gt;include&…
5078 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
5079
5080 &lt;p&gt;One can use the stdout of a &lt;code&gt;build.rs&lt;/code&gt; p…
5081 command-line options for &lt;code&gt;rustc&lt;/code&gt;, or set environm…
5082 or add library paths, or specific libraries.&lt;/p&gt;
5083 &lt;p&gt;&lt;strong&gt;Meson hates this scheme of things&lt;/strong&gt;.…
5084 do the pkg-config calls itself, and then pass that information down to
5085 Cargo, you guessed it, via command-line options or something
5086 well-defined like that. Again, the example &lt;code&gt;cargo_high_level…
5087 proposed above could be used to communicate this information from
5088 Meson to Cargo scripts. Meson also doesn't like this because it would
5089 prefer to know about &lt;code&gt;pkg-config&lt;/code&gt;-based libraries…
5090 fashion, without having to run a random script like &lt;code&gt;build.rs…
5091 &lt;h2&gt;Building C code from Rust&lt;/h2&gt;
5092 &lt;p&gt;Finally, some Rust crates build a bit of C code and then link t…
5093 into the compiled Rust code. I have no experience with that, but
5094 the respective build scripts generally use the &lt;a href="https://docs.…
5095 call a C compiler and pass options to it conveniently. I suppose
5096 Meson would prefer to do this instead, or at least to have a
5097 high-level way of passing down information to Cargo.&lt;/p&gt;
5098 &lt;p&gt;In effect, Meson has to be in charge of picking the C compiler.
5099 Having the thing-to-be-built pick on its own has caused big problems
5100 in the past: GObject-Introspection made the same mistake years ago
5101 when it decided to use distutils to detect the C compiler; gtk-doc did
5102 as well. When those tools are used, we still deal with problems with
5103 cross-compilation and when the system has more than one C compiler in
5104 it.&lt;/p&gt;
5105 &lt;h2&gt;Snarky comments about the Unix philosophy&lt;/h2&gt;
5106 &lt;p&gt;If part of the Unix philosophy is that shit can be glued togeth…
5107 environment variables and stringly-typed stdout... it's a pretty bad
5108 philosophy. All the cases above boil down to having a well-defined,
5109 more or less strongly-typed way to pass information between programs
5110 instead of shaking proverbial tree of the filesystem and the
5111 environment and seeing if something usable falls down.&lt;/p&gt;
5112 &lt;h2&gt;Would we really have to modify all &lt;code&gt;build.rs&lt;/co…
5113 &lt;p&gt;Probably. Why not? Meson already has a lot of very well-struc…
5114 knowledge of how to deal with multi-platform compilation and
5115 installation. Re-creating this knowledge in ad-hoc ways in &lt;code&gt;…
5116 is not very pleasant or maintainable.&lt;/p&gt;
5117 &lt;h3&gt;Related work&lt;/h3&gt;
5118 &lt;ul&gt;
5119 &lt;li&gt;
5120 &lt;p&gt;&lt;a href="https://internals.rust-lang.org/t/external-dependen…
5121 thread on using a declarative format to specify external dependencies&lt…
5122 &lt;/li&gt;
5123 &lt;li&gt;
5124 &lt;p&gt;&lt;a href="https://github.com/joshtriplett/metadeps"&gt;Run pk…
5125 &lt;/li&gt;
5126 &lt;/ul&gt;</content><category term="misc"></category><category term="ru…
5127 &lt;p&gt;&lt;img alt="Librsvg authors by lines of code by year" src="htt…
5128 &lt;p&gt;Authors by percentage of lines of code, each year:&lt;/p&gt;
5129 &lt;p&gt;&lt;img alt="Librsvg authors by percentage of lines of code by …
5130 &lt;p&gt;Which lines of code remain each year?&lt;/p&gt;
5131 &lt;p&gt;&lt;img alt="Lines of code that remain each year" src="https://…
5132 &lt;p&gt;The shitty thing about a gradual rewrite is that a few people e…
5133 "owning" all the lines of source code. Hopefully this post is a little …
5134 &lt;p&gt;&lt;img alt="Librsvg authors by lines of code by year" src="htt…
5135 &lt;p&gt;Authors by percentage of lines of code, each year:&lt;/p&gt;
5136 &lt;p&gt;&lt;img alt="Librsvg authors by percentage of lines of code by …
5137 &lt;p&gt;Which lines of code remain each year?&lt;/p&gt;
5138 &lt;p&gt;&lt;img alt="Lines of code that remain each year" src="https://…
5139 &lt;p&gt;The shitty thing about a gradual rewrite is that a few people e…
5140 "owning" all the lines of source code. Hopefully this post is a little
5141 acknowledgment of the people that made librsvg possible.&lt;/p&gt;
5142 &lt;p&gt;The charts are made with the incredible tool
5143 &lt;a href="https://github.com/erikbern/git-of-theseus"&gt;git-of-theseu…
5144 to &lt;a href="https://mastodon.art/@norwin"&gt;@[email protected]&lt;…
5145 up! Its README also points to a
5146 &lt;a href="https://github.com/src-d/hercules"&gt;Hercules&lt;/a&gt; plo…
5147 graphs. You know, for if you needed something to keep your computer
5148 busy during the weekend.&lt;/p&gt;</content><category term="misc"></cate…
5149 Rust now&lt;/a&gt;. &lt;/p&gt;
5150 &lt;p&gt;Today I finished porting the GObject boilerplate for the main
5151 &lt;code&gt;RsvgHandle&lt;/code&gt; object into Rust. This means that t…
5152 calls things like &lt;code&gt;g_type_register_static()&lt;/code&gt;, nor…
5153 &lt;code&gt;rsvg_handle_class_init()&lt;/code&gt; and such; all those ar…
5154 Rust now&lt;/a&gt;. &lt;/p&gt;
5155 &lt;p&gt;Today I finished porting the GObject boilerplate for the main
5156 &lt;code&gt;RsvgHandle&lt;/code&gt; object into Rust. This means that t…
5157 calls things like &lt;code&gt;g_type_register_static()&lt;/code&gt;, nor…
5158 &lt;code&gt;rsvg_handle_class_init()&lt;/code&gt; and such; all those ar…
5159 is this done?&lt;/p&gt;
5160 &lt;h2&gt;The life-changing magic of glib::subclass&lt;/h2&gt;
5161 &lt;p&gt;&lt;a href="https://coaxion.net/blog/"&gt;Sebastian Dröge&lt;/…
5162 utilities to make it possible to subclass GObjects in Rust, with
5163 little or no unsafe code. This &lt;a href="https://github.com/gtk-rs/gl…
5164 &lt;a href="https://github.com/gtk-rs/glib"&gt;glib-rs&lt;/a&gt;, the Ru…
5165 &lt;p&gt;Librsvg now uses the subclassing functionality in glib-rs, whic…
5166 care of some things automatically:&lt;/p&gt;
5167 &lt;ul&gt;
5168 &lt;li&gt;Registering your GObject types at runtime.&lt;/li&gt;
5169 &lt;li&gt;Creating safe traits on which you can implement &lt;code&gt;cl…
5170 &lt;code&gt;instance_init&lt;/code&gt;, &lt;code&gt;set_property&lt;/c…
5171 GObject paraphernalia.&lt;/li&gt;
5172 &lt;/ul&gt;
5173 &lt;p&gt;Check this out:&lt;/p&gt;
5174 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
5175
5176 &lt;span class="k"&gt;impl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&…
5177 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;const&lt;/s…
5178
5179 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;type&lt;/sp…
5180
5181 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;type&lt;/sp…
5182 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;type&lt;/sp…
5183
5184 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;glib_object…
5185
5186 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span…
5187 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;klass&l…
5188 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&…
5189
5190 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span…
5191 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Handle&…
5192 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&…
5193 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
5194 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
5195
5196 &lt;p&gt;In the &lt;code&gt;impl&lt;/code&gt; line, &lt;code&gt;Handle&l…
5197 to be &lt;code&gt;RsvgHandlePrivate&lt;/code&gt; in the C code.&lt;/p&gt;
5198 &lt;p&gt;The following lines say this:&lt;/p&gt;
5199 &lt;ul&gt;
5200 &lt;li&gt;
5201 &lt;p&gt;&lt;code&gt;const NAME: &amp;amp;'static str = "RsvgHandle";&lt…
5202 for GType's perusal.&lt;/p&gt;
5203 &lt;/li&gt;
5204 &lt;li&gt;
5205 &lt;p&gt;&lt;code&gt;type ParentType = glib::Object;&lt;/code&gt; - Pare…
5206 &lt;/li&gt;
5207 &lt;li&gt;
5208 &lt;p&gt;&lt;code&gt;type Instance&lt;/code&gt;, &lt;code&gt;type Class&…
5209 equivalent to GObject's class and instance structs.&lt;/p&gt;
5210 &lt;/li&gt;
5211 &lt;li&gt;
5212 &lt;p&gt;&lt;code&gt;glib_object_subclass!();&lt;/code&gt; - All the boi…
5213 automatically.&lt;/p&gt;
5214 &lt;/li&gt;
5215 &lt;li&gt;
5216 &lt;p&gt;&lt;code&gt;fn class_init&lt;/code&gt; - Should be familiar to …
5217 GObjects!&lt;/p&gt;
5218 &lt;/li&gt;
5219 &lt;/ul&gt;
5220 &lt;p&gt;And then, a couple of the property declarations:&lt;/p&gt;
5221 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
5222 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;subclass&lt…
5223 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ParamSp…
5224 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nam…
5225 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&am…
5226 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&am…
5227 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Han…
5228 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&…
5229 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Par…
5230 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/s…
5231 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}),&lt;/spa…
5232 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;subclass&lt…
5233 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ParamSp…
5234 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nam…
5235 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&am…
5236 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&am…
5237 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.…
5238 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;f6…
5239 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.…
5240 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Par…
5241 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/s…
5242 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}),&lt;/spa…
5243 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// ... etc…
5244 &lt;span class="p"&gt;];&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
5245 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
5246
5247 &lt;p&gt;This is quite similar to the way C code usually registers prope…
5248 for new GObject subclasses.&lt;/p&gt;
5249 &lt;p&gt;The moment at which a new GObject subclass gets registered agai…
5250 GType system is in the &lt;code&gt;foo_get_type()&lt;/code&gt; call. Th…
5251 librsvg for that:&lt;/p&gt;
5252 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
5253
5254 &lt;span class="n"&gt;GType&lt;/span&gt;
5255 &lt;span class="nf"&gt;rsvg_handle_get_type&lt;/span&gt; &lt;span class=…
5256 &lt;span class="p"&gt;{&lt;/span&gt;
5257 &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;rsvg…
5258 &lt;span class="p"&gt;}&lt;/span&gt;
5259 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
5260
5261 &lt;p&gt;And the Rust function that actually implements this:&lt;/p&gt;
5262 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
5263 &lt;span class="k"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&g…
5264 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Handle&lt;/…
5265 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
5266 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
5267
5268 &lt;p&gt;Here, &lt;code&gt;Handle::get_type()&lt;/code&gt; gets implemen…
5269 Sebastian's &lt;a href="https://github.com/gtk-rs/glib/tree/master/src/s…
5270 the parent class from the &lt;code&gt;impl ObjectSubclass for Handle&lt;…
5271 above, and calls &lt;code&gt;g_type_register_static()&lt;/code&gt; inter…
5272 &lt;p&gt;I can confirm now that implementing GObjects in Rust in this wa…
5273 exposing them to C, really works and is actually quite pleasant to
5274 do. &lt;a href="https://gitlab.gnome.org/federico/librsvg/blob/subclass…
5275 &lt;h2&gt;Further work&lt;/h2&gt;
5276 &lt;p&gt;There is some auto-generated C code to register librsvg's error…
5277 and a flags type against GType; I'll move those to Rust over the next
5278 few days.&lt;/p&gt;
5279 &lt;p&gt;Then, I think I'll try to actually remove all of the library's …
5280 points from the C code and implement them in Rust. Right now each C
5281 function is really just a single call to a Rust function, so this
5282 should be trivial-ish to do.&lt;/p&gt;
5283 &lt;p&gt;I'm waiting for a glib-rs release, the first one that will have…
5284 &lt;code&gt;glib::subclass&lt;/code&gt; code in it, before merging all o…
5285 librsvg's master branch.&lt;/p&gt;
5286 &lt;h2&gt;A new Rust API for librsvg?&lt;/h2&gt;
5287 &lt;p&gt;Finally, this got me thinking about what to do about the Rust b…
5288 to librsvg itself. The &lt;a href="https://github.com/selaux/rsvg-rs"&g…
5289 machinery to generate the binding: it reads the &lt;a href="https://peo…
5290 Introspection&lt;/a&gt; data from &lt;code&gt;Rsvg.gir&lt;/code&gt; and …
5291 for it.&lt;/p&gt;
5292 &lt;p&gt;However, the resulting API is mostly identical to the C API. T…
5293 an &lt;code&gt;rsvg::Handle&lt;/code&gt; with the same methods as the on…
5294 &lt;code&gt;RsvgHandle&lt;/code&gt;... and that API is not particularly …
5295 &lt;p&gt;At some point I had an unfinished branch to &lt;a href="https:/…
5296 librsvg&lt;/a&gt;. The intention was that librsvg's build procedure
5297 would first build &lt;code&gt;librsvg.so&lt;/code&gt; itself, then gener…
5298 usual, and &lt;strong&gt;then&lt;/strong&gt; generate rsvg-rs from that.…
5299 fucking with Autotools, and didn't finish integrating the projects.&lt;/…
5300 &lt;p&gt;Rsvg-rs is an &lt;em&gt;okay&lt;/em&gt; Rust API for using libr…
5301 perfectly well from the &lt;a href="https://github.com/selaux/rsvg-rs"&g…
5302 that all the functionality of librsvg is in Rust, I would like to take
5303 this opportunity to experiment with a better API for loading and
5304 rendering SVGs from Rust. This may make it more clear how to refactor
5305 the toplevel of the library. Maybe the &lt;code&gt;librsvg&lt;/code&gt;…
5306 its own Rust crate for public consumption, in addition to the usual
5307 &lt;code&gt;librsvg.so&lt;/code&gt; and &lt;code&gt;Rsvg.gir&lt;/code&gt…
5308 ABI.&lt;/p&gt;</content><category term="misc"></category><category term=…
5309 Rust code. Paolo Borelli's and Carlos Martín Nieto's latest commits
5310 made it possible.&lt;/p&gt;
5311 &lt;p&gt;What does "almost 100% Rust code" mean here?&lt;/p&gt;
5312 &lt;ul&gt;
5313 &lt;li&gt;
5314 &lt;p&gt;The C code no longer has struct fields that refer to the librar…
5315 real work. The only field …&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;</summar…
5316 Rust code. Paolo Borelli's and Carlos Martín Nieto's latest commits
5317 made it possible.&lt;/p&gt;
5318 &lt;p&gt;What does "almost 100% Rust code" mean here?&lt;/p&gt;
5319 &lt;ul&gt;
5320 &lt;li&gt;
5321 &lt;p&gt;The C code no longer has struct fields that refer to the librar…
5322 real work. The only field in &lt;code&gt;RsvgHandlePrivate&lt;/code&g…
5323 pointer to a Rust-side structure. All the rest of the library's
5324 data lives in Rust structs.&lt;/p&gt;
5325 &lt;/li&gt;
5326 &lt;li&gt;
5327 &lt;p&gt;The public API is implemented in C, but it is just stubs that
5328 immediately call into Rust functions. For example:&lt;/p&gt;
5329 &lt;/li&gt;
5330 &lt;/ul&gt;
5331 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
5332 &lt;span class="nf"&gt;rsvg_handle_render_cairo_sub&lt;/span&gt; &lt;spa…
5333 &lt;span class="p"&gt;{&lt;/span&gt;
5334 &lt;span class="n"&gt;g_return_val_if_fail&lt;/span&gt; &lt;span cla…
5335 &lt;span class="n"&gt;g_return_val_if_fail&lt;/span&gt; &lt;span cla…
5336
5337 &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;rsvg…
5338 &lt;span class="p"&gt;}&lt;/span&gt;
5339 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
5340
5341 &lt;ul&gt;
5342 &lt;li&gt;
5343 &lt;p&gt;The GObject boilerplate and supporting code is still in C:
5344 &lt;code&gt;rsvg_handle_class_init&lt;/code&gt; and &lt;code&gt;set_pr…
5345 &lt;/li&gt;
5346 &lt;li&gt;
5347 &lt;p&gt;All the high-level tests are still done in C.&lt;/p&gt;
5348 &lt;/li&gt;
5349 &lt;li&gt;
5350 &lt;p&gt;The gdk-pixbuf loader for SVG files is done in C.&lt;/p&gt;
5351 &lt;/li&gt;
5352 &lt;/ul&gt;
5353 &lt;p&gt;Someone posted a &lt;a href="https://www.reddit.com/r/rust/comm…
5354 comparing lines of code in each language vs. time.&lt;/p&gt;
5355 &lt;h2&gt;Rustifying the remaining C code&lt;/h2&gt;
5356 &lt;p&gt;There is only a handful of very small functions from the public…
5357 still implemented in C, and I am converting them one by one to Rust.
5358 These are just helper functions built on top of other public API that
5359 does the real work.&lt;/p&gt;
5360 &lt;p&gt;Converting the gdk-pixbuf loader to Rust seems like writing a l…
5361 glue code for the loadable module; the actual loading is just a couple
5362 of calls to librsvg's API.&lt;/p&gt;
5363 &lt;h3&gt;Rsvg-rs in rsvg?&lt;/h3&gt;
5364 &lt;p&gt;Converting the tests to Rust... ideally this would use the &lt;…
5365 bindings; for example, it is what I already use for &lt;a href="https://…
5366 benchmarking program for librsvg.&lt;/p&gt;
5367 &lt;p&gt;I have an &lt;a href="https://gitlab.gnome.org/federico/librsvg…
5368 into librsvg's own repository. This is because...&lt;/p&gt;
5369 &lt;ol&gt;
5370 &lt;li&gt;Librsvg builds its library, &lt;code&gt;librsvg.so&lt;/code&gt…
5371 &lt;li&gt;Gobject-introspection runs on &lt;code&gt;librsvg.so&lt;/code&…
5372 produces &lt;code&gt;librsvg.gir&lt;/code&gt;&lt;/li&gt;
5373 &lt;li&gt;Rsvg-rs's build system calls &lt;a href="https://github.com/gt…
5374 Rust binding's code.&lt;/li&gt;
5375 &lt;/ol&gt;
5376 &lt;p&gt;As you can imagine, doing all of this with Autotools is... rath…
5377 convoluted. It gives me a lot of anxiety to think that there is also
5378 an &lt;a href="https://gitlab.gnome.org/GNOME/librsvg/commits/wip/meson"…
5379 &lt;em&gt;probably&lt;/em&gt; doing the .so→.gir→rs chain would be e…
5380 knows. Help in this area is &lt;strong&gt;much&lt;/strong&gt; appreciat…
5381 &lt;h3&gt;An alternative?&lt;/h3&gt;
5382 &lt;p&gt;Rustified tests could, of course, call the C API of librsvg by …
5383 in &lt;code&gt;unsafe&lt;/code&gt; code. This may not be idiomatic, but…
5384 be done relatively quickly.&lt;/p&gt;
5385 &lt;h2&gt;Future work&lt;/h2&gt;
5386 &lt;p&gt;There are two options to get rid of all the C code in the libra…
5387 just leave C header files for public consumption:&lt;/p&gt;
5388 &lt;ol&gt;
5389 &lt;li&gt;
5390 &lt;p&gt;Do the GObject implementation in Rust, using Sebastian Dröge'…
5391 from GStreamer to do this easily.&lt;/p&gt;
5392 &lt;/li&gt;
5393 &lt;li&gt;
5394 &lt;p&gt;Work on making &lt;a href="https://gitlab.gnome.org/federico/gn…
5395 API directly, and in an ABI-compatible fashion to what there is
5396 right now.&lt;/p&gt;
5397 &lt;/li&gt;
5398 &lt;/ol&gt;
5399 &lt;p&gt;The second case will probably build upon the first one, since o…
5400 my plans for gnome-class is to make it generate code that uses
5401 Sebastian's, instead of generating all the GObject boilerplate by
5402 hand.&lt;/p&gt;</content><category term="misc"></category><category term…
5403 that doxed her. Coraline is doing extremely valuable work with the
5404 &lt;a href="https://www.contributor-covenant.org/"&gt;Contributor Covena…
5405 projects have &lt;a href="https://www.contributor-covenant.org/adopters"…
5406 &lt;p&gt;Coraline has been working for years in making free software, and
5407 computer technology …&lt;/p&gt;</summary><content type="html">&lt;p&gt…
5408 that doxed her. Coraline is doing extremely valuable work with the
5409 &lt;a href="https://www.contributor-covenant.org/"&gt;Contributor Covena…
5410 projects have &lt;a href="https://www.contributor-covenant.org/adopters"…
5411 &lt;p&gt;Coraline has been working for years in making free software, and
5412 computer technology circles in general, a welcome place for
5413 underrepresented groups.&lt;/p&gt;
5414 &lt;p&gt;I hope Coraline stays safe and strong. You can &lt;a href="htt…
5415 on Patreon&lt;/a&gt;.&lt;/p&gt;</content><category term="misc"></categor…
5416 year's GUADEC. Sorry, here it is!&lt;/p&gt;
5417 &lt;p&gt;&lt;a href="https://people.gnome.org/~federico/blog/docs/fmq-re…
5418 &lt;p&gt;You can also get the &lt;a href="https://people.gnome.org/~fede…
5419 released under a &lt;a href="https://creativecommons.org/licenses/by-sa/…
5420 &lt;p&gt;This is the &lt;a href="http://videos.guadec.org/2018/GUADEC%20…
5421 &lt;p&gt;&lt;strong&gt;&lt;em&gt;Update Dec/06:&lt;/em&gt;&lt;/strong&gt…
5422 year's GUADEC. Sorry, here it is!&lt;/p&gt;
5423 &lt;p&gt;&lt;a href="https://people.gnome.org/~federico/blog/docs/fmq-re…
5424 &lt;p&gt;You can also get the &lt;a href="https://people.gnome.org/~fede…
5425 released under a &lt;a href="https://creativecommons.org/licenses/by-sa/…
5426 &lt;p&gt;This is the &lt;a href="http://videos.guadec.org/2018/GUADEC%20…
5427 &lt;p&gt;&lt;strong&gt;&lt;em&gt;Update Dec/06:&lt;/em&gt;&lt;/strong&gt…
5428 pointers&lt;/a&gt;; I've updated the example code in the presentation to
5429 match &lt;a href="https://gitlab.gnome.org/GNOME/librsvg/merge_requests/…
5430 request has an interesting conversation on FFI esoterica, too.&lt;/p&gt;…
5431 to Rust, I went into a digression that has to do with the way librsvg
5432 decides which files are allowed to be referenced from within an SVG.&lt;…
5433 &lt;h1&gt;Resource references in SVG&lt;/h1&gt;
5434 &lt;p&gt;SVG files can reference other files …&lt;/p&gt;</summary><con…
5435 to Rust, I went into a digression that has to do with the way librsvg
5436 decides which files are allowed to be referenced from within an SVG.&lt;…
5437 &lt;h1&gt;Resource references in SVG&lt;/h1&gt;
5438 &lt;p&gt;SVG files can reference other files, i.e. they are not
5439 self-contained. For example, there can be an element like &lt;code&gt;&…
5440 xlink:href="foo.png"&amp;gt;&lt;/code&gt;, or one can request that a sub…
5441 another SVG be included with &lt;code&gt;&amp;lt;use xlink:href="seconda…
5442 Finally, there is the &lt;code&gt;xi:include&lt;/code&gt; mechanism to i…
5443 or XML into another XML file.&lt;/p&gt;
5444 &lt;p&gt;Since librsvg is sometimes used to render untrusted files that …
5445 the internet, it needs to be careful not to allow those files to
5446 reference any random resource on the filesystem. We don't want
5447 something like
5448 &lt;code&gt;&amp;lt;text&amp;gt;&amp;lt;xi:include href="/etc/passwd" pa…
5449 or something equally nefarious that would exfiltrate a random file
5450 into the rendered output.&lt;/p&gt;
5451 &lt;p&gt;Also, want to catch malicious SVGs that want to "phone home" by
5452 referencing a network resource like
5453 &lt;code&gt;&amp;lt;image xlink:href="http://evil.com/pingback.jpg"&amp;…
5454 &lt;p&gt;So, librsvg is careful to have a single place where it can load
5455 secondary resources, and first it validates the resource's URL to see
5456 if it is allowed.&lt;/p&gt;
5457 &lt;p&gt;The actual validation rules are not very important for this
5458 discussion; they are something like "no absolute URLs allowed" (so you
5459 can't request &lt;code&gt;/etc/passwd&lt;/code&gt;, "only siblings or (g…
5460 siblings allowed" (so &lt;code&gt;foo.svg&lt;/code&gt; can request &lt;c…
5461 &lt;code&gt;subdir/bar.svg&lt;/code&gt;, but not &lt;code&gt;../../bar.s…
5462 &lt;h1&gt;The code&lt;/h1&gt;
5463 &lt;p&gt;There was a central function &lt;code&gt;rsvg_io_acquire_stream…
5464 URL as a string. The code assumed that that URL had been first
5465 validated with a function called &lt;code&gt;allow_load(url)&lt;/code&gt…
5466 structure guaranteed that all the places that may acquire a stream
5467 would actually go through &lt;code&gt;allow_load()&lt;/code&gt; first, t…
5468 code in Rust made it possible to actually make it impossible to
5469 acquire a disallowed URL.&lt;/p&gt;
5470 &lt;p&gt;Before:&lt;/p&gt;
5471 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
5472
5473 &lt;span class="k"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&g…
5474
5475 &lt;span class="k"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&g…
5476 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span…
5477 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;acquire…
5478 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&…
5479 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Err&lt…
5480 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&…
5481 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
5482 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
5483
5484 &lt;p&gt;The refactored code now has an &lt;code&gt;AllowedUrl&lt;/code&…
5485 URL, plus the promise that it &lt;strong&gt;has&lt;/strong&gt; gone thro…
5486 &lt;ul&gt;
5487 &lt;li&gt;The URL has been run through a URL well-formedness parser.&lt;…
5488 &lt;li&gt;The resource is allowed to be loaded following librsvg's rules…
5489 &lt;/ul&gt;
5490 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
5491
5492 &lt;span class="k"&gt;impl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&…
5493 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;pub&lt;/spa…
5494 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;let&lt…
5495
5496 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/…
5497 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Ok…
5498 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/s…
5499 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Er…
5500 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/s…
5501 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&…
5502 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
5503
5504 &lt;span class="c1"&gt;// new prototype&lt;/span&gt;
5505 &lt;span class="k"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&g…
5506 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
5507
5508 &lt;p&gt;This forces callers to validate the URLs as soon as possible, r…
5509 after they get them from the SVG file. Now it is not possible to
5510 request a stream unless the URL has been validated first.&lt;/p&gt;
5511 &lt;h1&gt;Plain URIs vs. fragment identifiers&lt;/h1&gt;
5512 &lt;p&gt;Some of the elements in SVG that reference other data require f…
5513 files:&lt;/p&gt;
5514 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
5515 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
5516
5517 &lt;p&gt;And some others, that reference particular elements in secondar…
5518 require a fragment ID:&lt;/p&gt;
5519 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
5520 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
5521
5522 &lt;p&gt;And finally, the &lt;code&gt;feImage&lt;/code&gt; element, used…
5523 a filter effects pipeline, allows either:&lt;/p&gt;
5524 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
5525 &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;feImage…
5526
5527 &lt;span class="o"&gt;&amp;lt;!--&lt;/span&gt; &lt;span class="n"&gt;wil…
5528 &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;feImage…
5529 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
5530
5531 &lt;p&gt;So, I introduced a general &lt;code&gt;Href&lt;/code&gt; parser…
5532 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
5533 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PlainUri&lt…
5534 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;WithFragmen…
5535 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
5536
5537 &lt;span class="sd"&gt;/// Optional URI, mandatory fragment id&lt;/span&…
5538 &lt;span class="k"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&g…
5539 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
5540
5541 &lt;p&gt;The parts of the code that absolutely require a fragment id now…
5542 &lt;code&gt;Fragment&lt;/code&gt;. Parts which require a &lt;code&gt;Pl…
5543 &lt;p&gt;The next step is making those structs contain an &lt;code&gt;Al…
5544 directly, instead of just strings, so that for callers, obtaining a
5545 fully validated name is a one-step operation.&lt;/p&gt;
5546 &lt;p&gt;In general, the code is moving towards a scheme where all file …
5547 done at loading time. Right now, some of those external references
5548 get resolved at rendering time, which is somewhat awkward (for
5549 example, at rendering time the caller has no chance to use a
5550 &lt;code&gt;GCancellable&lt;/code&gt; to cancel loading). This refactor…
5551 validation is leaving the code in a very nice state.&lt;/p&gt;</content>…
5552 in Thessaloniki, Greece. This is the beautiful city that will host
5553 next year's GUADEC, but fortunately GUADEC will be in summertime!&lt;/p&…
5554 &lt;p&gt;We held the hackfest at the &lt;a href="http://coho.gr/"&gt;CoH…
5555 office between the …&lt;/p&gt;</summary><content type="html">&lt;p&gt;…
5556 in Thessaloniki, Greece. This is the beautiful city that will host
5557 next year's GUADEC, but fortunately GUADEC will be in summertime!&lt;/p&…
5558 &lt;p&gt;We held the hackfest at the &lt;a href="http://coho.gr/"&gt;CoH…
5559 office between the University and the sea.&lt;/p&gt;
5560 &lt;p&gt;Every such hackfest I am overwhelmed by the kind hackers who wo…
5561 [gnome-class], the code generator for GObject implementations in
5562 Rust.&lt;/p&gt;
5563 &lt;p&gt;Mredlek has been working on generalizing the code generators in
5564 gnome-class, so that we can have the following from the same run:&lt;/p&…
5565 &lt;ul&gt;
5566 &lt;li&gt;
5567 &lt;p&gt;Rust code generation, for the GObject implementations themselve…
5568 Thanks to mredlek, this is much cleaner than it was before; now both
5569 classes and interfaces share the same code for most of the
5570 boilerplate.&lt;/p&gt;
5571 &lt;/li&gt;
5572 &lt;li&gt;
5573 &lt;p&gt;GObject Introspection (&lt;code&gt;.gir&lt;/code&gt;) generatio…
5574 can be generated automatically.&lt;/p&gt;
5575 &lt;/li&gt;
5576 &lt;li&gt;
5577 &lt;p&gt;C header files (&lt;code&gt;.h&lt;/code&gt;), so the generated …
5578 C code as usual.&lt;/p&gt;
5579 &lt;/li&gt;
5580 &lt;/ul&gt;
5581 &lt;p&gt;So far, Rust and GIR work; C header files are not generated yet…
5582 &lt;p&gt;Mredlek is a new contributor to gnome-class, but unfortunately …
5583 able to attend the hackfest. Not only did he rewrite the gnome-class
5584 parser using the new version of &lt;a href="https://docs.rs/syn/0.15.22/…
5585 passing owned types to GObject methods, such as &lt;code&gt;String&lt;/c…
5586 &lt;code&gt;Variant&lt;/code&gt;. But the biggest thing is probably tha…
5587 lot easier to debug the generated Rust source; see &lt;a href="https://f…
5588 on debugging&lt;/a&gt; for details.&lt;/p&gt;
5589 &lt;p&gt;Speaking of which, thanks to Jordan Petridis for making the
5590 documentation be published automatically from Gitlab's Continuous
5591 Integration pipelines.&lt;/p&gt;
5592 &lt;p&gt;Alex Crichton kindly refactored our error propagation code, and…
5593 wrote docs on it&lt;/a&gt;! Along with Jordan, they updated the
5594 code for the Rust 2018 edition, and generally wrangled the build
5595 process to conform with the lastest Rust nightlies. Alex also made
5596 code generation a lot faster, by offloading auto-indentation to an
5597 external &lt;code&gt;rustfmt&lt;/code&gt; process, instead of using it a…
5598 &lt;code&gt;rustfmt&lt;/code&gt; crate meant that the compiler had a lot…
5599 During the whole hackfest, Alex was very helpful with Rust questions
5600 in general. While my strategy to see what the compiler does is to
5601 examine the disassembly in gdb, his strategy seems to be to look at
5602 the LLVM intermediate representation instead... OMG.&lt;/p&gt;
5603 &lt;h1&gt;And we can derive very simple GtkWidgets now!&lt;/h1&gt;
5604 &lt;p&gt;Saving the best for last... Antoni Boucher, the author of &lt;a…
5605 been working on making it possible to derive from &lt;code&gt;gtk::Widge…
5606 &lt;a href="https://gitlab.gnome.org/federico/gnome-class/merge_requests…
5607 deriving from &lt;code&gt;gtk::DrawingArea&lt;/code&gt; from Rust with v…
5608 &lt;p&gt;Normally, the &lt;a href="https://gtk-rs.org/"&gt;gtk-rs&lt;/a&…
5609 for GObject, which really is a type hierarchy defined at runtime. The
5610 static binding really wants to know what is a subclass of what: it
5611 needs to know in advance that &lt;code&gt;Button&lt;/code&gt;'s hierarch…
5612 Container → Widget → Object&lt;/code&gt;, plus all the &lt;code&gt;G…
5613 by any of those classes. Antoni has been working on making
5614 gnome-class extract that information automatically from GIR files, so
5615 that the gtk-rs macros that define new types will get all the
5616 necessary information.&lt;/p&gt;
5617 &lt;h1&gt;Future work&lt;/h1&gt;
5618 &lt;p&gt;There are still &lt;a href="https://gitlab.gnome.org/GNOME/gtk/…
5619 from deriving, say, from &lt;code&gt;gtk::Container&lt;/code&gt;, but ho…
5620 resolved soon.&lt;/p&gt;
5621 &lt;p&gt;Sebastian Dröge has been refactoring his Rust tools to create …
5622 subclasses with very idiomatic and refined Rust code. This is now at
5623 a state where gnome-class itself could generate that sort of code,
5624 instead of generating all the boilerplate from scratch. So, we'll
5625 start doing that, and integrating the necessary bits into gtk-rs as
5626 well.&lt;/p&gt;
5627 &lt;p&gt;Finally, during the last day I took a little break from gnome-c…
5628 work on librsvg. Julian Sparber has been updating the code to use new
5629 bindings in cairo-rs, and is also adding a &lt;a href="https://gitlab.gn…
5630 fetch an SVG element's geometry precisely.&lt;/p&gt;
5631 &lt;h1&gt;Thessaloniki&lt;/h1&gt;
5632 &lt;p&gt;Oh, boy, I wish the weather had been warmer. The city looks
5633 delightful to walk around, especially in the narrow streets on the
5634 hills. Can't wait to see it in summer during GUADEC.&lt;/p&gt;
5635 &lt;h1&gt;Thanks&lt;/h1&gt;
5636 &lt;p&gt;Finally, thanks to &lt;a href="http://coho.gr/"&gt;CoHo&lt;/a&g…
5637 Foundation for sponsoring my travel and accomodation. And to
5638 &lt;a href="https://www.centricular.com/"&gt;Centricular&lt;/a&gt; for t…
5639 &lt;p&gt;Special thanks to Jordan Petridis for being on top of everything
5640 build-wise all the time.&lt;/p&gt;
5641 &lt;p&gt;&lt;img alt="Sponsored by the GNOME Foundation" src="https://pe…
5642 from C to Rust. For many technical reasons, the library still uses
5643 libxml2, GNOME's historic XML parsing library, but some of the
5644 callbacks to handle XML events like &lt;code&gt;start_element&lt;/code&g…
5645 &lt;code&gt;characters&lt;/code&gt;, are now implemented in Rust. This …
5646 from C to Rust. For many technical reasons, the library still uses
5647 libxml2, GNOME's historic XML parsing library, but some of the
5648 callbacks to handle XML events like &lt;code&gt;start_element&lt;/code&g…
5649 &lt;code&gt;characters&lt;/code&gt;, are now implemented in Rust. This …
5650 running into all the cases where the original C code in librsvg failed
5651 to handle errors properly; Rust really makes it obvious when that
5652 happens.&lt;/p&gt;
5653 &lt;p&gt;In this post I want to talk a bit about propagating errors. Yo…
5654 a function, it returns an error, and then what?&lt;/p&gt;
5655 &lt;h2&gt;What can fail?&lt;/h2&gt;
5656 &lt;p&gt;It turns out that this question is highly context-dependent. L…
5657 say a program is starting up and tries to read a configuration file.
5658 What could go wrong?&lt;/p&gt;
5659 &lt;ul&gt;
5660 &lt;li&gt;
5661 &lt;p&gt;The file doesn't exist. Maybe it is the very first time the pr…
5662 is run, and so there &lt;em&gt;isn't&lt;/em&gt; a configuration file a…
5663 program provide a default configuration in this case? Or does it
5664 absolutely need a pre-written configuration file to be somewhere?&lt;/…
5665 &lt;/li&gt;
5666 &lt;li&gt;
5667 &lt;p&gt;The file can't be parsed. Should the program warn the user and
5668 exit, or should it revert to a default configuration (should it
5669 overwrite the file with valid, default values)? &lt;em&gt;Can&lt;/em&…
5670 the program warn the user, or is it a user-less program that at best
5671 can just shout into the void of a server-side log file?&lt;/p&gt;
5672 &lt;/li&gt;
5673 &lt;li&gt;
5674 &lt;p&gt;The file can be parsed, but the values are invalid. Same quest…
5675 as the case above.&lt;/p&gt;
5676 &lt;/li&gt;
5677 &lt;li&gt;
5678 &lt;p&gt;Etcetera.&lt;/p&gt;
5679 &lt;/li&gt;
5680 &lt;/ul&gt;
5681 &lt;p&gt;At each stage, the code will probably see very low-level errors…
5682 not found", "I/O error", "parsing failed", "value is out of range").
5683 What the code decides to do, or what it is able to do at any
5684 particular stage, depends both on the semantics you want from the
5685 program, and from the code structure itself.&lt;/p&gt;
5686 &lt;h2&gt;Structuring the problem&lt;/h2&gt;
5687 &lt;p&gt;This is an easy, but very coarse way of handling things:&lt;/p&…
5688 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
5689 &lt;span class="nf"&gt;read_configuration&lt;/span&gt; &lt;span class="p…
5690 &lt;span class="p"&gt;{&lt;/span&gt;
5691 &lt;span class="cm"&gt;/* open the file */&lt;/span&gt;
5692
5693 &lt;span class="cm"&gt;/* parse it */&lt;/span&gt;
5694
5695 &lt;span class="cm"&gt;/* set global variables to the configuration …
5696
5697 &lt;span class="cm"&gt;/* return true if success, or false if failur…
5698 &lt;span class="p"&gt;}&lt;/span&gt;
5699 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
5700
5701 &lt;p&gt;What is bad about this? Let's see:&lt;/p&gt;
5702 &lt;ul&gt;
5703 &lt;li&gt;
5704 &lt;p&gt;The calling code just gets a success/failure condition. In the…
5705 of failure, it doesn't get to know why things failed.&lt;/p&gt;
5706 &lt;/li&gt;
5707 &lt;li&gt;
5708 &lt;p&gt;If the function sets global variables with configuration values…
5709 they get read... and something goes wrong and the function returns
5710 an error... the caller ends up possibly in an inconsistent state,
5711 with a set of configuration variables that are only halfway-set.&lt;/p…
5712 &lt;/li&gt;
5713 &lt;li&gt;
5714 &lt;p&gt;If the function finds parse errors, well, do you really want to…
5715 UI code from inside it? The caller might be a better place to make
5716 that decision.&lt;/p&gt;
5717 &lt;/li&gt;
5718 &lt;/ul&gt;
5719 &lt;h2&gt;A slightly better structure&lt;/h2&gt;
5720 &lt;p&gt;Let's add an enumeration to indicate the possible errors, and a
5721 structure of configuration values.&lt;/p&gt;
5722 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
5723 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ConfigFileD…
5724 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ParseError&…
5725 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ValueError&…
5726 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
5727
5728 &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;ConfigV…
5729 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// a bunch…
5730 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
5731
5732 &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;read_config…
5733 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// open th…
5734
5735 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// parse t…
5736
5737 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// validat…
5738
5739 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// if ever…
5740 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
5741 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
5742
5743 &lt;p&gt;This is better, in that the caller decides what to do with the
5744 validated &lt;code&gt;ConfigValues&lt;/code&gt;: maybe it can just copy…
5745 program's global variables for configuration.&lt;/p&gt;
5746 &lt;p&gt;However, this scheme doesn't give the caller all the informatio…
5747 would like to present a really good error message. For example, the
5748 caller will get to know if there is a parse error, but it doesn't know
5749 specifically what failed during parsing. Similarly, it will just get
5750 to know if there was an invalid value, but not which one.&lt;/p&gt;
5751 &lt;h2&gt;Ah, so the problem is fractal&lt;/h2&gt;
5752 &lt;p&gt;We could have new structs to represent the little errors, and t…
5753 make them part of the original error enum:&lt;/p&gt;
5754 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
5755 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;line&lt;/sp…
5756 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;column&lt;/…
5757 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;error_reaso…
5758 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
5759
5760 &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;ValueEr…
5761 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;config_key&…
5762 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;error_reaso…
5763 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
5764
5765 &lt;span class="k"&gt;enum&lt;/span&gt; &lt;span class="nc"&gt;ConfigErr…
5766 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ConfigFileD…
5767 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ParseError&…
5768 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ValueError&…
5769 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
5770 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
5771
5772 &lt;p&gt;Is that enough? It depends.&lt;/p&gt;
5773 &lt;p&gt;The &lt;code&gt;ParseError&lt;/code&gt; and &lt;code&gt;ValueEr…
5774 &lt;code&gt;error_reason&lt;/code&gt; fields, which are strings. Presum…
5775 a &lt;code&gt;ParseError&lt;/code&gt; with &lt;code&gt;error_reason = "u…
5776 &lt;code&gt;ValueError&lt;/code&gt; with &lt;code&gt;error_reason = "can…
5777 &lt;p&gt;One problem with this is that if the low-level errors come with…
5778 messages in English, then the caller has to know how to localize them
5779 to the user's language. Also, if they don't have a machine-readable
5780 error code, then the calling code may not have enough information to
5781 decide what do do with the error.&lt;/p&gt;
5782 &lt;p&gt;Let's say we had a &lt;code&gt;ParseErrorKind&lt;/code&gt; enum…
5783 &lt;code&gt;UnexpectedToken&lt;/code&gt;, &lt;code&gt;EndOfFile&lt;/code…
5784 calling code know the &lt;em&gt;reason&lt;/em&gt; for the error. Also, …
5785 &lt;code&gt;gimme_localized_error_message()&lt;/code&gt; method for that…
5786 error.&lt;/p&gt;
5787 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
5788 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;UnexpectedT…
5789 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EndOfFile&l…
5790 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MissingComm…
5791 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// ... etc…
5792 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
5793
5794 &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;ParseEr…
5795 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;line&lt;/sp…
5796 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;column&lt;/…
5797 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;kind&lt;/sp…
5798 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
5799 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
5800
5801 &lt;p&gt;How can we expand this? Maybe the &lt;code&gt;ParseErrorKind::…
5802 variant wants to contain data that indicates &lt;em&gt;which&lt;/em&gt; …
5803 was wrong, so it would be &lt;code&gt;UnexpectedToken(String)&lt;/code&g…
5804 similar.&lt;/p&gt;
5805 &lt;p&gt;But is &lt;em&gt;that&lt;/em&gt; useful to the calling code? F…
5806 which is reading a configuration file... it probably only needs to
5807 know if it could parse the file, but maybe it doesn't really need any
5808 additional details on the reason for the parse error, other than
5809 having something useful to present to the user. Whether it is
5810 appropriate to burden the user with the actual details... does the app
5811 expect to make it the user's job to fix broken configuration files?
5812 Yes for a web server, where the user is a sysadmin; probably not for a
5813 random end-user graphical app, where people shouldn't need to write
5814 configuration files by hand in the first place (should &lt;em&gt;those&l…
5815 "Details" section in the error message window? I don't know!).&lt;/p&gt;
5816 &lt;p&gt;Maybe the low-level parsing/validation code &lt;em&gt;can&lt;/e…
5817 errors. But how can we propagate them to something more useful to the
5818 upper layers of the code?&lt;/p&gt;
5819 &lt;h2&gt;Translation and propagation&lt;/h2&gt;
5820 &lt;p&gt;Maybe our original &lt;code&gt;read_configuration()&lt;/code&gt…
5821 low-level errors into high-level ones:&lt;/p&gt;
5822 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
5823 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// open fi…
5824
5825 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span…
5826 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&…
5827 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&…
5828
5829 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/sp…
5830
5831 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// parse f…
5832
5833 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/sp…
5834
5835 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// validat…
5836
5837 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/sp…
5838
5839 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// yay!&lt…
5840 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Ok&lt;/spa…
5841 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
5842 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
5843
5844 &lt;p&gt;Etcetera. It is up to each part of the code to decide what do …
5845 lower-level errors. Can it recover from them? Should it fail the
5846 whole operation and return a higher-level error? Should it warn the
5847 user right there?&lt;/p&gt;
5848 &lt;h2&gt;Language facilities&lt;/h2&gt;
5849 &lt;p&gt;C makes it really easy to ignore errors, and pretty hard to pre…
5850 detailed errors like the above. One could mimic what Rust is actually
5851 doing with a collection of &lt;code&gt;union&lt;/code&gt; and &lt;code&g…
5852 gets very awkward very fast.&lt;/p&gt;
5853 &lt;p&gt;Rust provides these facilities at the language level, and the i…
5854 around &lt;code&gt;Result&lt;/code&gt; and error handling are very nice …
5855 even crates like &lt;a href="https://boats.gitlab.io/failure/intro.html"…
5856 automating error translation, propagation, and conversion to strings
5857 for presenting to users.&lt;/p&gt;
5858 &lt;h2&gt;Infinite details&lt;/h2&gt;
5859 &lt;p&gt;I've been recommending &lt;a href="http://joeduffyblog.com/2016…
5860 comes into a discussion of error handling in programming languages.
5861 It's a long, detailed, but very enlightening read on recoverable
5862 vs. unrecoverable errors, simple error codes vs. exceptions
5863 vs. monadic results, the performance/reliability/ease of use of each
5864 model... Definitely worth a read.&lt;/p&gt;</content><category term="mis…
5865 gdk-pixbuf's history. There is some talk about replacing it with
5866 something newer; hopefully this history will show some things that
5867 worked, some that didn't, and why.&lt;/p&gt;
5868 &lt;h2&gt;The beginnings&lt;/h2&gt;
5869 &lt;p&gt;Gdk-pixbuf started as a replacement for Imlib, the image …&lt…
5870 gdk-pixbuf's history. There is some talk about replacing it with
5871 something newer; hopefully this history will show some things that
5872 worked, some that didn't, and why.&lt;/p&gt;
5873 &lt;h2&gt;The beginnings&lt;/h2&gt;
5874 &lt;p&gt;Gdk-pixbuf started as a replacement for Imlib, the image loadin…
5875 rendering library that GNOME used in its earliest versions. Imlib
5876 came from the Enlightenment project; it provided an easy API around
5877 the idiosyncratic libungif, libjpeg, libpng, etc., and it maintained
5878 decoded images in memory with a uniform representation. Imlib also
5879 worked as an image cache for the Enlightenment window manager, which
5880 made memory management very inconvenient for GNOME.&lt;/p&gt;
5881 &lt;p&gt;Imlib worked well as a "just load me an image" library. It sho…
5882 that a small, uniform API to load various image formats into a common
5883 representation was desirable. And in those days, hiding all the
5884 complexities of displaying images in X was very important indeed.&lt;/p&…
5885 &lt;h2&gt;The initial API&lt;/h2&gt;
5886 &lt;p&gt;Gdk-pixbuf replaced Imlib, and added two important features:
5887 reference counting for image data, and support for an alpha channel.&lt;…
5888 &lt;p&gt;Gdk-pixbuf appeared with support for RGB(A) images. And althou…
5889 theory it was possible to grow the API to support other
5890 representations, &lt;a href="https://gitlab.gnome.org/GNOME/gdk-pixbuf/b…
5891 &lt;code&gt;GDK_COLORSPACE_RGB&lt;/code&gt;, and the &lt;a href="https:/…
5892 functions &lt;a href="https://gitlab.gnome.org/GNOME/gdk-pixbuf/blob/369…
5893 channel was done with a &lt;code&gt;gboolean&lt;/code&gt; argument in co…
5894 single &lt;code&gt;GDK_COLORSPACE_RGB&lt;/code&gt; value; we didn't have…
5895 &lt;a href="https://gitlab.freedesktop.org/cairo/cairo/blob/201791a5/src…
5896 enum values.&lt;/p&gt;
5897 &lt;p&gt;While all the code in gdk-pixbuf carefully checks that those
5898 conditions are met — RGBA at 8 bits per channel —, some applications
5899 inadvertently assume that &lt;em&gt;that&lt;/em&gt; is the only possible…
5900 into trouble really fast if gdk-pixbuf ever started returning pixbufs
5901 with different color spaces or depths.&lt;/p&gt;
5902 &lt;p&gt;One can still see the battle between bilevel-alpha
5903 vs. continuous-alpha in &lt;a href="https://gitlab.gnome.org/GNOME/gdk-p…
5904 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
5905 &lt;span class="p"&gt;{&lt;/span&gt;
5906 &lt;span class="n"&gt;GDK_PIXBUF_ALPHA_BILEVEL&lt;/span&gt;&lt;s…
5907 &lt;span class="n"&gt;GDK_PIXBUF_ALPHA_FULL&lt;/span&gt;
5908 &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="n"&gt;GdkPixbufAlph…
5909 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
5910
5911 &lt;p&gt;Fortunately, only the "&lt;a href="https://gitlab.gnome.org/GNO…
5912 drawable&lt;/a&gt;" functions take values of this type: before the Xre…
5913 days, it was a Big Deal to draw an image with alpha to an X window,
5914 and applications often opted to use a bitmask instead, even if they
5915 had jagged edges as a result.&lt;/p&gt;
5916 &lt;h2&gt;Pixel formats&lt;/h2&gt;
5917 &lt;p&gt;The only pixel format that ever got implemented was unpremultip…
5918 RGBA on all platforms. Back then I didn't understand &lt;a href="https:…
5919 alpha&lt;/a&gt;! Also, the GIMP followed that scheme, and copying
5920 it seemed like the easiest thing.&lt;/p&gt;
5921 &lt;p&gt;After gdk-pixbuf, libart also copied that pixel format, I think…
5922 &lt;p&gt;But later we got Cairo, Pixman, and all the Xrender stack. The…
5923 prefer premultiplied ARGB. Moreover, Cairo prefers it if each pixel
5924 is actually a 32-bit value, with the ARGB values inside it in
5925 platform-endian order. So if you look at a memory dump, a Cairo pixel
5926 looks like BGRA on a little-endian box, while it looks like ARGB on a
5927 big-endian box.&lt;/p&gt;
5928 &lt;p&gt;Every time we paint a &lt;code&gt;GdkPixbuf&lt;/code&gt; to a &…
5929 conversion from unpremultiplied RGBA to premultiplied, platform-endian
5930 ARGB. I talked a bit about this in &lt;a href="https://people.gnome.org…
5931 copies in GNOME&lt;/a&gt;.&lt;/p&gt;
5932 &lt;h2&gt;The loading API&lt;/h2&gt;
5933 &lt;p&gt;The public loading API in gdk-pixbuf, and its relationship to l…
5934 plug-ins, evolved in interesting ways.&lt;/p&gt;
5935 &lt;p&gt;At first the public API and loaders only implemented &lt;code&g…
5936 you gave the library a &lt;code&gt;FILE *&lt;/code&gt; and it gave you b…
5937 Back then we didn't have a robust MIME sniffing framework in the form
5938 of a library, so gdk-pixbuf got its own. This lives in the
5939 mostly-obsolete &lt;a href="https://gitlab.gnome.org/GNOME/gdk-pixbuf/bl…
5940 even has its own &lt;a href="https://gitlab.gnome.org/GNOME/gdk-pixbuf/b…
5941 Nowadays we do most MIME sniffing with GIO.&lt;/p&gt;
5942 &lt;p&gt;After the intial &lt;code&gt;load_from_file&lt;/code&gt; API...…
5943 loading first, and animation support aftewards.&lt;/p&gt;
5944 &lt;h2&gt;Progressive loading&lt;/h2&gt;
5945 &lt;p&gt;This where the calling program feeds chunks of bytes to the lib…
5946 and at the end a fully-formed &lt;code&gt;GdkPixbuf&lt;/code&gt; comes o…
5947 a single "read a whole file" operation.&lt;/p&gt;
5948 &lt;p&gt;We conflated this with a way to get &lt;a href="https://gitlab.…
5949 modified&lt;/a&gt; as the data gets parsed. I think we wanted to suppor…
5950 case of a web browser, which downloads images slowly over the network,
5951 and gradually displays them as they are downloaded. In 1998, images
5952 downloading slowly over the network was a real concern!&lt;/p&gt;
5953 &lt;p&gt;It took a lot of very careful work to convert the image loaders…
5954 parsed a whole file at a time, into loaders that could maintain some
5955 state between each time that they got handed an extra bit of buffer.&lt;…
5956 &lt;p&gt;It also sounded easy to implement the progressive updating API …
5957 simply emitting a signal that said, "this rectangular area got updated
5958 from the last read". It could handle the case of reading whole
5959 scanlines, or a few pixels, or even area-based updates for progressive
5960 JPEGs and PNGs.&lt;/p&gt;
5961 &lt;p&gt;The internal API for the image format loaders still keeps a
5962 distinction between the "load a whole file" API and the "load an image
5963 in chunks". Not all loaders got redone to simply just use the second
5964 one: &lt;code&gt;io-jpeg.c&lt;/code&gt; &lt;a href="https://gitlab.gnom…
5965 corresponding libjpeg functions. I think it could remove that code
5966 and use the progressive loading functions instead.&lt;/p&gt;
5967 &lt;h2&gt;Animations&lt;/h2&gt;
5968 &lt;p&gt;Animations: we followed the GIF model for animations, in which…
5969 frame overlays the previous one, and there's a delay set between each
5970 frame. This is not a video file; it's a hacky flipbook.&lt;/p&gt;
5971 &lt;p&gt;However, animations presented the problem that the whole gdk-pi…
5972 API was meant for static images, and now we needed to support
5973 multi-frame images as well.&lt;/p&gt;
5974 &lt;p&gt;We defined the "correct" way to use the gdk-pixbuf library as to
5975 actually try to load an animation, and then see if it is a
5976 single-frame image, in which case you can just get a &lt;code&gt;GdkPixb…
5977 the only frame and use it.&lt;/p&gt;
5978 &lt;p&gt;Or, if you got an animation, that would be a &lt;a href="https:…
5979 object, from which you could ask for an iterator to get each frame as
5980 a separate &lt;code&gt;GdkPixbuf&lt;/code&gt;.&lt;/p&gt;
5981 &lt;p&gt;However, the progressive updating API never got extended to rea…
5982 support animations. So, we have awkward functions like
5983 &lt;code&gt;gdk_pixbuf_animation_iter_on_currently_loading_frame()&lt;/c…
5984 &lt;h2&gt;Necessary accretion&lt;/h2&gt;
5985 &lt;p&gt;Gdk-pixbuf got support for saving just a few formats: JPEG, PN…
5986 TIFF, ICO, and some of the formats that are implemented with the
5987 Windows-native loaders.&lt;/p&gt;
5988 &lt;p&gt;Over time gdk-pixbuf got support for preserving some metadata-i…
5989 chunks from formats that provide it: DPI, color profiles, image
5990 comments, hotspots for cursors/icons...&lt;/p&gt;
5991 &lt;p&gt;While an image is being loaded with the progressive loaders, th…
5992 a clunky way to specify that one doesn't want the actual size of the
5993 image, but another size instead. The loader can handle that situation
5994 itself, hopefully if an image format actually embeds different sizes
5995 in it. Or if not, the main loading code will rescale the full loaded
5996 image into the size specified by the application.&lt;/p&gt;
5997 &lt;h2&gt;Historical cruft&lt;/h2&gt;
5998 &lt;p&gt;&lt;a href="https://gitlab.gnome.org/GNOME/gdk-pixbuf/blob/3693…
5999 funky encoding. Nowadays it's just easier to directly store a PNG or
6000 JPEG or whatever in a &lt;code&gt;GResource&lt;/code&gt;.&lt;/p&gt;
6001 &lt;p&gt;&lt;a href="https://gitlab.gnome.org/GNOME/gdk-pixbuf/blob/3693…
6002 Hopefully mostly unused now, but there's a good number of mostly old,
6003 third-party software that still uses gdk-pixbuf as an image loader and
6004 renderer to X drawables.&lt;/p&gt;
6005 &lt;p&gt;&lt;a href="https://gitlab.gnome.org/GNOME/gdk-pixbuf/blob/3693…
6006 scaling functions, which the original versions of EOG used for the
6007 core of the image viewer. Nowadays Cairo is the preferred way of
6008 doing this, since it not only does scaling, but general affine
6009 transformations as well. Did you know that
6010 &lt;code&gt;gdk_pixbuf_composite_color&lt;/code&gt; takes 17 arguments,…
6011 an image with alpha on top of a checkerboard? Yes, that used to be
6012 the core of EOG.&lt;/p&gt;
6013 &lt;h2&gt;Debatable historical cruft&lt;/h2&gt;
6014 &lt;p&gt;&lt;code&gt;gdk_pixbuf_get_pixels()&lt;/code&gt;. This lets th…
6015 pixels of a loaded pixbuf, and modify them. Gdk-pixbuf just did not
6016 have a concept of immutability.&lt;/p&gt;
6017 &lt;p&gt;Back in GNOME 1.x / 2.x, when it was fashionable to put icons b…
6018 menu items, or in toolbar buttons, applications would load their icon
6019 images, and modify them in various ways before setting them onto the
6020 corresponding widgets. Some things they did: load a colorful icon,
6021 desaturate it for "insensitive" command buttons or menu items, or
6022 simulate desaturation by compositing a 1x1-pixel checkerboard on the
6023 icon image. Or lighten the icon and set it as the "prelight" one onto
6024 widgets.&lt;/p&gt;
6025 &lt;p&gt;The concept of "decode an image and just give me the pixels" is…
6026 course useful. Image viewers, image processing programs, and all
6027 those, of course need this functionality.&lt;/p&gt;
6028 &lt;p&gt;However, these days GTK would prefer to have a way to decode an…
6029 and ship it as fast as possible ot the GPU, without intermediaries.
6030 There is all sorts of awkward machinery in the GTK widgets that
6031 can consume either an icon from an icon theme, or a user-supplied
6032 image, or one of the various schemes for providing icons that GTK has
6033 acquired over the years.&lt;/p&gt;
6034 &lt;p&gt;It is interesting to note that &lt;code&gt;gdk_pixbuf_get_pixel…
6035 pretty much since the beginning, but it was only until much later that
6036 we got &lt;code&gt;gdk_pixbuf_get_pixels_with_length()&lt;/code&gt;, the…
6037 *&lt;/code&gt; buffer and also its length" function, so that calling cod…
6038 chance of actually checking for buffer overruns. (... and it is one
6039 of the broken "give me a length" functions that returns a &lt;code&gt;gu…
6040 rather than a &lt;code&gt;gsize&lt;/code&gt;. There is a better
6041 &lt;code&gt;gdk_pixbuf_get_byte_length()&lt;/code&gt; which actually ret…
6042 though.)&lt;/p&gt;
6043 &lt;h2&gt;Problems with mutable pixbufs&lt;/h2&gt;
6044 &lt;p&gt;The main problem is that as things are right now, we have no
6045 flexibility in changing the internal representation of image data to
6046 make it better for current idioms: GPU-specific pixel formats may not
6047 be unpremultiplied RGBA data.&lt;/p&gt;
6048 &lt;p&gt;We have no API to say, "this pixbuf has been modified", akin to
6049 &lt;code&gt;cairo_surface_mark_dirty()&lt;/code&gt;: once an applicatio…
6050 &lt;code&gt;gdk_pixbuf_get_pixels()&lt;/code&gt;, gdk-pixbuf or GTK have…
6051 data &lt;em&gt;will&lt;/em&gt; be changed and they have to re-run the pi…
6052 the image to the GPU (format conversions? caching? creating a
6053 texture?).&lt;/p&gt;
6054 &lt;p&gt;Also, ever since the beginnings of the gdk-pixbuf API, we had a…
6055 create pixbufs from arbitrary user-supplied RGBA buffers: the
6056 &lt;code&gt;gdk_pixbuf_new_from_data&lt;/code&gt; functions. One proble…
6057 that memory management of the buffer is up to the calling application,
6058 so the resulting pixbuf isn't free to handle those resources as it
6059 pleases.&lt;/p&gt;
6060 &lt;p&gt;A relatively recent addition is &lt;code&gt;gdk_pixbuf_new_from…
6061 takes a &lt;code&gt;GBytes&lt;/code&gt; buffer instead of a random &lt;c…
6062 is created that way, it is &lt;em&gt;assumed&lt;/em&gt; to be immutable,…
6063 is basically a shared reference into a byte buffer, and it's just
6064 easier to think of it as immutable. (Nothing in C actually enforces
6065 immutability, but the API indicates that convention.)&lt;/p&gt;
6066 &lt;p&gt;Internally, &lt;code&gt;GdkPixbuf&lt;/code&gt; actually prefers…
6067 &lt;code&gt;GBytes&lt;/code&gt;. It will &lt;a href="https://gitlab.gno…
6068 something calls the old &lt;code&gt;gdk_pixbuf_get_pixels()&lt;/code&gt;…
6069 that will just take ownership of the internal buffer from the
6070 &lt;code&gt;GBytes&lt;/code&gt; (if the &lt;code&gt;GBytes&lt;/code&gt; …
6071 case, it will copy the buffer from the &lt;code&gt;GBytes&lt;/code&gt; a…
6072 of that copy. In either case, when the pixbuf downgrades itself to
6073 pixels, it is assumed that the calling application will modify the
6074 pixel data.&lt;/p&gt;
6075 &lt;h2&gt;What would immutable pixbufs look like?&lt;/h2&gt;
6076 &lt;p&gt;I mentioned this a bit in "&lt;a href="https://people.gnome.org…
6077 loaders in gdk-pixbuf would create immutable pixbufs, with an internal
6078 representation that is friendly to GPUs. In the proposed scheme, that
6079 internal representation would be a Cairo image surface; it can be
6080 something else if GTK/GDK eventually prefer a different way of
6081 shipping image data into the toolkit.&lt;/p&gt;
6082 &lt;p&gt;Those pixbufs would be immutable. In true C fashion we can cal…
6083 undefined behavior to change the pixel data (say, an app could request
6084 &lt;code&gt;gimme_the_cairo_surface&lt;/code&gt; and tweak it, but that …
6085 supported).&lt;/p&gt;
6086 &lt;p&gt;I think we could also have a "just give me the pixels" API, and…
6087 "create a pixbuf from these pixels" one, but those would be one-time
6088 conversions at the edge of the API. Internally, the pixel data that
6089 actually lives inside a &lt;code&gt;GdkPixbuf&lt;/code&gt; would remain …
6090 preferred representation, which is not necessarily what the
6091 application sees.&lt;/p&gt;
6092 &lt;h2&gt;What worked well&lt;/h2&gt;
6093 &lt;p&gt;A small API to load multiple image formats, and paint the images
6094 easily to the screen, while handling most of the X awkwardness
6095 semi-automatically, was very useful!&lt;/p&gt;
6096 &lt;p&gt;A way to get and modify pixel data: applications clearly like d…
6097 this. We can formalize it as an application-side thing only, and keep
6098 the internal representation immutable and in a format that can evolve
6099 according to the needs of the internal API.&lt;/p&gt;
6100 &lt;p&gt;Pluggable loaders, up to a point. Gdk-pixbuf doesn't support a…
6101 image formats in the world out of the box, but it is relatively easy
6102 for third-parties to provide loaders that, once installed, are
6103 automatically usable for all applications.&lt;/p&gt;
6104 &lt;h2&gt;What didn't work well&lt;/h2&gt;
6105 &lt;p&gt;Having effectively two pixel formats supported, and nothing els…
6106 gdk-pixbuf does packed RGB and unpremultiplied RGBA, and that's it.
6107 This isn't completely terrible: applications which really want to
6108 know about indexed or grayscale images, or high bit-depth ones, are
6109 &lt;em&gt;probably&lt;/em&gt; specialized enough that they can afford to…
6110 custom loaders with all the functionality they need.&lt;/p&gt;
6111 &lt;p&gt;Pluggable loaders, up to a point. While it is relatively easy …
6112 create third-party loaders, installation is awkward from a system's
6113 perspective: one has to run the script to regenerate the loader cache,
6114 there are more shared libraries running around, and the loaders are
6115 not sandboxed by default.&lt;/p&gt;
6116 &lt;p&gt;I'm not sure if it's worthwhile to let any application read "an…
6117 image format if gdk-pixbuf supports it. If your word processor lets
6118 you paste an image into the document... do you want it to use
6119 gdk-pixbuf's limited view of things and include a high bit-depth image
6120 with its probably inadequate conversions? Or would you rather do some
6121 processing by hand to ensure that the image looks as good as it can,
6122 in the format that your word processor actually supports? I don't
6123 know.&lt;/p&gt;
6124 &lt;p&gt;The API for animations is very awkward. We don't even support
6125 APNG... but honestly I don't recall actually seeing one of those in
6126 the wild.&lt;/p&gt;
6127 &lt;p&gt;The progressive loading API is awkward. The "feed some bytes i…
6128 loader" part is mostly okay; the "notify me about changes to the pixel
6129 data" is questionable nowadays. Web browsers don't use it; they
6130 implement their own loaders. Even EOG doesn't use it.&lt;/p&gt;
6131 &lt;p&gt;I think most code that actually connects to &lt;code&gt;GdkPixb…
6132 signals only uses the &lt;code&gt;size-prepared&lt;/code&gt; signal — …
6133 emitted soon after reading the image headers, when the loader gets to
6134 know the dimensions of the image. Apps sometimes use this to say,
6135 "this image is W*H pixels in size", but don't actually decode the
6136 rest of the image.&lt;/p&gt;
6137 &lt;p&gt;The gdk-pixbuf model of static images, or GIF animations, doesn…
6138 well for multi-page TIFFs. I'm not sure if this is actualy a problem.
6139 Again, applications with actual needs for multi-page TIFFs are
6140 probably specialized enough that they will want a full-featured TIFF
6141 loader of their own.&lt;/p&gt;
6142 &lt;h2&gt;Awkward architectures&lt;/h2&gt;
6143 &lt;h3&gt;Thumbnailers&lt;/h3&gt;
6144 &lt;p&gt;The thumbnailing system has slowly been moving towards a model …
6145 we actually have thumbnailers specific to each file format, instead of
6146 just assuming that we can dump any image into a gdk-pixbuf loader.&lt;/p…
6147 &lt;p&gt;If we take this all the way, we would be able to remove some we…
6148 code in, for example, the JPEG pixbuf loader. Right now it supports
6149 loading images at a size that the calling code requests, not only at
6150 the "natural" size of the JPEG. The thumbnailer can say, "I want to
6151 load this JPEG at 128x128 pixels" or whatever, and &lt;em&gt;in theory&l…
6152 JPEG loader will do the minimal amount of work required to do that.
6153 It's not 100% clear to me if this is actually working as intended, or
6154 if we downscale the whole image anyway.&lt;/p&gt;
6155 &lt;p&gt;We had a distinction between in-process and out-of-process
6156 thumbnailers, and it had to do with the way pixbuf loaders are used;
6157 I'm not sure if they are all out-of-process and sandboxed now.&lt;/p&gt;
6158 &lt;h3&gt;Non-raster data&lt;/h3&gt;
6159 &lt;p&gt;There is a gdk-pixbuf loader for SVG images which uses librsvg
6160 internally, but only in a very basic way: it simply loads the SVG at
6161 its preferred size. Librsvg jumps through some hoops to compute a
6162 "preferred size" for SVGs, as not all of them actually indicate one.
6163 The SVG model would rather have the renderer say that the SVG is to be
6164 inserted into a rectangle of certain width/height, and
6165 scaled/positioned inside the rectangle according to some other
6166 parameters (i.e. like one would put it inside an HTML document, with a
6167 &lt;code&gt;preserveAspectRatio&lt;/code&gt; attribute and all that). G…
6168 historically operated with a different model, one of "load me an
6169 image, I'll scale it to whatever size, and paint it".&lt;/p&gt;
6170 &lt;p&gt;This gdk-pixbuf loader for SVG files gets used for the SVG
6171 thumbnailer, or more accurately, the "throw random images into a
6172 gdk-pixbuf loader" thumbnailer. It may be better/cleaner to have a
6173 specific thumbnailer for SVGs instead.&lt;/p&gt;
6174 &lt;p&gt;Even EOG, our by-default image viewer, doesn't use the gdk-pixb…
6175 loader for SVGs: it actually special-cases them and uses librsvg
6176 directly, to be able to load an SVG once and re-render it at different
6177 sizes if one changes the zoom factor, for example.&lt;/p&gt;
6178 &lt;p&gt;GTK reads its SVG icons... without using librsvg... by assuming…
6179 librsvg installed its gdk-pixbuf loader, so it loads them as any
6180 normal raster image. This kind of dirty, but I can't quite pinpoint
6181 why. I'm sure it would be convenient for icon themes to ship a single
6182 SVG with tons of icons, and some metadata on their &lt;code&gt;id&lt;/co…
6183 could pick them out of the SVG file with &lt;code&gt;rsvg_render_cairo_s…
6184 something. Right now icon theme authors are responsible for splitting
6185 out those huge SVGs into many little ones, one for each icon, and I
6186 don't think that's their favorite thing in the world to do :)&lt;/p&gt;
6187 &lt;h3&gt;Exotic raster data&lt;/h3&gt;
6188 &lt;p&gt;High bit-depth images... would you expect EOG to be able to loa…
6189 Certainly; maybe not with all the fancy conversions from a real RAW
6190 photo editor. But maybe this can be done as EOG-specific plugins,
6191 rather than as low in the platform as the gdk-pixbuf loaders?&lt;/p&gt;
6192 &lt;p&gt;(Same thing for thumbnailing high bit-depth images: the loadin…
6193 should just provide its own thumbnailer program for those.)&lt;/p&gt;
6194 &lt;h3&gt;Non-image metadata&lt;/h3&gt;
6195 &lt;p&gt;The &lt;code&gt;gdk_pixbuf_set_option&lt;/code&gt; / &lt;code&g…
6196 functions is so that pixbuf loaders can set key/value pairs of strings
6197 onto a pixbuf. Loaders use this for &lt;code&gt;comment&lt;/code&gt; bl…
6198 for color calibration, or DPI information for images that have it, or
6199 EXIF data from photos. It is up to applications to actually use this
6200 information.&lt;/p&gt;
6201 &lt;p&gt;It's a bit uncomfortable that gdk-pixbuf makes no promises abou…
6202 kind of raster data it gives to the caller: right now it is raw
6203 RGB(A) data that is not gamma-corrected nor in any particular color
6204 space. It is up to the caller to see if the pixbuf has an ICC profile
6205 attached to it as an &lt;code&gt;option&lt;/code&gt;. Effectively, this…
6206 applications don't know if they are getting SRGB, or linear RGB, or
6207 what... unless they specifically care to look.&lt;/p&gt;
6208 &lt;p&gt;The gdk-pixbuf API could probably make promises: if you call &…
6209 function&lt;/em&gt; you will get SRGB data; if you call &lt;em&gt;this o…
6210 you'll get the raw RGBA data and we'll tell you its
6211 colorspace/gamma/etc.&lt;/p&gt;
6212 &lt;p&gt;The various &lt;code&gt;set_option&lt;/code&gt; / &lt;code&gt;g…
6213 gdk-pixbuf &lt;em&gt;saving&lt;/em&gt; code (up to now we have just talk…
6214 loaders). I don't know enough about how applications use the saving
6215 code in gdk-pixbuf... the thumbnailers use it to save PNGs or JPEGs,
6216 but other apps? No idea.&lt;/p&gt;
6217 &lt;h2&gt;What I would like to see&lt;/h2&gt;
6218 &lt;p&gt;&lt;strong&gt;Immutable pixbufs in a useful format.&lt;/strong&…
6219 this&lt;/a&gt; in a merge request; the internal code is now ready
6220 to take in different internal representations of pixel data. My goal
6221 is to make Cairo image surfaces the preferred, immutable, internal
6222 representation. This would give us a
6223 &lt;code&gt;gdk_pixbuf_get_cairo_surface()&lt;/code&gt;, which pretty mu…
6224 needs one reimplements by hand.&lt;/p&gt;
6225 &lt;p&gt;&lt;strong&gt;Find places that assume mutable pixbufs.&lt;/stro…
6226 mutable pixbufs, I think we would need to audit applications and
6227 libraries to find places that cause &lt;code&gt;GdkPixbuf&lt;/code&gt; s…
6228 into mutable ones: basically, find callers of
6229 &lt;code&gt;gdk_pixbuf_get_pixels()&lt;/code&gt; and related functions, …
6230 reimplement them differently. Maybe they don't need to tint icons by
6231 hand anymore? Maybe they &lt;em&gt;don't need icons&lt;/em&gt; anymore,…
6232 changing UI paradigms? Maybe they are using gdk-pixbuf as an image
6233 loader only?&lt;/p&gt;
6234 &lt;p&gt;&lt;strong&gt;Reconsider the loading-updates API.&lt;/strong&gt…
6235 &lt;code&gt;GdkPixbufLoader::area-updated&lt;/code&gt; signal at all? D…
6236 if we just... not emit it, or just emit it once at the end of the
6237 loading process? (Caveat: keeping it unchanged more or less means
6238 that "immutable pixbufs" as loaded by gdk-pixbuf actually mutate while
6239 being loaded, and this mutation is exposed to applications.)&lt;/p&gt;
6240 &lt;p&gt;&lt;strong&gt;Sandboxed loaders.&lt;/strong&gt; While these da…
6241 progressive feed-it-bytes API, sandboxed loaders would maybe prefer a
6242 read-a-whole-file approach. I don't know enough about memfd or how
6243 sandboxes pass data around to know how either would work.&lt;/p&gt;
6244 &lt;p&gt;&lt;strong&gt;Move loaders to Rust.&lt;/strong&gt; Yes, really…
6245 security-sensitive, and while we &lt;em&gt;do&lt;/em&gt; need to sandbox…
6246 certainly be better to do them in a memory-safe language. There are
6247 already pure Rust-based image loaders: &lt;a href="https://crates.io/cra…
6248 &lt;a href="https://crates.io/crates/png"&gt;PNG&lt;/a&gt;, &lt;a href="…
6249 I have no idea how featureful they are. We can certainly try them
6250 with gdk-pixbuf's own suite of test images. We can modify them to add
6251 hooks for things like a &lt;code&gt;size-prepared&lt;/code&gt; notificat…
6252 already have a way to read "just the image headers".&lt;/p&gt;
6253 &lt;p&gt;Rust makes it very easy to plug in &lt;a href="https://crates.i…
6254 &lt;a href="https://crates.io/crates/afl"&gt;fuzz testing&lt;/a&gt;, and…
6255 perfect for improving the loaders.&lt;/p&gt;
6256 &lt;p&gt;I started &lt;a href="https://gitlab.gnome.org/federico/gdk-pix…
6257 loaders&lt;/a&gt; some months ago, but there's nothing useful
6258 yet. One mismatch between gdk-pixbuf's model for loaders, and the
6259 existing Rust codecs, is that Rust codecs generally take something
6260 that implements the &lt;code&gt;Read&lt;/code&gt; trait: a blocking API …
6261 abstract sources; it's a pull API. The gdk-pixbuf model is a push
6262 API: the calling code creates a loader object, and then pushes bytes
6263 into it. The gdk-pixbuf convenience functions that take a
6264 &lt;code&gt;GInputStream&lt;/code&gt; basically do this:&lt;/p&gt;
6265 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
6266
6267 &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/spa…
6268 &lt;span class="n"&gt;n_read&lt;/span&gt; &lt;span class="o"&gt;=&lt…
6269 &lt;span class="n"&gt;gdk_pixbuf_loader_write&lt;/span&gt;&lt;span c…
6270 &lt;span class="p"&gt;}&lt;/span&gt;
6271
6272 &lt;span class="n"&gt;gdk_pixbuf_loader_close&lt;/span&gt; &lt;span clas…
6273 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
6274
6275 &lt;p&gt;However, this cannot be flipped around easily. We could probab…
6276 a second thread (easy, safe to do in Rust) to make the reader/decoder
6277 thread block while the main thread pushes bytes into it.&lt;/p&gt;
6278 &lt;p&gt;Also, I don't know how the Rust bindings for GIO present things…
6279 &lt;code&gt;GInputStream&lt;/code&gt; and friends, with our nice async c…
6280 that.&lt;/p&gt;
6281 &lt;p&gt;&lt;strong&gt;Deprecate animations?&lt;/strong&gt; Move that c…
6282 at memes in it? Do any "real apps" actually use GIF animations for
6283 their UI?&lt;/p&gt;
6284 &lt;p&gt;&lt;strong&gt;Formalize promises around returned color profiles…
6285 mentioned above: have an "easy API" that returns SRGB, and a "raw API"
6286 that returns the ARGB data from the image, plus info on its ICC
6287 profile, gamma, or any other info needed to turn this into a
6288 "good enough to be universal" representation. (I &lt;em&gt;think&lt;/em…
6289 Apple APIs that pass colors around do so with an ICC profile attached,
6290 which seems... pretty much necessary for correctness.)&lt;/p&gt;
6291 &lt;p&gt;&lt;strong&gt;Remove the internal MIME-sniffing machinery.&lt;/…
6292 &lt;p&gt;&lt;strong&gt;Deprecate the crufty/old APIs in gdk-pixbuf.&lt;/…
6293 Scaling/transformation, compositing, &lt;code&gt;GdkPixdata&lt;/code&gt;,
6294 &lt;code&gt;gdk-pixbuf-csource&lt;/code&gt;, all those. Pixel crunching…
6295 Cairo; the others are better done with &lt;code&gt;GResource&lt;/code&gt…
6296 &lt;p&gt;&lt;strong&gt;Figure out if we want blessed codecs; fix thumbna…
6297 loaders statically, unconditionally. Exotic formats can go in their
6298 own custom thumbnailers. Figure out if we want sandboxed loaders for
6299 everything, or just for user-side images (not ones read from the
6300 trusted system installation).&lt;/p&gt;
6301 &lt;p&gt;&lt;strong&gt;Have GTK4 communicate clearly about its drawing m…
6302 are having a disconnect between the GUI chrome, which is CSS/GPU
6303 friendly, and graphical content generated by applications, which by
6304 default right now is done via Cairo. And having Cairo as a to-screen
6305 and to-printer API is certainly very convenient! You Wouldn't Print a
6306 GUI, but certainly you would print a displayed document.&lt;/p&gt;
6307 &lt;p&gt;It would also be useful for GTK4 to actually define what its pr…
6308 image format is if it wants to ship it to the GPU with as little work
6309 as possible. Maybe it's a Cairo image surface? Maybe something else?&l…
6310 &lt;h2&gt;Conclusion&lt;/h2&gt;
6311 &lt;p&gt;We seem to change imaging models every ten years or so. Xlib, …
6312 Xrender with Cairo, then GPUs and CSS-based drawing for widgets.
6313 We've gone from trusted data on your local machine, to potentially malic…
6314 rains from the Internet. Gdk-pixbuf has spanned all of these periods
6315 so far, and it is due for a big change.&lt;/p&gt;</content><category ter…
6316 because it was leaking all the SVG nodes — has been interesting.&lt;/p…
6317 &lt;p&gt;&lt;em&gt;Memory leaks in Rust? Isn't it supposed to prevent t…
6318 &lt;p&gt;Well, yeah, but the leaks were caused by the C side of things, …
6319 &lt;code&gt;unsafe&lt;/code&gt; code in Rust, which …&lt;/p&gt;</summa…
6320 because it was leaking all the SVG nodes — has been interesting.&lt;/p…
6321 &lt;p&gt;&lt;em&gt;Memory leaks in Rust? Isn't it supposed to prevent t…
6322 &lt;p&gt;Well, yeah, but the leaks were caused by the C side of things, …
6323 &lt;code&gt;unsafe&lt;/code&gt; code in Rust, which does not prevent lea…
6324 &lt;p&gt;&lt;a href="https://gitlab.gnome.org/federico/librsvg/commit/29…
6325 function implemented in Rust, which returns a newly-acquired reference
6326 to an SVG node. The old code simply got a pointer to the node,
6327 without acquiring a reference. The new code was forgetting to
6328 &lt;code&gt;rsvg_node_unref()&lt;/code&gt;. No biggie.&lt;/p&gt;
6329 &lt;p&gt;&lt;a href="https://gitlab.gnome.org/GNOME/librsvg/commit/2d3dd…
6330 was apparently calling all the functions to unref nodes as
6331 appropriate, and even calling the &lt;code&gt;rsvg_tree_free()&lt;/code&…
6332 end; this is the "free the whole SVG tree" function.&lt;/p&gt;
6333 &lt;p&gt;There are these types:&lt;/p&gt;
6334 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
6335 &lt;span class="k"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&g…
6336
6337 &lt;span class="c1"&gt;// This is the real structure we care about&lt;/s…
6338 &lt;span class="k"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&g…
6339 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// This is…
6340 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;pub&lt;/spa…
6341 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;..&lt;/span…
6342 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
6343 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
6344
6345 &lt;p&gt;&lt;code&gt;Tree&lt;/code&gt; is the real struct that holds the…
6346 other data. Each node is an &lt;code&gt;Rc&amp;lt;Node&amp;gt;&lt;/code…
6347 leaked (... and all the children, recursively) because its reference
6348 count never went down from 1.&lt;/p&gt;
6349 &lt;p&gt;&lt;code&gt;RsvgTree&lt;/code&gt; is just an empty type. The c…
6350 &lt;code&gt;*const Tree&lt;/code&gt; as &lt;code&gt;*const RsvgTree&lt;/…
6351 the C code.&lt;/p&gt;
6352 &lt;p&gt;The &lt;code&gt;rsvg_tree_free()&lt;/code&gt; function, callabl…
6353 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
6354 &lt;span class="k"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&g…
6355 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span…
6356 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;let&lt…
6357 &lt;span class="w"&gt; &lt;/span&gt;&lt;span cla…
6358 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&…
6359 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
6360 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
6361
6362 &lt;p&gt;When we call &lt;code&gt;Box::from_raw()&lt;/code&gt; on a &lt;…
6363 a &lt;code&gt;Box&amp;lt;RsvgTree&amp;gt;&lt;/code&gt;... which is a box…
6364 frees zero memory when the box gets dropped.&lt;/p&gt;
6365 &lt;p&gt;The code was missing this cast:&lt;/p&gt;
6366 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
6367 &lt;span class="w"&gt; &lt;/span&gt;&lt;…
6368 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/sp…
6369 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
6370
6371 &lt;p&gt;So, &lt;code&gt;tree as *mut Tree&lt;/code&gt; gives us a value…
6372 &lt;code&gt;Box::from_raw()&lt;/code&gt; to return a &lt;code&gt;Box&amp…
6373 Dropping the box will drop the &lt;code&gt;Tree&lt;/code&gt;, reduce the…
6374 on the root node, and free all the nodes recursively.&lt;/p&gt;
6375 &lt;h2&gt;Monitoring an &lt;code&gt;Rc&amp;lt;T&amp;gt;&lt;/code&gt;'s r…
6376 &lt;p&gt;So, how does one set a gdb watchpoint on the reference count?&l…
6377 &lt;p&gt;First I set a breakpoint on a function which I knew would get p…
6378 the &lt;code&gt;Rc&amp;lt;Node&amp;gt;&lt;/code&gt; I care about:&lt;/p&…
6379 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
6380 Breakpoint 3 at 0x7ffff71f3aaa: file rsvg_internals/src/structure.rs, li…
6381
6382 (gdb) c
6383 Continuing.
6384
6385 Thread 1 &amp;quot;rsvg-convert&amp;quot; hit Breakpoint 3, &amp;lt;rsvg…
6386
6387 (gdb) p node
6388 $5 = (alloc::rc::Rc&amp;lt;rsvg_internals::node::Node&amp;gt; *) 0x64c890
6389 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
6390
6391 &lt;p&gt;Okay, &lt;code&gt;node&lt;/code&gt; is a reference to an &lt;co…
6392 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
6393 $6 = {ptr = {pointer = {__0 = 0x625800}}, phantom = {&amp;lt;No data fie…
6394 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
6395
6396 &lt;p&gt;Why, a &lt;code&gt;pointer&lt;/code&gt; to the actual contents …
6397 again:&lt;/p&gt;
6398 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
6399 $9 = {strong = {value = {value = 3}}, weak = {value = {value = 1}}, ...…
6400 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
6401
6402 &lt;p&gt;Aha! There are the &lt;code&gt;strong&lt;/code&gt; and &lt;cod…
6403 watchpoint on the strong reference count:&lt;/p&gt;
6404 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
6405 (gdb) watch *$ptr
6406 Hardware watchpoint 4: *$ptr
6407 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
6408
6409 &lt;p&gt;Continue running the program until the reference count changes:…
6410 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
6411 &lt;span class="nv"&gt;Thread&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/…
6412
6413 &lt;span class="nv"&gt;Old&lt;/span&gt; &lt;span class="nv"&gt;value&lt;…
6414 &lt;span class="nv"&gt;New&lt;/span&gt; &lt;span class="nv"&gt;value&lt;…
6415 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
6416
6417 &lt;p&gt;At this point I can print a stack trace and see if it makes sen…
6418 check that the refs/unrefs are matched, etc.&lt;/p&gt;
6419 &lt;p&gt;TL;DR: dig into the &lt;code&gt;Rc&amp;lt;T&amp;gt;&lt;/code&gt…
6420 watch it. It's wrapped in several layers of Rust-y types; &lt;code&gt;N…
6421 pointers, an &lt;code&gt;RcBox&lt;/code&gt; for the actual container of …
6422 object it's wrapping, and &lt;code&gt;Cell&lt;/code&gt;s for the refcoun…
6423 until you reach the refcount values and they are there.&lt;/p&gt;
6424 &lt;h2&gt;So, how did I find the missing cast?&lt;/h2&gt;
6425 &lt;p&gt;Using that gdb recipe, I watched the reference count of the top…
6426 SVG node change until the program exited. When the program
6427 terminated, the reference count was 1 — it should have dropped to 0 if
6428 there was no memory leak.&lt;/p&gt;
6429 &lt;p&gt;The last place where the toplevel node loses a reference is in
6430 &lt;code&gt;rsvg_tree_free()&lt;/code&gt;. I ran the program again and …
6431 function was being called; it &lt;em&gt;was&lt;/em&gt; being called corr…
6432 that the problem must lie in that function. After a little
6433 head-scratching, I found the missing cast. Other functions of the
6434 form &lt;code&gt;rsvg_tree_whatever()&lt;/code&gt; had that cast, but &l…
6435 missing it.&lt;/p&gt;
6436 &lt;p&gt;I think Rust now has better facilities to tag structs that are …
6437 as raw pointers to &lt;code&gt;extern&lt;/code&gt; code, to avoid this k…
6438 casting. We'll see.&lt;/p&gt;
6439 &lt;p&gt;In the meantime, apologies for the buggy releases!&lt;/p&gt;</c…
6440 for librsvg.&lt;/p&gt;
6441 &lt;p&gt;A popular way to add logging to Rust code is to use the &lt;a h…
6442 This lets you sprinkle simple messages in your code:&lt;/p&gt;
6443 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
6444 &lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span…
6445 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
6446
6447 &lt;p&gt;However, the &lt;a href="https://crates.io/crates/log"&gt;log �…
6448 for librsvg.&lt;/p&gt;
6449 &lt;p&gt;A popular way to add logging to Rust code is to use the &lt;a h…
6450 This lets you sprinkle simple messages in your code:&lt;/p&gt;
6451 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
6452 &lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span…
6453 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
6454
6455 &lt;p&gt;However, the &lt;a href="https://crates.io/crates/log"&gt;log&l…
6456 messages do not get emitted anywhere. The calling code has to set up
6457 a logger. Crates like &lt;a href="https://crates.io/crates/env_logger"&…
6458 program initialization, that gets configured through an environment
6459 variable.&lt;/p&gt;
6460 &lt;p&gt;And this is a problem for librsvg: we are &lt;em&gt;not&lt;/em…
6461 initialization! Librsvg is a library; it doesn't have a &lt;code&gt;mai…
6462 function. And since most of the calling code is not Rust, we can't
6463 assume that they can call code that can initialize the logging
6464 framework.&lt;/p&gt;
6465 &lt;h2&gt;Why not use glib's logging stuff?&lt;/h2&gt;
6466 &lt;p&gt;Currently this is a bit clunky to use from Rust, since glib's
6467 structured logging functions are not bound yet in &lt;a href="http://gtk…
6468 would be good to bind them and get this over with.&lt;/p&gt;
6469 &lt;h2&gt;What user experience do we want?&lt;/h2&gt;
6470 &lt;p&gt;In the past, what has worked well for me to do logging from lib…
6471 is to allow the user to set an environment variable to control the
6472 logging, or to drop a log configuration file in their $HOME. The
6473 former works well when the user is in control of running the program
6474 that will print the logs; the latter is useful when the user is not
6475 directly in control, like for gnome-shell, which gets launched through
6476 a lot of magic during session startup.&lt;/p&gt;
6477 &lt;p&gt;For librsvg, it's probably enough to just use an environment
6478 variable. Set &lt;code&gt;RSVG_LOG=parse_errors&lt;/code&gt;, run your …
6479 useful output. &lt;a href="https://makezine.com/2016/06/10/push-button-…
6480 &lt;h2&gt;Other options in Rust?&lt;/h2&gt;
6481 &lt;p&gt;There is a &lt;a href="https://crates.io/crates/slog"&gt;slog&l…
6482 context-less macros which depend on a single global logger, it
6483 provides logging macros to which you pass a logger object.&lt;/p&gt;
6484 &lt;p&gt;For librsvg, this means that the basic &lt;code&gt;RsvgHandle&l…
6485 own logger, based on an environment variable or whatever, and pass it
6486 around to all its child functions for when they need to log something.&l…
6487 &lt;p&gt;Slog supports structured logging, and seems to have some fancy …
6488 modes. We'll see.&lt;/p&gt;</content><category term="misc"></category><…
6489 on in librsvg right now:&lt;/p&gt;
6490 &lt;ol&gt;
6491 &lt;li&gt;
6492 &lt;p&gt;Paolo Borelli finished porting all the CSS properties to Rust.
6493 What was once a gigantic &lt;code&gt;RsvgState&lt;/code&gt; struct in…
6494 along with all the janky C code to parse individual properties …&lt…
6495 on in librsvg right now:&lt;/p&gt;
6496 &lt;ol&gt;
6497 &lt;li&gt;
6498 &lt;p&gt;Paolo Borelli finished porting all the CSS properties to Rust.
6499 What was once a gigantic &lt;code&gt;RsvgState&lt;/code&gt; struct in…
6500 along with all the janky C code to parse individual properties.
6501 The process of porting &lt;code&gt;RsvgState&lt;/code&gt; to Rust has…
6502 about two months ago&lt;/a&gt;, and has involved many multi-commit
6503 merge requests and refactorings. This is a tremendous amount of
6504 really good work! The result is all in Rust now in a &lt;code&gt;Sta…
6505 struct, which is opaque from C's viewpoint. The only places in C
6506 that still require accessors to the &lt;code&gt;State&lt;/code&gt; ar…
6507 effects code. Which brings me to...&lt;/p&gt;
6508 &lt;/li&gt;
6509 &lt;li&gt;
6510 &lt;p&gt;Ivan Molodetskikh, my Summer of Code student, submitted his &lt…
6511 merge request&lt;/a&gt; and it's merged to master now. This ports
6512 the bookkeeping infrastructure for SVG filters to Rust, and also
6513 the &lt;code&gt;feOffset&lt;/code&gt; filter is ported now. Right no…
6514 anything fancy to iterate over the pixels of Cairo image surfaces;
6515 that will come later. I am very happy that filters, which were a
6516 huge barrier, are now starting to get chipped away into nicer code.&l…
6517 &lt;/li&gt;
6518 &lt;li&gt;
6519 &lt;p&gt;I have started to move librsvg's old representation of CSS
6520 properties into something that can really represent properties that
6521 are not specified, or explicitly set to &lt;code&gt;inherit&lt;/code&…
6522 element's parent, or set to a normal value. Librsvg never had a
6523 representation of property values that actually matched the SVG/CSS
6524 specs; it just knew whether a property was specified or not for an
6525 element. This worked fine for properties which the spec mandates
6526 that they should inherit automatically, but those that &lt;em&gt;don'…
6527 were handled through special hacks. The new code makes this a lot
6528 cleaner. It should also make it easier to copy Servo's idioms for
6529 property inheritance.&lt;/p&gt;
6530 &lt;/li&gt;
6531 &lt;/ol&gt;</content><category term="misc"></category><category term="li…
6532 over the years.&lt;/p&gt;
6533 &lt;h1&gt;In ye olden days&lt;/h1&gt;
6534 &lt;p&gt;In the context of GIMP/GNOME, the only thing that knew how to d…
6535 images to X11 windows (doing palette mapping for 256-color graphics
6536 cards and dithering if necessary) was the …&lt;/p&gt;</summary><conten…
6537 over the years.&lt;/p&gt;
6538 &lt;h1&gt;In ye olden days&lt;/h1&gt;
6539 &lt;p&gt;In the context of GIMP/GNOME, the only thing that knew how to d…
6540 images to X11 windows (doing palette mapping for 256-color graphics
6541 cards and dithering if necessary) was the GIMP. Later, when GTK+ was
6542 written, it exported a &lt;code&gt;GtkPreview&lt;/code&gt; widget, which…
6543 image buffer supplied by the application and render it to an X window
6544 — this was what GIMP plug-ins could use in their user interface to
6545 show, well, previews of what they were about to do with the user's
6546 images. Later we got some obscure magic in a &lt;code&gt;GdkColorContex…
6547 object, which helped allocate X11 colors for the X drawing primitives.
6548 In turn, &lt;code&gt;GdkColorContext&lt;/code&gt; came from the port tha…
6549 XmHTML's color context object (and for those that remember, XmHTML
6550 became the first version of GtkHtml; later it was rewritten as a port
6551 of KDE's HTML widget). Thankfully all that stuff is gone now; we can
6552 now assume that video cards are 24-bit RGB or better everywhere, and
6553 there is no need to worry about limited color palettes and color
6554 allocation.&lt;/p&gt;
6555 &lt;p&gt;Later, we started using the Imlib library, from the Enlightenme…
6556 project, as an easy API to load images — the APIs from libungif,
6557 libjpeg, libpng, etc. were not something one really wanted to use
6558 directly — and also to keep images in memory with a uniform
6559 representation. Unfortunately, Imlib's memory management was
6560 peculiar, as it was tied to Enlightenment's model for caching and
6561 rendering loaded/scaled images.&lt;/p&gt;
6562 &lt;p&gt;A bunch of people worked to write GdkPixbuf: it kept Imlib's c…
6563 of a unified representation for image data, and an easy API to load
6564 various image formats. It added support for an alpha channel (we only
6565 had 1-bit masks before), and it put memory management in the hands of
6566 the calling application, in the form of reference counting. GdkPixbuf
6567 obtained some high-quality scaling functions, mainly for use by Eye Of
6568 Gnome (our image viewer) and by applications that just needed scaling
6569 instead of arbitrary transformations.&lt;/p&gt;
6570 &lt;p&gt;Later, we got libart, the first library in GNOME to do antialia…
6571 vector rendering and affine transformations. Libart was more or less
6572 compatible with GdkPixbuf: they both had the same internal
6573 representation for pixel data, but one had to pass the
6574 pixels/width/height/rowstride around by hand.&lt;/p&gt;
6575 &lt;h1&gt;Mea culpa&lt;/h1&gt;
6576 &lt;p&gt;Back then I didn't understand &lt;a href="https://keithp.com/~k…
6577 which is now ubiquitous. The GIMP made the decision to use
6578 non-premultiplied alpha when it introduced layers with transparency,
6579 probably to "avoid losing data" from transparent pixels. GdkPixbuf
6580 follows the same scheme.&lt;/p&gt;
6581 &lt;p&gt;(Now that the GIMP uses GEGL for its internal representation of
6582 images... I have no idea what it does with respect to alpha.)&lt;/p&gt;
6583 &lt;h1&gt;Cairo and afterwards&lt;/h1&gt;
6584 &lt;p&gt;Some time after the libart days, we got Cairo and pixman. Cair…
6585 different representation of images than GdkPixbuf's, and it supported
6586 more pixel formats and color models.&lt;/p&gt;
6587 &lt;p&gt;GTK2 got patched to use Cairo in the toplevel API. We still ha…
6588 dichotomy between Cairo's image surfaces, which are ARGB premultiplied
6589 data in memory, and GdkPixbufs, which are RGBA non-premultiplied.
6590 There are utilities in GTK+ to do these translations, but they are
6591 inconvenient: every time a program loads an image with GdkPixbuf's
6592 easy API, a translation has to happen from non-premul RGBA to premul
6593 ARGB.&lt;/p&gt;
6594 &lt;p&gt;Having two formats means that we inevitably do translations bac…
6595 forth of practically the same data. For example, when one embeds a
6596 JPEG inside an SVG, librsvg will read that JPEG using GdkPixbuf,
6597 translate it to Cairo's representation, composite it with Cairo onto
6598 the final result, and finally translate the whole thing back to a
6599 GdkPixbuf... if someone uses librsvg's legacy APIs to output pixbufs
6600 instead of rendering directly to a Cairo surface.&lt;/p&gt;
6601 &lt;p&gt;Who uses that legacy API? GTK+, of course! GTK+ loads scalabl…
6602 icons with GdkPixbuf's loader API, which dynamically links librsvg at
6603 runtime: in effect, GTK+ doesn't use librsvg directly. And the SVG
6604 pixbuf loader uses the "gimme a pixbuf" API in librsvg.&lt;/p&gt;
6605 &lt;h1&gt;GPUs&lt;/h1&gt;
6606 &lt;p&gt;Then, we got GPUs everywhere. Each GPU has its own preferred p…
6607 format. Image data has to be copied to the GPU at some point.
6608 Cairo's ARGB needs to be translated to the GPU's preferred format and
6609 alignment.&lt;/p&gt;
6610 &lt;h1&gt;Summary so far&lt;/h1&gt;
6611 &lt;ul&gt;
6612 &lt;li&gt;
6613 &lt;p&gt;Libraries that load images from standard formats have different
6614 output formats. Generally they can be coaxed into spitting ARGB or
6615 RGBA, but we don't expect them to support any random representation
6616 that a GPU may want.&lt;/p&gt;
6617 &lt;/li&gt;
6618 &lt;li&gt;
6619 &lt;p&gt;GdkPixbuf uses non-premultiplied RGBA data, always in that orde…
6620 &lt;/li&gt;
6621 &lt;li&gt;
6622 &lt;p&gt;Cairo uses premultiplied ARGB in platform-endian 32-bit chunks:…
6623 each pixel is 0xaarrggbb, then the bytes are shuffled around
6624 depending on whether the platform is little-endian or big-endian.&lt;/…
6625 &lt;/li&gt;
6626 &lt;li&gt;
6627 &lt;p&gt;Cairo internally uses a subset of the formats supported by pixm…
6628 &lt;/li&gt;
6629 &lt;li&gt;
6630 &lt;p&gt;GPUs use whatever they damn well please.&lt;/p&gt;
6631 &lt;/li&gt;
6632 &lt;li&gt;
6633 &lt;p&gt;Hilarity ensues.&lt;/p&gt;
6634 &lt;/li&gt;
6635 &lt;/ul&gt;
6636 &lt;h1&gt;What would we like to do?&lt;/h1&gt;
6637 &lt;p&gt;We would like to reduce the number of translations between image
6638 formats along the loading-processing-display pipeline. Here is a
6639 plan:&lt;/p&gt;
6640 &lt;ul&gt;
6641 &lt;li&gt;
6642 &lt;p&gt;Make sure Cairo/pixman support the image formats that GPUs gene…
6643 prefer. Have them do the necessary conversions if the rest of the
6644 program passes an unsupported format. Ensure that a Cairo image
6645 surface can be created with the GPU's preferred format.&lt;/p&gt;
6646 &lt;/li&gt;
6647 &lt;li&gt;
6648 &lt;p&gt;Make GdkPixbuf just be a wrapper around a Cairo image surface.
6649 &lt;code&gt;GdkPixbuf&lt;/code&gt; is already an opaque structure, and…
6650 to copy pixel data in case the calling code requests it, or wants to
6651 turn a pixbuf from immutable to mutable.&lt;/p&gt;
6652 &lt;/li&gt;
6653 &lt;li&gt;
6654 &lt;p&gt;Provide GdkPixbuf APIs that deal with Cairo image surfaces. For
6655 example, deprecate &lt;code&gt;gdk_pixbuf_new()&lt;/code&gt; and
6656 &lt;code&gt;gdk_pixbuf_new_from_data()&lt;/code&gt;, in favor of a new
6657 &lt;code&gt;gdk_pixbuf_new_from_cairo_image_surface()&lt;/code&gt;. I…
6658 &lt;code&gt;gdk_pixbuf_get_pixels()&lt;/code&gt; and related functions…
6659 &lt;code&gt;gdk_pixbuf_get_cairo_image_surface()&lt;/code&gt;. Mark t…
6660 data" functions as highly discouraged, and only for use really by
6661 applications that want to use GdkPixbuf as an image loader and
6662 little else.&lt;/p&gt;
6663 &lt;/li&gt;
6664 &lt;li&gt;
6665 &lt;p&gt;Remove calls in GTK+ that cause image conversions; make them use
6666 Cairo image surfaces directly, from GdkTexture up.&lt;/p&gt;
6667 &lt;/li&gt;
6668 &lt;li&gt;
6669 &lt;p&gt;Audit applications to remove calls that cause image conversions.
6670 Generally, look for where they use GdkPixbuf's deprecated APIs and
6671 update them.&lt;/p&gt;
6672 &lt;/li&gt;
6673 &lt;/ul&gt;
6674 &lt;h1&gt;Is this really a performance problem?&lt;/h1&gt;
6675 &lt;p&gt;This is in the "&lt;a href="https://people.gnome.org/~federico/…
6676 issues. All those conversions are not really slow (they don't make up
6677 for the biggest part of profiles), but they are nevertheless things
6678 that we could avoid doing. We may get some speedups, but it's
6679 probably more interesting to look at things like power consumption.&lt;/…
6680 &lt;p&gt;Right now I'm seeing this as a cool, minor optimization, but mo…
6681 &lt;strong&gt;a way to gradually modernize our image API&lt;/strong&gt;.…
6682 &lt;p&gt;We seem to change imaging models every N years (X11 -&amp;gt; l…
6683 -&amp;gt; Cairo -&amp;gt; render trees in GPUs -&amp;gt; ???). It is ve…
6684 applications to use different APIs. In the meantime, we can provide a
6685 more linear path for image data, instead of doing unnecessary
6686 conversions everywhere.&lt;/p&gt;
6687 &lt;h1&gt;Code&lt;/h1&gt;
6688 &lt;p&gt;I have a &lt;a href="https://gitlab.gnome.org/federico/gdk-pixb…
6689 gdk-pixbuf&lt;/a&gt;,
6690 which I'll be working on this week. Meanwhile, you may be interested
6691 in the ongoing &lt;a href="https://wiki.gnome.org/Hackfests/Performance2…
6692 generation for GObject interfaces. This is so that you can do&lt;/p&gt;
6693 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
6694 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;interface&l…
6695 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;virtua…
6696 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&…
6697 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
6698 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
6699
6700 &lt;p&gt;and it will generate the appropriate &lt;code&gt;FooIface&lt;/c…
6701 with the C versions of interfaces.&lt;/p&gt;
6702 &lt;p&gt;It turns …&lt;/p&gt;</summary><content type="html">&lt;p&gt;T…
6703 generation for GObject interfaces. This is so that you can do&lt;/p&gt;
6704 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
6705 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;interface&l…
6706 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;virtua…
6707 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&…
6708 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
6709 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
6710
6711 &lt;p&gt;and it will generate the appropriate &lt;code&gt;FooIface&lt;/c…
6712 with the C versions of interfaces.&lt;/p&gt;
6713 &lt;p&gt;It turns out that this can share a lot of code from the existin…
6714 generator for classes: both classes and interfaces are "just virtual
6715 method tables", plus signals and properties, and classes can actually
6716 have per-instance fields and such. I started refactoring the code
6717 generator to allow this.&lt;/p&gt;
6718 &lt;p&gt;I also took a second look at how to present good error messages…
6719 the &lt;code&gt;syn&lt;/code&gt; crate encounters a parse error. I need…
6720 and experiment with this carefully.&lt;/p&gt;
6721 &lt;h2&gt;Back home&lt;/h2&gt;
6722 &lt;p&gt;I'm back home now, jetlagged but very happy that gnome-class is…
6723 more advanced a state than it was before the hackfest. I'm &lt;strong&g…
6724 thankful&lt;/strong&gt; that practically everyone worked on it!&lt;/p&gt;
6725 &lt;p&gt;Also, &lt;strong&gt;thanks&lt;/strong&gt; to Alberto and Natali…
6726 apartment and showing me around Madrid, all while wrangling their
6727 adorable baby Mario. We had a lovely time on Saturday, and ate
6728 excellent food downtown.&lt;/p&gt;
6729 &lt;p&gt;&lt;img alt="Sponsored by the GNOME Foundation" src="https://pe…
6730 &lt;p&gt;&lt;img alt="Hosted by OpenShine" src="https://www.openshine.co…
6731 &lt;p&gt;Philippe &lt;a href="https://gitlab.gnome.org/federico/gnome-cl…
6732 &lt;p&gt;Alberto made the syntax for per-instance &lt;a href="https://gi…
6733 more ergonomic, and then made that code &lt;a href="https://gitlab.gnome…
6734 &lt;p&gt;Martin improved our &lt;a href="https://gitlab.gnome.org/federi…
6735 &lt;code&gt;snake_case&lt;/code&gt; for code generation.&lt;/p&gt;
6736 &lt;p&gt;Daniel added initial support for &lt;a href="https://gitlab.gno…
6737 This is not finished yet …&lt;/p&gt;</summary><content type="html">&lt…
6738 &lt;p&gt;Philippe &lt;a href="https://gitlab.gnome.org/federico/gnome-cl…
6739 &lt;p&gt;Alberto made the syntax for per-instance &lt;a href="https://gi…
6740 more ergonomic, and then made that code &lt;a href="https://gitlab.gnome…
6741 &lt;p&gt;Martin improved our &lt;a href="https://gitlab.gnome.org/federi…
6742 &lt;code&gt;snake_case&lt;/code&gt; for code generation.&lt;/p&gt;
6743 &lt;p&gt;Daniel added initial support for &lt;a href="https://gitlab.gno…
6744 This is not finished yet, but the initial parser and code generation
6745 is done.&lt;/p&gt;
6746 &lt;p&gt;Guillaume turned &lt;a href="https://github.com/gtk-rs/gir"&gt;…
6747 &lt;a href="http://gtk-rs.org/"&gt;gtk-rs&lt;/a&gt;, from a binary into …
6748 us have all the GObject Introspection information for parent classes
6749 at compilation time.&lt;/p&gt;
6750 &lt;p&gt;Antoni has been working on a tricky problem. &lt;a href="https…
6751 bitfields&lt;/a&gt; do not get reconstructed correctly from the
6752 GObject Introspection information — &lt;a href="https://github.com/rus…
6753 bitfields yet&lt;/a&gt;. This has two implications.
6754 First, we lose some of the original struct fields in the generated
6755 bindings. Second, the sizes of the generated structs are not the
6756 same as the original C structs, so &lt;code&gt;g_type_register_static()&…
6757 complains that one is trying to register an invalid class.&lt;/p&gt;
6758 &lt;p&gt;Yesterday we got as far as reading the &lt;a href="http://refsp…
6759 ABI manuals to see what the hell C compilers are supposed to do for
6760 laying out structs with bitfields. Most likely, we will have a
6761 temporary fix in &lt;a href="https://github.com/gtk-rs/gir"&gt;gir&lt;/a…
6762 structs with the same layout as the C ones, with padding in place of
6763 the space for bitfields. Later we can remove this when rustc gets
6764 support for C bitfields.&lt;/p&gt;
6765 &lt;p&gt;I've been working on support for GObject interfaces. The basic
6766 parsing is done; I'm about to refactor the code generation so I can
6767 reuse the parts that fill vtables from classes.&lt;/p&gt;
6768 &lt;p&gt;Yesterday we went to the Madrid Rust Meetup, a regular meeting …
6769 rustaceans here. Martin talked about WebRender; I talked about
6770 refactoring C to port it to Rust, and then Alex talked about Rust's
6771 plans for 2018. Fun times.&lt;/p&gt;
6772 &lt;p&gt;&lt;img alt="Sponsored by the GNOME Foundation" src="https://pe…
6773 &lt;p&gt;&lt;img alt="Hosted by OpenShine" src="https://www.openshine.co…
6774 &lt;p&gt;[arm]: &lt;/p&gt;</content><category term="misc"></category><ca…
6775 The &lt;a href="https://www.openshine.com/"&gt;OpenShine&lt;/a&gt; folks…
6776 seventh floor of a building by the &lt;a href="https://www.openstreetmap…
6777 roundabout&lt;/a&gt;.&lt;/p&gt;
6778 &lt;p&gt;I am very, very thankful that this time everyone seems to be wo…
6779 on developing &lt;a href="https://gitlab.gnome.org/federico/gnome-class"…
6780 The &lt;a href="https://www.openshine.com/"&gt;OpenShine&lt;/a&gt; folks…
6781 seventh floor of a building by the &lt;a href="https://www.openstreetmap…
6782 roundabout&lt;/a&gt;.&lt;/p&gt;
6783 &lt;p&gt;I am very, very thankful that this time everyone seems to be wo…
6784 on developing &lt;a href="https://gitlab.gnome.org/federico/gnome-class"…
6785 more brainpower is definitely welcome — all the indirection, type
6786 conversion, GObject obscurity, and procedural macro shenanigans
6787 definitely take a toll on oneself.&lt;/p&gt;
6788 &lt;h1&gt;Gnome-class internals&lt;/h1&gt;
6789 &lt;p&gt;&lt;img alt="Gnome-class internals on the whiteboard" src="http…
6790 &lt;p&gt;I explained how gnome-class works to the rest of the hackfest
6791 attendees. I've been writing a document on &lt;a href="https://federico…
6792 internals&lt;/a&gt;, so the whiteboard was a whirlwind tour through
6793 it.&lt;/p&gt;
6794 &lt;h1&gt;Error messages from the compiler&lt;/h1&gt;
6795 &lt;p&gt;Antoni Boucher, the author of &lt;a href="http://relm.ml/"&gt;r…
6796 asynchronous widgets with an Elm-like model), explained to me how relm
6797 manages to present good error messages from the Rust compiler, when
6798 the user's code has mistakes. Right now this is in a very bad state
6799 in gnome-class: user errors within the invocation of the procedural
6800 macro get shown by the compiler as errors &lt;em&gt;at&lt;/em&gt; the ma…
6801 don't get line number information that is meaningful.&lt;/p&gt;
6802 &lt;p&gt;For a large part of the day we tried to refactor bits of gnome-…
6803 to do something similar. It is very slightly better now, but this
6804 really requires me to sit down calmly, at home, and to fully
6805 understand how relm does it and what changes are needed in the &lt;a hre…
6806 parser crate to make it easy to present good errors.&lt;/p&gt;
6807 &lt;p&gt;I think I'll continue this work at home, as there is a lot of s…
6808 code to understand: the combinator parsers in &lt;a href="https://githu…
6809 handling scheme in &lt;a href="http://relm.ml/"&gt;relm&lt;/a&gt;, and t…
6810 &lt;h1&gt;Further work during the hackfest&lt;/h1&gt;
6811 &lt;p&gt;Other people working on gnome-class are adding support for GObj…
6812 properties, inheritance from non-Rust classes, and improving the
6813 ergonomics of class-private structures.&lt;/p&gt;
6814 &lt;p&gt;I think I'll stop working on error messages for now, and focus …
6815 on either supporting GTypeInterfaces, or completing support for type
6816 conversions for methods and signals.&lt;/p&gt;
6817 &lt;h1&gt;Other happenings in Rust&lt;/h1&gt;
6818 &lt;p&gt;Paolo Borelli has been &lt;a href="https://gitlab.gnome.org/GNO…
6819 This is the big structure that holds all the CSS state for SVG
6820 elements. This is very meticulous work, and I'm thankful that Paolo
6821 is paying good attention to it. Soon we will have all the style
6822 machinery for librsvg in Rust, which will make it easier to use the
6823 &lt;a href="https://crates.io/crates/selectors"&gt;selectors crate from …
6824 latter is unmaintained.&lt;/p&gt;
6825 &lt;h1&gt;Food&lt;/h1&gt;
6826 &lt;p&gt;&lt;img alt="Food in Madrid" src="https://people.gnome.org/~fed…
6827 &lt;p&gt;Ah, Spanish food. We have been enjoying cheese, jamón, tortil…
6828 pimientos, oxtail stews, natillas, café con leche...&lt;/p&gt;
6829 &lt;h1&gt;Thanks&lt;/h1&gt;
6830 &lt;p&gt;Thanks to &lt;a href="https://www.openshine.com/"&gt;OpenShine&…
6831 Foundation for sponsoring my travel. And thanks for Alberto Ruiz for
6832 putting me up in his house!&lt;/p&gt;
6833 &lt;p&gt;&lt;img alt="Sponsored by the GNOME Foundation" src="https://pe…
6834 properties from C to Rust. Many properties have symbolic values:&lt;/p&…
6835 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
6836
6837 stroke-linecap: butt | round | square | inherit
6838
6839 fill-rule: nonzero | evenodd | inherit
6840 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
6841
6842 &lt;p&gt;&lt;code&gt;StrokeLinejoin&lt;/code&gt; is the first property t…
6843 write a …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I have star…
6844 properties from C to Rust. Many properties have symbolic values:&lt;/p&…
6845 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
6846
6847 stroke-linecap: butt | round | square | inherit
6848
6849 fill-rule: nonzero | evenodd | inherit
6850 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
6851
6852 &lt;p&gt;&lt;code&gt;StrokeLinejoin&lt;/code&gt; is the first property t…
6853 write a little bunch of machinery to allow CSS properties to be kept
6854 in Rust-space instead of the main C structure that holds them
6855 (upcoming blog post about that). But for now, I just want to show how
6856 this boiled down to a macro after refactoring.&lt;/p&gt;
6857 &lt;h1&gt;First cut at the code&lt;/h1&gt;
6858 &lt;p&gt;The &lt;code&gt;stroke-linejoin&lt;/code&gt; property can have …
6859 &lt;code&gt;bevel&lt;/code&gt;, or &lt;code&gt;inherit&lt;/code&gt;. He…
6860 and the conventional machinery which librsvg uses to parse property valu…
6861 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
6862 &lt;span class="k"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&g…
6863 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Miter&lt;/s…
6864 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Round&lt;/s…
6865 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Bevel&lt;/s…
6866 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Inherit&lt;…
6867 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
6868
6869 &lt;span class="k"&gt;impl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&…
6870 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;type&lt;/sp…
6871 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;type&lt;/sp…
6872
6873 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span…
6874 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;match&l…
6875 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&am…
6876 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&am…
6877 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&am…
6878 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&am…
6879 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;_&l…
6880 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/s…
6881 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&…
6882 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
6883 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
6884
6885 &lt;p&gt;We &lt;code&gt;match&lt;/code&gt; the allowed string values and…
6886 big deal, right?&lt;/p&gt;
6887 &lt;p&gt;Properties also have a default value. For example, the SVG spe…
6888 that if a shape doesn't have a &lt;code&gt;stroke-linejoin&lt;/code&gt; …
6889 it will use &lt;code&gt;miter&lt;/code&gt; by default. Let's implement …
6890 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
6891 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span…
6892 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;StrokeL…
6893 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&…
6894 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
6895 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
6896
6897 &lt;p&gt;So far, we have three things:&lt;/p&gt;
6898 &lt;ul&gt;
6899 &lt;li&gt;An enum definition for the property's possible values.&lt;/li&…
6900 &lt;li&gt;&lt;code&gt;impl Parse&lt;/code&gt; so we can parse the proper…
6901 &lt;li&gt;&lt;code&gt;impl Default&lt;/code&gt; so the property knows it…
6902 &lt;/ul&gt;
6903 &lt;h1&gt;Where things got repetitive&lt;/h1&gt;
6904 &lt;p&gt;The next property I ported was &lt;code&gt;stroke-linecap&lt;/c…
6905 following values:&lt;/p&gt;
6906 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
6907 &lt;span class="k"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&g…
6908 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Butt&lt;/sp…
6909 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Round&lt;/s…
6910 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Square&lt;/…
6911 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Inherit&lt;…
6912 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
6913 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
6914
6915 &lt;p&gt;This is similar in shape to the &lt;code&gt;StrokeLinejoin&lt;/…
6916 it's just different names.&lt;/p&gt;
6917 &lt;p&gt;The parsing has exactly the same shape, and just different valu…
6918 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
6919 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;type&lt;/sp…
6920 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;type&lt;/sp…
6921
6922 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span…
6923 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;match&l…
6924 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&am…
6925 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&am…
6926 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&am…
6927 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&am…
6928
6929 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;_&l…
6930 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/s…
6931 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&…
6932 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
6933 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
6934
6935 &lt;p&gt;Same thing with the default:&lt;/p&gt;
6936 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
6937 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span…
6938 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;StrokeL…
6939 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&…
6940 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
6941 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
6942
6943 &lt;p&gt;Yes, the SVG spec has&lt;/p&gt;
6944 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
6945 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
6946
6947 &lt;p&gt;somewhere in it, much to the delight of the 12-year old in me.&…
6948 &lt;h1&gt;Refactoring to a macro&lt;/h1&gt;
6949 &lt;p&gt;Here I wanted to define a &lt;code&gt;make_ident_property!()&lt…
6950 get invoked like this:&lt;/p&gt;
6951 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
6952 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;StrokeLinej…
6953 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;default&lt;…
6954
6955 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;m…
6956 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;r…
6957 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;b…
6958 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;i…
6959 &lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
6960 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
6961
6962 &lt;p&gt;It's called &lt;code&gt;make_ident_property&lt;/code&gt; becaus…
6963 definition from simple string identifiers. It has the name of the
6964 property (&lt;code&gt;StrokeLinejoin&lt;/code&gt;), a &lt;code&gt;defaul…
6965 elements, one for each possible value.&lt;/p&gt;
6966 &lt;p&gt;In Rust-speak, the macro's basic pattern is like this:&lt;/p&gt;
6967 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
6968 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&…
6969 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;default&lt…
6970 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cp"&gt;$($str_pr…
6971 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&…
6972 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;..&lt;/…
6973 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span…
6974 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
6975 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
6976
6977 &lt;p&gt;Let's dissect that pattern:&lt;/p&gt;
6978 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
6979 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&…
6980 &lt;span class="c1"&gt;// ^^^^^^^^^^^^ will match an identifier and pu…
6981
6982 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;default&lt…
6983 &lt;span class="c1"&gt;// ^^^^^^^^^^^^^^^ will match an ident…
6984 &lt;span class="c1"&gt;// ^^^^^^^^ arbitrary text&lt;/span&gt;
6985
6986 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cp"&gt;$($str_pr…
6987 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class…
6988 &lt;span class="c1"&gt;// ^^ start of repetition ^^ end …
6989
6990 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&…
6991 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;..&lt;/…
6992 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span…
6993 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
6994 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
6995
6996 &lt;p&gt;For example, saying "&lt;code&gt;$foo: ident&lt;/code&gt;" in a…
6997 compiler will expect an identifier, and bind it to &lt;code&gt;$foo&lt;/…
6998 macro's definition.&lt;/p&gt;
6999 &lt;p&gt;Similarly, an &lt;code&gt;expr&lt;/code&gt; means that the comp…
7000 look for an expression — in this case, we want one of the string
7001 values.&lt;/p&gt;
7002 &lt;p&gt;In a macro pattern, anything that is not a binding is just arbi…
7003 text which must appear in the macro's invocation. This is how we can
7004 create a little syntax of our own within the macro: the "&lt;code&gt;de…
7005 part, and the "&lt;code&gt;=&amp;gt;&lt;/code&gt;" inside each string/sy…
7006 &lt;p&gt;Finally, macro patterns allow repetition. Anything within &lt;…
7007 indicates repetition. Here, &lt;code&gt;$(...)+&lt;/code&gt; indicates …
7008 compiler must match one or more of the repeating elements.&lt;/p&gt;
7009 &lt;p&gt;I pasted the duplicated code, and substituted the actual symbol…
7010 for the macro's bindings:&lt;/p&gt;
7011 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
7012 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&…
7013 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;default&lt…
7014 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cp"&gt;$($str_pr…
7015 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&…
7016 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cp"&gt;#[deri…
7017 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;pub&lt;…
7018 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cp"&gt;$(…
7019 &lt;span class="c1"&gt;// ^^^^^^^^^^^^^ this is how we invoke a…
7020
7021 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/s…
7022
7023 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;impl&lt…
7024 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;fn&…
7025 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cp"&g…
7026 &lt;span class="c1"&gt;// ^^^^^^^^^^^^^^^ construct an enum…
7027
7028 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&l…
7029 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/s…
7030
7031 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;impl&lt…
7032 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;typ…
7033 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;typ…
7034
7035 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;fn&…
7036 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt…
7037 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c…
7038 &lt;span class="c1"&gt;// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^…
7039
7040 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n…
7041 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt…
7042 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&l…
7043 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/s…
7044 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span…
7045 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
7046 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
7047
7048 &lt;h1&gt;Getting rid of duplicated code&lt;/h1&gt;
7049 &lt;p&gt;Now we have a macro that we can call to define new properties.
7050 Librsvg now has this, which is much more readable than all the code
7051 written by hand:&lt;/p&gt;
7052 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
7053 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;StrokeLinej…
7054 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;default&lt;…
7055
7056 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;m…
7057 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;r…
7058 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;b…
7059 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;i…
7060 &lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
7061
7062 &lt;span class="n"&gt;make_ident_property&lt;/span&gt;&lt;span class="o"…
7063 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;StrokeLinec…
7064 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;default&lt;…
7065
7066 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;b…
7067 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;r…
7068 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;s…
7069 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;i…
7070 &lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
7071
7072 &lt;span class="n"&gt;make_ident_property&lt;/span&gt;&lt;span class="o"…
7073 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FillRule&lt…
7074 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;default&lt;…
7075
7076 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;n…
7077 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;e…
7078 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;i…
7079 &lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
7080 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
7081
7082 &lt;p&gt;Etcetera. It's now easy to port similar symbol-based propertie…
7083 C to Rust.&lt;/p&gt;
7084 &lt;p&gt;Eventually I'll need to refactor all the crap that deals with
7085 inheritable properties, but that's for another time.&lt;/p&gt;
7086 &lt;h1&gt;Conclusion and references&lt;/h1&gt;
7087 &lt;p&gt;Rust macros are very powerful to refactor repetitive code like …
7088 &lt;p&gt;&lt;a href="https://doc.rust-lang.org/book/second-edition/appen…
7089 has an introductory appendix to macros, and &lt;a href="https://danielke…
7090 Macros&lt;/a&gt; is a
7091 fantastic resource that really dives into what you can do.&lt;/p&gt;</co…
7092 push some commits, the CI pipelines build the code and presumably run
7093 the test suite, and later you can know if this succeeded of failed.&lt;/…
7094 &lt;p&gt;But by the time something fails, the broken code is already in …
7095 public repository.&lt;/p&gt;
7096 &lt;p&gt;The …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Gitlab…
7097 push some commits, the CI pipelines build the code and presumably run
7098 the test suite, and later you can know if this succeeded of failed.&lt;/…
7099 &lt;p&gt;But by the time something fails, the broken code is already in …
7100 public repository.&lt;/p&gt;
7101 &lt;p&gt;The Rust community uses Bors, a bot that prevents this from hap…
7102 &lt;ul&gt;
7103 &lt;li&gt;
7104 &lt;p&gt;You push some commits and submit a merge request.&lt;/p&gt;
7105 &lt;/li&gt;
7106 &lt;li&gt;
7107 &lt;p&gt;A human looks at your merge request; they may tell you to make
7108 changes, or they may tell Bors that your request is approved for
7109 merging.&lt;/p&gt;
7110 &lt;/li&gt;
7111 &lt;li&gt;
7112 &lt;p&gt;Bors looks for approved merge requests. It merges each into a
7113 &lt;em&gt;temporary branch&lt;/em&gt; and waits for the CI pipeline to…
7114 CI passes, Bors automatically merges to master. If CI fails, Bors
7115 annotates the merge request with the failure, &lt;strong&gt;and the ma…
7116 repository stays working&lt;/strong&gt;.&lt;/p&gt;
7117 &lt;/li&gt;
7118 &lt;/ul&gt;
7119 &lt;p&gt;Bors also tells you if the mainline has moved forward and there…
7120 merge conflict. In that case you need to do a rebase yourself; the
7121 repository stays working in the meantime.&lt;/p&gt;
7122 &lt;p&gt;This leads to a very fair, very transparent process for contrib…
7123 and for maintainers. For all the details, watch &lt;a href="https://www…
7124 presentation on Rust's community
7125 automation&lt;/a&gt;
7126 (&lt;a href="http://edunham.net/2016/09/27/rust_s_community_automation.h…
7127 &lt;p&gt;For a description of where Bors came from, read &lt;a href="htt…
7128 blog&lt;/a&gt;.&lt;/p&gt;
7129 &lt;p&gt;&lt;a href="https://github.com/graydon/bors"&gt;Bors&lt;/a&gt; …
7130 &lt;a href="https://github.com/servo/homu"&gt;Homu&lt;/a&gt; and it is w…
7131 use currently. However, Homu depends on Github.&lt;/p&gt;
7132 &lt;p&gt;I just found out that there is a &lt;a href="https://github.com…
7133 Gitlab&lt;/a&gt;. Would anyone care
7134 to set it up?&lt;/p&gt;
7135 &lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; &lt;a href="https://a.weir…
7136 &lt;a href="https://octodon.social/@graydon/99719514193737493"&gt;people…
7137 suggested porting &lt;a href="https://bors.tech/"&gt;Bors-ng&lt;/a&gt; t…
7138 &lt;a href="https://a.weirder.earth/@bb010g/99719537971696863"&gt;for sc…
7139 reasons&lt;/a&gt;.&lt;/p&gt;</content><category term="misc"></category><…
7140 Summer, both for &lt;a href="https://www.outreachy.org/"&gt;Outreachy&lt…
7141 &lt;h1&gt;Librsvg projects&lt;/h1&gt;
7142 &lt;p&gt;&lt;strong&gt;&lt;em&gt;Project:&lt;/em&gt;&lt;/strong&gt; &lt;…
7143 &lt;p&gt;Currently librsvg implements SVG filter effects in C. These ar…
7144 image processing filters like Gaussian blur, matrix convolution,
7145 Porter-Duff alpha …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I…
7146 Summer, both for &lt;a href="https://www.outreachy.org/"&gt;Outreachy&lt…
7147 &lt;h1&gt;Librsvg projects&lt;/h1&gt;
7148 &lt;p&gt;&lt;strong&gt;&lt;em&gt;Project:&lt;/em&gt;&lt;/strong&gt; &lt;…
7149 &lt;p&gt;Currently librsvg implements SVG filter effects in C. These ar…
7150 image processing filters like Gaussian blur, matrix convolution,
7151 Porter-Duff alpha compositing, etc.&lt;/p&gt;
7152 &lt;p&gt;There are &lt;a href="https://gitlab.gnome.org/GNOME/librsvg/mi…
7153 &lt;ul&gt;
7154 &lt;li&gt;
7155 &lt;p&gt;Split the single &lt;code&gt;rsvg-filter.c&lt;/code&gt; into mu…
7156 easier to port each one individually.&lt;/p&gt;
7157 &lt;/li&gt;
7158 &lt;li&gt;
7159 &lt;p&gt;Figure out the common infrasctructure: &lt;code&gt;RsvgFilter&l…
7160 &lt;code&gt;RsvgFilterPrimitive&lt;/code&gt;. All the filter use thes…
7161 intermediate results when processing SVG elements.&lt;/p&gt;
7162 &lt;/li&gt;
7163 &lt;li&gt;
7164 &lt;p&gt;Experiment with the correct Rust abstractions to process images
7165 pixel-by-pixel. We would like to omit per-pixel bounds checks on
7166 array accesses. The &lt;a href="https://crates.io/crates/image"&gt;im…
7167 traits for pixels. WebKit's implementation of SVG filters also has
7168 interesting abstractions for things like the need for a sliding
7169 window with edge handling for Gaussian blurs.&lt;/p&gt;
7170 &lt;/li&gt;
7171 &lt;li&gt;
7172 &lt;p&gt;Ensure that our current filters code is actually working. Not …
7173 of the official SVG test suite's tests are in place right now for
7174 the filter effects; it is likely that some of our implementation is
7175 broken.&lt;/p&gt;
7176 &lt;/li&gt;
7177 &lt;/ul&gt;
7178 &lt;p&gt;For this project, it will be especially helpful to have a little
7179 background in image processing. You don't need to be an expert; just
7180 to have done some pixel crunching at some point. You need to be able
7181 to read C and write Rust.&lt;/p&gt;
7182 &lt;p&gt;&lt;strong&gt;&lt;em&gt;Project:&lt;/em&gt;&lt;/strong&gt; &lt;…
7183 &lt;p&gt;Librsvg uses an very simplistic algorithm for CSS cascading. I…
7184 libcroco to parse CSS style data; libcroco is unmaintained and rather
7185 prone to exploits. I want to use Servo's selectors crate to do the
7186 cascading; we already use the rust-cssparser crate as a tokenizer for
7187 basic CSS properties.&lt;/p&gt;
7188 &lt;ul&gt;
7189 &lt;li&gt;
7190 &lt;p&gt;For each node in its DOM tree, librsvg's &lt;code&gt;Node&lt;/c…
7191 &lt;code&gt;Vec&amp;lt;&amp;gt;&lt;/code&gt; of children. &lt;a href=…
7192 sibling and the first/last children instead&lt;/a&gt;. This is the
7193 data structure that rust-selectors prefers. The Kuchiki crate has
7194 an example implementation; borrowing some patterns from there could
7195 also help us simplify our reference counting for nodes.&lt;/p&gt;
7196 &lt;/li&gt;
7197 &lt;li&gt;
7198 &lt;p&gt;&lt;a href="https://gitlab.gnome.org/GNOME/librsvg/issues/223"&…
7199 big &lt;code&gt;RsvgState&lt;/code&gt; struct which holds the CSS stat…
7200 is easy to port this to Rust; it's more interesting to gradually
7201 move it to a scheme like Servo's, with a distinction between
7202 specified/computed/used values for each CSS property.&lt;/p&gt;
7203 &lt;/li&gt;
7204 &lt;/ul&gt;
7205 &lt;p&gt;For this project, it will be helpful to know a bit of how CSS w…
7206 Definitely be comfortable with Rust concepts like ownership and
7207 borrowing. You don't need to be an expert, but if you are going
7208 through the "fighting the borrow checker" stage, you'll have a harder
7209 time with this. Or it may be what lets you grow out of it! You need
7210 to be able to read C and write Rust.&lt;/p&gt;
7211 &lt;p&gt;&lt;strong&gt;&lt;em&gt;Bugs for newcomers:&lt;/em&gt;&lt;/stro…
7212 to librsvg&lt;/a&gt;. Some of these are in the Rust part, some
7213 in the C part, some in both &amp;mdash; take your pick!&lt;/p&gt;
7214 &lt;h1&gt;Projects for gnome-class&lt;/h1&gt;
7215 &lt;p&gt;&lt;a href="https://gitlab.gnome.org/federico/gnome-class"&gt;G…
7216 GObject implementations in Rust. Or at least that's the intention
7217 &amp;mdash; the project is in early development. The code is so new that
7218 &lt;a href="https://gitlab.gnome.org/federico/gnome-class/issues"&gt;pra…
7219 nature.&lt;/p&gt;
7220 &lt;p&gt;Gnome-class works like a little compiler. This is from one of …
7221 examples; note the call to &lt;code&gt;gobject_gen!&lt;/code&gt; in ther…
7222 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
7223 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;val&lt;/spa…
7224 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
7225
7226 &lt;span class="k"&gt;impl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&…
7227 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span…
7228 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Signale…
7229 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;val…
7230 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/s…
7231 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&…
7232 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
7233
7234 &lt;span class="n"&gt;gobject_gen&lt;/span&gt;&lt;span class="o"&gt;!&lt…
7235 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;class&lt;/s…
7236 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;type&lt…
7237 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&…
7238
7239 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;impl&lt;/sp…
7240 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;signal&…
7241
7242 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/…
7243 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;le…
7244 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pri…
7245 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="bp"&gt;se…
7246 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/s…
7247 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&…
7248 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
7249 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
7250
7251 &lt;p&gt;Gnome-class implements this &lt;code&gt;gobject_gen!&lt;/code&g…
7252 &lt;ol&gt;
7253 &lt;li&gt;
7254 &lt;p&gt;First we parse the code inside the macro using the &lt;code&gt;…
7255 This is a crate that lets you parse Rust source code from the
7256 &lt;code&gt;TokenStream&lt;/code&gt; that the compiler hands to implemen…
7257 macros. You give a &lt;code&gt;TokenStream&lt;/code&gt; to &lt;code&gt;…
7258 structs that represent function definitions, &lt;code&gt;impl&lt;/code&g…
7259 expressions, etc. From this parsing stage we build an Abstract Syntax
7260 Tree (AST) that closely matches the structure of the code that the
7261 user wrote.&lt;/p&gt;
7262 &lt;/li&gt;
7263 &lt;li&gt;
7264 &lt;p&gt;Second, we take the AST and convert it to higher-level concepts,
7265 while verifying that the code is semantically valid. For example, we
7266 build up a &lt;code&gt;Class&lt;/code&gt; structure for each defined GOb…
7267 annotate it with the methods and signals that the user defined for it.
7268 This stage is the High-level Internal Representation (HIR).&lt;/p&gt;
7269 &lt;/li&gt;
7270 &lt;li&gt;
7271 &lt;p&gt;Third, we generate Rust code from the validated HIR. For each
7272 class, we write out the boilerplate needed to register it against the
7273 GObject type system. For each virtual method we write a trampoline to
7274 let the C code call into the Rust implementation, and then write out
7275 the actual Rust impl that the user wrote. For each signal, we
7276 register it against the GObjectClass, and write the appropriate
7277 trampolines both to invoke the signal's default handler and any Rust
7278 callbacks for signal handlers.&lt;/p&gt;
7279 &lt;/li&gt;
7280 &lt;/ol&gt;
7281 &lt;p&gt;For this project, you definitely need to have written GObject c…
7282 C in the past. You don't need to know the GObject internals; just
7283 know that there are things like type registration, signal creation,
7284 argument marshalling, etc.&lt;/p&gt;
7285 &lt;p&gt;You don't need to know about compiler internals.&lt;/p&gt;
7286 &lt;p&gt;You don't need to have written Rust procedural macros; you can …
7287 as you go. The code has enough infrastructure right now that you can
7288 cut&amp;amp;paste useful bits to get started with new features. You sho…
7289 definitely be comfortable with the Rust borrow checker and simple
7290 lifetimes &amp;mdash; again, you can cut&amp;amp;paste useful code alrea…
7291 I'm happy to help with those.&lt;/p&gt;
7292 &lt;p&gt;This project demands a little patience. Working on the impleme…
7293 of procedural macros is not the smoothest experience right now (one
7294 needs to examine generated code carefully, and play some tricks with
7295 the compiler to debug things), but it's getting better very fast.&lt;/p&…
7296 &lt;h1&gt;How to apply as an intern&lt;/h1&gt;
7297 &lt;p&gt;&lt;a href="https://www.outreachy.org/apply/"&gt;Details for Ou…
7298 &lt;p&gt;&lt;a href="https://wiki.gnome.org/Outreach/SummerOfCode/Studen…
7299 in GNOME, and in particular, it's what librsvg uses to render all
7300 SVGs.&lt;/p&gt;
7301 &lt;p&gt;My immediate problem with Cairo is that it explodes when called…
7302 floating-point coordinates that fall outside the range that its
7303 internal fixed-point numbers can …&lt;/p&gt;</summary><content type="h…
7304 in GNOME, and in particular, it's what librsvg uses to render all
7305 SVGs.&lt;/p&gt;
7306 &lt;p&gt;My immediate problem with Cairo is that it explodes when called…
7307 floating-point coordinates that fall outside the range that its
7308 internal fixed-point numbers can represent. There is no validation of
7309 incoming data, so the polygon intersector ends up with data that makes
7310 no sense, and it crashes.&lt;/p&gt;
7311 &lt;p&gt;I've been studying how Cairo converts from floating-point to its
7312 fixed-point representation, and it's a nifty little algorithm. So I
7313 thought, no problem, I'll add validation, see how to represent the
7314 error state internally in Cairo, and see if clients are happy with
7315 getting back a &lt;code&gt;cairo_t&lt;/code&gt; in an error state.&lt;/p…
7316 &lt;p&gt;Cairo has a very thorough test suite... &lt;strong&gt;&lt;em&gt…
7317 is documented to be very hard to pass fully for all rendering
7318 backends. This is understandable, as there may be bugs in X servers
7319 or OpenGL implementations and such. But for the basic, software-only,
7320 in-memory image backend, Cairo should 100% pass its test suite all the
7321 time. This is not the case right now; in my tree, for all the tests
7322 of the image backend I get&lt;/p&gt;
7323 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
7324 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
7325
7326 &lt;p&gt;I have been looking at test failures to see what needs fixing. …
7327 reference images just need to be regenerated: there have been minor
7328 changes in font rendering that broke the reference tests. Some
7329 others have small differences in rendering gradients - not noticeable
7330 by eye, just by diff tools.&lt;/p&gt;
7331 &lt;p&gt;But some tests, I have no idea what changed that made them brea…
7332 &lt;p&gt;Cairo's git repository is accessible through [cgit.freedesktop.…
7333 As far as I know there is no continuous integration infrastructure to
7334 ensure that tests keep passing.&lt;/p&gt;
7335 &lt;h1&gt;Adding minimal continuous testing&lt;/h1&gt;
7336 &lt;p&gt;I've set up a &lt;a href="https://gitlab.com/federicomenaquinte…
7337 already has a &lt;a href="https://bugs.freedesktop.org/show_bug.cgi?id=1…
7338 invalid &lt;code&gt;free()&lt;/code&gt;&lt;/a&gt;, and some regenerated …
7339 &lt;p&gt;The repository &lt;a href="https://gitlab.com/federicomenaquint…
7340 pipeline&lt;/a&gt; on every commit. The test artifacts can then be
7341 downloaded when the test suite fails. Right now it is only testing
7342 the image backend, for in-memory software rendering.&lt;/p&gt;
7343 &lt;h1&gt;Initial bugs&lt;/h1&gt;
7344 &lt;p&gt;I've started reporting &lt;a href="https://gitlab.com/federicom…
7345 tests that fail. These should really be in Cairo's Bugzilla, but for
7346 now Gitlab makes it much easier to include test images directly in the
7347 bug descriptions, so that they are easier to browse. Read on.&lt;/p&gt;
7348 &lt;h1&gt;Would you like to help?&lt;/h1&gt;
7349 &lt;p&gt;A lot of projects use Cairo. We owe it to ourselves to have a …
7350 with a test suite that doesn't break. Getting to that point requires
7351 several things:&lt;/p&gt;
7352 &lt;ul&gt;
7353 &lt;li&gt;Fixing current failures in the image backend.&lt;/li&gt;
7354 &lt;li&gt;Setting up the CI infrastructure to be able to test other back…
7355 &lt;li&gt;Fixing failures in the other backends.&lt;/li&gt;
7356 &lt;/ul&gt;
7357 &lt;p&gt;If you have experience with Cairo, please take a look at the &l…
7358 You can see the &lt;a href="https://gitlab.com/federicomenaquintero/cair…
7359 suite in the same fashion on your machine.&lt;/p&gt;
7360 &lt;p&gt;I think we can make use of modern infrastructure like gitlab and
7361 continuous integration to improve Cairo quickly. Currently it suffers
7362 from lack of attention and hostile tools. Help us out if you can!&lt;/p…
7363 version 0.12. &lt;code&gt;syn&lt;/code&gt; is a somewhat esoteric crate…
7364 parse Rust code... from a stream of tokens... from within the
7365 implementation of a procedural macro. Gnome-class implements a
7366 mini-language inside your own Rust …&lt;/p&gt;</summary><content type=…
7367 version 0.12. &lt;code&gt;syn&lt;/code&gt; is a somewhat esoteric crate…
7368 parse Rust code... from a stream of tokens... from within the
7369 implementation of a procedural macro. Gnome-class implements a
7370 mini-language inside your own Rust code, and so it needs to parse
7371 Rust!&lt;/p&gt;
7372 &lt;p&gt;The API of &lt;code&gt;syn&lt;/code&gt; has changed &lt;em&gt;a…
7373 ass — but the new API seems on the road to stabilization, and is nicer
7374 indeed.&lt;/p&gt;
7375 &lt;p&gt;Here is a quick list of things I had to change in gnome-class to
7376 upgrade its version of &lt;code&gt;syn&lt;/code&gt;.&lt;/p&gt;
7377 &lt;p&gt;There is no &lt;code&gt;extern crate synom&lt;/code&gt; anymore…
7378 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
7379 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
7380
7381 &lt;p&gt;&lt;code&gt;SynomBuffer&lt;/code&gt; is now &lt;code&gt;TokenBu…
7382 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
7383 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
7384
7385 &lt;p&gt;&lt;code&gt;PResult&lt;/code&gt;, the result of &lt;code&gt;Syn…
7386 arguments reversed:&lt;/p&gt;
7387 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
7388 &lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;…
7389
7390 &lt;span class="c1"&gt;// therefore:&lt;/span&gt;
7391
7392 &lt;span class="k"&gt;impl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&…
7393
7394 &lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&…
7395 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
7396
7397 &lt;p&gt;The language tokens like &lt;code&gt;synom::tokens::Amp&lt;/cod…
7398 &lt;code&gt;synom::tokens::Type&lt;/code&gt;, are easier to use now. Th…
7399 macro which you can use in type definitions, instead of having to
7400 remember the particular name of each token type:&lt;/p&gt;
7401 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
7402
7403 &lt;span class="n"&gt;synom&lt;/span&gt;::&lt;span class="n"&gt;tokens&l…
7404 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
7405
7406 &lt;p&gt;And for the corresponding values when matching:&lt;/p&gt;
7407 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
7408
7409 &lt;span class="n"&gt;syn&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&g…
7410 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
7411
7412 &lt;p&gt;And to instantiate them for quoting/spanning:&lt;/p&gt;
7413 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
7414 &lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span…
7415 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
7416
7417 &lt;p&gt;(OK, that one wasn't nicer after all.)&lt;/p&gt;
7418 &lt;p&gt;To the get string for an &lt;code&gt;Ident&lt;/code&gt;:&lt;/p&…
7419 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
7420 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
7421
7422 &lt;p&gt;There is no &lt;code&gt;Delimited&lt;/code&gt; anymore; instead…
7423 struct. My diff has this:&lt;/p&gt;
7424 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
7425 + inputs: parens!(syn!(Punctuated&amp;lt;MyThing, Token!(,)&amp;gt;)) &…
7426 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
7427
7428 &lt;p&gt;There is no &lt;code&gt;syn::Mutability&lt;/code&gt; anymore; n…
7429 basically&lt;/p&gt;
7430 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
7431 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
7432
7433 &lt;p&gt;which I guess lets you refer to the span of the original &lt;co…
7434 if you need.&lt;/p&gt;
7435 &lt;p&gt;Some things changed names:&lt;/p&gt;
7436 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
7437
7438 &lt;span class="n"&gt;PatIdent&lt;/span&gt;&lt;span class="w"&gt; &lt;/s…
7439 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mode&lt;/sp…
7440 &lt;span class="w"&gt; &lt;/s…
7441 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ident&lt;/s…
7442 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;subpat&lt;/…
7443 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;at_token&lt…
7444 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
7445
7446 &lt;span class="n"&gt;TypeParen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/…
7447 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
7448
7449 &lt;p&gt;(I don't know everything that changed names; gnome-class doesn'…
7450 all the syn types yet; these are just the ones I've run into.)&lt;/p&gt;
7451 &lt;p&gt;This new &lt;code&gt;syn&lt;/code&gt; is much better at acknowl…
7452 macro hygiene. The &lt;a href="https://github.com/dtolnay/syn/tree/mast…
7453 it shows how to properly span generated code vs. original code, so
7454 compiler error messages are nice. I &lt;a href="https://github.com/rust…
7455 macro hygiene&lt;/a&gt; at some point.&lt;/p&gt;</content><category term…
7456 librsvg's continous integration (CI) pipeline. Take a look at this
7457 beauty:&lt;/p&gt;
7458 &lt;p&gt;&lt;img alt="Continuous integration pipeline" src="https://peop…
7459 &lt;p&gt;On every push, we run the &lt;strong&gt;Test&lt;/strong&gt; sta…
7460 on a Fedora container that runs "&lt;code&gt;make check&lt;/code&gt;" an…
7461 test suite passes.&lt;/p&gt;
7462 &lt;p&gt;We have a …&lt;/p&gt;</summary><content type="html">&lt;p&gt;…
7463 librsvg's continous integration (CI) pipeline. Take a look at this
7464 beauty:&lt;/p&gt;
7465 &lt;p&gt;&lt;img alt="Continuous integration pipeline" src="https://peop…
7466 &lt;p&gt;On every push, we run the &lt;strong&gt;Test&lt;/strong&gt; sta…
7467 on a Fedora container that runs "&lt;code&gt;make check&lt;/code&gt;" an…
7468 test suite passes.&lt;/p&gt;
7469 &lt;p&gt;We have a &lt;strong&gt;Lint&lt;/strong&gt; stage which can be …
7470 clippy&lt;/code&gt; to get Rust lints (check the style of Rust idioms), …
7471 fmt&lt;/code&gt; to check indentation and code style and such.&lt;/p&gt;
7472 &lt;p&gt;We have a &lt;strong&gt;Distro_test&lt;/strong&gt; stage which …
7473 weekly, using Gitlab's &lt;em&gt;Schedules&lt;/em&gt; feature, to check …
7474 pass on three major Linux distros. Recently we had trouble with
7475 different rendering due to differences in Freetype versions, which
7476 broke the tests (&lt;em&gt;ahem, likely because &lt;/em&gt;&lt;em&gt;I&l…
7477 Freetype in a while and distros were already using a newer one&lt;/em&gt…
7478 distro tests are intended to catch that.&lt;/p&gt;
7479 &lt;p&gt;Finally, we have a &lt;strong&gt;Rustc_test&lt;/strong&gt; stag…
7480 librsvg depends on have different minimum versions for the Rust
7481 compiler. These tests are intended to show when updating a dependency
7482 changes the minimum Rust version on which librsvg would compile. We
7483 don't have a policy yet for "how far from $newest" we should always
7484 work on, and it would be good to get input from distros on this. I
7485 think these Rust tests will be scheduled weekly as well.&lt;/p&gt;
7486 &lt;p&gt;Jordan has been experimenting with the pipeline's stages and the
7487 distro-specific idiosyncrasies for each build. This pipeline depends
7488 on some &lt;a href="https://gitlab.com/alatiera/librsvg-oci-images"&gt;c…
7489 librsvg's dependencies installed. These images are built weekly in
7490 &lt;code&gt;gitlab.com&lt;/code&gt;, so every week &lt;code&gt;gitlab.gn…
7491 librsvg's CI pipelines. Once image registries are enabled in
7492 &lt;code&gt;gitlab.gnome.org&lt;/code&gt;, we should be able to regenera…
7493 images locally without depending on an external service.&lt;/p&gt;
7494 &lt;p&gt;With the pre-built images, and caching of Rust artifacts, Jorda…
7495 able to &lt;strong&gt;reduce the time for the "test on every commit" bui…
7496 around 20 minutes, to little under 4 minutes in the current
7497 iteration. This will get even faster if the builds start using ccache
7498 and parallel builds from GNU make.&lt;/p&gt;
7499 &lt;p&gt;Currently we have a problem in that &lt;a href="https://gitlab.…
7500 builds&lt;/a&gt;, and haven't had a chance to investigate the root
7501 cause. Hopefully we can add 32-bit jobs to the CI pipeline to catch
7502 this breakage as soon as possible.&lt;/p&gt;
7503 &lt;p&gt;Having all these container images built for the CI infrastructu…
7504 means that it will be easy for people to &lt;strong&gt;set up a developm…
7505 environment&lt;/strong&gt; for librsvg, even though we have &lt;a href="…
7506 now&lt;/a&gt; thanks to Jordan. I haven't investigated setting up a
7507 Flatpak-based environment; this would be nice to have as well.&lt;/p&gt;…
7508 &lt;code&gt;rsvg-rs&lt;/code&gt; is the Rust binding to librsvg. Like t…
7509 it gets generated from a pre-built &lt;a href="https://people.gnome.org/…
7510 &lt;p&gt;It would be nice for librsvg to provide the Rust binding by its…
7511 that librsvg's own internal tools can be …&lt;/p&gt;</summary><content…
7512 &lt;code&gt;rsvg-rs&lt;/code&gt; is the Rust binding to librsvg. Like t…
7513 it gets generated from a pre-built &lt;a href="https://people.gnome.org/…
7514 &lt;p&gt;It would be nice for librsvg to provide the Rust binding by its…
7515 that librsvg's own internal tools can be implemented in Rust —
7516 currently all the tests are done in C, as are the &lt;code&gt;rsvg-conve…
7517 &lt;code&gt;rsvg-view-3(1)&lt;/code&gt; programs.&lt;/p&gt;
7518 &lt;p&gt;There are some implications for how &lt;code&gt;rsvg-rs&lt;/cod…
7519 For librsvg's internal consumption, the binding can be built from the
7520 &lt;code&gt;Rsvg-2.0.gir&lt;/code&gt; file that gets built out of the ma…
7521 for public consumption of &lt;code&gt;rsvg-rs&lt;/code&gt;, when it is b…
7522 crate and built by Cargo, that &lt;code&gt;Rsvg-2.0.gir&lt;/code&gt; nee…
7523 built and available: it wouldn't be appropriate for Cargo to build
7524 librsvg and the &lt;code&gt;.gir&lt;/code&gt; file itself.&lt;/p&gt;
7525 &lt;p&gt;If this sort of thing interests you, &lt;a href="https://gitlab…
7526 seems like it would be easier to just port some major parts from C to
7527 Rust than to just add accessors for them. Also, more and more of the
7528 meat of the library is in Rust now.&lt;/p&gt;
7529 &lt;p&gt;I'm …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Librsv…
7530 seems like it would be easier to just port some major parts from C to
7531 Rust than to just add accessors for them. Also, more and more of the
7532 meat of the library is in Rust now.&lt;/p&gt;
7533 &lt;p&gt;I'm switching back and forth a lot between C and Rust these day…
7534 C feels very, very primitive these days.&lt;/p&gt;
7535 &lt;h1&gt;A sort of elegy to C&lt;/h1&gt;
7536 &lt;p&gt;I fell in love with the C language about 24 years ago. I learn…
7537 basics of it by reading a Spanish translation of &lt;a href="https://en.…
7538 Language by K&amp;amp;R&lt;/a&gt; second edition. I had been using Turb…
7539 before in a reasonably low-level fashion, with pointers and manual
7540 memory allocation, and C felt refreshing and empowering.&lt;/p&gt;
7541 &lt;p&gt;K&amp;amp;R is a great book for its &lt;em&gt;style of writing&…
7542 programming. This little book even taught you how to implement a
7543 simple &lt;code&gt;malloc()&lt;/code&gt;/&lt;code&gt;free()&lt;/code&gt;…
7544 low-level constructs that seemed part of the language could be
7545 implemented in the language itself!&lt;/p&gt;
7546 &lt;p&gt;I got good at C over the following years. It is a small langua…
7547 with a small standard library. It was probably the perfect language
7548 to implement Unix kernels in 20,000 lines of code or so.&lt;/p&gt;
7549 &lt;p&gt;The GIMP and GTK+ taught me how to do fancy object orientation …
7550 GNOME taught me how to maintain large-scale software in C. 20,000
7551 lines of C code started to seem like a project one could more or less
7552 fully understand in a few weeks.&lt;/p&gt;
7553 &lt;p&gt;But our code bases are not that small anymore. Our software no…
7554 &lt;em&gt;huge&lt;/em&gt; expectations on the features that are availabl…
7555 language's standard library.&lt;/p&gt;
7556 &lt;h2&gt;Some good experiences with C&lt;/h2&gt;
7557 &lt;p&gt;Reading the POV-Ray code source code for the first time and lea…
7558 how to do object orientation and inheritance in C.&lt;/p&gt;
7559 &lt;p&gt;Reading the GTK+ source code and learning a C style that was le…
7560 maintainable, and clean.&lt;/p&gt;
7561 &lt;p&gt;Reading SIOD's source code, then the early Guile sources, and s…
7562 how a Scheme interpreter can be written in C.&lt;/p&gt;
7563 &lt;p&gt;Writing the initial versions of Eye of Gnome and fine-tuning the
7564 microtile rendering.&lt;/p&gt;
7565 &lt;h2&gt;Some bad experiences with C&lt;/h2&gt;
7566 &lt;p&gt;In the Evolution team, when everything was crashing. We had to…
7567 Solaris machine just to be able to buy Purify; there was no Valgrind
7568 back then.&lt;/p&gt;
7569 &lt;p&gt;Debugging gnome-vfs threading deadlocks.&lt;/p&gt;
7570 &lt;p&gt;Debugging Mesa and getting nowhere.&lt;/p&gt;
7571 &lt;p&gt;Taking over the intial versions of Nautilus-share and seeing th…
7572 never &lt;code&gt;free()&lt;/code&gt;d anything.&lt;/p&gt;
7573 &lt;p&gt;Trying to refactor code where I had no idea about the memory
7574 management strategy.&lt;/p&gt;
7575 &lt;p&gt;Trying to turn code into a library when it is full of global va…
7576 and no functions are &lt;code&gt;static&lt;/code&gt;.&lt;/p&gt;
7577 &lt;p&gt;But anyway — let's get on with things in Rust I miss in C.&lt…
7578 &lt;h1&gt;Automatic resource management&lt;/h1&gt;
7579 &lt;p&gt;One of the first blog posts I read about Rust was "&lt;a href="…
7580 having to close a socket&lt;/a&gt;". Rust borrows C++'s ideas about
7581 &lt;a href="http://wiki.c2.com/?ResourceAcquisitionIsInitialization"&gt;…
7582 adds in the single-ownership principle for values, and gives you
7583 automatic, deterministic resource management in a very neat package.&lt;…
7584 &lt;ul&gt;
7585 &lt;li&gt;
7586 &lt;p&gt;Automatic: you don't &lt;code&gt;free()&lt;/code&gt; by hand. …
7587 files get closed, mutexes get unlocked when they go out of scope.
7588 If you are wrapping an external resource, you just implement the
7589 &lt;a href="https://doc.rust-lang.org/book/second-edition/ch15-03-drop…
7590 like part of the language since you don't have to babysit its
7591 lifetime by hand.&lt;/p&gt;
7592 &lt;/li&gt;
7593 &lt;li&gt;
7594 &lt;p&gt;Deterministic: resources get created (memory allocated, initial…
7595 files opened, etc.), and they get destroyed when they go out of
7596 scope. There is no garbage collection: things really get terminated
7597 when you close a brace. You start to see your program's data
7598 lifetimes as a tree of function calls.&lt;/p&gt;
7599 &lt;/li&gt;
7600 &lt;/ul&gt;
7601 &lt;p&gt;After forgetting to free/close/destroy C objects all the time, …
7602 worse, figuring out where code that I didn't write forgot to do those
7603 things (or did them &lt;em&gt;twice&lt;/em&gt;, incorrectly)... I don't …
7604 again.&lt;/p&gt;
7605 &lt;h1&gt;Generics&lt;/h1&gt;
7606 &lt;p&gt;&lt;code&gt;Vec&amp;lt;T&amp;gt;&lt;/code&gt; really is a vecto…
7607 It's not an array of pointers to individually allocated objects. It
7608 gets compiled &lt;em&gt;specifically&lt;/em&gt; to code that can only ha…
7609 type &lt;code&gt;T&lt;/code&gt;.&lt;/p&gt;
7610 &lt;p&gt;After writing many janky macros in C to do similar things... I …
7611 want to do it again.&lt;/p&gt;
7612 &lt;h1&gt;Traits are not just interfaces&lt;/h1&gt;
7613 &lt;p&gt;&lt;a href="https://doc.rust-lang.org/book/second-edition/ch17-…
7614 has traits, which at first seem like Java interfaces — an easy way to
7615 do dynamic dispatch, so that if an object implements &lt;code&gt;Drawabl…
7616 you can assume it has a &lt;code&gt;draw()&lt;/code&gt; method.&lt;/p&gt;
7617 &lt;p&gt;However, traits are more powerful than that.&lt;/p&gt;
7618 &lt;h2&gt;Associated types&lt;/h2&gt;
7619 &lt;p&gt;&lt;a href="https://doc.rust-lang.org/book/second-edition/ch19-…
7620 provies the &lt;code&gt;Iterator&lt;/code&gt; trait which you can implem…
7621 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
7622 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;type&lt;/sp…
7623 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span…
7624 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
7625 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
7626
7627 &lt;p&gt;This means that whenever you implement &lt;code&gt;Iterator&lt;…
7628 object, you also have to specify an &lt;code&gt;Item&lt;/code&gt; type f…
7629 will be produced. If you call &lt;code&gt;next()&lt;/code&gt; and there…
7630 you'll get back a &lt;code&gt;Some(YourElementType)&lt;/code&gt;. When …
7631 out of items, it will return &lt;code&gt;None&lt;/code&gt;.&lt;/p&gt;
7632 &lt;p&gt;Associated types can refer to &lt;em&gt;other&lt;/em&gt; traits…
7633 &lt;p&gt;For example, in Rust, you can use &lt;code&gt;for&lt;/code&gt; …
7634 implements the &lt;code&gt;IntoIterator&lt;/code&gt; trait:&lt;/p&gt;
7635 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
7636 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sd"&gt;/// The ty…
7637 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;type&lt;/sp…
7638
7639 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sd"&gt;/// Which …
7640 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;type&lt;/sp…
7641
7642 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span…
7643 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
7644 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
7645
7646 &lt;p&gt;When implementing this trait, you must provide both the type of…
7647 &lt;code&gt;Item&lt;/code&gt; which your iterator will produce, and &lt;…
7648 type that implements &lt;code&gt;Iterator&lt;/code&gt; and that holds yo…
7649 &lt;p&gt;This way you can build webs of types that refer to each other. …
7650 can have a trait that says, "I can do foo and bar, but only if you
7651 give me a type that can do this and that".&lt;/p&gt;
7652 &lt;h1&gt;Slices&lt;/h1&gt;
7653 &lt;p&gt;I already posted about &lt;a href="https://people.gnome.org/~fe…
7654 how this is a pain in the ass once you get used to having them.&lt;/p&gt;
7655 &lt;h1&gt;Modern tooling for dependency management&lt;/h1&gt;
7656 &lt;p&gt;Instead of &lt;/p&gt;
7657 &lt;ul&gt;
7658 &lt;li&gt;Having to invoke &lt;code&gt;pkg-config&lt;/code&gt; by hand o…
7659 &lt;li&gt;Wrangling include paths for header files...&lt;/li&gt;
7660 &lt;li&gt;... and library files.&lt;/li&gt;
7661 &lt;li&gt;And basically depending on the user to ensure that the correct
7662 versions of libraries are installed,&lt;/li&gt;
7663 &lt;/ul&gt;
7664 &lt;p&gt;You write a &lt;code&gt;Cargo.toml&lt;/code&gt; file which list…
7665 your dependencies. These get downloaded from a well-known location,
7666 or from elsewhere if you specify.&lt;/p&gt;
7667 &lt;p&gt;You don't have to fight dependencies. It just works when you &…
7668 &lt;h1&gt;Tests&lt;/h1&gt;
7669 &lt;p&gt;C makes it very hard to have unit tests for several reasons:&lt…
7670 &lt;ul&gt;
7671 &lt;li&gt;
7672 &lt;p&gt;Internal functions are often &lt;code&gt;static&lt;/code&gt;. …
7673 called outside of the source file that defined them. A test program
7674 either has to &lt;code&gt;#include&lt;/code&gt; the source file where …
7675 live, or use &lt;code&gt;#ifdef&lt;/code&gt;s to remove the &lt;code&g…
7676 &lt;/li&gt;
7677 &lt;li&gt;
7678 &lt;p&gt;You have to write Makefile-related hackery to link the test pro…
7679 to only part of your code's dependencies, or to only part of the
7680 rest of your code.&lt;/p&gt;
7681 &lt;/li&gt;
7682 &lt;li&gt;
7683 &lt;p&gt;You have to pick a testing framework. You have to register tes…
7684 against the testing framework. You have to &lt;em&gt;learn&lt;/em&gt;…
7685 framework.&lt;/p&gt;
7686 &lt;/li&gt;
7687 &lt;/ul&gt;
7688 &lt;p&gt;In Rust you write&lt;/p&gt;
7689 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
7690 &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;test_that_f…
7691 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="fm"&gt;assert!&lt…
7692 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
7693 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
7694
7695 &lt;p&gt;anywhere in your program or library, and when you type &lt;code…
7696 IT JUST FUCKING WORKS. That code only gets linked into the
7697 test binary. You don't have to compile anything twice by hand, or
7698 write Makefile hackery, or figure out how to extract internal
7699 functions for testing.&lt;/p&gt;
7700 &lt;p&gt;This is a very killer feature for me.&lt;/p&gt;
7701 &lt;h1&gt;Documentation, with tests&lt;/h1&gt;
7702 &lt;p&gt;Rust generates documentation from comments in Markdown syntax. …
7703 in the docs &lt;em&gt;gets run as tests&lt;/em&gt;. You can illustrate …
7704 used &lt;em&gt;and&lt;/em&gt; test it at the same time:&lt;/p&gt;
7705 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
7706 &lt;span class="sd"&gt;///&lt;/span&gt;
7707 &lt;span class="sd"&gt;/// ```&lt;/span&gt;
7708 &lt;span class="sd"&gt;/// assert_eq!(multiply_by_two(5), 10);&lt;/span&…
7709 &lt;span class="sd"&gt;/// ```&lt;/span&gt;
7710 &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;multiply_by…
7711 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&…
7712 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
7713 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
7714
7715 &lt;p&gt;Your example code &lt;em&gt;gets run as tests&lt;/em&gt; to ens…
7716 documentation stays up to date with the actual code.&lt;/p&gt;
7717 &lt;p&gt;&lt;strong&gt;Update 2018/Feb/23:&lt;/strong&gt; QuietMisdreavu…
7718 doctests into runnable code
7719 internally&lt;/a&gt;.
7720 This is high-grade magic and thoroughly interesting.&lt;/p&gt;
7721 &lt;h1&gt;Hygienic macros&lt;/h1&gt;
7722 &lt;p&gt;Rust has hygienic macros that avoid all of C's problems with th…
7723 macros that inadvertently shadow identifiers in the code. You don't
7724 need to write macros where every symbol has to be in parentheses for
7725 &lt;code&gt;max(5 + 3, 4)&lt;/code&gt; to work correctly.&lt;/p&gt;
7726 &lt;h1&gt;No automatic coercions&lt;/h1&gt;
7727 &lt;p&gt;All the bugs in C that result from inadvertently converting an …
7728 to a &lt;code&gt;short&lt;/code&gt; or &lt;code&gt;char&lt;/code&gt; or …
7729 to explicitly convert.&lt;/p&gt;
7730 &lt;h1&gt;No integer overflow&lt;/h1&gt;
7731 &lt;p&gt;Enough said.&lt;/p&gt;
7732 &lt;h1&gt;Generally, no undefined behavior in safe Rust&lt;/h1&gt;
7733 &lt;p&gt;In Rust, it is considered a bug in the language if something wr…
7734 in "safe Rust" (what you would be allowed to write outside &lt;code&gt;u…
7735 blocks) results in undefined behavior. You can shift-right a negative
7736 integer and it will do exactly what you expect.&lt;/p&gt;
7737 &lt;h1&gt;Pattern matching&lt;/h1&gt;
7738 &lt;p&gt;You know how &lt;code&gt;gcc&lt;/code&gt; warns you if you &lt…
7739 handle all values? That's like a little baby.&lt;/p&gt;
7740 &lt;p&gt;Rust has &lt;a href="https://doc.rust-lang.org/book/second-edit…
7741 trick for enums inside a &lt;code&gt;match()&lt;/code&gt; expression. I…
7742 destructuring so you can return multiple values from a function:&lt;/p&g…
7743 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
7744 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;pub&lt;/spa…
7745 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
7746
7747 &lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&…
7748 &lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&…
7749 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
7750
7751 &lt;p&gt;You can &lt;code&gt;match()&lt;/code&gt; on strings. YOU CAN M…
7752 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
7753
7754 &lt;span class="k"&gt;match&lt;/span&gt;&lt;span class="w"&gt; &lt;/span…
7755 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;r…
7756 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;g…
7757 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&…
7758 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
7759 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
7760
7761 &lt;p&gt;You know how this is illegible?&lt;/p&gt;
7762 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
7763 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
7764
7765 &lt;p&gt;How about this instead, with pattern matching on function argum…
7766 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
7767 &lt;span class="k"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&g…
7768 &lt;span class="k"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&g…
7769
7770 &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;my_func&lt;…
7771 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Frob…
7772 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Bazi…
7773 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span…
7774 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;..&lt;/…
7775 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&…
7776
7777 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span…
7778 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;..&lt;/…
7779 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&…
7780 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
7781
7782 &lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt…
7783
7784 &lt;span class="n"&gt;my_func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/sp…
7785 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
7786
7787 &lt;h1&gt;Standard, useful error handling&lt;/h1&gt;
7788 &lt;p&gt;I've talked at length about this. No more returning a boolean …
7789 extra explanation for an error, no ignoring errors inadvertently, no
7790 exception handling with nonlocal jumps.&lt;/p&gt;
7791 &lt;h1&gt;#[derive(Debug)]&lt;/h1&gt;
7792 &lt;p&gt;If you write a new type (say, a struct with a ton of fields), y…
7793 &lt;code&gt;#[derive(Debug)]&lt;/code&gt; and Rust will know how to auto…
7794 type's contents for debug output. You no longer have to write a
7795 special function that you must call in gdb by hand just to examine a
7796 custom type.&lt;/p&gt;
7797 &lt;h1&gt;Closures&lt;/h1&gt;
7798 &lt;p&gt;No more passing function pointers and a &lt;code&gt;user_data&l…
7799 &lt;h1&gt;Conclusion&lt;/h1&gt;
7800 &lt;p&gt;I haven't done the "&lt;a href="https://doc.rust-lang.org/book/…
7801 compiler is able to prevent data races in threaded code. I imagine it
7802 being a game-changer for people who write concurrent code on an
7803 everyday basis.&lt;/p&gt;
7804 &lt;p&gt;C is an old language with primitive constructs and primitive to…
7805 It was a good language for small uniprocessor Unix kernels that ran in
7806 trusted, academic environments. It's no longer a good language for
7807 the software of today.&lt;/p&gt;
7808 &lt;p&gt;Rust is not easy to learn, but I think it is completely worth i…
7809 It's hard because it demands a lot from your understanding of the code
7810 you want to write. I think it's one of those languages that make you
7811 a better programmer and that let you tackle more ambitious problems.&lt;…
7812 a program that actually has a &lt;code&gt;main()&lt;/code&gt; function.&…
7813 &lt;p&gt;My experience with Rust so far has been threefold:&lt;/p&gt;
7814 &lt;ul&gt;
7815 &lt;li&gt;
7816 &lt;p&gt;Porting chunks of C to Rust for librsvg - this is all work on
7817 librsvg's internals and no users are exposed …&lt;/p&gt;&lt;/li&gt;&…
7818 a program that actually has a &lt;code&gt;main()&lt;/code&gt; function.&…
7819 &lt;p&gt;My experience with Rust so far has been threefold:&lt;/p&gt;
7820 &lt;ul&gt;
7821 &lt;li&gt;
7822 &lt;p&gt;Porting chunks of C to Rust for librsvg - this is all work on
7823 librsvg's internals and no users are exposed to it directly.&lt;/p&gt;
7824 &lt;/li&gt;
7825 &lt;li&gt;
7826 &lt;p&gt;Working on &lt;a href="https://github.com/nikomatsakis/gnome-cl…
7827 to generate GObject boilerplate from Rust. This feels like working
7828 on the edge of the exotic; it is something that runs &lt;em&gt;in&lt;/…
7829 compiler and spits code on behalf of the programmer.&lt;/p&gt;
7830 &lt;/li&gt;
7831 &lt;li&gt;
7832 &lt;p&gt;A few patches to the &lt;a href="http://gtk-rs.org"&gt;gtk-rs&l…
7833 internals, or something that feels library-like.&lt;/p&gt;
7834 &lt;/li&gt;
7835 &lt;/ul&gt;
7836 &lt;p&gt;But other than toy programs to test things, I haven't written a
7837 stand-alone tool until &lt;a href="https://people.gnome.org/~federico/bl…
7838 to just &lt;em&gt;run the thing&lt;/em&gt; instead of waiting for other …
7839 code to use it!&lt;/p&gt;
7840 &lt;h1&gt;Parsing command-line arguments&lt;/h1&gt;
7841 &lt;p&gt;There are quite a few Rust crates ("libraries") to parse comman…
7842 arguments. I read about &lt;a href="https://docs.rs/structopt-derive/0.…
7843 blog&lt;/a&gt;; structopt lets you define a &lt;code&gt;struct&lt;/code&…
7844 your command-line options, and then you annotate the fields in that
7845 &lt;code&gt;struct&lt;/code&gt; to indicate how they should be parsed fr…
7846 It works via Rust's procedural macros. Internally it generates stuff
7847 for the &lt;a href="https://docs.rs/clap/2.29.2/clap/"&gt;clap&lt;/a&gt;…
7848 command-line options.&lt;/p&gt;
7849 &lt;p&gt;And it is quite pleasant! This is basically all I needed to do…
7850 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
7851 &lt;span class="cp"&gt;#[structopt(name = &lt;/span&gt;&lt;span class="s…
7852 &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;Opt&lt;…
7853 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cp"&gt;#[structop…
7854 &lt;span class="cp"&gt; long = &lt;/span&gt;&lt;span cla…
7855 &lt;span class="cp"&gt; help = &lt;/span&gt;&lt;span cla…
7856 &lt;span class="cp"&gt; default_value = &lt;/span&gt;&lt;…
7857 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sleep_secs&…
7858
7859 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cp"&gt;#[structop…
7860 &lt;span class="cp"&gt; long = &lt;/span&gt;&lt;span cla…
7861 &lt;span class="cp"&gt; help = &lt;/span&gt;&lt;span cla…
7862 &lt;span class="cp"&gt; default_value = &lt;/span&gt;&lt;…
7863 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;num_parse&l…
7864
7865 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cp"&gt;#[structop…
7866 &lt;span class="cp"&gt; long = &lt;/span&gt;&lt;span cla…
7867 &lt;span class="cp"&gt; help = &lt;/span&gt;&lt;span cla…
7868 &lt;span class="cp"&gt; default_value = &lt;/span&gt;&lt;…
7869 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;num_render&…
7870
7871 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cp"&gt;#[structop…
7872 &lt;span class="cp"&gt; help = &lt;/span&gt;&lt;span clas…
7873 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;render_to_p…
7874
7875 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cp"&gt;#[structop…
7876 &lt;span class="cp"&gt; parse(from_os_str))]&lt;/span&gt;…
7877 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;inputs&lt;/…
7878 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
7879
7880 &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/sp…
7881 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/sp…
7882
7883 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span…
7884 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="fm"&gt;eprint…
7885 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;process…
7886 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&…
7887
7888 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;..&lt;/span…
7889 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
7890 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
7891
7892 &lt;p&gt;Each field in the &lt;code&gt;Opt&lt;/code&gt; struct above cor…
7893 argument; each field has annotations for &lt;code&gt;structopt&lt;/code&…
7894 appropriate code to parse each option. For example, the
7895 &lt;code&gt;render_to_pixbuf&lt;/code&gt; field has a long option name c…
7896 that field will be set to &lt;code&gt;true&lt;/code&gt; if the &lt;code&…
7897 to rsvg-bench.&lt;/p&gt;
7898 &lt;h1&gt;Handling errors&lt;/h1&gt;
7899 &lt;p&gt;Command-line programs generally have the luxury of being able t…
7900 exit as soon as they encounter an error.&lt;/p&gt;
7901 &lt;p&gt;In C this is a bit cumbersome since you need to deal with &lt;e…
7902 place that may return an error, find out what to print, and call
7903 &lt;code&gt;exit(1)&lt;/code&gt; by hand or something. If you miss a si…
7904 error is returned, your program will keep running with an inconsistent
7905 state.&lt;/p&gt;
7906 &lt;p&gt;In languages with exception handling, it's a bit easier - a sma…
7907 script can just let exceptions be thrown wherever, and if it catches
7908 them at the toplevel, it can just print the exception and abort
7909 gracefully. However, these nonlocal jumps make me uncomfortable; I
7910 think &lt;a href="http://joeduffyblog.com/2016/02/07/the-error-model/"&g…
7911 &lt;p&gt;Rust makes this easy: it forces you to handle every call that m…
7912 return an error, but it lets you bubble errors up easily, or handle
7913 them in-place, or translate them to a higher-level error.&lt;/p&gt;
7914 &lt;p&gt;In the Rust world the [&lt;code&gt;failure&lt;/code&gt;] crate …
7915 as a convenient, modern way to handle errors.&lt;/p&gt;
7916 &lt;p&gt;In rsvg-bench, errors can come from several places:&lt;/p&gt;
7917 &lt;ul&gt;
7918 &lt;li&gt;
7919 &lt;p&gt;I/O errors when reading files and directories.&lt;/p&gt;
7920 &lt;/li&gt;
7921 &lt;li&gt;
7922 &lt;p&gt;Errors from librsvg's parsing stage; you get a &lt;a href="http…
7923 &lt;/li&gt;
7924 &lt;li&gt;
7925 &lt;p&gt;Errors from the rendering stage. This can be a Cairo error (a
7926 &lt;a href="https://www.cairographics.org/manual/cairo-Error-handling.…
7927 render" from librsvg's old convenience api in C. Don't you hate it
7928 when C code just gives up and returns NULL or a boolean false,
7929 without any further details on &lt;em&gt;what&lt;/em&gt; went wrong?&l…
7930 &lt;/li&gt;
7931 &lt;/ul&gt;
7932 &lt;p&gt;For rsvg-bench, I just needed to be able to represent Cairo err…
7933 generic rendering errors. Everything else, like an &lt;code&gt;io::Erro…
7934 automatically wrapped by the &lt;code&gt;failure&lt;/code&gt; crate's me…
7935 needed to do this:&lt;/p&gt;
7936 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
7937 &lt;span class="cp"&gt;#[macro_use]&lt;/span&gt;&lt;span class="w"&gt;&l…
7938 &lt;span class="k"&gt;extern&lt;/span&gt;&lt;span class="w"&gt; &lt;/spa…
7939
7940 &lt;span class="cp"&gt;#[derive(Debug, Fail)]&lt;/span&gt;&lt;span class…
7941 &lt;span class="k"&gt;enum&lt;/span&gt; &lt;span class="nc"&gt;Processin…
7942 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cp"&gt;#[fail(dis…
7943 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CairoError&…
7944 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;status&…
7945 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span…
7946
7947 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cp"&gt;#[fail(dis…
7948 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RenderingEr…
7949 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
7950 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
7951
7952 &lt;p&gt;Whenever the code gets a Cairo error, I can translate it to a
7953 &lt;code&gt;ProcessingError::CairoError&lt;/code&gt; and bubble it up:&l…
7954 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
7955 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/sp…
7956 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/sp…
7957 &lt;span class="w"&gt; &lt;…
7958 &lt;span class="w"&gt; &lt;…
7959 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/s…
7960
7961 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;..&lt;/span…
7962 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
7963 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
7964
7965 &lt;p&gt;And when librsvg returns a "couldn't render" error, I translate…
7966 to a &lt;code&gt;ProcessingError::RenderingError&lt;/code&gt;:&lt;/p&gt;
7967 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
7968 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;..&lt;/span…
7969
7970 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/sp…
7971
7972 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span…
7973 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Ok&lt;…
7974 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&…
7975 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Err&lt…
7976 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&…
7977 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
7978 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
7979
7980 &lt;p&gt;Here, the &lt;code&gt;Ok()&lt;/code&gt; case of the &lt;code&gt…
7981 it's just &lt;code&gt;()&lt;/code&gt;, as the generated images are not s…
7982 are just rendered to get some timings, not to be saved or anything.&lt;/…
7983 &lt;h1&gt;Up to where do errors bubble?&lt;/h1&gt;
7984 &lt;p&gt;This is the "do everything" function:&lt;/p&gt;
7985 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
7986 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;..&lt;/span…
7987
7988 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;for&lt;/spa…
7989 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;process…
7990 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&…
7991
7992 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Ok&lt;/spa…
7993 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
7994 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
7995
7996 &lt;p&gt;For each path passed in the command line, process it. The prog…
7997 sees if the path corresponds to a directory, and it will scan it
7998 recursively. Or if the path is an SVG file, the program will load the
7999 file and render it.&lt;/p&gt;
8000 &lt;p&gt;Finally, &lt;code&gt;main()&lt;/code&gt; just has this:&lt;/p&g…
8001 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
8002 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/sp…
8003
8004 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;..&lt;/span…
8005
8006 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;match&lt;/s…
8007 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Ok&lt;…
8008 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Err&lt…
8009 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="fm"&gt;ep…
8010 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pro…
8011 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/s…
8012 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&…
8013 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
8014 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
8015
8016 &lt;p&gt;I.e. process command line arguments, run the whole thing, and p…
8017 error if there was one.&lt;/p&gt;
8018 &lt;p&gt;I really appreciate that most places that can return an error a…
8019 put a &lt;code&gt;?&lt;/code&gt; for the error to bubble up. This is mu…
8020 in C, where every call must have an &lt;code&gt;if (something_bad_happen…
8021 deal_with_it; }&lt;/code&gt; after it... and Rust won't let me get away …
8022 ignoring an error, but it makes it easy to actually deal with it properl…
8023 &lt;h1&gt;Reading an SVG file quickly&lt;/h1&gt;
8024 &lt;p&gt;Why, just &lt;code&gt;mmap()&lt;/code&gt; it and feed it to lib…
8025 This is easy in Rust:&lt;/p&gt;
8026 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
8027 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/sp…
8028 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/sp…
8029
8030 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/sp…
8031
8032 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/sp…
8033 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;..&lt;/span…
8034 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
8035 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
8036
8037 &lt;p&gt;Many things can go wrong here:&lt;/p&gt;
8038 &lt;ul&gt;
8039 &lt;li&gt;&lt;code&gt;File::open()&lt;/code&gt; can return an io::Error.…
8040 &lt;li&gt;&lt;code&gt;MmapOptions::map()&lt;/code&gt; can return an io::…
8041 system call, or from the &lt;code&gt;fstat(2)&lt;/code&gt; to read the…
8042 it.&lt;/li&gt;
8043 &lt;li&gt;&lt;code&gt;rsvg::Handle::new_from_data()&lt;/code&gt; can ret…
8044 file.&lt;/li&gt;
8045 &lt;/ul&gt;
8046 &lt;p&gt;The little &lt;code&gt;?&lt;/code&gt; characters after each cal…
8047 mean, just give me back the result, or convert the error to a
8048 &lt;code&gt;failure::Error&lt;/code&gt; that can be examined later. Thi…
8049 legible to me.&lt;/p&gt;
8050 &lt;h1&gt;Summary&lt;/h1&gt;
8051 &lt;p&gt;Writing command-line programs in Rust is fun! It's nice to have
8052 neurotically-safe scripts that one can trust in the future.&lt;/p&gt;
8053 &lt;p&gt;&lt;a href="https://gitlab.gnome.org/federico/rsvg-bench"&gt;Rs…
8054 compared to 2.40.20: SVGs with many &lt;a href="https://www.w3.org/TR/SV…
8055 attributes would slow it down. It was fixed in 2.42.1. We changed
8056 from using a &lt;a href="https://github.com/lalrpop/lalrpop/issues/269"&…
8057 called, to &lt;a href="https://github.com/servo/rust-cssparser"&gt;one �…
8058 compared to 2.40.20: SVGs with many &lt;a href="https://www.w3.org/TR/SV…
8059 attributes would slow it down. It was fixed in 2.42.1. We changed
8060 from using a &lt;a href="https://github.com/lalrpop/lalrpop/issues/269"&…
8061 called, to &lt;a href="https://github.com/servo/rust-cssparser"&gt;one t…
8062 parsing.&lt;/p&gt;
8063 &lt;p&gt;When I rewrote librsvg's parser for the &lt;code&gt;transform&l…
8064 to Rust, I was just &lt;a href="https://people.gnome.org/~federico/news-…
8065 I chose &lt;a href="https://github.com/lalrpop/lalrpop"&gt;lalrpop&lt;/a…
8066 It generates big, fast parsers, like what you would need for a
8067 compiler — but it compiles the tokenizer's regexes each time you call
8068 the parser. This is not a problem for a compiler, where you basically
8069 call the parser only once, but in librsvg, we may call it thousands of
8070 times for an SVG file with thousands of objects with &lt;code&gt;transfo…
8071 attributes.&lt;/p&gt;
8072 &lt;p&gt;So, for 2.42.1 I rewrote that parser using
8073 &lt;a href="https://github.com/servo/rust-cssparser"&gt;rust-cssparser&l…
8074 parse CSS data; it's a simple tokenizer with an API that knows about
8075 CSS's particular constructs. This is exactly the kind of data that
8076 librsvg cares about. Today all of librsvg's internal parsers work
8077 using rust-cssparser, or they are so simple that they can be done with
8078 Rust's normal functions to split strings and such.&lt;/p&gt;
8079 &lt;h1&gt;Getting good timings&lt;/h1&gt;
8080 &lt;p&gt;Librsvg ships with &lt;code&gt;rsvg-convert&lt;/code&gt;, a com…
8081 render an SVG file and write the output to a PNG. While it would be
8082 possible to get timings for SVG rendering by timing how long
8083 &lt;code&gt;rsvg-convert&lt;/code&gt; takes to run, it's a bit clunky fo…
8084 startup adds noise to the timings, and it only handles one file at a
8085 time.&lt;/p&gt;
8086 &lt;p&gt;So, I've written &lt;a href="https://gitlab.gnome.org/federico/…
8087 librsvg. I wanted a tool that:&lt;/p&gt;
8088 &lt;ul&gt;
8089 &lt;li&gt;
8090 &lt;p&gt;Is able to process many SVG images with a single command. For
8091 example, this lets us answer a question like, "how long does version
8092 N of librsvg take to render a directory full of SVG icons?" — which
8093 is important for the performance of an application chooser.&lt;/p&gt;
8094 &lt;/li&gt;
8095 &lt;li&gt;
8096 &lt;p&gt;Is able to &lt;em&gt;repeatedly&lt;/em&gt; process SVG files, f…
8097 SVG 1000 times in a row". This is useful to get accurate timings,
8098 as a single render may only take a few microseconds and may be hard
8099 to measure. It also helps with running profilers, as they will be
8100 able to get more useful samples if the SVG rendering process runs
8101 repeatedly for a long time.&lt;/p&gt;
8102 &lt;/li&gt;
8103 &lt;li&gt;
8104 &lt;p&gt;Exercises librsvg's major code paths for parsing and rendering
8105 separately. For example, librsvg uses different parts of the XML
8106 parser depending on whether it is being pushed data, vs. being asked
8107 to pull data from a stream. Also, we may only want to benchmark the
8108 parser but not the renderer; or we may want to parse SVGs only once
8109 but render them many times after that.&lt;/p&gt;
8110 &lt;/li&gt;
8111 &lt;li&gt;
8112 &lt;p&gt;Is aware of librsvg's peculiarities, such as the extra pass to
8113 convert a Cairo image surface to a GdkPixbuf when one uses the
8114 convenience function &lt;code&gt;rsvg_handle_get_pixbuf()&lt;/code&gt;…
8115 &lt;/li&gt;
8116 &lt;/ul&gt;
8117 &lt;p&gt;Currently rsvg-bench supports all of that.&lt;/p&gt;
8118 &lt;h1&gt;An initial benchmark&lt;/h1&gt;
8119 &lt;p&gt;I ran this&lt;/p&gt;
8120 &lt;p&gt;&lt;code&gt;/usr/bin/time rsvg-bench -p 1 -r 1 /usr/share/icons…
8121 &lt;p&gt;to cause every SVG icon in &lt;code&gt;/usr/share/icons&lt;/cod…
8122 rendered once (i.e. just render every file sequentially). I did this
8123 for librsvg 2.40.20 (C only), and 2.42.{0, 1, 2} (C and Rust). There
8124 are 5522 SVG files in there. The timings look like this:&lt;/p&gt;
8125 &lt;table&gt;
8126 &lt;thead&gt;
8127 &lt;tr&gt;
8128 &lt;th&gt;version&lt;/th&gt;
8129 &lt;th&gt;time (sec)&lt;/th&gt;
8130 &lt;/tr&gt;
8131 &lt;/thead&gt;
8132 &lt;tbody&gt;
8133 &lt;tr&gt;
8134 &lt;td&gt;2.40.20&lt;/td&gt;
8135 &lt;td&gt;95.54&lt;/td&gt;
8136 &lt;/tr&gt;
8137 &lt;tr&gt;
8138 &lt;td&gt;2.42.0&lt;/td&gt;
8139 &lt;td&gt;209.50&lt;/td&gt;
8140 &lt;/tr&gt;
8141 &lt;tr&gt;
8142 &lt;td&gt;2.42.1&lt;/td&gt;
8143 &lt;td&gt;97.18&lt;/td&gt;
8144 &lt;/tr&gt;
8145 &lt;tr&gt;
8146 &lt;td&gt;2.42.2&lt;/td&gt;
8147 &lt;td&gt;95.89&lt;/td&gt;
8148 &lt;/tr&gt;
8149 &lt;/tbody&gt;
8150 &lt;/table&gt;
8151 &lt;p&gt;&lt;img alt="Bar chart of timings" src="https://people.gnome.or…
8152 &lt;p&gt;So, 2.42.0 was over twice as slow as the C-only version, due to…
8153 parsing problems. But now, 2.42.2 is practically just as fast as the
8154 C only version. What made this possible?&lt;/p&gt;
8155 &lt;ul&gt;
8156 &lt;li&gt;2.40.20 - the old C-only version&lt;/li&gt;
8157 &lt;li&gt;2.42.0 - C + Rust, with a lalrpop parser for the &lt;code&gt;t…
8158 &lt;li&gt;2.42.1 - Servo's cssparser for the &lt;code&gt;transform&lt;/c…
8159 &lt;li&gt;2.42.2 - removed most C-to-Rust string copies during parsing&l…
8160 &lt;/ul&gt;
8161 &lt;p&gt;I have started taking profiles of rsvg-bench runs with sysprof,…
8162 there are some improvements worth making. Expect news soon!&lt;/p&gt;
8163 &lt;p&gt;&lt;a href="https://gitlab.gnome.org/federico/rsvg-bench"&gt;Rs…
8164 preparation for the 2.42.1 release?&lt;/p&gt;
8165 &lt;p&gt;I have prepared a list of bugs which I'd like to be fixed in the
8166 &lt;a href="https://gitlab.gnome.org/GNOME/librsvg/issues?milestone_titl…
8167 I'm already working …&lt;/p&gt;</summary><content type="html">&lt;p&gt…
8168 preparation for the 2.42.1 release?&lt;/p&gt;
8169 &lt;p&gt;I have prepared a list of bugs which I'd like to be fixed in the
8170 &lt;a href="https://gitlab.gnome.org/GNOME/librsvg/issues?milestone_titl…
8171 I'm already working on them.&lt;/p&gt;
8172 &lt;p&gt;There are two other bugs which I'd love someone to look at. Ne…
8173 of these requires deep knowledge of librsvg, just some debugging and
8174 code-writing:&lt;/p&gt;
8175 &lt;ul&gt;
8176 &lt;li&gt;
8177 &lt;p&gt;&lt;a href="https://gitlab.gnome.org/GNOME/librsvg/issues/141"&…
8178 the wrong fill: it's an image of a builder's trowel, and the inside
8179 is filled black instead of with a nice gradient. This is the only
8180 place in librsvg where a &lt;code&gt;cairo_surface_t&lt;/code&gt; is c…
8181 &lt;code&gt;GdkPixbuf&lt;/code&gt;; this involves unpremultiplying the…
8182 Maybe the relevant function is buggy?&lt;/p&gt;
8183 &lt;/li&gt;
8184 &lt;li&gt;
8185 &lt;p&gt;&lt;a href="https://gitlab.gnome.org/GNOME/librsvg/issues/136"&…
8186 parsed incorrectly. It is a list of CSS length values, separated by
8187 commas or spaces. Currently librsvg uses a shitty parser based on
8188 &lt;code&gt;g_strsplit()&lt;/code&gt; only for commas; it doesn't allo…
8189 space-separated list. Then, it uses &lt;code&gt;g_ascii_strtod()&lt;/…
8190 plain numbers; it doesn't support CSS lengths generically. This
8191 parser needs to be rewritten in Rust; we already have machinery
8192 there to parse CSS length values properly.&lt;/p&gt;
8193 &lt;/li&gt;
8194 &lt;/ul&gt;
8195 &lt;p&gt;Feel free to &lt;a href="[email protected]"&gt;contact me&lt;/…
8196 bugs themselves, if you would like to work on them. I'll happily
8197 guide you through the code :)&lt;/p&gt;</content><category term="misc"><…
8198 Continuous Integration (CI) enabled for projects there. After every
8199 commit, the CI machinery can build the project, run the tests, and
8200 tell you if something goes wrong.&lt;/p&gt;
8201 &lt;p&gt;&lt;a href="https://mail.gnome.org/archives/desktop-devel-list/…
8202 week" mail to …&lt;/p&gt;</summary><content type="html">&lt;p&gt;One n…
8203 Continuous Integration (CI) enabled for projects there. After every
8204 commit, the CI machinery can build the project, run the tests, and
8205 tell you if something goes wrong.&lt;/p&gt;
8206 &lt;p&gt;&lt;a href="https://mail.gnome.org/archives/desktop-devel-list/…
8207 week" mail to desktop-devel-list, and a link to how Nautilus
8208 implements CI in Gitlab. It turns out that it's reasonably easy to
8209 set up: you just create a &lt;a href="https://docs.gitlab.com/ce/ci/yam…
8210 toplevel of your project, and that has the configuration for what to
8211 run on every commit.&lt;/p&gt;
8212 &lt;p&gt;Of course instead of reading the manual, I copied-and-pasted th…
8213 from Nautilus and just changed some things in it. &lt;a href="https://g…
8214 linter&lt;/a&gt; so you can at least check the syntax before pushing a
8215 full job.&lt;/p&gt;
8216 &lt;p&gt;Then I read &lt;a href="https://mail.gnome.org/archives/desktop…
8217 builds its CI jobs on both Fedora and Ubuntu... and then the
8218 realization hit me:&lt;/p&gt;
8219 &lt;p&gt;&lt;em&gt;This lets me CI librsvg on multiple distros at once.&…
8220 trouble with slight differences in fontconfig/freetype in the past,
8221 and this would let me catch them early.&lt;/p&gt;
8222 &lt;p&gt;However, people on IRC advised against this, as &lt;strong&gt;w…
8223 hardware&lt;/strong&gt; to run CI on a large scale.&lt;/p&gt;
8224 &lt;p&gt;Linux distros have a vested interest in getting code out of gno…
8225 that works well. Surely they can give us some hardware?&lt;/p&gt;</cont…
8226 weeks since &lt;a href="https://people.gnome.org/~federico/blog/librsvg-…
8227 already received and merged &lt;a href="https://gitlab.gnome.org/GNOME/l…
8228 weird that Github uses "pull request" and Everyone(tm) knows the PR
8229 acronym, but Gitlab uses "merge request"?)&lt;/p&gt;
8230 &lt;h1&gt;Notifications …&lt;/h1&gt;</summary><content type="html">&lt…
8231 weeks since &lt;a href="https://people.gnome.org/~federico/blog/librsvg-…
8232 already received and merged &lt;a href="https://gitlab.gnome.org/GNOME/l…
8233 weird that Github uses "pull request" and Everyone(tm) knows the PR
8234 acronym, but Gitlab uses "merge request"?)&lt;/p&gt;
8235 &lt;h1&gt;Notifications about merge requests&lt;/h1&gt;
8236 &lt;p&gt;One thing to note if your GNOME project has moved to Gitlab: &…
8237 want to get notified of incoming merge requests&lt;/strong&gt;, you need
8238 to tell Gitlab that you want to "&lt;strong&gt;Watch&lt;/strong&gt;" tha…
8239 using one of the default notification settings. &lt;a href="https://git…
8240 Soriano&lt;/a&gt; for making me aware of this.&lt;/p&gt;
8241 &lt;h1&gt;Notifications from Github's mirror&lt;/h1&gt;
8242 &lt;p&gt;The &lt;a href="https://github.com/GNOME/"&gt;github&lt;/a&gt; …
8243 requests are &lt;a href="https://wiki.gnome.org/Sysadmin/GitHub"&gt;auto…
8244 is no way to notify the upstream maintainers when someone creates a
8245 pull request in the mirror (this is super-unfriendly by default, but
8246 at least submitters get notified that their PR would not be looked at
8247 by anyone, by default).&lt;/p&gt;
8248 &lt;p&gt;If you have a Github account, you can Watch the project in ques…
8249 get notified — the bot will close the pull request, but you will get
8250 notified, and then you can check it by hand, review it as appropriate,
8251 or redirect the submitter to gitlab.gnome.org instead.&lt;/p&gt;</conten…
8252 &lt;strong&gt;last release&lt;/strong&gt; in the 2.40.x series, which i…
8253 immediately.&lt;/p&gt;
8254 &lt;p&gt;People and distros are &lt;strong&gt;strongly encouraged&lt;/st…
8255 &lt;a href="https://ftp.gnome.org/pub/GNOME/sources/librsvg/2.41/"&gt;li…
8256 implemented in a …&lt;/p&gt;</summary><content type="html">&lt;p&gt;To…
8257 &lt;strong&gt;last release&lt;/strong&gt; in the 2.40.x series, which i…
8258 immediately.&lt;/p&gt;
8259 &lt;p&gt;People and distros are &lt;strong&gt;strongly encouraged&lt;/st…
8260 &lt;a href="https://ftp.gnome.org/pub/GNOME/sources/librsvg/2.41/"&gt;li…
8261 implemented in a mixture of C and Rust. It is 100% API and ABI
8262 compatible with 2.40.x, so it is a drop-in replacement for it. If you
8263 or your distro can compile Firefox 57, you can probably build
8264 librsvg-2.41.x without problems.&lt;/p&gt;
8265 &lt;h1&gt;Some statistics&lt;/h1&gt;
8266 &lt;p&gt;Here are a few runs of &lt;a href="https://github.com/cgag/loc"…
8267 when run on librsvg. The output is trimmed by hand to only include C
8268 and Rust files.&lt;/p&gt;
8269 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
8270 &lt;span class="nb"&gt;-------------------------------------------------…
8271 &lt;span class="c"&gt; Language Files Lines Blank Comment …
8272 &lt;span class="nb"&gt;-------------------------------------------------…
8273 &lt;span class="c"&gt; C 41 20972 3438 2100 1…
8274 &lt;span class="c"&gt; C/C&lt;/span&gt;&lt;span class="nb"&gt;++&lt;/spa…
8275 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
8276
8277 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
8278 &lt;span class="nb"&gt;-------------------------------------------------…
8279 &lt;span class="c"&gt; Language Files Lines Blank Comment …
8280 &lt;span class="nb"&gt;-------------------------------------------------…
8281 &lt;span class="c"&gt; C 34 17253 3024 1892 1…
8282 &lt;span class="c"&gt; C/C&lt;/span&gt;&lt;span class="nb"&gt;++&lt;/spa…
8283 &lt;span class="c"&gt; Rust 38 11254 1873 675 …
8284 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
8285
8286 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
8287 &lt;span class="c"&gt;just &amp;quot;real source code&amp;quot;:&lt;/spa…
8288 &lt;span class="nb"&gt;-------------------------------------------------…
8289 &lt;span class="c"&gt; Language Files Lines Blank Comment …
8290 &lt;span class="nb"&gt;-------------------------------------------------…
8291 &lt;span class="c"&gt; C 34 17253 3024 1892 1…
8292 &lt;span class="c"&gt; C/C&lt;/span&gt;&lt;span class="nb"&gt;++&lt;/spa…
8293 &lt;span class="c"&gt; Rust 38 9340 1513 610 …
8294 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
8295
8296 &lt;h2&gt;Summary&lt;/h2&gt;
8297 &lt;p&gt;Not counting blank lines nor comments:&lt;/p&gt;
8298 &lt;ul&gt;
8299 &lt;li&gt;
8300 &lt;p&gt;The C-only version has 16734 lines of C code.&lt;/p&gt;
8301 &lt;/li&gt;
8302 &lt;li&gt;
8303 &lt;p&gt;The C-only version has &lt;strong&gt;no unit tests&lt;/strong&g…
8304 &lt;/li&gt;
8305 &lt;li&gt;
8306 &lt;p&gt;The Rust-and-C version has 13539 lines of C code, 7217 lines of…
8307 code, and 1489 lines of unit tests in Rust.&lt;/p&gt;
8308 &lt;/li&gt;
8309 &lt;/ul&gt;
8310 &lt;p&gt;As for the integration tests:&lt;/p&gt;
8311 &lt;ul&gt;
8312 &lt;li&gt;
8313 &lt;p&gt;The C-only version has 64 integration tests.&lt;/p&gt;
8314 &lt;/li&gt;
8315 &lt;li&gt;
8316 &lt;p&gt;The Rust-and-C version has 130 integration tests.&lt;/p&gt;
8317 &lt;/li&gt;
8318 &lt;/ul&gt;
8319 &lt;p&gt;The Rust-and-C version supports a few more SVG features, and it…
8320 LOT more robust and spec-compliant with the SVG features that were
8321 supported in the C-only version.&lt;/p&gt;
8322 &lt;p&gt;The C sources in librsvg are shrinking steadily. It would be
8323 incredibly awesome if someone could run some &lt;code&gt;git filter-bran…
8324 with the &lt;a href="https://github.com/cgag/loc"&gt;&lt;code&gt;loc&lt;…
8325 lines vs. commits over time.&lt;/p&gt;</content><category term="misc"></…
8326 access it &lt;a href="https://gitlab.gnome.org/GNOME/librsvg"&gt;here&lt…
8327 &lt;p&gt;Gitlab allows workflows similar to Github: you can create an a…
8328 there, fork the librsvg repository, file bug reports, create merge
8329 requests... Hopefully this will make it nicer for contributors.&lt;/p&g…
8330 &lt;p&gt;In the meantime, feel free to &lt;a href="https://gitlab.gnome.…
8331 access it &lt;a href="https://gitlab.gnome.org/GNOME/librsvg"&gt;here&lt…
8332 &lt;p&gt;Gitlab allows workflows similar to Github: you can create an a…
8333 there, fork the librsvg repository, file bug reports, create merge
8334 requests... Hopefully this will make it nicer for contributors.&lt;/p&g…
8335 &lt;p&gt;In the meantime, feel free to &lt;a href="https://gitlab.gnome.…
8336 &lt;p&gt;This is a huge improvement for GNOME's development infrastructu…
8337 Thanks to Carlos Soriano, Andrea Veri, Philip Chimento, Alberto Ruiz,
8338 and all the people that made the move to Gitlab possible.&lt;/p&gt;</con…
8339 C code that implements SVG's &lt;code&gt;&amp;lt;text&amp;gt;&lt;/code&g…
8340 been replacing the little parsers in librsvg with Rust code.&lt;/p&gt;
8341 &lt;p&gt;And these days, the lack of string slices in C is bothering me …
8342 lot&lt;/em&gt;.&lt;/p&gt;
8343 &lt;h1&gt;What …&lt;/h1&gt;</summary><content type="html">&lt;p&gt;Por…
8344 C code that implements SVG's &lt;code&gt;&amp;lt;text&amp;gt;&lt;/code&g…
8345 been replacing the little parsers in librsvg with Rust code.&lt;/p&gt;
8346 &lt;p&gt;And these days, the lack of string slices in C is bothering me …
8347 lot&lt;/em&gt;.&lt;/p&gt;
8348 &lt;h1&gt;What if...&lt;/h1&gt;
8349 &lt;p&gt;It feels like it should be easy to just write something like&lt…
8350 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
8351 &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char…
8352 &lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;len…
8353 &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="n"&gt;StringSlice&l…
8354 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
8355
8356 &lt;p&gt;And then a whole family of functions. The starting point, wher…
8357 slice a whole string:&lt;/p&gt;
8358 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
8359 &lt;span class="nf"&gt;make_slice_from_string&lt;/span&gt; &lt;span clas…
8360 &lt;span class="p"&gt;{&lt;/span&gt;
8361 &lt;span class="n"&gt;StringSlice&lt;/span&gt; &lt;span class="n"&gt…
8362
8363 &lt;span class="n"&gt;assert&lt;/span&gt; &lt;span class="p"&gt;(&lt…
8364
8365 &lt;span class="n"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;.&lt;/…
8366 &lt;span class="n"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;.&lt;/…
8367 &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;slic…
8368 &lt;span class="p"&gt;}&lt;/span&gt;
8369 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
8370
8371 &lt;p&gt;But that wouldn't keep track of the lifetime of the original st…
8372 Okay, this is C, so you are used to keeping track of that yourself.&lt;/…
8373 &lt;p&gt;Onwards. Substrings?&lt;/p&gt;
8374 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
8375 &lt;span class="nf"&gt;make_sub_slice&lt;/span&gt;&lt;span class="p"&gt;…
8376 &lt;span class="p"&gt;{&lt;/span&gt;
8377 &lt;span class="n"&gt;StringSlice&lt;/span&gt; &lt;span class="n"&gt…
8378
8379 &lt;span class="n"&gt;assert&lt;/span&gt; &lt;span class="p"&gt;(&lt…
8380 &lt;span class="n"&gt;assert&lt;/span&gt; &lt;span class="p"&gt;(&lt…
8381 &lt;span class="cm"&gt;/* The su…
8382 &lt;span class="n"&gt;sub&lt;/span&gt;&lt;span class="p"&gt;.&lt;/sp…
8383 &lt;span class="n"&gt;sub&lt;/span&gt;&lt;span class="p"&gt;.&lt;/sp…
8384 &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;sub&…
8385 &lt;span class="p"&gt;}&lt;/span&gt;
8386 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
8387
8388 &lt;p&gt;Then you could write a million wrappers for &lt;code&gt;g_strsp…
8389 friends, or equivalents to them, to give you slices instead of C
8390 strings. But then:&lt;/p&gt;
8391 &lt;ul&gt;
8392 &lt;li&gt;
8393 &lt;p&gt;You have to keep track of lifetimes yourself.&lt;/p&gt;
8394 &lt;/li&gt;
8395 &lt;li&gt;
8396 &lt;p&gt;You have to wrap every function that returns a plain "&lt;code&…
8397 &lt;/li&gt;
8398 &lt;li&gt;
8399 &lt;p&gt;... and every function that takes a plain "&lt;code&gt;char *&…
8400 without a length parameter, because...&lt;/p&gt;
8401 &lt;/li&gt;
8402 &lt;li&gt;
8403 &lt;p&gt;You &lt;strong&gt;CANNOT&lt;/strong&gt; take &lt;code&gt;slice.…
8404 expects a plain "&lt;code&gt;char *&lt;/code&gt;", because your slice…
8405 nul terminator (the &lt;code&gt;'\0&lt;/code&gt; byte at the end of a …
8406 what kills the whole plan.&lt;/p&gt;
8407 &lt;/li&gt;
8408 &lt;/ul&gt;
8409 &lt;p&gt;Even if you had a helper library that implements C string slices
8410 like that, you would have a mismatch every time you needed to call a C
8411 function that expects a conventional C string in the form of a
8412 "&lt;code&gt;char *&lt;/code&gt;". &lt;em&gt;You need to put a nul ter…
8413 only have a slice, you need to &lt;em&gt;allocate memory&lt;/em&gt;, cop…
8414 it, and slap a 0 byte at the end. &lt;em&gt;Then&lt;/em&gt; you can pas…
8415 function that expects a normal C string.&lt;/p&gt;
8416 &lt;p&gt;There is hacky C code that needs to pass a substring to another
8417 function, so it &lt;em&gt;overwrites the byte after the substring with a…
8418 passes the substring, and &lt;em&gt;overwrites the byte back&lt;/em&gt;.…
8419 horrible, and doesn't work with strings that live in read-only
8420 memory. But that's the best that C lets you do.&lt;/p&gt;
8421 &lt;p&gt;I'm very happy with string slices in Rust, which work exactly l…
8422 &lt;code&gt;StringSlice&lt;/code&gt; above, but &lt;code&gt;&amp;amp;str…
8423 everything knows how to handle it.&lt;/p&gt;
8424 &lt;p&gt;The &lt;code&gt;glib-rs&lt;/code&gt; crate has conversion trait…
8425 slices into C, and vice-versa. We alredy saw some of those in the
8426 blog post about &lt;a href="https://people.gnome.org/~federico/blog/how-…
8427 &lt;h1&gt;Sizes of things&lt;/h1&gt;
8428 &lt;p&gt;Rust uses &lt;code&gt;usize&lt;/code&gt; to specify the size of…
8429 integer; 32 bits on 32-bit machines, and 64 bits on 64-bit machines;
8430 it's like C's &lt;code&gt;size_t&lt;/code&gt;.&lt;/p&gt;
8431 &lt;p&gt;In the Glib/C world, we have an assortment of types to represen…
8432 sizes of things:&lt;/p&gt;
8433 &lt;ul&gt;
8434 &lt;li&gt;
8435 &lt;p&gt;&lt;code&gt;gsize&lt;/code&gt;, the same as &lt;code&gt;size_t&…
8436 &lt;/li&gt;
8437 &lt;li&gt;
8438 &lt;p&gt;&lt;code&gt;gssize&lt;/code&gt;, a signed integer of the same s…
8439 okay if used to represent a negative offset, and &lt;em&gt;really funk…
8440 the Glib functions like
8441 &lt;code&gt;g_string_new_len (const char *str, gssize len)&lt;/co…
8442 means "call &lt;code&gt;strlen(str)&lt;/code&gt; for me because I'm to…
8443 length myself".&lt;/p&gt;
8444 &lt;/li&gt;
8445 &lt;li&gt;
8446 &lt;p&gt;&lt;code&gt;int&lt;/code&gt; - broken, as in libxml2, but we ca…
8447 64-bit machines, an &lt;code&gt;int&lt;/code&gt; to specify a length m…
8448 objects bigger than 2 GB.&lt;/p&gt;
8449 &lt;/li&gt;
8450 &lt;li&gt;
8451 &lt;p&gt;&lt;code&gt;long&lt;/code&gt; - marginally better than &lt;code…
8452 of actually being the same size as &lt;code&gt;size_t&lt;/code&gt;, bu…
8453 Probably okay for negative offsets; problematic for sizes which
8454 should really be unsigned.&lt;/p&gt;
8455 &lt;/li&gt;
8456 &lt;li&gt;
8457 &lt;p&gt;etc.&lt;/p&gt;
8458 &lt;/li&gt;
8459 &lt;/ul&gt;
8460 &lt;p&gt;I'm not sure how old &lt;code&gt;size_t&lt;/code&gt; is in the …
8461 can't have been there since the beginning of time &amp;mdash; otherwise
8462 people wouldn't have been using &lt;code&gt;int&lt;/code&gt; to specify …
8463 called "&lt;a href="http://www.greaterthancode.com/podcast/054-code-hosp…
8464 &lt;a href="http://www.nadiaodunayo.com/"&gt;Nadia Odunayo&lt;/a&gt;. …
8465 &lt;p&gt;Nadia talks about thinking of how to make people comfortable in…
8466 code and in your team/organization/etc., and does it in terms of
8467 thinking about host/guest relationships. Have you ever …&lt;/p&gt;</s…
8468 called "&lt;a href="http://www.greaterthancode.com/podcast/054-code-hosp…
8469 &lt;a href="http://www.nadiaodunayo.com/"&gt;Nadia Odunayo&lt;/a&gt;. …
8470 &lt;p&gt;Nadia talks about thinking of how to make people comfortable in…
8471 code and in your team/organization/etc., and does it in terms of
8472 thinking about host/guest relationships. Have you ever stayed in an
8473 AirBnB where the host carefully prepares some "welcome instructions"
8474 for you, or puts little notes in their apartment to orient/guide you,
8475 or gives you basic guidance around their city's transportation system?
8476 We can think in similar ways of how to make people comfortable with
8477 code bases.&lt;/p&gt;
8478 &lt;p&gt;This of course hit me on so many levels, because in the past I'…
8479 written about analogies between software and urbanism/architecture.
8480 &lt;a href="https://people.gnome.org/~federico/docs/software-with-qwan/i…
8481 talks about Christopher Alexander's architecture/urbanism patterns in
8482 the context of software, based on &lt;a href="http://dreamsongs.com/"&gt…
8483 and &lt;a href="http://zeta.math.utsa.edu/~yxk833/"&gt;Nikos Salingaros&…
8484 process. &lt;a href="https://people.gnome.org/~federico/blog/legacy-sys…
8485 how GNOME evolved parts of its user-visible software, and makes an
8486 analogy with cities that evolve over time instead of being torn down
8487 and rebuilt, based on urbanism ideas by Jane Jacobs, and
8488 architecture/construction ideas by Stewart Brand.&lt;/p&gt;
8489 &lt;p&gt;I definitely intend to do some thinking on Nadia's ideas for Co…
8490 Hospitality and try to connect them with this.&lt;/p&gt;
8491 &lt;p&gt;In the meantime, I've just rewritten the &lt;a href="https://gi…
8492 gnome-class&lt;/a&gt; to make it suitable as an
8493 introduction to hacking there.&lt;/p&gt;</content><category term="misc">…
8494 Hackfest&lt;/a&gt;, kindly hosted at the &lt;a href="https://kinvolk.io/…
8495 This is in a &lt;em&gt;great&lt;/em&gt; location, half a block away from…
8496 Tor&lt;/a&gt; station, right at the entrance of the trendy Kreuzberg
8497 neighborhood — full of interesting people, incredible graffitti, and
8498 good …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Last weekend I…
8499 Hackfest&lt;/a&gt;, kindly hosted at the &lt;a href="https://kinvolk.io/…
8500 This is in a &lt;em&gt;great&lt;/em&gt; location, half a block away from…
8501 Tor&lt;/a&gt; station, right at the entrance of the trendy Kreuzberg
8502 neighborhood — full of interesting people, incredible graffitti, and
8503 good, diverse food.&lt;/p&gt;
8504 &lt;p&gt;&lt;a href="https://people.gnome.org/~federico/blog/images/kott…
8505 &lt;h1&gt;My goals for the hackfest&lt;/h1&gt;
8506 &lt;p&gt;Over the past weeks I had been converting &lt;a href="https://g…
8507 from the old &lt;a href="https://github.com/nikomatsakis/lalrpop/"&gt;la…
8508 Macros framework for Rust, or &lt;code&gt;proc-macro2&lt;/code&gt; for s…
8509 parser for the gnome-class mini-language needs to be rewritten from
8510 being specified in a lalrpop grammar, to using Rust's &lt;a href="https:…
8511 crate.&lt;/p&gt;
8512 &lt;p&gt;Syn is a parser for Rust source code, written as a set of &lt;a…
8513 combinator parser macros. For gnome-class we want to extend the Rust
8514 language with a few conveniences to be able to specify GObject
8515 classes/subclasses, methods, signals, properties, interfaces, and all
8516 the goodies that GObject Introspection would expect.&lt;/p&gt;
8517 &lt;p&gt;During the hackfest, &lt;a href="https://github.com/alexcrichto…
8518 kindly took over my baby steps in compiler writing and made everything
8519 much more functional. It was invaluable to have him there to reason
8520 about macro hygiene (we &lt;em&gt;are&lt;/em&gt; generating an unhygieni…
8521 in the quoting system, and general Rust-iness of the whole thing.&lt;/p&…
8522 &lt;p&gt;I was also able to talk to &lt;a href="https://coaxion.net/blog…
8523 writing GObjects in Rust by hand, for GStreamer, and what sort of
8524 things gnome-class could make easier. Sebastian knows GObject very
8525 well, and has been doing awesome work in making it easy to derive
8526 GObjects by hand in Rust, without lots of boilerplate — something with
8527 which gnome-class can certainly help.&lt;/p&gt;
8528 &lt;p&gt;I was also looking forward to talking again with &lt;a href="ht…
8529 Gomez&lt;/a&gt;, one of the maintainers of &lt;a href="http://gtk-rs.org…
8530 does so much work in the Rust ecosystem that I can't believe he has
8531 time for it all.&lt;/p&gt;
8532 &lt;p&gt;&lt;img alt="Graffitti heads" src="https://people.gnome.org/~fe…
8533 &lt;h1&gt;Extend the Rust language for GObject? Like Vala?&lt;/h1&gt;
8534 &lt;p&gt;Yeah, pretty much.&lt;/p&gt;
8535 &lt;p&gt;Except that instead of a wholly new language, we use Rust as-is…
8536 we just add syntactic constructs that make it easy to write GObjects
8537 without boilerplate. For example, this works right now:&lt;/p&gt;
8538 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
8539
8540 &lt;span class="k"&gt;extern&lt;/span&gt;&lt;span class="w"&gt; &lt;/spa…
8541
8542 &lt;span class="cp"&gt;#[macro_use]&lt;/span&gt;&lt;span class="w"&gt;&l…
8543 &lt;span class="k"&gt;extern&lt;/span&gt;&lt;span class="w"&gt; &lt;/spa…
8544 &lt;span class="k"&gt;use&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&g…
8545
8546 &lt;span class="n"&gt;gobject_gen&lt;/span&gt;&lt;span class="o"&gt;!&lt…
8547 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// Derives…
8548 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;class&lt;/s…
8549 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&…
8550
8551 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;impl&lt;/sp…
8552 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// non…
8553 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;pub&lt;…
8554 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&…
8555 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/s…
8556
8557 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;virtua…
8558 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&…
8559 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/s…
8560 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&…
8561
8562 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// Inherit…
8563 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;class&lt;/s…
8564 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&…
8565
8566 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;impl&lt;/sp…
8567 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// ove…
8568 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// may…
8569 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;virtua…
8570 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&…
8571 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/s…
8572 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&…
8573 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
8574
8575 &lt;span class="cp"&gt;#[test]&lt;/span&gt;&lt;span class="w"&gt;&lt;/sp…
8576 &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;test&lt;/sp…
8577 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/sp…
8578 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/sp…
8579
8580 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="fm"&gt;assert!&lt…
8581 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="fm"&gt;assert!&lt…
8582 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="fm"&gt;assert!&lt…
8583 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="fm"&gt;assert!&lt…
8584 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
8585 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
8586
8587 &lt;p&gt;This generates a little boatload of &lt;a href="https://people.…
8588 including a good number of &lt;code&gt;unsafe&lt;/code&gt; calls to GObj…
8589 like &lt;code&gt;g_type_register_static_simple()&lt;/code&gt;. It also …
8590 traits and paraphernalia that Glib-rs would create for the Rust
8591 binding of a normal GObject written in C.&lt;/p&gt;
8592 &lt;p&gt;The idea is that from the outside world, your generated GObject
8593 classes are indistinguishable from GObjects implemented in C.&lt;/p&gt;
8594 &lt;p&gt;&lt;em&gt;The idea is to write GObject libraries in a better la…
8595 which can then be consumed from language bindings.&lt;/em&gt;&lt;/p&gt;
8596 &lt;h2&gt;Current status of gnome-class&lt;/h2&gt;
8597 &lt;p&gt;Up to about two weeks before the hackfest, the syntax for this
8598 mini-language was totally ad-hoc and limited. After a very productive
8599 &lt;a href="https://mail.gnome.org/archives/rust-list/2017-October/msg00…
8600 syntax that definitely looks more Rust-like. It is also easier to
8601 implement, since the Rust parser in syn can be mostly reused as-is, or
8602 pruned down for the parts where we only support GObject-like methods,
8603 and not all the Rust bells and whistles (generics, lifetimes, trait
8604 bounds).&lt;/p&gt;
8605 &lt;p&gt;Gnome-class supports deriving classes directly from the basic G…
8606 or from other GObject subclasses in the style of &lt;a href="https://git…
8607 &lt;p&gt;You can define virtual and non-virtual methods. You can overri…
8608 virtual methods from your superclasses.&lt;/p&gt;
8609 &lt;p&gt;Not all argument types are supported. In the end we should sup…
8610 argument types which are convertible from Rust to C types. We need to
8611 finish figuring out the annotations for ownership transfer of
8612 references.&lt;/p&gt;
8613 &lt;p&gt;We don't support GObject signals yet; I think that's my next ta…
8614 &lt;p&gt;We don't support GObject properties yet.&lt;/p&gt;
8615 &lt;p&gt;We don't support defining new GType interfaces yet, but it is p…
8616 It should be easy to support implementing existing interfaces, as it
8617 is pretty much the same as implementing a subclass.&lt;/p&gt;
8618 &lt;p&gt;The best way to see what works right now is probably to &lt;a h…
8619 examples&lt;/a&gt;, which also work as tests.&lt;/p&gt;
8620 &lt;h1&gt;Digression on macro hygiene&lt;/h1&gt;
8621 &lt;p&gt;Rust macros are &lt;em&gt;hygienic&lt;/em&gt;, unlike C macros …
8622 textual substitution. That is, names declared inside Rust macros will
8623 not clash with names in the calling code.&lt;/p&gt;
8624 &lt;p&gt;One peculiar thing about gnome-class is that the user gives us …
8625 names, like a class name &lt;code&gt;Foo&lt;/code&gt; and some things in…
8626 method name &lt;code&gt;bar&lt;/code&gt;, and a signal &lt;code&gt;baz&l…
8627 From there we want to generate a bunch of boilerplate for GObject
8628 registration and implementaiton. Some of the generated names in that
8629 boilerplate would be&lt;/p&gt;
8630 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
8631 &lt;span class="n"&gt;FooClass&lt;/span&gt; &lt;span class="o"&g…
8632 &lt;span class="n"&gt;Foo&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&…
8633 &lt;span class="n"&gt;Foo&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&…
8634 &lt;span class="n"&gt;Foo&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&…
8635 &lt;span class="n"&gt;foo_bar&lt;/span&gt;&lt;span class="p"&gt;()&lt;/s…
8636 &lt;span class="n"&gt;foo_get_type&lt;/span&gt;&lt;span class="p"&gt;()&…
8637 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
8638
8639 &lt;p&gt;However, if we want to actually generate those names inside our
8640 gnome-class macro &lt;em&gt;and make them visible to the caller&lt;/em&g…
8641 so &lt;em&gt;unhygienically&lt;/em&gt;. Alex started started a &lt;a hr…
8642 on macro hygiene&lt;/a&gt;, so expect some news in the Rust world
8643 soon.&lt;/p&gt;
8644 &lt;p&gt;TL;DR: there is a difference between a &lt;em&gt;code generator…
8645 gnome-class mostly intends to be, and a &lt;em&gt;macro system&lt;/em&gt…
8646 an aid in typing repetitive code.&lt;/p&gt;
8647 &lt;p&gt;&lt;img alt="Fuck wars" src="https://people.gnome.org/~federico…
8648 &lt;h1&gt;People for whom to to be thankful&lt;/h1&gt;
8649 &lt;p&gt;During the hackfest, &lt;a href="http://blog.nirbheek.in/"&gt;N…
8650 from Autotools to the Meson build system, and dealing with Rust
8651 peculiarities along the way. This is exactly what I needed! Thanks,
8652 Nirbheek!&lt;/p&gt;
8653 &lt;p&gt;&lt;a href="https://coaxion.net/blog/"&gt;Sebastian&lt;/a&gt; a…
8654 internals and how to use them from the Rust side.&lt;/p&gt;
8655 &lt;p&gt;&lt;a href="http://zee-nix.blogspot.com/"&gt;Zeeshan&lt;/a&gt; …
8656 ramen, Greek, excellent pizza... My stomach is definitely thankful.&lt;/…
8657 &lt;h1&gt;Berlin&lt;/h1&gt;
8658 &lt;p&gt;I love Berlin. It is a cosmopolitan, progressive, LGBTQ-friend…
8659 city, with lots of things to do, vast distances to be traveled, with
8660 good public transport and bike lanes, diverse food to be eaten along
8661 the way...&lt;/p&gt;
8662 &lt;p&gt;But damnit, it's also cold at this time of the year. I don't t…
8663 the weather was ever above 10°C while we were there, and mostly in a
8664 constant state of not-quite-rain. This is much different from the Berlin
8665 in the summer that I knew!&lt;/p&gt;
8666 &lt;p&gt;&lt;a href="https://people.gnome.org/~federico/blog/images/kimc…
8667 &lt;p&gt;This is my third time visiting Berlin. The first one was durin…
8668 Desktop Summit in 2011, and the second one was when my family and I
8669 visited the city two years ago. It is a city that I would definitely
8670 like to know better.&lt;/p&gt;
8671 &lt;h1&gt;Thanks to the GNOME Foundation...&lt;/h1&gt;
8672 &lt;p&gt;... for sponsoring my travel and accomodation during the hackfe…
8673 &lt;p&gt;&lt;img alt="Sponsored by the GNOME Foundation" src="https://pe…
8674 Emacs pop up a desktop-wide notification when a compilation finishes,
8675 i.e. after "&lt;code&gt;M-x compile&lt;/code&gt;" is done. Let's see if…
8676 wasting time in the web when I launch a compilation.&lt;/p&gt;
8677 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
8678 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;append …
8679 Emacs pop up a desktop-wide notification when a compilation finishes,
8680 i.e. after "&lt;code&gt;M-x compile&lt;/code&gt;" is done. Let's see if…
8681 wasting time in the web when I launch a compilation.&lt;/p&gt;
8682 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
8683 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;append&…
8684 &lt;span class="o"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"…
8685
8686 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;defun&lt;/spa…
8687 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;call-proces…
8688 &lt;span class="s"&gt;&amp;quot;-t&amp;quot;&lt;/span&gt; &lt;sp…
8689 &lt;span class="s"&gt;&amp;quot;-i&amp;quot;&lt;/span&gt; &lt;sp…
8690 &lt;span class="s"&gt;&amp;quot;Compilation finished in Emacs&am…
8691 &lt;span class="nv"&gt;status&lt;/span&gt;&lt;span class="p"&gt;…
8692 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content><category term="misc"></c…
8693 &lt;p&gt;Now let's get on and see how glib-rs handles boxed types.&lt;/p…
8694 &lt;h1&gt;Boxed types?&lt;/h1&gt;
8695 &lt;p&gt;Let's say you are given a sealed cardboard box with &lt;em&gt;s…
8696 can't know what's inside. You can just pass it on to someone else …&l…
8697 &lt;p&gt;Now let's get on and see how glib-rs handles boxed types.&lt;/p…
8698 &lt;h1&gt;Boxed types?&lt;/h1&gt;
8699 &lt;p&gt;Let's say you are given a sealed cardboard box with &lt;em&gt;s…
8700 can't know what's inside. You can just pass it on to someone else, or
8701 burn it. And since computers are magic duplication machines, you may
8702 want to copy the box and its contents... and maybe some day you will
8703 get around to opening it.&lt;/p&gt;
8704 &lt;p&gt;That's a boxed type. You get a pointer to &lt;em&gt;something&…
8705 what's inside. You can just pass it on to someone else, burn it — I
8706 mean, free it — or since computers are magic, copy the pointer and
8707 whatever it points to.&lt;/p&gt;
8708 &lt;p&gt;That's exactly the API for boxed types.&lt;/p&gt;
8709 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
8710 &lt;span class="k"&gt;typedef&lt;/span&gt; &lt;span class="kt"&gt;void&l…
8711
8712 &lt;span class="n"&gt;GType&lt;/span&gt; &lt;span class="nf"&gt;g_boxed_…
8713 &lt;span class="n"&gt;GBoxedCopyFunc…
8714 &lt;span class="n"&gt;GBoxedFreeFunc…
8715 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
8716
8717 &lt;h2&gt;Simple copying, simple freeing&lt;/h2&gt;
8718 &lt;p&gt;Imagine you have a color...&lt;/p&gt;
8719 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
8720 &lt;span class="n"&gt;guchar&lt;/span&gt; &lt;span class="n"&gt;r&lt…
8721 &lt;span class="n"&gt;guchar&lt;/span&gt; &lt;span class="n"&gt;g&lt…
8722 &lt;span class="n"&gt;guchar&lt;/span&gt; &lt;span class="n"&gt;b&lt…
8723 &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="n"&gt;Color&lt;/spa…
8724 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
8725
8726 &lt;p&gt;If you had a pointer to a Color, how would you copy it? Easy:&…
8727 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
8728 &lt;span class="p"&gt;{&lt;/span&gt;
8729 &lt;span class="n"&gt;Color&lt;/span&gt; &lt;span class="o"&gt;*&lt;…
8730 &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span…
8731 &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;b&lt…
8732 &lt;span class="p"&gt;}&lt;/span&gt;
8733 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
8734
8735 &lt;p&gt;That is, allocate a new &lt;code&gt;Color&lt;/code&gt;, and ess…
8736 contents.&lt;/p&gt;
8737 &lt;p&gt;And to free it? A simple &lt;code&gt;g_free()&lt;/code&gt; wor…
8738 things that need to be freed individually.&lt;/p&gt;
8739 &lt;h2&gt;Complex copying, complex freeing&lt;/h2&gt;
8740 &lt;p&gt;And if we had a color with a name?&lt;/p&gt;
8741 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
8742 &lt;span class="n"&gt;guchar&lt;/span&gt; &lt;span class="n"&gt;r&lt…
8743 &lt;span class="n"&gt;guchar&lt;/span&gt; &lt;span class="n"&gt;g&lt…
8744 &lt;span class="n"&gt;guchar&lt;/span&gt; &lt;span class="n"&gt;b&lt…
8745 &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;…
8746 &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="n"&gt;ColorWithName…
8747 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
8748
8749 &lt;p&gt;We can't just &lt;code&gt;*a = *b&lt;/code&gt; here, as we actu…
8750 &lt;code&gt;name&lt;/code&gt;. Okay:&lt;/p&gt;
8751 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
8752 &lt;span class="p"&gt;{&lt;/span&gt;
8753 &lt;span class="n"&gt;ColorWithName&lt;/span&gt; &lt;span class="o"&…
8754 &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&…
8755 &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&…
8756 &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&…
8757 &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&…
8758 &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;b&lt…
8759 &lt;span class="p"&gt;}&lt;/span&gt;
8760 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
8761
8762 &lt;p&gt;The corresponding &lt;code&gt;free_color_with_name()&lt;/code&g…
8763 &lt;code&gt;g_free(b)&lt;/code&gt;, of course.&lt;/p&gt;
8764 &lt;h1&gt;Glib-rs and boxed types&lt;/h1&gt;
8765 &lt;p&gt;Let's look at this by parts. First, a &lt;a href="https://gith…
8766 trait&lt;/a&gt; to define the basic API to manage the
8767 memory of boxed types. This is what defines the &lt;code&gt;copy&lt;/co…
8768 functions, like above.&lt;/p&gt;
8769 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
8770 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;unsafe&lt;/…
8771 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;unsafe&lt;/…
8772 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
8773 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
8774
8775 &lt;p&gt;Second, the &lt;a href="https://github.com/gtk-rs/glib/blob/f0a…
8776 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
8777 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;inner&lt;/s…
8778 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;_dummy&lt;/…
8779 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
8780 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
8781
8782 &lt;p&gt;This struct is generic over &lt;code&gt;T&lt;/code&gt;, the act…
8783 wrapping, and &lt;code&gt;MM&lt;/code&gt;, something which must implemen…
8784 &lt;code&gt;BoxedMemoryManager&lt;/code&gt; trait.&lt;/p&gt;
8785 &lt;p&gt;Inside, it stores &lt;code&gt;inner&lt;/code&gt;, an &lt;code&g…
8786 The &lt;code&gt;_dummy: PhantomData&amp;lt;MM&amp;gt;&lt;/code&gt; is a…
8787 struct doesn't actually store a memory manager, it acts as if it does
8788 — it does not concern us here.&lt;/p&gt;
8789 &lt;h2&gt;The &lt;em&gt;actual&lt;/em&gt; representation of boxed data&l…
8790 &lt;p&gt;Let's look at that &lt;a href="https://github.com/gtk-rs/glib/b…
8791 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
8792 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Native&lt;/…
8793 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ForeignOwne…
8794 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ForeignBorr…
8795 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
8796 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
8797
8798 &lt;p&gt;We have three cases:&lt;/p&gt;
8799 &lt;ul&gt;
8800 &lt;li&gt;
8801 &lt;p&gt;&lt;code&gt;Native(Box&amp;lt;T&amp;gt;)&lt;/code&gt; - this bo…
8802 know everything about it!&lt;/p&gt;
8803 &lt;/li&gt;
8804 &lt;li&gt;
8805 &lt;p&gt;&lt;code&gt;ForeignOwned(*mut T)&lt;/code&gt; - this boxed valu…
8806 we own it now. We will have to free it when we are done with it.&lt;/…
8807 &lt;/li&gt;
8808 &lt;li&gt;
8809 &lt;p&gt;&lt;code&gt;ForeignBorrowed(*mut T)&lt;/code&gt; - this boxed v…
8810 outside, but we are just borrowing it temporarily: we &lt;strong&gt;do…
8811 free it when we are done with it.&lt;/p&gt;
8812 &lt;/li&gt;
8813 &lt;/ul&gt;
8814 &lt;p&gt;For example, if we look at the &lt;a href="https://github.com/g…
8815 trait&lt;/a&gt; for the &lt;code&gt;Boxed&lt;/code&gt; struct, we will i…
8816 calls the &lt;code&gt;BoxedMemoryManager::free()&lt;/code&gt; &lt;strong…
8817 &lt;code&gt;ForeignOwned&lt;/code&gt; value:&lt;/p&gt;
8818 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
8819 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span…
8820 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;unsafe&…
8821 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&…
8822 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt…
8823 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&l…
8824 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/s…
8825 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&…
8826 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
8827 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
8828
8829 &lt;p&gt;If we had a &lt;code&gt;Native(Box&amp;lt;T&amp;gt;)&lt;/code&g…
8830 and Rust knows how to &lt;code&gt;Drop&lt;/code&gt; its own &lt;code&gt;…
8831 allocated in the heap).&lt;/p&gt;
8832 &lt;p&gt;But for external resources, we must tell Rust how to manage the…
8833 Again: in the case where the Rust side owns the reference to the
8834 external boxed data, we have a &lt;code&gt;ForeignOwned&lt;/code&gt; and…
8835 &lt;code&gt;free()&lt;/code&gt;ing it; in the case where the Rust side i…
8836 data temporarily, we have a &lt;code&gt;ForeignBorrowed&lt;/code&gt; and…
8837 we are done.&lt;/p&gt;
8838 &lt;h2&gt;Copying&lt;/h2&gt;
8839 &lt;p&gt;When do we have to copy a boxed value? For example, when we tr…
8840 from Rust to Glib with full transfer of ownership, i.e. the
8841 &lt;a href="https://github.com/gtk-rs/glib/blob/f0a2aae96162fd628fb0e3ee…
8842 before&lt;/a&gt;. This is how that trait method is
8843 implemented for &lt;code&gt;Boxed&lt;/code&gt;:&lt;/p&gt;
8844 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
8845 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span…
8846 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;use&lt;…
8847 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;let&lt…
8848 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Nat…
8849 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;For…
8850 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;};&lt;/…
8851 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;unsafe&…
8852 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&…
8853 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
8854 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
8855
8856 &lt;p&gt;See the &lt;code&gt;MM:copy(ptr)&lt;/code&gt; in the last line?…
8857 happens. The lines above just get the appropriate pointer to the data
8858 data from the &lt;code&gt;AnyBox&lt;/code&gt; and cast it.&lt;/p&gt;
8859 &lt;p&gt;There is extra boilerplate in &lt;code&gt;boxed.rs&lt;/code&gt;…
8860 mostly a bunch of trait implementations to copy the boxed data at the
8861 appropriate times (e.g. the &lt;code&gt;FromGlibPtrNone&lt;/code&gt; tra…
8862 implementation of the &lt;code&gt;Deref&lt;/code&gt; trait to get to the…
8863 / AnyBox&lt;/code&gt; easily, etc. The trait implementations are there …
8864 make it as convenient as possible to handle &lt;code&gt;Boxed&lt;/code&g…
8865 &lt;h2&gt;Who implements BoxedMemoryManager?&lt;/h2&gt;
8866 &lt;p&gt;Up to now, we have seen things like the implementation of &lt;c…
8867 &lt;code&gt;Boxed&lt;/code&gt;, which uses &lt;code&gt;BoxedMemoryManage…
8868 implementation of &lt;code&gt;ToGlibPtr&lt;/code&gt; which uses &lt;code…
8869 &lt;p&gt;But those are just the trait's "abstract" methods, so to speak.…
8870 actually implements them?&lt;/p&gt;
8871 &lt;p&gt;Glib-rs has a general-purpose macro to wrap Glib types. It can…
8872 boxed types, shared pointer types, and GObjects. For now we will just
8873 look at boxed types.&lt;/p&gt;
8874 &lt;p&gt;Glib-rs comes with a macro, &lt;a href="http://gtk-rs.org/docs/…
8875 different ways. You can use it to automatically write the boilerplate
8876 for a boxed type like this:&lt;/p&gt;
8877 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
8878 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;pub&lt;/spa…
8879
8880 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;match&lt;/s…
8881 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;copy&lt…
8882 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;free&lt…
8883 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;get_typ…
8884 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&…
8885 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
8886 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
8887
8888 &lt;p&gt;This expands to an internal
8889 &lt;a href="https://github.com/gtk-rs/glib/blob/f0a2aae96162fd628fb0e3ee…
8890 things. We will only look at particularly interesting bits.&lt;/p&gt;
8891 &lt;p&gt;First, the macro creates a newtype around a tuple with 1) the a…
8892 data type you want to box, and 2) a memory manager. In the example
8893 above, the newtype would be called &lt;code&gt;Color&lt;/code&gt;, and i…
8894 &lt;code&gt;ffi:Color&lt;/code&gt; (say, a C struct).&lt;/p&gt;
8895 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
8896 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
8897
8898 &lt;p&gt;Aha! And that &lt;code&gt;MemoryManager&lt;/code&gt;? The mac…
8899 type:&lt;/p&gt;
8900 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
8901 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
8902
8903 &lt;p&gt;Then it &lt;a href="https://github.com/gtk-rs/glib/blob/f0a2aae…
8904 &lt;code&gt;MemoryManager&lt;/code&gt; struct:&lt;/p&gt;
8905 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
8906 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cp"&gt;#[…
8907 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;uns…
8908 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cp"&g…
8909 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&l…
8910
8911 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cp"&gt;#[…
8912 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;uns…
8913 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cp"&g…
8914 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&l…
8915 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/s…
8916 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
8917
8918 &lt;p&gt;There! &lt;em&gt;This&lt;/em&gt; is where the &lt;code&gt;copy…
8919 on the bits of code with which you invoked the macro. In the call to
8920 &lt;code&gt;glib_wrapper!()&lt;/code&gt; we had this:&lt;/p&gt;
8921 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
8922 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;free&lt…
8923 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
8924
8925 &lt;p&gt;In the impl aboe, the &lt;code&gt;$copy_expr&lt;/code&gt; will …
8926 &lt;code&gt;ffi::color_copy(mut_override(ptr))&lt;/code&gt; and &lt;code…
8927 &lt;code&gt;ffi::color_free(ptr)&lt;/code&gt;, which defines our impleme…
8928 manager for our &lt;code&gt;Color&lt;/code&gt; boxed type.&lt;/p&gt;
8929 &lt;h2&gt;Zero-sized what?&lt;/h2&gt;
8930 &lt;p&gt;Within the macro's definition, let's look again at the definiti…
8931 our boxed type and the memory manager object that actually implements
8932 the &lt;code&gt;BoxedMemoryManager&lt;/code&gt; trait. Here is what the…
8933 to with our &lt;code&gt;Color&lt;/code&gt; example:&lt;/p&gt;
8934 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
8935
8936 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;pub&lt;…
8937
8938 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;impl&lt…
8939 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;uns…
8940 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;uns…
8941 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/s…
8942 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
8943
8944 &lt;p&gt;Here, &lt;code&gt;MemoryManager&lt;/code&gt; is a zero-sized ty…
8945 take up any space&lt;/strong&gt; in the &lt;code&gt;Color&lt;/code&gt; t…
8946 in the heap, it is really as if it contained an &lt;code&gt;ffi::Color&l…
8947 C struct we are wrapping) &lt;em&gt;and nothing else&lt;/em&gt;.&lt;/p&g…
8948 &lt;p&gt;All the knowledge about how to copy/free &lt;code&gt;ffi::Color…
8949 the compiler&lt;/strong&gt; thanks to the trait implementation. When th…
8950 expands all the macros and monomorphizes all the generic functions,
8951 the calls to &lt;code&gt;ffi::color_copy()&lt;/code&gt; and &lt;code&gt;…
8952 inlined at the appropriate spots&lt;/strong&gt;. There is no need to ha…
8953 auxiliary structures taking up space in the heap, just to store
8954 function pointers to the copy/free functions, or anything like that.&lt;…
8955 &lt;h1&gt;Next up&lt;/h1&gt;
8956 &lt;p&gt;You may have seen that our example call to &lt;code&gt;glib_wra…
8957 passed in a &lt;code&gt;ffi::color_get_type()&lt;/code&gt; function. We…
8958 how glib-rs wraps Glib's &lt;code&gt;GType&lt;/code&gt;, &lt;code&gt;GVa…
8959 getting closer and closer to being able to wrap &lt;code&gt;GObject&lt;/…
8960 &lt;p&gt;Stay tuned!&lt;/p&gt;</content><category term="misc"></category…
8961 blog&lt;/a&gt;, so they may be a bit hard to find from this new blog.
8962 Here is a list of those posts, just so they are easier to find:&lt;/p&gt;
8963 &lt;ul&gt;
8964 &lt;li&gt;&lt;a href="https://people.gnome.org/~federico/news-2016-10.ht…
8965 &lt;li&gt;&lt;a href="https://people.gnome.org/~federico/news-2016-10.ht…
8966 blog&lt;/a&gt;, so they may be a bit hard to find from this new blog.
8967 Here is a list of those posts, just so they are easier to find:&lt;/p&gt;
8968 &lt;ul&gt;
8969 &lt;li&gt;&lt;a href="https://people.gnome.org/~federico/news-2016-10.ht…
8970 &lt;li&gt;&lt;a href="https://people.gnome.org/~federico/news-2016-10.ht…
8971 &lt;li&gt;&lt;a href="https://people.gnome.org/~federico/news-2016-11.ht…
8972 &lt;li&gt;&lt;a href="https://people.gnome.org/~federico/news-2016-11.ht…
8973 &lt;li&gt;&lt;a href="https://people.gnome.org/~federico/news-2016-11.ht…
8974 &lt;li&gt;&lt;a href="https://people.gnome.org/~federico/news-2016-11.ht…
8975 &lt;li&gt;&lt;a href="https://people.gnome.org/~federico/news-2017-01.ht…
8976 &lt;li&gt;&lt;a href="https://people.gnome.org/~federico/news-2017-02.ht…
8977 &lt;li&gt;&lt;a href="https://people.gnome.org/~federico/news-2017-02.ht…
8978 &lt;li&gt;&lt;a href="https://people.gnome.org/~federico/news-2017-02.ht…
8979 &lt;li&gt;&lt;a href="https://people.gnome.org/~federico/news-2017-02.ht…
8980 &lt;li&gt;&lt;a href="https://people.gnome.org/~federico/news-2017-04.ht…
8981 &lt;/ul&gt;
8982 &lt;p&gt;Within this new blog, you can look for articles with the &lt;a …
8983 a detour and look at &lt;a href="https://wiki.gnome.org/Projects/GObject…
8984 seem like an obscure part of the GNOME platform, it is an absolutely
8985 vital part of it: it is what lets people write GNOME applications in
8986 any language.&lt;/p&gt;
8987 &lt;p&gt;Let's start with a …&lt;/p&gt;</summary><content type="html">…
8988 a detour and look at &lt;a href="https://wiki.gnome.org/Projects/GObject…
8989 seem like an obscure part of the GNOME platform, it is an absolutely
8990 vital part of it: it is what lets people write GNOME applications in
8991 any language.&lt;/p&gt;
8992 &lt;p&gt;Let's start with a bit of history.&lt;/p&gt;
8993 &lt;h1&gt;Brief history of language bindings in GNOME&lt;/h1&gt;
8994 &lt;p&gt;When we started GNOME in 1997, we didn't want to write &lt;em&g…
8995 C. We had some inspiration from elsewhere.&lt;/p&gt;
8996 &lt;h2&gt;Prehistory: GIMP and the Procedural Database&lt;/h2&gt;
8997 &lt;p&gt;There was already good precedent for software written in a comb…
8998 programming languages. Emacs, the flagship text editor of the
8999 GNU project, was written with a relatively small core in C, and the
9000 majority of the program in Emacs Lisp.&lt;/p&gt;
9001 &lt;p&gt;In similar fashion, we were very influenced by the design of th…
9002 which was very innovative at that time. The GIMP has a large core
9003 written in C. However, it supports plug-ins or &lt;em&gt;scripts&lt;/em…
9004 variety of languages. Initially the only scripting language available
9005 for the GIMP was Scheme.&lt;/p&gt;
9006 &lt;p&gt;The GIMP's plug-ins and scripts run as separate processes, so
9007 they don't have immediate access to the data of the image being
9008 edited, or to the core functions of the program like "paint with a
9009 brush at this location". To let plug-ins and scripts access these
9010 data and these functions, the GIMP has what it calls a
9011 Procedural Database (PDB). This is a
9012 list of functions that the core program or plug-ins wish to export.
9013 For example, there are functions like &lt;code&gt;gimp-scale-image&lt;/c…
9014 &lt;code&gt;gimp-move-layer&lt;/code&gt;. Once these functions are regi…
9015 PDB, any part of the program or plug-ins can call them. Scripts are
9016 often written to automate common tasks — for example, when one wants
9017 to adjust the contrast of photos and scale them in bulk. Scripts can
9018 call functions in the PDB easily, irrespective of the programming
9019 language they are written in.&lt;/p&gt;
9020 &lt;p&gt;We wanted to write GNOME's core libraries in C, and write a sim…
9021 Procedural Database to allow those libraries to be called from any
9022 programming language. Eventually it turned out that a PDB was not
9023 necessary, and there were better ways to go about enabling different
9024 programming languages.&lt;/p&gt;
9025 &lt;h2&gt;Enabling sane memory management&lt;/h2&gt;
9026 &lt;p&gt;GTK+ started out with a very simple scheme for memory managemen…
9027 container owned its child widgets, and so on recursively. When you
9028 freed a container, it would be responsible for freeing its children.&lt;…
9029 &lt;p&gt;However, consider what happens when a widget needs to hold a re…
9030 to another widget that is not one of its children. For example, a
9031 GtkLabel with an underlined mnemonic ("_N_ame:") needs to have a
9032 reference to the GtkEntry that should be focused when you press
9033 Alt-N. In the very earliest versions of GTK+, how to do this was
9034 undefined: C programmers were already used to having shared pointers
9035 everywhere, and they were used to being responsible for managing their
9036 memory.&lt;/p&gt;
9037 &lt;p&gt;Of course, this was prone to bugs. If you have something like&…
9038 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
9039 &lt;span class="n"&gt;GtkWidget&lt;/span&gt; &lt;span class="n"&gt;p…
9040
9041 &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;…
9042 &lt;span class="n"&gt;GtkWidget&lt;/span&gt; &lt;span class="o"&gt;*…
9043 &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="n"&gt;GtkLabel&lt;/…
9044 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
9045
9046 &lt;p&gt;then if you are writing the destructor, you may simply want to&…
9047 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
9048 &lt;span class="nf"&gt;gtk_label_free&lt;/span&gt; &lt;span class="p"&gt…
9049 &lt;span class="p"&gt;{&lt;/span&gt;
9050 &lt;span class="n"&gt;g_free&lt;/span&gt; &lt;span class="p"&gt;(&lt…
9051 &lt;span class="n"&gt;gtk_widget_free&lt;/span&gt; &lt;span class="p…
9052
9053 &lt;span class="n"&gt;free_parent_instance&lt;/span&gt; &lt;span cla…
9054 &lt;span class="p"&gt;}&lt;/span&gt;
9055 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
9056
9057 &lt;p&gt;Say you have a GtkBox with the label and its associated GtkEntr…
9058 Then, freeing the GtkBox would recursively free the label with that
9059 &lt;code&gt;gtk_label_free()&lt;/code&gt;, and then the entry with its o…
9060 the time the entry gets freed, the line
9061 &lt;code&gt;gtk_widget_free (widget_to_focus)&lt;/code&gt; has already …
9062 we get a double-free bug!&lt;/p&gt;
9063 &lt;p&gt;Madness!&lt;/p&gt;
9064 &lt;p&gt;That is, we had no idea what we were doing. Or rather, our
9065 understanding of widgets had not evolved to the point of acknowledging
9066 that a widget tree is not a simply tree, but rather a
9067 directed graph of container-child relationships, plus
9068 random-widget-to-random-widget relationships. And of course, other
9069 parts of the program &lt;em&gt;which are not even widget implementations…
9070 need to keep references to widgets and free them or not as
9071 appropriate.&lt;/p&gt;
9072 &lt;p&gt;I think Marius Vollmer was the first person to start formalizing
9073 this. He came from the world of GNU Guile, a Scheme interpreter, and
9074 so he already knew how garbage collection and seas of shared
9075 references ought to work.&lt;/p&gt;
9076 &lt;p&gt;Marius implemented reference-counting for GTK+ — that's where
9077 &lt;code&gt;gtk_object_ref()&lt;/code&gt; and &lt;code&gt;gtk_object_unr…
9078 got moved to the base &lt;code&gt;GObject&lt;/code&gt; class, so we now …
9079 and &lt;code&gt;g_object_unref()&lt;/code&gt; and a host of functions to…
9080 references, notification of destruction, and all the things required
9081 to keep garbage collectors happy.&lt;/p&gt;
9082 &lt;h2&gt;The first language bindings&lt;/h2&gt;
9083 &lt;p&gt;The very first language bindings were written by hand. The GTK…
9084 was small, and it seemed feasible to take&lt;/p&gt;
9085 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
9086 &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;gtk_widg…
9087
9088 &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;gtk_cont…
9089 &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;gtk_cont…
9090 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
9091
9092 &lt;p&gt;and just wrap those functions in various languages, by hand, on…
9093 as-needed basis.&lt;/p&gt;
9094 &lt;p&gt;Of course, there is a lot of duplication when doing things that…
9095 As the C API grows, one needs to do more and more manual work to
9096 keep up with it.&lt;/p&gt;
9097 &lt;p&gt;Also, C structs with public fields are problematic. If we had&…
9098 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
9099 &lt;span class="n"&gt;guchar&lt;/span&gt; &lt;span class="n"&gt;r&lt…
9100 &lt;span class="n"&gt;guchar&lt;/span&gt; &lt;span class="n"&gt;g&lt…
9101 &lt;span class="n"&gt;guchar&lt;/span&gt; &lt;span class="n"&gt;b&lt…
9102 &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="n"&gt;GdkColor&lt;/…
9103 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
9104
9105 &lt;p&gt;and we &lt;em&gt;expect&lt;/em&gt; program code to fill in a &l…
9106 pass it to a drawing function like&lt;/p&gt;
9107 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
9108 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
9109
9110 &lt;p&gt;then it is no problem to do that in C:&lt;/p&gt;
9111 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
9112
9113 &lt;span class="n"&gt;gdk_set_foreground_color&lt;/span&gt; &lt;span cla…
9114 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
9115
9116 &lt;p&gt;But to do that in a high level language? You don't have access…
9117 struct fields! And back then, libffi wasn't generally available.&lt;/p&…
9118 &lt;p&gt;Authors of language bindings had to write some glue code, in C,…
9119 hand, to let people access a C struct and then pass it on to GTK+.
9120 For example, for Python, they would need to write something like&lt;/p&g…
9121 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
9122 &lt;span class="nf"&gt;make_wrapped_gdk_color&lt;/span&gt; &lt;span clas…
9123 &lt;span class="p"&gt;{&lt;/span&gt;
9124 &lt;span class="n"&gt;GdkColor&lt;/span&gt; &lt;span class="o"&gt;*&…
9125 &lt;span class="n"&gt;PyObject&lt;/span&gt; &lt;span class="o"&gt;*&…
9126
9127 &lt;span class="n"&gt;g_color&lt;/span&gt; &lt;span class="o"&gt;=&l…
9128 &lt;span class="cm"&gt;/* ... fill in g_color-&amp;gt;r, g, b from t…
9129
9130 &lt;span class="n"&gt;py_color&lt;/span&gt; &lt;span class="o"&gt;=&…
9131 &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;py_c…
9132 &lt;span class="p"&gt;}&lt;/span&gt;
9133 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
9134
9135 &lt;p&gt;Writing that by hand is an incredible amount of drudgery.&lt;/p…
9136 &lt;p&gt;What language bindings needed was a &lt;em&gt;description&lt;/e…
9137 machine-readable format, so that the glue code could be written by a
9138 code generator.&lt;/p&gt;
9139 &lt;h2&gt;The first API descriptions&lt;/h2&gt;
9140 &lt;p&gt;I don't remember if it was the GNU Guile people, or the PyGTK p…
9141 who started to write descriptions of the GNOME API by hand. For ease
9142 of parsing, it was done in a Scheme-like dialect. A description may
9143 look like&lt;/p&gt;
9144 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
9145 &lt;span class="c1"&gt;;;; void gtk_widget_show (GtkWidget *widge…
9146 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;method…
9147 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&g…
9148 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&g…
9149
9150 &lt;span class="c1"&gt;;;; void gtk_widget_hide (GtkWidget *widge…
9151 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;method…
9152 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&g…
9153 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&g…
9154
9155 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;class&lt;/spa…
9156 &lt;span class="c1"&gt;;;; void gtk_container_add (GtkContainer *…
9157 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;method…
9158 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&g…
9159 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&g…
9160
9161 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;struct&lt;/sp…
9162 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;field…
9163 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;field…
9164 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;field…
9165 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
9166
9167 &lt;p&gt;Again, writing those descriptions by hand (and keeping up with …
9168 API) was a lot of work, but the glue code to implement the binding
9169 could be done mostly automatically. The generated code may need
9170 subsequent tweaks by hand to deal with details that the Scheme-like
9171 descriptions didn't contemplate, but it was better than writing
9172 &lt;em&gt;everything&lt;/em&gt; by hand.&lt;/p&gt;
9173 &lt;h2 id="type-system"&gt;Glib gets a real type system&lt;/h2&gt;
9174 &lt;p&gt;Tim Janik took over the parts of Glib that implement
9175 objects/signals/types, and added a lot of things to create a good type
9176 system for C. This is where things like &lt;code&gt;GType&lt;/code&gt;,…
9177 fundamental types come from.&lt;/p&gt;
9178 &lt;p&gt;For example, a &lt;code&gt;GType&lt;/code&gt; is an identifier …
9179 type plus, well, a value of that type. You can ask a &lt;code&gt;GValue…
9180 you an int? are you a GObject?".&lt;/p&gt;
9181 &lt;p&gt;You can register new types: for example, there would be code i…
9182 that registers a new &lt;code&gt;GType&lt;/code&gt; for &lt;code&gt;GdkC…
9183 "are you a color?".&lt;/p&gt;
9184 &lt;p&gt;Registering a type involves telling the GObject system things l…
9185 to copy values of that type, and how to free them. For &lt;code&gt;GdkC…
9186 this may be just &lt;code&gt;g_new() / g_free()&lt;/code&gt;; for refere…
9187 it may be &lt;code&gt;g_object_ref() / g_object_unref()&lt;/code&gt;.&lt…
9188 &lt;h3&gt;Objects can be queried about some of their properties&lt;/h3&g…
9189 &lt;p&gt;A widget can tell you when you press a mouse button mouse on it…
9190 will emit the &lt;code&gt;button-press-event&lt;/code&gt; signal. When …
9191 implementation registers this signal, it calls something like&lt;/p&gt;
9192 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
9193 &lt;span class="n"&gt;gtk_widget_get_type&lt;/span&gt;&lt;span c…
9194 &lt;span class="p"&gt;...&lt;/span&gt;
9195 &lt;span class="n"&gt;G_TYPE_BOOLEAN&lt;/span&gt;&lt;span class=…
9196 &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;…
9197 &lt;span class="n"&gt;GDK_TYPE_EVENT&lt;/span&gt;&lt;span class=…
9198 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
9199
9200 &lt;p&gt;This tells GObject that &lt;code&gt;GtkWidget&lt;/code&gt; will…
9201 &lt;code&gt;button-press-event&lt;/code&gt;, with a return type of &lt;c…
9202 a single argument of type &lt;code&gt;GDK_TYPE_EVENT&lt;/code&gt;. This…
9203 appropriate marshalling of arguments when the signal is emitted.&lt;/p&g…
9204 &lt;p&gt;But also! &lt;em&gt;You can query the signal for its argument …
9205 run &lt;code&gt;g_signal_query()&lt;/code&gt;, which will then tell you …
9206 the signal: its name, return type, argument types, etc. A language
9207 binding could run &lt;code&gt;g_signal_query()&lt;/code&gt; &lt;em&gt;an…
9208 signal automatically&lt;/em&gt; to the Scheme-like description language.…
9209 then generate the binding from &lt;em&gt;that&lt;/em&gt;.&lt;/p&gt;
9210 &lt;h2&gt;Not all of an object's properties can be queried&lt;/h2&gt;
9211 &lt;p&gt;Unfortunately, although GObject signals and properties &lt;em&g…
9212 queried, methods can't be. C doesn't have classes with methods, and GOb…
9213 not really have any provisions to implement them. &lt;/p&gt;
9214 &lt;p&gt;Conventionally, for a static method one would just do&lt;/p&gt;
9215 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
9216 &lt;span class="nf"&gt;gtk_widget_set_flags&lt;/span&gt; &lt;span class=…
9217 &lt;span class="p"&gt;{&lt;/span&gt;
9218 &lt;span class="cm"&gt;/* modify a struct field within &amp;quot;wid…
9219 &lt;span class="cm"&gt;/* repaint or something */&lt;/span&gt;
9220 &lt;span class="p"&gt;}&lt;/span&gt;
9221 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
9222
9223 &lt;p&gt;And for a virtual method one would put a function pointer in th…
9224 structure, and provide a convenient way to call it:&lt;/p&gt;
9225 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
9226 &lt;span class="n"&gt;GtkObjectClass&lt;/span&gt; &lt;span class="n"…
9227
9228 &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="p"&gt;(&lt;…
9229 &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="n"&gt;GtkWidgetClas…
9230
9231 &lt;span class="kt"&gt;void&lt;/span&gt;
9232 &lt;span class="nf"&gt;gtk_widget_draw&lt;/span&gt; &lt;span class="p"&g…
9233 &lt;span class="p"&gt;{&lt;/span&gt;
9234 &lt;span class="n"&gt;GtkWidgetClass&lt;/span&gt; &lt;span class="o"…
9235
9236 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span…
9237 &lt;span class="p"&gt;}&lt;/span&gt;
9238 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
9239
9240 &lt;p&gt;And GObject has no idea about this method — there is no way t…
9241 it; it just exists in C-space.&lt;/p&gt;
9242 &lt;p&gt;Now, historically, GTK+'s header files have been written in a &…
9243 consistent style. It is quite possible to write a tool that will take
9244 a header file like&lt;/p&gt;
9245 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
9246 &lt;span class="k"&gt;typedef&lt;/span&gt; &lt;span class="k"&gt;struct&…
9247 &lt;span class="n"&gt;GtkObject&lt;/span&gt; &lt;span class="n"&gt;p…
9248
9249 &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="p"&gt;(&lt;…
9250 &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="n"&gt;GtkWidgetClas…
9251
9252 &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;gtk_widg…
9253 &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;gtk_widg…
9254 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
9255
9256 &lt;p&gt;and parse it, even if it is with a simple parser that does not
9257 completely understand the C language, and have heuristics like&lt;/p&gt;
9258 &lt;ul&gt;
9259 &lt;li&gt;
9260 &lt;p&gt;Is there a &lt;code&gt;class_name_foo()&lt;/code&gt; function p…
9261 corresponding &lt;code&gt;foo&lt;/code&gt; field in the &lt;code&gt;Cl…
9262 static method.&lt;/p&gt;
9263 &lt;/li&gt;
9264 &lt;li&gt;
9265 &lt;p&gt;Is there a &lt;code&gt;class_name_bar()&lt;/code&gt; function w…
9266 &lt;code&gt;Class&lt;/code&gt; structure? It's probably a virtual met…
9267 &lt;/li&gt;
9268 &lt;li&gt;
9269 &lt;p&gt;Etc.&lt;/p&gt;
9270 &lt;/li&gt;
9271 &lt;/ul&gt;
9272 &lt;p&gt;And in fact, that's what we had. C header files would get pars…
9273 with those heuristics, and the Scheme-like description files would get
9274 generated.&lt;/p&gt;
9275 &lt;h2&gt;Scheme-like descriptions get reused, kind of&lt;/h2&gt;
9276 &lt;p&gt;Language binding authors started reusing the Scheme-like
9277 descriptions. Sometimes they would cannibalize the descriptions from
9278 PyGTK, or Guile (again, I don't remember where the canonical version
9279 was maintained) and use them as they were.&lt;/p&gt;
9280 &lt;p&gt;Other times they would copy the files, modify them by hand some…
9281 and &lt;em&gt;then&lt;/em&gt; use them to generate their language bindin…
9282 &lt;h2&gt;C being hostile&lt;/h2&gt;
9283 &lt;p&gt;From just reading/parsing a C function prototype, you cannot kn…
9284 certain things. If one function argument is of type &lt;code&gt;Foo *&l…
9285 &lt;ul&gt;
9286 &lt;li&gt;
9287 &lt;p&gt;the function gets a pointer to something which it should not mo…
9288 ("in" parameter)&lt;/p&gt;
9289 &lt;/li&gt;
9290 &lt;li&gt;
9291 &lt;p&gt;the function gets a pointer to uninitialized data which it will…
9292 ("out" parameter)&lt;/p&gt;
9293 &lt;/li&gt;
9294 &lt;li&gt;
9295 &lt;p&gt;the function gets a pointer to initialized data which it will u…
9296 and modify ("inout" parameter)&lt;/p&gt;
9297 &lt;/li&gt;
9298 &lt;li&gt;
9299 &lt;p&gt;the function will copy that pointer and hold a reference to the
9300 pointed data, and not free it when it's done&lt;/p&gt;
9301 &lt;/li&gt;
9302 &lt;li&gt;
9303 &lt;p&gt;the function will take over the ownership of the pointed data, …
9304 free it when it's done&lt;/p&gt;
9305 &lt;/li&gt;
9306 &lt;li&gt;
9307 &lt;p&gt;etc.&lt;/p&gt;
9308 &lt;/li&gt;
9309 &lt;/ul&gt;
9310 &lt;p&gt;Sometimes people would include these annotations in the Scheme-…
9311 description language. But wouldn't it be better if those annotations
9312 came &lt;em&gt;from the C code itself&lt;/em&gt;?&lt;/p&gt;
9313 &lt;h1&gt;GObject Introspection appears&lt;/h1&gt;
9314 &lt;p&gt;For GNOME 3, we wanted a unified solution for language bindings…
9315 &lt;ul&gt;
9316 &lt;li&gt;
9317 &lt;p&gt;Have a single way to extract the machine-readable descriptions …
9318 the C API.&lt;/p&gt;
9319 &lt;/li&gt;
9320 &lt;li&gt;
9321 &lt;p&gt;Have every language binding be automatically generated from tho…
9322 descriptions.&lt;/p&gt;
9323 &lt;/li&gt;
9324 &lt;li&gt;
9325 &lt;p&gt;In the descriptions, have &lt;em&gt;all&lt;/em&gt; the informat…
9326 generate a correct language binding...&lt;/p&gt;
9327 &lt;/li&gt;
9328 &lt;li&gt;
9329 &lt;p&gt;... including documentation.&lt;/p&gt;
9330 &lt;/li&gt;
9331 &lt;/ul&gt;
9332 &lt;p&gt;We had to do a lot of work to accomplish this. For example:&lt…
9333 &lt;ul&gt;
9334 &lt;li&gt;
9335 &lt;p&gt;Remove C-isms from the public API. Varargs functions, those th…
9336 have &lt;code&gt;foo (int x, ...)&lt;/code&gt;, can't be easily desc…
9337 other languages. Instead, have something like
9338 &lt;code&gt;foov (int x, int num_args, GValue *args_array)&lt;/c…
9339 consumed by other languages.&lt;/p&gt;
9340 &lt;/li&gt;
9341 &lt;li&gt;
9342 &lt;p&gt;Add &lt;em&gt;annotations&lt;/em&gt; throughout the code so tha…
9343 can know about in/out/inout arguments, and whether pointer arguments
9344 are borrowed references or a full transfership of ownership.&lt;/p&gt;
9345 &lt;/li&gt;
9346 &lt;li&gt;
9347 &lt;p&gt;Take the in-line documentation comments and store them as part …
9348 the machine-readable description of the API.&lt;/p&gt;
9349 &lt;/li&gt;
9350 &lt;li&gt;
9351 &lt;p&gt;When compiling a library, automatically do all the things like
9352 &lt;code&gt;g_signal_query()&lt;/code&gt; and spit out machine-readabl…
9353 those parts of the API.&lt;/p&gt;
9354 &lt;/li&gt;
9355 &lt;/ul&gt;
9356 &lt;p&gt;So, GObject Introspection is all of those things.&lt;/p&gt;
9357 &lt;h2&gt;Annotations&lt;/h2&gt;
9358 &lt;p&gt;If you have looked at the C code for a GNOME library, you may h…
9359 seen something like this:&lt;/p&gt;
9360 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
9361 &lt;span class="cm"&gt; * gtk_widget_get_parent:&lt;/span&gt;
9362 &lt;span class="cm"&gt; * @widget: a #GtkWidget&lt;/span&gt;
9363 &lt;span class="cm"&gt; *&lt;/span&gt;
9364 &lt;span class="cm"&gt; * Returns the parent container of @widget.&lt;/s…
9365 &lt;span class="cm"&gt; *&lt;/span&gt;
9366 &lt;span class="cm"&gt; * Returns: (transfer none) (nullable): the paren…
9367 &lt;span class="cm"&gt; **/&lt;/span&gt;
9368 &lt;span class="n"&gt;GtkWidget&lt;/span&gt; &lt;span class="o"&gt;*&lt;…
9369 &lt;span class="nf"&gt;gtk_widget_get_parent&lt;/span&gt; &lt;span class…
9370 &lt;span class="p"&gt;{&lt;/span&gt;
9371 &lt;span class="p"&gt;...&lt;/span&gt;
9372 &lt;span class="p"&gt;}&lt;/span&gt;
9373 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
9374
9375 &lt;p&gt;See that "&lt;code&gt;(transfer none) (nullable)&lt;/code&gt;" …
9376 The &lt;code&gt;(transfer none)&lt;/code&gt; means that the return value…
9377 ownership does &lt;em&gt;not&lt;/em&gt; get transferred to the caller, i…
9378 retains ownership. Finally, the &lt;code&gt;(nullable)&lt;/code&gt; ind…
9379 function can return &lt;code&gt;NULL&lt;/code&gt;, when the widget has n…
9380 &lt;p&gt;A language binding will then use this information as follows:&l…
9381 &lt;ul&gt;
9382 &lt;li&gt;
9383 &lt;p&gt;It will not &lt;code&gt;unref()&lt;/code&gt; the parent widget …
9384 &lt;/li&gt;
9385 &lt;li&gt;
9386 &lt;p&gt;It will deal with a &lt;code&gt;NULL&lt;/code&gt; pointer in a …
9387 assuming that references are not null.&lt;/p&gt;
9388 &lt;/li&gt;
9389 &lt;/ul&gt;
9390 &lt;p&gt;Every now and then someone discovers a public function which is
9391 lacking an annotation of that sort — for GNOME's purposes this is a
9392 bug; fortunately, it is easy to add that annotation to the C sources
9393 and regenerate the machine-readable descriptions.&lt;/p&gt;
9394 &lt;h2&gt;Machine-readable descriptions, or repository files&lt;/h2&gt;
9395 &lt;p&gt;So, what do those machine-readable descriptions actually look l…
9396 They moved away from a Scheme-like language and got turned into XML,
9397 because early XXIst century.&lt;/p&gt;
9398 &lt;p&gt;The machine-readable descriptions are called &lt;em&gt;GObject …
9399 Repository files&lt;/em&gt;, or GIR for short.&lt;/p&gt;
9400 &lt;p&gt;Let's look at some parts of &lt;code&gt;Gtk-3.0.gir&lt;/code&gt…
9401 &lt;code&gt;/usr/share/gir-1.0/Gtk-3.0.gir&lt;/code&gt;.&lt;/p&gt;
9402 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
9403
9404 &lt;span class="nt"&gt;&amp;lt;namespace&lt;/span&gt; &lt;span class="…
9405 &lt;span class="na"&gt;version=&lt;/span&gt;&lt;span class=…
9406 &lt;span class="na"&gt;shared-library=&lt;/span&gt;&lt;span…
9407 &lt;span class="na"&gt;c:identifier-prefixes=&lt;/span&gt;&…
9408 &lt;span class="na"&gt;c:symbol-prefixes=&lt;/span&gt;&lt;s…
9409 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
9410
9411 &lt;p&gt;For the toplevel "&lt;code&gt;Gtk&lt;/code&gt;" namespace, this…
9412 called. All identifiers have "&lt;code&gt;Gtk&lt;/code&gt;" or "&lt;cod…
9413 &lt;h3&gt;A class with methods and a signal&lt;/h3&gt;
9414 &lt;p&gt;Let's look at the description for &lt;code&gt;GtkEntry&lt;/code…
9415 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
9416 &lt;span class="na"&gt;c:symbol-prefix=&lt;/span&gt;&lt;span …
9417 &lt;span class="na"&gt;c:type=&lt;/span&gt;&lt;span class="s"…
9418 &lt;span class="na"&gt;parent=&lt;/span&gt;&lt;span class="s"…
9419 &lt;span class="na"&gt;glib:type-name=&lt;/span&gt;&lt;span c…
9420 &lt;span class="na"&gt;glib:get-type=&lt;/span&gt;&lt;span cl…
9421 &lt;span class="na"&gt;glib:type-struct=&lt;/span&gt;&lt;span…
9422
9423 &lt;span class="nt"&gt;&amp;lt;doc&lt;/span&gt; &lt;span class="na…
9424 widget. A fairly large set of key bindings are supported
9425 by default. If the entered text is longer than the allocation
9426 ...
9427 &lt;span class="nt"&gt;&amp;lt;/doc&amp;gt;&lt;/span&gt;
9428 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
9429
9430 &lt;p&gt;This is the start of the description for &lt;code&gt;GtkEntry&l…
9431 that everything is prefixed with "&lt;code&gt;Gtk&lt;/code&gt;", so the …
9432 "&lt;code&gt;Entry&lt;/code&gt;". Its parent class is &lt;code&gt;Widge…
9433 registers it against the GObject type system is &lt;code&gt;gtk_entry_ge…
9434 &lt;p&gt;Also, there are the toplevel documentation comments for the &lt…
9435 class.&lt;/p&gt;
9436 &lt;p&gt;Onwards!&lt;/p&gt;
9437 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
9438 &lt;span class="nt"&gt;&amp;lt;implements&lt;/span&gt; &lt;span cl…
9439 &lt;span class="nt"&gt;&amp;lt;implements&lt;/span&gt; &lt;span cl…
9440 &lt;span class="nt"&gt;&amp;lt;implements&lt;/span&gt; &lt;span cl…
9441 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
9442
9443 &lt;p&gt;GObject classes can implement various interfaces; this is the l…
9444 that &lt;code&gt;GtkEntry&lt;/code&gt; supports.&lt;/p&gt;
9445 &lt;p&gt;Next, let's look at a single method:&lt;/p&gt;
9446 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
9447 &lt;span class="nt"&gt;&amp;lt;doc&lt;/span&gt; &lt;span class="…
9448
9449 &lt;span class="nt"&gt;&amp;lt;return-value&lt;/span&gt; &lt;spa…
9450 &lt;span class="nt"&gt;&amp;lt;type&lt;/span&gt; &lt;span clas…
9451 &lt;span class="nt"&gt;&amp;lt;/return-value&amp;gt;&lt;/span&gt;
9452
9453 &lt;span class="nt"&gt;&amp;lt;parameters&amp;gt;&lt;/span&gt;
9454 &lt;span class="nt"&gt;&amp;lt;instance-parameter&lt;/span&gt;…
9455 &lt;span class="nt"&gt;&amp;lt;type&lt;/span&gt; &lt;span cl…
9456 &lt;span class="nt"&gt;&amp;lt;/instance-parameter&amp;gt;&lt;…
9457 &lt;span class="nt"&gt;&amp;lt;/parameters&amp;gt;&lt;/span&gt;
9458 &lt;span class="nt"&gt;&amp;lt;/method&amp;gt;&lt;/span&gt;
9459 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
9460
9461 &lt;p&gt;The method &lt;code&gt;get_text&lt;/code&gt; and its correspond…
9462 value is an UTF-8 encoded string, and ownership of the memory for that
9463 string is not transferred to the caller.&lt;/p&gt;
9464 &lt;p&gt;The method takes a single parameter which is the &lt;code&gt;en…
9465 &lt;p&gt;Now, let's look at a signal:&lt;/p&gt;
9466 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
9467 &lt;span class="nt"&gt;&amp;lt;doc&lt;/span&gt; &lt;span class="…
9468 the Enter key. ...&lt;span class="nt"&gt;&amp;lt;/doc&amp;gt;&lt;/span&g…
9469
9470 &lt;span class="nt"&gt;&amp;lt;return-value&lt;/span&gt; &lt;spa…
9471 &lt;span class="nt"&gt;&amp;lt;type&lt;/span&gt; &lt;span clas…
9472 &lt;span class="nt"&gt;&amp;lt;/return-value&amp;gt;&lt;/span&gt;
9473 &lt;span class="nt"&gt;&amp;lt;/glib:signal&amp;gt;&lt;/span&gt;
9474
9475 &lt;span class="nt"&gt;&amp;lt;/class&amp;gt;&lt;/span&gt;
9476 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
9477
9478 &lt;p&gt;The "&lt;code&gt;activate&lt;/code&gt;" signal takes no argumen…
9479 type &lt;code&gt;void&lt;/code&gt;, i.e. no return value.&lt;/p&gt;
9480 &lt;h3&gt;A struct with public fields&lt;/h3&gt;
9481 &lt;p&gt;The following comes from &lt;code&gt;Gdk-3.0.gir&lt;/code&gt;; …
9482 &lt;code&gt;GdkRectangle&lt;/code&gt;.&lt;/p&gt;
9483 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
9484 &lt;span class="na"&gt;c:type=&lt;/span&gt;&lt;span class="s…
9485 &lt;span class="na"&gt;glib:type-name=&lt;/span&gt;&lt;span …
9486 &lt;span class="na"&gt;glib:get-type=&lt;/span&gt;&lt;span c…
9487 &lt;span class="na"&gt;c:symbol-prefix=&lt;/span&gt;&lt;span…
9488
9489 &lt;span class="nt"&gt;&amp;lt;field&lt;/span&gt; &lt;span class="…
9490 &lt;span class="nt"&gt;&amp;lt;type&lt;/span&gt; &lt;span class=…
9491 &lt;span class="nt"&gt;&amp;lt;/field&amp;gt;&lt;/span&gt;
9492 &lt;span class="nt"&gt;&amp;lt;field&lt;/span&gt; &lt;span class="…
9493 &lt;span class="nt"&gt;&amp;lt;type&lt;/span&gt; &lt;span class=…
9494 &lt;span class="nt"&gt;&amp;lt;/field&amp;gt;&lt;/span&gt;
9495 &lt;span class="nt"&gt;&amp;lt;field&lt;/span&gt; &lt;span class="…
9496 &lt;span class="nt"&gt;&amp;lt;type&lt;/span&gt; &lt;span class=…
9497 &lt;span class="nt"&gt;&amp;lt;/field&amp;gt;&lt;/span&gt;
9498 &lt;span class="nt"&gt;&amp;lt;field&lt;/span&gt; &lt;span class="…
9499 &lt;span class="nt"&gt;&amp;lt;type&lt;/span&gt; &lt;span class=…
9500 &lt;span class="nt"&gt;&amp;lt;/field&amp;gt;&lt;/span&gt;
9501
9502 &lt;span class="nt"&gt;&amp;lt;/record&amp;gt;&lt;/span&gt;
9503 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
9504
9505 &lt;p&gt;So that's the &lt;code&gt;x/y/width/height&lt;/code&gt; fields …
9506 order as they are defined in the C code.&lt;/p&gt;
9507 &lt;p&gt;And so on. The idea is for the whole API exported by a GObject
9508 library to be describable by that format. If something can't be
9509 described, it's a bug in the library, or a bug in the format.&lt;/p&gt;
9510 &lt;h1&gt;Making language bindings start up quickly: typelib files&lt;/h…
9511 &lt;p&gt;As we saw, the GIR files are the XML descriptions of GObject AP…
9512 Dynamic languages like Python would prefer to generate the language
9513 binding on the fly, as needed, instead of pre-generating a huge
9514 binding.&lt;/p&gt;
9515 &lt;p&gt;However, GTK+ is a big API: &lt;code&gt;Gtk-3.0.gir&lt;/code&gt…
9516 all of that just to be able to generate &lt;code&gt;gtk_widget_show()&lt…
9517 would be too slow. Also, there are GTK+'s dependencies: Atk, Gdk,
9518 Cairo, etc. You don't want to parse &lt;em&gt;everything&lt;/em&gt; jus…
9519 &lt;p&gt;So, we have an extra step that compiles the GIR files down to b…
9520 &lt;code&gt;.typelib&lt;/code&gt; files. For example,
9521 &lt;code&gt;/usr/lib64/girepository-1.0/Gtk-3.0.typelib&lt;/code&gt; is …
9522 machine. Those files get &lt;code&gt;mmap()&lt;/code&gt;ed for fast acc…
9523 shared between processes.&lt;/p&gt;
9524 &lt;h2&gt;How dynamic language bindings use typelib files&lt;/h2&gt;
9525 &lt;p&gt;GObject Introspection comes with a library that language binding
9526 implementors can use to consume those &lt;code&gt;.typelib&lt;/code&gt; …
9527 &lt;code&gt;libgirepository&lt;/code&gt; library has functions like "lis…
9528 available in this namespace", or "call this function with these
9529 values for arguments, and give me back the return value here".&lt;/p&gt;
9530 &lt;p&gt;Internally, &lt;code&gt;libgirepository&lt;/code&gt; uses &lt;c…
9531 functions in the dynamically-linked libraries.&lt;/p&gt;
9532 &lt;p&gt;So, when you write &lt;code&gt;foo.py&lt;/code&gt; and do&lt;/p…
9533 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
9534 &lt;span class="n"&gt;gi&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt…
9535 &lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;gi.repos…
9536 &lt;span class="n"&gt;win&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&…
9537 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
9538
9539 &lt;p&gt;what happens is that &lt;code&gt;pygobject&lt;/code&gt; calls &…
9540 the &lt;code&gt;.typelib&lt;/code&gt;, and sees that the constructor for…
9541 function called &lt;code&gt;gtk_window_new()&lt;/code&gt;. After seeing…
9542 wants to be called, it calls the function using &lt;code&gt;libffi&lt;/c…
9543 result with a &lt;code&gt;PyObject&lt;/code&gt;, and that's what you get…
9544 &lt;h1&gt;Static languages&lt;/h1&gt;
9545 &lt;p&gt;A static language like Rust prefers to have the whole language …
9546 pre-generated. This is what the various crates in &lt;a href="https://g…
9547 do.&lt;/p&gt;
9548 &lt;p&gt;&lt;a href="https://github.com/gtk-rs/gir/tree/master/src"&gt;T…
9549 and does two things:&lt;/p&gt;
9550 &lt;ul&gt;
9551 &lt;li&gt;
9552 &lt;p&gt;Reconstructs the C function prototypes and C struct declaration…
9553 but in a way Rust can understand them. This gets output to the &lt;a hr…
9554 crate&lt;/a&gt;.&lt;/p&gt;
9555 &lt;/li&gt;
9556 &lt;li&gt;
9557 &lt;p&gt;Creates idiomatic Rust code for the language binding. This gets
9558 output to the various crates; for example, &lt;a href="https://github.co…
9559 &lt;/li&gt;
9560 &lt;/ul&gt;
9561 &lt;p&gt;When reconstructing the C structs and prototypes, we get stuff …
9562 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
9563 &lt;span class="k"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&g…
9564 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;pub&lt;/spa…
9565 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;pub&lt;/spa…
9566 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
9567
9568 &lt;span class="k"&gt;extern&lt;/span&gt;&lt;span class="w"&gt; &lt;/spa…
9569 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;pub&lt;/spa…
9570 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
9571 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
9572
9573 &lt;p&gt;And the idiomatic bindings? Stay tuned!&lt;/p&gt;</content><ca…
9574 Apart from all the Rust goodness, and the large number of bug fixes, I
9575 am very happy with the way the build system works these days. I've
9576 found it invaluable to have good examples of Autotools incantations to �…
9577 Apart from all the Rust goodness, and the large number of bug fixes, I
9578 am very happy with the way the build system works these days. I've
9579 found it invaluable to have good examples of Autotools incantations to
9580 copy&amp;amp;paste, so hopefully this will be useful to someone else.&lt…
9581 &lt;p&gt;There are some subtleties that a "good" autotools setup demands…
9582 so far I think librsvg is doing well:&lt;/p&gt;
9583 &lt;ul&gt;
9584 &lt;li&gt;
9585 &lt;p&gt;The &lt;code&gt;configure&lt;/code&gt; script checks for &lt;co…
9586 &lt;/li&gt;
9587 &lt;li&gt;
9588 &lt;p&gt;"&lt;code&gt;make distcheck&lt;/code&gt;" works. This means th…
9589 performed with &lt;code&gt;builddir != srcdir&lt;/code&gt;, and also…
9590 the available tests and they all pass.&lt;/p&gt;
9591 &lt;/li&gt;
9592 &lt;li&gt;
9593 &lt;p&gt;The &lt;code&gt;rsvg_internals&lt;/code&gt; library is built wi…
9594 &lt;code&gt;Makefile.am&lt;/code&gt; calls &lt;code&gt;cargo build&lt;…
9595 able to handle debug and release builds.&lt;/p&gt;
9596 &lt;/li&gt;
9597 &lt;li&gt;
9598 &lt;p&gt;"&lt;code&gt;make clean&lt;/code&gt;" cleans up the Rust build …
9599 &lt;/li&gt;
9600 &lt;li&gt;
9601 &lt;p&gt;If you change a &lt;code&gt;.rs&lt;/code&gt; file and type &lt;…
9602 gets rebuilt.&lt;/p&gt;
9603 &lt;/li&gt;
9604 &lt;li&gt;
9605 &lt;p&gt;Etcetera. I think librsvg feels like a normal autotool'ed libr…
9606 Let's see how this is done.&lt;/p&gt;
9607 &lt;/li&gt;
9608 &lt;/ul&gt;
9609 &lt;h1&gt;Librsvg's basic autotools setup&lt;/h1&gt;
9610 &lt;p&gt;Librsvg started out with a fairly traditional autotools setup w…
9611 &lt;a href="https://git.gnome.org/browse/librsvg/tree/configure.ac?h=2.4…
9612 historical reasons the &lt;code&gt;.[ch]&lt;/code&gt; source files live …
9613 &lt;code&gt;librsvg/&lt;/code&gt; directory, not in a &lt;code&gt;src&lt…
9614 that.&lt;/p&gt;
9615 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
9616 ├ configure.ac
9617 ├ Makefile.am
9618 ├ *.[ch]
9619 ├ src/
9620 ├ doc/
9621 ├ tests/
9622 └ win32/
9623 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
9624
9625 &lt;h1&gt;Adding Rust to the build&lt;/h1&gt;
9626 &lt;p&gt;The Rust source code lives in &lt;a href="https://git.gnome.org…
9627 where &lt;a href="https://git.gnome.org/browse/librsvg/tree/rust/Cargo.t…
9628 &lt;code&gt;src&lt;/code&gt; subdirectory with the &lt;code&gt;*.rs&lt;/…
9629 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
9630 ├ configure.ac
9631 ├ Makefile.am
9632 ├ *.[ch]
9633 ├ src/
9634 ├ rust/ &amp;lt;--- this is new!
9635 │ ├ Cargo.toml
9636 │ └ src/
9637 ├ doc/
9638 ├ tests/
9639 └ win32/
9640 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
9641
9642 &lt;h2&gt;Detecting the presence of &lt;code&gt;cargo&lt;/code&gt; and &…
9643 &lt;p&gt;This goes in &lt;code&gt;configure.ac&lt;/code&gt;:&lt;/p&gt;
9644 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
9645 AS_IF&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;test&lt;…
9646 AC_MSG_ERROR&lt;span class="o"&gt;([&lt;/span&gt;cargo is required. …
9647 &lt;span class="o"&gt;)&lt;/span&gt;
9648 AC_CHECK_PROG&lt;span class="o"&gt;(&lt;/span&gt;RUSTC, &lt;span class="…
9649 AS_IF&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;test&lt;…
9650 AC_MSG_ERROR&lt;span class="o"&gt;([&lt;/span&gt;rustc is required. …
9651 &lt;span class="o"&gt;)&lt;/span&gt;
9652 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
9653
9654 &lt;p&gt;These two try to execute &lt;code&gt;cargo&lt;/code&gt; and &lt…
9655 with an error message if they are not present.&lt;/p&gt;
9656 &lt;h2&gt;Supporting debug or release mode for the Rust build&lt;/h2&gt;
9657 &lt;p&gt;One can call cargo like "&lt;code&gt;cargo build --release&lt;/…
9658 optimizations, or normally like just "&lt;code&gt;cargo build&lt;/code&g…
9659 debug information. That is, the latter is the default: if you don't
9660 pass any options, cargo does a debug build.&lt;/p&gt;
9661 &lt;p&gt;Autotools and C compilers normally work a bit differently; one …
9662 call the configure script like "&lt;code&gt;CFLAGS='-g -O0' ./configure&…
9663 debug build, or "&lt;code&gt;CFLAGS='-O2 -fomit-frame-pointer' ./configu…
9664 a release build.&lt;/p&gt;
9665 &lt;p&gt;Linux distros already have all the infrastructure to pass the
9666 appropriate &lt;code&gt;CFLAGS&lt;/code&gt; to &lt;code&gt;configure&lt;…
9667 appropriate flag to Cargo. My main requirement for this was:&lt;/p&gt;
9668 &lt;ul&gt;
9669 &lt;li&gt;Distros shouldn't have to substantially change their RPM specf…
9670 (or whatever) to accomodate the Rust build.&lt;/li&gt;
9671 &lt;li&gt;I assume that distros will want to make release builds by defa…
9672 &lt;li&gt;I as a developer am comfortable with passing extra options to …
9673 debug builds on my machine.&lt;/li&gt;
9674 &lt;/ul&gt;
9675 &lt;p&gt;The scheme in librsvg lets you run "&lt;code&gt;configure --ena…
9676 make it call a plain &lt;code&gt;cargo build&lt;/code&gt;, or a plain "&…
9677 it use &lt;code&gt;cargo build --release&lt;/code&gt; instead. The &lt;…
9678 usual through an environment variable. This way, distros don't have
9679 to change their packaging to keep on making release builds as usual.&lt;…
9680 &lt;p&gt;This goes in &lt;code&gt;configure.ac&lt;/code&gt;:&lt;/p&gt;
9681 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
9682 dnl we build &lt;span class="k"&gt;in&lt;/span&gt; public release mode.
9683
9684 AC_ARG_ENABLE&lt;span class="o"&gt;(&lt;/span&gt;debug,
9685 AC_HELP_STRING&lt;span class="o"&gt;([&lt;/span&gt;--enabl…
9686 &lt;span class="o"&gt;[&lt;/span&gt;Build R…
9687 &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nv"&gt…
9688 &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nv"&gt…
9689
9690 AC_MSG_CHECKING&lt;span class="o"&gt;(&lt;/span&gt;whether to build Rust…
9691 &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;test&lt;/sp…
9692 AC_MSG_RESULT&lt;span class="o"&gt;(&lt;/span&gt;yes&lt;span class="…
9693 &lt;span class="nv"&gt;RUST_TARGET_SUBDIR&lt;/span&gt;&lt;span class…
9694 &lt;span class="k"&gt;else&lt;/span&gt;
9695 AC_MSG_RESULT&lt;span class="o"&gt;(&lt;/span&gt;no&lt;span class="o…
9696 &lt;span class="nv"&gt;RUST_TARGET_SUBDIR&lt;/span&gt;&lt;span class…
9697 &lt;span class="k"&gt;fi&lt;/span&gt;
9698 AM_CONDITIONAL&lt;span class="o"&gt;([&lt;/span&gt;DEBUG_RELEASE&lt;span…
9699
9700 AC_SUBST&lt;span class="o"&gt;([&lt;/span&gt;RUST_TARGET_SUBDIR&lt;span …
9701 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
9702
9703 &lt;p&gt;This defines an Automake conditional called &lt;code&gt;DEBUG_R…
9704 will use in &lt;code&gt;Makefile.am&lt;/code&gt; later.&lt;/p&gt;
9705 &lt;p&gt;It also causes &lt;code&gt;@RUST_TARGET_SUBDIR@&lt;/code&gt; to…
9706 with either &lt;code&gt;debug&lt;/code&gt; or &lt;code&gt;release&lt;/co…
9707 &lt;h2&gt;Adding Rust source files&lt;/h2&gt;
9708 &lt;p&gt;The &lt;code&gt;librsvg/rust/src&lt;/code&gt; directory has all…
9709 tracks their dependencies and whether they need to be rebuilt if one cha…
9710 However, since that directory is not tracked by &lt;code&gt;make&lt;/cod…
9711 rebuild things if a Rust source file changes! So, we need to tell our
9712 &lt;code&gt;Makefile.am&lt;/code&gt; about those files:&lt;/p&gt;
9713 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
9714 rust/build.rs &lt;span class="se"&gt;\&lt;/span&gt;
9715 rust/Cargo.toml &lt;span class="se"&gt;\&lt;/span&gt;
9716 rust/src/aspect_ratio.rs &lt;span class="se"&gt;\&lt;/span&gt;
9717 rust/src/bbox.rs &lt;span class="se"&gt;\&lt;/span&gt;
9718 rust/src/cnode.rs &lt;span class="se"&gt;\&lt;/span&gt;
9719 rust/src/color.rs &lt;span class="se"&gt;\&lt;/span&gt;
9720 ...
9721
9722 &lt;span class="nv"&gt;RUST_EXTRA&lt;/span&gt; &lt;span class="o"&gt;=&l…
9723 rust/Cargo.lock
9724
9725 &lt;span class="nv"&gt;EXTRA_DIST&lt;/span&gt; &lt;span class="o"&gt;+=&…
9726 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
9727
9728 &lt;p&gt;It's a bit unfortunate that the change tracking is duplicated i…
9729 &lt;code&gt;Makefile&lt;/code&gt;, but we are already used to listing al…
9730 in there, anyway.&lt;/p&gt;
9731 &lt;p&gt;Most notably, the &lt;code&gt;rust&lt;/code&gt; subdirectory is…
9732 in &lt;code&gt;Makefile.am&lt;/code&gt;, since there is no &lt;code&gt;r…
9733 &lt;h2&gt;Cargo release or debug build?&lt;/h2&gt;
9734 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
9735 &lt;span class="nv"&gt;CARGO_RELEASE_ARGS&lt;/span&gt;&lt;span class="o"…
9736 &lt;span class="cp"&gt;else&lt;/span&gt;
9737 &lt;span class="nv"&gt;CARGO_RELEASE_ARGS&lt;/span&gt;&lt;span class="o"…
9738 &lt;span class="cp"&gt;endif&lt;/span&gt;
9739 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
9740
9741 &lt;p&gt;We will call &lt;code&gt;cargo build&lt;/code&gt; with that arg…
9742 &lt;h2&gt;Verbose or quiet build?&lt;/h2&gt;
9743 &lt;p&gt;Librsvg uses &lt;code&gt;AM_SILENT_RULES([yes])&lt;/code&gt; in…
9744 you just run "&lt;code&gt;make&lt;/code&gt;" for a quiet build, or "&lt;…
9745 full command lines passed to the compiler. Cargo supports something
9746 similar, so let's add it to &lt;code&gt;Makefile.am&lt;/code&gt;:&lt;/p&…
9747 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
9748 &lt;span class="nv"&gt;cargo_verbose_&lt;/span&gt; &lt;span class="o"&gt…
9749 &lt;span class="nv"&gt;cargo_verbose_0&lt;/span&gt; &lt;span class="o"&g…
9750 &lt;span class="nv"&gt;cargo_verbose_1&lt;/span&gt; &lt;span class="o"&g…
9751 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
9752
9753 &lt;p&gt;This expands the &lt;code&gt;V&lt;/code&gt; variable to empty, …
9754 expanding &lt;em&gt;that&lt;/em&gt; gives us the final command-line argu…
9755 &lt;code&gt;CARGO_VERBOSE&lt;/code&gt; variable.&lt;/p&gt;
9756 &lt;h2&gt;What's the filename of the library we are building?&lt;/h2&gt;
9757 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
9758 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
9759
9760 &lt;p&gt;Remember our &lt;code&gt;@RUST_TARGET_SUBDIR@&lt;/code&gt; from…
9761 plain "&lt;code&gt;cargo build&lt;/code&gt;", it will put the binaries in
9762 &lt;code&gt;rust/target/debug&lt;/code&gt;. But if you call "&lt;code&g…
9763 will put the binaries in &lt;code&gt;rust/target/release&lt;/code&gt;.&l…
9764 &lt;p&gt;With the bit above, the &lt;code&gt;RUST_LIB&lt;/code&gt; varia…
9765 for the built library. The &lt;code&gt;@abs_top_builddir@&lt;/code&gt; …
9766 the build directory is not the same as the source directory.&lt;/p&gt;
9767 &lt;h2&gt;Okay, so how do we call &lt;code&gt;cargo&lt;/code&gt;?&lt;/h2…
9768 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
9769 &lt;span class="nb"&gt;cd&lt;/span&gt; &lt;span class="k"&gt;$(&lt;/…
9770 &lt;span class="nv"&gt;CARGO_TARGET_DIR&lt;/span&gt;&lt;span class="…
9771 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
9772
9773 &lt;p&gt;We make the funky library filename depend on &lt;code&gt;$(RUST…
9774 That's what will cause &lt;code&gt;make&lt;/code&gt; to rebuild the Rust…
9775 the Rust source files changes.&lt;/p&gt;
9776 &lt;p&gt;We override the &lt;code&gt;CARGO_TARGET_DIR&lt;/code&gt; with …
9777 call &lt;code&gt;cargo build&lt;/code&gt; with the correct arguments.&lt…
9778 &lt;h2&gt;Linking into the main C library&lt;/h2&gt;
9779 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
9780 &lt;span class="k"&gt;$(&lt;/span&gt;LIBRSVG_LIBS&lt;span class=…
9781 &lt;span class="k"&gt;$(&lt;/span&gt;LIBM&lt;span class="k"&gt;)…
9782 &lt;span class="k"&gt;$(&lt;/span&gt;RUST_LIB&lt;span class="k"&…
9783 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
9784
9785 &lt;p&gt;This expands our &lt;code&gt;$(RUST_LIB)&lt;/code&gt; from abov…
9786 with librsvg's other dependencies.&lt;/p&gt;
9787 &lt;h2&gt;&lt;code&gt;make check&lt;/code&gt;&lt;/h2&gt;
9788 &lt;p&gt;This is our hook so that &lt;code&gt;make check&lt;/code&gt; wi…
9789 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
9790 &lt;span class="nb"&gt;cd&lt;/span&gt; &lt;span class="k"&gt;$(&…
9791 &lt;span class="nv"&gt;CARGO_TARGET_DIR&lt;/span&gt;&lt;span cla…
9792 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
9793
9794 &lt;h2&gt;&lt;code&gt;make clean&lt;/code&gt;&lt;/h2&gt;
9795 &lt;p&gt;Same thing for &lt;code&gt;make clean&lt;/code&gt; and &lt;code…
9796 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
9797 &lt;span class="nb"&gt;cd&lt;/span&gt; &lt;span class="k"&gt;$(&…
9798 &lt;span class="nv"&gt;CARGO_TARGET_DIR&lt;/span&gt;&lt;span cla…
9799 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
9800
9801 &lt;h1&gt;Vendoring dependencies&lt;/h1&gt;
9802 &lt;p&gt;Linux distros probably want Rust packages to come bundled with …
9803 dependencies, so that they can replace them later with newer/patched
9804 versions.&lt;/p&gt;
9805 &lt;p&gt;Here is a hook so that &lt;code&gt;make dist&lt;/code&gt; will …
9806 run before making the tarball. That command will creates a
9807 &lt;code&gt;rust/vendor&lt;/code&gt; directory with a copy of all the Ru…
9808 librsvg depends on.&lt;/p&gt;
9809 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
9810
9811 &lt;span class="nf"&gt;dist-hook&lt;/span&gt;&lt;span class="o"&gt;:&lt;…
9812 &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/sp…
9813 cargo vendor -q &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt…
9814 mkdir .cargo &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &…
9815 cp cargo-vendor-config .cargo/config&lt;span class="o"&gt;)&lt;/span…
9816 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
9817
9818 &lt;p&gt;The tarball needs to have a &lt;code&gt;rust/.cargo/config&lt;/…
9819 the vendored sources (i.e. the embedded dependencies), but we don't
9820 want &lt;em&gt;that&lt;/em&gt; in our development source tree. Instead,…
9821 from a &lt;a href="https://git.gnome.org/browse/librsvg/tree/rust/cargo-…
9822 source tree:&lt;/p&gt;
9823 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
9824 &lt;span class="c1"&gt;#&lt;/span&gt;
9825 &lt;span class="c1"&gt;# In the distributed tarball, this file should en…
9826 &lt;span class="c1"&gt;# rust/.cargo/config&lt;/span&gt;
9827
9828 &lt;span class="k"&gt;[source.crates-io]&lt;/span&gt;
9829 &lt;span class="n"&gt;registry&lt;/span&gt; &lt;span class="o"&gt;=&lt;/…
9830 &lt;span class="n"&gt;replace-with&lt;/span&gt; &lt;span class="o"&gt;=&…
9831
9832 &lt;span class="k"&gt;[source.vendored-sources]&lt;/span&gt;
9833 &lt;span class="n"&gt;directory&lt;/span&gt; &lt;span class="o"&gt;=&lt;…
9834 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
9835
9836 &lt;h1&gt;One last thing&lt;/h1&gt;
9837 &lt;p&gt;If you put this in your &lt;code&gt;Cargo.toml&lt;/code&gt;, re…
9838 smaller. This turns on link-time optimizations (LTO), which removes
9839 unused functions from the binary.&lt;/p&gt;
9840 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
9841 &lt;span class="n"&gt;lto&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&…
9842 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
9843
9844 &lt;h1&gt;Summary and thanks&lt;/h1&gt;
9845 &lt;p&gt;I think the above is some good boilerplate that you can put in …
9846 &lt;code&gt;configure.ac&lt;/code&gt; / &lt;code&gt;Makefile.am&lt;/code…
9847 your C code. It handles &lt;code&gt;make&lt;/code&gt;-y things like &lt…
9848 check&lt;/code&gt;; debug and release builds; verbose and quiet builds;
9849 &lt;code&gt;builddir != srcdir&lt;/code&gt;; all the goodies.&lt;/p&gt;
9850 &lt;p&gt;I think the only thing I'm missing is to check for the &lt;code…
9851 binary. I'm not sure how to only check for that if I'm the one making
9852 tarballs... maybe an &lt;code&gt;--enable-maintainer-mode&lt;/code&gt; f…
9853 &lt;p&gt;This would definitely not have been possible without prior work.
9854 Thanks to everyone who figured out Autotools before me, so I could
9855 cut&amp;amp;paste your goodies:&lt;/p&gt;
9856 &lt;p&gt;&lt;em&gt;Update 2017/Nov/11:&lt;/em&gt; Fixed the initializati…
9857 to Tobias Mueller for catching this.&lt;/p&gt;
9858 &lt;ul&gt;
9859 &lt;li&gt;&lt;a href="https://www.figuiere.net/hub/blog/?2016/10/07/862-…
9860 &lt;li&gt;&lt;a href="http://lukenukem.co.nz/gsoc/2017/05/17/gso_2.html"…
9861 &lt;li&gt;&lt;a href="https://github.com/endlessm/ostree/commit/9169268c…
9862 &lt;li&gt;&lt;a href="https://blog.ometer.com/2017/01/10/dear-package-ma…
9863 &lt;/ul&gt;</content><category term="misc"></category><category term="li…
9864 &lt;p&gt;In the &lt;a href="https://people.gnome.org/~federico/blog/how-…
9865 the &lt;a href="http://gtk-rs.org/docs/glib/translate/trait.FromGlib.htm…
9866 code convert from/to Glib's simple types, like to convert from a Glib
9867 &lt;code&gt;gboolean&lt;/code&gt; to a Rust &lt;code&gt;bool&lt;/code&gt…
9868 &lt;p&gt;In the &lt;a href="https://people.gnome.org/~federico/blog/how-…
9869 the &lt;a href="http://gtk-rs.org/docs/glib/translate/trait.FromGlib.htm…
9870 code convert from/to Glib's simple types, like to convert from a Glib
9871 &lt;code&gt;gboolean&lt;/code&gt; to a Rust &lt;code&gt;bool&lt;/code&gt…
9872 needs of strings; since they are passed by reference and are not
9873 copied as simple values, we can use
9874 &lt;a href="http://gtk-rs.org/docs/glib/translate/trait.FromGlibPtrNone.…
9875 &lt;a href="http://gtk-rs.org/docs/glib/translate/trait.FromGlibPtrFull.…
9876 &lt;em&gt;ownership transfer&lt;/em&gt; we want, none for "just make it …
9877 using a borrowed reference", or full for "I'll take over the data and
9878 free it when I'm done". Going the other way around, we can use
9879 &lt;a href="http://gtk-rs.org/docs/glib/translate/trait.ToGlibPtr.html"&…
9880 Glib.&lt;/p&gt;
9881 &lt;p&gt;In this part, we'll see the tools that glib-rs provides to do
9882 conversions of more complex data types. We'll look at two cases:&lt;/p&…
9883 &lt;ul&gt;
9884 &lt;li&gt;
9885 &lt;p&gt;&lt;a href="#null-term-string-array"&gt;Passing null-terminated…
9886 from Glib to Rust&lt;/p&gt;
9887 &lt;/li&gt;
9888 &lt;li&gt;
9889 &lt;p&gt;&lt;a href="#passing-glists"&gt;Passing &lt;code&gt;GList&lt;/c…
9890 &lt;/li&gt;
9891 &lt;/ul&gt;
9892 &lt;p&gt;And one final case just in passing:&lt;/p&gt;
9893 &lt;ul&gt;
9894 &lt;li&gt;&lt;a href="#passing-containers-to-glib"&gt;Passing containers…
9895 &lt;/ul&gt;
9896 &lt;h1&gt;Passing arrays from Glib to Rust&lt;/h1&gt;
9897 &lt;p&gt;We'll look at the case for transferring null-terminated arrays …
9898 strings, since it's an interesting one. There are other traits to
9899 convert from Glib arrays whose length is known, not implied with a
9900 NULL element, but for now we'll only look at arrays of strings.&lt;/p&gt;
9901 &lt;h2 id="null-term-string-array"&gt;Null-terminated arrays of strings&…
9902 &lt;p&gt;Look at this function for &lt;code&gt;GtkAboutDialog&lt;/code&g…
9903 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
9904 &lt;span class="cm"&gt; * gtk_about_dialog_add_credit_section:&lt;/span&…
9905 &lt;span class="cm"&gt; * @about: A #GtkAboutDialog&lt;/span&gt;
9906 &lt;span class="cm"&gt; * @section_name: The name of the section&lt;/spa…
9907 &lt;span class="cm"&gt; * @people: (array zero-terminated=1): The people…
9908 &lt;span class="cm"&gt; * ...&lt;/span&gt;
9909 &lt;span class="cm"&gt; */&lt;/span&gt;
9910 &lt;span class="kt"&gt;void&lt;/span&gt;
9911 &lt;span class="n"&gt;gtk_about_dialog_add_credit_section&lt;/span&gt; &…
9912 &lt;span class="k"&gt;const&lt;/spa…
9913 &lt;span class="k"&gt;const&lt;/spa…
9914 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
9915
9916 &lt;p&gt;You would use this like&lt;/p&gt;
9917 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
9918 &lt;span class="s"&gt;&amp;quot;Alice &amp;lt;[email protected]&amp;…
9919 &lt;span class="s"&gt;&amp;quot;Bob &amp;lt;[email protected]&amp;gt;&…
9920 &lt;span class="s"&gt;&amp;quot;Clara &amp;lt;[email protected]&amp;…
9921 &lt;span class="nb"&gt;NULL&lt;/span&gt;
9922 &lt;span class="p"&gt;};&lt;/span&gt;
9923
9924 &lt;span class="n"&gt;gtk_about_dialog_add_credit_section&lt;/span&gt; &…
9925 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
9926
9927 &lt;p&gt;The function expects an array of &lt;code&gt;gchar *&lt;/code&g…
9928 a NULL. Instead of passing an explicit length for the array, it's
9929 done implicitly by requiring a NULL pointer after the last element.
9930 The gtk-doc annotation says &lt;code&gt;(array zero-terminated=1)&lt;/co…
9931 generate information for the GObject-Introspection Repository (GIR),
9932 this is what comes out:&lt;/p&gt;
9933 &lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;…
9934 &lt;span class="normal"&gt; 2&lt;/span&gt;
9935 &lt;span class="normal"&gt; 3&lt;/span&gt;
9936 &lt;span class="normal"&gt; 4&lt;/span&gt;
9937 &lt;span class="normal"&gt; 5&lt;/span&gt;
9938 &lt;span class="normal"&gt; 6&lt;/span&gt;
9939 &lt;span class="normal"&gt; 7&lt;/span&gt;
9940 &lt;span class="normal"&gt; 8&lt;/span&gt;
9941 &lt;span class="normal"&gt; 9&lt;/span&gt;
9942 &lt;span class="normal"&gt;10&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/t…
9943 &lt;span class="na"&gt;c:identifier=&lt;/span&gt;&lt;span class=…
9944 &lt;span class="na"&gt;version=&lt;/span&gt;&lt;span class="s"&g…
9945 ..
9946 &lt;span class="nt"&gt;&amp;lt;parameter&lt;/span&gt; &lt;span class…
9947 &lt;span class="nt"&gt;&amp;lt;doc&lt;/span&gt; &lt;span class="na…
9948 &lt;span class="nt"&gt;&amp;lt;array&lt;/span&gt; &lt;span class="…
9949 &lt;span class="nt"&gt;&amp;lt;type&lt;/span&gt; &lt;span class=…
9950 &lt;span class="nt"&gt;&amp;lt;/array&amp;gt;&lt;/span&gt;
9951 &lt;span class="nt"&gt;&amp;lt;/parameter&amp;gt;&lt;/span&gt;
9952 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
9953 &lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
9954 &lt;p&gt;You can see the &lt;code&gt;transfer-ownership="none"&lt;/code&…
9955 that the function will not take ownership of the passed array; it will
9956 make its own copy instead. By convention, GIR assumes that arrays of
9957 strings are NULL-terminated, so there is no special annotation for
9958 that here. If we were implementing this function in Rust, how would we
9959 read that C array of UTF-8 strings and turn it into a Rust
9960 &lt;code&gt;Vec&amp;lt;String&amp;gt;&lt;/code&gt; or something? Easy:&…
9961 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
9962 &lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&…
9963 &lt;span class="c1"&gt;// rust_translators is a Vec&amp;lt;String&amp;gt…
9964 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
9965
9966 &lt;p&gt;Let's look at how this bad boy is implemented.&lt;/p&gt;
9967 &lt;h3&gt;First stage: &lt;code&gt;impl FromGlibPtrContainer for Vec&amp…
9968 &lt;p&gt;We want to go from a "&lt;code&gt;*mut *mut c_char&lt;/code&g…
9969 to a &lt;code&gt;Vec&amp;lt;String&amp;gt;&lt;/code&gt;. Indeed, there …
9970 &lt;code&gt;FromGlibPtrContainer&lt;/code&gt; trait for &lt;code&gt;Vec&…
9971 &lt;a href="https://github.com/gtk-rs/glib/blob/e46aa7f27cc74f3cdcb54d94…
9972 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
9973 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;unsafe&lt;/…
9974 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FromGli…
9975 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&…
9976 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
9977
9978 &lt;p&gt;So... that &lt;code&gt;from_glib_none()&lt;/code&gt; will retur…
9979 want. Let's look at the first few lines of &lt;a href="https://github.c…
9980 &lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;…
9981 &lt;span class="normal"&gt;2&lt;/span&gt;
9982 &lt;span class="normal"&gt;3&lt;/span&gt;
9983 &lt;span class="normal"&gt;4&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td…
9984 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;unsafe&…
9985 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Fro…
9986 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/s…
9987 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
9988 &lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
9989 &lt;p&gt;Aha! This is inside a &lt;a href="https://github.com/gtk-rs/gl…
9990 It's done like that so the same trait can be implemented for &lt;code&gt…
9991 &lt;code&gt;mut&lt;/code&gt; pointers to &lt;code&gt;c_char&lt;/code&gt;…
9992 &lt;p&gt;See the call to &lt;code&gt;c_ptr_array_len()&lt;/code&gt; in l…
9993 out where the NULL pointer is at the end of the array: it figures out
9994 the array's length. &lt;/p&gt;
9995 &lt;h3&gt;Second stage: &lt;code&gt;impl FromGlibContainerAsVec::from_gl…
9996 &lt;p&gt;Now that the length of the array is known, the implementation c…
9997 &lt;a href="https://github.com/gtk-rs/glib/blob/e46aa7f27cc74f3cdcb54d94…
9998 &lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;…
9999 &lt;span class="normal"&gt; 2&lt;/span&gt;
10000 &lt;span class="normal"&gt; 3&lt;/span&gt;
10001 &lt;span class="normal"&gt; 4&lt;/span&gt;
10002 &lt;span class="normal"&gt; 5&lt;/span&gt;
10003 &lt;span class="normal"&gt; 6&lt;/span&gt;
10004 &lt;span class="normal"&gt; 7&lt;/span&gt;
10005 &lt;span class="normal"&gt; 8&lt;/span&gt;
10006 &lt;span class="normal"&gt; 9&lt;/span&gt;
10007 &lt;span class="normal"&gt;10&lt;/span&gt;
10008 &lt;span class="normal"&gt;11&lt;/span&gt;
10009 &lt;span class="normal"&gt;12&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/t…
10010 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;unsafe&…
10011 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&…
10012 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt…
10013 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&l…
10014
10015 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;le…
10016 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;for…
10017 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt…
10018 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&l…
10019 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;res…
10020 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/s…
10021 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
10022 &lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
10023 &lt;p&gt;Lines 3/4: If the number of elements is zero, or the array is N…
10024 return an empty &lt;code&gt;Vec&lt;/code&gt;.&lt;/p&gt;
10025 &lt;p&gt;Line 7: Allocate a &lt;code&gt;Vec&lt;/code&gt; of suitable siz…
10026 &lt;p&gt;Lines 8/9: For each of the pointers in the C array, call
10027 &lt;code&gt;from_glib_none()&lt;/code&gt; to convert it from a &lt;code&…
10028 like we saw in &lt;a href="https://people.gnome.org/~federico/blog/how-g…
10029 &lt;p&gt;Done! We started with a &lt;code&gt;*mut *mut c_char&lt;/code&…
10030 c_char&lt;/code&gt; and ended up with a &lt;code&gt;Vec&amp;lt;String&am…
10031 &lt;h1 id="passing-glists"&gt;Passing &lt;code&gt;GList&lt;/code&gt;s to…
10032 &lt;p&gt;Some functions don't give you an array; they give you a &lt;cod…
10033 &lt;code&gt;GSList&lt;/code&gt;. There is an implementation of
10034 &lt;code&gt;FromGlibPtrArrayContainerAsVec&lt;/code&gt; &lt;a href="http…
10035 &lt;code&gt;GList&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt;
10036 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
10037 &lt;span class="k"&gt;where&lt;/span&gt;&lt;span class="w"&gt; &lt;/span…
10038
10039 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;unsafe&lt;/…
10040 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;let&lt…
10041 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FromGli…
10042 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&…
10043 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
10044
10045 &lt;p&gt;The &lt;code&gt;impl&lt;/code&gt; declaration is pretty horribl…
10046 method: &lt;code&gt;from_glib_none_as_vec()&lt;/code&gt; takes in a &lt…
10047 &lt;code&gt;g_list_length()&lt;/code&gt; on it, and finally calls
10048 &lt;code&gt;FromGlibContainer::from_glib_none_num()&lt;/code&gt; with th…
10049 &lt;h3&gt;I have a Glib container and its length&lt;/h3&gt;
10050 &lt;p&gt;In turn, that &lt;code&gt;from_glib_none_num()&lt;/code&gt; goe…
10051 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
10052 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;unsafe&lt;/…
10053 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FromGli…
10054 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&…
10055 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
10056
10057 &lt;p&gt;Okay, getting closer to the actual implementation.&lt;/p&gt;
10058 &lt;h3&gt;Give me a vector already&lt;/h3&gt;
10059 &lt;p&gt;Finally, we get to the function that &lt;a href="https://github…
10060 &lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;…
10061 &lt;span class="normal"&gt; 2&lt;/span&gt;
10062 &lt;span class="normal"&gt; 3&lt;/span&gt;
10063 &lt;span class="normal"&gt; 4&lt;/span&gt;
10064 &lt;span class="normal"&gt; 5&lt;/span&gt;
10065 &lt;span class="normal"&gt; 6&lt;/span&gt;
10066 &lt;span class="normal"&gt; 7&lt;/span&gt;
10067 &lt;span class="normal"&gt; 8&lt;/span&gt;
10068 &lt;span class="normal"&gt; 9&lt;/span&gt;
10069 &lt;span class="normal"&gt;10&lt;/span&gt;
10070 &lt;span class="normal"&gt;11&lt;/span&gt;
10071 &lt;span class="normal"&gt;12&lt;/span&gt;
10072 &lt;span class="normal"&gt;13&lt;/span&gt;
10073 &lt;span class="normal"&gt;14&lt;/span&gt;
10074 &lt;span class="normal"&gt;15&lt;/span&gt;
10075 &lt;span class="normal"&gt;16&lt;/span&gt;
10076 &lt;span class="normal"&gt;17&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/t…
10077 &lt;span class="k"&gt;where&lt;/span&gt;&lt;span class="w"&gt; &lt;/span…
10078
10079 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;unsafe&lt;/…
10080 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/…
10081 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ret…
10082 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/s…
10083 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;let&lt…
10084 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;for&lt;…
10085 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;le…
10086 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&…
10087 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt…
10088 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&l…
10089 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ptr…
10090 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/s…
10091 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;res&lt;…
10092 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&…
10093 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
10094 &lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
10095 &lt;p&gt;Again, ignore the horrible &lt;code&gt;impl&lt;/code&gt; declar…
10096 &lt;code&gt;from_glib_none_num_as_vec()&lt;/code&gt;.&lt;/p&gt;
10097 &lt;p&gt;Line 4: that function takes in a &lt;code&gt;ptr&lt;/code&gt; t…
10098 the list's length, which we already computed above.&lt;/p&gt;
10099 &lt;p&gt;Line 5: Return an empty vector if we have an empty list.&lt;/p&…
10100 &lt;p&gt;Line 8: Allocate a vector of suitable capacity.&lt;/p&gt;
10101 &lt;p&gt;Line 9: For each element, convert it with &lt;code&gt;from_glib…
10102 it to the array.&lt;/p&gt;
10103 &lt;p&gt;Line 14: Walk to the next element in the list.&lt;/p&gt;
10104 &lt;h1 id="passing-containers-to-glib"&gt;Passing containers from Rust t…
10105 &lt;p&gt;This post is getting a bit long, so I'll just mention this brie…
10106 There is a trait &lt;code&gt;ToGlibContainerFromSlice&lt;/code&gt; that …
10107 and can convert it to various Glib types.&lt;/p&gt;
10108 &lt;ul&gt;
10109 &lt;li&gt;
10110 &lt;p&gt;To &lt;a href="https://github.com/gtk-rs/glib/blob/e46aa7f27cc7…
10111 methods like &lt;code&gt;to_glib_none_from_slice()&lt;/code&gt; and
10112 &lt;code&gt;to_glib_full_from_slice()&lt;/code&gt;&lt;/p&gt;
10113 &lt;/li&gt;
10114 &lt;li&gt;
10115 &lt;p&gt;To an &lt;a href="https://github.com/gtk-rs/glib/blob/e46aa7f27…
10116 between &lt;code&gt;to_glib_none_from_slice()&lt;/code&gt;, which give…
10117 we saw &lt;a href="https://people.gnome.org/~federico/blog/how-glib-rs…
10118 &lt;code&gt;to_glib_full_from_slice()&lt;/code&gt;, which gives you ba…
10119 array with copied items. Finally, &lt;code&gt;to_glib_container_from_…
10120 gives you back a &lt;code&gt;g_malloc()&lt;/code&gt;ed array of &lt;em…
10121 than plain values themselves. Which function you choose depends on
10122 which C API you want to call.&lt;/p&gt;
10123 &lt;/li&gt;
10124 &lt;/ul&gt;
10125 &lt;p&gt;I hope this post gives you enough practice to be able to "follo…
10126 traits" for each of those if you want to look at the implementations.&lt…
10127 &lt;h1&gt;Next up&lt;/h1&gt;
10128 &lt;p&gt;Passing boxed types, like public structs.&lt;/p&gt;
10129 &lt;p&gt;Passing reference-counted types.&lt;/p&gt;
10130 &lt;p&gt;How glib-rs wraps GObjects.&lt;/p&gt;</content><category term="…
10131 &lt;li&gt;&lt;a href="https://people.gnome.org/~federico/blog/how-glib-r…
10132 &lt;li&gt;&lt;a href="https://people.gnome.org/~federico/blog/how-glib-r…
10133 &lt;li&gt;&lt;a href="https://people.gnome.org/~federico/blog/how-glib-r…
10134 &lt;/ul&gt;
10135 &lt;p&gt;During the &lt;a href="https://wiki.gnome.org/Hackfests/Rust201…
10136 started the implementation of &lt;a href="http://smallcultfollowing.com/…
10137 that will let people implement new GObject classes in …&lt;/p&gt;</sum…
10138 &lt;li&gt;&lt;a href="https://people.gnome.org/~federico/blog/how-glib-r…
10139 &lt;li&gt;&lt;a href="https://people.gnome.org/~federico/blog/how-glib-r…
10140 &lt;li&gt;&lt;a href="https://people.gnome.org/~federico/blog/how-glib-r…
10141 &lt;/ul&gt;
10142 &lt;p&gt;During the &lt;a href="https://wiki.gnome.org/Hackfests/Rust201…
10143 started the implementation of &lt;a href="http://smallcultfollowing.com/…
10144 that will let people implement new GObject classes in Rust and export
10145 them to the world. Currently, if you want to write a new GObject
10146 (e.g. a new widget) and put it in a library so that it can be used
10147 from language bindings via GObject-Introspection, you have to do it in
10148 C. It would be nice to be able to do this in a safe language like
10149 Rust.&lt;/p&gt;
10150 &lt;h1&gt;How would it be done by hand?&lt;/h1&gt;
10151 &lt;p&gt;In a C implementation of a new GObject subclass, one calls thin…
10152 &lt;code&gt;g_type_register_static()&lt;/code&gt; and &lt;code&gt;g_sign…
10153 careful to specify the correct &lt;code&gt;GType&lt;/code&gt; for each v…
10154 super-careful about everything, as C demands.&lt;/p&gt;
10155 &lt;p&gt;In Rust, one &lt;em&gt;can&lt;/em&gt; in fact do exactly the sa…
10156 same, low-level GObject and GType functions. You can use
10157 &lt;code&gt;#[repr(C)]&lt;/code&gt;] for the instance and class structs …
10158 allocate for you, and which you then fill in.&lt;/p&gt;
10159 &lt;p&gt;You can see an example of this in gst-plugins-rs. This is wher…
10160 GObject, in Rust, by calling Glib functions by
10161 hand: &lt;a href="https://github.com/sdroege/gst-plugin-rs/blob/782fe5dc…
10162 &lt;a href="https://github.com/sdroege/gst-plugin-rs/blob/782fe5dcc93dbd…
10163 &lt;h1&gt;How would it be done by a machine?&lt;/h1&gt;
10164 &lt;p&gt;That's what Niko's gnome-class is about. During the hackfest it
10165 got to the point of being able to generate the code to create a new
10166 GObject subclass, register it, and export functions for methods. The
10167 syntax is not finalized yet, but it looks something like this:&lt;/p&gt;
10168 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
10169 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;class&lt;/s…
10170 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;struct&…
10171 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;val…
10172 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/s…
10173
10174 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;signal&…
10175
10176 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/…
10177 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;le…
10178 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pri…
10179 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;//…
10180 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/s…
10181
10182 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/…
10183 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;le…
10184 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pri…
10185 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/s…
10186 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&…
10187 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
10188 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
10189
10190 &lt;p&gt;I started adding support for declaring GObject signals — main…
10191 able to parse them from what goes inside &lt;code&gt;gobject_gen!()&lt;/…
10192 being able to call &lt;code&gt;g_signal_newv()&lt;/code&gt; at the appro…
10193 the &lt;code&gt;class_init()&lt;/code&gt; implementation.&lt;/p&gt;
10194 &lt;h1&gt;Types in signals&lt;/h1&gt;
10195 &lt;p&gt;Creating a signal for a GObject class is basically like specify…
10196 function prototype: the object will invoke a callback function with
10197 certain arguments and return value when the signal is emitted. For
10198 example, this is how &lt;code&gt;GtkButton&lt;/code&gt; registers its &l…
10199 signal&lt;/a&gt;:&lt;/p&gt;
10200 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
10201 &lt;span class="n"&gt;g_signal_new&lt;/span&gt; &lt;span class="p"&g…
10202 &lt;span class="p"&gt;...&lt;/span&gt;
10203 &lt;span class="n"&gt;G_TYPE_BOOLEAN&lt;/span&gt;&lt;s…
10204 &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p…
10205 &lt;span class="n"&gt;GDK_TYPE_EVENT&lt;/span&gt;&lt;s…
10206 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
10207
10208 &lt;p&gt;&lt;code&gt;g_signal_new()&lt;/code&gt; creates the signal and …
10209 integer. Later, when the object wants to emit the signal, it uses
10210 that signal id like this:&lt;/p&gt;
10211 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
10212 &lt;span class="n"&gt;gboolean&lt;/span&gt; &lt;span class="n"&gt;return…
10213
10214 &lt;span class="n"&gt;g_signal_emit&lt;/span&gt; &lt;span class="p"&gt;(…
10215 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
10216
10217 &lt;p&gt;In the nice &lt;code&gt;gobject_gen!()&lt;/code&gt; macro, if I…
10218 declaration like&lt;/p&gt;
10219 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
10220 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
10221
10222 &lt;p&gt;then I will need to be able to translate the type names for
10223 &lt;code&gt;ButtonPressEvent&lt;/code&gt; and &lt;code&gt;bool&lt;/code&…
10224 understand: I need the &lt;a href="https://developer.gnome.org/gobject/…
10225 types like &lt;code&gt;gboolean&lt;/code&gt; get constants like &lt;a hr…
10226 that are defined at runtime, like &lt;code&gt;GDK_TYPE_EVENT&lt;/code&gt…
10227 generated at runtime, too, when one registers the type with
10228 &lt;code&gt;g_type_register_*()&lt;/code&gt;.&lt;/p&gt;
10229 &lt;table&gt;
10230 &lt;thead&gt;
10231 &lt;tr&gt;
10232 &lt;th align="left"&gt;Rust type&lt;/th&gt;
10233 &lt;th align="left"&gt;GType&lt;/th&gt;
10234 &lt;/tr&gt;
10235 &lt;/thead&gt;
10236 &lt;tbody&gt;
10237 &lt;tr&gt;
10238 &lt;td align="left"&gt;i32&lt;/td&gt;
10239 &lt;td align="left"&gt;G_TYPE_INT&lt;/td&gt;
10240 &lt;/tr&gt;
10241 &lt;tr&gt;
10242 &lt;td align="left"&gt;u32&lt;/td&gt;
10243 &lt;td align="left"&gt;G_TYPE_UINT&lt;/td&gt;
10244 &lt;/tr&gt;
10245 &lt;tr&gt;
10246 &lt;td align="left"&gt;bool&lt;/td&gt;
10247 &lt;td align="left"&gt;G_TYPE_BOOLEAN&lt;/td&gt;
10248 &lt;/tr&gt;
10249 &lt;tr&gt;
10250 &lt;td align="left"&gt;etc.&lt;/td&gt;
10251 &lt;td align="left"&gt;etc.&lt;/td&gt;
10252 &lt;/tr&gt;
10253 &lt;/tbody&gt;
10254 &lt;/table&gt;
10255 &lt;h1&gt;Glib types in Rust&lt;/h1&gt;
10256 &lt;p&gt;How does &lt;a href="http://gtk-rs.org/docs/glib/"&gt;glib-rs&l…
10257 types?&lt;/p&gt;
10258 &lt;h2&gt;Going from Glib to Rust&lt;/h2&gt;
10259 &lt;p&gt;First we need a way to convert Glib's types to Rust, and vice-v…
10260 There is a trait to convert simple Glib types into Rust types:&lt;/p&gt;
10261 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
10262 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span…
10263 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
10264 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
10265
10266 &lt;p&gt;This means, if I have a &lt;code&gt;T&lt;/code&gt; which is a G…
10267 you a &lt;code&gt;from_glib()&lt;/code&gt; function which will convert i…
10268 which is &lt;code&gt;Sized&lt;/code&gt;, i.e. a type whose size is known…
10269 &lt;p&gt;For example, this is how it is implemented for booleans:&lt;/p&…
10270 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
10271 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cp"&gt;#[inline]&…
10272 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span…
10273 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!&lt;/s…
10274 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&…
10275 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
10276 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
10277
10278 &lt;p&gt;and you use it like this:&lt;/p&gt;
10279 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
10280
10281 &lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&…
10282 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
10283
10284 &lt;p&gt;Booleans in glib and Rust have &lt;a href="https://people.gnome…
10285 different values. Glib's booleans use the C convention: 0 is false
10286 and anything else is true, while in Rust booleans are strictly &lt;code&…
10287 or &lt;code&gt;true&lt;/code&gt;, and the size is undefined (with the cu…
10288 one byte).&lt;/p&gt;
10289 &lt;h2&gt;Going from Rust to Glib&lt;/h2&gt;
10290 &lt;p&gt;And to go the other way around, from a Rust &lt;code&gt;bool&lt…
10291 There is this trait:&lt;/p&gt;
10292 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
10293 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;type&lt;/sp…
10294
10295 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span…
10296 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
10297 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
10298
10299 &lt;p&gt;This means, if you have a Rust type that maps to a corresponding
10300 &lt;code&gt;GlibType&lt;/code&gt;, this will give you a &lt;code&gt;to_g…
10301 conversion.&lt;/p&gt;
10302 &lt;p&gt;This is the implementation for booleans:&lt;/p&gt;
10303 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
10304 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;type&lt;/sp…
10305
10306 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cp"&gt;#[inline]&…
10307 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span…
10308 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/…
10309 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&…
10310 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
10311 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
10312
10313 &lt;p&gt;And it is used like this:&lt;/p&gt;
10314 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
10315
10316 &lt;span class="n"&gt;g_some_function_that_takes_gboolean&lt;/span&gt;&l…
10317 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
10318
10319 &lt;p&gt;(If you are thinking "a function call to marshal a boolean" —…
10320 the functions are inlined, and the optimizer basically compiles them
10321 down to nothing.)&lt;/p&gt;
10322 &lt;h2 id="pointer-types"&gt;Pointer types - from Glib to Rust&lt;/h2&gt;
10323 &lt;p&gt;That's all very nice for simple types like booleans and ints.
10324 Pointers to other objects are slightly more complicated.&lt;/p&gt;
10325 &lt;p&gt;GObject-Introspection allows one to specify how pointer argumen…
10326 functions are handled by using a &lt;a href="https://developer.gnome.org…
10327 &lt;h3&gt;&lt;code&gt;(transfer none)&lt;/code&gt;&lt;/h3&gt;
10328 &lt;p&gt;For example, if you call &lt;code&gt;gtk_window_set_title(windo…
10329 would expect the function to make its own copy of the &lt;code&gt;"Hello…
10330 string. In Rust terms, you would be passing it a simple &lt;em&gt;borro…
10331 reference&lt;/em&gt;. GObject-Introspection (we'll abbreviate it as GI)…
10332 this &lt;code&gt;GI_TRANSFER_NOTHING&lt;/code&gt;, and it's specified by…
10333 &lt;code&gt;(transfer none)&lt;/code&gt; in the documentation strings f…
10334 or return values.&lt;/p&gt;
10335 &lt;p&gt;The corresponding trait to bring in pointers from Glib to Rust,
10336 without taking ownership, is this. It's &lt;code&gt;unsafe&lt;/code&gt;…
10337 used to de-reference pointers that come from the wild west:&lt;/p&gt;
10338 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
10339 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;unsafe&lt;/…
10340 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
10341 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
10342
10343 &lt;p&gt;And you use it via this generic function:&lt;/p&gt;
10344 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
10345 &lt;span class="k"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&g…
10346 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FromGlibPtr…
10347 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
10348 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
10349
10350 &lt;p&gt;Let's look at how this works. Here is the &lt;code&gt;FromGlib…
10351 implemented for strings.&lt;/p&gt;
10352 &lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;…
10353 &lt;span class="normal"&gt;2&lt;/span&gt;
10354 &lt;span class="normal"&gt;3&lt;/span&gt;
10355 &lt;span class="normal"&gt;4&lt;/span&gt;
10356 &lt;span class="normal"&gt;5&lt;/span&gt;
10357 &lt;span class="normal"&gt;6&lt;/span&gt;
10358 &lt;span class="normal"&gt;7&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td…
10359 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cp"&gt;#[inline]&…
10360 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;unsafe&lt;/…
10361 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="fm"&gt;assert…
10362 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String…
10363 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&…
10364 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
10365 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
10366 &lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
10367 &lt;p&gt;Line 1: given a pointer to a &lt;code&gt;c_char&lt;/code&gt;, t…
10368 &lt;p&gt;Line 4: check for NULL pointers&lt;/p&gt;
10369 &lt;p&gt;Line 5: Use the CStr to wrap the C
10370 &lt;code&gt;ptr&lt;/code&gt;, &lt;a href="https://people.gnome.org/~fede…
10371 copy the string for us.&lt;/p&gt;
10372 &lt;p&gt;Unfortunately, there's a copy involved in the last step. It ma…
10373 possible to use &lt;a href="https://doc.rust-lang.org/std/borrow/enum.Co…
10374 the &lt;code&gt;char*&lt;/code&gt; from Glib is indeed valid UTF-8.&lt;/…
10375 &lt;h3&gt;&lt;code&gt;(transfer full)&lt;/code&gt;&lt;/h3&gt;
10376 &lt;p&gt;And how about transferring ownership of the pointed-to value? …
10377 is this trait:&lt;/p&gt;
10378 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
10379 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;unsafe&lt;/…
10380 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
10381 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
10382
10383 &lt;p&gt;And the implementation for strings is as follows. In Glib's sc…
10384 things, "transferring ownership of a string" means that the recipient
10385 of the string must eventually &lt;code&gt;g_free()&lt;/code&gt; it.&lt;/…
10386 &lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;…
10387 &lt;span class="normal"&gt;2&lt;/span&gt;
10388 &lt;span class="normal"&gt;3&lt;/span&gt;
10389 &lt;span class="normal"&gt;4&lt;/span&gt;
10390 &lt;span class="normal"&gt;5&lt;/span&gt;
10391 &lt;span class="normal"&gt;6&lt;/span&gt;
10392 &lt;span class="normal"&gt;7&lt;/span&gt;
10393 &lt;span class="normal"&gt;8&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td…
10394 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cp"&gt;#[inline]&…
10395 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;unsafe&lt;/…
10396 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;let&lt…
10397 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;glib_ff…
10398 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;res&lt;…
10399 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&…
10400 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
10401 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
10402 &lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
10403 &lt;p&gt;Line 1: given a pointer to a &lt;code&gt;c_char&lt;/code&gt;, t…
10404 &lt;p&gt;Line 4: Do the conversion with &lt;code&gt;from_glib_none()&lt;…
10405 saw before, put it in &lt;code&gt;res&lt;/code&gt;.&lt;/p&gt;
10406 &lt;p&gt;Line 5: Call &lt;code&gt;g_free()&lt;/code&gt; on the original …
10407 &lt;p&gt;Line 6: Return the &lt;code&gt;res&lt;/code&gt;, a Rust string …
10408 &lt;h2&gt;Pointer types - from Rust to Glib&lt;/h2&gt;
10409 &lt;p&gt;Consider the case where you want to pass a &lt;code&gt;String&l…
10410 that takes a &lt;code&gt;*const c_char&lt;/code&gt; — in C parlance, a…
10411 Glib function acquiring ownership of the string. For example, assume
10412 that the C version of &lt;code&gt;gtk_window_set_title()&lt;/code&gt; is…
10413 module. You may want to call it like this:&lt;/p&gt;
10414 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
10415 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;gtk_ffi&lt;…
10416 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
10417 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
10418
10419 &lt;p&gt;Now, what would that &lt;code&gt;make_c_string_from_rust_string…
10420 &lt;ul&gt;
10421 &lt;li&gt;
10422 &lt;p&gt;&lt;strong&gt;We have:&lt;/strong&gt; a Rust &lt;code&gt;String…
10423 &lt;/li&gt;
10424 &lt;li&gt;
10425 &lt;p&gt;&lt;strong&gt;We want:&lt;/strong&gt; a &lt;code&gt;*const char…
10426 &lt;/li&gt;
10427 &lt;/ul&gt;
10428 &lt;p&gt;So, let's write this:&lt;/p&gt;
10429 &lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;…
10430 &lt;span class="normal"&gt;2&lt;/span&gt;
10431 &lt;span class="normal"&gt;3&lt;/span&gt;
10432 &lt;span class="normal"&gt;4&lt;/span&gt;
10433 &lt;span class="normal"&gt;5&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td…
10434 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/sp…
10435 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/sp…
10436 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ptr&lt;/spa…
10437 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
10438 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
10439 &lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
10440 &lt;p&gt;Line 1: Take in a &lt;code&gt;&amp;amp;String&lt;/code&gt;; ret…
10441 &lt;p&gt;Line 2: Build a &lt;a href="https://people.gnome.org/~federico/…
10442 allocates a byte buffer with space for a nul terminator, and copies
10443 the string's bytes. We &lt;code&gt;unwrap()&lt;/code&gt; for this simpl…
10444 &lt;code&gt;CString::new()&lt;/code&gt; will return an error if the &lt;…
10445 characters in the middle of the string, which C doesn't understand.&lt;/…
10446 &lt;p&gt;Line 3: Call &lt;code&gt;into_raw()&lt;/code&gt; to get a point…
10447 cast it to a &lt;code&gt;*const c_char&lt;/code&gt;. &lt;em&gt;We'll ne…
10448 &lt;p&gt;But this kind of sucks, because we the have to use this functio…
10449 the pointer to a C function, and then reconstitute the &lt;code&gt;CStri…
10450 can free the byte buffer:&lt;/p&gt;
10451 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
10452 &lt;span class="k"&gt;unsafe&lt;/span&gt;&lt;span class="w"&gt; &lt;/spa…
10453 &lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&…
10454 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
10455
10456 &lt;p&gt;The solution that Glib-rs provides for this is very Rusty, and …
10457 elegant.&lt;/p&gt;
10458 &lt;h3&gt;Stashes&lt;/h3&gt;
10459 &lt;p&gt;We want:&lt;/p&gt;
10460 &lt;ul&gt;
10461 &lt;li&gt;A temporary place to put a piece of data&lt;/li&gt;
10462 &lt;li&gt;A pointer to that buffer&lt;/li&gt;
10463 &lt;li&gt;Automatic memory management for both of those&lt;/li&gt;
10464 &lt;/ul&gt;
10465 &lt;p&gt;Glib-rs defines a &lt;code&gt;Stash&lt;/code&gt; for this:&lt;/…
10466 &lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;…
10467 &lt;span class="normal"&gt;2&lt;/span&gt;
10468 &lt;span class="normal"&gt;3&lt;/span&gt;
10469 &lt;span class="normal"&gt;4&lt;/span&gt;
10470 &lt;span class="normal"&gt;5&lt;/span&gt;
10471 &lt;span class="normal"&gt;6&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td…
10472 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&g…
10473 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&g…
10474 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;pub&lt;/spa…
10475 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;pub&lt;/spa…
10476 &lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
10477 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
10478 &lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
10479 &lt;p&gt;... and the piece of data must be of of the &lt;em&gt;associate…
10480 &lt;code&gt;ToGlibPtr::Storage&lt;/code&gt;, which we will see shortly.&…
10481 &lt;p&gt;This struct &lt;code&gt;Stash&lt;/code&gt; goes along with the …
10482 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
10483 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;type&lt;/sp…
10484
10485 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span…
10486 &lt;span class="w"&gt; …
10487 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
10488 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
10489
10490 &lt;p&gt;Let's unpack this by looking at the implementation of the "tran…
10491 String to a C function while keeping ownership":&lt;/p&gt;
10492 &lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;…
10493 &lt;span class="normal"&gt;2&lt;/span&gt;
10494 &lt;span class="normal"&gt;3&lt;/span&gt;
10495 &lt;span class="normal"&gt;4&lt;/span&gt;
10496 &lt;span class="normal"&gt;5&lt;/span&gt;
10497 &lt;span class="normal"&gt;6&lt;/span&gt;
10498 &lt;span class="normal"&gt;7&lt;/span&gt;
10499 &lt;span class="normal"&gt;8&lt;/span&gt;
10500 &lt;span class="normal"&gt;9&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td…
10501 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;type&lt;/sp…
10502
10503 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cp"&gt;#[inline]&…
10504 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span…
10505 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;let&lt…
10506 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Stash&l…
10507 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&…
10508 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
10509 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
10510 &lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
10511 &lt;p&gt;Line 1: We implement &lt;code&gt;ToGlibPtr&amp;lt;'a *const c_c…
10512 declaring the lifetime &lt;code&gt;'a&lt;/code&gt; for the &lt;code&gt;S…
10513 &lt;p&gt;Line 2: Our temporary storage is a &lt;code&gt;CString&lt;/code…
10514 &lt;p&gt;Line 6: Make a CString like before.&lt;/p&gt;
10515 &lt;p&gt;Line 7: Create the &lt;code&gt;Stash&lt;/code&gt; with a pointe…
10516 and the CString itself.&lt;/p&gt;
10517 &lt;h3&gt;&lt;code&gt;(transfer none)&lt;/code&gt;&lt;/h3&gt;
10518 &lt;p&gt;Now, we can use "&lt;code&gt;.0&lt;/code&gt;" to extract the fi…
10519 which is precisely the pointer we want to a byte buffer:&lt;/p&gt;
10520 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
10521 &lt;span class="k"&gt;unsafe&lt;/span&gt;&lt;span class="w"&gt; &lt;/spa…
10522 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
10523
10524 &lt;p&gt;Now Rust knows that the temporary buffer inside the &lt;code&gt…
10525 &lt;code&gt;my_string&lt;/code&gt;, and it will free it automatically wh…
10526 out of scope. If we can accept the &lt;code&gt;.to_glib_none().0&lt;/co…
10527 for "lending" pointers to C, this works perfectly.&lt;/p&gt;
10528 &lt;h3 id="ptr-transfer-full"&gt;&lt;code&gt;(transfer full)&lt;/code&g…
10529 &lt;p&gt;And for transferring ownership to the C function? The &lt;code…
10530 trait has another method:&lt;/p&gt;
10531 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
10532 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;..&lt;/span…
10533
10534 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span…
10535 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
10536 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
10537
10538 &lt;p&gt;And here is the implementation for strings:&lt;/p&gt;
10539 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
10540 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span…
10541 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;unsafe&…
10542 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;gli…
10543 &lt;span class="w"&gt; &lt;/span&gt;&lt;s…
10544 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt…
10545 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/s…
10546 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&…
10547 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
10548
10549 &lt;p&gt;We basically &lt;code&gt;g_strndup()&lt;/code&gt; the Rust stri…
10550 buffer &lt;em&gt;and&lt;/em&gt; its &lt;code&gt;len()&lt;/code&gt;, and …
10551 code will be responsible for &lt;code&gt;g_free()&lt;/code&gt;ing the C-…
10552 &lt;h1&gt;Next up&lt;/h1&gt;
10553 &lt;p&gt;Transferring lists and arrays. Stay tuned!&lt;/p&gt;</content>…
10554 in several ways. In this post I'll show several things related to the
10555 process of building strings, from bytes in memory, or from a file, or
10556 from &lt;code&gt;char *&lt;/code&gt; things passed from C.&lt;/p&gt;
10557 &lt;h1&gt;Strings in Rust&lt;/h1&gt;
10558 &lt;p&gt;The easiest way to build …&lt;/p&gt;</summary><content type="…
10559 in several ways. In this post I'll show several things related to the
10560 process of building strings, from bytes in memory, or from a file, or
10561 from &lt;code&gt;char *&lt;/code&gt; things passed from C.&lt;/p&gt;
10562 &lt;h1&gt;Strings in Rust&lt;/h1&gt;
10563 &lt;p&gt;The easiest way to build a string is to do it directly at compi…
10564 time:&lt;/p&gt;
10565 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
10566 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
10567
10568 &lt;p&gt;In Rust, strings are UTF-8. Here, the compiler checks our stri…
10569 literal is valid UTF-8. If we try to be sneaky and insert an
10570 invalid character...&lt;/p&gt;
10571 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
10572 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
10573
10574 &lt;p&gt;We get a compiler error:&lt;/p&gt;
10575 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
10576 --&amp;gt; foo.rs:2:30
10577 |
10578 2 | let my_string = &amp;quot;Hello \xf0&amp;quot;;
10579 | ^^
10580 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
10581
10582 &lt;p&gt;Rust strings know their length, unlike C strings. They &lt;em&…
10583 a nul character in the middle, because they don't need a nul
10584 terminator at the end.&lt;/p&gt;
10585 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
10586 &lt;span class="fm"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/…
10587 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
10588
10589 &lt;p&gt;The output is what you expect:&lt;/p&gt;
10590 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
10591 00000000 48 65 6c 6c 6f 20 00 20 7a 65 72 6f 0a |Hello . zer…
10592 0000000d ^ note the nul char here
10593 $
10594 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
10595
10596 &lt;p&gt;So, to summarize, in Rust:&lt;/p&gt;
10597 &lt;ul&gt;
10598 &lt;li&gt;Strings are encoded in UTF-8&lt;/li&gt;
10599 &lt;li&gt;Strings know their length&lt;/li&gt;
10600 &lt;li&gt;Strings can have nul chars in the middle&lt;/li&gt;
10601 &lt;/ul&gt;
10602 &lt;p&gt;This is a bit different from C:&lt;/p&gt;
10603 &lt;ul&gt;
10604 &lt;li&gt;Strings don't exist!&lt;/li&gt;
10605 &lt;/ul&gt;
10606 &lt;p&gt;Okay, just kidding. In C:&lt;/p&gt;
10607 &lt;ul&gt;
10608 &lt;li&gt;A lot of software has standardized on UTF-8.&lt;/li&gt;
10609 &lt;li&gt;Strings don't know their length - a &lt;code&gt;char *&lt;/cod…
10610 beginning of the string.&lt;/li&gt;
10611 &lt;li&gt;Strings conventionally have a nul terminator, that is, a zero …
10612 that marks the end of the string. Therefore, you can't have nul
10613 characters in the middle of strings.&lt;/li&gt;
10614 &lt;/ul&gt;
10615 &lt;h1&gt;Building a string from bytes&lt;/h1&gt;
10616 &lt;p&gt;Let's say you have an array of bytes and want to make a string …
10617 them. Rust won't let you just cast the array, like C would. First
10618 you need to do UTF-8 validation. For example:&lt;/p&gt;
10619 &lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;…
10620 &lt;span class="normal"&gt; 2&lt;/span&gt;
10621 &lt;span class="normal"&gt; 3&lt;/span&gt;
10622 &lt;span class="normal"&gt; 4&lt;/span&gt;
10623 &lt;span class="normal"&gt; 5&lt;/span&gt;
10624 &lt;span class="normal"&gt; 6&lt;/span&gt;
10625 &lt;span class="normal"&gt; 7&lt;/span&gt;
10626 &lt;span class="normal"&gt; 8&lt;/span&gt;
10627 &lt;span class="normal"&gt; 9&lt;/span&gt;
10628 &lt;span class="normal"&gt;10&lt;/span&gt;
10629 &lt;span class="normal"&gt;11&lt;/span&gt;
10630 &lt;span class="normal"&gt;12&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/t…
10631 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/sp…
10632 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;match&lt;/s…
10633 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Ok&lt;…
10634 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Err&lt…
10635 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&…
10636 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
10637
10638 &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/sp…
10639 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;convert_and…
10640 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;convert_and…
10641 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
10642 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
10643 &lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
10644 &lt;p&gt;In lines 10 and 11, we call &lt;code&gt;convert_and_print()&lt;…
10645 arrays of bytes; the first one is valid UTF-8, and the second one
10646 isn't.&lt;/p&gt;
10647 &lt;p&gt;Line 2 calls &lt;a href="https://doc.rust-lang.org/std/string/s…
10648 i.e. something with a success value or an error. In lines 3-5 we
10649 unpack this &lt;code&gt;Result&lt;/code&gt;. If it's &lt;code&gt;Ok&lt;…
10650 which has been validated for UTF-8. Otherwise, we print the debug
10651 representation of the error.&lt;/p&gt;
10652 &lt;p&gt;The program prints the following:&lt;/p&gt;
10653 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
10654 Hello
10655 FromUtf8Error { bytes: [72, 101, 240, 108, 108, 111], error: Utf8Error {…
10656 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
10657
10658 &lt;p&gt;Here, in the error case, the &lt;a href="https://doc.rust-lang.…
10659 are UTF-8 and are &lt;code&gt;valid_up_to&lt;/code&gt; index 2; that is …
10660 index. We also get some extra information which lets the program know
10661 if the problematic sequence was incomplete and truncated at the end of
10662 the byte array, or if it's complete and in the middle.&lt;/p&gt;
10663 &lt;p&gt;And for a "just make this printable, pls" API? We can
10664 use &lt;a href="https://doc.rust-lang.org/std/string/struct.String.html#…
10665 sequences with &lt;code&gt;U+FFFD REPLACEMENT CHARACTER&lt;/code&gt;:&lt…
10666 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
10667 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/sp…
10668 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="fm"&gt;println!&l…
10669 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
10670
10671 &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/sp…
10672 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;convert_and…
10673 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;convert_and…
10674 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
10675 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
10676
10677 &lt;p&gt;This prints the following:&lt;/p&gt;
10678 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
10679 Hello
10680 He�llo
10681 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
10682
10683 &lt;h1&gt;Reading from files into strings&lt;/h1&gt;
10684 &lt;p&gt;Now, let's assume you want to read chunks of a file and put the…
10685 strings. Let's go from the low-level parts up to the high level "read
10686 a line" API.&lt;/p&gt;
10687 &lt;h2&gt;Single bytes and single UTF-8 characters&lt;/h2&gt;
10688 &lt;p&gt;When you open a &lt;a href="https://doc.rust-lang.org/std/fs/st…
10689 &lt;a href="https://doc.rust-lang.org/std/io/trait.Read.html"&gt;&lt;cod…
10690 it can also give you back an iterator over &lt;em&gt;bytes&lt;/em&gt;, o…
10691 over UTF-8 &lt;em&gt;characters&lt;/em&gt;.&lt;/p&gt;
10692 &lt;p&gt;The &lt;a href="https://doc.rust-lang.org/std/io/trait.Read.htm…
10693 whose &lt;code&gt;next()&lt;/code&gt; method returns &lt;code&gt;Result&…
10694 the iterator for its next item, that &lt;code&gt;Result&lt;/code&gt; mea…
10695 out of it successfully, or an I/O error.&lt;/p&gt;
10696 &lt;p&gt;In contrast, the &lt;a href="https://doc.rust-lang.org/std/io/t…
10697 a &lt;a href="https://doc.rust-lang.org/std/io/struct.Chars.html"&gt;&lt…
10698 &lt;code&gt;Result&amp;lt;char, CharsError&amp;gt;&lt;/code&gt;, not &l…
10699 extended &lt;a href="https://doc.rust-lang.org/std/io/enum.CharsError.ht…
10700 when &lt;code&gt;next()&lt;/code&gt; tries to read the next UTF-8 sequen…
10701 the file has invalid data. &lt;code&gt;CharsError&lt;/code&gt; also has…
10702 I/O errors.&lt;/p&gt;
10703 &lt;h2&gt;Reading lines&lt;/h2&gt;
10704 &lt;p&gt;While you could build a UTF-8 string one character at a time, t…
10705 are more efficient ways to do it.&lt;/p&gt;
10706 &lt;p&gt;You can create a &lt;a href="https://doc.rust-lang.org/std/io/s…
10707 that implements the &lt;a href="https://doc.rust-lang.org/std/io/trait.R…
10708 convenient &lt;a href="https://doc.rust-lang.org/std/io/trait.BufRead.ht…
10709 String and it returns a &lt;code&gt;Result&amp;lt;usize, io::Error&amp;…
10710 number of bytes read, or an error.&lt;/p&gt;
10711 &lt;p&gt;That method is declared in the &lt;a href="https://doc.rust-lan…
10712 implements. Why the separation? Because other concrete structs also
10713 implement &lt;code&gt;BufRead&lt;/code&gt;, such as &lt;a href="https://…
10714 you use a vector of bytes like an I/O &lt;code&gt;Read&lt;/code&gt; or &…
10715 implementation, similar to &lt;a href="https://developer.gnome.org/gio/s…
10716 &lt;p&gt;If you prefer an iterator rather than the &lt;code&gt;read_line…
10717 &lt;code&gt;BufRead&lt;/code&gt; also gives you a &lt;a href="https://do…
10718 a &lt;a href="https://doc.rust-lang.org/std/io/struct.Lines.html"&gt;&lt…
10719 &lt;p&gt;In both cases — the &lt;code&gt;read_line()&lt;/code&gt; meth…
10720 error that you can get back can be of &lt;a href="https://doc.rust-lang.…
10721 which indicates that there was an invalid UTF-8 sequence in the line
10722 to be read. It can also be a normal I/O error, of course.&lt;/p&gt;
10723 &lt;h1&gt;Summary so far&lt;/h1&gt;
10724 &lt;p&gt;There is no way to build a &lt;code&gt;String&lt;/code&gt;, or …
10725 UTF-8 data. All the methods that let you turn bytes into string-like
10726 things perform validation, and return a &lt;code&gt;Result&lt;/code&gt; …
10727 your bytes validated correctly.&lt;/p&gt;
10728 &lt;p&gt;The exceptions are in the &lt;code&gt;unsafe&lt;/code&gt; metho…
10729 like &lt;a href="https://doc.rust-lang.org/std/string/struct.String.html…
10730 them if you are &lt;em&gt;absolutely sure&lt;/em&gt; that your bytes wer…
10731 UTF-8 beforehand.&lt;/p&gt;
10732 &lt;p&gt;There is no way to bring in data from a file (or anything file-…
10733 that implements the &lt;a href="https://doc.rust-lang.org/std/io/trait.R…
10734 without going through functions that do UTF-8 validation. There is
10735 not an unsafe "read a line" API without validation — you would have to
10736 build one yourself, but the I/O hit is probably going to be slower than
10737 validating data in memory, anyway, so you may as well validate.&lt;/p&gt;
10738 &lt;h1&gt;C strings and Rust&lt;/h1&gt;
10739 &lt;p&gt;For unfortunate historical reasons, C flings around &lt;code&gt…
10740 different things. In the context of Glib, it can mean&lt;/p&gt;
10741 &lt;ul&gt;
10742 &lt;li&gt;A valid, nul-terminated UTF-8 sequence of bytes (a "normal str…
10743 &lt;li&gt;A nul-terminated file path, which has no meaningful encoding&l…
10744 &lt;li&gt;A nul-terminated sequence of bytes, not validated as UTF-8.&lt…
10745 &lt;/ul&gt;
10746 &lt;p&gt;What a particular &lt;code&gt;char *&lt;/code&gt; means depends…
10747 &lt;h2&gt;Bringing a string from C to Rust&lt;/h2&gt;
10748 &lt;p&gt;From Rust's viewpoint, getting a raw &lt;code&gt;char *&lt;/cod…
10749 c_char&lt;/code&gt;" in Rust parlance) means that it gets a pointer to a…
10750 unknown length.&lt;/p&gt;
10751 &lt;p&gt;Now, that may not be entirely accurate:&lt;/p&gt;
10752 &lt;ul&gt;
10753 &lt;li&gt;You may indeed only have a pointer to a buffer of unknown leng…
10754 &lt;li&gt;You may have a pointer to a buffer, and also know its length
10755 (i.e. the offset at which the nul terminator is)&lt;/li&gt;
10756 &lt;/ul&gt;
10757 &lt;p&gt;The Rust standard library provides a &lt;a href="https://doc.ru…
10758 "I have a pointer to an array of bytes, and I know its length, and I
10759 know the last byte is a nul".&lt;/p&gt;
10760 &lt;p&gt;&lt;code&gt;CStr&lt;/code&gt; provides an &lt;a href="https://d…
10761 raw pointer, and walks the memory to which it points until it finds a
10762 nul byte. You &lt;em&gt;must&lt;/em&gt; give it a valid pointer, and yo…
10763 guarantee that there is a nul terminator, or &lt;code&gt;CStr&lt;/code&g…
10764 the end of your process' address space looking for one.&lt;/p&gt;
10765 &lt;p&gt;Alternatively, if you know the length of your byte array, and y…
10766 that it has a nul byte at the end, you can
10767 call &lt;a href="https://doc.rust-lang.org/std/ffi/struct.CStr.html#meth…
10768 the function will check that a) the last byte in that slice is indeed
10769 a nul, and b) there are no nul bytes in the middle.&lt;/p&gt;
10770 &lt;p&gt;The unsafe version of this last function
10771 is &lt;a href="https://doc.rust-lang.org/std/ffi/struct.CStr.html#method…
10772 an &lt;code&gt;&amp;amp;[u8]&lt;/code&gt; slice, but &lt;em&gt;you&lt;/e…
10773 and that there are no nul bytes in the middle.&lt;/p&gt;
10774 &lt;p&gt;&lt;em&gt;I really like that the Rust documentation tells you w…
10775 are not "instantaneous" and must instead walks arrays, like to do
10776 validation or to look for the nul terminator above.&lt;/em&gt;&lt;/p&gt;
10777 &lt;h2&gt;Turning a CStr into a string-like&lt;/h2&gt;
10778 &lt;p&gt;Now, the above indicates that a &lt;code&gt;CStr&lt;/code&gt; i…
10779 bytes. We have no idea what the bytes inside look like; we just know
10780 that they don't contain any other nul bytes.&lt;/p&gt;
10781 &lt;p&gt;There is a &lt;a href="https://doc.rust-lang.org/std/ffi/struct…
10782 &lt;code&gt;Result&amp;lt;&amp;amp;str, Utf8Error&amp;gt;&lt;/code&gt;.…
10783 of bytes. If the array is valid, the function just returns a slice of
10784 the validated bytes minus the nul terminator (i.e. just what you
10785 expect for a Rust string slice). Otherwise, it returns an &lt;code&gt;U…
10786 with the details like we discussed before.&lt;/p&gt;
10787 &lt;p&gt;There is also &lt;a href="https://doc.rust-lang.org/std/ffi/str…
10788 replacement of invalid UTF-8 sequences like we discussed before.&lt;/p&g…
10789 &lt;h1&gt;Conclusion&lt;/h1&gt;
10790 &lt;p&gt;Strings in Rust are UTF-8 encoded, they know their length, and …
10791 can have nul bytes in the middle.&lt;/p&gt;
10792 &lt;p&gt;To build a string from raw bytes, you must go through functions…
10793 do UTF-8 validation and tell you if it failed. There are unsafe
10794 functions that let you skip validation, but then of course you are on
10795 your own.&lt;/p&gt;
10796 &lt;p&gt;The low-level functions which read data from files operate on b…
10797 On top of those, there are convenience functions to read validated
10798 UTF-8 characters, lines, etc. All of these tell you when there was
10799 invalid UTF-8 or an I/O error.&lt;/p&gt;
10800 &lt;p&gt;Rust lets you wrap a raw &lt;code&gt;char *&lt;/code&gt; that y…
10801 that can later be validated and turned into a string. Anything that
10802 manipulates a raw pointer is &lt;code&gt;unsafe&lt;/code&gt;; this inclu…
10803 pointer into a C string abstraction" API, and the "build me an array
10804 of bytes from this raw pointer" API. Later, you can validate &lt;em&gt;…
10805 as UTF-8 and build real Rust strings — or know if the validation
10806 failed.&lt;/p&gt;
10807 &lt;p&gt;Rust builds these little "corridors" through the API so that il…
10808 states are unrepresentable.&lt;/p&gt;</content><category term="misc"></c…
10809 called
10810 &lt;a href="https://people.gnome.org/~federico/blog/docs/fmq-porting-c-t…
10811 This is the PDF file; be sure to scroll past the full-page
10812 presentation pages until you reach the speaker's notes, especially for
10813 the code sections!&lt;/p&gt;
10814 &lt;p&gt;&lt;a href="https://people.gnome.org/~federico/blog/docs/fmq-po…
10815 &lt;p&gt;You can also get the …&lt;/p&gt;</summary><content type="html…
10816 called
10817 &lt;a href="https://people.gnome.org/~federico/blog/docs/fmq-porting-c-t…
10818 This is the PDF file; be sure to scroll past the full-page
10819 presentation pages until you reach the speaker's notes, especially for
10820 the code sections!&lt;/p&gt;
10821 &lt;p&gt;&lt;a href="https://people.gnome.org/~federico/blog/docs/fmq-po…
10822 &lt;p&gt;You can also get the &lt;a href="https://people.gnome.org/~fede…
10823 released under a &lt;a href="https://creativecommons.org/licenses/by-sa/…
10824 &lt;p&gt;For the presentation, my daughter Luciana made some drawings of
10825 Ferris, the Rust mascot, also released under the same license:&lt;/p&gt;
10826 &lt;p&gt;&lt;a href="https://people.gnome.org/~federico/blog/docs/ferris…
10827 &lt;a href="https://people.gnome.org/~federico/blog/docs/ferris-2.png"&g…
10828 &lt;a href="https://people.gnome.org/~federico/blog/docs/ferris-3.png"&g…
10829 &lt;a href="https://people.gnome.org/~federico/blog/docs/ferris-4.png"&g…
10830 been some API breaks (!!!) in the unstable libraries that it uses
10831 since the last time I locked them. This post is about an interesting
10832 case of API breakage.&lt;/p&gt;
10833 &lt;p&gt;&lt;a href="https://github.com/servo/rust-cssparser"&gt;rust-cs…
10834 CSS. Well, more …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Ye…
10835 been some API breaks (!!!) in the unstable libraries that it uses
10836 since the last time I locked them. This post is about an interesting
10837 case of API breakage.&lt;/p&gt;
10838 &lt;p&gt;&lt;a href="https://github.com/servo/rust-cssparser"&gt;rust-cs…
10839 CSS. Well, more like &lt;em&gt;tokenizing&lt;/em&gt; CSS: you give it a…
10840 gives you back tokens, and you are supposed to compose CSS selector
10841 information or other CSS values from the tokens.&lt;/p&gt;
10842 &lt;p&gt;Librsvg uses rust-cssparser now for most of the micro-languages…
10843 SVG's attribute values, instead of its old, fragile C parsers. I hope
10844 to be able to use it in conjunction with Servo's &lt;a href="https://git…
10845 crate to fully parse CSS data and replace &lt;a href="https://git.gnome.…
10846 &lt;p&gt;A few months ago, rust-cssparser's API looked more or less like…
10847 following. This is the old representation of a &lt;code&gt;Token&lt;/co…
10848 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
10849 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// an iden…
10850 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Ident&lt;/s…
10851
10852 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// a plain…
10853 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Number&lt;/…
10854
10855 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// a perce…
10856 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Percentage&…
10857
10858 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;WhiteSpace&…
10859 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Comma&lt;/s…
10860
10861 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;..&lt;/span…
10862 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
10863 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
10864
10865 &lt;p&gt;That is, a &lt;code&gt;Token&lt;/code&gt; can be an &lt;code&gt…
10866 &lt;code&gt;Number&lt;/code&gt;, a &lt;code&gt;Percentage&lt;/code&gt;, …
10867 &lt;p&gt;On top of that is the old API for a &lt;code&gt;Parser&lt;/code…
10868 a string and then it gives you back tokens:&lt;/p&gt;
10869 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
10870 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;pub&lt;/spa…
10871
10872 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;pub&lt;/spa…
10873
10874 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;..&lt;/span…
10875 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
10876 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
10877
10878 &lt;p&gt;This means the following. You create the parser out of a strin…
10879 with &lt;code&gt;new()&lt;/code&gt;. You can then extract a &lt;code&gt…
10880 sucessfully, or with an empty error value. The parser uses a lifetime
10881 &lt;code&gt;'i&lt;/code&gt; on the string from which it is constructed: …
10882 return identifiers, for example, could return sub-string slices that
10883 come from the original string, and the parser has to be marked with a
10884 lifetime so that it does not outlive its underlying string.&lt;/p&gt;
10885 &lt;p&gt;A few commits later, rust-cssparser got changed to return detai…
10886 error values, so that instead of &lt;code&gt;()&lt;/code&gt; you get a a…
10887 with sub-cases like &lt;code&gt;UnexpectedToken&lt;/code&gt; or &lt;code…
10888 &lt;p&gt;After the changes to the error values for results, I didn't pay…
10889 attention to rust-cssparser for while. Yesterday I wanted to update
10890 librsvg to use the newest rust-cssparser, and had some interesting
10891 problems.&lt;/p&gt;
10892 &lt;p&gt;First, &lt;code&gt;Parser::new()&lt;/code&gt; was changed from …
10893 taking a &lt;code&gt;ParserInput&lt;/code&gt; struct. This is an implem…
10894 lets the parser cache the last token it saw. Not a big deal:&lt;/p&gt;
10895 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
10896 &lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&…
10897
10898 &lt;span class="c1"&gt;// you now construct it like&lt;/span&gt;
10899 &lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&…
10900 &lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&…
10901 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
10902
10903 &lt;p&gt;I am not completely sure why this is exposed to the public API,…
10904 Rust won't allow you to have two mutable references to a
10905 &lt;code&gt;ParserInput&lt;/code&gt;, and the only consumer of a (mutabl…
10906 the &lt;code&gt;Parser&lt;/code&gt;, anyway.&lt;/p&gt;
10907 &lt;p&gt;However, the &lt;code&gt;parser.next()&lt;/code&gt; function ch…
10908 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
10909 &lt;span class="k"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&g…
10910
10911 &lt;span class="c1"&gt;// new version&lt;/span&gt;
10912 &lt;span class="k"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&g…
10913 &lt;span class="c1"&gt;// note this bad boy here -------^&lt;/span&gt;
10914 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
10915
10916 &lt;p&gt;The successful &lt;code&gt;Result&lt;/code&gt; from &lt;code&gt…
10917 &lt;code&gt;Token&lt;/code&gt;, not a plain &lt;code&gt;Token&lt;/code&g…
10918 giving you a borrowed reference to its internally-cached token.&lt;/p&gt;
10919 &lt;p&gt;My parsing functions for the old API looked similar to the
10920 following. This is a function that parses a string into an angle; it
10921 can look like &lt;code&gt;"45deg"&lt;/code&gt; or &lt;code&gt;"1.5rad"&l…
10922 &lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;…
10923 &lt;span class="normal"&gt; 2&lt;/span&gt;
10924 &lt;span class="normal"&gt; 3&lt;/span&gt;
10925 &lt;span class="normal"&gt; 4&lt;/span&gt;
10926 &lt;span class="normal"&gt; 5&lt;/span&gt;
10927 &lt;span class="normal"&gt; 6&lt;/span&gt;
10928 &lt;span class="normal"&gt; 7&lt;/span&gt;
10929 &lt;span class="normal"&gt; 8&lt;/span&gt;
10930 &lt;span class="normal"&gt; 9&lt;/span&gt;
10931 &lt;span class="normal"&gt;10&lt;/span&gt;
10932 &lt;span class="normal"&gt;11&lt;/span&gt;
10933 &lt;span class="normal"&gt;12&lt;/span&gt;
10934 &lt;span class="normal"&gt;13&lt;/span&gt;
10935 &lt;span class="normal"&gt;14&lt;/span&gt;
10936 &lt;span class="normal"&gt;15&lt;/span&gt;
10937 &lt;span class="normal"&gt;16&lt;/span&gt;
10938 &lt;span class="normal"&gt;17&lt;/span&gt;
10939 &lt;span class="normal"&gt;18&lt;/span&gt;
10940 &lt;span class="normal"&gt;19&lt;/span&gt;
10941 &lt;span class="normal"&gt;20&lt;/span&gt;
10942 &lt;span class="normal"&gt;21&lt;/span&gt;
10943 &lt;span class="normal"&gt;22&lt;/span&gt;
10944 &lt;span class="normal"&gt;23&lt;/span&gt;
10945 &lt;span class="normal"&gt;24&lt;/span&gt;
10946 &lt;span class="normal"&gt;25&lt;/span&gt;
10947 &lt;span class="normal"&gt;26&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/t…
10948 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/sp…
10949
10950 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/sp…
10951 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/s…
10952
10953 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;match&lt;/s…
10954 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Token&l…
10955
10956 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Token&l…
10957 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;le…
10958
10959 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;mat…
10960 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt…
10961 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt…
10962 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt…
10963 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt…
10964 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&l…
10965 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/…
10966
10967 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;_&lt;/s…
10968 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}.&lt;/span…
10969 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt…
10970 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt…
10971 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt…
10972 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
10973 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
10974 &lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
10975 &lt;p&gt;This is a bit ugly, but it was the first version that passed the
10976 tests. Lines 4 and 5 mean, "get the first token or return an error".
10977 Line 17 means, "anything except &lt;code&gt;deg&lt;/code&gt;, &lt;code&g…
10978 causes the &lt;code&gt;match&lt;/code&gt; expression to generate an erro…
10979 feeling very proud of using &lt;code&gt;and_then()&lt;/code&gt; in line …
10980 &lt;code&gt;parser.expect_exhausted()&lt;/code&gt;, to ensure that the p…
10981 any more tokens after the angle/units.&lt;/p&gt;
10982 &lt;p&gt;However, in the new version of rust-cssparser, Parser.next() gi…
10983 back a &lt;code&gt;Result&lt;/code&gt; with a &lt;code&gt;&amp;amp;Token…
10984 token —, while the old version returned a plain &lt;code&gt;Token&lt;/…
10985 I thought, I'm just going to de-reference the value in the &lt;code&gt;m…
10986 be done with it:&lt;/p&gt;
10987 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
10988 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/s…
10989
10990 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;match&lt;/s…
10991 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// ^ de…
10992 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Token&l…
10993
10994 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Token&l…
10995 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// …
10996 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
10997
10998 &lt;p&gt;The compiler complained elsewhere. The whole function now look…
10999 this:&lt;/p&gt;
11000 &lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;…
11001 &lt;span class="normal"&gt; 2&lt;/span&gt;
11002 &lt;span class="normal"&gt; 3&lt;/span&gt;
11003 &lt;span class="normal"&gt; 4&lt;/span&gt;
11004 &lt;span class="normal"&gt; 5&lt;/span&gt;
11005 &lt;span class="normal"&gt; 6&lt;/span&gt;
11006 &lt;span class="normal"&gt; 7&lt;/span&gt;
11007 &lt;span class="normal"&gt; 8&lt;/span&gt;
11008 &lt;span class="normal"&gt; 9&lt;/span&gt;
11009 &lt;span class="normal"&gt;10&lt;/span&gt;
11010 &lt;span class="normal"&gt;11&lt;/span&gt;
11011 &lt;span class="normal"&gt;12&lt;/span&gt;
11012 &lt;span class="normal"&gt;13&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/t…
11013 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/sp…
11014
11015 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/sp…
11016 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/s…
11017
11018 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;match&lt;/s…
11019 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// ...…
11020 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}.&lt;/span…
11021 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt…
11022 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt…
11023 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt…
11024 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
11025 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
11026 &lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
11027 &lt;p&gt;But in line 4, &lt;code&gt;token&lt;/code&gt; is now a referenc…
11028 inside &lt;code&gt;parser&lt;/code&gt;, and &lt;code&gt;parser&lt;/code&…
11029 compiler didn't like that line 10 (the call to
11030 &lt;code&gt;parser.expect_exhausted()&lt;/code&gt;) was trying to borrow…
11031 again.&lt;/p&gt;
11032 &lt;p&gt;I played a bit with creating a temporary scope around the assig…
11033 to &lt;code&gt;token&lt;/code&gt; so that it would only borrow &lt;code&…
11034 scope. Things ended up like this, without the call to &lt;code&gt;and_t…
11035 after the &lt;code&gt;match&lt;/code&gt;:&lt;/p&gt;
11036 &lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;…
11037 &lt;span class="normal"&gt; 2&lt;/span&gt;
11038 &lt;span class="normal"&gt; 3&lt;/span&gt;
11039 &lt;span class="normal"&gt; 4&lt;/span&gt;
11040 &lt;span class="normal"&gt; 5&lt;/span&gt;
11041 &lt;span class="normal"&gt; 6&lt;/span&gt;
11042 &lt;span class="normal"&gt; 7&lt;/span&gt;
11043 &lt;span class="normal"&gt; 8&lt;/span&gt;
11044 &lt;span class="normal"&gt; 9&lt;/span&gt;
11045 &lt;span class="normal"&gt;10&lt;/span&gt;
11046 &lt;span class="normal"&gt;11&lt;/span&gt;
11047 &lt;span class="normal"&gt;12&lt;/span&gt;
11048 &lt;span class="normal"&gt;13&lt;/span&gt;
11049 &lt;span class="normal"&gt;14&lt;/span&gt;
11050 &lt;span class="normal"&gt;15&lt;/span&gt;
11051 &lt;span class="normal"&gt;16&lt;/span&gt;
11052 &lt;span class="normal"&gt;17&lt;/span&gt;
11053 &lt;span class="normal"&gt;18&lt;/span&gt;
11054 &lt;span class="normal"&gt;19&lt;/span&gt;
11055 &lt;span class="normal"&gt;20&lt;/span&gt;
11056 &lt;span class="normal"&gt;21&lt;/span&gt;
11057 &lt;span class="normal"&gt;22&lt;/span&gt;
11058 &lt;span class="normal"&gt;23&lt;/span&gt;
11059 &lt;span class="normal"&gt;24&lt;/span&gt;
11060 &lt;span class="normal"&gt;25&lt;/span&gt;
11061 &lt;span class="normal"&gt;26&lt;/span&gt;
11062 &lt;span class="normal"&gt;27&lt;/span&gt;
11063 &lt;span class="normal"&gt;28&lt;/span&gt;
11064 &lt;span class="normal"&gt;29&lt;/span&gt;
11065 &lt;span class="normal"&gt;30&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/t…
11066 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/sp…
11067 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/sp…
11068
11069 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/sp…
11070 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;let&lt…
11071 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&l…
11072
11073 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;match&l…
11074 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Tok…
11075
11076 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Tok…
11077 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&g…
11078
11079 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt…
11080 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s…
11081 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s…
11082 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s…
11083 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n…
11084 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt…
11085 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&…
11086
11087 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;_&l…
11088 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/s…
11089 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span…
11090
11091 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;parser&lt;/…
11092
11093 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Ok&lt;/spa…
11094 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
11095 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
11096 &lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
11097 &lt;p&gt;Lines 5 through 25 are basically&lt;/p&gt;
11098 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
11099 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// par…
11100 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span…
11101 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
11102
11103 &lt;p&gt;And after &lt;em&gt;that&lt;/em&gt; is done, I test for &lt;cod…
11104 There is no chaining of results with helper functions; instead it's
11105 just going through each token linearly.&lt;/p&gt;
11106 &lt;p&gt;The API break was annoying to deal with, but fortunately the ca…
11107 code ended up cleaner, and I didn't have to change anything in the
11108 tests. I hope rust-cssparser can stabilize its API for consumers that
11109 are not Servo.&lt;/p&gt;</content><category term="misc"></category><cate…
11110 but never blogged about it. Shame on me!&lt;/em&gt;&lt;/p&gt;
11111 &lt;p&gt;I wrote an article, &lt;a href="https://recompilermag.com/issue…
11112 Recompiler magazine. Is GNOME, now at 20 years old, legacy software?
11113 Is it different from mainframe software …&lt;/p&gt;</summary><content …
11114 but never blogged about it. Shame on me!&lt;/em&gt;&lt;/p&gt;
11115 &lt;p&gt;I wrote an article, &lt;a href="https://recompilermag.com/issue…
11116 Recompiler magazine. Is GNOME, now at 20 years old, legacy software?
11117 Is it different from mainframe software because "everyone" can change
11118 it? Does long-lived software have the same patterns of change as
11119 cities and physical artifacts? Can we learn from the building trades
11120 and urbanism for maintaining software in the long term? &lt;em&gt;Could…
11121 turn legacy software into a good legacy?&lt;/em&gt;&lt;/p&gt;
11122 &lt;p&gt;You can read the article &lt;a href="https://recompilermag.com/…
11123 &lt;p&gt;Also, let me take this opportunity to recommend &lt;a href="htt…
11124 magazine. It is the most enjoyable technical publication I read.
11125 Their &lt;a href="https://recompilermag.com/podcast/"&gt;podcast&lt;/a&g…
11126 &lt;p&gt;&lt;strong&gt;Update 2017/06/10&lt;/strong&gt; - Spanish versio…
11127 the Alt-Tab behavior in gnome-shell.&lt;/p&gt;
11128 &lt;p&gt;The default is to have &lt;code&gt;Alt-Tab&lt;/code&gt; switch …
11129 current workspace. One can use &lt;code&gt;Alt-backtick&lt;/code&gt; (o…
11130 have above Tab) to switch between windows in the …&lt;/p&gt;</summary>…
11131 the Alt-Tab behavior in gnome-shell.&lt;/p&gt;
11132 &lt;p&gt;The default is to have &lt;code&gt;Alt-Tab&lt;/code&gt; switch …
11133 current workspace. One can use &lt;code&gt;Alt-backtick&lt;/code&gt; (o…
11134 have above Tab) to switch between windows in the current application.&lt…
11135 &lt;p&gt;I prefer a Windows-like setup, where &lt;code&gt;Alt-Tab&lt;/co…
11136 windows in the current workspace, regardless of the application to
11137 which they belong.&lt;/p&gt;
11138 &lt;p&gt;Many moons ago there was a gnome-shell extension to change this
11139 behavior, but these days (GNOME 3.24) it can be done without
11140 extensions. It is a bit convoluted.&lt;/p&gt;
11141 &lt;h1&gt;With the GUI&lt;/h1&gt;
11142 &lt;p&gt;If you are using X instead of Wayland, this works:&lt;/p&gt;
11143 &lt;ol&gt;
11144 &lt;li&gt;
11145 &lt;p&gt;Unset the &lt;strong&gt;Switch applications&lt;/strong&gt; comm…
11146 &lt;code&gt;gnome-control-center&lt;/code&gt;, go to &lt;em&gt;Keyboa…
11147 applications&lt;/em&gt; command. Click on it, and hit &lt;code&gt;Ba…
11148 dialog that prompts you for the keyboard shortcut. Click on the
11149 &lt;em&gt;Set&lt;/em&gt; button.&lt;/p&gt;
11150 &lt;/li&gt;
11151 &lt;li&gt;
11152 &lt;p&gt;Set the &lt;strong&gt;Switch windows&lt;/strong&gt; command. W…
11153 &lt;em&gt;Keyboard&lt;/em&gt; settings, find the &lt;em&gt;Switch win…
11154 it, and hit &lt;code&gt;Alt-Tab&lt;/code&gt;. Click &lt;em&gt;Set&lt…
11155 &lt;/li&gt;
11156 &lt;/ol&gt;
11157 &lt;p&gt;That should be all you need, unless you are in Wayland. In tha…
11158 you need to do it on the command line.&lt;/p&gt;
11159 &lt;h1&gt;With the command line, or in Wayland&lt;/h1&gt;
11160 &lt;p&gt;The kind people on &lt;a href="irc://irc.gnome.org/#gnome-hacke…
11161 3.24, changing &lt;code&gt;Alt-Tab&lt;/code&gt; doesn't work on Wayland …
11162 because the compositor captures the &lt;code&gt;Alt-Tab&lt;/code&gt; key…
11163 inside the dialog that prompts you for a keyboard shortcut. In that
11164 case, you have to change the configuration keys directly instead of
11165 using the GUI:&lt;/p&gt;
11166 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
11167 gsettings &lt;span class="nb"&gt;set&lt;/span&gt; org.gnome.desktop.wm.k…
11168 gsettings &lt;span class="nb"&gt;set&lt;/span&gt; org.gnome.desktop.wm.k…
11169 gsettings &lt;span class="nb"&gt;set&lt;/span&gt; org.gnome.desktop.wm.k…
11170 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
11171
11172 &lt;p&gt;Of course the above also works in X, too.&lt;/p&gt;
11173 &lt;h1&gt;Changing windows across all workspaces&lt;/h1&gt;
11174 &lt;p&gt;If you'd like to switch between windows in all workspaces, rath…
11175 in the current workspace, find the &lt;code&gt;org.gnome.shell.window-sw…
11176 current-workspace-only&lt;/code&gt; GSettings key and change it. You ca…
11177 in &lt;code&gt;dconf-editor&lt;/code&gt;, or on the command line with&lt…
11178 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
11179 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content><category term="misc"></c…
11180 standard library when you open a file. I wanted to learn how Rust
11181 handles system calls and &lt;code&gt;errno&lt;/code&gt;, and all the lit…
11182 POSIX API. This is what I learned!&lt;/p&gt;
11183 &lt;h1&gt;The C side of …&lt;/h1&gt;</summary><content type="html">&lt…
11184 standard library when you open a file. I wanted to learn how Rust
11185 handles system calls and &lt;code&gt;errno&lt;/code&gt;, and all the lit…
11186 POSIX API. This is what I learned!&lt;/p&gt;
11187 &lt;h1&gt;The C side of things&lt;/h1&gt;
11188 &lt;p&gt;When you open a file, or create a socket, or do anything else t…
11189 returns an object that can be accessed like a file, you get a &lt;em&gt;…
11190 descriptor&lt;/em&gt; in the form of an &lt;code&gt;int&lt;/code&gt;.&lt…
11191 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
11192 &lt;span class="cm"&gt; * -1 in case of error.&lt;/span&gt;
11193 &lt;span class="cm"&gt; */&lt;/span&gt;
11194 &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/…
11195 &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;socket&lt…
11196 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
11197
11198 &lt;p&gt;You get a nonnegative integer in case of success, or -1 in case…
11199 error. If there's an error, you look at &lt;code&gt;errno&lt;/code&gt;,…
11200 integer error code. &lt;/p&gt;
11201 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
11202
11203 &lt;span class="nl"&gt;retry_open&lt;/span&gt;&lt;span class="p"&gt;:&lt…
11204 &lt;span class="n"&gt;fd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&g…
11205 &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&g…
11206 &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/sp…
11207 &lt;span class="cm"&gt;/* File doesn&amp;#39;t exist */&lt;/span…
11208 &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/…
11209 &lt;span class="p"&gt;...&lt;/span&gt;
11210 &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/…
11211 &lt;span class="k"&gt;goto&lt;/span&gt; &lt;span class="n"&gt;re…
11212 &lt;span class="p"&gt;}&lt;/span&gt;
11213 &lt;span class="p"&gt;}&lt;/span&gt;
11214 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
11215
11216 &lt;p&gt;Many system calls can return &lt;code&gt;EINTR&lt;/code&gt;, wh…
11217 call", which means that &lt;em&gt;something&lt;/em&gt; interrupted the k…
11218 was doing your system call and it returned control to userspace, with
11219 the syscall unfinished. For example, your process may have received a
11220 Unix signal (e.g. you send it &lt;code&gt;SIGSTOP&lt;/code&gt; by pressi…
11221 terminal, or you resized the terminal and your process got a
11222 &lt;code&gt;SIGWINCH&lt;/code&gt;). Most of the time &lt;code&gt;EINTR&…
11223 retry the operation: if you Control-Z a program to suspend it, and
11224 then &lt;code&gt;fg&lt;/code&gt; to continue it again; and if the progra…
11225 of &lt;code&gt;open()&lt;/code&gt;ing a file, you would expect it to con…
11226 point and to actually open the file. Software that doesn't check for
11227 &lt;code&gt;EINTR&lt;/code&gt; can fail in very subtle ways!&lt;/p&gt;
11228 &lt;p&gt;Once you have an open file descriptor, you can read from it:&lt…
11229 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
11230 &lt;span class="nf"&gt;read_five_bytes&lt;/span&gt; &lt;span class="p"&g…
11231 &lt;span class="p"&gt;{&lt;/span&gt;
11232 &lt;span class="kt"&gt;ssize_t&lt;/span&gt; &lt;span class="n"&gt;re…
11233
11234 &lt;span class="nl"&gt;retry&lt;/span&gt;&lt;span class="p"&gt;:&lt;…
11235 &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt…
11236 &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/sp…
11237 &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt…
11238 &lt;span class="k"&gt;goto&lt;/span&gt; &lt;span class="n"&g…
11239 &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&…
11240 &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi…
11241 &lt;span class="p"&gt;}&lt;/span&gt;
11242 &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/…
11243 &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;…
11244 &lt;span class="p"&gt;}&lt;/span&gt;
11245 &lt;span class="p"&gt;}&lt;/span&gt;
11246 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
11247
11248 &lt;p&gt;... and one has to remember that if &lt;code&gt;read()&lt;/code…
11249 were at the end-of-file; if it returns less than the number of bytes
11250 requested it means we were close to the end of file; if this is a
11251 nonblocking socket and it returns &lt;code&gt;EWOULDBLOCK&lt;/code&gt; o…
11252 must decide to retry the operation or actually wait and try again
11253 later.&lt;/p&gt;
11254 &lt;p&gt;There is a lot of buggy software written in C that tries to use…
11255 POSIX API directly, and gets these subtleties wrong. Most programs
11256 written in high-level languages use the I/O facilities provided by
11257 their language, which hopefully make things easier.&lt;/p&gt;
11258 &lt;h1&gt;I/O in Rust&lt;/h1&gt;
11259 &lt;p&gt;Rust makes &lt;a href="https://doc.rust-lang.org/book/first-edi…
11260 ignore an error, the code &lt;em&gt;looks&lt;/em&gt; like it is ignoring…
11261 (e.g. you can grep for &lt;code&gt;unwrap()&lt;/code&gt; and find lazy c…
11262 code actually &lt;em&gt;looks better&lt;/em&gt; if it doesn't ignore the…
11263 properly propagates it upstream (e.g. you can use the &lt;code&gt;?&lt;/…
11264 propagate errors to the calling function).&lt;/p&gt;
11265 &lt;p&gt;I keep recommending &lt;a href="http://joeduffyblog.com/2016/02…
11266 discusses POSIX-like error codes vs. exceptions vs. more modern
11267 approaches like Haskell's and Rust's - definitely worth studying over
11268 a few of days (also, see Miguel's valiant effort to &lt;a href="https://…
11269 from exceptions for I/O errors&lt;/a&gt;).&lt;/p&gt;
11270 &lt;p&gt;So, what happens when one opens a file in Rust, from the toplev…
11271 down to the system calls? Let's go down the rabbit hole.&lt;/p&gt;
11272 &lt;p&gt;You can open a file like this:&lt;/p&gt;
11273 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
11274
11275 &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/sp…
11276 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/sp…
11277 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;..&lt;/span…
11278 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
11279 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
11280
11281 &lt;p&gt;This does &lt;em&gt;not&lt;/em&gt; give you a raw file descript…
11282 &lt;code&gt;io::Result&amp;lt;fs::File, io::Error&amp;gt;&lt;/code&gt;, …
11283 you actually got back a File that you can operate on, or an error.&lt;/p…
11284 &lt;p&gt;Let's look at the &lt;a href="https://github.com/rust-lang/rust…
11285 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
11286 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;pub&lt;/spa…
11287 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;OpenOpt…
11288 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&…
11289
11290 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;pub&lt;/spa…
11291 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;OpenOpt…
11292 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&…
11293 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;..&lt;/span…
11294 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
11295 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
11296
11297 &lt;p&gt;Here, &lt;code&gt;OpenOptions&lt;/code&gt; is an auxiliary stru…
11298 pattern. Instead of passing bitflags for the various
11299 &lt;code&gt;O_CREATE/O_APPEND/etc.&lt;/code&gt; flags from the &lt;code&…
11300 builds a struct with the desired options, and finally calls &lt;code&gt;…
11301 on it.&lt;/p&gt;
11302 &lt;p&gt;So, let's look at the &lt;a href="https://github.com/rust-lang/…
11303 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
11304 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="bp"&gt;self&l…
11305 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&…
11306
11307 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span…
11308 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;let&lt…
11309 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Ok&lt;…
11310 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&…
11311 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
11312
11313 &lt;p&gt;See that &lt;code&gt;fs_imp::File::open()&lt;/code&gt;? That's…
11314 platform-specific wrapper for opening files. Let's look
11315 at &lt;a href="https://github.com/rust-lang/rust/blob/3f8b93693da78c2cfe…
11316 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
11317 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;let&lt…
11318 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;File&lt…
11319 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&…
11320 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
11321
11322 &lt;p&gt;The first line, &lt;code&gt;let path = cstr(path)?&lt;/code&gt;…
11323 into a nul-terminated C string. The second line calls the following:&lt…
11324 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
11325 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;let&lt…
11326 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n…
11327 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n…
11328 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p…
11329 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;let&lt…
11330 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ope…
11331 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;})&lt;/…
11332 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;let&lt…
11333
11334 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;..&lt;/…
11335
11336 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Ok&lt;…
11337 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&…
11338 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
11339
11340 &lt;p&gt;Here, &lt;code&gt;let flags = ...&lt;/code&gt; converts the &lt…
11341 beginning to an int with bit flags.&lt;/p&gt;
11342 &lt;p&gt;Then, it does &lt;code&gt;let fd = cvt_r (LAMBDA)&lt;/code&gt;,…
11343 calls the actual &lt;code&gt;open64()&lt;/code&gt; from libc (a Rust wra…
11344 libc): it returns a file descriptor, or -1 on error. Why is this
11345 done in a lambda? Let's look at &lt;a href="https://github.com/rust-lan…
11346 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
11347 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;where&lt;/s…
11348 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;F&lt;…
11349 &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
11350 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;loop&lt;/sp…
11351 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;match&l…
11352 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Er…
11353 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;oth…
11354 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/s…
11355 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&…
11356 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
11357 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
11358
11359 &lt;p&gt;Okay! Here &lt;code&gt;f&lt;/code&gt; is the lambda that calls…
11360 it in a loop and translates the POSIX-like result into something
11361 friendly to Rust. This loop is where it handles &lt;code&gt;EINTR&lt;/c…
11362 translated into &lt;code&gt;ErrorKind::Interrupted&lt;/code&gt;. I supp…
11363 for &lt;code&gt;convert_retry()&lt;/code&gt;? Let's look at
11364 the &lt;a href="https://github.com/rust-lang/rust/blob/3f8b93693da78c2cf…
11365 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
11366 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span…
11367 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Err&lt…
11368 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&…
11369 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Ok&lt;…
11370 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&…
11371 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
11372 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
11373
11374 &lt;p&gt;(The &lt;code&gt;IsMinusOne&lt;/code&gt; shenanigans are just a…
11375 multiple integer types without a lot of &lt;code&gt;as&lt;/code&gt; cast…
11376 &lt;p&gt;The above means, if the POSIX-like result was -1, return an &lt…
11377 the last error returned by the operating system. That should surely
11378 be &lt;code&gt;errno&lt;/code&gt; internally, correct? Let's look at
11379 the &lt;a href="https://github.com/rust-lang/rust/blob/3f8b93693da78c2cf…
11380 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
11381 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Error&l…
11382 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&…
11383 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
11384
11385 &lt;p&gt;We don't need to look at &lt;code&gt;Error::from_raw_os_error()…
11386 conversion function from an &lt;code&gt;errno&lt;/code&gt; value into a …
11387 However, let's look at &lt;a href="https://github.com/rust-lang/rust/blo…
11388 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
11389 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;unsafe&lt;/…
11390 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/s…
11391 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&…
11392 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
11393 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
11394
11395 &lt;p&gt;Here, &lt;code&gt;errno_location()&lt;/code&gt; is an &lt;code&…
11396 (or whatever C library your Unix uses). It returns a pointer to the
11397 actual int which is the &lt;code&gt;errno&lt;/code&gt; thread-local vari…
11398 code can't use libc's global variables directly, there needs to be a
11399 way to get their addresses via function calls - that's what
11400 &lt;code&gt;errno_location()&lt;/code&gt; is for.&lt;/p&gt;
11401 &lt;h2&gt;And on Windows?&lt;/h2&gt;
11402 &lt;p&gt;Remember the internal &lt;code&gt;File.open()&lt;/code&gt;? Th…
11403 like &lt;a href="https://github.com/rust-lang/rust/blob/3f8b93693da78c2c…
11404 &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;cod…
11405 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;let&lt…
11406 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;let&lt…
11407 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;c&l…
11408 &lt;span class="w"&gt; &lt;/span&gt;&lt;span c…
11409 &lt;span class="w"&gt; &lt;/span&gt;&lt;span c…
11410 &lt;span class="w"&gt; &lt;/span&gt;&lt;span c…
11411 &lt;span class="w"&gt; &lt;/span&gt;&lt;span c…
11412 &lt;span class="w"&gt; &lt;/span&gt;&lt;span c…
11413 &lt;span class="w"&gt; &lt;/span&gt;&lt;span c…
11414 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;};&lt;/…
11415 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/…
11416 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Er…
11417 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/s…
11418 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Ok…
11419 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/s…
11420 &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&…
11421 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
11422
11423 &lt;p&gt;&lt;code&gt;CreateFileW()&lt;/code&gt; is the Windows API funct…
11424 conversion of error codes inside &lt;code&gt;Error::last_os_error()&lt;/…
11425 analogously - it calls &lt;code&gt;GetLastError()&lt;/code&gt; from the …
11426 converts it.&lt;/p&gt;
11427 &lt;h2&gt;Can we not call C libraries?&lt;/h2&gt;
11428 &lt;p&gt;The Rust/Unix code above depends on the system's libc for &lt;c…
11429 &lt;code&gt;errno&lt;/code&gt;, which are entirely C constructs. Libc i…
11430 the system calls. There are efforts to make the Rust standard library
11431 &lt;em&gt;not&lt;/em&gt; use libc and use syscalls directly.&lt;/p&gt;
11432 &lt;p&gt;As an example, you can look at
11433 the &lt;a href="https://github.com/rust-lang/rust/blob/3f8b93693da78c2cf…
11434 system kernel entirely written in Rust. Fun times!&lt;/p&gt;
11435 &lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; If you want to see what a …
11436 like, &lt;a href="https://github.com/japaric/steed"&gt;take a look at st…
11437 without C dependencies.&lt;/p&gt;
11438 &lt;h1&gt;Conclusion&lt;/h1&gt;
11439 &lt;p&gt;Rust is very meticulous about error handling, but it succeeds in
11440 making it pleasant to read. I/O functions give you back an
11441 &lt;code&gt;io::Result&amp;lt;&amp;gt;&lt;/code&gt;, which you piece apa…
11442 error.&lt;/p&gt;
11443 &lt;p&gt;Internally, and for each platform it supports, the Rust standard
11444 library translates &lt;code&gt;errno&lt;/code&gt; from libc into an &lt;…
11445 enum. The standard library also automatically handles Unix-isms like
11446 retrying operations on &lt;code&gt;EINTR&lt;/code&gt;.&lt;/p&gt;
11447 &lt;p&gt;I've been enjoying reading the &lt;a href="https://github.com/r…
11448 has taught me many Rust-isms, and it's nice to see how the
11449 hairy/historical libc constructs are translated into clean Rust
11450 idioms. I hope this little trip down the rabbit hole for the
11451 &lt;code&gt;open(2)&lt;/code&gt; system call lets you look in other inte…
11452 an
11453 &lt;a href="https://people.gnome.org/~federico/misc/activity-log.el"&gt;…
11454 Back then, I seemed to write multiple short blog entries in a day
11455 rather than longer articles (&lt;em&gt;doing Mastodon before it was cool…
11456 But my blogging patterns have changed. I've been wanting to add …&lt;…
11457 an
11458 &lt;a href="https://people.gnome.org/~federico/misc/activity-log.el"&gt;…
11459 Back then, I seemed to write multiple short blog entries in a day
11460 rather than longer articles (&lt;em&gt;doing Mastodon before it was cool…
11461 But my blogging patterns have changed. I've been wanting to add some
11462 more features to the script: moving to a page-per-post model, support
11463 for draft articles, tags, and syntax highlighting for code excerpts...&l…
11464 &lt;p&gt;This is a wheel that I do not find worth reinventing these days.
11465 After &lt;a href="https://mastodon.social/@federicomena/8360985"&gt;aski…
11466 generators (thanks to everyone who replied!), I've decided to give
11467 &lt;a href="https://blog.getpelican.com/"&gt;Pelican&lt;/a&gt; a try. I…
11468 documentation" is high on my list of things to look for when shopping
11469 for tools, and Pelican's docs are nice from the start.&lt;/p&gt;
11470 &lt;p&gt;The old blog is still available &lt;a href="https://people.gnom…
11471 &lt;p&gt;If you find broken links, or stuff that doesn't work correctly …
11472
You are viewing proxied material from codemadness.org. The copyright of proxied material belongs to its original authors. Any comments or complaints in relation to proxied material should be directed to the original authors of the content concerned. Please see the disclaimer for more details.