#include <nstd/core/optional.h>
#include <nstd/core/result.h>
#include <nstd/core/time.h>
#include <nstd/heap_ptr.h>
#include <nstd/nstd.h>
#include <nstd/thread.h>
#include <nstd/timed_mutex.h>
#include <chrono>
#include <mutex>
#ifdef NSTD_TIMED_MUTEX_OS_UNIX_IMPL
# include <nstd/os/unix/mutex.h>
#endif
NSTDAPI NSTDOptionalTimedMutex nstd_timed_mutex_new(const NSTDHeapPtr data) {
#ifdef NSTD_TIMED_MUTEX_OS_UNIX_IMPL
return nstd_os_unix_mutex_new(data);
#else
try {
const std::timed_mutex *const mutex{new std::timed_mutex{}};
const NSTDTimedMutex timed_mutex{(NSTDAnyMut)mutex, data, NSTD_FALSE, NSTD_FALSE};
return NSTDOptionalTimedMutex{NSTD_OPTIONAL_SOME, {timed_mutex}};
} catch (...) {
return NSTDOptionalTimedMutex{NSTD_OPTIONAL_NONE, {}};
}
#endif
}
NSTDAPI NSTDBool nstd_timed_mutex_is_poisoned(const NSTDTimedMutex *const mutex) {
#ifdef NSTD_TIMED_MUTEX_OS_UNIX_IMPL
return nstd_os_unix_mutex_is_poisoned(mutex);
#else
return mutex->poisoned;
#endif
}
NSTDAPI NSTDOptionalTimedMutexLockResult nstd_timed_mutex_lock(const NSTDTimedMutex *const mutex) {
#ifdef NSTD_TIMED_MUTEX_OS_UNIX_IMPL
return nstd_os_unix_mutex_lock(mutex);
#else
try {
((std::timed_mutex *)mutex->inner)->lock();
const_cast<NSTDTimedMutex *>(mutex)->locked = NSTD_TRUE;
NSTDOptionalTimedMutexLockResult ret{NSTD_OPTIONAL_SOME, {}};
const NSTDTimedMutexGuard guard{mutex};
if (mutex->poisoned)
ret.value.some = NSTDTimedMutexLockResult{NSTD_RESULT_ERR, {guard}};
else
ret.value.some = NSTDTimedMutexLockResult{NSTD_RESULT_OK, {guard}};
return ret;
} catch (...) {
return NSTDOptionalTimedMutexLockResult{NSTD_OPTIONAL_NONE, {}};
}
#endif
}
NSTDAPI NSTDOptionalTimedMutexLockResult nstd_timed_mutex_try_lock(const NSTDTimedMutex *const mutex
) {
#ifdef NSTD_TIMED_MUTEX_OS_UNIX_IMPL
return nstd_os_unix_mutex_try_lock(mutex);
#else
if (((std::timed_mutex *)mutex->inner)->try_lock()) {
const_cast<NSTDTimedMutex *>(mutex)->locked = NSTD_TRUE;
NSTDOptionalTimedMutexLockResult ret{NSTD_OPTIONAL_SOME, {}};
const NSTDTimedMutexGuard guard{mutex};
if (mutex->poisoned)
ret.value.some = NSTDTimedMutexLockResult{NSTD_RESULT_ERR, {guard}};
else
ret.value.some = NSTDTimedMutexLockResult{NSTD_RESULT_OK, {guard}};
return ret;
} else
return NSTDOptionalTimedMutexLockResult{NSTD_OPTIONAL_NONE, {}};
#endif
}
NSTDAPI NSTDOptionalTimedMutexLockResult
nstd_timed_mutex_timed_lock(const NSTDTimedMutex *const mutex, const NSTDDuration duration) {
#ifdef NSTD_TIMED_MUTEX_OS_UNIX_IMPL
return nstd_os_unix_mutex_timed_lock(mutex, duration);
#else
const std::chrono::duration<NSTDFloat64> dur{nstd_core_time_duration_get(duration)};
if (((std::timed_mutex *)mutex->inner)->try_lock_for(dur)) {
const_cast<NSTDTimedMutex *>(mutex)->locked = NSTD_TRUE;
NSTDOptionalTimedMutexLockResult ret{NSTD_OPTIONAL_SOME, {}};
const NSTDTimedMutexGuard guard{mutex};
if (mutex->poisoned)
ret.value.some = NSTDTimedMutexLockResult{NSTD_RESULT_ERR, {guard}};
else
ret.value.some = NSTDTimedMutexLockResult{NSTD_RESULT_OK, {guard}};
return ret;
} else
return NSTDOptionalTimedMutexLockResult{NSTD_OPTIONAL_NONE, {}};
#endif
}
NSTDAPI NSTDAny nstd_timed_mutex_get(const NSTDTimedMutexGuard *const guard) {
#ifdef NSTD_TIMED_MUTEX_OS_UNIX_IMPL
return nstd_os_unix_mutex_get(guard);
#else
return nstd_heap_ptr_get(&guard->mutex->data);
#endif
}
NSTDAPI NSTDAnyMut nstd_timed_mutex_get_mut(NSTDTimedMutexGuard *const guard) {
#ifdef NSTD_TIMED_MUTEX_OS_UNIX_IMPL
return nstd_os_unix_mutex_get_mut(guard);
#else
return nstd_heap_ptr_get_mut(const_cast<NSTDHeapPtr *>(&guard->mutex->data));
#endif
}
NSTDAPI NSTDOptionalHeapPtr nstd_timed_mutex_into_inner(const NSTDTimedMutex mutex) {
#ifdef NSTD_TIMED_MUTEX_OS_UNIX_IMPL
return nstd_os_unix_mutex_into_inner(mutex);
#else
if (!mutex.locked)
delete (std::timed_mutex *)mutex.inner;
if (!mutex.poisoned)
return NSTDOptionalHeapPtr{NSTD_OPTIONAL_SOME, {mutex.data}};
else {
nstd_heap_ptr_free(mutex.data);
return NSTDOptionalHeapPtr{NSTD_OPTIONAL_NONE, {}};
}
#endif
}
NSTDAPI void nstd_timed_mutex_unlock(const NSTDTimedMutexGuard guard) {
#ifdef NSTD_TIMED_MUTEX_OS_UNIX_IMPL
nstd_os_unix_mutex_unlock(guard);
#else
NSTDTimedMutex *const mutex{const_cast<NSTDTimedMutex *>(guard.mutex)};
if (nstd_thread_is_panicking())
mutex->poisoned = NSTD_TRUE;
mutex->locked = NSTD_FALSE;
((std::timed_mutex *)mutex->inner)->unlock();
#endif
}
NSTDAPI void nstd_timed_mutex_free(const NSTDTimedMutex mutex) {
#ifdef NSTD_TIMED_MUTEX_OS_UNIX_IMPL
nstd_os_unix_mutex_free(mutex);
#else
if (!mutex.locked)
delete (std::timed_mutex *)mutex.inner;
nstd_heap_ptr_free(mutex.data);
#endif
}
NSTDAPI void nstd_timed_mutex_drop(const NSTDTimedMutex mutex, void (*const callback)(NSTDAnyMut)) {
#ifdef NSTD_TIMED_MUTEX_OS_UNIX_IMPL
nstd_os_unix_mutex_drop(mutex, callback);
#else
if (!mutex.locked)
delete (std::timed_mutex *)mutex.inner;
if (!mutex.poisoned)
nstd_heap_ptr_drop(mutex.data, callback);
else
nstd_heap_ptr_free(mutex.data);
#endif
}