<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Denys Séguret</title>
    <description>The latest articles on DEV Community by Denys Séguret (@dystroy).</description>
    <link>https://dev.to/dystroy</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F133321%2F9770e033-8b65-4392-ad56-419dee9416e2.png</url>
      <title>DEV Community: Denys Séguret</title>
      <link>https://dev.to/dystroy</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/dystroy"/>
    <language>en</language>
    <item>
      <title>SafeCloset, a Secret Safe - Why and how I made it in Rust </title>
      <dc:creator>Denys Séguret</dc:creator>
      <pubDate>Tue, 07 Dec 2021 18:00:18 +0000</pubDate>
      <link>https://dev.to/dystroy/safecloset-a-secret-safe-why-and-how-i-made-it-in-rust-2k47</link>
      <guid>https://dev.to/dystroy/safecloset-a-secret-safe-why-and-how-i-made-it-in-rust-2k47</guid>
      <description>&lt;p&gt;Like everybody, I have small secrets to store, like door codes, some passwords, where I buried the body, etc.&lt;/p&gt;

&lt;p&gt;They must be kept away from other eyes but, more importantly, they must be available, even if I'm traveling far from my computers.&lt;/p&gt;

&lt;p&gt;And they must be easily backed up without risk.&lt;/p&gt;

&lt;p&gt;In the past, I've dealt with such secret storage with various solutions, like having files decrypted, edited with my favorite editor, then encrypted again.&lt;/p&gt;

&lt;p&gt;They were full of weaknesses:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;temporary clear files that could be inadvertently backed up, or staying here if I had to leave or in case of crash&lt;/li&gt;
&lt;li&gt;editor weaknesses, like backup files and plugins&lt;/li&gt;
&lt;li&gt;OS specificity making them inaccessible when far from my computers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The temporary clear files where the most dangerous problem. I've had to hunt for my clear files after a badly parameterized backup rule.&lt;br&gt;
Editor plugins were a real threat too, especially as I started using an AI plugin storing whole extracts of my texts for better auto-completion.&lt;/p&gt;

&lt;p&gt;So I had to find or build better.&lt;/p&gt;

&lt;p&gt;The obvious requirements for my new solution were:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;an encrypted storage file, with a strong algorithm&lt;/li&gt;
&lt;li&gt;a storage format making it possible to keep the file on non secure disks&lt;/li&gt;
&lt;li&gt;a multi-platform application, that can be easily carried too&lt;/li&gt;
&lt;li&gt;totally open-source, so that the program can be fixed or rewritten&lt;/li&gt;
&lt;li&gt;no clear file ever created, no data sent to external API, so the application is an editor too&lt;/li&gt;
&lt;li&gt;pure Rust, to avoid most nasty bugs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I added a few less obvious requirements:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;easy fuzzy key search&lt;/li&gt;
&lt;li&gt;fast opening, instant closing&lt;/li&gt;
&lt;li&gt;auto-closing (dead man switch)&lt;/li&gt;
&lt;li&gt;focus on ergonomics, I want to feel comfortable editing in the application&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And in case I inadvertently become a secret agent:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;plausible deniability by putting drawers (storage units) inside other ones&lt;/li&gt;
&lt;li&gt;non observability of deep drawers (having several versions of the file doesn't let you know whether there were changes and in which deep drawer)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now, let's see the technical choices.&lt;/p&gt;

&lt;h3&gt;
  
  
  Programming language: Rust
&lt;/h3&gt;

&lt;p&gt;As I said, this was obvious to me. Such program can't really be written today in another language. Rust doesn't prevent all bugs, but it makes it possible to avoid the nasty ones which stay hidden and compromise security.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cryptographic algorithm and library : AES-GCM
&lt;/h3&gt;

&lt;p&gt;I never considered rolling my own algorithm or using a lightly tested library.&lt;/p&gt;

&lt;p&gt;I choose an AEDS crate from the RustCrypto group: &lt;a href="https://github.com/RustCrypto/AEADs/tree/master/aes-gcm-siv"&gt;AES-GCM in its SIV variant&lt;/a&gt; (the SIV variant isn't really needed but it doesn't cost much).&lt;/p&gt;

&lt;h3&gt;
  
  
  File format
&lt;/h3&gt;

&lt;p&gt;The minimal unit of secret in SafeCloset is an &lt;em&gt;entry&lt;/em&gt;, which is made of  a name and a value, for example "VISA Card code" and "9875".&lt;/p&gt;

&lt;p&gt;Entries are stored together in a &lt;em&gt;drawer&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;SafeCloset uses the metaphor of &lt;em&gt;closets&lt;/em&gt; and &lt;em&gt;drawers&lt;/em&gt;:&lt;br&gt;
A SafeCloset file contains something which is called a &lt;em&gt;closet&lt;/em&gt;.&lt;br&gt;
A &lt;em&gt;closet&lt;/em&gt; contains several &lt;em&gt;drawers&lt;/em&gt;. Each drawer is separately encrypted, with its own passphrase (and nonce).&lt;/p&gt;

&lt;p&gt;A drawer also contains a closet, which contains deeper drawers.&lt;/p&gt;

&lt;p&gt;To ensure plausible deniability, drawers are automatically created, including deep ones, and nothing distinguishes drawers that you created and you can open from the ones which were automatically created and that you can't open (you could if you knew their password but they aren't displayed on creation and they only contain random bytes anyway).&lt;/p&gt;

