uv_python/
implementation.rs

1use std::{
2    fmt::{self, Display},
3    str::FromStr,
4};
5use thiserror::Error;
6
7use crate::Interpreter;
8
9#[derive(Error, Debug)]
10pub enum Error {
11    #[error("Unknown Python implementation `{0}`")]
12    UnknownImplementation(String),
13}
14
15#[derive(Debug, Eq, PartialEq, Clone, Copy, Default, PartialOrd, Ord, Hash)]
16pub enum ImplementationName {
17    Pyodide,
18    GraalPy,
19    PyPy,
20    #[default]
21    CPython,
22}
23
24#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Hash)]
25pub enum LenientImplementationName {
26    Unknown(String),
27    Known(ImplementationName),
28}
29
30impl ImplementationName {
31    pub(crate) fn short_names() -> impl Iterator<Item = &'static str> {
32        ["cp", "pp", "gp"].into_iter()
33    }
34
35    pub(crate) fn long_names() -> impl Iterator<Item = &'static str> {
36        ["cpython", "pypy", "graalpy", "pyodide"].into_iter()
37    }
38
39    pub(crate) fn iter_all() -> impl Iterator<Item = Self> {
40        [Self::CPython, Self::PyPy, Self::GraalPy, Self::Pyodide].into_iter()
41    }
42
43    pub fn pretty(self) -> &'static str {
44        match self {
45            Self::CPython => "CPython",
46            Self::PyPy => "PyPy",
47            Self::GraalPy => "GraalPy",
48            Self::Pyodide => "Pyodide",
49        }
50    }
51
52    pub fn executable_name(self) -> &'static str {
53        match self {
54            Self::CPython | Self::Pyodide => "python",
55            Self::PyPy | Self::GraalPy => self.into(),
56        }
57    }
58
59    pub fn matches_interpreter(self, interpreter: &Interpreter) -> bool {
60        match self {
61            Self::Pyodide => interpreter.os().is_emscripten(),
62            _ => interpreter
63                .implementation_name()
64                .eq_ignore_ascii_case(self.into()),
65        }
66    }
67}
68
69impl LenientImplementationName {
70    pub fn pretty(&self) -> &str {
71        match self {
72            Self::Known(implementation) => implementation.pretty(),
73            Self::Unknown(name) => name,
74        }
75    }
76
77    pub fn executable_name(&self) -> &str {
78        match self {
79            Self::Known(implementation) => implementation.executable_name(),
80            Self::Unknown(name) => name,
81        }
82    }
83}
84
85impl From<&ImplementationName> for &'static str {
86    fn from(value: &ImplementationName) -> &'static str {
87        match value {
88            ImplementationName::CPython => "cpython",
89            ImplementationName::PyPy => "pypy",
90            ImplementationName::GraalPy => "graalpy",
91            ImplementationName::Pyodide => "pyodide",
92        }
93    }
94}
95
96impl From<ImplementationName> for &'static str {
97    fn from(value: ImplementationName) -> &'static str {
98        (&value).into()
99    }
100}
101
102impl<'a> From<&'a LenientImplementationName> for &'a str {
103    fn from(value: &'a LenientImplementationName) -> &'a str {
104        match value {
105            LenientImplementationName::Known(implementation) => implementation.into(),
106            LenientImplementationName::Unknown(name) => name,
107        }
108    }
109}
110
111impl FromStr for ImplementationName {
112    type Err = Error;
113
114    /// Parse a Python implementation name from a string.
115    ///
116    /// Supports the full name and the platform compatibility tag style name.
117    fn from_str(s: &str) -> Result<Self, Self::Err> {
118        match s.to_ascii_lowercase().as_str() {
119            "cpython" | "cp" => Ok(Self::CPython),
120            "pypy" | "pp" => Ok(Self::PyPy),
121            "graalpy" | "gp" => Ok(Self::GraalPy),
122            "pyodide" => Ok(Self::Pyodide),
123            _ => Err(Error::UnknownImplementation(s.to_string())),
124        }
125    }
126}
127
128impl Display for ImplementationName {
129    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
130        f.write_str(self.into())
131    }
132}
133
134impl From<&str> for LenientImplementationName {
135    fn from(s: &str) -> Self {
136        match ImplementationName::from_str(s) {
137            Ok(implementation) => Self::Known(implementation),
138            Err(_) => Self::Unknown(s.to_string()),
139        }
140    }
141}
142
143impl From<ImplementationName> for LenientImplementationName {
144    fn from(implementation: ImplementationName) -> Self {
145        Self::Known(implementation)
146    }
147}
148
149impl Display for LenientImplementationName {
150    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
151        match self {
152            Self::Known(implementation) => implementation.fmt(f),
153            Self::Unknown(name) => f.write_str(&name.to_ascii_lowercase()),
154        }
155    }
156}