<?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: Ramayen</title>
    <description>The latest articles on DEV Community by Ramayen (@vimyoung).</description>
    <link>https://dev.to/vimyoung</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4099323%2F95994829-e1a6-4b94-9cd0-fdd57c34befd.png</url>
      <title>DEV Community: Ramayen</title>
      <link>https://dev.to/vimyoung</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/vimyoung"/>
    <language>en</language>
    <item>
      <title>Frame Rate improvement for faster Rendering</title>
      <dc:creator>Ramayen</dc:creator>
      <pubDate>Wed, 10 Dec 2025 00:00:00 +0000</pubDate>
      <link>https://dev.to/vimyoung/frame-rate-improvement-for-faster-rendering-2kem</link>
      <guid>https://dev.to/vimyoung/frame-rate-improvement-for-faster-rendering-2kem</guid>
      <description>&lt;p&gt;In this article, we are going to go through following:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A basic reference of what the performance issue was.&lt;/li&gt;
&lt;li&gt;Initial analysis approach with logging and results of logs.&lt;/li&gt;
&lt;li&gt;Brief section about &lt;code&gt;perf&lt;/code&gt; and how it can be used in this scenario.&lt;/li&gt;
&lt;li&gt;Understanding the issue with &lt;code&gt;flamegraph&lt;/code&gt; outputs.&lt;/li&gt;
&lt;li&gt;Previous architecture of program and why it was used.&lt;/li&gt;
&lt;li&gt;Exploring possible solutions and their limitations.&lt;/li&gt;
&lt;li&gt;Results after application of optimal approach in performace.&lt;/li&gt;
&lt;li&gt;Discussing further improvements in rendering and possible assumptions.&lt;/li&gt;
&lt;li&gt;Concluding the article with updated &lt;code&gt;flamegraph&lt;/code&gt; output with better performance.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;So, to give some context:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I have been making a library called &lt;strong&gt;Spell&lt;/strong&gt; which provides a backend of slint to create desktop widgets for linux ricing.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;There are a lot of words in the previous sentence which may not make sense. Let us go through them in reverse Desktop linux users may be familiar with the word "ricing". Daily driving linux as your primary desktop machine has a lot of perks. One get greater control over the OS (and hardware) and endless customizability options. One such customisation is a clean slate of "display" without any UI components. So you don't have top bars, app launchers, docks, panels, lock screens etc. This can be done when you opt out of using community maintained desktop environments (like gnome, plasma etc) and go on to just use a window manager (or wayland compositor in this case). The system thus configured remains extremely light and minimal. You can then install 3rd party tools or code these UI components yourself. People create their own workflows from scratch. This gives a fresh look to your desktop and the exact setup you want.&lt;/p&gt;

&lt;p&gt;Traditionally, these UI components are made in GTK UI toolkit. Plasma (by KDE) uses Qt for its applications. To easy the development of creating these widgets/UI components, various people have created frameworks that applies abstraction over GTK to ease out the process. Rather than making another GTK widget toolkit, Spell explores a unique gap. It provides the backend of slint, a declarative language, to create these UI components. My choice of integrating slint for this use case is due to its versatility and great integration with rust which helped in the process of porting it to wayland. Now, I received a recent issue on CPU usage maxing to 100 percent when using spell. The article discusses how the performance is improved and the issue is fixed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Initial Response
&lt;/h2&gt;

