Skip to content
Peter Bertok edited this page Oct 13, 2015 · 5 revisions

Overview

This is where I am collecting a list of issues, notes, and critiques of the Rust language in the course of translating the Google Brotli decoder from C.

Implicit Integer Casts

Rust has a habit of complaining about incompatible types, even in cases where an automatic cast should be available. For example, adding a smaller integer to a larger one is an error, unlike in most other languages:

 expected `u16`,
    found `u32`
(expected u16,
    found u32) [E0308]
src\decoder.rs:31             offs += table[offs].value + ((bits >> HUFFMAN_TABLE_BITS) & !((0xffffffff) << nbits ));
                              ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src\decoder.rs:31:41: 31:99 help: run `rustc --explain E0308` to see a detailed explanation
src\decoder.rs:31:21: 31:99 error: mismatched types:

'Memcopy' Unstable or Unsafe

While Rust makes many difficult things trivial, such as thread safety, trivial things are often inordinately difficult. There is no elegant, simple way to invoke the memcpy intrinsic on a pair of slices containing data with the 'Copy' trait. This should be a built-in language element, but the only safe, stable API I've found is to use the std::io library, as follows:

dst.write( src ).unwrap();

Eww....

Indexed and IndexedMut only accept usize

Opened a Rust issue: https://github.com/rust-lang/rust/issues/29010

Missing Intrinsics

Google has put some effort into optimising Brotli for mobile devices. For example, there are short functions and macros defined in a number of places that expose compiler optimisations or native instructions. Such macros fall through to plain C code on platforms that are missing native support. Rust has some of these instructions or compiler hints exposed in the standard library, but key ones are missing.

For example, the original Google code uses these macros to give the compiler optimisation hints. Note the "LLVM" filter! Rust uses LLVM as a back-end as well, so the back-end support is certainly available!

#if (__GNUC__ > 2) || (__GNUC__ == 2 && __GNUC_MINOR__ > 95) || \
    (defined(__llvm__) && __has_builtin(__builtin_expect))
#define PREDICT_TRUE(x) (__builtin_expect(!!(x), 1))
#define PREDICT_FALSE(x) (__builtin_expect(x, 0))
#else
#define PREDICT_FALSE(x) (x)
#define PREDICT_TRUE(x) (x)
#endif

An interesting case is this macro, which checks if a value is known at compile time. This allows some fairly complex optimisations to be made, allowing the rather primitive C language to emulate some of the more advanced features typically only found in languages like C++:

/* IS_CONSTANT macros returns true for compile-time constant expressions. */
#if (__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ > 0) || \
    (defined(__llvm__) && __has_builtin(__builtin_constant_p))
#define IS_CONSTANT(x) __builtin_constant_p(x)
#else
#define IS_CONSTANT(x) 0
#endif

The biggest gap is the bit/byte manipulation instructions. Some are present, but the ARM rbit instruction, for example, is missing.

Fixed-sized arrays can't derive the 'Default' trait

This should compile, but doesn't:

#[derive(Default)]
struct Foo {
    bar: [i32;4]
}