diff --git a/src/conversion.rs b/src/conversion.rs index e5716429..5256d5e1 100644 --- a/src/conversion.rs +++ b/src/conversion.rs @@ -174,10 +174,7 @@ pub trait FromPyObject<'source>: Sized { /// Identity conversion: allows using existing `PyObject` instances where /// `T: ToPyObject` is expected. -impl<'a, T: ?Sized> ToPyObject for &'a T -where - T: ToPyObject, -{ +impl<'a, T: ?Sized + ToPyObject> ToPyObject for &'a T { #[inline] fn to_object(&self, py: Python) -> PyObject { ::to_object(*self, py) diff --git a/src/types/string.rs b/src/types/string.rs index 2bb5e3cd..4d110c59 100644 --- a/src/types/string.rs +++ b/src/types/string.rs @@ -141,6 +141,19 @@ impl ToPyObject for String { } } +impl ToPyObject for char { + fn to_object(&self, py: Python) -> PyObject { + self.into_py(py) + } +} + +impl IntoPy for char { + fn into_py(self, py: Python) -> PyObject { + let mut bytes = [0u8; 4]; + PyString::new(py, self.encode_utf8(&mut bytes)).into() + } +} + impl IntoPy for String { fn into_py(self, py: Python) -> PyObject { PyString::new(py, &self).into() @@ -156,7 +169,7 @@ impl<'a> IntoPy for &'a String { /// Allows extracting strings from Python objects. /// Accepts Python `str` and `unicode` objects. -impl<'source> crate::FromPyObject<'source> for &'source str { +impl<'source> FromPyObject<'source> for &'source str { fn extract(ob: &'source PyAny) -> PyResult { ::try_from(ob)?.to_str() } @@ -172,6 +185,20 @@ impl<'source> FromPyObject<'source> for String { } } +impl<'source> FromPyObject<'source> for char { + fn extract(obj: &'source PyAny) -> PyResult { + let s = PyString::try_from(obj)?.to_str()?; + let mut iter = s.chars(); + if let (Some(ch), None) = (iter.next(), iter.next()) { + Ok(ch) + } else { + Err(crate::exceptions::PyValueError::new_err(format!( + "Expected a sting of length 1", + ))) + } + } +} + #[cfg(test)] mod test { use super::PyString; @@ -198,6 +225,16 @@ mod test { assert_eq!(s, s2); } + #[test] + fn test_extract_char() { + Python::with_gil(|py| { + let ch = '😃'; + let py_string = ch.to_object(py); + let ch2: char = FromPyObject::extract(py_string.as_ref(py)).unwrap(); + assert_eq!(ch, ch2); + }) + } + #[test] fn test_to_str_ascii() { let gil = Python::acquire_gil();