pocketstation 1.0.0

Source-aware desktop audio Session SDK
const STABLE_KEY_PREFIX: &str = "wasapi:pid:";
const CREATION_TIME_SEPARATOR: &str = ":creation-100ns:";

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) struct ProcessInstanceFingerprint {
    pub(crate) process_id: u32,
    pub(crate) creation_time_100ns: u64,
}

impl ProcessInstanceFingerprint {
    pub(crate) fn new(process_id: u32, creation_time_100ns: u64) -> Self {
        Self {
            process_id,
            creation_time_100ns,
        }
    }

    pub(crate) fn stable_key(self) -> String {
        format!(
            "{STABLE_KEY_PREFIX}{}{CREATION_TIME_SEPARATOR}{}",
            self.process_id, self.creation_time_100ns
        )
    }

    pub(crate) fn parse(stable_key: &str) -> Option<Self> {
        let body = stable_key.strip_prefix(STABLE_KEY_PREFIX)?;
        let (process_id, creation_time_100ns) = body.split_once(CREATION_TIME_SEPARATOR)?;
        Some(Self {
            process_id: process_id.parse().ok()?,
            creation_time_100ns: creation_time_100ns.parse().ok()?,
        })
    }

    pub(crate) fn matches(self, process_id: u32, creation_time_100ns: u64) -> bool {
        self.process_id == process_id && self.creation_time_100ns == creation_time_100ns
    }
}

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

    #[test]
    fn given_process_instance_when_stable_key_round_trips_then_pid_and_creation_time_are_retained()
    {
        let fingerprint = ProcessInstanceFingerprint::new(4_242, 133_980_144_000_000_000);

        assert_eq!(
            ProcessInstanceFingerprint::parse(&fingerprint.stable_key()),
            Some(fingerprint)
        );
    }

    #[test]
    fn given_legacy_pid_key_when_parsed_then_process_instance_is_rejected() {
        assert_eq!(ProcessInstanceFingerprint::parse("wasapi:pid:4242"), None);
    }

    #[test]
    fn given_reused_pid_when_creation_time_changes_then_process_instance_does_not_match() {
        let fingerprint = ProcessInstanceFingerprint::new(4_242, 100);

        assert!(!fingerprint.matches(4_242, 101));
    }

    #[test]
    fn given_different_pid_when_creation_time_matches_then_process_instance_does_not_match() {
        let fingerprint = ProcessInstanceFingerprint::new(4_242, 100);

        assert!(!fingerprint.matches(4_243, 100));
    }
}