rust/pyo3-sharedref/tests/test_sharedref.rs
changeset 52613 ac0cb3c334a1
parent 52612 a945845137b1
equal deleted inserted replaced
52612:a945845137b1 52613:ac0cb3c334a1
    24     })
    24     })
    25 }
    25 }
    26 
    26 
    27 /// "leak" in the sense of `SharedByPyObject` the `string` data field,
    27 /// "leak" in the sense of `SharedByPyObject` the `string` data field,
    28 /// taking care of all the boilerplate
    28 /// taking care of all the boilerplate
    29 fn leak_string(owner: &Bound<'_, Owner>) -> SharedByPyObject<&'static String> {
    29 fn share_string(
    30     let cell = &owner.borrow().string;
    30     owner: &Bound<'_, Owner>,
    31     unsafe { cell.share(owner) }
    31 ) -> SharedByPyObject<&'static String> {
    32 }
    32     let shareable = &owner.borrow().string;
    33 
    33     unsafe { shareable.share(owner) }
    34 fn try_leak_string(
    34 }
       
    35 
       
    36 fn try_share_string(
    35     owner: &Bound<'_, Owner>,
    37     owner: &Bound<'_, Owner>,
    36 ) -> Result<SharedByPyObject<&'static String>, TryShareError> {
    38 ) -> Result<SharedByPyObject<&'static String>, TryShareError> {
    37     let cell = &owner.borrow().string;
    39     let shareable = &owner.borrow().string;
    38     unsafe { cell.try_share(owner) }
    40     unsafe { shareable.try_share(owner) }
    39 }
    41 }
    40 
    42 
    41 /// Mutate the `string` field of `owner` as would be done from Python code
    43 /// Mutate the `string` field of `owner` as would be done from Python code
    42 ///
    44 ///
    43 /// This is to simulate normal mutation of the owner object from
    45 /// This is to simulate normal mutation of the owner object from
    47 /// from rust-cpython
    49 /// from rust-cpython
    48 fn mutate_string<'py>(
    50 fn mutate_string<'py>(
    49     owner: &'py Bound<'py, Owner>,
    51     owner: &'py Bound<'py, Owner>,
    50     f: impl FnOnce(&mut String),
    52     f: impl FnOnce(&mut String),
    51 ) -> () {
    53 ) -> () {
    52     let cell = &owner.borrow_mut().string;
    54     let shareable = &owner.borrow_mut().string;
    53     let shared_ref = unsafe { cell.borrow_with_owner(owner) };
    55     let shared_ref = unsafe { shareable.borrow_with_owner(owner) };
    54     f(&mut shared_ref.write());
    56     f(&mut shared_ref.write());
    55 }
    57 }
    56 
    58 
    57 #[test]
    59 #[test]
    58 fn test_leaked_borrow() -> PyResult<()> {
    60 fn test_shared_borrow() -> PyResult<()> {
    59     with_setup(|py, owner| {
    61     with_setup(|py, owner| {
    60         let leaked = leak_string(owner);
    62         let shared = share_string(owner);
    61         let leaked_ref = unsafe { leaked.try_borrow(py) }.unwrap();
    63         let shared_ref = unsafe { shared.try_borrow(py) }.unwrap();
    62         assert_eq!(*leaked_ref, "new");
    64         assert_eq!(*shared_ref, "new");
    63         Ok(())
    65         Ok(())
    64     })
    66     })
    65 }
    67 }
    66 
    68 
    67 #[test]
    69 #[test]
    68 fn test_leaked_borrow_mut() -> PyResult<()> {
    70 fn test_shared_borrow_mut() -> PyResult<()> {
    69     with_setup(|py, owner| {
    71     with_setup(|py, owner| {
    70         let leaked = leak_string(owner);
    72         let shared = share_string(owner);
    71         let mut leaked_iter = unsafe { leaked.map(py, |s| s.chars()) };
    73         let mut shared_iter = unsafe { shared.map(py, |s| s.chars()) };
    72         let mut leaked_ref =
    74         let mut shared_ref =
    73             unsafe { leaked_iter.try_borrow_mut(py) }.unwrap();
    75             unsafe { shared_iter.try_borrow_mut(py) }.unwrap();
    74         assert_eq!(leaked_ref.next(), Some('n'));
    76         assert_eq!(shared_ref.next(), Some('n'));
    75         assert_eq!(leaked_ref.next(), Some('e'));
    77         assert_eq!(shared_ref.next(), Some('e'));
    76         assert_eq!(leaked_ref.next(), Some('w'));
    78         assert_eq!(shared_ref.next(), Some('w'));
    77         assert_eq!(leaked_ref.next(), None);
    79         assert_eq!(shared_ref.next(), None);
    78         Ok(())
    80         Ok(())
    79     })
    81     })
    80 }
    82 }
    81 
    83 
    82 #[test]
    84 #[test]
    83 fn test_leaked_borrow_after_mut() -> PyResult<()> {
    85 fn test_shared_borrow_after_mut() -> PyResult<()> {
    84     with_setup(|py, owner| {
    86     with_setup(|py, owner| {
    85         let leaked = leak_string(owner);
    87         let shared = share_string(owner);
    86         mutate_string(owner, String::clear);
    88         mutate_string(owner, String::clear);
    87         assert!(unsafe { leaked.try_borrow(py) }.is_err());
    89         assert!(unsafe { shared.try_borrow(py) }.is_err());
    88         Ok(())
    90         Ok(())
    89     })
    91     })
    90 }
    92 }
    91 
    93 
    92 #[test]
    94 #[test]
    93 fn test_leaked_borrow_mut_after_mut() -> PyResult<()> {
    95 fn test_shared_borrow_mut_after_mut() -> PyResult<()> {
    94     with_setup(|py, owner| {
    96     with_setup(|py, owner| {
    95         let leaked = leak_string(owner);
    97         let shared = share_string(owner);
    96         let mut leaked_iter = unsafe { leaked.map(py, |s| s.chars()) };
    98         let mut shared_iter = unsafe { shared.map(py, |s| s.chars()) };
    97 
    99 
    98         mutate_string(owner, String::clear);
   100         mutate_string(owner, String::clear);
    99         assert!(unsafe { leaked_iter.try_borrow_mut(py) }.is_err());
   101         assert!(unsafe { shared_iter.try_borrow_mut(py) }.is_err());
   100         Ok(())
   102         Ok(())
   101     })
   103     })
   102 }
   104 }
   103 
   105 
   104 #[test]
   106 #[test]
   105 #[should_panic(expected = "map() over invalidated shared reference")]
   107 #[should_panic(expected = "map() over invalidated shared reference")]
   106 fn test_leaked_map_after_mut() {
   108 fn test_shared_map_after_mut() {
   107     with_setup(|py, owner| {
   109     with_setup(|py, owner| {
   108         let leaked = leak_string(owner);
   110         let shared = share_string(owner);
   109         mutate_string(owner, String::clear);
   111         mutate_string(owner, String::clear);
   110         let _leaked_iter = unsafe { leaked.map(py, |s| s.chars()) };
   112         let _shared_iter = unsafe { shared.map(py, |s| s.chars()) };
   111         Ok(())
   113         Ok(())
   112     })
   114     })
   113     .expect("should already have panicked")
   115     .expect("should already have panicked")
   114 }
   116 }
   115 
   117 
   116 /// run `try_borrow_mut` on the `string` field and assert it is not an error
   118 /// run `try_borrow_mut` on the `string` field and assert it is not an error
   117 ///
   119 ///
   118 /// Simply returning the `Result` is not possible, because that is
   120 /// Simply returning the `Result` is not possible, because that is
   119 /// returning a reference to data owned by the function
   121 /// returning a reference to data owned by the function
   120 fn assert_try_write_string_ok(owner: &Bound<'_, Owner>) {
   122 fn assert_try_write_string_ok(owner: &Bound<'_, Owner>) {
   121     let cell = &owner.borrow().string;
   123     let shareable = &owner.borrow().string;
   122     let shared_ref = unsafe { cell.borrow_with_owner(owner) };
   124     let shared_ref = unsafe { shareable.borrow_with_owner(owner) };
   123     assert!(shared_ref.try_write().is_ok());
   125     assert!(shared_ref.try_write().is_ok());
   124 }
   126 }
   125 
   127 
   126 fn assert_try_write_string_err(owner: &Bound<'_, Owner>) {
   128 fn assert_try_write_string_err(owner: &Bound<'_, Owner>) {
   127     let cell = &owner.borrow().string;
   129     let shareable = &owner.borrow().string;
   128     let shared_ref = unsafe { cell.borrow_with_owner(owner) };
   130     let shared_ref = unsafe { shareable.borrow_with_owner(owner) };
   129     assert!(shared_ref.try_write().is_err());
   131     assert!(shared_ref.try_write().is_err());
   130 }
   132 }
   131 
   133 
   132 fn assert_try_read_string_err(owner: &Bound<'_, Owner>) {
   134 fn assert_try_read_string_err(owner: &Bound<'_, Owner>) {
   133     let cell = &owner.borrow().string;
   135     let shareable = &owner.borrow().string;
   134     let shared_ref = unsafe { cell.borrow_with_owner(owner) };
   136     let shared_ref = unsafe { shareable.borrow_with_owner(owner) };
   135     assert!(shared_ref.try_read().is_err());
   137     assert!(shared_ref.try_read().is_err());
   136 }
   138 }
   137 
   139 
   138 #[test]
   140 #[test]
   139 fn test_try_write_while_leaked_ref() -> PyResult<()> {
   141 fn test_try_write_while_shared_ref() -> PyResult<()> {
   140     with_setup(|py, owner| {
   142     with_setup(|py, owner| {
   141         assert_try_write_string_ok(owner);
   143         assert_try_write_string_ok(owner);
   142         let leaked = leak_string(owner);
   144         let shared = share_string(owner);
   143         {
   145         {
   144             let _leaked_ref = unsafe { leaked.try_borrow(py) }.unwrap();
   146             let _shared_ref = unsafe { shared.try_borrow(py) }.unwrap();
   145             assert_try_write_string_err(owner);
   147             assert_try_write_string_err(owner);
   146             {
   148             {
   147                 let _leaked_ref2 = unsafe { leaked.try_borrow(py) }.unwrap();
   149                 let _shared_ref2 = unsafe { shared.try_borrow(py) }.unwrap();
   148                 assert_try_write_string_err(owner);
   150                 assert_try_write_string_err(owner);
   149             }
   151             }
   150             assert_try_write_string_err(owner);
   152             assert_try_write_string_err(owner);
   151         }
   153         }
   152         assert_try_write_string_ok(owner);
   154         assert_try_write_string_ok(owner);
   153         Ok(())
   155         Ok(())
   154     })
   156     })
   155 }
   157 }
   156 
   158 
   157 #[test]
   159 #[test]
   158 fn test_try_write_while_leaked_ref_mut() -> PyResult<()> {
   160 fn test_try_write_while_shared_ref_mut() -> PyResult<()> {
   159     with_setup(|py, owner| {
   161     with_setup(|py, owner| {
   160         assert_try_write_string_ok(owner);
   162         assert_try_write_string_ok(owner);
   161         let leaked = leak_string(owner);
   163         let shared = share_string(owner);
   162         let mut leaked_iter = unsafe { leaked.map(py, |s| s.chars()) };
   164         let mut shared_iter = unsafe { shared.map(py, |s| s.chars()) };
   163         {
   165         {
   164             let _leaked_ref =
   166             let _shared_ref =
   165                 unsafe { leaked_iter.try_borrow_mut(py) }.unwrap();
   167                 unsafe { shared_iter.try_borrow_mut(py) }.unwrap();
   166             assert_try_write_string_err(owner);
   168             assert_try_write_string_err(owner);
   167         }
   169         }
   168         assert_try_write_string_ok(owner);
   170         assert_try_write_string_ok(owner);
   169         Ok(())
   171         Ok(())
   170     })
   172     })
   171 }
   173 }
   172 
   174 
   173 #[test]
   175 #[test]
   174 fn test_try_leak_while_write() -> PyResult<()> {
   176 fn test_try_share_while_write() -> PyResult<()> {
   175     with_setup(|_py, owner| {
   177     with_setup(|_py, owner| {
   176         let cell = &owner.borrow().string;
   178         let shareable = &owner.borrow().string;
   177         let shared_ref = unsafe { cell.borrow_with_owner(owner) };
   179         let shared_ref = unsafe { shareable.borrow_with_owner(owner) };
   178         let _mut_ref = shared_ref.write();
   180         let _mut_ref = shared_ref.write();
   179 
   181 
   180         assert!(try_leak_string(owner).is_err());
   182         assert!(try_share_string(owner).is_err());
   181         Ok(())
   183         Ok(())
   182     })
   184     })
   183 }
   185 }
   184 
   186 
   185 #[test]
   187 #[test]
   186 #[should_panic(expected = "already mutably borrowed")]
   188 #[should_panic(expected = "already mutably borrowed")]
   187 fn test_leak_while_write() {
   189 fn test_share_while_write() {
   188     with_setup(|_py, owner| {
   190     with_setup(|_py, owner| {
   189         let cell = &owner.borrow().string;
   191         let shareable = &owner.borrow().string;
   190         let shared_ref = unsafe { cell.borrow_with_owner(owner) };
   192         let shared_ref = unsafe { shareable.borrow_with_owner(owner) };
   191         let _mut_ref = shared_ref.write();
   193         let _mut_ref = shared_ref.write();
   192 
   194 
   193         leak_string(owner);
   195         share_string(owner);
   194         Ok(())
   196         Ok(())
   195     })
   197     })
   196     .expect("should already have panicked")
   198     .expect("should already have panicked")
   197 }
   199 }
   198 
   200 
   199 #[test]
   201 #[test]
   200 fn test_try_write_while_borrow() -> PyResult<()> {
   202 fn test_try_write_while_borrow() -> PyResult<()> {
   201     with_setup(|_py, owner| {
   203     with_setup(|_py, owner| {
   202         let cell = &owner.borrow().string;
   204         let shareable = &owner.borrow().string;
   203         let shared_ref = unsafe { cell.borrow_with_owner(owner) };
   205         let shared_ref = unsafe { shareable.borrow_with_owner(owner) };
   204         let _ref = shared_ref.read();
   206         let _ref = shared_ref.read();
   205 
   207 
   206         assert_try_write_string_err(owner);
   208         assert_try_write_string_err(owner);
   207         Ok(())
   209         Ok(())
   208     })
   210     })
   210 
   212 
   211 #[test]
   213 #[test]
   212 #[should_panic(expected = "already borrowed")]
   214 #[should_panic(expected = "already borrowed")]
   213 fn test_write_while_borrow() {
   215 fn test_write_while_borrow() {
   214     with_setup(|_py, owner| {
   216     with_setup(|_py, owner| {
   215         let cell = &owner.borrow().string;
   217         let shareable = &owner.borrow().string;
   216         let shared_ref = unsafe { cell.borrow_with_owner(owner) };
   218         let shared_ref = unsafe { shareable.borrow_with_owner(owner) };
   217         let _ref = shared_ref.read();
   219         let _ref = shared_ref.read();
   218 
   220 
   219         let shared_ref2 = unsafe { cell.borrow_with_owner(owner) };
   221         let shared_ref2 = unsafe { shareable.borrow_with_owner(owner) };
   220         let _mut_ref = shared_ref2.write();
   222         let _mut_ref = shared_ref2.write();
   221         Ok(())
   223         Ok(())
   222     })
   224     })
   223     .expect("should already have panicked")
   225     .expect("should already have panicked")
   224 }
   226 }
   225 
   227 
   226 #[test]
   228 #[test]
   227 fn test_try_borrow_while_write() -> PyResult<()> {
   229 fn test_try_borrow_while_write() -> PyResult<()> {
   228     with_setup(|_py, owner| {
   230     with_setup(|_py, owner| {
   229         let cell = &owner.borrow().string;
   231         let shareable = &owner.borrow().string;
   230         let shared_ref = unsafe { cell.borrow_with_owner(owner) };
   232         let shared_ref = unsafe { shareable.borrow_with_owner(owner) };
   231         let _mut_ref = shared_ref.write();
   233         let _mut_ref = shared_ref.write();
   232 
   234 
   233         assert_try_read_string_err(owner);
   235         assert_try_read_string_err(owner);
   234         Ok(())
   236         Ok(())
   235     })
   237     })
   237 
   239 
   238 #[test]
   240 #[test]
   239 #[should_panic(expected = "already mutably borrowed")]
   241 #[should_panic(expected = "already mutably borrowed")]
   240 fn test_borrow_while_write() {
   242 fn test_borrow_while_write() {
   241     with_setup(|_py, owner| {
   243     with_setup(|_py, owner| {
   242         let cell = &owner.borrow().string;
   244         let shareable = &owner.borrow().string;
   243         let shared_ref = unsafe { cell.borrow_with_owner(owner) };
   245         let shared_ref = unsafe { shareable.borrow_with_owner(owner) };
   244         let _mut_ref = shared_ref.write();
   246         let _mut_ref = shared_ref.write();
   245 
   247 
   246         let shared_ref2 = unsafe { cell.borrow_with_owner(owner) };
   248         let shared_ref2 = unsafe { shareable.borrow_with_owner(owner) };
   247         let _ref = shared_ref2.read();
   249         let _ref = shared_ref2.read();
   248         Ok(())
   250         Ok(())
   249     })
   251     })
   250     .expect("should already have panicked")
   252     .expect("should already have panicked")
   251 }
   253 }