use std::fmt;
use std::str::FromStr;
use serde::Serialize;
use crate::error::Error;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default, Serialize)]
#[serde(rename_all = "kebab-case")]
pub enum Proxy {
#[default]
Github,
GhProxy,
Xget,
Jsdelivr,
Statically,
}
impl Proxy {
pub const ALL: [Proxy; 5] = [
Proxy::Github,
Proxy::GhProxy,
Proxy::Xget,
Proxy::Jsdelivr,
Proxy::Statically,
];
pub const fn as_str(self) -> &'static str {
match self {
Proxy::Github => "github",
Proxy::GhProxy => "gh-proxy",
Proxy::Xget => "xget",
Proxy::Jsdelivr => "jsdelivr",
Proxy::Statically => "statically",
}
}
pub const fn list() -> &'static str {
"github, gh-proxy, xget, jsdelivr, statically"
}
pub const fn description(self) -> &'static str {
match self {
Proxy::Github => "download straight from github.com (no proxy)",
Proxy::GhProxy => "mirror github.com through gh-proxy.com",
Proxy::Xget => "mirror github.com through xget.xi-xu.me",
Proxy::Jsdelivr => "serve repository files through cdn.jsdelivr.net",
Proxy::Statically => "serve repository files through cdn.statically.io",
}
}
pub const fn supports_release_assets(self) -> bool {
matches!(self, Proxy::Github | Proxy::GhProxy | Proxy::Xget)
}
}
impl fmt::Display for Proxy {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.as_str())
}
}
impl FromStr for Proxy {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s.trim().to_ascii_lowercase().as_str() {
"github" | "direct" | "none" | "off" => Ok(Proxy::Github),
"gh-proxy" | "ghproxy" => Ok(Proxy::GhProxy),
"xget" => Ok(Proxy::Xget),
"jsdelivr" => Ok(Proxy::Jsdelivr),
"statically" => Ok(Proxy::Statically),
other => Err(Error::UnknownProxy {
input: other.to_string(),
expected: Proxy::list(),
}),
}
}
}
#[cfg(feature = "cli")]
impl clap::ValueEnum for Proxy {
fn value_variants<'a>() -> &'a [Self] {
&Proxy::ALL
}
fn to_possible_value(&self) -> Option<clap::builder::PossibleValue> {
Some(clap::builder::PossibleValue::new(self.as_str()).help(self.description()))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn parses_aliases() {
assert_eq!("direct".parse::<Proxy>().unwrap(), Proxy::Github);
assert_eq!("ghproxy".parse::<Proxy>().unwrap(), Proxy::GhProxy);
assert_eq!("XGet".parse::<Proxy>().unwrap(), Proxy::Xget);
}
#[test]
fn server_only_cdns_reject_release_assets() {
assert!(Proxy::Github.supports_release_assets());
assert!(Proxy::GhProxy.supports_release_assets());
assert!(!Proxy::Jsdelivr.supports_release_assets());
assert!(!Proxy::Statically.supports_release_assets());
}
#[test]
fn round_trips_through_str() {
for proxy in Proxy::ALL {
assert_eq!(proxy.as_str().parse::<Proxy>().unwrap(), proxy);
}
}
}