#[rustfmt::skip]
use {
    ::safer_ffi::{
        dyn_traits::DynDrop,
        futures::FfiFutureExecutor,
        prelude::*,
    },
    ::std::{
        sync::Arc,
    },
};

/// A `dyn` type-erased (and thus completely layout agnostic
/// (_e.g._, tokio-agnostic)) and yet FFI-compatible version of an `async`
/// runtime executor.
///
/// Keep it in sync with `rust/dittolive-ditto-sys/lib.rs`!
#[derive(Clone, Debug)]
#[derive_ReprC]
#[repr(C)]
pub struct DynExecutor {
    /// The main object used to spawn futures and whatnot.
    pub handle: VirtualPtr<dyn Send + Sync + FfiFutureExecutor>,

    /// The drop glue potentially driving the shutdown of the runtime.
    pub _runtime: DynDrop,
}

impl DynExecutor {
    /// initialize this struct by constructing a new async runtime.
    pub fn new() -> ::std::io::Result<Self> {
        let mut builder = ::tokio::runtime::Builder::new_multi_thread();
        builder.enable_all();

        if cfg!(any(target_os = "ios", target_os = "android")) {
            // So we have a total of 32 threads on 8 core devices
            // The number 32 was chosen by Tom to maximise performance on the
            // iPad Pro under load without crashing.
            let max_blocking_threads = 24;

            builder.max_blocking_threads(max_blocking_threads);
        }
        let runtime = builder.build()?;
        Ok(Self {
            handle: Arc::new(runtime.handle().clone()).into(),
            _runtime: DynDrop::new(runtime),
        })
    }
}
