Reader small image

You're reading from  Network Programming with Rust

Product typeBook
Published inFeb 2018
Reading LevelIntermediate
PublisherPackt
ISBN-139781788624893
Edition1st Edition
Languages
Concepts
Right arrow
Author (1)
Abhishek Chanda
Abhishek Chanda
author image
Abhishek Chanda

Abhishek Chanda studied computer science at IIEST Shibpur in India and electrical engineering at Rutgers University. He has been working on networking and distributed systems since 2008. Over his career, he has worked with large companies (like Microsoft and Dell) and small startups (Cloudscaling, DataSine) in India, US, and the UK. He is enthusiastic about open source software and has contributed to a number of projects like OpenStack, Nomad etc. He contributes to a number of open source projects. He came across Rust in 2015 and found it to be a perfect fit for writing highly performant systems.
Read more about Abhishek Chanda

Right arrow

Introduction to Rust and its Ecosystem

The Rust programming language is sponsored by Mozilla and supported by a community of developers from across the globe. Rust is promoted as a systems programming language that supports automatic memory management without the overhead of a runtime or a garbage collector, concurrency without data races enforced by the compiler, and zero cost abstractions and generics. In subsequent sections, we will discuss these features in more detail. Rust is statically typed and borrows a number of functional programming ideas. A fascinating aspect of Rust is the use of the type system to guarantee memory safety without using a runtime. This makes Rust uniquely suitable for low-resource embedded devices and real-time systems, which require strong guarantees around code correctness. On the flip side, this often means that the compiler has to do a lot more...

The Rust ecosystem

The success or failure of an open source project is often determined by the strength of the community around it. Having a coherent ecosystem helps in building a strong community. Since Rust is primarily driven by Mozilla, they have been able to build a strong ecosystem around it, the primary components being:

  • Source code: Rust hosts all the source code in GitHub. Developers are encouraged to report bugs and submit pull requests in there. At the time of writing, the Rust repository on GitHub has 1,868 unique contributors, over 2,700 open bug reports, and 90 open pull requests. The core Rust team is composed of Mozilla employees and contributors from other organizations (like Google, Baidu, and so on). The team uses GitHub for all collaborations; even major changes to any component have to be first proposed by writing a Request For Comments (RFC). This way, everyone...

Getting started with Rust

The Rust toolchain installer is available at: https://www.rustup.rs/. The following commands will install all three versions of the toolchain on a system. For the examples in this book, we will use a Linux machine running Ubuntu 16.04. While most of Rust should not depend on the OS, there can be minor differences.

We will point out any strict dependencies on the OS:

# curl https://sh.rustup.rs -sSf | sh
# source $HOME/.cargo/env
# rustup install nightly beta

We will need to put Cargo's bin directory to our PATH by editing .bashrc. Run the following to do that:

$ echo "export PATH=$HOME/.cargo/bin:$PATH" >> ~/.bashrc

A Rust installation comes with a lot of documentation built in; they can be accessed by running the following command. This should open up the documentation in a browser window:

# rustup doc

The next step is to set up a...

Introduction to the borrow checker

The most important aspect of Rust is the ownership and borrowing model. Based on the strict enforcing of borrowing rules, the compiler can guarantee memory safety without an external garbage collector. This is done by the borrow checker, a subsystem of the compiler. By definition, every resource created has a lifetime and an owner associated with it, which operates under the following rules:

  • Each resource has exactly one owner at any point in time. By default, the owner is the variable that created that resource, and its lifetime is the lifetime of the enclosing scope. Others can borrow or copy the resource if they need to. Note that a resource can be anything from a variable or a function. A function takes ownership of a resource from its caller; returning from the function transfers back ownership.
  • When the owner's scope has finished...

Generics and the trait system

Rust supports writing generic code that is later bound with more concrete types, either during compile time or during runtime. People who are familiar with templates in C++ might notice that generics in Rust are pretty similar to templates, as far as syntax goes. The following example illustrates how to use generic programming. We also introduce some new constructs which we haven't discussed before, which we will explain as we proceed.

Much like C and C++, a Rust struct defines a user-defined type that aggregates multiple logically connected resources in one unit. Our struct here defines a tuple of two variables. We define a generic struct and we use a generic type parameter, written here as <T>. Each member of the struct is defined to be of that type. We later define a generic function that sums the two elements of the tuple. Let&apos...

Error handling

