newspaint

Documenting Problems That Were Difficult To Find The Answer To

Category Archives: Rust

Rust/Cargo Outputting Dollar Angle Bracket Symbols

So you’re compiling source using Cargo/Rust and you see output similar to the following:

error[E0046]$<2>: not all trait items implemented, missing: `decode`, `encode`$<2>
  $<2>--> $<2>src/main.rs:7:1$<2>
   $<2>|$<2>
7$<2>  $<2>| $<2>impl tokio_core::io::Codec for LineCodec {$<2>
   $<2>| $<2>^$<2> missing `decode`, `encode` in implementation$<2>

error$: aborting due to previous error$

This is full of dollar, angle bracket, number, angle bracket characters.

The fix is to change your terminal, e.g.:

TERM=xterm

On doing this I had the output in full colour without the mysterious symbols.

Implementing Custom Sort For BTree In Rust

So you want to use a std::collections::btree_map::BTreeMap but you want your keys sorted in a different way to the default for the type.

In this example I show how you can provide a BTreeMap that has String keys but sorted in reverse order. But, by altering the cmp() function for the std::cmp::Ord trait for a custom type, you can make the sort in any order you desire.

It is a bit of a pain, however. As this post points out you have to define partial_cmp() and partial_eq() functions from other traits as well, as well as adding the Eq trait to your struct.

// http://rustbyexample.com/custom_types/structs.html
struct RString {
    s: String,
}

use std::cmp::Ord;
use std::cmp::Ordering;

impl PartialEq for RString {
    fn eq(&self, other:&Self) -> bool {
        if self.s == other.s {
            true
        } else {
            false
        }
    }
}

// this does not actually have any methods, it's just a flag on the type
impl Eq for RString { }

// make partial_cmp() just return result from cmp()
impl PartialOrd for RString {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        let me: &String = &(self.s);
        let them: &String = &(other.s);

        Some( me.cmp( them ) )
    }
}

impl Ord for RString {
    fn cmp(&self, other:&Self) -> Ordering {
        let me: &String = &(self.s);
        let them: &String = &(other.s);

        if me > them {
            Ordering::Less
        } else if me < them {
            Ordering::Greater
        } else {
            Ordering::Equal
        }
    }
}

use std::env;
use std::collections::btree_map::BTreeMap;
fn main() {
    // collect environment variable keys into a vector we can sort
    let mut sortedmap : BTreeMap<Box<RString>,Box<String>> = BTreeMap::new();

    for (key, value) in env::vars() {
        sortedmap.insert(
            Box::<RString>::new( RString { s: key } ),
            Box::<String>::new( value )
        );
    }

    for (key, value) in sortedmap {
        println!( "{} => {}", (*key).s, *value );
    }
}

This could also be implemented using a tuple containing a single element:

// http://rustbyexample.com/custom_types/structs.html
struct RString(String);

use std::cmp::Ord;
use std::cmp::Ordering;

impl PartialEq for RString {
    fn eq(&self, other:&Self) -> bool {
        if self.0 == other.0 {
            true
        } else {
            false
        }
    }
}

// this does not actually have any methods, it's just a flag on the type
impl Eq for RString { }

// make partial_cmp() just return result from cmp()
impl PartialOrd for RString {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        let me: &String = &(self.0);
        let them: &String = &(other.0);

        Some( me.cmp( them ) )
    }
}

impl Ord for RString {
    fn cmp(&self, other:&Self) -> Ordering {
        let me: &String = &(self.0);
        let them: &String = &(other.0);

        if me > them {
            Ordering::Less
        } else if me < them {
            Ordering::Greater
        } else {
            Ordering::Equal
        }
    }
}

use std::env;
use std::collections::btree_map::BTreeMap;
fn main() {
    // collect environment variable keys into a vector we can sort
    let mut sortedmap : BTreeMap<Box<RString>,Box<String>> = BTreeMap::new();

    for (key, value) in env::vars() {
        sortedmap.insert(
            Box::<RString>::new( RString(key) ),
            Box::<String>::new( value )
        );
    }

    for (key, value) in sortedmap {
        println!( "{} => {}", (*key).0, *value );
    }
}