&lt;p&gt;I wasn't surprised by the issue as I was also having some performance issues when using spell in rust's debug profile. I thought the problem originated from weak CPU power of my system but the issue confirmed that spell's rendering is not optimised and can be improved. I first added some print statements to see how long it takes to render a buffer( a chunk of memory where the UI's pixel data is stored, generally in the form of arrays) to screen. The result is following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Skia Elapsed Time: 0
Normal Elapsed Time: 0
Release 110 @ (14.37109375, 29.28515625)
Keyboard focus entered
Keyboard focus entered
This trait implementation of RenderBuffer is Run
Skia Elapsed Time: 8
Normal Elapsed Time: 126
This trait implementation of RenderBuffer is Run
Skia Elapsed Time: 14
Normal Elapsed Time: 121
This trait implementation of RenderBuffer is Run
Skia Elapsed Time: 14
Normal Elapsed Time: 124
This trait implementation of RenderBuffer is Run
Skia Elapsed Time: 14
Normal Elapsed Time: 124
This trait implementation of RenderBuffer is Run
Skia Elapsed Time: 9
Normal Elapsed Time: 127
This trait implementation of RenderBuffer is Run
Skia Elapsed Time: 3
Normal Elapsed Time: 126
Skia Elapsed Time: 0
Normal Elapsed Time: 0

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The section shows logs for a 200ms animation on the buffer. Some things to note:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;When there no changes/interactions, the rendering time is zero milliseconds, this can be seen at the start and end of these logs.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Each buffer's repainting produces 3 logs, the time it took slint's backend skia to change pixel, represented by &lt;code&gt;Skia Elapsed Time&lt;/code&gt;, the time it took to process for wayland by &lt;code&gt;Normal Elapsed Time&lt;/code&gt; and if the frame is actually updated or not by printing &lt;code&gt;This trait implementation of RenderBuffer is Run&lt;/code&gt; if true.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;This log is the highest every time it took to produce a new frame, generally the time for Skia rendering varies around 9 ms and for processing it took around 32 ms on average, so though the value is fluctuating, (like here it took as long as 130 ms for a frame), on average it took 40 ms to produce a frame (in release profile).&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This shows some scope of improvement, if it takes on average 40 ms to produce a new frame, for a 200ms, I was only getting 5 frame, hence resulting in jerky animations. So, these logs do help in understanding where the maximum amount of time is being taken, yet the hike in CPU can't be explained by logs alone, they provide the time data but not the computation details.&lt;/p&gt;

&lt;p&gt;This shows some scope of improvement, if it takes on average 40 ms to produce a new frame, for 200ms, I was only getting 5 frames, hence resulting in jerky animations. So, these logs do help in understanding where the maximum amount of time is being taken, yet the hike in cpu can't be explained by logs alone, they provide the time data but not the computation details.&lt;/p&gt;

&lt;p&gt;So, when searching for the tools to access the computational details, I recalled I had bookmarked &lt;a href="https://phoenixnap.com/kb/linux-perf" rel="noopener noreferrer"&gt;this&lt;/a&gt; page on &lt;code&gt;perf&lt;/code&gt;command when reading the mail of Andres Freud about the xz vulnerability (out of curiosity). Surfing further brought me to &lt;code&gt;flamegraph&lt;/code&gt; (and extension &lt;code&gt;cargo-flamegraph&lt;/code&gt;for rust projects) which can show perf output into an interactive graph svg for better interpretation of program. So, let's understand a bit about how &lt;code&gt;perf&lt;/code&gt; works.&lt;/p&gt;

&lt;h3&gt;
  
  
  How does perf work, in layman's terms
&lt;/h3&gt;

&lt;p&gt;I was intrigued by &lt;code&gt;perf&lt;/code&gt; and wanted to know how it works internally to produce such necessary performance information. Turns out, modern processors have special registers called Hardware performance pointers. As per Wikipedia, these store counts of hardware-related activities, which are further used for performance analysis in certain aspects. Modern OS kernels provide APIs to access information by these registers. This is exploited by perf. Flamegraphs then uses perf's metrics to produce these graphs, how to interpret them is best explained on their website. Quoting&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The x-axis shows the stack profile population, sorted alphabetically (it is not the passage of time), and the y-axis shows stack depth, counting from zero at the bottom. Each rectangle represents a stack frame. The wider a frame is is, the more often it was present in the stacks.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Stack profile population is basically a trace of which functions are called and how often a function/instruction call occurs. So, with this info in place we can analyse some data output.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Issue
&lt;/h2&gt;

