// Copyright 2026 International Digital Economy Academy
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
///|
type Mutex
///|
extern "c" fn uv_mutex_make() -> Mutex = "moonbit_uv_mutex_make"
///|
#owned(mutex)
extern "c" fn uv_mutex_init(mutex : Mutex) -> Int = "moonbit_uv_mutex_init"
///|
pub fn Mutex::new() -> Mutex raise Errno {
let mutex = uv_mutex_make()
let status = uv_mutex_init(mutex)
if status != 0 {
raise Errno::of_int(status)
}
return mutex
}
///|
#owned(mutex, other)
extern "c" fn uv_mutex_copy(mutex : Mutex, other : Mutex) = "moonbit_uv_mutex_copy"
///|
#owned(mutex)
extern "c" fn uv_mutex_lock(mutex : Mutex) = "moonbit_uv_mutex_lock"
///|
#owned(mutex)
extern "c" fn uv_mutex_trylock(mutex : Mutex) -> Int = "moonbit_uv_mutex_trylock"
///|
#owned(mutex)
extern "c" fn uv_mutex_unlock(mutex : Mutex) = "moonbit_uv_mutex_unlock"
///|
pub fn Mutex::lock(self : Mutex) -> Unit {
uv_mutex_lock(self)
}
///|
pub fn Mutex::trylock(self : Mutex) -> Unit raise Errno {
let status = uv_mutex_trylock(self)
if status < 0 {
raise Errno::of_int(status)
}
}
///|
pub fn Mutex::unlock(self : Mutex) -> Unit {
uv_mutex_unlock(self)
}
///|
/// Shares an object safely between threads.
///
/// In MoonBit, the default reference counting (RC) for objects is not atomic,
/// so it is not safe to share most objects directly between threads.
///
/// To enable safe sharing, we use a separate atomic reference counter (ARC)
/// stored alongside the actual object data. The MoonBit object itself is
/// managed by non-atomic RC, but the shared payload is managed by ARC.
///
/// When you want to share an object:
/// - The MoonBit object holds a pointer to a heap-allocated block containing
/// both the ARC and the payload (e.g., a mutex or thread handle).
/// - Copying the MoonBit object only copies the pointer; the ARC is incremented
/// atomically (guarded by a mutex if needed).
/// - When a copy is dropped, the ARC is decremented atomically. When ARC
/// reaches zero, the payload is freed.
///
/// Example: `uv_thread_t` stores an `arc` field and a `uv_mutex_t` object in a
/// heap-allocated block. All increments/decrements of `arc` are protected by
/// the mutex to ensure thread safety.
///
/// Diagram:
///
/// ```plaintext
/// (thread 0) (thread 1)
/// +--------+ +--------+
/// | rc (M) | | rc (M) |
/// +--------+ +--------+
/// \ /
/// \---> +---------+ <---/
/// | arc (F) |
/// +---------+
/// | mutex |
/// +---------+
/// | payload |
/// +---------+
/// ```
///
/// The `Share` trait provides a `share` method to allow implementor of this
/// trait to create a new MoonBit object pointing to the same shared payload,
/// incrementing the ARC safely.
pub trait Share {
share(Self) -> Self
}
///|
pub impl Share for Mutex with share(self : Mutex) -> Mutex {
let other = uv_mutex_make()
uv_mutex_copy(self, other)
return other
}