// !

use crossbeam_channel::{Sender, unbounded};
use pyo3::prelude::*;
use std::thread;

type Job = Box<dyn FnOnce(Python) + Send + 'static>;

#[derive(Debug)]
pub struct PythonRuntime {
    tx: Sender<Job>,
}

impl PythonRuntime {
    pub fn start() -> Self {
        let (tx, rx) = unbounded::<Job>();

        thread::spawn(move || {
            Python::attach(|py| {
                // GIL attached only once
                while let Ok(job) = rx.recv() {
                    job(py);
                }
            });
        });

        Self { tx }
    }

    pub fn exec<F>(&self, f: F)
    where
        F: FnOnce(Python) + Send + 'static,
    {
        self.tx.send(Box::new(f)).unwrap();
    }
}
