#pragma once

#include "errors.h"

#include <util/generic/strbuf.h>

namespace NSrvKernel {

    template <class Call>
    auto RSyscallImpl(TSourceLocation src, TStringBuf mess, Call&& call) noexcept {
        using TRes = TErrorOr<decltype(call())>;
        auto ret = call();
        if (ret == (decltype(ret)(-1))) {
            auto err = LastSystemError();
            return TRes(MakeError<TSystemError>(src + TSystemError(err) << mess));
        }
        return TRes(ret);
    }

    template <class Call>
    auto SyscallImpl(TSourceLocation src, TStringBuf mess, Call&& call) noexcept {
        return RSyscallImpl(src, mess, std::forward<Call>(call)).ReleaseError();
    }

#if defined(Y_SYSCALL) || defined(Y_R_SYSCALL)
#   error "already defined"
#endif

#define Y_SYSCALL(call) \
    ::NSrvKernel::SyscallImpl( __LOCATION__, #call, [&](){ return call; })

#define Y_R_SYSCALL(call) \
    ::NSrvKernel::RSyscallImpl( __LOCATION__, #call, [&](){ return call; })
}
