Full Code Listing Up to the "Include the Images in the Main Program of the Rust Version of sl" Page

Return back to the "Include the Images in the Main Program of the Rust Version of sl" Page

src/main.rs
/* main.rs */

mod d51;
mod extras;

use extras::*;

fn main() {
    let (speed, fly, kind, oops) = parse_opts();
    draw_image(speed, fly, kind, oops)
} // end of main()
src/d51.rs
/* d51.rs */

pub fn get_d51() -> Vec<Vec<String>> {
    let d51: Vec<Vec<String>> = vec![
        vec![
            /* Frame-set #0 */
            "      ====        ________                ___________ ".to_string(),
            "  _D _|  |_______/        \\__I_I_____===__|_________| ".to_string(),
            "   |(_)---  |   H\\________/ |   |        =|___ ___|   ".to_string(),
            "   /     |  |   H  |  |     |   |         ||_| |_||   ".to_string(),
            "  |      |  |   H  |__--------------------| [___] |   ".to_string(),
            "  | ________|___H__/__|_____/[][]~\\_______|       |   ".to_string(),
            "  |/ |   |-----------I_____I [][] []  D   |=======|__ ".to_string(),
            "__/ =| o |=-~~\\  /~~\\  /~~\\  /~~\\ ____Y___________|__ ".to_string(),
            " |/-=|___|=    ||    ||    ||    |_____/~\\___/        ".to_string(),
            "  \\_/      \\O=====O=====O=====O_/      \\_/            ".to_string(),
        ],
        vec![
            /* Frame-set #1 */
            "      ====        ________                ___________ ".to_string(),
            "  _D _|  |_______/        \\__I_I_____===__|_________| ".to_string(),
            "   |(_)---  |   H\\________/ |   |        =|___ ___|   ".to_string(),
            "   /     |  |   H  |  |     |   |         ||_| |_||   ".to_string(),
            "  |      |  |   H  |__--------------------| [___] |   ".to_string(),
            "  | ________|___H__/__|_____/[][]~\\_______|       |   ".to_string(),
            "  |/ |   |-----------I_____I [][] []  D   |=======|__ ".to_string(),
            "__/ =| o |=-~~\\  /~~\\  /~~\\  /~~\\ ____Y___________|__ ".to_string(),
            " |/-=|___|=O=====O=====O=====O   |_____/~\\___/        ".to_string(),
            "  \\_/      \\__/  \\__/  \\__/  \\__/      \\_/            ".to_string(),
        ],
        vec![
            /* Frame-set #2 */
            "      ====        ________                ___________ ".to_string(),
            "  _D _|  |_______/        \\__I_I_____===__|_________| ".to_string(),
            "   |(_)---  |   H\\________/ |   |        =|___ ___|   ".to_string(),
            "   /     |  |   H  |  |     |   |         ||_| |_||   ".to_string(),
            "  |      |  |   H  |__--------------------| [___] |   ".to_string(),
            "  | ________|___H__/__|_____/[][]~\\_______|       |   ".to_string(),
            "  |/ |   |-----------I_____I [][] []  D   |=======|__ ".to_string(),
            "__/ =| o |=-O=====O=====O=====O \\ ____Y___________|__ ".to_string(),
            " |/-=|___|=    ||    ||    ||    |_____/~\\___/        ".to_string(),
            "  \\_/      \\__/  \\__/  \\__/  \\__/      \\_/            ".to_string(),
        ],
        vec![
            /* Frame-set #3 */
            "      ====        ________                ___________ ".to_string(),
            "  _D _|  |_______/        \\__I_I_____===__|_________| ".to_string(),
            "   |(_)---  |   H\\________/ |   |        =|___ ___|   ".to_string(),
            "   /     |  |   H  |  |     |   |         ||_| |_||   ".to_string(),
            "  |      |  |   H  |__--------------------| [___] |   ".to_string(),
            "  | ________|___H__/__|_____/[][]~\\_______|       |   ".to_string(),
            "  |/ |   |-----------I_____I [][] []  D   |=======|__ ".to_string(),
            "__/ =| o |=-~O=====O=====O=====O\\ ____Y___________|__ ".to_string(),
            " |/-=|___|=    ||    ||    ||    |_____/~\\___/        ".to_string(),
            "  \\_/      \\__/  \\__/  \\__/  \\__/      \\_/            ".to_string(),
        ],
        vec![
            /* Frame-set #4 */
            "      ====        ________                ___________ ".to_string(),
            "  _D _|  |_______/        \\__I_I_____===__|_________| ".to_string(),
            "   |(_)---  |   H\\________/ |   |        =|___ ___|   ".to_string(),
            "   /     |  |   H  |  |     |   |         ||_| |_||   ".to_string(),
            "  |      |  |   H  |__--------------------| [___] |   ".to_string(),
            "  | ________|___H__/__|_____/[][]~\\_______|       |   ".to_string(),
            "  |/ |   |-----------I_____I [][] []  D   |=======|__ ".to_string(),
            "__/ =| o |=-~~\\  /~~\\  /~~\\  /~~\\ ____Y___________|__ ".to_string(),
            " |/-=|___|=   O=====O=====O=====O|_____/~\\___/        ".to_string(),
            "  \\_/      \\__/  \\__/  \\__/  \\__/      \\_/            ".to_string(),
        ],
        vec![
            /* Frame-set #5 */
            "      ====        ________                ___________ ".to_string(),
            "  _D _|  |_______/        \\__I_I_____===__|_________| ".to_string(),
            "   |(_)---  |   H\\________/ |   |        =|___ ___|   ".to_string(),
            "   /     |  |   H  |  |     |   |         ||_| |_||   ".to_string(),
            "  |      |  |   H  |__--------------------| [___] |   ".to_string(),
            "  | ________|___H__/__|_____/[][]~\\_______|       |   ".to_string(),
            "  |/ |   |-----------I_____I [][] []  D   |=======|__ ".to_string(),
            "__/ =| o |=-~~\\  /~~\\  /~~\\  /~~\\ ____Y___________|__ ".to_string(),
            " |/-=|___|=    ||    ||    ||    |_____/~\\___/        ".to_string(),
            "  \\_/      \\_O=====O=====O=====O/      \\_/            ".to_string(),
        ],
    ];

    return d51;
} // end of get_d51()
src/extras.rs
/* extras.rs */

