1use crate::device;
5use anyhow::anyhow;
6use std::{fmt, str};
7
8#[derive(Copy, Clone, Debug, Default, PartialEq)]
10pub struct Filter {
11 pub bus: u8,
12 pub dev: Option<u8>,
13 pub func: Option<u8>,
14}
15
16impl Filter {
17 pub fn matches(&self, device: &device::Device<'_>) -> bool {
18 if device.device.bus_id != self.bus {
19 return false;
20 }
21
22 if let Some(dev) = &self.dev {
23 if device.device.device_id != *dev {
24 return false;
25 }
26 }
27
28 if let Some(func) = &self.func {
29 if device.device.function_id != *func {
30 return false;
31 }
32 }
33
34 true
35 }
36}
37
38impl std::fmt::Display for Filter {
39 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
40 write!(f, "{:02x}:", self.bus)?;
41 if let Some(dev) = self.dev {
42 write!(f, "{:02x}:", dev)?;
43 } else {
44 write!(f, "**:")?;
45 }
46 if let Some(func) = self.func {
47 write!(f, "{:1x}:", func)
48 } else {
49 write!(f, "*")
50 }
51 }
52}
53
54impl str::FromStr for Filter {
55 type Err = anyhow::Error;
56
57 fn from_str(s: &str) -> Result<Self, Self::Err> {
58 let vs: Vec<char> = s.chars().collect();
63 if s.len() == 1 || s.len() == 4 || s.len() == 6 {
64 return Err(anyhow!("filter is incomplete."));
65 }
66
67 if s.len() >= 3 && vs[2] != ':' {
68 return Err(anyhow!(format!("expected ':', but found '{}' in position {}", vs[2], 2)));
69 }
70
71 if s.len() >= 6 && vs[5] != '.' {
72 return Err(anyhow!(format!("expected '.', but found '{}' in position {}", vs[5], 5)));
73 }
74
75 if s.len() > 7 {
76 return Err(anyhow!("filter is too long."));
77 }
78
79 let bus = u8::from_str_radix(&s[0..2], 16)?;
80 let dev = if s.len() >= 5 { Some(u8::from_str_radix(&s[3..5], 16)?) } else { None };
81 let func = if s.len() == 7 { Some(u8::from_str_radix(&s[6..7], 16)?) } else { None };
82
83 Ok(Filter { bus, dev, func })
84 }
85}