I’m writing a simple utility for manage the /etc/hosts file. I want it in a native language so I can make it SUID, or even better, to lock it down via capabilities. I want to remember how to code in rust. Once I get a simple bit working, I want to refactor. Here’s what I did.
Here is the functioning code:
use std::env; use std::fs; fn words_by_line<'a>(s: &'a str) -> Vec<Vec<&'a str> > { s.lines().map(|line| { line.split_whitespace().collect() }).collect() } fn main() { let args: Vec<String> = env::args().collect(); let filename = &args[1]; let _operation = &args[2]; let contents = fs::read_to_string(filename) .expect("Something went wrong reading the file"); let wbyl = words_by_line(&contents); for i in &wbyl { for j in i{ print!("{} ", j); } println!(""); } } |
Build and run with
cargo build ./target/debug/hostsman ./hosts list
And it spits out the contents of the local copy of /etc/hosts. We’ll treat this as the unit test for now.
The next step is to start working towards a switch based on the _operation variable. To do this, I want to pull the loop that dumps the file out into its own function. And to do that, I need to figure out the type of the Vector. I use the hack of introducing an error to get the compiler to tell me the type. I change the assignment line to get:
let wbyl: u8 = words_by_line(&contents); |
And that tells me:
error[E0308]: mismatched types --> src/main.rs:18:20 | 18 | let wbyl: u8 = words_by_line(&contents); | ^^^^^^^^^^^^^^^^^^^^^^^^ expected u8, found struct `std::vec::Vec` | = note: expected type `u8` found type `std::vec::Vec<std::vec::Vec<&str>>` |
So I convert the code to use that, build and run. Code now looks like this:
let wbyl: std::vec::Vec> = words_by_line(& contents) |
Now now create a function by copying the existing code block and using the variable type in the parameter list. It looks like this:
use std::env; use std::fs; fn words_by_line<'a>(s: &'a str) -> Vec<Vec<&'a str>> { s.lines().map(|line| { line.split_whitespace().collect() }).collect() } fn list(wbyl: std::vec::Vec<std::vec::Vec<&str>>){ for i in &wbyl { for j in i{ print!("{} ", j); } println!(""); } } fn main() { let args: Vec<String> = env::args().collect(); let filename = &args[1]; let _operation = &args[2]; let contents = fs::read_to_string(filename) .expect("Something went wrong reading the file"); let wbyl: std::vec::Vec<std::vec::Vec<&str>> = words_by_line(&contents); list(wbyl); } |
Now we are prepped to continue development. Next up is to parse the command and execute a different function based on it.