use crate::d51::*;
use ncurses::*;
use std::{thread, time::Duration};

// Use c[ommand] l[ine] a[rgument] p[arser] to get command-line arguments.
use clap::Parser;

// This tells clap to derive info it needs from the struct we build below, from the "#[" lines.
#[derive(Parser)]

/* Define the argument inputs we might expect; put them in a struct named "Args". */
struct Args {
    /// Move the train '[[z]ip]py', '[f]ast', '[[m]ed]ium', '[s]low' or '[c]rawl'?
    #[arg(short, long, default_value_t = String::from("med"))]
    // The above tells clap that the next line is an argument, that can be entered in as "s" or "speed".
    speed: String,

    /// Fly?
    #[arg(short, long, default_value_t = false)]
    fly: bool,

    /// What Kind of object? D51 | C51 | Little | Jack | Boat | Plane
    #[arg(short, long, default_value_t = String::from("D51"))]
    kind: String,

    /// Oops?
    #[arg(short, long, default_value_t = false)]
    oops: bool,
} // end of Args definitions

pub fn parse_opts() -> (u64, bool, String, bool) {
    // Get command-line options using Clap.
    let switches: Args = Args::parse();

    // Set "speed".
    let speed: u64 = match (&switches.speed.to_uppercase()).as_str() {
        // The variable "switches.speed" is a String-type (as defined above in the "Args" struct). We upper-case
        // it, then compare it to possible matches which are string-slices (&str), which requires the ".as_str()"
        // conversion. We then "return" the selected value, which is assigned to "speed".
        "Z" | "ZIPPY" | "ZIP" | "U" | "ULTRAFAST" => 10,
        "F" | "FAST" => 20,
        "M" | "MED" | "MEDIUM" => 50,
        "S" | "SLOW" => 100,
        "C" | "CRAWL" => 400,
        _ => {
            println!("Invalid input; must be '[z]ippy/[u]ltrafast, '[f]ast', '[[m]ed]ium', '[s]low', or '[c]rawl'. You entered '{}', so the default of 'medium' was used.", switches.speed);
            50
        }
    };

    // Set "kind".
    let kind: String = match (&switches.kind.to_uppercase()).as_str() {
        "D" | "D51" => String::from("D51"), // Alternative way of doing '"D51".to_string()'.
        "C" | "C51" => String::from("C51"),
        "L" | "LITTLE" => String::from("LITTLE"),
        "J" | "JACK" => String::from("JACK"),
        "B" | "BOAT" => String::from("BOAT"),
        "P" | "PLANE" => String::from("PLANE"),
        _ => {
            // If none of them match, then ...
            println!("Invalid input; run program with '--help' option for more information. You entered '{}', so the default of 'd51' was used.", switches.kind);
            String::from("D51")
        }
    };

    return (speed, switches.fly, kind, switches.oops);
} // end of parse_opts()

