-
-
Save rust-play/041f9a6f5dfa3a5fc59ece7105cc4dfd to your computer and use it in GitHub Desktop.
Code shared from the Rust Playground
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// WARNING: THIS CODE IS A HACKY PROTOTYPE FOR TOY PURPOSES ONLY. | |
// CHOOSING TO COPY THIS CODE INTO YOUR RUST PROGRAM IS WILDLY UNSOUND. | |
// | |
// ping me (davidhewitt) on the PyO3 issue tracker and we can figure out | |
// how to do this safely. | |
use std::collections::{HashMap, hash_map::Iter as MapIter}; | |
// pyclass 1 | |
pub struct Class { | |
data: HashMap<String, String> | |
} | |
// pyclass 2 | |
pub struct Iterator { | |
// Ouch this type signature is horrible! Maybe PyO3 can pack this up in | |
// a type alias / with a macro. | |
inner: Box<dyn for<'a> PyOwned<MapIter<'a, String, String>>> | |
} | |
// pyproto for Iterator | |
impl Iterator { | |
fn __next__(&mut self) -> Option<(&String, &String)> { | |
self.inner.get_mut().next() | |
} | |
} | |
// Not actually how PyCell / PyRef implemented, but it'll do for sketching | |
// the types here. | |
pub struct PyCell<T>(T); | |
pub struct PyRef<'a, T>(&'a T); | |
impl<T> PyCell<T> { | |
fn borrow(&self) -> PyRef<T> { | |
PyRef(&self.0) | |
} | |
} | |
trait PyOwned<T> { | |
fn get_mut(&mut self) -> &mut T; | |
} | |
impl<'py> PyRef<'py, Class> { | |
fn to_dyn_owned(self: &Self, it: MapIter<'py, String, String>) -> Box<dyn for<'a> PyOwned<MapIter<'a, String, String>>> | |
{ | |
// In here be wildly unsafe code to make the type system line up. | |
// This should be able to be "swept under the rug" by PyO3 in a safe wrapper. | |
// This is the wildly unsafe escape from Rust's lifetime system | |
let static_r = unsafe { std::mem::transmute(self) }; | |
let static_it = unsafe { std::mem::transmute(it) }; | |
struct PyOwnedImpl { | |
// FIXME: this is totally wrong, needs to be Py<T> or similar which stores | |
// the python pointer rather than the borrow. As-is, this would be pointing | |
// at dangling memory. | |
_r: PyRef<'static, Class>, | |
// This 'static also smells bad, but it's the only way to avoid having | |
// a lifetime on the outer value. | |
// It's probably needed to convince Rust that the MapIter lives | |
// long enough. | |
inner: MapIter<'static, String, String> | |
} | |
impl<'a> PyOwned<MapIter<'a, String, String>> for PyOwnedImpl { | |
fn get_mut(&mut self) -> &mut MapIter<'a, String, String> { | |
// Without this transmute, the compiler cannot assert that 'a outlives static... !? | |
unsafe { std::mem::transmute(&mut self.inner) } | |
} | |
} | |
Box::new(PyOwnedImpl { _r: static_r, inner: static_it }) | |
} | |
} | |
fn main() { | |
let mut data = HashMap::new(); | |
data.insert("foo".to_string(), "bar".to_string()); | |
let cell = PyCell(Class { data }); | |
let r = cell.borrow(); | |
let mut it = Iterator { | |
inner: PyRef::to_dyn_owned(&r, r.0.data.iter()) | |
}; | |
println!("{:?}", it.__next__()); | |
assert_eq!(it.__next__(), None); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment