pub const VENDOR: u16 = 0x04B0;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Model {
Ls40,
Ls50,
Ls4000,
Ls5000,
Ls8000,
Ls9000,
}
const MODELS: &[(Model, &str, Option<u16>)] = &[
(Model::Ls9000, "LS-9000", None),
(Model::Ls8000, "LS-8000", None),
(Model::Ls5000, "LS-5000", Some(0x4002)),
(Model::Ls4000, "LS-4000", None),
(Model::Ls50, "LS-50", Some(0x4001)),
(Model::Ls40, "LS-40", Some(0x4000)),
];
impl Model {
pub fn from_product(product: &str) -> Option<Self> {
MODELS
.iter()
.find(|(_, name, _)| product.contains(name))
.map(|(model, _, _)| *model)
}
pub fn from_usb(vendor: u16, product: u16) -> Option<Self> {
if vendor != VENDOR {
return None;
}
MODELS
.iter()
.find(|(_, _, pid)| *pid == Some(product))
.map(|(model, _, _)| *model)
}
pub fn usb(self) -> Option<u16> {
MODELS
.iter()
.find(|(model, _, _)| *model == self)
.and_then(|(_, _, pid)| *pid)
}
pub fn name(self) -> &'static str {
MODELS
.iter()
.find(|(model, _, _)| *model == self)
.map(|(_, name, _)| *name)
.expect("every model is in the table")
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn a_product_field_names_one_model() {
assert_eq!(Model::from_product("LS-9000 ED"), Some(Model::Ls9000));
assert_eq!(Model::from_product("LS-5000 ED"), Some(Model::Ls5000));
assert_eq!(Model::from_product("LS-50 ED"), Some(Model::Ls50));
assert_eq!(Model::from_product("LS-2000"), None);
}
#[test]
fn a_usb_unit_is_known_before_it_is_asked() {
assert_eq!(Model::from_usb(VENDOR, 0x4002), Some(Model::Ls5000));
assert_eq!(Model::from_usb(0x1234, 0x4002), None);
assert_eq!(Model::Ls5000.usb(), Some(0x4002));
assert_eq!(Model::Ls9000.usb(), None);
}
#[test]
fn the_table_agrees_with_itself() {
for (model, name, pid) in MODELS {
assert_eq!(Model::from_product(name), Some(*model));
assert_eq!(model.usb(), *pid);
assert_eq!(model.name(), *name);
if let Some(pid) = pid {
assert_eq!(Model::from_usb(VENDOR, *pid), Some(*model));
}
}
}
}