pub fn draw_image(delay: u64, fly: bool, kind: String, oops: bool) {
    // Start ncurses, initializing "stdscr()".
    initscr();

    // Don't echo keypresses to screen.
    noecho();

    // Turn off the display of the cursor.
    curs_set(CURSOR_VISIBILITY::CURSOR_INVISIBLE);

    // Get the screen dimensions.
    let mut screen_height = 0;
    let mut screen_width = 0;
    getmaxyx(stdscr(), &mut screen_height, &mut screen_width);

    // Load ASCII-art into "image" variable (a vector of vectors holding Strings).
    let image = match kind.as_str() {
        // Which image are we supposed to draw?
        "D51" => get_d51(), // Neither image will work at this point.
        "C51" => get_image("./c51.txt"),
        "LITTLE" => get_image("./little.txt"),
        "JACK" => get_image("./jack.txt"),
        &_ => {
            // If the user enters an unknown image name (say, "racecar") ...
            println!(
                "Invalid kind. You entered '{}'; the default was used instead.",
                kind
            );
            get_d51()
        }
    };
    let height = image[0].len() as i32; // How tall (in rows) is the image?
    let mut row = screen_height - height; // Put the bottom of the image at the bottom of the screen.
    let count_of_inner_vecs: usize = image.len(); // How many animation cel frames in this image?
    let length: i32 = image[0][0].len() as i32; // How long (width in screen columns/chars) is the image?
    let ms = Duration::from_millis(delay); // This is the "delay" converted to a format for the "sleep()" function below.

    let mut current_inner_vec: usize = count_of_inner_vecs - 1; // Count down from highest-numbered frame; then repeat cycle.

    for col in ((-length)..screen_width).rev() {
        // Count down from right-edge until leading edge of image drags all of image off left-edge.
        let current_frame = &image[current_inner_vec]; // Of the various inner_vecs, get the one we're drawing into its own variable.
        let mut line = row; // Keep "row" unaltered unless we're flying; use "line" within loop.
        for each_line in current_frame {
            my_mvaddstr(line, col, &each_line, screen_width, screen_height);
            line = line + 1;
        }
        refresh(); // Necessary to "bring to the forefront" the drawing we just did "in the back staging area".

        /* Pause so our eyes can see the frame. */
        thread::sleep(ms);
        // row = screen_height - height; // Reset row back to starting row.

        if current_inner_vec > 0 {
            current_inner_vec = current_inner_vec - 1; // Prepare to display next frame.
        } else {
            // we've gotten down to last frame, so ...
            current_inner_vec = count_of_inner_vecs - 1; // ... start over.
            if fly {
                // And if we're flying ...
                row -= 1; // ... fly up one row, and ...
                line = row + height; // ... erase last (bottom) line drawn, using enough repeated spaces for image's length.
                my_mvaddstr(
                    line,
                    col,
                    &" ".repeat(length as usize),
                    screen_width,
                    screen_height,
                );
                // No need to refresh(); next frame will do it for us.
            }
        }
    }
    /* Once finished, terminate ncurses. */
    endwin();
} // end of draw_image()

