Tags: #rust #exercise #io #file #semver #trait
#![allow(unused)]
use std::{
fmt::Display,
fs::File,
io::{BufRead, BufReader, Read},
};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
struct SemVer {
major: u16,
minor: u16,
patch: u16,
}
impl SemVer {
fn new(major: u16, minor: u16, patch: u16) -> SemVer {
SemVer {
major,
minor,
patch,
}
}
fn new_short(major: u16) -> SemVer {
Self::new(major, 0, 0)
}
fn info(&self) {
println!(
"hi, I'm a semver: {}.{}.{}",
self.major, self.minor, self.patch
)
}
fn patch(&mut self) -> &mut u16 {
&mut self.patch
}
}
impl Default for SemVer {
fn default() -> Self {
Self::new_short(1)
}
}
impl Display for SemVer {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}.{}.{}", self.major, self.minor, self.patch)
}
}
// http://doc.rust-lang.org/1.59.0/std/convert/trait.From.html
impl From<&str> for SemVer {
fn from(s: &str) -> Self {
let vs: Vec<u16> = s.split('.').filter_map(|item| item.parse().ok()).collect();
assert!(vs.len() == 3);
SemVer {
major: vs[0],
minor: vs[1],
patch: vs[2],
}
}
}
#[derive(Debug)]
struct Program {
name: String,
release_history: Vec<SemVer>,
}
fn main() -> Result<(), std::io::Error> {
// create a `Vec` to hold the list of programs
let mut programs: Vec<Program> = Vec::new();
// open "releases.txt", bail on error
let f = File::open("releases.txt")?;
let reader = BufReader::new(f);
// use a `BufReader` to iterate over the lines of the file handle
// if the line can be read (it might be invalid data), split it on ","
// take the first element of your split - that's the name
// the rest is a list of &str slices that each can be MAPPED INTO a SemVer!
// we're still in iterator land - time to collect and push the result to our program vec
//
// TODO: Investigate reducing down with either .map or .filter_map.
for line in reader.lines().flatten() {
let line: Vec<&str> = line.split(',').collect();
let program = line[0];
if !program.is_empty() {
let versions = line[1..].iter().filter(|item| !item.is_empty());
let mut semvers: Vec<SemVer> = Vec::new();
for version in versions {
semvers.push(SemVer::from(*version))
}
if !semvers.is_empty() {
programs.push(Program{
name: program.to_string(),
release_history: semvers,
});
}
}
}
// finally, print the program vec.
println!("{:#?}", programs);
Ok(())
}
hello-world,0.0.1,0.0.5,1.0.0
no-versions-with-comma,
semver-training,0.0.1
no-versions-no-comma
foo-with-sparse-array-of-versions,1.0.1,,2.0.0
file-io,0.1.5,1.0.1,2.0.0,2.0.5