&lt;p&gt;When looking at the (rather boring ) perf output, I could only figure out the fact that a custom function of mine has a rather equal or more biased CPU percentage to &lt;code&gt;Self&lt;/code&gt; than to the slint drawing it calls, but the structure of wayland involve various checks and callbacks, so the overhead mechanism of wayland was shadowing the data. So, I moved towards looking flamegraphs, which gave a rather clear picture. The primary graph looked like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhs8igytup3b57s54cf8u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhs8igytup3b57s54cf8u.png" width="800" height="269"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A few thing to notice:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;First of all &lt;code&gt;..ault::Default::default&lt;/code&gt; entry left of &lt;code&gt;spell_framework::run_loop_once&lt;/code&gt;is unrelated to the topic of analysis because it represents some other utility initialisation.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;run_event_loop&lt;/code&gt; is the custom function called on each iteration of frame. First optimisation can be noticed here, the function calls &lt;code&gt;block_displatch&lt;/code&gt;and a &lt;code&gt;dispatching_impl&lt;/code&gt;(mark 2) methods wherein &lt;code&gt;blocking_dispatch&lt;/code&gt; itself calls&lt;code&gt;dispatching_impl&lt;/code&gt;(mark 1) internally. In a single iteration, the process of dispatching of events need not happen twice, so I removed &lt;code&gt;blocking_dispatch&lt;/code&gt;in favour of calling &lt;code&gt;blocking_read&lt;/code&gt; and &lt;code&gt;dispatching_impl&lt;/code&gt; directly once. This brought some improvement. The changed code produced the following graph.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2wpaptyohkozawcju6sk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2wpaptyohkozawcju6sk.png" width="800" height="247"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On further analysis:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;run_loop_once&lt;/code&gt; calls 3 sequential functions in it, namely:

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;flush&lt;/code&gt; : Flushes old requests of updation of the UI if pending.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;blocking_read&lt;/code&gt;: internal wayland function which seeks new requests. It uses half of it computational work in &lt;code&gt;Self&lt;/code&gt; and almost half in call&lt;code&gt;InnerEventGaurd::read&lt;/code&gt;, but since this is an internal function provided by wayland_client, there can be no optimisations by me.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;dispatching_impl&lt;/code&gt;: called by the event queue to run the callback function which renders the new frame. It internally calls &lt;code&gt;SpellWin::converter&lt;/code&gt;(mark &lt;strong&gt;1&lt;/strong&gt; ) which is a custom function I made. It has scope of improvement, let's zoom in to understand the distribution.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;It is important to note that even though &lt;code&gt;flush&lt;/code&gt; and &lt;code&gt;blocking_read&lt;/code&gt; holds more space in the graph, they are repeated functions with very less computational work. They block to read input/events, the CPU works more in rendering the new buffer to pixels.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frg8lw501sbn8flknae1b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frg8lw501sbn8flknae1b.png" width="798" height="226"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This graph tells a singular thing very prominently. the &lt;code&gt;draw_if_needed&lt;/code&gt;(top right) function is what calls the Skia renderer on the buffer memory chunk to update the pixels, so of all the time &lt;code&gt;converter&lt;/code&gt; takes to process, only about 25 percent is utilised in actual rendering, the rest is the processing of new information. It is at this point I understood what was going wrong. Here is a actual snippet for you to guess(though the function shouldn't make sense without context but I have added comments for help)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;qh&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;QueueHandle&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;Self&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="c1"&gt;// Initialisation and setting basic vars.&lt;/span&gt;
        &lt;span class="nn"&gt;slint&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;platform&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;update_timers_and_animations&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;u32&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.size.width&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;u32&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.size.height&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;window_adapter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.adapter&lt;/span&gt;&lt;span class="nf"&gt;.clone&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.is_hidden&lt;/span&gt;&lt;span class="nf"&gt;.get&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
             &lt;span class="c1"&gt;// Rendering from Skia&lt;/span&gt;
            &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;redraw_val&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;window_adapter&lt;/span&gt;&lt;span class="nf"&gt;.draw_if_needed&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

            &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;pool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.memory_manager.pool&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;buffer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.memory_manager.wayland_buffer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;primary_canvas&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="nf"&gt;.canvas&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

          &lt;span class="c1"&gt;// Converting slint array for wayland memory Buffer&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;redraw_val&lt;/span&gt; &lt;span class="p"&gt;||&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.first_configure&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="n"&gt;primary_canvas&lt;/span&gt;
                        &lt;span class="nf"&gt;.iter_mut&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                        &lt;span class="nf"&gt;.enumerate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                        &lt;span class="nf"&gt;.for_each&lt;/span&gt;&lt;span class="p"&gt;(|(&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;)|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                            &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.core&lt;/span&gt;&lt;span class="nf"&gt;.borrow&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="py"&gt;.primary_buffer&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
                        &lt;span class="p"&gt;});&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

           &lt;span class="c1"&gt;// Leftover layer calls for asking new frame and reattaching updated Buffer.&lt;/span&gt;
            &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.first_configure&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.layer&lt;/span&gt;&lt;span class="nf"&gt;.wl_surface&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.damage_buffer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;width&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;i32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;height&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;i32&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.layer&lt;/span&gt;&lt;span class="nf"&gt;.wl_surface&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.frame&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;qh&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.layer&lt;/span&gt;&lt;span class="nf"&gt;.wl_surface&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.clone&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
            &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.layer&lt;/span&gt;&lt;span class="nf"&gt;.wl_surface&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.attach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="nf"&gt;.wl_buffer&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.layer&lt;/span&gt;&lt;span class="nf"&gt;.commit&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The issue is at line 19. Technically, this instruction copies every array element to the buffer. Element of buffer are simply &lt;code&gt;u8&lt;/code&gt; (unsigned int of 8 bits) values where 4 consecutive values represent a pixel (in RGBA format). So, on every frame the whole memory space carrying the pixels were being copied. This was an expensive process. For example for a 500 width and 800 height widget the memory array would be of length &lt;code&gt;500 * 800 * 4 = 1,600,000&lt;/code&gt;. And this array was copied almost every time.&lt;/p&gt;

