import typing
import functools
import asyncio


def executor_function(sync_function: typing.Callable):
    # Taken from Jishaku ( https://github.com/Gorialis/jishaku/blob/master/jishaku/functools.py#L20 )
    """
    A decorator that wraps a sync function in an executor, changing it into an async function.
    This allows processing functions to be wrapped and used immediately as an async function.

    Parameters
    ----------
    sync_function : typing.Callable
        The function to be wrapped.

    Returns
    -------
    typing.Callable
        The wrapped function as a coroutine.
    """

    @functools.wraps(sync_function)
    async def sync_wrapper(*args, **kwargs):
        """
        Asynchronous function that wraps a sync function with an executor.
        """

        loop = asyncio.get_event_loop()
        internal_function = functools.partial(sync_function, *args, **kwargs)
        return await loop.run_in_executor(None, internal_function)

    return sync_wrapper