&lt;p&gt;Drawers are serialized using the &lt;a href="https://serde.rs/"&gt;serde&lt;/a&gt; crate which is kind of standard in the Rust world and is very convenient. For the encoding format, I choose &lt;a href="https://msgpack.org/index.html"&gt;MessagePack&lt;/a&gt; which, like JSON, allows field addition but is much more compact. Having optional fields is very important to allow evolution of the file format while ensuring old files will stay compatible with newer versions of the application.&lt;/p&gt;

&lt;p&gt;Combining the chosen encryption scheme and the serialization encoding with the list of structures and fields, the complete file format is described in the &lt;a href="https://dystroy.org/safecloset/community/#storage-format"&gt;community page&lt;/a&gt; to allow replacement of the application if needed.&lt;/p&gt;

&lt;h3&gt;
  
  
  Making an UI in the terminal
&lt;/h3&gt;

&lt;p&gt;There are many low level libraries whose features go from the basic (and easy) task of coloring and styling the text you print in the terminal to handling events, terminal size, alternate screen, etc. I personally like &lt;a href="https://github.com/crossterm-rs/crossterm"&gt;Crossterm&lt;/a&gt; which is cross platform and well designed.&lt;/p&gt;

&lt;p&gt;I combine it with &lt;a href="https://github.com/Canop/termimad/"&gt;Termimad&lt;/a&gt;, a crate I made to manage skins, generate texts without mixing the style and the content, handle text inputs, even with wide characters, and a lot of small TUI related problems.&lt;/p&gt;

&lt;p&gt;Termimad allows fancy things like editing texts in small areas of your terminal and fading the view behind the menus or dialogs:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--M71XjnL0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dystroy.org/safecloset/img/menu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--M71XjnL0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dystroy.org/safecloset/img/menu.png" alt="the fancy color fading" width="562" height="356"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As the author of Termimad I feel comfortable to &lt;em&gt;not&lt;/em&gt; recommend you use it for your own TUI. Not that it's bad, I like it, but it's a strange beast covering much more than what a library should do, and at a much lower level than your typical framework. If you're not used to low level TUI libraries and well versed in Rust, I suggest you look at other higher level TUI crates.&lt;br&gt;
If you still hesitate, come to &lt;a href="https://miaou.dystroy.org/3768"&gt;my chat&lt;/a&gt; and I'll tell you whether Termimad might be the right choice for your application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Other libraries
&lt;/h2&gt;

&lt;p&gt;They're very few other crates involved, way less than in common programs of the same complexity. This was a deliberate choice consistent with the global efforts of making it easier to check the source and of reducing the attack surface. &lt;/p&gt;

&lt;h2&gt;
  
  
  The result: SafeCloset
&lt;/h2&gt;

&lt;p&gt;Here it is: &lt;a href="https://dystroy.org/safecloset/"&gt;https://dystroy.org/safecloset/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If I may say so, I'd say SafeCloset is convenient and pleasant to use.&lt;br&gt;
It lets me find and read my secrets in a few keystrokes.&lt;br&gt;
And it seems to be the most secure solution I ever used.&lt;br&gt;
I designed it to be intuitive for other users too, and I hope I succeeded.&lt;/p&gt;

&lt;p&gt;To better introduce it,  I made a website explaining how it works, how to install it, how to use it: &lt;a href="https://dystroy.org/safecloset/"&gt;https://dystroy.org/safecloset/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The current version is a candidate for a release as 1.0, there's nothing important missing right now, but I'll let some time run to be sure.&lt;/p&gt;

&lt;p&gt;I'd welcome your opinion!&lt;br&gt;
And if you have questions, for example on technical details, please ask.&lt;/p&gt;