&lt;p&gt;So, now we know the issue. It is still important to understand why I wrote such code and how can I mitigate the copying by possible solutions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this architecture was chosen
&lt;/h2&gt;

&lt;p&gt;A spell window (called &lt;code&gt;SpellWin&lt;/code&gt;) is composed of 2 components, the primary being the wayland part and secondarily an &lt;code&gt;Rc&lt;/code&gt; (reference counter) to the slint backend (can be seen as &lt;code&gt;self.window_adapter&lt;/code&gt; in the above code). The backend of slint is called for redrawing, parsing key input events, touch input events and cursor pointer input events.&lt;code&gt;Buffer&lt;/code&gt; is a struct provided by Smithay (maintain's port of wayland in rust) for accessing the underlying memory which stores the pixels. The issue is that Buffer can't be passed to slint backend during the initialisation of &lt;code&gt;SpellWin&lt;/code&gt; as its mutable reference is required for features like:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Hiding window from screen, without clearing the buffer.&lt;/li&gt;
&lt;li&gt;Reappearing of window, without redrawing.&lt;/li&gt;
&lt;li&gt;Showing only a section of Buffer.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;As one may know, a mutable reference can't be accessed if value is behind a reference counter. Buffer can not be wrapped by RefCell due to some trait requirements. So, I came up with a &lt;code&gt;SharedCore&lt;/code&gt; (a struct storing arrays of pixels for various buffers) wrapped in &lt;code&gt;Rc&amp;lt;RefCell&amp;lt;&amp;gt;&amp;gt;&lt;/code&gt; and passed an instance to both slint and wayland. Then, when &lt;code&gt;draw_if_needed&lt;/code&gt; was called slint made changes to &lt;code&gt;SharedCore&lt;/code&gt;, later complete array of SharedCore was copied into Buffer for rendering. Both initialisation and rendering is shown below.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Initialisation :&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F23535ekdgdhlsxqzcu7r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F23535ekdgdhlsxqzcu7r.png" width="800" height="432"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Rendering of a Frame :&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F10bxv22cxi0znmpp9v4z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F10bxv22cxi0znmpp9v4z.png" width="800" height="392"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Exploring Solutions
&lt;/h2&gt;

&lt;p&gt;So, what are my options here. Given the problem to share same memory chunk of Buffer between 2 separate processes. Let's explore possible alternatives and see if one can fit into this architecture. It is important to mention that &lt;code&gt;Buffer&lt;/code&gt; doesn't implement clone. It is provided/ created by another struct call &lt;code&gt;SlotPool&lt;/code&gt; responsible for creating buffers of various sizes. Also the fact that a &lt;code&gt;Slotpool&lt;/code&gt;'s instance is always necessary to grab the underlying canvas (i.e. &lt;code&gt;&amp;amp;mut [u8]&lt;/code&gt;) of a Buffer to write over the memory directly.&lt;/p&gt;

&lt;p&gt;The first and most direct approach is to merge the structs of slint's backend and wayland objects, that way wayland's wouldn't have to hold a stance of slint's backend, rather it would become slint's backend. The approach poses 2 primary restrictions which can not be overlooked.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Slint need a backend to be set for it to use it. Otherwise, slint chooses the default rendering mechanism to show the UI. This will end up in creation of an application window for desktop. This will not be appropriate as we want widgets to be made from slint.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Slint's platform setting mechanism expect an Rc wrapped instance of the new backend due to its structure of APIs. But then the whole window of slint &lt;strong&gt;and wayland&lt;/strong&gt; would need to be wrapped and parsed. Resulting in the fact that all methods of &lt;code&gt;SpellWin&lt;/code&gt; would need to be converted from &lt;code&gt;&amp;amp;mut self&lt;/code&gt; to &lt;code&gt;&amp;amp;self&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Another obvious approach is to pass both &lt;code&gt;Buffer&lt;/code&gt; and &lt;code&gt;SlotPool&lt;/code&gt; to slint, yet again this approach poses some issues of its own.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;This makes my code less readable given the fact that the distinction between slint's backend and wayland's objects are not properly separated.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Even if they could be passed, all other functionalities of wayland reside within &lt;code&gt;SpellWin&lt;/code&gt; directly. So even though the buffer could be updated directly, the change couldn't be transferred to an actual visual frame.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I did try to implement this architectural change and after 2 days of work I started bumping into runtime errors of reference already being borrowed mutable so I had to revert back.&lt;/p&gt;

&lt;p&gt;Only when I was about to ask the same on a forum I decided to sweep the docs one last time to ensure these values can't be copied. There I came across a method of &lt;code&gt;Buffer&lt;/code&gt; which yielded a struct called &lt;code&gt;Slot&lt;/code&gt;. This was a basic object whose only job was to provide the underlying memory chunks. Surplus to it, &lt;code&gt;Slot&lt;/code&gt; could also be cloned since all the clones would point to same pixels.&lt;/p&gt;

&lt;p&gt;So, I came up with the approach that during initialisation, an instance of &lt;code&gt;Slot&lt;/code&gt; of a &lt;code&gt;Buffer&lt;/code&gt; would be passed to slint. When a new frame be called, Skia (slint's backend) would directly write to pixels via &lt;code&gt;Slot&lt;/code&gt;, then buffer could be directly pushed for the new frame. &lt;strong&gt;Initialisation :&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8nymvkrguopuzzr8d98p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8nymvkrguopuzzr8d98p.png" width="800" height="387"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Rendering of a frame :&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcqr1fsxiv4o2nasvop0n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcqr1fsxiv4o2nasvop0n.png" width="800" height="339"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Expected results
&lt;/h2&gt;

&lt;p&gt;So, after the work of another few days I was able to fight the compiler and brought this architecture into my code. The next thing was to check the performance improvements which this experiment bought, so I looked up the logs to find the rendering of buffers with an average of 8 ms. With all the copying time stripped, normal rendering of skia is at 8ms so it is all that was left. Hence, now a 200 ms animation had 25 frames rather than 5 which is a great improvement. With these changes in place I closed the issue with the Author of issue satisfied. Added "Massive performance improvement in rendering" in my CHANGELOG.md and called it a win.&lt;/p&gt;

&lt;h2&gt;
  
  
  Scope for more optimisation
&lt;/h2&gt;

&lt;p&gt;When I started with this project, frame's rendering was at 140 ms, I brought it down to 40 and now 7ms. So, further changes may bring very light improvements. Also, with this rate the library will be compatible with a monitor of frame rate as high as 120Hz. Nonetheless, currently my loop runs indefinitely when there is no change in buffer. this loop should be brought to sleep for the frame rate of monitor rendering upon. Hence, preventing loops from over run. blocking the loop is not optimal as it hosts events from multiple sources and blocking on one would cause issues in submission of events from these other sources. Other improvement can be seen in line 30 of the code I provided.&lt;/p&gt;

&lt;p&gt;Since damaging the buffer for a new frame takes a rectangular space in local coordinate system, this can be modified to enable partial rendering from the data skia provides. It would have to be seen though if extra computation of calculating rectangles is worth the time cut provided by partial rendering. Another metric which is left but should be considered is the actual time to render a buffer into frame.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;So, with everything in place, here is the updated flamegraph of &lt;code&gt;run_loop_once&lt;/code&gt;. You can notice that &lt;code&gt;converter&lt;/code&gt;'s time is mostly invested in calling the rendering only.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fju6kjjj3sw8pmzwii78w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fju6kjjj3sw8pmzwii78w.png" width="800" height="242"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With this, we have reached the end of the blog, thanks for reading it. Provide any inputs and contact me for suggestions. Thank you and Happy Coding !&lt;/p&gt;

</description>
      <category>theoreticalwriteups</category>
      <category>rust</category>
    </item>
    <item>
      <title>Hardened Scopes: A mental model for rust</title>
      <dc:creator>Ramayen</dc:creator>
      <pubDate>Thu, 06 Nov 2025 00:00:00 +0000</pubDate>
      <link>https://dev.to/vimyoung/hardened-scopes-a-mental-model-for-rust-51gd</link>
      <guid>https://dev.to/vimyoung/hardened-scopes-a-mental-model-for-rust-51gd</guid>
      <description>&lt;p&gt;In this article, we are going to go through following:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Explaining how rust works and how it should be though of.&lt;/li&gt;
&lt;li&gt;Shortcomings of basic mental models when refactoring code.&lt;/li&gt;
&lt;li&gt;Designing function signatures for less pain in large projects.&lt;/li&gt;
&lt;li&gt;Role of better architectures for projects.&lt;/li&gt;
&lt;li&gt;Concluding the article with brief summary.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;I came across rust almost two years ago now. It is so to say my first language that I learned seriously and all by myself. No tutorials watched. Just the books on the lang. I knew python before that but I was only 12 and I never cared to look beyond the basic control flow of the language. My world was confined in Jupyter notebooks and I never made something usable out of my understanding. Unlike python, I learned rust on my own and spend quiet some time in trying to deliver something open source to the community. I made a TUI application,a small framework, read the official rust book and completed rustlings. While writing code, an idea of model of &lt;em&gt;how rust should be thought of&lt;/em&gt; occurred to me that I found good enough to share. As I came across a hell amount of issues while fighting the borrow checker. There is a common pattern that I was doing wrong almost always.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Borrow Checker can be thought of as a sub-program of rustc compiler that checks the ownership rules in a code snippet. Ownership rules are discussed below.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The most widely used way of understanding the ownership rules for the lang is to think of references and mut references as &lt;strong&gt;pointers&lt;/strong&gt; (like in &lt;code&gt;C&lt;/code&gt;) and reason about the requirement of that variable in a function or block. If you want to read the data, a normal reference should be used. If you think that the data might be changed or modified in a code block then the reference should be mutable. Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;interest&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;u32&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;years&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;u32&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="c1"&gt;// Amount represents the total amount, initially it is equal to principal&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;u32&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10045&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nf"&gt;simple_interest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;interest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;years&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"The amount to be repaid: {}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;simple_interest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="nb"&gt;u32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;interest&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;u32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;years&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;u32&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;interest&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;years&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here you can see that on running this program with command &lt;code&gt;rustc filname.rs&lt;/code&gt;, we get the amount.&lt;/p&gt;

&lt;p&gt;The concept is pretty simple and precisely fits what the ownership rules try to say. The problem is, when you enter into real world and start building something in rust while keeping this philosophy, it feels pretty scarce. I mean you will face very basic ownership errors and the compiler shakes pretty well. I agree that refining comes after you do a ton of mistakes, specially in rust.&lt;/p&gt;

&lt;p&gt;Still, a better sense of the language can be provided to mitigate it and start off with better ground. The objective is not to make the beginner avoid mistakes but give them a better perspective of what they are actually writing and not just wait for the compiler to point it out ( the rush and excitement after knowing something is wrong before LSP points it out is satisfying, I felt it for the first time when I was sure that explicit lifetimes would be needed in a function signature before the compiler pointed it out). Thus, with the intro in place, Let's get started on &lt;em&gt;thinking rust better&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Refactoring and code isolation
&lt;/h2&gt;

&lt;p&gt;Let us first get a grasp of how ownership is implemented in rust. It is a common notion that ownership is &lt;strong&gt;all about&lt;/strong&gt; references and which variable "owns" what in the memory. It is more than that. Actually, the ownership &lt;strong&gt;is&lt;/strong&gt; implemented at the end of scopes.&lt;/p&gt;

&lt;p&gt;As a scope ends (with a delimiter &lt;code&gt;}&lt;/code&gt;), the owners in that scope are dropped according to ownership rules:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The ownership rules are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Each value in Rust has an &lt;em&gt;owner&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;There can only be one owner at a time.&lt;/li&gt;
&lt;li&gt;When the owner goes out of scope, the value will be dropped.&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;

&lt;p&gt;So, don't worry about references. Rather, worry about scopes. They are the devils. They drop variables and clear values in heap. Think of scopes as a kind of box/ machine that takes in objects(references and moved variables) but doesn't give them out very easily. Rather, it is very choosy in what to give away. A very practical example for this kind of nature can be witnessed when following the usual software development cycle. When fitting the application logic into code, we often put a ton of functionalities in single functions just to make things work. Then we refactor. Then we create some tests, fail them, add some code and refactor again.&lt;/p&gt;

&lt;p&gt;As a general rule of programming, a single block (by block I mean a function, struct, enum etc) should not do more than one (or at max two) tasks.So, following this software development cycle with a rust project creates a lot of friction in the refactoring part. As said before, refactoring code ( particularly separating code into separate helper/secondary functions) in rust is the main( and the first) place where you tussle with the borrow checker. Why? Think of it, when refactoring code you are essentially bringing auxiliary tasks into separate reusable components. But in doing so you are putting the code in another scope (in a sense) inside your normal function. You can see the issue easily by placing the auxiliary code inside a scope and see a ton of &lt;em&gt;moved there, variable cant be used&lt;/em&gt; or &lt;em&gt;use of moved value&lt;/em&gt; kind of errors.&lt;/p&gt;

&lt;p&gt;Here is a example of code (with improper error handling) that takes in 2 strings containing equal number of &lt;code&gt;--&lt;/code&gt; separated integers and adds the corresponding values to produce another string.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;io&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;first_string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;String&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;second_string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;String&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;output&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;String&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="k"&gt;loop&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Enter the first string (Type END to suspend)"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nn"&gt;io&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;stdin&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.read_line&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;first_string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;first_string&lt;/span&gt;&lt;span class="nf"&gt;.trim&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"END"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Enter the second string (length should be same as string one)"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nn"&gt;io&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;stdin&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.read_line&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;second_string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;first_in_vals&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Vec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;u32&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;first_string&lt;/span&gt;
            &lt;span class="nf"&gt;.split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"--"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="nf"&gt;.map&lt;/span&gt;&lt;span class="p"&gt;(|&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="nf"&gt;.trim&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="py"&gt;.parse&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;u32&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
            &lt;span class="nf"&gt;.collect&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;second_in_vals&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Vec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;u32&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;second_string&lt;/span&gt;
            &lt;span class="nf"&gt;.split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"--"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="nf"&gt;.map&lt;/span&gt;&lt;span class="p"&gt;(|&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="nf"&gt;.trim&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.parse&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
            &lt;span class="nf"&gt;.collect&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;first_in_vals&lt;/span&gt;&lt;span class="nf"&gt;.iter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.enumerate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;output&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nd"&gt;format!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"{output}--{}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;second_in_vals&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;]));&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;first_in_vals&lt;/span&gt;&lt;span class="nf"&gt;.len&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;output&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;output&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"--"&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Result: {}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="nf"&gt;.chars&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.skip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="py"&gt;.collect&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

        &lt;span class="c1"&gt;// Since read_lines append the text input, it is important to clear the previous text.&lt;/span&gt;
        &lt;span class="n"&gt;first_string&lt;/span&gt;&lt;span class="nf"&gt;.clear&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;second_string&lt;/span&gt;&lt;span class="nf"&gt;.clear&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="nf"&gt;.clear&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(())&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's save it into &lt;code&gt;summation.rs&lt;/code&gt; and compile with (make sure rust and its compiler is installed, view &lt;a href="https://rust-lang.org/learn/get-started/" rel="noopener noreferrer"&gt;Official Guide&lt;/a&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;rustc summation.rs
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run the program's binary with some sample input and it will work fine with the given constraints on inputs. Now suppose we have a large codebase and we want to abstract all the printing functionality separately. Change line 31 with&lt;code&gt;print_out_result(output);&lt;/code&gt; and add the following function below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;print_out_result&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Result: {}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="nf"&gt;.chars&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.skip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="py"&gt;.collect&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Do the changes and compile...&lt;/p&gt;

