Convert "sl" Source Code from C to Rust

Previous - Put All Images into One Separate File

Convert the const to a Vector of String-type Vectors

Create a Place-holder Module/Function for Converting the const To a Vector of String-type Vectors

Now that we have simplified the creation/storage/retrieval of our graphic images, let's make the processing of those images easier, by converting the const value into a vector of String-type vectors.

Below are the changes we'll make to our "main.rs" file. We're being a little bit verbose with our symbol names, but this verbosity helps to document what's going on.

main.rs
/* main.rs */

mod convert_to_vec;
mod images;

use convert_to_vec::str_to_vecvecstring;
use images::*;

fn main() {
    let model_str: &str = PLANE;
    let model_vecvecstring = str_to_vecvecstring(model_str);
    println!("{}", model_str);
    println!("{:?}", model_vecvecstring);
} // end of main()

Notice that instead of putting the "str_to_vecvecstring()" function in our "main.rs" file, we're putting it into its own separate "convert_to_vec.rs" file ("module", essentially). The only reasons we are doing it this way is to keep the "main.rs" file clean, and to separate more cleanly the various tasks we're doing.

We're currently only printing the resulting image variable using the debug formatter ("{:?}"), because the standard println!() formatter will choke on trying to print a vector. We're not interested at this moment in pretty output, but we just want to make sure our processes are working.

Of course, this means we have to create the new "convert_to_vec" module. We'll start out with just a place-holder function that tests the basic process; we'll complete it later. For now, create the file and fill it with the following:

src/convert_to_vec.rs
/* convert_to_vec.rs */

pub fn str_to_vecvecstring(incoming_str: &str) -> Vec<Vec<String>> {
    // Test that we got the &str data.
    println!("Incoming str = {}", incoming_str);
    
    // Convert &str-type to String-type.
    let outgoing = incoming_str.to_string();
    
    // Convert that to one-vector in an outer vector.
    let outgoing_vecvecstring = vec!{vec!{outgoing}};
    
    // Return the result from this function.
    return outgoing_vecvecstring;
    
} // end of str_to_vecvecstring()

The new function first displays the &str it gets (named "incoming_str"), just to test our functionality; this will display the four frames of the plane. Then it converts that &str to a vector of vectors, which it returns to the "main()" function, which prints that vector of vectors using the debug formatter, which results in a jumble of plane parts being displayed.

Now that we've proven we are getting the string into our function successfully, we no longer need that test line:

src/convert_to_vec.rs
/* convert_to_vec.rs */

pub fn str_to_vecvecstring(incoming_str: &str) -> Vec<Vec<String>> {
    // Test that we got the &str data.
    println!("Incoming str = {}", incoming_str);
    
    // Convert &str-type to String-type.
    let outgoing = incoming_str.to_string();
    
    // Convert that to one-vector in an outer vector.
    let outgoing_vecvecstring = vec!{vec!{outgoing}};
    
    // Return the result from this function.
    return outgoing_vecvecstring;
    
} // end of str_to_vecvecstring()

Create a Module/Function to Properly Display the Vector of String-type Vectors

Here's the change we'll need to make to our "main()" function:

main.rs
/* main.rs */
 
mod convert_to_vec;
mod display;
mod images;
 
use convert_to_vec::str_to_vecvecstring;
use display::display_image;
use images::*;

fn main() {                                                                     
    let model_str: &str = PLANE;
    let model_vecvecstring = str_to_vecvecstring(model_str);                    
    println!("{:?}", model_vecvecstring);
    display_image(model_vecvecstring);
} // end of main()    

And here's our new module/file:

src/display.rs
/* display.rs */

pub fn display_image(image_vecvec: Vec<Vec<String>>) {
    let mut frame_num = 0;
    for each_frame in image_vecvec {                                            
        println!("Frame {}:", frame_num);                                       
        for each_line in each_frame {                                           
            println!("{}", each_line);                                          
        }                                                                       
        frame_num += 1;                                                         
    }
} // end of display_image()

When you run this, you should see two copies of your chosen image; the first is as a single &str-type of data, and the second is as a vector of String-type vectors.

But, that vector of String-type vectors only has one inner vector, which contains all the frames of the image. We instead need one inner vector for each frame of the image. So we'll need to return back to the function we started above, and finish it.

Finish the Function for Converting the const To a Vector of String-type Vectors

Replace our entire "src/convert_to_vec" file with the following:

Now let's do the actual full conversion.

src/convert_to_vec.rs
/* convert_to_vec.rs */

pub fn str_to_vecvecstring(incoming_str: &str) -> Vec<Vec<String>> {
    //The first character in the original const, after the 'r"', is a newline; lose it.
    let image_str: &str = &incoming_str[1..];

    // Create new empty vector of vectors of Strings.
    let mut outer_vec: Vec<Vec<String>> = Vec::new();

    // This keeps track of which frame/inner vector we're processing.
    let mut inner_vec_num: usize = 0; // We'll start with the first one.

    // Create a first new inner vector into the outer vector.
    outer_vec.push(Vec::new());

    for mut each_line in image_str.lines() { // Cycle through each line of the image_str image.
        if each_line == "" { // If the line is a blank line ...
            // ... we're starting a new frame, so create a new inner vector...
            outer_vec.push(Vec::new());
            // ... and increase the count of vectors by one.
            inner_vec_num += 1;
        } else { // The line is not blank, so process it as part of the current frame.
            if &each_line[each_line.len() - 1..] == "'" { // If end of line is a single-quote ...
                each_line = &each_line[0..each_line.len() - 1]; // ... remove it.
            }
            // Now add the non-blank line to the current inner vector.
            outer_vec[inner_vec_num].push(each_line.to_string());
        } // Then move on to the next loop/line.
    }
    // Return the finished vector of String vectors.
    outer_vec
} // end of str_to_vecvecstring()

When you run this, you should see all the frames of your chosen image, numbered.

Wouldn't it be nice to be able to specify at the command-line which image you wanted to display? We can, by Getting User-provided Options From the Command-line.