One of Rust's major goals is enabling the developer to write robust software. An essential component of this is advanced error handling. In this section, we will take a deeper look at how Rust does error handling. But before that, let's take a detour and look at some type theory. Specifically, we are interested in algebraic data types (ADT), types formed by combining other types. The two most common ADTs are sum and product types. A struct in Rust is an example of a product type. This name derives from the fact that given a struct, the range of its type is essentially the Cartesian product of the ranges of each of its components, since an instance of the type has values for all of its constituent types. In contrast, a sum type is when the ADT can assume the type of only one of its constituents. An example of this is an enum in Rust. While similar to enums...

The macro system

Rust supports a macro system that has evolved quite a lot over the years. A distinctive feature of Rust macros are that they are guaranteed to not refer to identifiers outside their scope by accident, and so the macro implementation in Rust is hygienic. As one would expect, Rust macros are expanded to source code ahead of the compilation in place, and are compiled with the translation unit. The compiler enforces scoping rules on expanded macros to make them hygienic. Rust macros differ from other constructs in that they always end in an exclamation mark !.

Modern Rust has two ways of working with macros; the older, syntactic macro way, and the newer, procedural macro way. Let's look at each of these:

Syntactic macros

...

Functional features in Rust

Rust has been inspired by functional languages such as Haskell and OCaml. Unsurprisingly, Rust has rich support for functional programming both in the language and in the standard library. In this section, we will look at some of these.

Higher-order functions

We have seen previously how Rust functions define an isolated scope in which all local variables live. Thus, variables outside the scope can never leak into it unless they are explicitly passed as arguments. There can be cases where this is not the desired behavior; closures provide an anonymous function like mechanism, which has access to all the resources defined in the scope in which it is defined. This enables the compiler to enforce the...

Concurrency primitives

One of the promises of Rust is to enable fearless concurrency. Quite naturally, Rust has support for writing concurrent code through a number of mechanisms. In this chapter, we will discuss a few of these. We have seen how the Rust compiler uses borrow checking to ensure correctness of programs at compile time. It turns out that those primitives are also useful in verifying correctness of concurrent code. Now, there are multiple ways of implementing threading in a language. The simplest possible way is to create a new OS thread for each thread created in the platform. This is often called 1:1 threading. On the other hand, a number of application threads can be mapped to one OS thread. This is called N:1 threading. While this approach is resource-light since we end up with fewer actual threads, there is a higher overhead of context switches. A middle ground...

Testing

Rust treats testing as a first-class construct; all tools in the ecosystem supports testing. The compiler provides a built-in configuration attribute that designates a module for testing. There is also a test attribute that designates functions as tests. When Cargo generates a project from scratch, it sets up this boilerplate. Let's look at an example project; we will call it factorial. It will export a macro that computes the factorial given an integer. Since we have conveniently written such a macro before, we will just re-use that code here. Note that since this crate will be used as a library, this does not have a main function:

# cargo new factorial --lib
# cargo test
Compiling factorial v0.1.0 (file:///Users/Abhishek/Desktop/rust-book/src/ch2/factorial)
Finished dev [unoptimized + debuginfo] target(s) in 1.6 secs
Running target/debug/deps/factorial-364286f171614349...

Summary

This chapter was a very short introduction to the Rust language and the ecosystem. Given this background in Rust, let's look at a frequently asked question: should a company adopt Rust? Like a lot of things in engineering, the correct answer is that it depends on a lot of factors. One of the primary reasons for adopting Rust would be the ability to write robust code with less of a footprint as possible. Thus, Rust is suitable for projects targeting embedded devices. This area has traditionally used assembly, C, and C++. Rust can provide the same performance guarantees while ensuring code correctness. Rust also works well for offloading performance intensive computation from Python or Ruby. The primary pain point with Rust is that the learning curve can be steep. Thus, a team trying to adopt Rust might spend a lot of time fighting with the compiler, trying to run code...

lock icon
The rest of the chapter is locked
You have been reading a chapter from
Network Programming with Rust
Published in: Feb 2018Publisher: PacktISBN-13: 9781788624893
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
undefined
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $15.99/month. Cancel anytime

Author (1)

author image
Abhishek Chanda

Abhishek Chanda studied computer science at IIEST Shibpur in India and electrical engineering at Rutgers University. He has been working on networking and distributed systems since 2008. Over his career, he has worked with large companies (like Microsoft and Dell) and small startups (Cloudscaling, DataSine) in India, US, and the UK. He is enthusiastic about open source software and has contributed to a number of projects like OpenStack, Nomad etc. He contributes to a number of open source projects. He came across Rust in 2015 and found it to be a perfect fit for writing highly performant systems.
Read more about Abhishek Chanda