&lt;p&gt;See! You get the &lt;code&gt;error[E0382]: use of moved value: 'output'&lt;/code&gt;. Thus, one may notice that even such a trivial change won't work as expected if you will not keep the borrow checker in mind. Of course, as suggested by the compiler, you can clone the string and move on but it is more work than putting code in separate functions and getting done with it.&lt;/p&gt;

&lt;p&gt;Now, think in terms of scopes and answer some fundamental questions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Where is the need to define the variables?

&lt;ul&gt;
&lt;li&gt;Many a times when writing a program some variables were getting declared from some other code /function and they can be created inside rather than being taken as an argument.&lt;/li&gt;
&lt;li&gt;As an example, in the above code snippet, you can remove &lt;code&gt;output.clear();&lt;/code&gt;by initialising output inside the loop, thus it gets renewed on each iteration.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Does your helper component needs to consume the value eternally?

&lt;ul&gt;
&lt;li&gt;This is a important question. Various times a value needs to be transformed (like converting a queryable diesel struct into another struct used across your application) rather than being used for creating something else. In such cases the value needs to be moved.&lt;/li&gt;
&lt;li&gt;If the value( of the variable) needs to be read and changed and also used later, the you don't want your &lt;code&gt;}&lt;/code&gt; delimiter to eat it, hence use the references.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Extra Info :&lt;/strong&gt; If we are taking and returning ands returning more than one reference, then we need to explicitly state the lifetime of the objects. It is an issue as explicit lifetimes tend to percolate to the parent derived data types.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;As in the above example, rather than cloning, you could change the signature of &lt;code&gt;print_out_result&lt;/code&gt; as &lt;code&gt;fn print_out_result(output: &amp;amp;mut str)&lt;/code&gt; and pass mutable reference of output in the function call. This prevents unnecessary hard cloning of strings.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When answering these questions, you will precisely know what to move and what to give reference to.&lt;/p&gt;