</description>
      <category>rust</category>
      <category>opensource</category>
      <category>showdev</category>
      <category>cryptography</category>
    </item>
    <item>
      <title>Lapin, a terminal game in Rust</title>
      <dc:creator>Denys Séguret</dc:creator>
      <pubDate>Thu, 12 Mar 2020 11:07:34 +0000</pubDate>
      <link>https://dev.to/dystroy/lapin-a-terminal-game-in-rust-6np</link>
      <guid>https://dev.to/dystroy/lapin-a-terminal-game-in-rust-6np</guid>
      <description>&lt;p&gt;My kids (4yo and 6yo) are fan of the command line since the first time I showed them &lt;code&gt;sl&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;One month ago, my youngest one asked for a game with a rabbit and a pink knight.&lt;/p&gt;

&lt;p&gt;In such a case, you can either postpone indefinitely or you can rush to finish it in the evenings of a few weeks so that he's still young enough to appreciate it.&lt;/p&gt;

&lt;p&gt;So &lt;a href="https://github.com/Canop/lapin" rel="noopener noreferrer"&gt;here it is&lt;/a&gt;, a game with a rabbit chased by foxes, wolves, and riffle armed hunters.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2FCanop%2Flapin%2Fraw%2Fmaster%2Fimg%2Fcitadel-corner.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2FCanop%2Flapin%2Fraw%2Fmaster%2Fimg%2Fcitadel-corner.png" alt="the game"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A turn by turn game where invulnerable pink knights fight all your foes.&lt;/p&gt;

&lt;p&gt;Rules so simple your kids will remember them after you've told them once.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdystroy.org%2Flapin%2Flong-help.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdystroy.org%2Flapin%2Flong-help.png" alt="help"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And an editor, because the best game for a kid is to draw (more so if the inks are made of foxes and pink knights and grass and mud...).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2FCanop%2Flapin%2Fraw%2Fmaster%2Fimg%2Fsapin.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2FCanop%2Flapin%2Fraw%2Fmaster%2Fimg%2Fsapin.png" alt="editor"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And campaigns in which you can pack sequences of levels you or your kids made.&lt;/p&gt;

&lt;p&gt;If you're more than 6yo, you won't be impressed by the graphics.&lt;/p&gt;