fn my_mvaddstr(row: i32, mut col: i32, frame_line: &str, screen_width: i32, screen_height: i32) {
    /* This function recieves one line of an ASCII-art image, and
        trims away any of that line that would otherwise be displayed
        off-screen; then it displays the remaining portion of the
        line.
    */

    let mut line = frame_line.to_string(); // An &str is immutable by nature; we need a mutable string.

    // Trim from left side as train moves off left edge
    if col < 0 {
        // If we've moved left of the left-edge,
        for _ in 0..col.abs() {
            // for each column beyond edge,
            line.remove(0); // trim the first char off the string, repeatedly.
        } // "line" should now have front end trimmed off.
        col = 0;
    }

    // Trim from right side if it extends off right edge
    if col + (line.len() as i32) > screen_width {
        let amt_to_trim = (col + (line.len() as i32)) - screen_width;
        for _ in 0..amt_to_trim {
            line.pop();
        }
    }

    if (row >= 0) && (row < screen_height) {
        // We're within screen bounds, so it's okay to display this line.
        mvaddstr(row, col, &line);
    }
} // end of my_mvaddstr()

fn get_image(filename: &str) -> Vec<Vec<String>> {
    /*  This function reads a text file containing a series of ASCII-art image "frames". This gets put into a
        variable as one long string of UTF-8 characters (think of 'em as ASCII chars, though). This string is
        then broken down into separate lines, breaking at the newline/end-of-line characters, and each line is
        pushed onto an inner vector. When a blank line is found, we
        skip on to the next loop, and create a new inner vector at the same time, and then repeat the above
        process. Eventually, each of the image frames is put into its own inner vector, and all those inner
        vectors are put into an outer vector named "outer_vec".
    */

    let mut outer_vec: Vec<Vec<String>> = Vec::new(); // Outer vec holding all the inner frame vecs.

    // Read the file containing the image, into a variable named "image_string".
    let image_string = std::fs::read_to_string(filename).expect("Error opening file.");

    let mut inner_vec: usize = 0; // To keep track of which frame/inner vector we're working with.

    outer_vec.push(Vec::new()); // Create first frame vec in outer vec, named "frames".

    // Process each line of the text file that's been read into memory.
    for each_line in image_string.lines() {
        // Break-up the single String variable "image_string" at newlines.
        if each_line != "" {
            // If the line is not blank,
            let line_string = each_line.replace("\"", " ").to_string(); // replace quotes with spaces, & convert the &str variable to a String variable
            outer_vec[inner_vec].push(line_string); // Then copy that String into the current inner frame vec.
        } else {
            // Else, if the line is blank, then we're between frames, so ignore the blan line, and
            inner_vec += 1; // prep for a new inner frame vec, and then
            outer_vec.push(Vec::new()); // create that new inner frame vec,
        } // before looping around to the next line.
    }

    return outer_vec;
} // end of get_image()
src/c51.txt
"        ___                                            "
"       _|_|_  _     __       __             ___________"
"    D__/   \_(_)___|  |__H__|  |_____I_Ii_()|_________|"
"     | `---'   |:: `--'  H  `--'         |  |___ ___|  "
"    +|~~~~~~~~++::~~~~~~~H~~+=====+~~~~~~|~~||_| |_||  "
"    ||        | ::       H  +=====+      |  |::  ...|  "
"|    | _______|_::-----------------[][]-----|       |  "
"| /~~ ||   |-----/~~~~\  /[I_____I][][] --|||_______|__"
"------'|oOo|==[]=-     ||      ||      |  ||=======_|__"
"/~\____|___|/~\_|   O=======O=======O  |__|+-/~\_|     "
"\_/         \_/  \____/  \____/  \____/      \_/       "

"        ___                                            "
"       _|_|_  _     __       __             ___________"
"    D__/   \_(_)___|  |__H__|  |_____I_Ii_()|_________|"
"     | `---'   |:: `--'  H  `--'         |  |___ ___|  "
"    +|~~~~~~~~++::~~~~~~~H~~+=====+~~~~~~|~~||_| |_||  "
"    ||        | ::       H  +=====+      |  |::  ...|  "
"|    | _______|_::-----------------[][]-----|       |  "
"| /~~ ||   |-----/~~~~\  /[I_____I][][] --|||_______|__"
"------'|oOo|===[]=-    ||      ||      |  ||=======_|__"
"/~\____|___|/~\_|    O=======O=======O |__|+-/~\_|     "
"\_/         \_/  \____/  \____/  \____/      \_/       "

