/**
 * Runtime helpers for turning an `Effect` program into a host application's
 * main entry point.
 *
 * This module is the low-level layer used by platform adapters to run a main
 * effect, observe its fiber, report unhandled failures, and translate the
 * resulting `Exit` into an application or process exit code. Application code
 * usually calls the platform-provided runner; runtime integrations use
 * {@link makeRunMain} directly.
 *
 * **Mental model**
 *
 * - {@link makeRunMain} forks the supplied `Effect` and gives the host adapter
 *   the running fiber plus a teardown callback
 * - The host adapter installs platform-specific hooks such as signal handlers,
 *   fiber observers, process exits, worker termination, or test harness
 *   callbacks
 * - {@link defaultTeardown} maps successful exits to `0`, interruption-only
 *   failures to `130`, failures with {@link errorExitCode} to that code, and
 *   other failures to `1`
 * - {@link errorReported} controls automatic failure logging; set it to
 *   `false` on errors that have already been reported
 *
 * **Common tasks**
 *
 * - Build a platform runner: {@link makeRunMain}
 * - Reuse the standard exit-code rules: {@link defaultTeardown}
 * - Customize failure exit codes: {@link errorExitCode},
 *   {@link getErrorExitCode}
 * - Control automatic failure logging: {@link errorReported},
 *   {@link getErrorReported}
 *
 * **Gotchas**
 *
 * - `makeRunMain` starts the main fiber, but the adapter callback is
 *   responsible for observing that fiber and eventually invoking teardown.
 * - `disableErrorReporting` only disables automatic failure logging. It does
 *   not change the `Exit`, interruption behavior, or teardown exit-code rules.
 * - Error markers are read from `Cause.squash(cause)`, so causes with multiple
 *   failures use the squashed failure value to determine logging and exit code.
 *
 * **Example** (Creating a minimal runner)
 *
 * ```ts
 * import { Effect, Runtime } from "effect"
 *
 * const runMain = Runtime.makeRunMain(({ fiber, teardown }) => {
 *   fiber.addObserver((exit) => {
 *     teardown(exit, (code) => {
 *       console.log(`finished with exit code ${code}`)
 *     })
 *   })
 * })
 *
 * runMain(Effect.log("booted"))
 * ```
 *
 * @since 4.0.0
 */
import * as Cause from "effect/Cause";
import * as Effect from "effect/Effect";
import * as Exit from "effect/Exit";
import { constVoid, dual } from "effect/Function";
/**
 * The default teardown function that determines exit codes from an Effect exit.
 *
 * **When to use**
 *
 * Use as the standard teardown for main programs when you want conventional
 * process exit codes and support for {@link errorExitCode}.
 *
 * **Details**
 *
 * This teardown follows these exit-code rules:
 *
 * - `0` for successful completion.
 * - `130` for interruption-only failures.
 * - The squashed error's {@link errorExitCode} value for other failures when
 *   present.
 * - `1` for other failures.
 *
 * **Gotchas**
 *
 * The `130` code is used only when the Cause contains interruptions and no
 * other failure reasons. Mixed causes use the squashed error path instead.
 *
 * **Example** (Using default teardown)
 *
 * ```ts
 * import { Exit, Runtime } from "effect"
 *
 * const logExitCode = (exit: Exit.Exit<any, any>) => {
 *   Runtime.defaultTeardown(exit, (code) => {
 *     console.log(`Exit code: ${code}`)
 *   })
 * }
 *
 * logExitCode(Exit.succeed(42))
 * // Output: Exit code: 0
 *
 * logExitCode(Exit.fail("error"))
 * // Output: Exit code: 1
 *
 * logExitCode(Exit.interrupt(123))
 * // Output: Exit code: 130
 * ```
 *
 * @see {@link errorExitCode} for customizing failure exit codes
 *
 * @category running
 * @since 4.0.0
 */