Note that a tuple’s single element can be accessed through the .0 field.

Creating a Basic CGI Executable Using Rust

I created a new cargo project called “cgitest”:

~$ cargo new cgitest --bin
~$ cd cgitest
~/cgitest$

Then I added the following Rust code into src/main.rs:

// Use the following as a guide:
//   http://httpd.apache.org/docs/current/howto/cgi.html

use std::io::Write;
use std::env;
use std::collections::btree_map::BTreeMap;

fn write_stderr( msg : String ) {
    let mut stderr = std::io::stderr();
    write!(&mut stderr, "{}", msg).unwrap();
}

fn write_stderr_s( msg : &str ) {
    write_stderr( msg.to_string() );
}

fn write_stdout( msg : String ) {
    let mut stdout = std::io::stdout();
    write!(&mut stdout, "{}", msg).unwrap();
}

fn write_stdout_s( msg : &str ) {
    write_stdout( msg.to_string() );
}

fn html_escape( msg : String ) -> String {
    let mut copy : String = String::with_capacity( msg.len() );

    for thechar in msg.chars() {
        if thechar == '&' {
            copy.push_str( "&amp;" );
        } else if thechar == '<' {
            copy.push_str( "&lt;" );
        } else if thechar == '>' {
            copy.push_str( "&gt;" );
        } else if thechar == '\"' {
            copy.push_str( "&quot;" );
        } else {
            copy.push( thechar );
        }
    }

    return copy;
}

fn main() {
    write_stdout_s( "Content-type: text/html\n" );
    write_stdout_s( "\n" );
    write_stdout_s( "<html>\n" );
    write_stdout_s( "  <head>\n" );
    write_stdout_s( "    <title>Rust CGI Test</title>\n" );
    write_stdout_s( "    <style type=\"text/css\">\n" );
    write_stdout_s( "      td { border:1px solid black; }\n" );
    write_stdout_s( "      td { font-family:monospace; }\n" );
    write_stdout_s( "      table { border-collapse:collapse; }\n" );
    write_stdout_s( "    </style>\n" );
    write_stdout_s( "  </head>\n" );
    write_stdout_s( "  <body>\n" );
    write_stdout_s( "    <h1>Environment</h1>\n" );
    write_stdout_s( "    <table>\n" );
    write_stdout_s( "      <tr><th>Key</th><th>Value</th></tr>\n" );

    // copy environment into a BTreeMap which is sorted
    let mut sortedmap : BTreeMap<String,String> = BTreeMap::new();
    for (key, value) in env::vars() {
        sortedmap.insert( key, value );
    }

    // output environment into HTML table
    for (key, value) in sortedmap {
        write_stdout(
            format!(
                "      <tr><td>{}</td><td>{}</td></tr>\n",
                html_escape( key ),
                html_escape( value )
            )
        );
    }
    write_stdout_s( "    </table>\n" );
    write_stdout_s( "  </body>\n" );
    write_stdout_s( "</html>\n" );
}

Compiling it using the cargo build --release command produced a binary in target/release/cgitest which can be launched from Apache as a CGI script.

Where Is The Std Crate Located In A Rust Installation

I downloaded Rust (the programming language) from the Rust downloads page. Specifically I downloaded the 64-bit Linux .tar.gz file and then extracted it to /opt/ on my filesystem and symlinked /opt/rust to the untarred directory.

However when I went to compile a test Rust program I got the following error:

$ /opt/rust/rustc/bin/rustc test.rs
error: can't find crate for `std` [E0463]
error: aborting due to previous error

I searched for the std crate by running:

$ find /opt/rust/ -name 'libstd*'
/opt/rust/rustc/lib/libstd-d16b8f0e.so
/opt/rust/rust-std-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libstd-d16b8f0e.so
/opt/rust/rust-std-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libstd-d16b8f0e.rlib
/opt/rust/rust-docs/share/doc/rust/html/src/std/up/src/libstd

