can-utils-rs 0.2.0

A pure Rust CLI utility for managing and manipulating CAN interfaces and printing pretty CAN data.
Documentation
use std::fmt;

#[derive(Debug, Clone)]
pub struct CanBitrate {
    pub bitrate: u32,
}

impl fmt::Display for CanBitrate {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let label = match self.bitrate {
            1_000_000 => "1 Mbit".to_string(),
            _ if self.bitrate >= 1_000 => format!("{} kbit", self.bitrate / 1_000),
            _ => self.bitrate.to_string(),
        };

        write!(f, "{:<10} ({})", label, self.bitrate)
    }
}

pub fn can_bitrates() -> Vec<CanBitrate> {
    let mut bitrates = vec![
        CanBitrate { bitrate: 10_000 },
        CanBitrate { bitrate: 20_000 },
        CanBitrate { bitrate: 50_000 },
        CanBitrate { bitrate: 125_000 },
        CanBitrate { bitrate: 250_000 },
        CanBitrate { bitrate: 500_000 },
        CanBitrate { bitrate: 1_000_000 },
    ];

    bitrates.sort_by(|a, b| b.bitrate.cmp(&a.bitrate));
    bitrates
}

#[derive(Debug, Clone)]
pub struct SlcanSpeed {
    pub bitrate: u32,
    pub flag: &'static str,
}

impl fmt::Display for SlcanSpeed {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let label = match self.bitrate {
            1_000_000 => "1 Mbit".to_string(),
            _ if self.bitrate >= 1_000 => format!("{} kbit", self.bitrate / 1_000),
            _ => self.bitrate.to_string(),
        };

        write!(f, "{:<10} ({}, {})", label, self.bitrate, self.flag)
    }
}

pub fn slcan_speeds() -> Vec<SlcanSpeed> {
    let mut speeds = vec![
        SlcanSpeed {
            bitrate: 10_000,
            flag: "s0",
        },
        SlcanSpeed {
            bitrate: 20_000,
            flag: "s1",
        },
        SlcanSpeed {
            bitrate: 50_000,
            flag: "s2",
        },
        SlcanSpeed {
            bitrate: 100_000,
            flag: "s3",
        },
        SlcanSpeed {
            bitrate: 125_000,
            flag: "s4",
        },
        SlcanSpeed {
            bitrate: 250_000,
            flag: "s5",
        },
        SlcanSpeed {
            bitrate: 500_000,
            flag: "s6",
        },
        SlcanSpeed {
            bitrate: 800_000,
            flag: "s7",
        },
        SlcanSpeed {
            bitrate: 1_000_000,
            flag: "s8",
        },
    ];

    speeds.sort_by(|a, b| b.bitrate.cmp(&a.bitrate));
    speeds
}

#[derive(Debug, Clone)]
pub enum CanMode {
    Native,
    Slcan,
    Virtual,
}

impl fmt::Display for CanMode {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            CanMode::Native => write!(f, "Native CAN bus"),
            CanMode::Slcan => write!(f, "Non-native CAN bus (slcand)"),
            CanMode::Virtual => write!(f, "Virtual CAN bus (vcan)"),
        }
    }
}

#[derive(Debug, Clone)]
pub struct NativeConfig {
    pub iface: String,
    pub bitrate: CanBitrate,
}

#[derive(Debug, Clone)]
pub struct SlcanConfig {
    pub tty: String,
    pub iface: String,
    pub speed: SlcanSpeed,
    pub uart_baud: u32,
}

#[derive(Debug, Clone)]
pub struct VirtualConfig {
    pub iface: String,
}

#[derive(Debug, Clone)]
pub enum AppConfig {
    Native(NativeConfig),
    Slcan(SlcanConfig),
    Virtual(VirtualConfig),
}

impl AppConfig {
    pub fn iface(&self) -> &str {
        match self {
            AppConfig::Native(cfg) => &cfg.iface,
            AppConfig::Slcan(cfg) => &cfg.iface,
            AppConfig::Virtual(cfg) => &cfg.iface,
        }
    }

    pub fn set_iface(&mut self, new_iface: String) {
        match self {
            AppConfig::Native(cfg) => cfg.iface = new_iface,
            AppConfig::Slcan(cfg) => cfg.iface = new_iface,
            AppConfig::Virtual(cfg) => cfg.iface = new_iface,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ExistingIfaceAction {
    Replace,
    Rename,
    Skip,
    Cancel,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum InterfaceResolution {
    Proceed,
    SkipSetup,
}