1use std::fs::File;
19use std::io::{self, BufRead, BufReader};
20
21#[derive(Debug, PartialEq)]
23pub struct Module {
24 pub module: String,
26 pub size: u64,
28 pub used_by: Vec<String>
30}
31
32impl Module {
33 pub fn parse(line: &str) -> io::Result<Module> {
35 let mut parts = line.split(' ');
36
37 let name = parts.next().ok_or_else(|| io::Error::new(
38 io::ErrorKind::InvalidData,
39 "module name not found"
40 ))?;
41
42 let size = parts.next().ok_or_else(|| io::Error::new(
43 io::ErrorKind::InvalidData,
44 "size not found"
45 ))?;
46
47 let used_by = parts.nth(1).ok_or_else(|| io::Error::new(
48 io::ErrorKind::InvalidData,
49 "used_by not found"
50 ))?;
51
52 Ok(Module {
53 module: name.to_string(),
54 size: size.parse::<u64>().map_err(|_| io::Error::new(
55 io::ErrorKind::InvalidData,
56 "module size is not a number"
57 ))?,
58 used_by: if used_by == "-" {
59 vec![]
60 } else {
61 used_by.split(',')
62 .map(String::from)
63 .filter(|x| !x.is_empty())
64 .collect()
65 }
66 })
67 }
68
69 pub fn parse_from<'a, I: Iterator<Item = &'a str>>(lines: I) -> io::Result<Vec<Module>> {
71 lines.map(Self::parse).collect()
72 }
73
74 pub fn all() -> io::Result<Vec<Module>> {
76 ModuleIter::new()?.collect()
77 }
78}
79
80pub struct ModuleIter {
82 file: BufReader<File>,
83 buffer: String,
84}
85
86impl ModuleIter {
87 pub fn new() -> io::Result<Self> {
88 Ok(Self {
89 file: BufReader::new(File::open("/proc/modules")?),
90 buffer: String::with_capacity(512),
91 })
92 }
93}
94
95impl Iterator for ModuleIter {
96 type Item = io::Result<Module>;
97
98 fn next(&mut self) -> Option<Self::Item> {
99 self.buffer.clear();
100 match self.file.read_line(&mut self.buffer) {
101 Ok(read) if read == 0 => None,
102 Ok(_) => Some(Module::parse(&self.buffer)),
103 Err(why) => Some(Err(why))
104 }
105 }
106}
107
108#[cfg(test)]
109mod tests {
110 use super::*;
111
112 const SAMPLE: &str = r#"snd_hda_intel 40960 9 - Live 0x0000000000000000
113snd_hda_codec 126976 4 snd_hda_codec_hdmi,snd_hda_codec_realtek,snd_hda_codec_generic,snd_hda_intel, Live 0x0000000000000000
114snd_hda_core 81920 5 snd_hda_codec_hdmi,snd_hda_codec_realtek,snd_hda_codec_generic,snd_hda_intel,snd_hda_codec, Live 0x0000000000000000
115nvidia_drm 40960 11 - Live 0x0000000000000000 (POE)"#;
116
117 #[test]
118 fn modules() {
119 assert_eq!(
120 Module::parse_from(SAMPLE.lines()).unwrap(),
121 vec![
122 Module {
123 module: "snd_hda_intel".into(),
124 size: 40960,
125 used_by: vec![]
126 },
127 Module {
128 module: "snd_hda_codec".into(),
129 size: 126_976,
130 used_by: vec![
131 "snd_hda_codec_hdmi".into(),
132 "snd_hda_codec_realtek".into(),
133 "snd_hda_codec_generic".into(),
134 "snd_hda_intel".into(),
135 ]
136 },
137 Module {
138 module: "snd_hda_core".into(),
139 size: 81920,
140 used_by: vec![
141 "snd_hda_codec_hdmi".into(),
142 "snd_hda_codec_realtek".into(),
143 "snd_hda_codec_generic".into(),
144 "snd_hda_intel".into(),
145 "snd_hda_codec".into(),
146 ]
147 },
148 Module {
149 module: "nvidia_drm".into(),
150 size: 40960,
151 used_by: vec![]
152 },
153 ]
154 )
155 }
156}