malvin 0.2.5

Non-interactive research and coding agent
use std::path::PathBuf;

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct HerdrEnv {
    pub socket_path: PathBuf,
    pub pane_id: String,
}

impl HerdrEnv {
    #[must_use]
    pub fn from_os_env() -> Option<Self> {
        from_values(
            std::env::var_os("HERDR_ENV"),
            std::env::var_os("HERDR_SOCKET_PATH"),
            std::env::var_os("HERDR_PANE_ID"),
        )
    }
}

#[must_use]
pub fn from_values(
    herdr_env: Option<std::ffi::OsString>,
    socket_path: Option<std::ffi::OsString>,
    pane_id: Option<std::ffi::OsString>,
) -> Option<HerdrEnv> {
    if herdr_env.as_deref() != Some(std::ffi::OsStr::new("1")) {
        return None;
    }
    let socket = socket_path?.into_string().ok()?;
    let pane = pane_id?.into_string().ok()?;
    if socket.is_empty() || pane.is_empty() {
        return None;
    }
    Some(HerdrEnv {
        socket_path: PathBuf::from(socket),
        pane_id: pane,
    })
}

#[cfg(test)]
mod tests {
    use super::{HerdrEnv, from_values};
    use std::ffi::OsString;

    #[test]
    fn gate_requires_exact_env_one_and_nonempty_socket_pane() {
        assert!(from_values(None, Some("s".into()), Some("p".into())).is_none());
        assert!(from_values(Some("0".into()), Some("s".into()), Some("p".into())).is_none());
        assert!(from_values(Some("1".into()), Some("".into()), Some("p".into())).is_none());
        assert!(from_values(Some("1".into()), Some("s".into()), Some("".into())).is_none());
        assert_eq!(
            from_values(
                Some("1".into()),
                Some("/tmp/h.sock".into()),
                Some("pane".into())
            ),
            Some(HerdrEnv {
                socket_path: "/tmp/h.sock".into(),
                pane_id: "pane".into(),
            })
        );
    }

    #[test]
    fn from_os_env_matches_process_env_snapshot() {
        let _ = HerdrEnv::from_os_env();
        let _ = OsString::new();
    }
}