pkill_lib/
process.rs

1use std::{num::ParseIntError, str::FromStr};
2
3use sysinfo::{Pid, Process, SystemExt};
4
5/// Process searching inputs
6#[derive(Debug, Clone, PartialEq, Eq)]
7pub enum ProcessQuery {
8    /// Query for process with pid
9    Pid(Pid),
10    /// Query for processes with name containing
11    Name(String),
12}
13
14impl FromStr for ProcessQuery {
15    type Err = ParseIntError;
16
17    fn from_str(s: &str) -> Result<ProcessQuery, Self::Err> {
18        let value = s.parse::<Pid>().map_or_else(
19            |_| ProcessQuery::Name(s.to_string()),
20            |pid| ProcessQuery::Pid(pid),
21        );
22        Ok(value)
23    }
24}
25
26/// Search for processes based on `query`
27///
28/// # Returns
29///
30/// A vector containing a number of processes based on the `query`
31///
32/// * [`ProcessQuery::Pid`] - A single process if one was found
33/// * [`ProcessQuery::Name`] - All processes with a name containing the query string
34///
35/// If no results were found, an empty vector will be returned
36pub fn search<'a, S: SystemExt>(sys: &'a S, query: &'a ProcessQuery) -> Vec<&'a Process> {
37    match query {
38        ProcessQuery::Pid(pid) => sys
39            .process(*pid)
40            .map_or_else(|| Vec::new(), |process| vec![process]),
41        ProcessQuery::Name(name) => sys.processes_by_name(&name).collect::<Vec<&Process>>(),
42    }
43}
44
45#[cfg(test)]
46mod tests {
47    use super::*;
48
49    #[test]
50    fn process_query_should_parse_string() -> anyhow::Result<()> {
51        let result: ProcessQuery = "argument".parse()?;
52
53        assert_eq!(result, ProcessQuery::Name("argument".to_string()));
54
55        Ok(())
56    }
57
58    #[test]
59    fn process_query_should_parse_pid() -> anyhow::Result<()> {
60        let result: ProcessQuery = "1234".parse()?;
61
62        assert_eq!(result, ProcessQuery::Pid(Pid::from(1234)));
63
64        Ok(())
65    }
66}