解析/ proc / cpuinfo失败

时间:2019-01-16 20:17:17

标签: rust

我正在尝试在Linux上解析/proc/cpuinfo,并且遇到了一些麻烦。

我想退货:

  • 型号名称
  • 核心
  • 兄弟姐妹

我想将它们作为结构返回,但是我对所有返回它们的东西感到满意。

use std::{
    collections::HashMap,
    fmt,
    fs::File,
    io::{self, Read},
};

pub struct CPUInfo {
    pub model_name: String,
    pub cores: u16,
}

#[derive(Debug)]
pub enum Error {
    UnsupportedSystem,
    //ExecFailed(io::Error),
    IO(io::Error),
    Unknown,
}

impl fmt::Display for Error {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        use self::Error::*;
        match *self {
            UnsupportedSystem => write!(fmt, "System is not supported"),
            //ExecFailed(ref e) => write!(fmt, "Execution failed: {}", e),
            IO(ref e) => write!(fmt, "IO error: {}", e),
            Unknown => write!(fmt, "An unknown error occurred"),
        }
    }
}

impl std::error::Error for Error {
    fn description(&self) -> &str {
        use self::Error::*;
        match *self {
            UnsupportedSystem => "unsupported system",
            //ExecFailed(_) => "execution failed",
            IO(_) => "io error",
            Unknown => "unknown error",
        }
    }

    fn cause(&self) -> Option<&std::error::Error> {
        use self::Error::*;
        match *self {
            UnsupportedSystem => None,
            //ExecFailed(ref e) => Some(e),
            IO(ref e) => Some(e),
            Unknown => None,
        }
    }
}

impl From<io::Error> for Error {
    fn from(e: io::Error) -> Error {
        Error::IO(e)
    }
}

pub fn get_cpu() -> Result<CPUInfo, Error> {
    if cfg!(target_os = "linux") {
        let mut s = String::new();
        File::open("/proc/cpuinfo")?.read_to_string(&mut s)?;
        let mut cpuinfo_hashmap = HashMap::new();
        for line in s.lines() {
            let mut split_line = line.split_whitespace();
            let label = split_line.next();
            let value = split_line.next();
            if value.is_some() && label.is_some() {
                let label = label.unwrap().split(':').nth(0).ok_or(Error::Unknown)?;
                let value = value.unwrap().to_string();
                cpuinfo_hashmap.insert(label, value.to_string());
            }
        }

        Ok(CPUInfo {
            model_name: {
                let m = cpuinfo_hashmap.get("model name").ok_or(Error::Unknown)?;
                m.to_string()
            },
            cores: {
                let c = cpuinfo_hashmap.get("siblings").ok_or(Error::Unknown)?;
                let cores: u16 = c.parse::<u16>().unwrap();
                cores
            },
        })
    } else {
        Err(Error::UnsupportedSystem)
    }
}

fn main() {
    let cpu = get_cpu().expect("error getting cpu");
    println!("CPU: {} {}", cpu.model_name, cpu.cores)
}

Rust Playground

此代码失败:

thread 'main' panicked at 'error getting cpu: Unknown', libcore/result.rs:1009:5
note: Run with `RUST_BACKTRACE=1` for a backtrace.

然后Reddit上的某人建议使用derive_builder,所以我尝试了:

pub fn cpu_info() -> Result<CPUInfo, Error> {
    let file = File::open("/proc/cpuinfo")?;
    let buf_reader = BufReader::new(file);
    let mut builder = &mut CPUInfoBuilder::default();

    for line in buf_reader.lines() {
        let line = line.unwrap();
        let kv: Vec<_> = line.splitn(2, ':').map(|s| s.trim()).collect();

        builder = match kv.as_slice() {
            ["model name", v] => builder.model_name(v.to_string()),
            ["cpu cores", v] => builder.cores(v.parse::<u16>().ok().ok_or(Error::Unknown)?),
            [_, _] => builder,
            [_] => builder,
            _ => unreachable!(),
        }
    }
    Ok(builder.build().expect("failed"))
}

还会编译并失败。

1 个答案:

答案 0 :(得分:1)

您的代码有一些问题。我讨厌只为他们重写一个人的代码,但是即使编译成功后,您要做的某些事情也无法正常工作。下面的代码为您提供了一些指针。

以下代码可构建您期望的结构,打印到HashMap进行调试,然后在结构中打印信息以方便查看:

use std::{
    fs::File,
    io::{BufRead, BufReader, Error, ErrorKind},
};

use hashbrown::HashMap;

fn main() {
    let cpu = get_cpu().unwrap();
    println!("{}{}", cpu.model_name, cpu.cores);
}

pub struct CPUInfo {
    pub model_name: String,
    pub cores: u16,
}

pub fn get_cpu() -> Result<CPUInfo, Error> {
    if cfg!(target_os = "linux") {
        let f = File::open("/proc/cpuinfo")?;
        let reader = BufReader::new(f);
        let mut cpuinfo_hashmap: HashMap<String, String> = HashMap::new();

        for line in reader.lines().take(20) {
            let line = line.unwrap();
            let mut split_line = line.split(':');
            let label = split_line.next();
            let value = split_line.next();
            if value.is_some() && label.is_some() {
                let label = label.unwrap().trim().to_string();
                let value = value.unwrap().trim().to_string();
                cpuinfo_hashmap.insert(label, value);
            }
        }

        println!("{:?}", cpuinfo_hashmap);

        Ok(CPUInfo {
            model_name: {
                let m = cpuinfo_hashmap
                    .get("model name")
                    .ok_or(Error::from(ErrorKind::InvalidData))?;
                m.clone()
            },
            cores: {
                let c = cpuinfo_hashmap
                    .get("siblings")
                    .ok_or(Error::from(ErrorKind::InvalidData))?;
                let cores: u16 = c.parse::<u16>().unwrap_or(0);
                cores
            },
        })
    } else {
        Err(Error::from(ErrorKind::Other))
    }
}

您的代码有问题:

  1. 您没有发布进口商品,这对我来说真的很困难
  2. 您不能BufRead String,需要直接BufRead File
  3. 您的line变量在使用前需要解开
  4. 行需要展开并绑定到变量,以防止借入检查错误
  5. 您首先在空白处分割行,然后再在":"字符上分割,这将为您提供一个HashMap,其中包含20个看起来像"processor" : ":"的条目