uv_python/
implementation.rs1use 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 {
54 match self {
55 Self::CPython | Self::Pyodide => "python",
56 Self::PyPy | Self::GraalPy => self.into(),
57 }
58 }
59
60 pub fn executable_install_name(self) -> &'static str {
62 match self {
63 Self::Pyodide => "pyodide",
64 _ => self.executable_name(),
65 }
66 }
67
68 pub fn matches_interpreter(self, interpreter: &Interpreter) -> bool {
69 match self {
70 Self::Pyodide => interpreter.os().is_emscripten(),
71 _ => interpreter
72 .implementation_name()
73 .eq_ignore_ascii_case(self.into()),
74 }
75 }
76}
77
78impl LenientImplementationName {
79 pub fn pretty(&self) -> &str {
80 match self {
81 Self::Known(implementation) => implementation.pretty(),
82 Self::Unknown(name) => name,
83 }
84 }
85
86 pub fn executable_name(&self) -> &str {
87 match self {
88 Self::Known(implementation) => implementation.executable_name(),
89 Self::Unknown(name) => name,
90 }
91 }
92
93 pub fn executable_install_name(&self) -> &str {
94 match self {
95 Self::Known(implementation) => implementation.executable_install_name(),
96 Self::Unknown(name) => name,
97 }
98 }
99}
100
101impl From<&ImplementationName> for &'static str {
102 fn from(value: &ImplementationName) -> &'static str {
103 match value {
104 ImplementationName::CPython => "cpython",
105 ImplementationName::PyPy => "pypy",
106 ImplementationName::GraalPy => "graalpy",
107 ImplementationName::Pyodide => "pyodide",
108 }
109 }
110}
111
112impl From<ImplementationName> for &'static str {
113 fn from(value: ImplementationName) -> &'static str {
114 (&value).into()
115 }
116}
117
118impl<'a> From<&'a LenientImplementationName> for &'a str {
119 fn from(value: &'a LenientImplementationName) -> &'a str {
120 match value {
121 LenientImplementationName::Known(implementation) => implementation.into(),
122 LenientImplementationName::Unknown(name) => name,
123 }
124 }
125}
126
127impl FromStr for ImplementationName {
128 type Err = Error;
129
130 fn from_str(s: &str) -> Result<Self, Self::Err> {
134 match s.to_ascii_lowercase().as_str() {
135 "cpython" | "cp" => Ok(Self::CPython),
136 "pypy" | "pp" => Ok(Self::PyPy),
137 "graalpy" | "gp" => Ok(Self::GraalPy),
138 "pyodide" => Ok(Self::Pyodide),
139 _ => Err(Error::UnknownImplementation(s.to_string())),
140 }
141 }
142}
143
144impl Display for ImplementationName {
145 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
146 f.write_str(self.into())
147 }
148}
149
150impl From<&str> for LenientImplementationName {
151 fn from(s: &str) -> Self {
152 match ImplementationName::from_str(s) {
153 Ok(implementation) => Self::Known(implementation),
154 Err(_) => Self::Unknown(s.to_string()),
155 }
156 }
157}
158
159impl From<ImplementationName> for LenientImplementationName {
160 fn from(implementation: ImplementationName) -> Self {
161 Self::Known(implementation)
162 }
163}
164
165impl Display for LenientImplementationName {
166 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
167 match self {
168 Self::Known(implementation) => implementation.fmt(f),
169 Self::Unknown(name) => f.write_str(&name.to_ascii_lowercase()),
170 }
171 }
172}