ref_sharing.rs
121 lines
| 4.0 KiB
| application/rls-services+xml
|
RustLexer
Yuya Nishihara
|
r43352 | // ref_sharing.rs | ||
Raphaël Gomès
|
r42997 | // | ||
// Copyright 2019 Raphaël Gomès <rgomes@octobus.net> | ||||
// | ||||
Yuya Nishihara
|
r43352 | // Permission is hereby granted, free of charge, to any person obtaining a copy | ||
// of this software and associated documentation files (the "Software"), to | ||||
// deal in the Software without restriction, including without limitation the | ||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or | ||||
// sell copies of the Software, and to permit persons to whom the Software is | ||||
// furnished to do so, subject to the following conditions: | ||||
// | ||||
// The above copyright notice and this permission notice shall be included in | ||||
// all copies or substantial portions of the Software. | ||||
// | ||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | ||||
// IN THE SOFTWARE. | ||||
Raphaël Gomès
|
r42997 | |||
//! Macros for use in the `hg-cpython` bridge library. | ||||
/// Defines a `py_class!` that acts as a Python iterator over a Rust iterator. | ||||
Yuya Nishihara
|
r43158 | /// | ||
/// TODO: this is a bit awkward to use, and a better (more complicated) | ||||
/// procedural macro would simplify the interface a lot. | ||||
/// | ||||
/// # Parameters | ||||
/// | ||||
/// * `$name` is the identifier to give to the resulting Rust struct. | ||||
Yuya Nishihara
|
r44704 | /// * `$leaked` corresponds to `UnsafePyLeaked` in the matching `@shared data` | ||
/// declaration. | ||||
Yuya Nishihara
|
r43158 | /// * `$iterator_type` is the type of the Rust iterator. | ||
/// * `$success_func` is a function for processing the Rust `(key, value)` | ||||
/// tuple on iteration success, turning it into something Python understands. | ||||
/// * `$success_func` is the return type of `$success_func` | ||||
/// | ||||
Yuya Nishihara
|
r44689 | /// # Safety | ||
/// | ||||
/// `$success_func` may take a reference, but it's lifetime may be cheated. | ||||
/// Do not copy it out of the function call. | ||||
/// | ||||
Yuya Nishihara
|
r43158 | /// # Example | ||
/// | ||||
/// ``` | ||||
/// struct MyStruct { | ||||
/// inner: HashMap<Vec<u8>, Vec<u8>>; | ||||
/// } | ||||
/// | ||||
/// py_class!(pub class MyType |py| { | ||||
Yuya Nishihara
|
r44704 | /// @shared data inner: MyStruct; | ||
Yuya Nishihara
|
r43158 | /// | ||
/// def __iter__(&self) -> PyResult<MyTypeItemsIterator> { | ||||
Yuya Nishihara
|
r43611 | /// let leaked_ref = self.inner_shared(py).leak_immutable(); | ||
Yuya Nishihara
|
r43161 | /// MyTypeItemsIterator::from_inner( | ||
Yuya Nishihara
|
r43158 | /// py, | ||
Yuya Nishihara
|
r43579 | /// unsafe { leaked_ref.map(py, |o| o.iter()) }, | ||
Yuya Nishihara
|
r43158 | /// ) | ||
/// } | ||||
/// }); | ||||
/// | ||||
/// impl MyType { | ||||
/// fn translate_key_value( | ||||
/// py: Python, | ||||
/// res: (&Vec<u8>, &Vec<u8>), | ||||
/// ) -> PyResult<Option<(PyBytes, PyBytes)>> { | ||||
/// let (f, entry) = res; | ||||
/// Ok(Some(( | ||||
/// PyBytes::new(py, f), | ||||
/// PyBytes::new(py, entry), | ||||
/// ))) | ||||
/// } | ||||
/// } | ||||
/// | ||||
Yuya Nishihara
|
r43159 | /// py_shared_iterator!( | ||
Yuya Nishihara
|
r43158 | /// MyTypeItemsIterator, | ||
Yuya Nishihara
|
r44704 | /// UnsafePyLeaked<HashMap<'static, Vec<u8>, Vec<u8>>>, | ||
Yuya Nishihara
|
r43158 | /// MyType::translate_key_value, | ||
/// Option<(PyBytes, PyBytes)> | ||||
/// ); | ||||
/// ``` | ||||
Yuya Nishihara
|
r43159 | macro_rules! py_shared_iterator { | ||
Raphaël Gomès
|
r42997 | ( | ||
$name: ident, | ||||
Yuya Nishihara
|
r43447 | $leaked: ty, | ||
Raphaël Gomès
|
r42997 | $success_func: expr, | ||
$success_type: ty | ||||
) => { | ||||
py_class!(pub class $name |py| { | ||||
Yuya Nishihara
|
r43607 | data inner: RefCell<$leaked>; | ||
Raphaël Gomès
|
r42997 | |||
def __next__(&self) -> PyResult<$success_type> { | ||||
Yuya Nishihara
|
r43607 | let mut leaked = self.inner(py).borrow_mut(); | ||
Yuya Nishihara
|
r44689 | let mut iter = unsafe { leaked.try_borrow_mut(py)? }; | ||
Yuya Nishihara
|
r43607 | match iter.next() { | ||
None => Ok(None), | ||||
Yuya Nishihara
|
r44689 | // res may be a reference of cheated 'static lifetime | ||
Yuya Nishihara
|
r43607 | Some(res) => $success_func(py, res), | ||
Raphaël Gomès
|
r42997 | } | ||
} | ||||
def __iter__(&self) -> PyResult<Self> { | ||||
Ok(self.clone_ref(py)) | ||||
} | ||||
}); | ||||
impl $name { | ||||
pub fn from_inner( | ||||
py: Python, | ||||
Yuya Nishihara
|
r43160 | leaked: $leaked, | ||
Raphaël Gomès
|
r42997 | ) -> PyResult<Self> { | ||
Self::create_instance( | ||||
py, | ||||
Yuya Nishihara
|
r43607 | RefCell::new(leaked), | ||
Raphaël Gomès
|
r42997 | ) | ||
} | ||||
} | ||||
}; | ||||
} | ||||