&lt;h2&gt;
  
  
  Designing function signatures
&lt;/h2&gt;

&lt;p&gt;Even before refactoring, the borrow checker and strict rust compiler introduce themselves as soon as you start getting out of your standard main function and start to build new functions. Function signatures are a whole game in itself in rust. Hey Bhaumik, then why this section is after the refactoring part?&lt;/p&gt;

&lt;p&gt;Function signatures do come first but in my experience they don't create much nuisance in small code bases. You really need to give them a thought when designing your project. The arguments that a function can take(i.e. its interface) in rust is not just data types like in other programming languages. It can take data types, references to data types, mutable references to data types, data types wrapped in Types like &lt;code&gt;Result&lt;/code&gt; and &lt;code&gt;Option&lt;/code&gt; and data types wrapped in smart pointers like &lt;code&gt;Rc&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This becomes a significant part then. I wouldn't go on to write more questions for you to answer for resolution. Ultimately you need to focus on what you can tolerate to be eaten by &lt;code&gt;}&lt;/code&gt; and what you can't and that decision goes up to the thinking of where you want to use those objects later, what are their objectives etc.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;For example at various places you need to remember that doing &lt;code&gt;.clone()&lt;/code&gt; might be a workaround for the compiler error but doing so can create a logical bug in software. Since, clone creates hard copies of objects, that means if your object is storing some state of your program, then creating copies will lose that data.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Ending this small section brings me to the last part that needs to be addressed before concluding the article. If you notice, most of the times the fight with borrow checker starts when you expand your ideas beyond a certain scope. Thus designing of function signature ultimately relates to how you are design your program for real world applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  Software Design
&lt;/h2&gt;

