(&self, jen: &PyObject, vm: &VirtualMachine)
| 209 | } |
| 210 | |
| 211 | pub fn close(&self, jen: &PyObject, vm: &VirtualMachine) -> PyResult<PyObjectRef> { |
| 212 | if self.closed.load() { |
| 213 | return Ok(vm.ctx.none()); |
| 214 | } |
| 215 | // If generator hasn't started (FRAME_CREATED), just mark as closed |
| 216 | if self.frame.lasti() == 0 { |
| 217 | self.closed.store(true); |
| 218 | return Ok(vm.ctx.none()); |
| 219 | } |
| 220 | let result = self.run_with_context(jen, vm, |f| { |
| 221 | f.gen_throw( |
| 222 | vm, |
| 223 | vm.ctx.exceptions.generator_exit.to_owned().into(), |
| 224 | vm.ctx.none(), |
| 225 | vm.ctx.none(), |
| 226 | ) |
| 227 | }); |
| 228 | self.closed.store(true); |
| 229 | // Release frame locals and stack to free references held by the |
| 230 | // closed generator, matching gen_send_ex2 with close_on_completion. |
| 231 | self.frame.clear_locals_and_stack(); |
| 232 | match result { |
| 233 | Ok(ExecutionResult::Yield(_)) => { |
| 234 | Err(vm.new_runtime_error(format!("{} ignored GeneratorExit", gen_name(jen, vm)))) |
| 235 | } |
| 236 | Err(e) if !is_gen_exit(&e, vm) => Err(e), |
| 237 | Ok(ExecutionResult::Return(value)) => Ok(value), |
| 238 | _ => Ok(vm.ctx.none()), |
| 239 | } |
| 240 | } |
| 241 | |
| 242 | pub fn suspended(&self) -> bool { |
| 243 | !self.closed.load() && !self.running.load() && self.frame.lasti() > 0 |
no test coverage detected