Tag Archives: Rust

Gluon Lang Show

Gluon is a small, statically-typed, functional programming language designed for application embedding into Rust code.

Gluon lang is a native Rust implementation and does not require any FFI interfacing to foreign C libraries, such as for guile.

Gluon lang provides a feature called “implicit arguments” that can be used to realize parametric polymorphism.

Just Gluon lang is a a bit picky regarding recursion and implicit arguments, for example using the Functor Show from module std.show.
The following document is helpful to understand the feature http://marwes.github.io/2018/06/19/gluon-0.8.html

The following is a short example demonstrating its usage.

Let’s have two file,

  • the module maybe.glu exporting both symbols Maybe and show
  • and the application app.glu
// file: maybe.glu

let show @ { ? } = import! std.show
let { (<>) } = import! std.semigroup

// A `Maybe` represents a parameterized type for an optional value
type Maybe a =
  | Just a
  | Nothing

// Stringifying the `Maybe` value
let show ?d : [Show a] -> Show (Maybe a) =
    let show o =
        match o with
        | Just x -> "Just (" <> d.show x <> ")"
        | Nothing -> "Nothing"
    { show }

in
{  Maybe, show }

Now, the application app.glu imports both symbols, using the following expression

let maybe @ { Maybe , ? } = import! maybe

Here, the placeholder ? is important to import in the function shows as scoped symbol maybe.show to avoid ambiguity with symbol show.show.

// file: app.glu
let prelude = import! std.prelude
let  { Show, show } = import! std.show
let io @ { ? } = import! std.io
let string @ { ? } = import! std.string

let maybe @ { Maybe , ? } = import! maybe

let val : maybe.Maybe String = Just "foo"
in
io.println (show val)

Execution in console will be as follows

$ gluon app.glu 
Just ("foo")

Rust Memory Layout Optimization (Enum)

Usage of enum-types is inherent in Rust, usually causing additional overhead due to the enum-discriminator. But, there are a number of optimizations that may eliminate this memory overhead. The following is just a cheatsheet. For further reading see https://rust-lang.github.io/unsafe-code-guidelines/layout/enums.html

Data-Less and Uninhabited fields

Introduced by MR https://github.com/rust-lang/rust/pull/45225

Size optimizations implemented so far:

  • ignoring uninhabited variants (i.e. containing uninhabited fields), e.g.:
    • Option<!> is 0 bytes
    • Result<T, !> has the same size as T
  • using arbitrary niches, not just 0, to represent a data-less variant, e.g.:
    • Option<bool>, Option<Option<bool>>, Option<Ordering> are all 1 byte
    • Option<char> is 4 bytes
  • using a range of niches to represent multiple data-less variants, e.g.:
    • enum E { A(bool), B, C, D } is 1 byte

An integer that is known not to equal zero.

See https://doc.rust-lang.org/std/num/struct.NonZeroUsize.html

This enables some memory layout optimization. For example, Option<NonZeroUsize> is the same size as usize:

use std::mem::size_of;
assert_eq!(size_of::<Option<core::num::NonZeroUsize>>(), size_of::<usize>());

And analogous to it all other NonZero types https://doc.rust-lang.org/std/num/index.html

Please note, using an optimized Option<NonZeroX>, its enum-discriminator will be one of the ‘unused’ bit-combinations in the underlying integer representation, for example the bit combination all zero representing state Option::None.

Rust Function implementing Generator

The following example demonstrates how to implement a Rust-function implementing a generator (unstable feature in nightly compiler)

#![feature(generators, generator_trait)]
use std::ops::{Generator, GeneratorState};
use std::pin::Pin;

fn generator() -> impl Generator<
Yield=(),
Return=()>
{
   let generator = || {
      println!("2");
      yield;
      println!("4");
    };
   generator
}

#[derive(Debug, Clone)]
enum MyError {
   Fault
}

