~skye/git/src/com.rs

view raw


/*
 * common functions and utilities
 */

use colored::Colorize;
use rand::{distributions::Alphanumeric, thread_rng, Rng};

use crate::{macros::*, now, CFG};
use std::{
    fmt::Display,
    io::{self, Write},
};

pub mod cfg {
    pub const VERSION: &str = "version 0.0.1: OXIDIZED";
}

pub mod err {
    pub const IO_ERR: i32 = 1;
    pub const DB_CON_ERR: i32 = 2;
}

pub fn page<X, Y>(t: X, b: Y) -> String
where
    String: From<X>,
    String: From<Y>,
{
    let t = String::from(t);
    let b = String::from(b);

    log!("page: t: {t:?}");
    format!(
        r#"
        <!DOCTYPE html>
        <html>
            <head>
                <title>{title} :: {t}</title>
                <meta charset="utf-8">
                <link rel="stylesheet" type="text/css" href="/style.css">
            </head>
            <body>
                <div id="head">
                    <b><a href="/">{title}</a></b>
                </div>
                <div id="page">
                    {b}
                </div>
                <div id="foot">
                    {version}
                </div>
            </body>
        </html>
        "#,
        title = match CFG["title"].as_str() {
            Some(x) => x,
            None => "badboy git",
        },
        version = cfg::VERSION
    )
}

pub fn err(m: &str, goto: &str) -> String {
    page(
        format!("error :: {m}").as_str(),
        format!(
            r#"
            <h1>{m}</h1>
            <p><a href="{goto}">go back</a></p>
            "#
        ),
    )
}

pub fn mkhash() -> String {
    thread_rng()
        .sample_iter(&Alphanumeric)
        .take(32)
        .map(char::from)
        .collect()
}

pub fn puts<T>(s: T)
where
    String: From<T>,
    T: Display,
{
    print!("{s}");
    match io::stdout().flush() {
        Ok(_) => (),
        Err(e) => eprintln!("error flushing stdout: {e}"),
    };
}

/** panic except not really because we don't want to kill the server
 * for now just log */
pub fn panic<T>(e: T) -> !
where
    String: From<T>,
    T: Display,
{
    eprintln!("{}: {e}", "fatal error".bold().red());
    std::process::exit(-1);
}

/** basename of a path */
pub fn basename(s: &str) -> &str {
    let x: Vec<&str> = s.split("/").collect();
    if x.len() > 0 {
        x[x.len() - 1]
    } else {
        ""
    }
}

/** dirname of a path */
pub fn dirname(s: &str) -> String {
    let mut x: Vec<&str> = s.split("/").collect();
    /* remove the last item, which is the basename */
    x.pop();

    if x.len() > 0 {
        x.join("/")
    } else {
        String::new()
    }
}

/** generic trim for trim_right and trim_left, taking an argument that determines
 * if the chars are reversed.
 * setting rev to true makes it a trim left, otherwise it's a trim right */
fn trim_<T>(s: T, c: char, rev: bool) -> String
where
    String: From<T>,
{
    let mut s = {
        let s = String::from(s);
        /* reverse if needed */
        if rev {
            s.chars().rev().collect::<String>()
        } else {
            s
        }
    };

    /* mutable iterator */
    let mut i = s.chars().rev().collect::<Vec<char>>();
    let mut i = i.iter_mut();

    /* pop while char == c */
    while let Some(x) = i.next() {
        if *x == c {
            let p = s.pop();
            safe_assert_eq!(p, Some(c));
        } else {
            break;
        }
    }

    if rev {
        s.chars().rev().collect::<String>()
    } else {
        s
    }
}

/** trim all chars matching c from the left */
pub fn trim_left<T>(s: T, c: char) -> String
where
    String: From<T>,
{
    trim_(s, c, true)
}

/** trim all chars matching c from the right */
pub fn trim_right<T>(s: T, c: char) -> String
where
    String: From<T>,
{
    trim_(s, c, false)
}

/**
 * turn a raw string into a "heredoc" by stripping the whitespace on
 * the beginning of each line
 */
/*
pub fn heredoc<X>(x: X) -> String
where
    String: From<X>,
{
    let x = String::from(x);
    x.split("\n").map(|x| trim_left(x, ' ')).collect::<String>()
}
*/

/** convert an int to a corresponding bool */
pub fn i64_to_bool(x: i64) -> bool {
    if x == 0 {
        false
    } else {
        true
    }
}

/** convert a bool to a corresponding int */
pub fn bool_to_i64(x: bool) -> i64 {
    if x {
        1
    } else {
        0
    }
}