Category 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

Data containers without data payload or containers over types of “zero byte size” the following optimizations exist.

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.

Wrappers as Option<T> or Result<T> over “NonZero” data types may be optimized by the compiler.

For example Option<usize> may occupy up to 16 bytes, using 8 additional bytes for the discriminator to represent a flag such as 0x00 and 0x01. In contrast using the NonZeroUsize as in Option<NonZeroUsize> the memory consumption may shrink to 8 bytes in total. using the unused bit of NonZeroUsize to represent the discriminator of the generic data type Option<T>

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"),
   }
}

ChaosCamp 2019

Attending the Chaos Camp 2019 as speaker was quite an experience. I did a talk about Secure Architecture of IoT Devices https://fahrplan.events.ccc.de/camp/2019/Fahrplan/events/10268.html

UTest Harness for Rust (Setup/Test/Release)

Edit Titel should have been “setup/test/teardown”

The crate test-generator-utest implements a 3-phase utest-harness for Rust. These 3 phases are:

Setup: the setup function must initialize the context; in case the setup-function panics/aborts, the utest is aborted
fn() -> Context

Test: if the setup did return with valud context item, the context-reference is borowed to invoke the test-function
fn( & Context )

Teardown: no matter if the test-function above did panic/abort, the teardown function is invoked to release the context
fn( Context )

No matter of any panic or failing assertion in the second phase (feature testing), the teardown function is invoked. The test will either succeed, or otherwise unwinding a failure in the setup-phase, the test-phase or the teardown-phase.

This crate has been inspired by the post of Eric Opines.

## Usage

Please see the executable example mytests

#[cfg(test)]
extern crate test_generator_utest;

// demonstrating usage of utest-harness
mod testsuite {
    use std::fs::File;
    use std::io::prelude::*;

    use test_generator_utest::utest;

    // Defining a context structure, storing the resources
    struct Context<'t> { file: File, name: &'t str }

    // Setup - Initializing the resources
    fn setup<'t>(filename: &str) -> Context {
        // unwrap may panic
        Context { file: File::create(filename).unwrap(), name: filename }
    }

    // Teardown - Releasing the resources
    fn teardown(context: Context) {
        let Context { file, name } = context;

        // drop file resources
        std::mem::drop(file);

        // unwrap may panic
        std::fs::remove_file(name).unwrap();
    }

    // Test - verify feature
    fn test_write_hello_world(ctx: &Context) {
        // may panic
        let mut file = ctx.file.try_clone().unwrap();

        // may panic
        file.write_all(b"Hello, world!\n").unwrap();

        // demonstrating assertion
        assert_eq!(1,1);

        std::mem::drop(file);
    }

    // Test - verify feature
    fn test_write_hello_europe(ctx: &Context) {
        // may panic
        let mut file = ctx.file.try_clone().unwrap();

        // may panic
        file.write_all(b"Hello, Europe!\n").unwrap();

        // demonstrating assertion
        assert_eq!(1,1);

        std::mem::drop(file);
    }

    // Defining Utest formed by setup, test and teardown
    utest!(hello_world,
        || setup("/tmp/hello_world.txt"),
        |ctx_ref| test_write_hello_world(ctx_ref),
        |ctx|teardown(ctx));


    // Defining Utest formed by setup, test and teardown
    utest!(hello_europe,
        || setup("/tmp/hello_europe.txt"),
        test_write_hello_europe,
        teardown);
}

Executing the example code cargo test -p test-generator-example testsuite the testsuote above will print the following output.

running 2 tests
test testsuite::hello_europe ... ok
test testsuite::hello_world ... ok

test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 3 filtered out

Please let me know about possibel improvements via github-issues at test-generator-utest