bim-core 0.15.4

Client core for bench.im.
Documentation
use std::fmt;

use serde::{Deserialize, Serialize};

const WIDTH: [(u32, u8); 38] = [
    (126, 1),
    (159, 0),
    (687, 1),
    (710, 0),
    (711, 1),
    (727, 0),
    (733, 1),
    (879, 0),
    (1154, 1),
    (1161, 0),
    (4347, 1),
    (4447, 2),
    (7467, 1),
    (7521, 0),
    (8369, 1),
    (8426, 0),
    (9000, 1),
    (9002, 2),
    (11021, 1),
    (12350, 2),
    (12351, 1),
    (12438, 2),
    (12442, 0),
    (19893, 2),
    (19967, 1),
    (55203, 2),
    (63743, 1),
    (64106, 2),
    (65039, 1),
    (65059, 0),
    (65131, 2),
    (65279, 1),
    (65376, 2),
    (65500, 1),
    (65510, 2),
    (120831, 1),
    (262141, 2),
    (1114109, 1),
];

fn get_width(o: u32) -> u8 {
    if o == 0xE || o == 0xF {
        return 0;
    }
    for (num, wid) in WIDTH {
        if o <= num {
            return wid;
        }
    }
    1
}

pub fn justify_name(name: &str, length: u8, left_right: bool) -> String {
    let mut name_width = 0;
    let mut justified_name = String::new();

    for c in name.chars() {
        let w = get_width(c as u32);
        if name_width + w < length {
            name_width += w;
            justified_name.push(c);
        }
    }

    if name_width < length {
        let space_count = length - name_width;
        let spaces = " ".repeat(space_count as usize);
        if left_right {
            justified_name += spaces.as_str();
        } else {
            justified_name = spaces + &justified_name;
        }
    }
    justified_name
}

#[derive(Serialize, Deserialize)]
pub struct SpeedTestResult {
    #[serde(serialize_with = "serialize_f64")]
    upload: f64,
    upload_status: String,
    #[serde(serialize_with = "serialize_f64")]
    download: f64,
    download_status: String,
    #[serde(serialize_with = "serialize_f64")]
    latency: f64,
    #[serde(serialize_with = "serialize_f64")]
    jitter: f64,
}

fn serialize_f64<S>(x: &f64, serializer: S) -> Result<S::Ok, S::Error>
where
    S: serde::Serializer,
{
    let s = format!("{:.1}", x);
    serializer.serialize_str(&s)
}

impl SpeedTestResult {
    pub fn build(
        upload: f64,
        upload_status: String,
        download: f64,
        download_status: String,
        latency: f64,
        jitter: f64,
    ) -> SpeedTestResult {
        return SpeedTestResult {
            upload,
            upload_status,
            download,
            download_status,
            latency,
            jitter,
        };
    }

    pub fn text(&self) -> String {
        let upload = justify_name(&format!("{:.1}", &self.upload), 9, false);
        let upload_status = justify_name(&self.upload_status, 5, false);
        let download = justify_name(&format!("{:.1}", &self.download), 9, false);
        let download_status = justify_name(&self.download_status, 5, false);
        let latency = justify_name(&format!("{:.1}", &self.latency), 7, false);
        let jitter = justify_name(&format!("{:.1}", &self.jitter), 7, false);

        format!("{upload},{upload_status},{download},{download_status},{latency},{jitter}")
    }
}

impl fmt::Display for SpeedTestResult {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(
            f,
            "Upload {:.1}Mbps {}, Download: {:.1}Mbps {}, Latency {:.1}, Jitter {:.1}",
            self.upload,
            self.upload_status,
            self.download,
            self.download_status,
            self.latency,
            self.jitter
        )
    }
}