Asynchronous Programming with Tokio

If you are interested in learning about asynchronous programming in more depth, I recommend reading Asynchronous Programming in Rust.

Asynchronous programming

When we run code that makes network requests, these request are sent through the network.

Sending the request and waiting for the response is done by the network peripheral and doesn’t require the CPU. This means, the CPU is free to do other things while it waits.

Code written synchronously will send a request and then block the thread waiting for a response. For example:

1
2
3
4
fn main() {
    let resp = reqwest::blocking::get("https://httpbin.org/ip")?.text()?;
    println!("{:#?}", resp);
}
Read More

Programming Concurrency in Rust

One of Rust’s most praised features is how it makes concurrent programming safe. In this article we are going to learn some ways to do concurrent programming and explain how Rust makes them safe compared to other programming languages.

Working with threads

We can start new threads with thread::spawn:

1
2
3
4
5
6
7
8
9
10
use std::thread;
use std::time::Duration;

fn main() {
    thread::spawn(|| {
        println!("The spawned thread");
    });

    thread::sleep(Duration::from_millis(1));
}

This will print:

1
The spawned thread
Read More

Smart Pointers in Rust

Rust is considered safe because it makes sure variable ownership is managed correctly in our code. In the most basic case, Rust enforces these rules:

  • Each value in Rust has an owner.
  • There can only be one owner at a time.
  • When the owner goes out of scope, the value will be dropped.

The problem is that there are some scenarios where we need to break these rules. This is where smart pointers help us.

What are smart pointers?

Smart pointers are structs that manage some internal data.

They are called pointers because they implement the Deref trait, so they can be used like pointers (Using the & and * syntax).

Read More

Rust References Lifetimes

Rust has a mechanism called borrow checker that makes sure references are not used when they are not valid anymore. The borrow checker uses lifetimes to do its job internally.

Let’s look at a simple example where the borrow checker detects a possibly invalid reference:

1
2
3
4
5
6
7
8
9
10
fn main() {
    let r;

    {
        let i = 1;
        r = &i;
    }

    println!("{}", r);
}

If we compile this, we’ll get the following error:

Read More

Traits, Rust's Interfaces

As the title says, traits are Rust’s alternative to Interfaces. They allow us to use polymorphism in Rust. We can create a trait like this:

1
2
3
trait Calculator {
    fn add(&self, left: i32, right: i32) -> i32;
}

To implement the trait we use the impl keyword on a struct:

1
2
3
4
5
6
7
struct GoodCalculator {}

impl Calculator for GoodCalculator {
    fn add(&self, left: i32, right: i32) -> i32 {
        left + right
    }
}
Read More

Testing in Rust

In this article, we are going to learn how to write and run tests for Rust.

Unit tests

Rust made the interesting decision that unit tests should be written in the same files as the code under test. Let’s imagine we have a module with a function named add:

1
2
3
pub fn add(left: i64, right: i64) -> i64 {
    left + right
}

If we want to test that function, we would modify the file to look like this:

Read More

Introduction to Rust

Rust is a relatively new programming language that promises to be as fast as C, but less complex and error prone.

Rust compiles directly to machine code, so it doesn’t require a virtual machine. This makes it faster than languages like Java or Python. It also doesn’t use a garbage collector, which makes it faster and more predictive than other compiled languages like Golang.

On top of speed and predictability, Rust also promises a programming model that ensures memory and thread safety, which makes it great for complex applications.

Installation

The recommended way to install rust in Linux and Mac is using this command:

1
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

We will be greeted by this prompt asking to choose an option:

1
2
3
1) Proceed with installation (default)
2) Customize installation
3) Cancel installation
Read More

Sending HTTP requests with Arduino

To make HTTP and HTTPS requests from an Arduino board, we need to first install the ArduinoHttpClient library:

1
arduino-cli lib install ArduinoHttpClient

Once we have the library, we can use it to make requests:

Read More

Using Arduino Language Server With Neovim

In this post we’re going to configure neovim to work with Arduino Language Server.

Nvim Lsp Config

Neovim comes with an LSP client included, nvim-lspconfig is a plugin that helps us configure the client so it can talk to LSP servers.

This configuration should be enough to get started with Arduino:

1
2
3
4
5
6
return {
  "neovim/nvim-lspconfig",
  config = function()
    require('lspconfig').arduino_language_server.setup {}
  end
}
Read More

Using Arduino Serial Monitor From Linux

Arduino Serial Monitor is a tool that can be used for debugging or interacting with our Arduino board. More specifically, it allows us to read and write data to a serial port.

For our sketch to be able to use the serial monitor, we need to use Serial.begin and specify a baud rate. For example:

1
Serial.begin(9600);

The valid baud rates vary depending on the board we are using. 9600 is a safe value that works on most boards.

Reading

The first thing we want to do is print to the serial port. For example:

1
Serial.println("Hello");
Read More