fn generator2() -> impl Generator<
   Yield=Result<u32, MyError>,
   Return=&'static str>
{
   let generator = || {
      yield Ok(1);
      yield Err(MyError::Fault);
      return "foo";
   };
   generator
}

fn main() {
   let mut generator = generator();

   println!("1");
   Pin::new(&mut generator).resume(());
   println!("3");
   Pin::new(&mut generator).resume(());
   println!("5");

   println!("-------");

   let mut generator2 = generator2();

   match Pin::new(&mut generator2).resume(()) {
      GeneratorState::Yielded(val) => { println!("{:?}", val); }
      _ => panic!("unexpected value from resume"),
   }

   match Pin::new(&mut generator2).resume(()) {
      GeneratorState::Yielded(val) => { println!  ("{:?}", val); }
      _ => panic!("unexpected value from resume"),
   }

   match Pin::new(&mut generator2).resume(()) {
      GeneratorState::Complete(val) => { println!("{}", val); }
      _ => panic!("unexpected value from resume"),
   }
}

The Computer Language Benachmarks Game: Rust ranks #1 for n-body

The Computer Language Benchmarks Game is a free software project for comparing how a given subset of simple algorithms can be implemented in various popular programming languages.

I converted the fastest (dating early 2019) n-body C-implementation (#4) to Rust (#7) in a one-to-one fashion, gaining a performance encreasement by factor 1.6 to my own surprise.

The moment writing, the benachmarks are measured on quad-core 2.4Ghz Intel® Q6600® ; dating back to the year 2006. This ancient hardware supports the SSSE3 64bit-SIMD instructions; both implementations are making use them intensively.

The conversion of the implementation from C to Rust was fun and educational; listing just a few:

  • The pattern of “static global memory” of C had to be transformed to similar code just based on he Rust ownership model.
  • Dealing with memory alignment-directives in Rust
  • Using the early, stable SIMD-API of Rust, namely std::arch::x86_64::*

I must admit that newer test-hardware with support for more advanced AVX-512 SIMD-instructions, would permit to run an even faster Rust-implementation of the n-body task as part of these benchmarks.

Rust crates – frehberg’s annotated catalogue

The base of Rust users and contributors is growing steadily. The amount of libraries (aka crates) at http://crates.io is growing quickly; the overall “noise” is increasing. Some libraries might not be maintained any longer 🙁

This annotated catalogue shall help the Rust-users to find specific, popular, mature Rust crates. This list is WIP (Work In Progress), reflecting my personal shortlist. The ordering in the table top-down doesn’t express any preference.

For more extensive listings, please check out content of https://crates.io (or the categorized search engine https://lib.rs) and corresponding API-docs at https://docs.rs

Other sources of information might be:

NameDescription
nomnom is a parser combinators library written in Rust. Its goal is to provide tools to build safe parsers without compromising the speed or memory consumption.
pestpest is a general purpose parser written in Rust with a focus on accessibility, correctness, and performance. It uses parsing expression grammars (or PEG) as input.
assert_matchesProvides a macro, assert_matches, which tests whether a value matches a given pattern, causing a panic if the match fails.
bytesA utility library for working with bytes.
serdeSerde is a framework for serializing and deserializing Rust data structures efficiently and generically.
serde_jsonSerde JSON serializing and deserializing implementation for Rust.
tokioTokio is an event-driven, non-blocking I/O platform for writing asynchronous applications with the Rust programming language.
romioAsynchronous network primitives in Rust. Romio combines the powerful futures abstractions with the nonblocking IO primitives of mio to provide efficient and ergonomic asynchronous IO primitives for the Rust asynchronous networking ecosystem. Whereas Tokio is using stable Rust-features only, Romio may use so called "unstable" Rust-features from nightly releases.
uomUnits of measurement is a crate that does automatic type-safe zero-cost dimensional analysis.
mockiatoA strict, yet friendly mocking library for Rust
proptestProptest is a property testing framework (i.e., the QuickCheck family) inspired by the Hypothesis framework for Python. It allows to test that certain properties of your code hold for arbitrary inputs, and if a failure is found, automatically finds the minimal test case to reproduce the problem.
test-case-deriveThis crate provides #[test_case] procedural macro attribute that generates multiple parametrized tests using one body with different input parameters.
env_loggerImplements a logger that can be configured via environment variables. env_logger makes sense when used in executables (binary projects). Libraries should use the log crate instead.
gtkRust bindings and wrappers for GLib, GDK 3, GTK+ 3 and Cairo; the popular, platform independent GUI library.
rust-qtDo not use! In contrast to the gtk crate, this GUI library is incomplete and it seems it is no longer maintained.
flutter-engineExperimental! Flutter is Google’s portable UI toolkit for building beautiful, natively-compiled applications for mobile, web, and desktop from a single codebase.
gfxgfx is a high-performance, bindless graphics API for the Rust programming language. It aims to be the default API for Rust graphics: for one-off applications, or higher level libraries or engines.
lazy_staticA macro for declaring lazily evaluated statics in Rust. Using this macro, it is possible to have statics that require code to be executed at runtime in order to be initialized.
regexA Rust library for parsing, compiling, and executing regular expressions. Its syntax is similar to Perl-style regular expressions, but lacks a few features like look around and backreferences. In exchange, all searches execute in linear time with respect to the size of the regular expression and search text. Much of the syntax and implementation is inspired by RE2.
memmapA cross-platform Rust API for memory mapped buffers. May be used to speed-up file-IO.
randA Rust library for random number generation. Rand provides utilities to generate random numbers, to convert them to useful types and distributions, and some randomness-related algorithms.
bastionBastion is a Fault-tolerant Runtime for Rust applications, a supervisor framework as known from Erlang.
test-generatorTest-Generator provides the macros test_resources and bench_resources, executing a test for all items matching a specific glob-pattern, such as "res/tests/*.idl"
test-generator-utestTest-Generator-Utest providing 3-phase testing macro "utest!(setup, test, teardown)"

Rust – Arrays? Make chains, not concat!

If your application needs to iterate over a bunch of items from different sources or arrays, someone with C/C++ background might copy all items into a single vector and iterate this vector.

This strategy will cause high costs in terms of allocating heap memory for the consecutive vector buffer.

Instead, keep the data where it is, and chain it together to form an iterator over a virtual array.

The following Rust code demonstrates the chaining of multiple arrays, forming a single iterator, without any additional allocation of vector buffer in heap.

Note, the zip operation in the following code snippet pairs each item with a slot in the buffer. The zip will stop if either end is reached, the end of chained_byte_sequence or the end of therequest buffer, whichever comes first. Just, the length of chained_byte_sequence might be unknown and only a single pass shall be performed. So, how do we know all items have been written, and the amount? The solution is to borrow the iterator via chained_byte_sequence.by_ref(), iterating the chain and finally verifying if any item remained in the sequence chained_byte_sequence.next()!=None.

  let req_method_get = b"GET ";
    let req_method_head = b"HEAD ";
    let uri = b"/infotext.html HTTP/1.1";

    let mut request = [0 as u8; 128];

    // chaining various byte-arrays together, for example two here:
    let mut chained_byte_sequence =  req_method_get.iter()
        .chain(uri.iter());

    // take a ref and zip against the destination buffer and 
    // while iterating via fold, each element is counted.
    let  nwritten =
        chained_byte_sequence
        .by_ref()
        .zip(request.as_mut())
            .fold(0, |cnt, (item, slot) | {
                *slot = item.clone(); cnt+1
            });

    // finally, verify the iterator of the chained_byte_sequence is empty
    if chained_byte_sequence.next()!=None {
        /* slice too short */ panic!();
    } else {
        println!("{:?}", &request[0..nwritten].as_ref());
    };