comparison rust/pyo3-sharedref/src/lib.rs @ 52614:76a0bdb0e4ca

rust-pyo3-sharedref: demonstrating unsafety of map() We are actually about to lift it, and it will be more convincing if this compiling version of the old example could be refused by the compiler. Note: the `no_run` attribute on the example block checks that it compiles but does not run the example.
author Georges Racinet <georges.racinet@cloudcrane.io>
date Mon, 16 Dec 2024 12:13:46 +0100
parents a945845137b1
children 78b2894cd58c
comparison
equal deleted inserted replaced
52613:ac0cb3c334a1 52614:76a0bdb0e4ca
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 /// TODO this first example would not compile if [`SharedByPyObject::map()`]
473 /// would only accept [`Fn`] instead of [`FnOnce`].
474 ///
475 /// ```ignore 472 /// ```ignore
476 /// let outer; 473 /// let mut outer = empty;
477 /// unsafe { shared.map(py, |o| { outer = o }) }; // Bad 474 /// let mut shared_iter = shared.map(py, |o| o.chars());
478 /// ```
479 ///
480 /// ```ignore
481 /// let outer;
482 /// let mut shared_iter = shared.map(py, |o| o.iter());
483 /// { 475 /// {
484 /// let mut iter = unsafe { shared_iter.try_borrow_mut(py) }; 476 /// let mut iter = unsafe { shared_iter.try_borrow_mut(py) };
485 /// let inner = iter.next(); // Good, in borrow scope 477 /// let inner = iter.next(); // Good, in borrow scope
486 /// outer = inner; // Bad, &'static T may outlive 478 /// outer = inner; // Bad, &'static T may outlive
487 /// } 479 /// }
580 /// # Safety 572 /// # Safety
581 /// 573 ///
582 /// The lifetime of the object passed in to the function `f` is artificial. 574 /// The lifetime of the object passed in to the function `f` is artificial.
583 /// It's typically a static reference, but is valid only while the 575 /// It's typically a static reference, but is valid only while the
584 /// corresponding `SharedByPyObject` is alive. Do not copy it out of the 576 /// corresponding `SharedByPyObject` is alive. Do not copy it out of the
585 /// function call. 577 /// function call. For example, the following does compile:
586 /// TODO would it be safe with `f: impl Fn(T) -> U` then? 578 ///
579 /// ```no_run
580 /// # use pyo3::prelude::*;
581 /// # use pyo3_sharedref::PyShareable;
582 /// #[pyclass]
583 /// struct Owner {
584 /// value: PyShareable<String>
585 /// }
586 ///
587 /// #[pymethods]
588 /// impl Owner {
589 /// #[new]
590 /// fn new(s: &str) -> Self {
591 /// Self { value: s.to_owned().into() }
592 /// }
593 /// }
594 ///
595 /// const EMPTY: &'static str = "";
596 ///
597 /// let mut outer = EMPTY;
598 /// Python::with_gil(|py| {
599 /// let owner = Bound::new(py, Owner::new("hello")).unwrap();
600 /// let shareable = &owner.borrow().value;
601 /// let shared = unsafe { shareable.share(&owner) };
602 ///
603 /// unsafe { shared.map(py, |o| { outer = o }) }; // Bad
604 /// });
605 /// ```
587 pub unsafe fn map<U>( 606 pub unsafe fn map<U>(
588 self, 607 self,
589 py: Python, 608 py: Python,
590 f: impl FnOnce(T) -> U, 609 f: impl FnOnce(T) -> U,
591 ) -> SharedByPyObject<U> { 610 ) -> SharedByPyObject<U> {