
header "sys" as sys

#if OS != win
use mem
#end

+ class Mutex[T] imut {
	- mutex: ptr

	#if is_void_type(T)

	+ static fn new() SELF { 
		#if OS == win
		let mut = sys:CreateMutexA(null, false, null)
        #else
		let mut = mem:calloc(64)
		sys:pthread_mutex_init(mut, null)
		#end
		return SELF { mutex: mut }
	}

	+ fn lock() void {
        #if OS == win
        sys:WaitForSingleObject(this.mutex, sys:INFINITE.@cast(u32))
        #else
		sys:pthread_mutex_lock(this.mutex)
		#end
	}

	+ fn unlock() void {
        #if OS == win
        sys:ReleaseMutex(this.mutex)
        #else
		sys:pthread_mutex_unlock(this.mutex)
		#end
	}

	#else
	- value: T

	+ static fn new(value: T) SELF { 
		#if OS == win
		let mut = sys:CreateMutexA(null, false, null)
        #else
		let mut = mem:calloc(sys:CONST.mutex_size)
		sys:pthread_mutex_init(mut, null)
		#end
		return SELF { mutex: mut, value: value }
	}

	+ fn lock() T {
        #if OS == win
        sys:WaitForSingleObject(this.mutex, sys:INFINITE.@cast(u32))
        #else
		sys:pthread_mutex_lock(this.mutex)
		#end
		return swap this.value with null
	}

	+ fn unlock(value: T) void {
        #if OS == win
        sys:ReleaseMutex(this.mutex)
        #else
		sys:pthread_mutex_unlock(this.mutex)
		this.value = value
		#end
	}

	#end

	fn gc_free() void {
        #if OS == win
        sys:CloseHandle(this.mutex)
        #else
		sys:pthread_mutex_destroy(this.mutex)
		mem:free(this.mutex)
		#end
	}
}
