//! Общие утилиты командной строки для всех демонстрационных программ. #![allow( dead_code, reason = "модуль компилируется отдельно для каждого примера, поэтому часть API используется в соседних примерах" )] use m::vfd::VfdConfig; use std::str::FromStr; use std::vec::IntoIter; const DEFAULT_PORT: &str = "/dev/cu.usbmodem101"; const DEFAULT_WIDTH: usize = 20; /// Общие аргументы примера: serial-порт, ширина дисплея и оставшиеся параметры. pub struct ExampleArgs { pub config: VfdConfig, pub width: usize, remaining: IntoIter, } impl ExampleArgs { /// Читает общие аргументы из командной строки и применяет безопасные значения по умолчанию. pub fn from_env() -> Self { let mut values = std::env::args().skip(1); let port_name = values.next().unwrap_or_else(|| DEFAULT_PORT.to_string()); let width = values .next() .and_then(|value| value.parse().ok()) .unwrap_or(DEFAULT_WIDTH); let config = VfdConfig::new(port_name).with_width(width); Self { width: config.width, config, remaining: values.collect::>().into_iter(), } } /// Читает следующий аргумент нужного типа или возвращает переданное значение по умолчанию. pub fn parse_or(&mut self, default: T) -> T where T: FromStr, { self.remaining .next() .and_then(|value| value.parse().ok()) .unwrap_or(default) } /// Читает следующий строковый аргумент или возвращает строку по умолчанию. pub fn string_or(&mut self, default: &str) -> String { self.remaining.next().unwrap_or_else(|| default.to_string()) } } /// Приостанавливает пример на указанное число миллисекунд. pub fn sleep_ms(delay_ms: u64) { std::thread::sleep(std::time::Duration::from_millis(delay_ms)); }