proc-tree 0.1.1

Linux process tree: snapshot, incremental maintenance via fork/exec events, ancestry chain queries, PID reuse detection
Documentation
//! Process tree types: events, links, and node definitions.

use std::fmt;

// ---- Process events (decoupled from proc-connector) ----

/// A process lifecycle event. Decoupled from any specific event source
/// (proc-connector, audit, etc.) so users can adapt their own events.
#[derive(Debug, Clone)]
pub enum ProcEvent {
    /// A new process was created. `parent_pid` is the parent.
    Fork {
        child_pid: u32,
        parent_pid: u32,
        timestamp_ns: u64,
    },
    /// A process executed a new program. Its cmd/user may have changed.
    Exec { pid: u32, timestamp_ns: u64 },
    /// A process exited. The node is preserved for historical chain lookups.
    Exit { pid: u32 },
}

// ---- ProcessLink (structured chain element) ----

/// A single entry in a process ancestry chain.
///
/// Displayed as `"pid|cmd|user"` by the `Display` impl.
///
/// ```
/// use proc_tree::ProcessLink;
///
/// let link = ProcessLink { pid: 102, cmd: "touch".into(), user: "root".into() };
/// assert_eq!(link.to_string(), "102|touch|root");
/// ```
///
/// A chain is a `Vec<ProcessLink>` ordered from child to ancestor.
#[derive(Debug, Clone)]
pub struct ProcessLink {
    pub pid: u32,
    pub cmd: String,
    pub user: String,
}

impl fmt::Display for ProcessLink {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}|{}|{}", self.pid, self.cmd, self.user)
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn process_link_display_format() {
        let link = ProcessLink {
            pid: 42,
            cmd: "bash".into(),
            user: "root".into(),
        };
        assert_eq!(link.to_string(), "42|bash|root");
    }

    #[test]
    fn process_link_clone() {
        let link = ProcessLink {
            pid: 1,
            cmd: "init".into(),
            user: "root".into(),
        };
        let link2 = link.clone();
        assert_eq!(link.pid, link2.pid);
        assert_eq!(link.cmd, link2.cmd);
        assert_eq!(link.user, link2.user);
    }

    #[test]
    fn proc_event_clone() {
        let e = ProcEvent::Fork {
            child_pid: 100,
            parent_pid: 1,
            timestamp_ns: 42,
        };
        let e2 = e.clone();
        match e2 {
            ProcEvent::Fork {
                child_pid,
                parent_pid,
                timestamp_ns,
            } => {
                assert_eq!(child_pid, 100);
                assert_eq!(parent_pid, 1);
                assert_eq!(timestamp_ns, 42);
            }
            _ => panic!("expected Fork"),
        }
    }
}