I tried then compiling my Rust program using the first path, “/opt/rust/rustc/lib/“:

$ /opt/rust/rustc/bin/rustc -L /opt/rust/rustc/lib test.rs
error:error: can't find crate for `core` which `std` depends on [E0463]
error:error: aborting due to previous error

So, where is libcore?

$ find /opt/rust/ -name 'libcore*'
/opt/rust/rust-std-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libcore-d16b8f0e.rlib
/opt/rust/rust-docs/share/doc/rust/html/src/core/up/src/libcore

I then tried compiling using the path to libcore.

$ /opt/rust/rustc/bin/rustc -L /opt/rust/rust-std-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib test.rs
$

Success!

If you want to pass command line options for rustc to cargo you can do it as follows:

$ RUSTFLAGS="-L /opt/rust/rust-std-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib" cargo
$

C-Style For Loop in Rust Language

A matter of some contention amongst Rust developers and users is the C-style for loop. At present it is not supported in the language – favouring iterators instead.

Simple counting jobs, such as counting from 0 to 99, are efficiently handled by the Rust compiler using the range() function.

In fact the compiler is so clever that loops over small iterated ranges can be efficiently unrolled:

fn main() {
    for i in range(0, 4u) {
        println!("{}", i)
    }
}

outputs:

0
1
2
3

… and the underlying assembler calls the print function four times rather than actually looping.

But what if you want to iterate something a little unorthodox, e.g.:

// test most specific 32-bit IPv4 netmask up to widest netmask
// in routing table
for ( mask = 4294967295; mask > 0; mask <<= 1 ) {
    ....
}

In Rust this can be expressed using the following form:

fn main() {
    for mask in std::iter::iterate(
        |x| x << 1, 
        0xFFFFFFFFu32
    ).take_while(
        |x| *x > 0
    ) {
        println!("{:t}", mask);
    }
}

Still – doesn’t roll off the tongue, does it.

It is possible to emulate a C-style for loop (contributed here) using a Rust macro:

#![feature(macro_rules)]

macro_rules! cfor {
    ($init: stmt; $cond: expr; $step: expr $body: block) => {
        {
            let mut first = true;
            $init;
            while {
                if first {
                    first = false
                } else {
                    $step
                }

                $cond
            } $body
        }
    }
}

fn main() {
    cfor!(let mut mask = 4294967295u32; mask > 0; mask <<= 1 {
        if mask & 0xFF000000u32 == 0xF0000000u32 {
            println!("{:t} (only top 4 bits set, continue)", mask);
            continue
        }
        
        if mask & 0xFF000000u32 == 0xC0000000u32 {
            println!("{:t} (only top 2 bits set, aborting)", mask);
            break;
        }

        println!("{:t}", mask);
    })
}

Which outputs:

11111111111111111111111111111111
11111111111111111111111111111110
11111111111111111111111111111100
11111111111111111111111111111000
11111111111111111111111111110000
11111111111111111111111111100000
11111111111111111111111111000000
11111111111111111111111110000000
11111111111111111111111100000000
11111111111111111111111000000000
11111111111111111111110000000000
11111111111111111111100000000000
11111111111111111111000000000000
11111111111111111110000000000000
11111111111111111100000000000000
11111111111111111000000000000000
11111111111111110000000000000000
11111111111111100000000000000000
11111111111111000000000000000000
11111111111110000000000000000000
11111111111100000000000000000000
11111111111000000000000000000000
11111111110000000000000000000000
11111111100000000000000000000000
11111111000000000000000000000000
11111110000000000000000000000000
11111100000000000000000000000000
11111000000000000000000000000000
11110000000000000000000000000000 (only top 4 bits set, continue)
11100000000000000000000000000000
11000000000000000000000000000000 (only top 2 bits set, aborting)

.. as expected.