bspc-rs 0.1.1

Implementation of bspc in Rust
Documentation
use std::env;
use std::io::{self, BufRead, BufReader, Write};
use std::os::unix::net::UnixStream;

use crate::errors::ReplyError;

fn locate_socket() -> String {
    if let Ok(path) = env::var("BSPWM_SOCKET") {
        path
    } else if let Ok(display) = env::var("DISPLAY") {
        let mut parsed = display.split(':');
        let host = if let Some(x) = parsed.next() { x } else { "" };

        let mut parsed = parsed
            .next()
            .expect("Error occured while parsing DISPLAY variable")
            .split('.');

        let display_num = if let Some(x) = parsed.next() { x } else { "" };

        let screen_num = if let Some(x) = parsed.next() { x } else { "0" };

        format!("/tmp/bspwm{host}_{display_num}_{screen_num}-socket")
    } else {
        panic!("$DISPLAY variable is not set, can't proceed ...");
    }
}

pub(crate) fn connect() -> io::Result<UnixStream> {
    let socket_path = locate_socket();
    let stream = UnixStream::connect(socket_path)?;

    Ok(stream)
}

pub trait BspcCommunication {
    fn send_message(&mut self, message: &str) -> io::Result<()>;
    fn receive_message(&mut self) -> Result<Vec<String>, ReplyError>;
}

impl BspcCommunication for UnixStream {
    fn send_message(&mut self, message: &str) -> io::Result<()> {
        self.write_all(message.as_bytes())?;
        self.flush()?;

        Ok(())
    }

    fn receive_message(&mut self) -> Result<Vec<String>, ReplyError> {
        let buf_reader = BufReader::new(self);
        let mut lines_iter = buf_reader.lines();
        let mut result = Vec::new();

        let first_line = match lines_iter.next() {
            Some(x) => x?,
            None => {
                return Err(ReplyError::NoReply);
            }
        };
        let first_line = first_line.as_bytes();

        if first_line[0] == 7 {
            let reply = String::from_utf8(first_line[1..].to_vec())?;
            return Err(ReplyError::RequestFailed(reply));
        } else {
            let first_line = String::from_utf8(first_line.to_vec())?;
            result.push(first_line);
        }

        for line in lines_iter {
            result.push(line?);
        }

        Ok(result)
    }
}