1use pyo3::exceptions::PyValueError;
2use pyo3::prelude::*;
3use pyo3::pybacked::PyBackedStr;
4use pyo3::types::PyString;
5use pyo3::FromPyObject;
6use url::Url;
7
8#[derive(Debug, Clone, PartialEq)]
10pub struct PyUrl(Url);
11
12impl PyUrl {
13 pub fn new(url: Url) -> Self {
15 Self(url)
16 }
17
18 pub fn into_inner(self) -> Url {
20 self.0
21 }
22}
23
24impl<'py> FromPyObject<'_, 'py> for PyUrl {
25 type Error = PyErr;
26
27 fn extract(obj: Borrowed<'_, 'py, PyAny>) -> Result<Self, Self::Error> {
28 let s = obj.extract::<PyBackedStr>()?;
29 let url = Url::parse(&s).map_err(|err| PyValueError::new_err(err.to_string()))?;
30 Ok(Self(url))
31 }
32}
33
34impl<'py> IntoPyObject<'py> for PyUrl {
35 type Target = PyString;
36 type Output = Bound<'py, PyString>;
37 type Error = std::convert::Infallible;
38
39 fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
40 Ok(PyString::new(py, self.0.as_str()))
41 }
42}
43
44impl<'py> IntoPyObject<'py> for &PyUrl {
45 type Target = PyString;
46 type Output = Bound<'py, PyString>;
47 type Error = std::convert::Infallible;
48
49 fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
50 Ok(PyString::new(py, self.0.as_str()))
51 }
52}
53
54impl AsRef<Url> for PyUrl {
55 fn as_ref(&self) -> &Url {
56 &self.0
57 }
58}
59
60impl From<PyUrl> for String {
61 fn from(value: PyUrl) -> Self {
62 value.0.into()
63 }
64}