export const defaultTeardown = (exit, onExit) => {
  if (Exit.isSuccess(exit)) return onExit(0);
  if (Cause.hasInterruptsOnly(exit.cause)) return onExit(130);
  return onExit(getErrorExitCode(Cause.squash(exit.cause)));
};
/**
 * Creates a platform-specific main program runner that handles Effect execution lifecycle.
 *
 * **When to use**
 *
 * Use when building a runtime adapter for a host platform. Most applications
 * should use a platform-provided runner, such as `NodeRuntime.runMain`, rather
 * than constructing one directly.
 *
 * **Details**
 *
 * The runner executes Effect programs as main entry points. The provided function receives a forked fiber and a teardown callback so it can install platform-specific signal handling, fiber observers, and final exit behavior.
 *
 * `disableErrorReporting` disables the automatic log emitted for unreported
 * non-interruption failures. It does not change exit-code calculation or the
 * custom teardown callback.
 *
 * **Gotchas**
 *
 * The setup function is responsible for observing the fiber and eventually
 * invoking teardown. `makeRunMain` also tries to keep the host process alive
 * with a long interval while the main fiber is running; if the host blocks
 * timers, the runner still starts but cannot use that keep-alive fallback.
 *
 * **Example** (Creating platform runners)
 *
 * ```ts
 * import { Effect, Fiber, Runtime } from "effect"
 *
 * // Create a simple runner for a hypothetical platform
 * const runMain = Runtime.makeRunMain(({ fiber, teardown }) => {
 *   // Set up signal handling
 *   const handleSignal = () => {
 *     Effect.runSync(Fiber.interrupt(fiber))
 *   }
 *
 *   // Add signal listeners (platform-specific)
 *   // process.on('SIGINT', handleSignal)
 *   // process.on('SIGTERM', handleSignal)
 *
 *   // Handle fiber completion
 *   fiber.addObserver((exit) => {
 *     teardown(exit, (code) => {
 *       console.log(`Program finished with exit code: ${code}`)
 *       // process.exit(code)
 *     })
 *   })
 * })
 *
 * // Use the runner
 * const program = Effect.gen(function*() {
 *   yield* Effect.log("Starting program")
 *   yield* Effect.sleep(1000)
 *   yield* Effect.log("Program completed")
 *   return "success"
 * })
 *
 * // Run with default options
 * runMain(program)
 *
 * // Run with custom teardown
 * runMain(program, {
 *   teardown: (exit, onExit) => {
 *     console.log("Custom teardown logic")
 *     Runtime.defaultTeardown(exit, onExit)
 *   }
 * })
 * ```
 *
 * @category running
 * @since 4.0.0
 */
export const makeRunMain = f => dual(args => Effect.isEffect(args[0]), (effect, options) => {
  const fiber = options?.disableErrorReporting === true ? Effect.runFork(effect) : Effect.runFork(Effect.tapCause(effect, cause => {
    if (Cause.hasInterruptsOnly(cause)) return Effect.void;
    const isReported = getErrorReported(Cause.squash(cause));
    return isReported ? Effect.logError(cause) : Effect.void;
  }));
  try {
    const keepAlive = globalThis.setInterval(constVoid, 2_147_483_647);
    fiber.addObserver(() => {
      clearInterval(keepAlive);
    });
  } catch {}
  const teardown = options?.teardown ?? defaultTeardown;
  return f({
    fiber,
    teardown
  });
});
/**
 * Allows associating an exit code with an error for determining the process
 * exit code on failure.
 *
 * **When to use**
 *
 * Use when error classes should map failures to a specific process exit code
 * when handled by {@link defaultTeardown}.
 *
 * **Details**
 *
 * Attach this marker as a readonly property on an error object. When the main
 * program fails, {@link defaultTeardown} squashes the Cause and reads the marker
 * from the resulting error value.
 *
 * **Gotchas**
 *
 * The marker is read from the squashed failure value. If a Cause contains
 * multiple failures, the selected squashed error determines the exit code.
 *
 * **Example** (Setting a process exit code)
 *
 * ```ts
 * import { Data, Effect, Runtime } from "effect"
 * import { NodeRuntime } from "@effect/platform-node"
 *
 * class MyError extends Data.TaggedError("MyError") {
 *   readonly [Runtime.errorExitCode] = 42
 * }
 *
 * // If the program fails with MyError, the process will exit with code 42
 * NodeRuntime.runMain(Effect.fail(new MyError()))
 * ```
 *
 * @see {@link errorReported} for controlling automatic error logging
 * @see {@link defaultTeardown} for the default failure exit-code rules that read this marker
 * @see {@link getErrorExitCode} for reading the marker from unknown error values
 *
 * @category symbols
 * @since 4.0.0
 */
