1use {
2 snafu::prelude::*,
3 std::{
4 fmt,
5 str::FromStr,
6 },
7};
8
9#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
11pub struct DeviceId {
12 pub major: u32,
13 pub minor: u32,
14}
15
16#[derive(Debug, Snafu)]
17#[snafu(display("Could not parse {string} as a device id"))]
18pub struct ParseDeviceIdError {
19 string: String,
20}
21
22impl fmt::Display for DeviceId {
23 fn fmt(
24 &self,
25 f: &mut fmt::Formatter,
26 ) -> fmt::Result {
27 write!(f, "{}:{}", self.major, self.minor)
28 }
29}
30
31impl FromStr for DeviceId {
32 type Err = ParseDeviceIdError;
33 fn from_str(string: &str) -> Result<Self, Self::Err> {
35 (|| {
36 let mut parts = string.split(':').fuse();
37 match (parts.next(), parts.next(), parts.next()) {
38 (Some(major), Some(minor), None) => {
39 let major = major.parse().ok()?;
40 let minor = minor.parse().ok()?;
41 Some(Self { major, minor })
42 }
43 (Some(int), None, None) => {
44 let int: u64 = int.parse().ok()?;
45 Some(int.into())
46 }
47 _ => None,
48 }
49 })()
50 .with_context(|| ParseDeviceIdSnafu { string })
51 }
52}
53
54impl From<u64> for DeviceId {
55 fn from(num: u64) -> Self {
56 let dev = num as libc::dev_t;
58 Self {
59 major: libc::major(dev) as u32,
60 minor: libc::minor(dev) as u32,
61 }
62 }
63}
64
65impl DeviceId {
66 pub fn new(
67 major: u32,
68 minor: u32,
69 ) -> Self {
70 Self { major, minor }
71 }
72}
73
74#[test]
75fn test_from_str() {
76 assert_eq!(DeviceId::new(8, 16), DeviceId::from_str("8:16").unwrap());
77}
78