&lt;p&gt;As a developer you might find a few interesting things in this small and hopefully clear program:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;to start with, it's in Rust and I try to keep it &lt;a href="https://github.com/Canop/lapin/tree/master/src" rel="noopener noreferrer"&gt;clean&lt;/a&gt;. As usual in Rust, this was a delightful coding experience, almost bug-free from start to finish. An exemple of the zero cost abstractions and the sanity it brings is the use of separate types for the position on screen and the position in the game's world, I know I usually have confusion in code dealing with several reference systems in the same unit and there was none this time.&lt;/li&gt;
&lt;li&gt;a sane and safe state+transition based application architecture&lt;/li&gt;
&lt;li&gt;a &lt;a href="https://github.com/crossterm-rs/crossterm" rel="noopener noreferrer"&gt;crossterm&lt;/a&gt; based terminal UI with support for mouse, resize (and support for any size starting at 20*5), etc.&lt;/li&gt;
&lt;li&gt;pathfinding (Dijkstra and A*)&lt;/li&gt;
&lt;li&gt;hundreds of independent actors acting according to their own goals&lt;/li&gt;
&lt;li&gt;parallel computation of actor moves using &lt;a href="https://docs.rs/rayon/" rel="noopener noreferrer"&gt;rayon&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;unbounded maps&lt;/li&gt;
&lt;li&gt;sub-character move animation (try the game to understand)&lt;/li&gt;
&lt;li&gt;undo/redo stack&lt;/li&gt;
&lt;li&gt;serialization in user chosen format using &lt;a href="https://serde.rs/" rel="noopener noreferrer"&gt;serde&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;resource (default campaign) packed in the executable&lt;/li&gt;
&lt;li&gt;no excessive optimization (I considered a bitset based map and decided it wasn't worth the pain and stuck to sane and easy to read and change data structures)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And I'd welcome any help or advice to improve the program!&lt;/p&gt;

&lt;p&gt;(or levels for my kids)&lt;/p&gt;

&lt;p&gt;The code is almost a kid's game too:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;impl ActorKind {
    pub fn eats(self, other: Self) -&amp;gt; bool {
        use ActorKind::*;
        match (self, other) {
            (Fox, Lapin) =&amp;gt; true,
            (Knight, Fox) =&amp;gt; true,
            (Knight, Hunter) =&amp;gt; true,
            (Knight, Wolf) =&amp;gt; true,
            (Wolf, Hunter) =&amp;gt; true,
            (Wolf, Sheep) =&amp;gt; true,
            (Wolf, Lapin) =&amp;gt; true,
            _ =&amp;gt; false,
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Here's the repository: &lt;a href="https://github.com/Canop/lapin" rel="noopener noreferrer"&gt;https://github.com/Canop/lapin&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I'll be happy to answer your questions about the game or the code!&lt;/p&gt;

</description>
      <category>rust</category>
      <category>opensource</category>
      <category>showdev</category>
      <category>terminal</category>
    </item>
    <item>
      <title>An exploration of Rust/Wasm</title>
      <dc:creator>Denys Séguret</dc:creator>
      <pubDate>Mon, 01 Jul 2019 08:37:42 +0000</pubDate>
      <link>https://dev.to/dystroy/an-exploration-or-rust-wasm-50gp</link>
      <guid>https://dev.to/dystroy/an-exploration-or-rust-wasm-50gp</guid>
      <description>&lt;p&gt;A few days ago, I decided I needed to have an idea of what was the state and promises of Rust/Wasm development.&lt;/p&gt;

&lt;p&gt;And in order to have a clear idea of the soundness and strength of the foundations, I didn't want to deal with the advantages and problems of the various frameworks, I wanted to look at the real deal, Rust/Wasm without superfluous frameworks and libs.&lt;/p&gt;

&lt;p&gt;And I didn't want a mix approach with hard things done in JavaScript, I wanted to see whether you can do everything from rust and to what extent your experience is as positive as the classical Rust one.&lt;/p&gt;

&lt;p&gt;So I decided to write the tic-tac-toe game in pure Rust/Wasm.&lt;/p&gt;

&lt;p&gt;Before I go on with the journey, &lt;a href="https://dystroy.org/wasm-tictactoe/"&gt;Here's the result&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Nothing fancy but it made me test what I wanted to test. It works. And if you open the network tab of your browser's developer tools, you can notice the files are rather small, and there's no polling or useless redraw.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://webassembly.org/"&gt;WebAssembly&lt;/a&gt; is a binary instruction format that you can give any recent browser and which will be executed sandboxed with access to the browser. So building a rust+wasm application is mostly compiling your rust files into a .wasm file that you can serve to your browser in place of your usual JavaScript one. Your application will still contain a little bootstraper loading your wasm file and giving it to the browser, I hope this artefact will soon enough disappear.&lt;/p&gt;

&lt;p&gt;The first reef waiting for the explorer is that most tutorials are full of unneeded contorsions and tools, for example using npm, webpack and a framework when what you want is just to learn Rust/Wasm. This is the equivalent of learning JavaScript by first installing Angular, jQuery and Gulp.&lt;/p&gt;

&lt;p&gt;Here's a simple example, though: &lt;a href="https://rustwasm.github.io/docs/wasm-bindgen/examples/without-a-bundler.html"&gt;wasm-bindgen without a bundler&lt;/a&gt;. It's only a "Hello World" but it sets us on track.&lt;/p&gt;

&lt;p&gt;The basis is to use the &lt;em&gt;wasm-pack&lt;/em&gt; cargo tool to build the wasm file. You'll use only three libraries: &lt;code&gt;wasm-bindgen&lt;/code&gt; which links the JavaScript and Wasm world, &lt;code&gt;js_sys&lt;/code&gt; wich gives access to standard build-in objects like the JSON parser, the binary arrays or the Math function (when in wasm, you don't have access to the standard Rust libraries, even the ones which can be sandboxed, because they would have to be embedded in the wasm file), and &lt;code&gt;web_sys&lt;/code&gt; which gives you access to the browser's world (including the DOM).&lt;/p&gt;

&lt;p&gt;So, thanks to the example, I just wrote by hand the few files (no, you don't need a generator), that is the &lt;code&gt;Cargo.toml&lt;/code&gt; file and &lt;code&gt;src/lib.rs&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This is enough. You just have to execute&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;wasm-pack build --target web
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;and &lt;em&gt;voilà&lt;/em&gt;, you have a pkg directory containing your wasm file and a standard JS bootstraper.&lt;/p&gt;

&lt;p&gt;Of course, just like a JS file doesn't make an application, a Wasm one doesn't. So I added a HTML file, and a CSS one (you should have a look at &lt;a href="https://github.com/Canop/wasm-tictactoe/blob/master/index.html"&gt;the HTML file&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;From there, you just have to open your file through HTTP (after having configured the server to serve &lt;code&gt;.wasm&lt;/code&gt; files with the &lt;code&gt;application/wasm&lt;/code&gt; mime type. There's no need to publish to the npm repository, there's no need to use another packager, you can keep those kind of tasks for when your application really needs it and you know why, with the tool chain of your choice.&lt;/p&gt;

&lt;p&gt;At this point I had just copied the code from the example, which was adding an element with "Hello World" as inner HTML.&lt;/p&gt;

&lt;p&gt;The next step was to add the elements of a Tic-Tac-Toe game, the matrix.&lt;br&gt;
Knowing the DOM well enough I had no difficulty finding the right methods and structs in web_sys (Exhibit 1: &lt;a href="https://rustwasm.github.io/wasm-bindgen/api/web_sys/struct.Element.html"&gt;Element&lt;/a&gt;.&lt;br&gt;
I could directly write the elements in rust. It was clean enough but you fast notice this interface gives you a lesser type system, as some methods return you some value which may, or not, be of the desired type (for example if you create a node with &lt;code&gt;document.create_element&lt;/code&gt;, the &lt;code&gt;Node&lt;/code&gt; you get may be, or not, a &lt;code&gt;HtmlElement&lt;/code&gt; depending on the tag.&lt;br&gt;
This could easily be isolated in a tiny helper library, though, so this isn't a big deal.&lt;/p&gt;

&lt;p&gt;Glancing at &lt;a href="https://rustwasm.github.io/wasm-bindgen/api/web_sys/"&gt;web_sys&lt;/a&gt;, you may notice the methods to add event listeners are also here.&lt;br&gt;
web-sys does include a facility to make rust Closures and JavaScript closures interact. This isn't as simple as it seems.&lt;/p&gt;

&lt;p&gt;Now it looks good, we just have to design how we will cleanly keep our application state around and have a normal event based web application continuously adding and removing elements and event listeners, deal with events, and so on.&lt;/p&gt;

&lt;p&gt;Just the normal life of a web app, with the sanity of Rust, the perfect dream.&lt;/p&gt;

&lt;p&gt;But it's not that simple.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You must keep a reference to your rust closure or the JavaScript event handler will fail when called (at runtime... there's no compile time check). There's also the possibility to leak them but we're looking for a viable solution for a real application, so it's absolutely out of question.&lt;/li&gt;
&lt;li&gt;There's only one UI thread, and your event handlers are called on this thread.&lt;/li&gt;
&lt;li&gt;A Rust application isn't supposed to have a mutable static state anyway.&lt;/li&gt;
&lt;li&gt;You can't store your handlers behind an Arc, because the pointer to the JS isn't transferable between threads&lt;/li&gt;
&lt;li&gt;You don't have mpsc channels (in fact you don't have much of the &lt;em&gt;std&lt;/em&gt; utilities)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So... There's no really clean solution.&lt;/p&gt;

&lt;p&gt;I built something which is probably safe, and quite clear, but it involves ugly calls to &lt;code&gt;unsafe&lt;/code&gt; blocks to access the global state. I've put the active event handlers in this global state (which could be modularized).&lt;/p&gt;

&lt;p&gt;Closure creation and boxing is ugly too (exhibit 2: &lt;a href="https://github.com/Canop/wasm-tictactoe/blob/master/src/board_view.rs"&gt;BoardView&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Part of this problem could easily be isolated by a small framework, but the core isn't pretty.&lt;br&gt;
And a big framework means bigger wasm files.&lt;br&gt;
I hope some micro framework just for this problem will appear and be good enough without succumbing to the tentation of building a whole bag of template/binding/virtual-dom/etc fatness (some will need this one, of course, but we need a small strong core too).&lt;/p&gt;

&lt;p&gt;From there I just had to add the necessary logic (which isn't long or complicated for such a game) and the "You win/lose" panel, then to add a "New Game" button, mostly to check I can add and remove buttons and their handlers without leaking memory.&lt;/p&gt;

&lt;p&gt;And the game is done.&lt;/p&gt;

&lt;p&gt;With this experience, here's how I see the use of rust+wasm compared to JavaScript:&lt;/p&gt;

&lt;h2&gt;
  
  
  What do we gain
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;We write in Rust, which has a nicer syntax. Union types, traits, patterns, sane generics, an ownership which avoids the overhead of a garbage collector (and you really don't want your wasm file to include a GC), and no null pointer&lt;/li&gt;
&lt;li&gt;We have a little better type safety&lt;/li&gt;
&lt;li&gt;A lot more is tested at compile time than if we were to use JS, TS or another wasm language&lt;/li&gt;
&lt;li&gt;Rust modularisation is much cleaner than anything standard in the JS world, both at the internal application level and when it comes to use external packages&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What do we &lt;em&gt;not&lt;/em&gt; gain
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Type checking isn't totally perfect, due to the interface with the browser. It's probably not much better than TypeScript at this point&lt;/li&gt;
&lt;li&gt;There are more runtime errors that what would be expected from a rust program (because it's not a rust program, it's a browser+rust program)&lt;/li&gt;
&lt;li&gt;There's no multithreading. Concurrency tools like the mpsc channels aren't available. Even mutexes are only partly usable. Yes I'm sure there will be tools "supporting" multithreading through webworkers but serialization-based message passing between agents is reserved to a smaller set of use cases. Rust will be the most apt to use safe multithreading when SharedArrayBuffers are back, but there's no clear direction or dates for that. &lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What do we &lt;em&gt;not&lt;/em&gt; lose
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;There's not much from the client-side JS ecosystem which will be missed. Tools will be easily made to replace them.&lt;/li&gt;
&lt;li&gt;building applications totally or partly based in Rust doesn't seem to me to really complexify the tool chain. And I'm not sure it's slower to compile Rust than to lint/transpile JS nowadays.&lt;/li&gt;
&lt;li&gt;files aren't big. Rust needs no runtime, needs no gargbage collector, so there's not much to add to the wasm files.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What do we lose
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Managing the state of your application and the handlers makes for ugly code.&lt;/li&gt;
&lt;li&gt;There's less liberty in the architecture of your application.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As I love Rust I'll probably write some of my next webapp frontends in Rust/Wasm but this will need a small framework (of my own if I don't find anything good enough) and it's not something I would recommend at this point to developers with no knowledge of Rust.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;As you may have noticed, I wrote this with not much experience in Wasm (which was the point). I'd be really interested by your analysis and maybe corrections.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>rustwasmweb</category>
    </item>
    <item>
      <title>Edit your file hierarchy with Broot 0.7</title>
      <dc:creator>Denys Séguret</dc:creator>
      <pubDate>Fri, 08 Mar 2019 14:27:03 +0000</pubDate>
      <link>https://dev.to/dystroy/edit-your-file-hierarchy-with-broot-07-33fh</link>
      <guid>https://dev.to/dystroy/edit-your-file-hierarchy-with-broot-07-33fh</guid>
      <description>&lt;p&gt;I've just released the new version of &lt;a href="https://dystroy.org/" rel="noopener noreferrer"&gt;Broot&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The previous versions focused on viewing and navigating the file hierarchy but I noticed, just like a few other testers, that it could be very convenient to also edit it.&lt;/p&gt;

&lt;p&gt;When you create, move, delete, copy your files or directories, you usually do it in the blind, meaning you do some ls (or br) before, and maybe some after.&lt;/p&gt;

&lt;p&gt;With the new version of broot you see the file hierarchy when you type your command, and it's immediately updated. The tree view went from read-only to read-write.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fvcww5gvwmx5p743jj3uv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fvcww5gvwmx5p743jj3uv.png" alt="mkdir"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Standard file commands are built in, you don't need to add them, but the &lt;a href="https://dystroy.org/broot/documentation/configuration/#verbs" rel="noopener noreferrer"&gt;verb configuration syntax&lt;/a&gt; allows you to define your own commands the same way and you get to preview the expanded command before it's executed.&lt;/p&gt;

&lt;p&gt;There are already &lt;strong&gt;a lot&lt;/strong&gt; of features I can build upon this, and that I plan to do, but the more testers, ideas, stories I get, the happier I'll be!&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/Canop" rel="noopener noreferrer"&gt;
        Canop
      &lt;/a&gt; / &lt;a href="https://github.com/Canop/broot" rel="noopener noreferrer"&gt;
        broot
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      A new way to see and navigate directory trees : https://dystroy.org/broot
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Broot&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a href="https://github.com/Canop/broot/actions/workflows/tests.yml" rel="noopener noreferrer"&gt;&lt;img src="https://github.com/Canop/broot/actions/workflows/tests.yml/badge.svg" alt="Tests"&gt;&lt;/a&gt; &lt;a href="https://github.com/Canop/brootLICENSE" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/6581c31c16c1b13ddc2efb92e2ad69a93ddc4a92fd871ff15d401c4c6c9155a4/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d626c75652e737667" alt="MIT"&gt;&lt;/a&gt; &lt;a href="https://crates.io/crates/broot" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/07d9b56535306382e7287694f5202b47b0e26f58eb0adc68ea64cfcbcd51f109/68747470733a2f2f696d672e736869656c64732e696f2f6372617465732f762f62726f6f742e737667" alt="Latest Version"&gt;&lt;/a&gt; &lt;a href="https://miaou.dystroy.org/3490?broot" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/e58b2603c199e48d0690a29517e71f0c18c6153a5ba900119fec2a92ff662bd6/68747470733a2f2f6d69616f752e64797374726f792e6f72672f7374617469632f736869656c64732f726f6f6d2e737667" alt="Chat on Miaou"&gt;&lt;/a&gt; &lt;a href="https://repology.org/project/broot/versions" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/f314cc63d0b67b7004a4575c99efe87796f01115875c98d4b77c959c9e9c4352/68747470733a2f2f7265706f6c6f67792e6f72672f62616467652f74696e792d7265706f732f62726f6f742e737667" alt="Packaging status"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A better way to navigate directories&lt;/p&gt;
&lt;p&gt;&lt;a href="https://dystroy.org/broot/" rel="nofollow noopener noreferrer"&gt;&lt;strong&gt;Complete Documentation&lt;/strong&gt;&lt;/a&gt; -
&lt;a href="https://dystroy.org/broot/install/" rel="nofollow noopener noreferrer"&gt;&lt;strong&gt;Installation Instructions&lt;/strong&gt;&lt;/a&gt; -
&lt;a href="https://dystroy.org/blog/contributing/" rel="nofollow noopener noreferrer"&gt;&lt;strong&gt;Contributing or Getting Help&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Get an overview of a directory, even a big one&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;Hit &lt;code&gt;br -s&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/Canop/brootwebsite/docs/img/20230930-overview.png"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2FCanop%2Fbrootwebsite%2Fdocs%2Fimg%2F20230930-overview.png" alt="overview"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Notice the &lt;em&gt;unlisted&lt;/em&gt;?&lt;/p&gt;
&lt;p&gt;That's what makes it usable where the old &lt;code&gt;tree&lt;/code&gt; command would produce pages of output.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;.gitignore&lt;/code&gt; files are properly dealt with to put unwanted files out of your way.&lt;/p&gt;
&lt;p&gt;As you sometimes want to see gitignored files, or hidden ones, you'll soon get used to the alti and alth shortcuts to toggle those visibilities.&lt;/p&gt;
&lt;p&gt;(you can ignore them though, see &lt;a href="https://dystroy.org/broot/navigation/#toggles" rel="nofollow noopener noreferrer"&gt;documentation&lt;/a&gt;).&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Find a directory then &lt;code&gt;cd&lt;/code&gt; to it&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;type a few letters&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/Canop/brootwebsite/docs/img/20230930-cd.png"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2FCanop%2Fbrootwebsite%2Fdocs%2Fimg%2F20230930-cd.png" alt="cd"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Hit altenter and you're back to the terminal in the desired location.&lt;/p&gt;
&lt;p&gt;This way, you can navigate to a directory with the minimum amount of keystrokes, even if you don't exactly remember where it is.&lt;/p&gt;
&lt;p&gt;Broot is fast and doesn't…&lt;/p&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/Canop/broot" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


</description>
      <category>rust</category>
      <category>cli</category>
      <category>linux</category>
      <category>opensource</category>
    </item>
    <item>
      <title>broot, a new way to browse directories</title>
      <dc:creator>Denys Séguret</dc:creator>
      <pubDate>Fri, 01 Feb 2019 11:05:05 +0000</pubDate>
      <link>https://dev.to/dystroy/broot-a-new-way-to-browse-directories-779</link>
      <guid>https://dev.to/dystroy/broot-a-new-way-to-browse-directories-779</guid>
      <description>&lt;p&gt;I always loved the overview you can get from a tree like view. But &lt;code&gt;tree&lt;/code&gt; is almost never usable, because it usually generates pages (or hundreds of pages) of output.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;tree&lt;/code&gt; is also not interactively searchable and of course doesn't act as a launcher. &lt;/p&gt;

&lt;p&gt;&lt;code&gt;tree&lt;/code&gt; was one of the starting point in the reflection. &lt;code&gt;fzf&lt;/code&gt; was another one, I can't live without fuzzy search anymore.&lt;/p&gt;

&lt;p&gt;And thus I made &lt;a href="https://github.com/Canop/broot" rel="noopener noreferrer"&gt;broot&lt;/a&gt; which I use all the time, which lets me go to any directory or file with a few keystrokes and faster than any other one.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fnkbjz085ov9drby0pic5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fnkbjz085ov9drby0pic5.png" alt="shortcut"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It's ready for general consumption, now, but I'm still thirsty for feedback.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;broot&lt;/strong&gt; can be launched with commands, which allows for example non interactive shortcuts like this one:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F4p9g423vr5q5012ag6dl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F4p9g423vr5q5012ag6dl.png" alt="dcd rulset"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If any rust expert is around, I'd love to discuss the code, especially any ideas of micro-optimizations (the development of such a program is all about speed).&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/Canop" rel="noopener noreferrer"&gt;
        Canop
      &lt;/a&gt; / &lt;a href="https://github.com/Canop/broot" rel="noopener noreferrer"&gt;
        broot
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      A new way to see and navigate directory trees : https://dystroy.org/broot
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Broot&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a href="https://github.com/Canop/broot/actions/workflows/tests.yml" rel="noopener noreferrer"&gt;&lt;img src="https://github.com/Canop/broot/actions/workflows/tests.yml/badge.svg" alt="Tests"&gt;&lt;/a&gt; &lt;a href="https://github.com/Canop/brootLICENSE" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/6581c31c16c1b13ddc2efb92e2ad69a93ddc4a92fd871ff15d401c4c6c9155a4/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d626c75652e737667" alt="MIT"&gt;&lt;/a&gt; &lt;a href="https://crates.io/crates/broot" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/07d9b56535306382e7287694f5202b47b0e26f58eb0adc68ea64cfcbcd51f109/68747470733a2f2f696d672e736869656c64732e696f2f6372617465732f762f62726f6f742e737667" alt="Latest Version"&gt;&lt;/a&gt; &lt;a href="https://miaou.dystroy.org/3490?broot" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/e58b2603c199e48d0690a29517e71f0c18c6153a5ba900119fec2a92ff662bd6/68747470733a2f2f6d69616f752e64797374726f792e6f72672f7374617469632f736869656c64732f726f6f6d2e737667" alt="Chat on Miaou"&gt;&lt;/a&gt; &lt;a href="https://repology.org/project/broot/versions" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/f314cc63d0b67b7004a4575c99efe87796f01115875c98d4b77c959c9e9c4352/68747470733a2f2f7265706f6c6f67792e6f72672f62616467652f74696e792d7265706f732f62726f6f742e737667" alt="Packaging status"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A better way to navigate directories&lt;/p&gt;
&lt;p&gt;&lt;a href="https://dystroy.org/broot/" rel="nofollow noopener noreferrer"&gt;&lt;strong&gt;Complete Documentation&lt;/strong&gt;&lt;/a&gt; -
&lt;a href="https://dystroy.org/broot/install/" rel="nofollow noopener noreferrer"&gt;&lt;strong&gt;Installation Instructions&lt;/strong&gt;&lt;/a&gt; -
&lt;a href="https://dystroy.org/blog/contributing/" rel="nofollow noopener noreferrer"&gt;&lt;strong&gt;Contributing or Getting Help&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Get an overview of a directory, even a big one&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;Hit &lt;code&gt;br -s&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/Canop/brootwebsite/docs/img/20230930-overview.png"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2FCanop%2Fbrootwebsite%2Fdocs%2Fimg%2F20230930-overview.png" alt="overview"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Notice the &lt;em&gt;unlisted&lt;/em&gt;?&lt;/p&gt;
&lt;p&gt;That's what makes it usable where the old &lt;code&gt;tree&lt;/code&gt; command would produce pages of output.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;.gitignore&lt;/code&gt; files are properly dealt with to put unwanted files out of your way.&lt;/p&gt;
&lt;p&gt;As you sometimes want to see gitignored files, or hidden ones, you'll soon get used to the alti and alth shortcuts to toggle those visibilities.&lt;/p&gt;
&lt;p&gt;(you can ignore them though, see &lt;a href="https://dystroy.org/broot/navigation/#toggles" rel="nofollow noopener noreferrer"&gt;documentation&lt;/a&gt;).&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Find a directory then &lt;code&gt;cd&lt;/code&gt; to it&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;type a few letters&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/Canop/brootwebsite/docs/img/20230930-cd.png"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2FCanop%2Fbrootwebsite%2Fdocs%2Fimg%2F20230930-cd.png" alt="cd"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Hit altenter and you're back to the terminal in the desired location.&lt;/p&gt;
&lt;p&gt;This way, you can navigate to a directory with the minimum amount of keystrokes, even if you don't exactly remember where it is.&lt;/p&gt;
&lt;p&gt;Broot is fast and doesn't…&lt;/p&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/Canop/broot" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


</description>
      <category>githunt</category>
      <category>rust</category>
      <category>cli</category>
      <category>linux</category>
    </item>
  </channel>
</rss>
