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
Test-generator v0.3
A new version of test-generator (0.3) has been published. This crate introduces #[test_resources(PATTERN]
and #[bench_resources(PATTERN)]
procedural macro attributes that generates multiple parametrized tests using one body with different resource input parameters. A test is generated for each resource matching the specific resource location pattern.
Rust derive(Default) for enum-types
Rust derive(Default) can be used for structs, implemting the default-instanciation. Sadly it can’t be used for enum-types, as there is no strategy to pick one of the enum-variants as default. The following discussion at Rust Internals hopefully will trigger an RFC to close this feature-gap.
https://internals.rust-lang.org/t/request-derive-enums-default/10576
Go To Statement Considered Harmful (discussed)
Talking with other developers about control-flow patterns, after a while someone will cite Edgar Dijkstra’s paper
“Go To Statement Considered Harmful” Communications of the ACM 11, 3 (March 1968), pages 147-148
Usually those developers argue, that go to statements should be abolished completely.
Just, it is important to note, that this paper is about loop-control-structures, comparing the expressiveness of recursive function calls, while/repeat-statements and goto-statements with each other (preferred pattern mentioned first).
And Dijkstra does not oppose the usage of go to statements in general, but mentioning a use case for go to statements:
“The remark about the undesirability of the go to statement is far from new. I remember having read the explicit recommendation to restrict the use of the go to statement to alarm exits, but I have not been able to trace it; presumably, it has been made by C.A.R. Hoare.”
My interpretation of this statement is, that go to statements can be tolerated for so called “alarm exits” as being used widely in C-code of OS-Kernels and embedded systems.
An “alarm exit” may look like this, realizing a single exit point for the success case and a single one for the error case, instead of spreading multiple exit-points all over the function.
/** foo reading a file and returns with SUCCESS, otherwise with ERROR
*/
int foo(const char* filename) {
int fd = INVALID_FD;
if (filename==INVALID_STRING) {
goto alarm_exit;
}
fd = open_file(filename);
if (fd == INVALID_FD) {
goto alarm_exit;
}
/* do something, release resource and exit with success */
close_file(fd);
return SUCCESS_CASE;
alarm_exit:
/* release resources if allocated */
if (fd!=INVALID_FD) close_file(fd);
return ERROR_CASE;
}
So, next time having a discussion with fundamental developers, abolishing all occurances of go to statements (even for the “alarm exits” use case), I will be happy to cite Dijkstra and Hoare 😉
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.