use std::str::FromStr;
use crate::config::Language;
use crate::hook::InstallInfo;
use crate::languages::bun::BunRequest;
use crate::languages::deno::DenoRequest;
use crate::languages::dotnet::DotnetRequest;
use crate::languages::golang::GoRequest;
use crate::languages::node::NodeRequest;
use crate::languages::python::PythonRequest;
use crate::languages::ruby::RubyRequest;
use crate::languages::rust::RustRequest;
#[derive(thiserror::Error, Debug)]
pub(crate) enum Error {
#[error("Invalid `language_version` value: `{0}`")]
InvalidVersion(String),
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub(crate) enum LanguageRequest {
Any { system_only: bool },
Bun(BunRequest),
Dotnet(DotnetRequest),
Deno(DenoRequest),
Golang(GoRequest),
Ruby(RubyRequest),
Node(NodeRequest),
Python(PythonRequest),
Rust(RustRequest),
Semver(SemverRequest),
}
impl LanguageRequest {
pub(crate) fn is_any(&self) -> bool {
match self {
LanguageRequest::Any { .. } => true,
LanguageRequest::Bun(req) => req.is_any(),
LanguageRequest::Dotnet(req) => req.is_any(),
LanguageRequest::Deno(req) => req.is_any(),
LanguageRequest::Golang(req) => req.is_any(),
LanguageRequest::Node(req) => req.is_any(),
LanguageRequest::Python(req) => req.is_any(),
LanguageRequest::Ruby(req) => req.is_any(),
LanguageRequest::Rust(req) => req.is_any(),
LanguageRequest::Semver(_) => false,
}
}
pub(crate) fn allows_download(&self) -> bool {
match self {
LanguageRequest::Any { system_only } => !system_only,
LanguageRequest::Bun(_)
| LanguageRequest::Dotnet(_)
| LanguageRequest::Deno(_)
| LanguageRequest::Golang(_)
| LanguageRequest::Node(_)
| LanguageRequest::Python(_)
| LanguageRequest::Ruby(_)
| LanguageRequest::Rust(_)
| LanguageRequest::Semver(_) => true,
}
}
pub(crate) fn parse(lang: Language, request: &str) -> Result<Self, Error> {
if request == "default" || request.is_empty() {
return Ok(LanguageRequest::Any { system_only: false });
}
if request == "system" {
return Ok(LanguageRequest::Any { system_only: true });
}
Ok(match lang {
Language::Bun => Self::Bun(request.parse()?),
Language::Dotnet => Self::Dotnet(request.parse()?),
Language::Deno => Self::Deno(request.parse()?),
Language::Golang => Self::Golang(request.parse()?),
Language::Node => Self::Node(request.parse()?),
Language::Python => Self::Python(request.parse()?),
Language::Ruby => Self::Ruby(request.parse()?),
Language::Rust => Self::Rust(request.parse()?),
Language::Conda
| Language::Coursier
| Language::Dart
| Language::Docker
| Language::DockerImage
| Language::Fail
| Language::Haskell
| Language::Julia
| Language::Lua
| Language::Perl
| Language::Pygrep
| Language::R
| Language::Script
| Language::Swift
| Language::System => Self::Semver(request.parse()?),
})
}
pub(crate) fn satisfied_by(&self, install_info: &InstallInfo) -> bool {
match self {
LanguageRequest::Any { .. } => true,
LanguageRequest::Bun(req) => req.satisfied_by(install_info),
LanguageRequest::Dotnet(req) => req.satisfied_by(install_info),
LanguageRequest::Deno(req) => req.satisfied_by(install_info),
LanguageRequest::Golang(req) => req.satisfied_by(install_info),
LanguageRequest::Node(req) => req.satisfied_by(install_info),
LanguageRequest::Python(req) => req.satisfied_by(install_info),
LanguageRequest::Ruby(req) => req.satisfied_by(install_info),
LanguageRequest::Rust(req) => req.satisfied_by(install_info),
LanguageRequest::Semver(req) => req.satisfied_by(install_info),
}
}
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub(crate) struct SemverRequest(semver::VersionReq);
impl FromStr for SemverRequest {
type Err = Error;
fn from_str(request: &str) -> Result<Self, Self::Err> {
semver::VersionReq::parse(request)
.map(SemverRequest)
.map_err(|_| Error::InvalidVersion(request.to_string()))
}
}
impl SemverRequest {
fn satisfied_by(&self, install_info: &InstallInfo) -> bool {
self.0.matches(&install_info.language_version)
}
}
pub(crate) fn try_into_u64_slice(version: &str) -> Result<Vec<u64>, std::num::ParseIntError> {
version
.split('.')
.map(str::parse::<u64>)
.collect::<Result<Vec<_>, _>>()
}