Mercurial > public > mercurial-scm > hg
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> { |