"        ___                                            "
"       _|_|_  _     __       __             ___________"
"    D__/   \_(_)___|  |__H__|  |_____I_Ii_()|_________|"
"     | `---'   |:: `--'  H  `--'         |  |___ ___|  "
"    +|~~~~~~~~++::~~~~~~~H~~+=====+~~~~~~|~~||_| |_||  "
"    ||        | ::       H  +=====+      |  |::  ...|  "
"|    | _______|_::-----------------[][]-----|       |  "
"| /~~ ||   |-----/~~~~\  /[I_____I][][] --|||_______|__"
"------'|oOo|===[]=- O=======O=======O  |  ||=======_|__"
"/~\____|___|/~\_|      ||      ||      |__|+-/~\_|     "
"\_/         \_/  \____/  \____/  \____/      \_/       "

"        ___                                            "
"       _|_|_  _     __       __             ___________"
"    D__/   \_(_)___|  |__H__|  |_____I_Ii_()|_________|"
"     | `---'   |:: `--'  H  `--'         |  |___ ___|  "
"    +|~~~~~~~~++::~~~~~~~H~~+=====+~~~~~~|~~||_| |_||  "
"    ||        | ::       H  +=====+      |  |::  ...|  "
"|    | _______|_::-----------------[][]-----|       |  "
"| /~~ ||   |-----/~~~~\  /[I_____I][][] --|||_______|__"
"------'|oOo|==[]=- O=======O=======O   |  ||=======_|__"
"/~\____|___|/~\_|      ||      ||      |__|+-/~\_|     "
"\_/         \_/  \____/  \____/  \____/      \_/       "

"        ___                                            "
"       _|_|_  _     __       __             ___________"
"    D__/   \_(_)___|  |__H__|  |_____I_Ii_()|_________|"
"     | `---'   |:: `--'  H  `--'         |  |___ ___|  "
"    +|~~~~~~~~++::~~~~~~~H~~+=====+~~~~~~|~~||_| |_||  "
"    ||        | ::       H  +=====+      |  |::  ...|  "
"|    | _______|_::-----------------[][]-----|       |  "
"| /~~ ||   |-----/~~~~\  /[I_____I][][] --|||_______|__"
"------'|oOo|=[]=- O=======O=======O    |  ||=======_|__"
"/~\____|___|/~\_|      ||      ||      |__|+-/~\_|     "
"\_/         \_/  \____/  \____/  \____/      \_/       "

"        ___                                            "
"       _|_|_  _     __       __             ___________"
"    D__/   \_(_)___|  |__H__|  |_____I_Ii_()|_________|"
"     | `---'   |:: `--'  H  `--'         |  |___ ___|  "
"    +|~~~~~~~~++::~~~~~~~H~~+=====+~~~~~~|~~||_| |_||  "
"    ||        | ::       H  +=====+      |  |::  ...|  "
"|    | _______|_::-----------------[][]-----|       |  "
"| /~~ ||   |-----/~~~~\  /[I_____I][][] --|||_______|__"
"------'|oOo|=[]=-      ||      ||      |  ||=======_|__"
"/~\____|___|/~\_|  O=======O=======O   |__|+-/~\_|     "
"\_/         \_/  \____/  \____/  \____/      \_/       "
src/jack.txt"
" \ 0 /   "
"  \|/    "
"   |     "
"  / \    "
"_/   \_  "
"         "

"         "
" __0__   "
"/  |  \  "
"  / \    "
" _\ /_   "
"         "

"         "
"   o     "
" /\ /\   "
" |/ \|   "
" _\ /_   "
"         "
src/little.txt
"     ++      +------ ____                 ____________________ "
"     ||      |+-+ |  |   \@@@@@@@@@@@     |  ___ ___ ___ ___ | "
"   /---------|| | |  |    \@@@@@@@@@@@@@_ |  |_| |_| |_| |_| | "
"  + ========  +-+ |  |                  | |__________________| "
" _|--O========O~\-+  |__________________| |__________________| "
"//// \_/      \_/       (O)       (O)        (O)        (O)    "