&lt;p&gt;Though completely out of scope from the motive of this article, I found it compulsive to add a note on importance of how you think the processes of your program. For example, I created a TUI application for the purpose of practising rust. Then I converted it to multi threaded for taking keyboard input events from a separate thread.&lt;/p&gt;

&lt;p&gt;Converting the app from a single to multi-thread design required some significant alteration which led to breaking of software thrice! I couldn't get my head around using &lt;code&gt;Arc&lt;/code&gt; and &lt;code&gt;Mutex&lt;/code&gt; properly. Though I manged to achieve the task by using &lt;code&gt;mpsc&lt;/code&gt;(Multiple Producer Single Consumer) channels, I was stuck at this issue for a week or so because of 2 issues:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;I didn't thoroughly thought about how I want to achieve the muti-threaded nature.&lt;/li&gt;
&lt;li&gt;Borrow checker made it a lengthy task to quickly change code across files to try a new approach.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;All I want to say is that some clarity about what your trying to achieve and how you are trying to achieve is important. It may be good to take help from diagrams or arrows to draw out the basic control flow with pen and paper.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;This brings us to end. I hope by this time you would have got a descent idea on how to up skill your rust programming. The article talked about an approach to think about rust's ownership rules while trying to build something great. It went through how other methods fell short, how you can think in terms of &lt;code&gt;}&lt;/code&gt; / end of scope, how these methods apply in code refactoring and function creation and in the end how a better software design always give an upper hand. The article doesn't follow today's trend of keeping things crisp and too much on the point that it might leave some essential background. This is fine with me. I am not a seasoned programmer, I am an enthusiast at learning new things and open for any suggestions for improvement. Suggestions and typo fixes can be send to &lt;code&gt;ramayen&lt;/code&gt;in discord. Keep experimenting and Happy Coding !&lt;/p&gt;

</description>
      <category>theoreticalwriteups</category>
      <category>rust</category>
      <category>architecture</category>
    </item>
  </channel>
</rss>
