//! An analog of a Python String. //! //! To return to Python you must use ```into_raw``` method and return a raw pointer. //! You can create them using the ```from``` trait method, from both ```&str``` and ```String```. //! //! # Safety //! When passed from Python you can convert from PyString to an owned string //! (```from_ptr_into_string``` method) or to a ```&str``` slice (to_str method), or //! to a PyString reference (```from_ptr``` method). Those operations are unsafe //! as they require dereferencing a raw pointer. //! //! # Examples //! //! ``` //! use rustypy::PyString; //! let pystr = PyString::from("Hello world!"); //! //! // prepare to return to Python: //! let ptr = pystr.into_raw(); //! // convert from raw pointer to an owned String //! let rust_string = unsafe { PyString::from_ptr_to_string(ptr) }; //! ``` use libc::c_char; use std::ffi::CString; use std::convert::From; use std::fmt; /// An analog of a Python string. /// /// Read the [module docs](index.html) for more information. #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct PyString { _inner: CString, } impl PyString { /// Get a PyString from a previously boxed raw pointer. /// /// # Safety /// Ensure that the passed ptr is valid pub unsafe fn from_ptr(ptr: *mut PyString) -> PyString { if ptr.is_null() { panic!("trying to deref a null ptr!"); } *Box::from_raw(ptr) } /// Constructs an owned String from a raw pointer. /// /// # Safety /// Ensure that the passed ptr is valid pub unsafe fn from_ptr_to_string(ptr: *mut PyString) -> String { if ptr.is_null() { panic!("trying to deref a null ptr!"); } let pystr = *(Box::from_raw(ptr)); String::from(pystr._inner.to_str().unwrap()) } /// Returns PyString as a raw pointer. Use this whenever you want to return /// a PyString to Python. pub fn into_raw(self) -> *mut PyString { Box::into_raw(Box::new(self)) } /// Return a PyString from a raw char pointer. pub unsafe fn from_raw(ptr: *const c_char) -> PyString { PyString { _inner: CStr::from_ptr(ptr).to_owned(), } } } impl fmt::Display for PyString { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", String::from(self._inner.to_str().unwrap())) } } impl<'a> From<&'a str> for PyString { /// Copies a string slice to a PyString. fn from(s: &'a str) -> PyString { PyString { _inner: CString::new(s).unwrap(), } } } impl From for PyString { /// Copies a String to a PyString. fn from(s: String) -> PyString { PyString { _inner: CString::new(s).unwrap(), } } } impl From for String { fn from(s: PyString) -> String { s.to_string() } } /// Destructs the PyString, mostly to be used from Python. #[doc(hidden)] #[no_mangle] pub unsafe extern "C" fn pystring_free(ptr: *mut PyString) { if ptr.is_null() { return; } Box::from_raw(ptr); } use std::ffi::CStr; /// Creates a PyString wrapper from a raw c_char pointer #[doc(hidden)] #[no_mangle] pub unsafe extern "C" fn pystring_new(ptr: *const c_char) -> *mut PyString { let pystr = PyString { _inner: CStr::from_ptr(ptr).to_owned(), }; pystr.into_raw() } /// Consumes the wrapper and returns a raw c_char pointer. Afterwards is not necessary /// to destruct it as it has already been consumed. #[doc(hidden)] #[no_mangle] pub unsafe extern "C" fn pystring_get_str(ptr: *mut PyString) -> *const c_char { let pystr: PyString = PyString::from_ptr(ptr); pystr._inner.into_raw() } #[cfg(test)] mod tests { use super::*; #[test] fn pystring_operations() { let source = "test string"; let owned_pystr = PyString::from(source).into_raw(); let back_from_py = unsafe { PyString::from_ptr_to_string(owned_pystr) }; assert_eq!(back_from_py, "test string"); { String::from(source); } } }