"     ++      +------ ____                 ____________________ " 
"     ||      |+-+ |  |   \@@@@@@@@@@@     |  ___ ___ ___ ___ | "
"   /---------|| | |  |    \@@@@@@@@@@@@@_ |  |_| |_| |_| |_| | "
"  + ========  +-+ |  |                  | |__________________| "
" _|--/O========O\-+  |__________________| |__________________| "
"//// \_/      \_/       (O)       (O)        (O)        (O)    "

"     ++      +------ ____                 ____________________ "
"     ||      |+-+ |  |   \@@@@@@@@@@@     |  ___ ___ ___ ___ | "
"   /---------|| | |  |    \@@@@@@@@@@@@@_ |  |_| |_| |_| |_| | "
"  + ========  +-+ |  |                  | |__________________| "
" _|--/~O========O-+  |__________________| |__________________| "
"//// \_/      \_/       (O)       (O)        (O)        (O)    "

"     ++      +------ ____                 ____________________ "
"     ||      |+-+ |  |   \@@@@@@@@@@@     |  ___ ___ ___ ___ | "
"   /---------|| | |  |    \@@@@@@@@@@@@@_ |  |_| |_| |_| |_| | "
"  + ========  +-+ |  |                  | |__________________| "
" _|--/~\------/~\-+  |__________________| |__________________| "
"//// \_O========O       (O)       (O)        (O)        (O)    "

"     ++      +------ ____                 ____________________ "
"     ||      |+-+ |  |   \@@@@@@@@@@@     |  ___ ___ ___ ___ | "
"   /---------|| | |  |    \@@@@@@@@@@@@@_ |  |_| |_| |_| |_| | "
"  + ========  +-+ |  |                  | |__________________| "
" _|--/~\------/~\-+  |__________________| |__________________| "
"//// \O========O/       (O)       (O)        (O)        (O)    "

"     ++      +------ ____                 ____________________ "
"     ||      |+-+ |  |   \@@@@@@@@@@@     |  ___ ___ ___ ___ | "
"   /---------|| | |  |    \@@@@@@@@@@@@@_ |  |_| |_| |_| |_| | "
"  + ========  +-+ |  |                  | |__________________| "
" _|--/~\------/~\-+  |__________________| |__________________| "
"//// O========O_/       (O)       (O)        (O)        (O)    "
scratch 1
use std::env::current_exe;

fn main() {
    // Get the path to the executable, where our data files should be.
    let mut path = current_exe().expect("An error occurred.");
    path.pop();

    // Convert that path to the path/file to the image file.
    path.push("jack.txt");

    // Read the file containing the image, into a variable.
    let image_string = std::fs::read_to_string(path).expect("Error opening file.");  

    // Print that variable containing the image.
    println!("{}", image_string);

    // for each_vec in JACK {
    //     for (line_count,each_line) in each_vec.lines().enumerate() {
    //         gotoyx(line_count as i32 + 14, 30);
    //         println!("{}", each_line);
    //     }
    // }
} // end of main()

fn gotoyx(y: i32, x: i32) {
    const ESC: &str = "\x1b[";
    print!("{}{};{}H", ESC, y, x);
} // end of gotoyx()
scratch 2
" \ 0 /   "
"  \|/    "
"   |     "
"  / \    "
"_/   \_  "

"         "
" __0__   "
"/  |  \  "
"  / \    "
" _\ /_   "

"         "
"   o     "
" /\ /\   "
" |/ \|   "
" _\ /_   "

"         "
" __0__   "
"/  |  \  "
"  / \    "
" _\ /_   "
"         "
scratch 3
/* acquire_image.rs */

