PHPFixing
  • Privacy Policy
  • TOS
  • Ask Question
  • Contact Us
  • Home
  • PHP
  • Programming
  • SQL Injection
  • Web3.0

Thursday, August 25, 2022

[FIXED] What is the idiomatic way to hardcode a byte vector with some metadata in a Rust module?

 August 25, 2022     arrays, hardcode, idioms, module, rust     No comments   

Issue

I am following the Rust wasm tutorial. in which you build a game-of-life clone and am currently doing the "Initialize the universe with a single space ship" exercise.

To implement the ship I started a module which holds the ship data and associated functions to draw a ship to a grid. In this module I want to store some pre-made well known ships/patterns as for example the copperhead ship.

For the data structure I came up with following struct:

// life_patterns.rs
pub struct LifePattern {
  width: u32,
  height: u32,
  data: Vec<u8>,
}

Now I want to hardcode the actual data into the module. Coming from a JavaScript background I came up with:

// life_patterns.rs
pub const COPPERHEAD: LifePattern = LifePattern {
  width: 10,
  height: 13,
  data: vec![
    0, 0, 0, 0, 1, 1, 0, 0, 0, 0,
    0, 0, 0, 1, 1, 1, 1, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 1, 1, 1, 1, 1, 1, 0, 0,
    0, 0, 0, 1, 1, 1, 1, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 1, 1, 0, 0, 1, 1, 0, 0,
    1, 1, 0, 1, 0, 0, 1, 0, 1, 1,
    0, 0, 0, 1, 0, 0, 1, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 1, 1, 0, 0, 0, 0,
    0, 0, 0, 0, 1, 1, 0, 0, 0, 0,
    ],
}

I want then draw the pattern to an existing grid like so:

// lib.rs
life_patterns::draw(grid, start_index, life_patterns::COPPERHEAD);

My solution doesn't compile with the error messages:

allocations are not allowed in constants E0010
calls in constants are limited to constant functions, tuple structs and tuple variants E0015

So now my question, how do I properly hardcode the data for the copperhead ship in the life_patterns module in an idiomatic way?

A more general way to ask this could be: "How do I hardcode an Vec<u8> and two u32 in a Rust module idiomaticly?"


Solution

In order to stay close to the usage you show in your question, I would use lazy_static.

Its purpose is to provide something similar to const when the initialisation is not compatible with const; it then happens once for all at run-time.


edit

A very interesting remark of @Caesar suggest relying on once_cell which should become standard.

The other answer suggests a readable pattern, which is a very good idea in my opinion.

The example keeps the original solution as a comment and suggests another solution considering the two previous remarks.

pub struct LifePattern {
    width: u32,
    height: u32,
    data: Vec<u8>,
}

/*
lazy_static::lazy_static! {
    pub static ref COPPERHEAD: LifePattern = LifePattern {
        width: 10,
        height: 13,
        data: vec![
            0, 0, 0, 0, 1, 1, 0, 0, 0, 0,
            0, 0, 0, 1, 1, 1, 1, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 1, 1, 1, 1, 1, 1, 0, 0,
            0, 0, 0, 1, 1, 1, 1, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 1, 1, 0, 0, 1, 1, 0, 0,
            1, 1, 0, 1, 0, 0, 1, 0, 1, 1,
            0, 0, 0, 1, 0, 0, 1, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 1, 1, 0, 0, 0, 0,
            0, 0, 0, 0, 1, 1, 0, 0, 0, 0,
            ],
    };
}
*/

static COPPERHEAD: once_cell::sync::Lazy<LifePattern> =
    once_cell::sync::Lazy::new(|| LifePattern {
        width: 10,
        height: 13,
        data: "\
            ____XX____\
            ___XXXX___\
            __________\
            __XXXXXX__\
            ___XXXX___\
            __________\
            __XX__XX__\
            XX_X__X_XX\
            ___X__X___\
            __________\
            __________\
            ____XX____\
            ____XX____"
            .chars()
            .map(|c| if c == 'X' { 1 } else { 0 })
            .collect(),
    });

fn main() {
    let pattern: &LifePattern = &COPPERHEAD;
    println!("with={}", pattern.width);
    println!("height={}", pattern.height);
    println!("data={:?}", pattern.data);
}


Answered By - prog-fh
Answer Checked By - Dawn Plyler (PHPFixing Volunteer)
  • Share This:  
  •  Facebook
  •  Twitter
  •  Stumble
  •  Digg
Newer Post Older Post Home

0 Comments:

Post a Comment

Note: Only a member of this blog may post a comment.

Total Pageviews

Featured Post

Why Learn PHP Programming

Why Learn PHP Programming A widely-used open source scripting language PHP is one of the most popular programming languages in the world. It...

Subscribe To

Posts
Atom
Posts
Comments
Atom
Comments

Copyright © PHPFixing