For a comparison I’ve implemented two small programs, porting it from Java code ( https://www.reddit.com/r/haskell/comments/6znim3/performance_enumerating_all_3674160/ ), this is an (useless) extract of the Rust code:
const N: usize = 24;
type Config = [u8; N];
type Indexes = [usize; N];
const OP0: Indexes = [1,3,0,2,21,20,6,7,4,5,10,11,12,
13,14,15,9,8,18,19,16,17,22,23];
fn update(cfg: &Config) -> Config {
let mut new_cfg: Config = Default::default();
for i in 0 .. N {
new_cfg[i] = cfg[OP0[i]];
}
new_cfg
}
fn main() {
use std::str::from_utf8_unchecked;
const SOLVED: &'static Config = b"RRRRYYYYBBBBOOOOWWWWGGGG";
let new_cfg = update(SOLVED);
println!("{}", unsafe { from_utf8_unchecked(&new_cfg) });
}
In this code I’d like to avoid using unsafe code, but I’d also like to keep the performance of from_utf8_unchecked(), avoiding useless UTF8 testing. A way to do this is to introduce subtypes in Rust:
// subtype with enumeration:
subtype Cfg: Ascii = [b'R', b'Y', b'B', b'O', b'W', b'G'];
// Simpler less strict alternative, ranged subtype:
subtype Cfg: Ascii = b'B' ... b'W';
type Config = [Cfg; N];
const SOLVED: &'static Config = b"RRRRYYYYBBBBOOOOWWWWGGGG";
// Using:
fn from_ascii(_: &[Ascii]) -> &str;
// Sloppy typing, subtype implicits converts to the type Ascii:
println!("{}", from_ascii(&new_cfg));
// Alternative:
println!("{}", str::from(&new_cfg));
// More strongly typed alternative:
println!("{}", str::from(Ascii::from(&new_cfg)));
In the last alternative Ascii::from() converts a subtype of Ascii to Ascii. (Note: Ada language has a similar useful feature since long time).