pub fn get_image(kind: String) -> String {
    // This function returns the contents of an ASCII-art .txt file, stripped of its side-delimiting quote-marks.
    // The ASCII-art .txt file (e.g. "d51.txt") should be in the same dir as the executable.

    // Get the full path & name of executable (e.g., "/usr/bin/sl").
    let mut path = std::env::current_exe().expect("Error getting current_exe path environment.");

    // Strip off the executable name, leaving just the path to the directory (e.e., "/usr/bin/").
    path.pop();

    // Use format! to concatenate "kind" (e.g. "D51"), lower-cased (e.g., "d51"), with ".txt" (e.g., "d51.txt").
    let filename = format!("{}{}", kind.to_lowercase(), ".txt");

    // Then add that filename to the path from above (e.g., "/usr/bin/d51.txt").
    path.push(filename);

    // Prep an error message in case things don't go as we expect while reading the file.
    let possible_err_msg = format!("Error reading file '{}'.", path.display());

    // Read that image-containing file (e.e., "/usr/bin/d51.txt") into a variable (or show error if it fails).
    let mut image_string = std::fs::read_to_string(path).expect(&possible_err_msg);

    // Strip the quote-marks that delimit the side boundaries of the ASCII-art image.
    image_string = image_string.replace("\"", "");

    return image_string;
} // end of get_image()
scratch 4
/* main.rs */

mod acquire_image;
mod d51;
mod drawing;
mod parsing;

use acquire_image::*;
use drawing::*;
use parsing::*;

fn main() {
    let (speed, fly, kind, oops) = parse_opts();
    let image = get_image(kind);
    for each_line in image.lines() {
        println!("{}", each_line);
    }
    //    draw_image(speed, fly, kind, oops);
} // end of main()
/* parsing.rs */ // Use c[ommand] l[ine] a[rgument] p[arser] to get command-line arguments. use clap::Parser; // This tells clap to derive info it needs from the struct we build below, from the "#[" lines. #[derive(Parser)] /* Define the argument inputs we might expect; put them in a struct named "Args". */ struct Args { /// Move the train '[[z]ip]py', '[f]ast', '[[m]ed]ium', '[s]low' or '[c]rawl'? #[arg(short, long, default_value_t = String::from("med"))] // The above tells clap that the next line is an argument, that can be entered in as "s" or "speed". speed: String, /// Fly? #[arg(short, long, default_value_t = false)] fly: bool, /// What Kind of object? D51 | C51 | Little | Jack | Boat | Plane #[arg(short, long, default_value_t = String::from("D51"))] kind: String, /// Oops? #[arg(short, long, default_value_t = false)] oops: bool, } // end of Args definitions pub fn parse_opts() -> (u64, bool, String, bool) { // Get command-line options using Clap. let switches: Args = Args::parse(); // Set "speed". let speed: u64 = match (&switches.speed.to_uppercase()).as_str() { // The variable "switches.speed" is a String-type (as defined above in the "Args" struct). We upper-case // it, then compare it to possible matches which are string-slices (&str), which requires the ".as_str()" // conversion. We then "return" the selected value, which is assigned to "speed". "Z" | "ZIPPY" | "ZIP" | "U" | "ULTRAFAST" => 10, "F" | "FAST" => 20, "M" | "MED" | "MEDIUM" => 50, "S" | "SLOW" => 100, "C" | "CRAWL" => 400, _ => { println!("Invalid input; must be '[z]ippy/[u]ltrafast, '[f]ast', '[[m]ed]ium', '[s]low', or '[c]rawl'. You entered '{}', so the default of 'medium' was used.", switches.speed); 50 } }; // Set "kind". let kind: String = match (&switches.kind.to_uppercase()).as_str() { "D" | "D51" => String::from("D51"), // Alternative way of doing '"D51".to_string()'. "C" | "C51" => String::from("C51"), "L" | "LITTLE" => String::from("LITTLE"), "J" | "JACK" => String::from("JACK"), "B" | "BOAT" => String::from("BOAT"), "P" | "PLANE" => String::from("PLANE"), _ => { // If none of them match, then ... println!("Invalid input; run program with '--help' option for more information. You entered '{}', so the default of 'd51' was used.", switches.kind); String::from("D51") } }; return (speed, switches.fly, kind, switches.oops); } // end of parse_opts()
scratch 5

Return back to the "Include the Images in the Main Program of the Rust Version of sl" Page