lfs_core/
device_id.rs

1use {
2    snafu::prelude::*,
3    std::str::FromStr,
4};
5
6/// Id of a device, as can be found in MetadataExt.dev().
7#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
8pub struct DeviceId {
9    pub major: u32,
10    pub minor: u32,
11}
12
13#[derive(Debug, Snafu)]
14#[snafu(display("Could not parse {string} as a device id"))]
15pub struct ParseDeviceIdError {
16    string: String,
17}
18
19impl FromStr for DeviceId {
20    type Err = ParseDeviceIdError;
21    /// this code is based on `man 5 proc` and my stochastic interpretation
22    fn from_str(string: &str) -> Result<Self, Self::Err> {
23        (|| {
24            let mut parts = string.split(':').fuse();
25            match (parts.next(), parts.next(), parts.next()) {
26                (Some(major), Some(minor), None) => {
27                    let major = major.parse().ok()?;
28                    let minor = minor.parse().ok()?;
29                    Some(Self { major, minor })
30                }
31                (Some(int), None, None) => {
32                    let int: u64 = int.parse().ok()?;
33                    Some( int.into() )
34                }
35                _ => None,
36            }
37        })().with_context(|| ParseDeviceIdSnafu { string })
38    }
39}
40
41impl From<u64> for DeviceId {
42    fn from(num: u64) -> Self {
43        Self {
44            major: (num >> 8) as u32,
45            minor: (num & 0xFF) as u32,
46        }
47    }
48}
49
50impl DeviceId {
51    pub fn new(major: u32, minor: u32) -> Self {
52        Self { major, minor }
53    }
54}
55
56#[test]
57fn test_from_str() {
58    assert_eq!(DeviceId::new(8, 16), DeviceId::from_str("8:16").unwrap());
59}
60
61#[test]
62fn test_from_u64() {
63    assert_eq!(DeviceId::new(8, 16), DeviceId::from(2064u64));
64}