use std::{convert, ops::Index}; const B64TABLE: &str = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789._"; fn b64(data: &[u8]) -> String { let binary: Vec = data .iter() .flat_map(|b| (0..8).rev().map(move |i| (b >> i) & 1)) .collect(); let mut chunks: Vec> = binary.chunks(6).map(|s| s.to_vec()).collect(); let last = chunks.last_mut().unwrap(); if last.len() < 6 { for _ in last.len()..6 { last.push(0); } } let decimal: Vec = chunks .iter() .map(|bits| bits.iter().fold(0, |acc, &bit| (acc << 1) | bit)) .collect(); let mut converted: Vec = Vec::new(); for dec in decimal { converted.push(B64TABLE.chars().nth(dec as usize).unwrap().to_string()); } match data.len() % 3 { 1 => { converted.push("--".to_string()); } 2 => { converted.push("-".to_string()); } _ => {} } converted.join("") } pub fn compute_disc_id(first_track: u8, last_track: u8, leadout: u32, offsets: &[u32]) -> String { let mut toc = String::new(); toc.push_str(&format!("{first_track:02X}{last_track:02X}{leadout:08X}")); for i in 0..99 { let offset = offsets.get(i).copied().unwrap_or(0); toc.push_str(&format!("{:08X}", offset)); } toc } #[cfg(test)] mod tests { use super::*; #[test] fn known_example() { let first_track = 1; let last_track = 12; let leadout = 224556; let offsets = [ 150, 9078, 13528, 34182, 53768, 70987, 96424, 118425, 136793, 159514, 179777, 198006, ]; assert_eq!( compute_disc_id(first_track, last_track, leadout, &offsets), "T_prJXQSrqbnH8OE.dgOKsHm5Uw-" ); } #[test] fn base64() { assert_eq!(b64("Man".as_bytes()), "TWFu".to_string()); assert_eq!(b64("M".as_bytes()), "TQ--".to_string()); assert_eq!(b64("Ma".as_bytes()), "TWE-".to_string()); } }