///|
/// The fallback reason used when callers pass an empty or whitespace-only
/// reason.
///
/// This value is intentionally readable because some native backends expose the
/// reason in system diagnostics or activity monitors. Applications can override
/// it per call when they want more task-specific text, but keeping a default
/// reason makes the simple API path ergonomic.
pub let default_reason : String = "MoonBit keepawake request"
///|
/// Acquires a keep-awake guard for the current operating system.
///
/// The returned guard activates the native inhibition immediately and keeps it
/// alive until `Guard::release` is called or the guard is reclaimed by the
/// runtime. On Windows the reclaim path may run on a different thread; the
/// release is accounted for correctly, but the acquiring thread's power-state
/// flags can persist until that thread exits, so explicit release from the
/// acquiring thread is recommended. Blank reasons are normalized to
/// `default_reason` so callers can keep call sites simple without losing
/// readable backend diagnostics.
///
/// `reason` should describe the user-visible work being protected, such as
/// `"Exporting a large report"` or `"Downloading offline assets"`. `scope`
/// controls whether the request blocks system sleep, display sleep, or both.
///
/// Prefer `acquire` when your code naturally manages a long-lived handle. If
/// the work is already scoped to a single callback, `with_keepawake` is usually
/// more convenient because it guarantees structured release.
///
/// # Errors
///
/// Raises `KeepAwakeError::BackendUnavailable` when the current environment
/// cannot provide a usable keep-awake backend, and raises
/// `KeepAwakeError::OperationFailed` when a backend exists but the native
/// acquire step still fails.
///
/// # Example
/// ```mbt nocheck
/// let guard = @proton_keepawake.acquire(
/// reason="Encoding a large video",
/// scope=@proton_keepawake.Scope::PreventSystemAndDisplaySleep,
/// )
///
/// // ... perform the long-running work ...
///
/// guard.release()
/// ```
pub fn acquire(
reason? : String = default_reason,
scope? : Scope = Scope::PreventSystemSleep,
) -> Guard raise KeepAwakeError {
let handle = native_guard_create(
@ffi.to_cstr(normalize_reason(reason)),
scope.native_code(),
)
finish_acquire(handle)
}
///|
/// Runs an action while a keep-awake guard is held.
///
/// This is the most ergonomic API for scoped work such as file exports, build
/// steps, or long-running synchronization tasks. The guard is released after
/// `action` finishes. If `action` raises, release is still attempted and any
/// release failure is suppressed in favor of the original error.
///
/// This helper is the best default when the keep-awake lifetime should exactly
/// match one operation. It keeps the call site small, avoids leaking a guard in
/// early-return branches, and preserves the original application error if both
/// the action and the release step fail.
///
/// `reason` and `scope` behave the same way as in `acquire`. The return value
/// of `action` is passed through unchanged.
///
/// # Errors
///
/// Raises the same `KeepAwakeError` values as `acquire`, plus any error raised
/// by `action`.
///
/// # Example
/// ```mbt nocheck
/// let summary = @proton_keepawake.with_keepawake(
/// () => "done",
/// reason="Syncing local cache",
/// // ... perform long-running work ...
/// scope=@proton_keepawake.Scope::PreventSystemSleep,
/// )
/// ```
pub fn[T] with_keepawake(
action : () -> T raise?,
reason? : String = default_reason,
scope? : Scope = Scope::PreventSystemSleep,
) -> T raise {
let handle = acquire(reason~, scope~)
run_with_cleanup(fn() -> T raise { action() }, fn() -> Unit raise {
handle.release()
})
}
///|
/// Returns whether the underlying native inhibition is still active.
///
/// This becomes `false` after a successful call to `Guard::release`, and it is
/// also `false` for guards returned by a failed acquire attempt before the
/// error is raised to the caller.
///
/// Use this method for diagnostics, assertions, or defensive checks around
/// cleanup-heavy workflows. Most callers do not need to poll it during normal
/// operation because the guard exposes only a single lifecycle boundary:
/// active versus released.
pub fn Guard::active(self : Guard) -> Bool {
native_guard_is_active(self)
}
///|
/// Returns the scope that was requested when the guard was created.
///
/// This is the semantic scope originally passed to `acquire` or
/// `with_keepawake`, not a platform-specific low-level flag set. It is useful
/// when code stores guards in higher-level abstractions and later wants to
/// inspect or report what kind of inhibition is currently in effect.
pub fn Guard::scope(self : Guard) -> Scope {
scope_from_native_code(native_guard_scope_code(self))
}
///|
/// Releases the native keep-awake request.
///
/// Releasing a guard is idempotent. Calling `release` on an inactive guard is a
/// no-op. If the backend reports an unexpected release failure, this method
/// raises `KeepAwakeError::OperationFailed`.
///
/// Call this as soon as the protected work finishes when you acquired the guard
/// manually. Releasing early is preferred over waiting for runtime cleanup,
/// because explicit release makes the lifetime obvious and avoids depending on
/// garbage collection timing.
///
/// # Errors
///
/// Raises `KeepAwakeError::OperationFailed` if the backend reports that the
/// native release operation did not complete successfully.
pub fn Guard::release(self : Guard) -> Unit raise KeepAwakeError {
let status = native_guard_release(self)
finish_release(status, native_guard_last_error(self))
}