def bind_callsig(sig, args, kwargs):
    """Returns a dict with each parameter name from ``sig`` mapped to
    values from ``args``, ``kwargs`` as if a function with ``sig``
    was called with ``(*args, **kwargs)``.

    Similar to `inspect.Signature.bind`."""
    assigned = {}

    varkwargs = next(
        (param for param in sig.parameters.values()
        if param.kind == param.VAR_KEYWORD), None)
    if varkwargs:
        assigned[varkwargs.name] = {}

    params = iter(sig.parameters.values())
    args_ = iter(args)
    i = 0
    for (i, posarg), param in zip(enumerate(args_, 1), params):
        if param.kind in (param.POSITIONAL_ONLY, param.POSITIONAL_OR_KEYWORD):
            assigned[param.name] = posarg
        elif param.kind == param.VAR_POSITIONAL:
            assigned[param.name] = (posarg,) + tuple(args_)
            break
        else:
            raise TypeError('too many positional arguments')
    else:
        if args[:i] != args:
            raise TypeError('too many positional arguments')

    for key, value in kwargs.items():
        if key in sig.parameters:
            param = sig.parameters[key]
            if param.kind == param.POSITIONAL_ONLY:
                raise TypeError('{0!r} is positional-only'.format(key))
            elif param.kind in (param.POSITIONAL_OR_KEYWORD,
                                param.KEYWORD_ONLY):
                if key in assigned:
                    raise TypeError('{0!r} was specified twice'.format(key))
                assigned[key] = value
                continue
        if varkwargs:
            assigned[varkwargs.name][key] = value
        else:
            raise TypeError('unknown parameter {0!r}'.format(key))

    for param in sig.parameters.values():
        if param.name not in assigned:
            if param.kind == param.VAR_POSITIONAL:
                assigned[param.name] = ()
            elif param.default != param.empty:
                assigned[param.name] = param.default
            else:
                raise TypeError('omitted required parameter {0!r}'.format(
                    param.name))

    return assigned