Exercise from advent of code (day 3)

You can find the exercise on: https://adventofcode.com/2022/day/3

use std::collections::HashSet;
use std::fs::File;
use std::io::{self, BufRead};
use std::path::Path;

fn resolve_priority(character: char) -> i32 {
    let start_ascii_code_lowercase = 'a' as i32;
    let start_ascii_code_uppercase = 'A' as i32;
    let char_in_ascii_code = character as i32;

    if char_in_ascii_code < start_ascii_code_lowercase {
        return char_in_ascii_code - start_ascii_code_uppercase + 27;
    }
    char_in_ascii_code - start_ascii_code_lowercase + 1
}

fn resolve_unique_chars(rucksack: &str) -> HashSet<char> {
    let characters: HashSet<char> = rucksack.chars().collect();
    characters
}

fn resolve_compartments(rucksack: &str) -> (&str, &str) {
    let size_compartments = rucksack.len() / 2;
    rucksack.split_at(size_compartments)
}

fn find_duplicate_char(rucksack: &str) -> char {
    let compartments = resolve_compartments(rucksack);

    for item in resolve_unique_chars(rucksack) {
        if compartments.0.contains(item) && compartments.1.contains(item) {
            return item;
        }
    }
    panic!("no duplicates found!")
}

fn calculate_score(rucksack: &str) -> i32 {
    let duplicate_item = find_duplicate_char(rucksack);
    resolve_priority(duplicate_item)
}

fn main() {
    let mut total_score = 0;
    if let Ok(lines) = read_lines("./input.txt") {
        for line in lines {
            if let Ok(input_line) = line {
                total_score += calculate_score(&input_line);
            }
        }
    }

    println!("total score: {:?}", total_score);
}

// The output is wrapped in a Result to allow matching on errors
// Returns an Iterator to the Reader of the lines of the file.
fn read_lines<P>(filename: P) -> io::Result<io::Lines<io::BufReader<File>>>
    where P: AsRef<Path>, {
    let file = File::open(filename)?;
    Ok(io::BufReader::new(file).lines())
}

#[cfg(test)]
mod tests {
    // Note this useful idiom: importing names from outer (for mod tests) scope.
    use super::*;

    #[test]
    fn test_priority() {
        assert_eq!(resolve_priority('a'), 1, "'a' should be 1");
        assert_eq!(resolve_priority('z'), 26, "'z' should be 26");
        assert_eq!(resolve_priority('A'), 27, "'A' should be 27");
        assert_eq!(resolve_priority('Z'), 52, "'Z' should be 52");
    }

    #[test]
    fn test_example_first_rucksack() {
        assert_eq!(calculate_score("vJrwpWtwJgWrhcsFMMfFFhFp"), 16, "first rucksack should have priority 16");
        assert_eq!(calculate_score("jqHRNqRjqzjGDLGLrsFMfFZSrLrFZsSL"), 38, "second rucksack should have priority 16");
        assert_eq!(calculate_score("PmmdzqPrVvPwwTWBwg"), 42, "third rucksack should have priority 16");
        assert_eq!(calculate_score("wMqvLMZHhHMvwLHjbvcjnnSBnvTQFn"), 22, "fourth rucksack should have priority 16");
        assert_eq!(calculate_score("ttgJtRGJQctTZtZT"), 20, "fifth rucksack should have priority 16");
        assert_eq!(calculate_score("CrZsJsPPZsGzwwsLwLmpwMDw"), 19, "sixth rucksack should have priority 16");
    }
}