export const errorExitCode = "~effect/Runtime/errorExitCode";
/**
 * Reads the runtime exit-code marker from an unknown error value.
 *
 * **When to use**
 *
 * Use to read a custom failure exit code from an unknown error value, falling
 * back to the default failure code.
 *
 * **Details**
 *
 * Returns the numeric `[Runtime.errorExitCode]` property when it is present on
 * an object. Otherwise returns `1`, the default failure exit code used by
 * `defaultTeardown`.
 *
 * **Gotchas**
 *
 * Non-object values, missing markers, and non-number marker values all return
 * `1`.
 *
 * @see {@link errorExitCode} for the marker read by this function
 *
 * @category accessors
 * @since 4.0.0
 */
export const getErrorExitCode = u => {
  if (typeof u === "object" && u !== null && errorExitCode in u) {
    const code = u[errorExitCode];
    if (typeof code === "number") {
      return code;
    }
  }
  return 1;
};
/**
 * Defines the runtime marker that controls default `runMain` error logging for an error.
 *
 * **When to use**
 *
 * Use when error classes are already reported by application code and should
 * not be logged again by the default main runner.
 *
 * **Details**
 *
 * Set `[Runtime.errorReported]` to `false` on an error object to suppress the
 * runtime log because the error has already been reported. Omitted or
 * non-boolean values are treated as `true`, so failures are logged by default.
 *
 * **Gotchas**
 *
 * This marker controls only automatic error logging. It does not change the
 * failure Cause or the process exit code.
 * `makeRunMain` reads the marker from `Cause.squash(cause)`, so for causes
 * with multiple failures, the squashed error determines whether default logging
 * is suppressed.
 *
 * **Example** (Suppressing error reporting)
 *
 * ```ts
 * import { Data, Effect, Runtime } from "effect"
 * import { NodeRuntime } from "@effect/platform-node"
 *
 * class MyError extends Data.TaggedError("MyError") {
 *   readonly [Runtime.errorReported] = false
 * }
 *
 * // If the program fails with MyError, the process will exit with code 1 but
 * // no error will be logged.
 * NodeRuntime.runMain(Effect.fail(new MyError()))
 * ```
 *
 * @see {@link errorExitCode} for controlling failure exit codes
 * @see {@link getErrorReported} for reading the marker from unknown error values
 *
 * @category symbols
 * @since 4.0.0
 */
export const errorReported = "~effect/Runtime/errorReported";
/**
 * Reads the runtime error-reporting marker from an unknown error value.
 *
 * **When to use**
 *
 * Use to read whether an unknown error value should be treated as already
 * reported by the default main runner.
 *
 * **Details**
 *
 * Returns a boolean `[Runtime.errorReported]` property when it is present on an
 * object. Otherwise returns `true`, so failures are logged by default.
 *
 * **Gotchas**
 *
 * Non-object values, missing markers, and non-boolean marker values all return
 * `true`.
 *
 * @see {@link errorReported} for the marker read by this function
 *
 * @category accessors
 * @since 4.0.0
 */
export const getErrorReported = u => {
  if (typeof u === "object" && u !== null && errorReported in u) {
    const isReported = u[errorReported];
    if (typeof isReported === "boolean") {
      return isReported;
    }
  }
  return true;
};
//# sourceMappingURL=Runtime.js.map