base64-const 0.0.6

Base64 encode/decode with const-friendly decode and URL-safe macros
Documentation
use base64_const::{base64_decode, url_safe_util::{from_url_safe, to_url_safe}};


enum Command {
    Encode(String),
    EncodeBytes(Vec<u8>),
    Decode(String),
    EncodeUrlSafe(String),
    DecodeUrlSafe(String),
    ToUrlSafe(String),
    FromUrlSafe(String),
}

fn main() {

    const DECODED: &[u8] = &base64_decode!("TWE=");
    assert_eq!(DECODED, b"Ma");

    const LONG_DECODED: &[u8] = &base64_decode!("TWFu");
    assert_eq!(LONG_DECODED, b"Man");


    let command = args_to_command();
    match command {
        Command::Encode(value) => {
            println!("base64 encoding \"{}\"", &value);
            println!("encoded > {}", base64_const::encode(value.as_bytes()));
        },
        Command::EncodeBytes(bytes) => {
            println!("base64 encoding hex({}) \"{:02x?}\"", bytes.len(), &bytes);
            println!("encoded > {}", base64_const::encode(&bytes));
        },
        Command::Decode(value) => {
            println!("base64 decoding \"{}\"", &value);
            let result = base64_const::decode(value.as_bytes());
            println!("decode bytes > ({}) [{}]", result.len(), bytes_to_hex_string(&result));
            match std::str::from_utf8(&result) {
                Ok(result) => println!("decode utf8 > {}", result),
                Err(err) => println!("decode utf8 > failed, {}", err),
            }
        },
        Command::EncodeUrlSafe(value) => {
            println!("base64 Url-safe encoding \"{}\"", &value);
            println!("encoded > {}", to_url_safe(base64_const::encode(value.as_bytes())));
        },
        Command::DecodeUrlSafe(value) => {
            println!("base64 decoding \"{}\"", &value);
            let result = base64_const::decode(from_url_safe(value).as_bytes());
            println!("decode bytes > ({}) [{}]", result.len(), bytes_to_hex_string(&result));
            match std::str::from_utf8(&result) {
                Ok(result) => println!("decode utf8 > {}", result),
                Err(err) => println!("decode utf8 > failed, {}", err),
            }
        },
        Command::ToUrlSafe(value) => {
            println!("Url safe > {}", to_url_safe(value));
        },
        Command::FromUrlSafe(value) => {
            println!("Url Unsafe > {}", from_url_safe(value));
        }
    }
}

const DEFAULT_MSG:&str = "  cargo run -- -e <string> : encode
    cargo run -- -b <string> : encode bytes
    cargo run -- -d <string> : decode
    cargo run -- -se <string> : encode url safe
    cargo run -- -sd <string> : decode url-safe
    cargo run -- --to_url-safe <string> : convert to url safe
    cargo run -- --from-url-safe <string> : convert from urlsafe";

fn args_to_command() -> Command{
    let args = std::env::args().skip(1).collect::<Vec<_>>();
    if args.len() == 0 {
        panic!("{}", DEFAULT_MSG);
    };
    if args.len() > 1 && (args[0] == "e" || args[0] == "-e") {
        Command::Encode(args[1].clone())
    }
    else if args.len() > 1 && (args[0] == "b" || args[0] == "-b") {
        Command::EncodeBytes(parse_bytes(&args[1]))
    }
    else if args.len() > 1 && (args[0] == "d" || args[0] == "-d") {
        Command::Decode(args[args.len() - 1].clone())
    }
    else if args.len() > 1 && (args[0] == "--se") {
        Command::EncodeUrlSafe(args[args.len() - 1].clone())
    }
    else if args.len() > 1 && (args[0] == "--sd") {
        Command::DecodeUrlSafe(args[args.len() - 1].clone())
    }
    else if args.len() > 1 && (args[0] == "--to-url-safe") {
        Command::ToUrlSafe(args[args.len() - 1].clone())
    }
    else if args.len() > 1 && (args[0] == "--from-url-safe") {
        Command::FromUrlSafe(args[args.len() - 1].clone())
    }
    else {
        panic!("{}", DEFAULT_MSG)
    }
}

fn parse_bytes(s:&str) -> Vec<u8>{
    s.trim_start_matches("[").trim_end_matches("]")
        .split(",")
        .map(|item|u8::from_str_radix(item.trim().trim_start_matches("0x"), 16))
        .collect::<Result<Vec<_>, _>>().expect("can't parse bytes array")
}

fn bytes_to_hex_string(bytes:&[u8]) -> String{
    bytes.iter().map(|i|format!("{:#04x}", i)).collect::<Vec<_>>().join(", ")
}