rust/pyo3-sharedref/src/lib.rs
changeset 52615 78b2894cd58c
parent 52614 76a0bdb0e4ca
child 52843 189491cea922
equal deleted inserted replaced
52614:76a0bdb0e4ca 52615:78b2894cd58c
   467 /// Even though [`SharedByPyObject`] tries to enforce the real lifetime of the
   467 /// Even though [`SharedByPyObject`] tries to enforce the real lifetime of the
   468 /// underlying object, the object having the artificial `'static` lifetime
   468 /// underlying object, the object having the artificial `'static` lifetime
   469 /// may be exposed to your Rust code. You must be careful to not make a bare
   469 /// may be exposed to your Rust code. You must be careful to not make a bare
   470 /// reference outlive the actual object lifetime.
   470 /// reference outlive the actual object lifetime.
   471 ///
   471 ///
   472 /// ```ignore
   472 /// See [`Self::try_borrow_mut()`] for an example of the kind of trouble that
   473 /// let mut outer = empty;
   473 /// can arise.
   474 /// let mut shared_iter = shared.map(py, |o| o.chars());
       
   475 /// {
       
   476 ///     let mut iter = unsafe { shared_iter.try_borrow_mut(py) };
       
   477 ///     let inner = iter.next();  // Good, in borrow scope
       
   478 ///     outer = inner;            // Bad, &'static T may outlive
       
   479 /// }
       
   480 /// ```
       
   481 pub struct SharedByPyObject<T: ?Sized> {
   474 pub struct SharedByPyObject<T: ?Sized> {
   482     owner: PyObject,
   475     owner: PyObject,
   483     state: &'static PySharedState,
   476     state: &'static PySharedState,
   484     /// Generation counter of data `T` captured when SharedByPyObject is
   477     /// Generation counter of data `T` captured when SharedByPyObject is
   485     /// created.
   478     /// created.
   496 impl<T: ?Sized> SharedByPyObject<T> {
   489 impl<T: ?Sized> SharedByPyObject<T> {
   497     // No panicking version of borrow() and borrow_mut() are implemented
   490     // No panicking version of borrow() and borrow_mut() are implemented
   498     // because the underlying value is supposed to be mutated in Python
   491     // because the underlying value is supposed to be mutated in Python
   499     // world, and the Rust library designer can't prevent it.
   492     // world, and the Rust library designer can't prevent it.
   500 
   493 
   501     // try_borrow() and try_borrow_mut() are unsafe because self.data may
       
   502     // have a function returning the inner &'static reference.
       
   503     // If T is &'static U, its lifetime can be easily coerced to &'a U, but
       
   504     // how could we do that for Whatever<'static> in general?
       
   505 
       
   506     /// Immutably borrows the wrapped value.
   494     /// Immutably borrows the wrapped value.
   507     ///
   495     ///
   508     /// Borrowing fails if the underlying reference has been invalidated.
   496     /// Borrowing fails if the underlying reference has been invalidated.
   509     ///
   497     ///
   510     /// # Safety
   498     /// # Safety
   511     ///
   499     ///
   512     /// The lifetime of the innermost object is artificial. Do not obtain and
   500     /// The lifetime of the innermost object is artificial. Do not obtain and
   513     /// copy it out of the borrow scope.
   501     /// copy it out of the borrow scope.
       
   502     ///
       
   503     /// The lifetime of the innermost object is artificial. Do not obtain and
       
   504     /// copy it out of the borrow scope. More generally, the returned `&T`
       
   505     /// may have a method returning an inner reference, which would typically
       
   506     /// be `'static` and not safe without the `owner` Python object, so the
       
   507     /// problem might be less obvious than in the example below.
       
   508     ///
       
   509     /// The following example does compile and illustrates the problem.
       
   510     /// In this case, the data is a `Vec<String>` and the leaked reference
       
   511     /// `&'static str`, which points to some element of the vector. This
       
   512     /// illustrates that the leaks are not necessarily to the whole of the
       
   513     /// shared data.
       
   514     ///
       
   515     /// ```no_run
       
   516     /// # use pyo3::prelude::*;
       
   517     /// # use pyo3_sharedref::PyShareable;
       
   518     /// #[pyclass]
       
   519     /// struct Owner {
       
   520     ///     value: PyShareable<Vec<String>>
       
   521     /// }
       
   522     ///
       
   523     /// #[pymethods]
       
   524     /// impl Owner {
       
   525     ///     #[new]
       
   526     ///     fn new(s: &str) -> Self {
       
   527     ///         let split: Vec<_> = s.split(' ').map(String::from).collect();
       
   528     ///         Self { value: split.into() }
       
   529     ///     }
       
   530     /// }
       
   531     ///
       
   532     /// const EMPTY: &'static str = "";
       
   533     ///
       
   534     /// let mut outer = EMPTY;
       
   535     /// Python::with_gil(|py| {
       
   536     ///     let owner = Bound::new(py, Owner::new("hello")).unwrap();
       
   537     ///     let shareable = &owner.borrow().value;
       
   538     ///     let shared = unsafe { shareable.share(&owner) };
       
   539     ///     {
       
   540     ///         let inner = unsafe { shared.try_borrow(py) }.unwrap();
       
   541     ///         outer = &inner[0]; // Bad, &'static str does outlive the scope
       
   542     ///     }
       
   543     /// });
       
   544     /// ```
   514     pub unsafe fn try_borrow<'a>(
   545     pub unsafe fn try_borrow<'a>(
   515         &'a self,
   546         &'a self,
   516         py: Python<'a>,
   547         py: Python<'a>,
   517     ) -> PyResult<SharedByPyObjectRef<'a, T>> {
   548     ) -> PyResult<SharedByPyObjectRef<'a, T>> {
   518         self.validate_generation(py)?;
   549         self.validate_generation(py)?;
   524 
   555 
   525     /// Mutably borrows the wrapped value.
   556     /// Mutably borrows the wrapped value.
   526     ///
   557     ///
   527     /// Borrowing fails if the underlying reference has been invalidated.
   558     /// Borrowing fails if the underlying reference has been invalidated.
   528     ///
   559     ///
   529     /// Typically `T` is an iterator. If `T` is an immutable reference,
   560     /// Typically `T` would be an iterator obtained by the [`Self::map`]
   530     /// `get_mut()` is useless since the inner value can't be mutated.
   561     /// method.
   531     ///
   562     ///
   532     /// # Safety
   563     /// # Safety
   533     ///
   564     ///
   534     /// The lifetime of the innermost object is artificial. Do not obtain and
   565     /// The lifetime of the innermost object is artificial. Do not obtain and
   535     /// copy it out of the borrow scope.
   566     /// copy it out of the borrow scope. More generally, the returned `&T`
       
   567     /// may have a method returning an inner reference, which would typically
       
   568     /// be `'static` and not safe without the `owner` Python object, so the
       
   569     /// problem might be less obvious than in the example below.
       
   570     ///
       
   571     /// The following example does compile and illustrates the problem.
       
   572     /// It is very close to the example given in [`Self::try_borrow`] because
       
   573     /// the problem does not arise from the mutability of the reference
       
   574     /// returned by this function.
       
   575     ///
       
   576     /// In this case, the data is a `Vec<String>` and the leaked reference
       
   577     /// `&'static str`, which points to some element of the vector. This
       
   578     /// illustrates that the leaks are not necessarily to the whole of the
       
   579     /// shared data.
       
   580     ///
       
   581     /// ```no_run
       
   582     /// # use pyo3::prelude::*;
       
   583     /// # use pyo3_sharedref::PyShareable;
       
   584     /// #[pyclass]
       
   585     /// struct Owner {
       
   586     ///     value: PyShareable<Vec<String>>
       
   587     /// }
       
   588     ///
       
   589     /// #[pymethods]
       
   590     /// impl Owner {
       
   591     ///     #[new]
       
   592     ///     fn new(s: &str) -> Self {
       
   593     ///         let split: Vec<_> = s.split(' ').map(String::from).collect();
       
   594     ///         Self { value: split.into() }
       
   595     ///     }
       
   596     /// }
       
   597     ///
       
   598     /// const EMPTY: &'static str = "";
       
   599     ///
       
   600     /// let mut outer = EMPTY;
       
   601     /// Python::with_gil(|py| {
       
   602     ///     let owner = Bound::new(py, Owner::new("hello")).unwrap();
       
   603     ///     let shareable = &owner.borrow().value;
       
   604     ///     let shared = unsafe { shareable.share(&owner) };
       
   605     ///     let mut shared_iter = unsafe { shared.map(py, |o| o.iter()) };
       
   606     ///     {
       
   607     ///         let mut iter = unsafe {
       
   608     ///             shared_iter.try_borrow_mut(py)
       
   609     ///         }.unwrap();
       
   610     ///         let inner = iter.next().unwrap();  // Good, in borrow scope
       
   611     ///         outer = inner; // Bad, &'static str does outlive the scope
       
   612     ///     }
       
   613     /// });
       
   614     /// ```
   536     pub unsafe fn try_borrow_mut<'a>(
   615     pub unsafe fn try_borrow_mut<'a>(
   537         &'a mut self,
   616         &'a mut self,
   538         py: Python<'a>,
   617         py: Python<'a>,
   539     ) -> PyResult<SharedByPyObjectRefMut<'a, T>> {
   618     ) -> PyResult<SharedByPyObjectRefMut<'a, T>> {
   540         self.validate_generation(py)?;
   619         self.validate_generation(py)?;