lfs_core/
device_id.rs

1use {
2    snafu::prelude::*,
3    std::{
4        fmt,
5        str::FromStr,
6    },
7};
8
9/// Id of a device, as can be found in MetadataExt.dev().
10#[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    /// this code is based on `man 5 proc` and my stochastic interpretation
34    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        // need to use libc, bit format is platform-dependent
57        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