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 {
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 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}