cargo-ibuild 1.2.1

cargo-ibuild
use crate::config::{ARM64_TARGET, X64_TARGET};
use std::{
    any::{Any, TypeId},
    error::Error,
    process::Command,
};

pub trait Param {
    fn set(&mut self, s: String);
}

impl Param for String {
    fn set(&mut self, s: String) {
        *self = s;
    }
}

impl Param for Option<bool> {
    fn set(&mut self, s: String) {
        *self = match s.as_str() {
            "true" | "1" | "on" => Some(true),
            "false" | "0" | "off" => Some(false),
            _ => *self,
        };
    }
}

impl Param for bool {
    fn set(&mut self, _: String) {
        *self = !*self;
    }
}

impl Param for Option<String> {
    fn set(&mut self, s: String) {
        *self = Some(s);
    }
}

pub fn get_param<T: Any + Param + Clone>(
    args: &mut Vec<String>,
    key: &str,
    default: T,
    remove: bool,
) -> T {
    let mut value = default.clone();
    match args.iter().position(|x| x == key) {
        Some(idx) => {
            if value.type_id() == TypeId::of::<bool>() {
                value.set(String::new());
                if remove {
                    args.remove(idx);
                }
            } else {
                if idx + 1 < args.len() {
                    value.set(args[idx + 1].clone());
                    if remove {
                        args.remove(idx);
                        args.remove(idx);
                    }
                } else {
                    panic!("Missing value for {key}");
                }
            }
        }
        None => (),
    }
    value
}

pub fn get_channel_and_target(args: &mut Vec<String>) -> Result<(String, String), Box<dyn Error>> {
    let line = String::from_utf8_lossy(
        &Command::new("rustup")
            .args(["show", "active-toolchain"])
            .output()?
            .stdout,
    )
    .trim()
    .to_string();
    let active_channel = line.split("-").next().unwrap().to_string();
    let mut active_target =
        get_param(args, "--target", X64_TARGET.to_string(), true).to_lowercase();
    if active_target == "x86_64" || active_target == "x64" {
        active_target = X64_TARGET.to_string();
    }
    if active_target == "arm64" || active_target == "aarch64" {
        active_target = ARM64_TARGET.to_string();
    }
    if active_target != X64_TARGET && active_target != ARM64_TARGET {
        panic!("Unsupported Target: {}", active_target);
    }

    Ok((active_channel, active_target))
}