//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2020 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

import Swift
@_implementationOnly import SwiftConcurrencyInternalShims

// ==== Task -------------------------------------------------------------------

/// A unit of asynchronous work.
///
/// When you create an instance of `Task`,
/// you provide a closure that contains the work for that task to perform.
/// Tasks can start running immediately after creation;
/// you don't explicitly start or schedule them.
/// After creating a task, you use the instance to interact with it ---
/// for example, to wait for it to complete or to cancel it.
/// It's not a programming error to discard a reference to a task
/// without waiting for that task to finish or canceling it.
/// A task runs regardless of whether you keep a reference to it.
/// However, if you discard the reference to a task,
/// you give up the ability
/// to wait for that task's result or cancel the task.
///
/// To support operations on the current task,
/// which can be either a detached task or child task,
/// `Task` also exposes class methods like `yield()`.
/// Because these methods are asynchronous,
/// they're always invoked as part of an existing task.
///
/// Only code that's running as part of the task can interact with that task.
/// To interact with the current task,
/// you call one of the static methods on `Task`.
///
/// A task's execution can be seen as a series of periods where the task ran.
/// Each such period ends at a suspension point or the
/// completion of the task.
/// These periods of execution are represented by instances of `PartialAsyncTask`.
/// Unless you're implementing a custom executor,
/// you don't directly interact with partial tasks.
///
/// For information about the language-level concurrency model that `Task` is part of,
/// see [Concurrency][concurrency] in [The Swift Programming Language][tspl].
///
/// [concurrency]: https://docs.swift.org/swift-book/LanguageGuide/Concurrency.html
/// [tspl]: https://docs.swift.org/swift-book/
///
/// Task Cancellation
/// =================
///
/// Tasks include a shared mechanism for indicating cancellation,
/// but not a shared implementation for how to handle cancellation.
/// Depending on the work you're doing in the task,
/// the correct way to stop that work varies.
/// Likewise,
/// it's the responsibility of the code running as part of the task
/// to check for cancellation whenever stopping is appropriate.
/// In a long-task that includes multiple pieces,
/// you might need to check for cancellation at several points,
/// and handle cancellation differently at each point.
/// If you only need to throw an error to stop the work,
/// call the `Task.checkCancellation()` function to check for cancellation.
/// Other responses to cancellation include
/// returning the work completed so far, returning an empty result, or returning `nil`.
///
/// Cancellation is a purely Boolean state;
/// there's no way to include additional information
/// like the reason for cancellation.
/// This reflects the fact that a task can be canceled for many reasons,
/// and additional reasons can accrue during the cancellation process.
///
/// ### Task closure lifetime
/// Tasks are initialized by passing a closure containing the code that will be executed by a given task.
///
/// After this code has run to completion, the task has completed, resulting in either
/// a failure or result value, this closure is eagerly released.
///
/// Retaining a task object doesn't indefinitely retain the closure,
/// because any references that a task holds are released
/// after the task completes.
/// Consequently, tasks rarely need to capture weak references to values.
///
/// For example, in the following snippet of code it is not necessary to capture the actor as `weak`,
/// because as the task completes it'll let go of the actor reference, breaking the
/// reference cycle between the Task and the actor holding it.
///
/// ```
/// struct Work: Sendable {}
///
/// actor Worker {
///     var work: Task<Void, Never>?
///     var result: Work?
///
///     deinit {
///         // even though the task is still retained,
///         // once it completes it no longer causes a reference cycle with the actor
///
///         print("deinit actor")
///     }
///
///     func start() {
///         work = Task {
///             print("start task work")
///             try? await Task.sleep(for: .seconds(3))
///             self.result = Work() // we captured self
///             print("completed task work")
///             // but as the task completes, this reference is released
///         }
///         // we keep a strong reference to the task
///     }
/// }
/// ```
///
/// And using it like this:
///
/// ```
/// await Worker().start()
/// ```
///
/// Note that the actor is only retained by the start() method's use of `self`,
/// and that the start method immediately returns, without waiting for the
/// unstructured `Task` to finish. Once the task is completed and its closure is
/// destroyed, the strong reference to the actor is also released allowing the
/// actor to deinitialize as expected.
///
/// Therefore, the above call will consistently result in the following output:
///
/// ```other
/// start task work
/// completed task work
/// deinit actor
/// ```
@available(SwiftStdlib 5.1, *)
@frozen
public struct Task<Success: Sendable, Failure: Error>: Sendable {
  @usableFromInline
  @available(SwiftStdlib 5.1, *)
  internal let _task: Builtin.NativeObject

  @_alwaysEmitIntoClient
  internal init(_ task: Builtin.NativeObject) {
    self._task = task
  }
}

@available(SwiftStdlib 5.1, *)
extension Task {
  /// The result from a throwing task, after it completes.
  ///
  /// If the task hasn't completed,
  /// accessing this property waits for it to complete
  /// and its priority increases to that of the current task.
  /// Note that this might not be as effective as
  /// creating the task with the correct priority,
  /// depending on the executor's scheduling details.
  ///
  /// If the task throws an error, this property propagates that error.
  /// Tasks that respond to cancellation by throwing `CancellationError`
  /// have that error propagated here upon cancellation.
  ///
  /// - Returns: The task's result.
  public var value: Success {
    @_alwaysEmitIntoClient
    // This name is slightly different purely to avoid a clash with
    // the original property and keep the mangling concise.
    @_silgen_name("$sScT6_valuexvg")
    get async throws {
      return try await _taskFutureGetThrowing(_task)
    }
  }

  /// This is the original property as it was defined before
  /// adoption of typed throws. It is preserved for backward
  /// compatibility with its original name and shouldn't be
  /// directly referenceable.
  var _abi_value: Success {
    @usableFromInline
    @_silgen_name("$sScT5valuexvg")
    get async throws {
      return try await _taskFutureGetThrowing(_task)
    }
  }

  /// The result or error from a throwing task, after it completes.
  ///
  /// If the task hasn't completed,
  /// accessing this property waits for it to complete
  /// and its priority increases to that of the current task.
  /// Note that this might not be as effective as
  /// creating the task with the correct priority,
  /// depending on the executor's scheduling details.
  ///
  /// - Returns: If the task succeeded,
  ///   `.success` with the task's result as the associated value;
  ///   otherwise, `.failure` with the error as the associated value.
  public var result: Result<Success, Failure> {
    get async {
      do {
        return .success(try await value)
      } catch {
        return .failure(error as! Failure) // as!-safe, guaranteed to be Failure
      }
    }
  }

  /// Cancels this task.
  ///
  /// Cancelling a task has three primary effects:
  ///
  /// - It flags the task as canceled.
  /// - It causes any active cancellation handlers on the task to run, once.
  /// - It cancels any child tasks and task groups of the task, including
  ///   those created in the future. If those tasks have cancellation handlers,
  ///   they also are triggered.
  ///
  /// Task cancellation is cooperative and idempotent.
  ///
  /// Cancelling a task does not automatically cause arbitrary functions on the task
  /// to stop running or throw errors. A function _may_ choose to react
  /// to cancellation by ending its work early, and it is conventional to
  /// signal that to callers by throwing `CancellationError`. However,
  /// a function that doesn't specifically check for cancellation will
  /// run to completion normally, even if the task it is running on is
  /// canceled. However, that function might still end early if it calls
  /// other code that handles cancellation by throwing and that function doesn't
  /// handle the error.
  ///
  /// It's safe to cancel a task from any task or thread. It's safe for
  /// multiple tasks or threads to cancel the same task at the same
  /// time. Cancelling a task that has already been canceled has no
  /// additional effect.
  ///
  /// `cancel` may need to acquire locks and synchronously run
  /// arbitrary cancellation-handler code associated with the
  /// canceled task. To reduce the risk of deadlock, it is
  /// recommended that callers release any locks they might be
  /// holding before they call cancel.
  ///
  /// If the task has already run past the last point where it could have
  /// performed a cancellation check, cancelling it may have no observable effects.
  ///
  /// - SeeAlso: `Task.checkCancellation()`
  /// - SeeAlso: `withTaskCancellationHandler(operation:onCancel:isolation:)`
  public func cancel() {
    unsafe _taskCancel(_AsyncTask(_task))
  }
}

@available(SwiftStdlib 5.1, *)
extension Task where Failure == Never {
  /// The result from a nonthrowing task, after it completes.
  ///
  /// If the task hasn't completed yet,
  /// accessing this property waits for it to complete
  /// and its priority increases to that of the current task.
  /// Note that this might not be as effective as
  /// creating the task with the correct priority,
  /// depending on the executor's scheduling details.
  ///
  /// Tasks that never throw an error can still check for cancellation,
  /// but they need to use an approach like returning `nil`
  /// instead of throwing an error.
  public var value: Success {
    get async {
      return await _taskFutureGet(_task)
    }
  }
}

@available(SwiftStdlib 5.1, *)
extension Task: Hashable {
  public func hash(into hasher: inout Hasher) {
    UnsafeRawPointer(Builtin.bridgeToRawPointer(_task)).hash(into: &hasher)
  }
}

@available(SwiftStdlib 5.1, *)
extension Task: Equatable {
  public static func ==(lhs: Self, rhs: Self) -> Bool {
    unsafe UnsafeRawPointer(Builtin.bridgeToRawPointer(lhs._task)) ==
      UnsafeRawPointer(Builtin.bridgeToRawPointer(rhs._task))
  }
}

// ==== Task Priority ----------------------------------------------------------

/// The priority of a task.
///
/// The executor determines how priority information affects the way tasks are scheduled.
/// The behavior varies depending on the executor currently being used.
/// Typically, executors attempt to run tasks with a higher priority
/// before tasks with a lower priority.
/// However, the semantics of how priority is treated are left up to each
/// platform and `Executor` implementation.
///
/// Child tasks automatically inherit their parent task's priority.
/// Detached tasks created by `detach(priority:operation:)` don't inherit task priority
/// because they aren't attached to the current task.
///
/// In some situations the priority of a task is elevated ---
/// that is, the task is treated as it if had a higher priority,
/// without actually changing the priority of the task:
///
/// - If a task runs on behalf of an actor,
///   and a new higher-priority task is enqueued to the actor,
///   then the actor's current task is temporarily elevated
///   to the priority of the enqueued task.
///   This priority elevation allows the new task
///   to be processed at the priority it was enqueued with.
/// - If a higher-priority task accesses the `value` property,
///   then the priority of this task increases until the task completes.
///
/// In both cases, priority elevation helps you prevent a low-priority task
/// from blocking the execution of a high priority task,
/// which is also known as *priority inversion*.
@available(SwiftStdlib 5.1, *)
public struct TaskPriority: RawRepresentable, Sendable {
  public typealias RawValue = UInt8
  public var rawValue: UInt8

  public init(rawValue: UInt8) {
    self.rawValue = rawValue
  }

  public static let high: TaskPriority = .init(rawValue: 0x19)

  @_alwaysEmitIntoClient
  public static var medium: TaskPriority {
    .init(rawValue: 0x15)
  }

  public static let low: TaskPriority = .init(rawValue: 0x11)

  public static let userInitiated: TaskPriority = high
  public static let utility: TaskPriority = low
  public static let background: TaskPriority = .init(rawValue: 0x09)

  @available(*, deprecated, renamed: "medium")
  public static let `default`: TaskPriority = .init(rawValue: 0x15)
}

@available(SwiftStdlib 5.1, *)
extension TaskPriority: Equatable {
  public static func == (lhs: TaskPriority, rhs: TaskPriority) -> Bool {
    lhs.rawValue == rhs.rawValue
  }

  public static func != (lhs: TaskPriority, rhs: TaskPriority) -> Bool {
    lhs.rawValue != rhs.rawValue
  }
}

@available(SwiftStdlib 5.1, *)
extension TaskPriority: Comparable {
  public static func < (lhs: TaskPriority, rhs: TaskPriority) -> Bool {
    lhs.rawValue < rhs.rawValue
  }

  public static func <= (lhs: TaskPriority, rhs: TaskPriority) -> Bool {
    lhs.rawValue <= rhs.rawValue
  }

  public static func > (lhs: TaskPriority, rhs: TaskPriority) -> Bool {
    lhs.rawValue > rhs.rawValue
  }

  public static func >= (lhs: TaskPriority, rhs: TaskPriority) -> Bool {
    lhs.rawValue >= rhs.rawValue
  }
}


@available(SwiftStdlib 5.9, *)
@_unavailableInEmbedded
extension TaskPriority: CustomStringConvertible {
  @available(SwiftStdlib 5.9, *)
  public var description: String {
    switch self.rawValue {
    case Self.low.rawValue:
      return "\(Self.self).low"
    case Self.medium.rawValue:
      return "\(Self.self).medium"
    case Self.high.rawValue:
      return "\(Self.self).high"
    case Self.background.rawValue:
      return "\(Self.self).background"
    default:
      return "\(Self.self)(rawValue: \(self.rawValue))"
    }
  }
}

#if !SWIFT_CONCURRENCY_EMBEDDED
@available(SwiftStdlib 5.1, *)
extension TaskPriority: Codable { }
#endif

@available(SwiftStdlib 5.1, *)
extension Task where Success == Never, Failure == Never {

  /// The current task's priority.
  ///
  /// If you access this property outside of any task,
  /// this queries the system to determine the
  /// priority at which the current function is running.
  /// If the system can't provide a priority,
  /// this property's value is `Priority.default`.
  public static var currentPriority: TaskPriority {
    unsafe withUnsafeCurrentTask { unsafeTask in
      // If we are running on behalf of a task, use that task's priority.
      if let unsafeTask = unsafe unsafeTask {
         return unsafe unsafeTask.priority
      }

      // Otherwise, query the system.
      return TaskPriority(rawValue: UInt8(_getCurrentThreadPriority()))
    }
  }

  /// The current task's base priority.
  ///
  /// If you access this property outside of any task, this returns nil
  @available(SwiftStdlib 5.7, *)
  public static var basePriority: TaskPriority? {
    unsafe withUnsafeCurrentTask { task in
      // If we are running on behalf of a task, use that task's priority.
      if let unsafeTask = unsafe task {
         return unsafe TaskPriority(rawValue: _taskBasePriority(unsafeTask._rawTask))
      }
      return nil
    }
  }

}

@available(SwiftStdlib 5.1, *)
extension TaskPriority {
  /// Downgrade user-interactive to user-initiated.
  var _downgradeUserInteractive: TaskPriority {
    return self
  }
}

// ==== Job Flags --------------------------------------------------------------

/// Flags for schedulable jobs.
///
/// This is a port of the C++ FlagSet.
@available(SwiftStdlib 5.1, *)
struct JobFlags {
  /// Kinds of schedulable jobs.
  enum Kind: Int32 {
    case task = 0
  }

  /// The actual bit representation of these flags.
  var bits: Int32 = 0

  /// The kind of job described by these flags.
  var kind: Kind {
    get {
      Kind(rawValue: bits & 0xFF)!
    }

    set {
      bits = (bits & ~0xFF) | newValue.rawValue
    }
  }

  /// Whether this is an asynchronous task.
  var isAsyncTask: Bool { kind == .task }

  /// The priority given to the job.
  var priority: TaskPriority? {
    get {
      let value = (Int(bits) & 0xFF00) >> 8

      if value == 0 {
        return nil
      }

      return TaskPriority(rawValue: UInt8(value))
    }

    set {
      bits = (bits & ~0xFF00) | Int32((Int(newValue?.rawValue ?? 0) << 8))
    }
  }

  /// Whether this is a child task.
  var isChildTask: Bool {
    get {
      (bits & (1 << 24)) != 0
    }

    set {
      if newValue {
        bits = bits | 1 << 24
      } else {
        bits = (bits & ~(1 << 24))
      }
    }
  }

  /// Whether this is a future.
  var isFuture: Bool {
    get {
      (bits & (1 << 25)) != 0
    }

    set {
      if newValue {
        bits = bits | 1 << 25
      } else {
        bits = (bits & ~(1 << 25))
      }
    }
  }

  /// Whether this is a group child.
  var isGroupChildTask: Bool {
    get {
      (bits & (1 << 26)) != 0
    }

    set {
      if newValue {
        bits = bits | 1 << 26
      } else {
        bits = (bits & ~(1 << 26))
      }
    }
  }

  /// Whether this is a task created by the 'async' operation, which
  /// conceptually continues the work of the synchronous code that invokes
  /// it.
  var isContinuingAsyncTask: Bool {
    get {
      (bits & (1 << 27)) != 0
    }

    set {
      if newValue {
        bits = bits | 1 << 27
      } else {
        bits = (bits & ~(1 << 27))
      }
    }
  }
}

// ==== Task Creation Flags --------------------------------------------------

/// Form task creation flags for use with the createAsyncTask builtins.
@available(SwiftStdlib 5.1, *)
@_alwaysEmitIntoClient
func taskCreateFlags(
  priority: TaskPriority?, isChildTask: Bool, copyTaskLocals: Bool,
  inheritContext: Bool, enqueueJob: Bool,
  addPendingGroupTaskUnconditionally: Bool,
  isDiscardingTask: Bool,
  isSynchronousStart: Bool
) -> Int {
  var bits = 0
  bits |= (bits & ~0xFF) | Int(priority?.rawValue ?? 0)
  if isChildTask {
    bits |= 1 << 8
  }
  if copyTaskLocals {
    bits |= 1 << 10
  }
  if inheritContext {
    bits |= 1 << 11
  }
  if enqueueJob {
    bits |= 1 << 12
  }
  if addPendingGroupTaskUnconditionally {
    bits |= 1 << 13
  }
  if isDiscardingTask {
    bits |= 1 << 14
  }
  // 15 is used by 'IsTaskFunctionConsumed'
  if isSynchronousStart {
    bits |= 1 << 16
  }
  return bits
}

// ==== Task Name --------------------------------------------------------------

@available(SwiftStdlib 6.2, *)
extension Task where Success == Never, Failure == Never {

  /// Returns the human-readable name of the current task,
  /// if it was set during the tasks' creation.
  ///
  /// Tasks can be named during their creation, which can be helpful to identify
  /// unique tasks which may be created at same source locations, for example:
  ///
  ///     func process(items: [Int]) async {
  ///       await withTaskGroup { group in
  ///         for item in items {
  ///           group.addTask(name: "process-\(item)") {
  ///             await process(item)
  ///           }
  ///         }
  ///       }
  ///     }
  ///
  /// ### Task name availability
  /// The task name is only available when running with a recent runtime (Swift 6.2+).
  ///
  /// ``Task`` initializers which may accept a task name are more available than this property,
  /// for convenience purposes, in order to not have to set task names conditionally
  /// however their effect is runtime dependent, and is reflected in the availability of this property.
  @available(SwiftStdlib 6.2, *)
  public static var name: String? {
    return _getCurrentTaskNameString()
  }
}

@available(SwiftStdlib 5.1, *)
extension Task {

  /// Return the task's name, if it was set during its creation.
  @inlinable
  @available(SwiftStdlib 6.4, *)
  public var name: String? {
    if let name = unsafe _getTaskName(_AsyncTask(self._task)) {
      unsafe String(cString: name)
    } else {
      nil
    }
  }
}

// ==== Voluntary Suspension -----------------------------------------------------

@available(SwiftStdlib 5.1, *)
extension Task where Success == Never, Failure == Never {

  /// Suspends the current task and allows other tasks to execute.
  ///
  /// A task can voluntarily suspend itself
  /// in the middle of a long-running operation
  /// that doesn't contain any suspension points,
  /// to let other tasks run for a while
  /// before execution returns to this task.
  ///
  /// If this task is the highest-priority task in the system,
  /// the executor immediately resumes execution of the same task.
  /// As such,
  /// this method isn't necessarily a way to avoid resource starvation.
  public static func yield() async {
    return await Builtin.withUnsafeContinuation { (continuation: Builtin.RawUnsafeContinuation) -> Void in
      let job = _taskCreateNullaryContinuationJob(
          priority: Int(Task.currentPriority.rawValue),
          continuation: continuation)

      #if !$Embedded && !SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY
      if #available(StdlibDeploymentTarget 6.3, *) {
        let executor = Task.currentExecutor

        executor.enqueue(ExecutorJob(context: job))
      } else {
        fatalError("we shouldn't get here; if we have, availability is broken")
      }
      #else
      _enqueueJobGlobal(job)
      #endif
    }
  }
}

// ==== UnsafeCurrentTask ------------------------------------------------------

/// Calls a closure with an unsafe reference to the current task.
///
/// If you call this function from the body of an asynchronous function,
/// the unsafe task handle passed to the closure is always non-`nil`
/// because an asynchronous function always runs in the context of a task.
/// However, if you call this function from the body of a synchronous function,
/// and that function isn't executing in the context of any task,
/// the unsafe task handle is `nil`.
///
/// Storing an unsafe reference to a task doesn't affect the task's actual life cycle,
/// and the behavior of accessing an unsafe task reference
/// outside of the `withUnsafeCurrentTask(body:)` method's closure is unsafe and undefined behavior.
/// There's no safe way to retrieve a reference to the current task
/// and save it for long-term use.
/// To query the current task without saving a reference to it,
/// use properties like `currentPriority`.
/// If you need to store a reference to a task,
/// create an unstructured task using `Task.detached(priority:operation:)` instead.
///
/// - Parameters:
///   - body: A closure that takes an `UnsafeCurrentTask` parameter.
///     If `body` has a return value,
///     that value is also used as the return value
///     for the `withUnsafeCurrentTask(body:)` function.
///
/// - Returns: The return value, if any, of the `body` closure.
@available(SwiftStdlib 5.1, *)
public func withUnsafeCurrentTask<T>(body: (UnsafeCurrentTask?) throws -> T) rethrows -> T {
  guard let _task = unsafe _getCurrentAsyncTask() else {
    return try body(nil)
  }

  return try unsafe body(UnsafeCurrentTask(_task))
}

/// Calls a closure with an unsafe reference to the current task.
///
/// If you call this function from the body of an asynchronous function,
/// the unsafe task handle passed to the closure is always non-`nil`
/// because an asynchronous function always runs in the context of a task.
///
/// The operation is guaranteed to execute on the caller's isolation.
///
/// Storing an unsafe reference to a task doesn't affect the task's actual life cycle,
/// and the behavior of accessing an unsafe task reference
/// outside of the `withUnsafeCurrentTask(body:)` method's closure is unsafe and undefined behavior.
/// There's no safe way to retrieve a reference to the current task
/// and save it for long-term use.
/// To query the current task without saving a reference to it,
/// use properties like `currentPriority`.
/// If you need to store a reference to a task,
/// create an unstructured task using `Task.detached(priority:operation:)` instead.
///
/// - Parameters:
///   - body: A closure that takes an `UnsafeCurrentTask` parameter.
///     If `body` has a return value,
///     that value is also used as the return value
///     for the `withUnsafeCurrentTask(body:)` function.
///
/// - Returns: The return value, if any, of the `body` closure.
@available(SwiftStdlib 6.0, *)
// Note: Could not be always-emit-into client since the UnsafeCurrentTask initializer was not usableFromInline
// in 6.0, so we can't make this symbol more available than the availability of UnsafeCurrentTask.init.
@abi(
  // abi only necessary to avoid redeclaration clash with previous declaration (__abi_withUnsafeCurrentTask)
  nonisolated(nonsending) func withUnsafeCurrentTaskNonsending<T>(
    body: nonisolated(nonsending) (UnsafeCurrentTask?) async throws -> T
  ) async rethrows -> T
)
public nonisolated(nonsending) func withUnsafeCurrentTask<T>(
  body: nonisolated(nonsending) (UnsafeCurrentTask?) async throws -> T
) async rethrows -> T {
  guard let _task = unsafe _getCurrentAsyncTask() else {
    return try await body(nil)
  }

  return try unsafe await body(UnsafeCurrentTask(_task))
}

// Old version for ABI compatibility
@available(SwiftStdlib 6.0, *)
@usableFromInline
@abi(
  func withUnsafeCurrentTask<T>(body: (UnsafeCurrentTask?) async throws -> T) async rethrows -> T
)
internal func __abi_withUnsafeCurrentTask<T>(
  body: (UnsafeCurrentTask?) async throws -> T
) async rethrows -> T {
  unsafe try await withUnsafeCurrentTask(body: body)
}

/// An unsafe reference to the current task.
///
/// To get an instance of `UnsafeCurrentTask` for the current task,
/// call the `withUnsafeCurrentTask(body:)` method.
/// Don't store an unsafe task reference
/// for use outside that method's closure.
/// Storing an unsafe reference doesn't affect the task's actual life cycle,
/// and the behavior of accessing an unsafe task reference
/// outside of the `withUnsafeCurrentTask(body:)` method's closure isn't defined.
///
/// Only APIs on `UnsafeCurrentTask` that are also part of `Task`
/// are safe to invoke from a task other than
/// the task that this `UnsafeCurrentTask` instance refers to.
/// Calling other APIs from another task is undefined behavior,
/// breaks invariants in other parts of the program running on this task,
/// and may lead to crashes or data loss.
///
/// For information about the language-level concurrency model that `UnsafeCurrentTask` is part of,
/// see [Concurrency][concurrency] in [The Swift Programming Language][tspl].
///
/// [concurrency]: https://docs.swift.org/swift-book/LanguageGuide/Concurrency.html
/// [tspl]: https://docs.swift.org/swift-book/
@available(SwiftStdlib 5.1, *)
@unsafe
public struct UnsafeCurrentTask {
  @usableFromInline
  @available(SwiftStdlib 5.1, *)
  internal let _rawTask: _AsyncTask

  /// ABI-compat shim for the old `_task: Builtin.NativeObject` accessor.
  /// Inlined client code compiled against earlier stdlibs references the
  /// mangled `_$sSct5_taskBovg` / `_$sSct5_taskBovpMV` symbols; preserving
  /// them keeps that code linking. The old caller's calling convention
  /// expects a `+1` owned reference, so we retain on each call.
  @usableFromInline
  @available(SwiftStdlib 5.1, *)
  internal var _task: Builtin.NativeObject {
    @_transparent
    get {
      let ref: Builtin.NativeObject =
        unsafe Builtin.bridgeFromRawPointer(_rawTask._rawValue)
      Builtin.retain(ref)
      return ref
    }
  }

  // May only be created by the standard library.
  @usableFromInline // Since 6.4
  @available(SwiftStdlib 5.1, *)
  internal init(_ asyncTask: _AsyncTask) {
    unsafe self._rawTask = asyncTask
  }

  /// A Boolean value that indicates whether the current task was canceled.
  ///
  /// After the value of this property becomes `true`, it remains `true` indefinitely.
  /// There is no way to uncancel a task.
  ///
  /// This property returns the actual cancellation state of the task, regardless of whether
  /// a cancellation shield is active. Use ``Task/isCancelled`` (the static property)
  /// if you need cancellation checking that respects active shields.
  ///
  /// ### Instance property isCancelled ignores Task Cancellation Shields
  ///
  /// The instance property `task.isCancelled`
  /// is not contextual and therefore does not respect cancellation shields. If a task
  /// was cancelled and is executing
  /// with an active cancellation shield, this property will return the _actual_
  /// cancellation status of the specific task.
  ///
  /// It is possible to determine if a shield is active and then actively determine
  /// that the cancelled status should be temporarily ignored by using this pair of APIs:
  ///
  /// ```swift
  /// withUnsafeCurrentTask { unsafeTask in
  ///   if unsafeTask.hasActiveCancellationShield {
  ///     false
  ///   } else {
  ///     unsafeTask.isCancelled
  ///   }
  /// }
  /// ```
  ///
  /// Which is equivalent to the contextually aware static `Task.isCancelled` property:
  ///
  /// ```swift
  /// // Contextually aware, and equivalent to the snippet using UnsafeCurrentTask:
  /// Task.isCancelled
  /// ```
  ///
  /// Prefer using `Task.isCancelled` (the static property) in most situations when checking
  /// the cancellation status from inside the task.
  ///
  /// - SeeAlso: ``Task/isCancelled``
  /// - SeeAlso: ``Task/checkCancellation()``
  /// - SeeAlso: ``Task/hasActiveCancellationShield``
  /// - SeeAlso: ``withTaskCancellationShield(operation:)``
  public var isCancelled: Bool {
    if #available(SwiftStdlib 6.4, *) {
      unsafe _isCancelled(ignoreTaskCancellationShield: true)
    } else {
      unsafe _taskIsCancelled(_rawTask)
    }
  }

  /// Check if the task is cancelled, optionally ignoring active cancellation shields.
  @available(SwiftStdlib 6.4, *)
  @_alwaysEmitIntoClient
  internal func _isCancelled(ignoreTaskCancellationShield: Bool) -> Bool {
    let flags: UInt64 = ignoreTaskCancellationShield ? 0x1 : 0x0
    return unsafe _taskIsCancelledWithFlags(_rawTask, flags: flags)
  }

  /// The current task's priority.
  ///
  /// - SeeAlso: `TaskPriority`
  /// - SeeAlso: `Task.currentPriority`
  public var priority: TaskPriority {
    unsafe TaskPriority(rawValue: _taskCurrentPriority(_rawTask))
  }

  /// The current task's base priority.
  ///
  /// - SeeAlso: `TaskPriority`
  /// - SeeAlso: `Task.basePriority`
  @available(SwiftStdlib 5.9, *)
  public var basePriority: TaskPriority {
    unsafe TaskPriority(rawValue: _taskBasePriority(_rawTask))
  }

  /// Cancel the current task.
  ///
  /// The task will be immediately cancelled and cancellation will propagate towards any child tasks it has.
  ///
  /// ### Interaction with Task Cancellation Shields
  /// Note that cancellation may not be observed if a task is currently executing with an
  /// active task cancellation shield. Refer to cancellation shield documentation for detailed semantics.
  ///
  /// - SeeAlso: ``withTaskCancellationShield(operation:)``
  /// - SeeAlso: ``Task/hasActiveTaskCancellationShield``
  public func cancel() {
    unsafe _taskCancel(_rawTask)
  }

  /// Checks if this task is executing in a scope with a task cancellation shield activated by the
  /// ``withTaskCancellationShield(operation:)`` function.
  ///
  /// An active task cancellation shield prevents a task's ability to observe if it was cancelled,
  /// i.e. the ``Task/isCancelled`` property will always return `false` when the task is executing
  /// with an active shield.
  ///
  /// This property is primarily aimed at debugging and understanding cancellation behavior
  /// in complex call hierarchies, and should not be used in regular control flow.
  ///
  /// Returns `true` when executing within a task that has an active cancellation shield.
  ///
  /// Cancellation shields are not automatically inherited by child tasks; each child task must install
  /// its own shield if needed if it, independently, wanted to ignore cancellation during a specific scope.
  ///
  /// - SeeAlso: ``withTaskCancellationShield(operation:)``
  /// - SeeAlso: ``Task/hasActiveCancellationShield``
  @available(SwiftStdlib 6.4, *)
  @_alwaysEmitIntoClient
  public var hasActiveCancellationShield: Bool {
    @_alwaysEmitIntoClient
    get {
      unsafe _taskHasActiveCancellationShield(_rawTask)
    }
  }

  /// Return the task's name, if it was set during its creation.
  @inlinable
  @available(SwiftStdlib 6.4, *)
  public var name: String? {
    if let name = unsafe _getTaskName(_rawTask) {
      unsafe String(cString: name)
    } else {
      nil
    }
  }
}

@available(SwiftStdlib 5.1, *)
@available(*, unavailable)
extension UnsafeCurrentTask: Sendable { }

@available(SwiftStdlib 5.1, *)
extension UnsafeCurrentTask: @unsafe Hashable {
  public func hash(into hasher: inout Hasher) {
    unsafe UnsafeRawPointer(_rawTask._rawValue).hash(into: &hasher)
  }
}

@available(SwiftStdlib 5.1, *)
extension UnsafeCurrentTask: Equatable {
  public static func ==(lhs: Self, rhs: Self) -> Bool {
    unsafe Bool(Builtin.cmp_eq_RawPointer(lhs._rawTask._rawValue, rhs._rawTask._rawValue))
  }
}

// ==== Internal ---------------------------------------------------------------

/// Opaque non-owning handle to an `AsyncTask` object.
@available(SwiftStdlib 5.1, *)
@frozen
@unsafe
@usableFromInline
internal struct _AsyncTask {
  @usableFromInline
  internal let _rawValue: Builtin.RawPointer

  @usableFromInline @_transparent
  internal init(_ rawValue: Builtin.RawPointer) {
    unsafe self._rawValue = rawValue
  }

  /// Bridge a `Task._task` (a `Builtin.NativeObject` strong reference) into
  /// a non-owning `_AsyncTask`. The caller's `Builtin.NativeObject` keeps
  /// the task alive for the duration the wrapper is used.
  @usableFromInline @_transparent
  internal init(_ task: Builtin.NativeObject) {
    unsafe self._rawValue = Builtin.bridgeToRawPointer(task)
  }
}

@available(SwiftStdlib 5.1, *)
@_silgen_name("swift_task_getCurrent")
@usableFromInline
internal func _getCurrentAsyncTask() -> _AsyncTask?

@available(SwiftStdlib 5.1, *)
@_silgen_name("swift_task_getJobFlags")
func getJobFlags(_ task: Builtin.NativeObject) -> JobFlags

@available(SwiftStdlib 5.1, *)
@_silgen_name("swift_task_enqueueGlobal")
@usableFromInline
func _enqueueJobGlobal(_ task: Builtin.Job)

@available(SwiftStdlib 5.9, *)
func _enqueueJobGlobal(_ task: UnownedJob) {
  _enqueueJobGlobal(task._context)
}

@available(SwiftStdlib 5.1, *)
@_silgen_name("swift_task_enqueueGlobalWithDelay")
@usableFromInline
func _enqueueJobGlobalWithDelay(_ delay: UInt64, _ task: Builtin.Job)

@available(SwiftStdlib 5.9, *)
func _enqueueJobGlobalWithDelay(_ delay: UInt64, _ task: UnownedJob) {
  return _enqueueJobGlobalWithDelay(delay, task._context)
}

@available(StdlibDeploymentTarget 5.7, *)
@_silgen_name("swift_task_enqueueGlobalWithDeadline")
@usableFromInline
func _enqueueJobGlobalWithDeadline(_ seconds: Int64, _ nanoseconds: Int64,
                                   _ toleranceSec: Int64, _ toleranceNSec: Int64,
                                   _ clock: Int32, _ task: UnownedJob)

@available(SwiftStdlib 5.1, *)
@usableFromInline
@_silgen_name("swift_task_asyncMainDrainQueue")
internal func _asyncMainDrainQueue() -> Never

@available(SwiftStdlib 5.1, *)
@usableFromInline
@_silgen_name("swift_task_getMainExecutor")
internal func _getMainExecutor() -> Builtin.Executor

/// Get the default generic serial executor.
///
/// It is used by default used by tasks and default actors,
/// unless other executors are specified.
@available(SwiftStdlib 6.0, *)
@usableFromInline
internal func _getGenericSerialExecutor() -> Builtin.Executor {
  // The `SerialExecutorRef` to "default generic executor" is guaranteed
  // to be a zero value;
  //
  // As the runtime relies on this in multiple places,
  // so instead of a runtime call to get this executor ref, we bitcast a "zero"
  // of expected size to the builtin executor type.
  unsafe unsafeBitCast((UInt(0), UInt(0)), to: Builtin.Executor.self)
}

#if SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY
@available(SwiftStdlib 5.1, *)
@available(*, unavailable, message: "Unavailable in task-to-thread concurrency model")
@usableFromInline
@preconcurrency
internal func _runAsyncMain(_ asyncFun: @Sendable @escaping () async throws -> ()) {
  fatalError("Unavailable in task-to-thread concurrency model")
}
#elseif !SWIFT_CONCURRENCY_EMBEDDED
@available(SwiftStdlib 5.1, *)
@usableFromInline
@preconcurrency
internal func _runAsyncMain(_ asyncFun: @Sendable @escaping () async throws -> ()) {
  let taskFlags = taskCreateFlags(
    priority: nil, isChildTask: false, copyTaskLocals: false,
    inheritContext: false, enqueueJob: false,
    addPendingGroupTaskUnconditionally: false,
    isDiscardingTask: false, isSynchronousStart: false)

  let (theTask, _) = Builtin.createAsyncTask(taskFlags) {
    do {
      try await asyncFun()
      exit(0)
    } catch {
      _errorInMain(error)
    }
  }

  let job = Builtin.convertTaskToJob(theTask)
  if #available(StdlibDeploymentTarget 6.3, *) {
    MainActor.executor.enqueue(ExecutorJob(context: job))
  } else {
    fatalError("we shouldn't get here; if we have, availability is broken")
  }

  _asyncMainDrainQueue()
}
#endif

// FIXME: both of these ought to take their arguments _owned so that
//        we can do a move out of the future in the common case where it's
//        unreferenced
@available(SwiftStdlib 5.1, *)
@_silgen_name("swift_task_future_wait")
public func _taskFutureGet<T>(_ task: Builtin.NativeObject) async -> T

@available(SwiftStdlib 5.1, *)
@_silgen_name("swift_task_future_wait_throwing")
public func _taskFutureGetThrowing<T>(_ task: Builtin.NativeObject) async throws -> T

@available(SwiftStdlib 5.1, *)
@_silgen_name("swift_task_cancel")
@usableFromInline
internal func _taskCancel(_ task: _AsyncTask)

@available(SwiftStdlib 5.1, *)
@_silgen_name("swift_task_isCancelled")
@usableFromInline
internal func _taskIsCancelled(_ task: _AsyncTask) -> Bool

@available(SwiftStdlib 6.4, *)
@_silgen_name("swift_task_isCancelledWithFlags")
@usableFromInline
internal func _taskIsCancelledWithFlags(_ task: _AsyncTask, flags: UInt64) -> Bool

@available(SwiftStdlib 6.4, *)
@_silgen_name("swift_task_hasActiveCancellationShield")
@usableFromInline
internal func _taskHasActiveCancellationShield(_ task: _AsyncTask) -> Bool

@available(SwiftStdlib 5.1, *)
@_silgen_name("swift_task_currentPriority")
@usableFromInline
internal func _taskCurrentPriority(_ task: _AsyncTask) -> UInt8

@available(SwiftStdlib 6.2, *)
@_silgen_name("swift_task_escalate")
@discardableResult
@usableFromInline
internal func _taskEscalate(_ task: _AsyncTask, newPriority: UInt8) -> UInt8

@available(SwiftStdlib 5.1, *)
@_silgen_name("swift_task_basePriority")
@usableFromInline
internal func _taskBasePriority(_ task: _AsyncTask) -> UInt8

@available(SwiftStdlib 5.1, *)
@_silgen_name("swift_task_createNullaryContinuationJob")
func _taskCreateNullaryContinuationJob(priority: Int, continuation: Builtin.RawUnsafeContinuation) -> Builtin.Job

@available(SwiftStdlib 5.1, *)
@usableFromInline
@_silgen_name("swift_task_isCurrentExecutor")
func _taskIsCurrentExecutor(_ executor: Builtin.Executor) -> Bool

@available(SwiftStdlib 6.2, *)
@_silgen_name("swift_task_isCurrentExecutorWithFlags")
@usableFromInline
internal func _taskIsCurrentExecutor(
  executor: Builtin.Executor, flags: UInt64) -> Bool

@available(SwiftStdlib 6.2, *)
extension GlobalActor {
  @available(SwiftStdlib 6.2, *)
  @_silgen_name("_swift_task_isCurrentGlobalActor")
  internal static func _taskIsCurrentGlobalActor() -> Bool {
    let executor = unsafe sharedUnownedExecutor
    return unsafe _taskIsCurrentExecutor(executor: executor.executor, flags: 0)
  }
}

@available(SwiftStdlib 5.1, *)
@usableFromInline
@_silgen_name("swift_task_reportUnexpectedExecutor")
func _reportUnexpectedExecutor(_ _filenameStart: Builtin.RawPointer,
                               _ _filenameLength: Builtin.Word,
                               _ _filenameIsASCII: Builtin.Int1,
                               _ _line: Builtin.Word,
                               _ _executor: Builtin.Executor)

@available(SwiftStdlib 5.1, *)
@_silgen_name("swift_task_getCurrentThreadPriority")
func _getCurrentThreadPriority() -> Int

@available(SwiftStdlib 6.2, *)
@_silgen_name("swift_task_getCurrentTaskName")
internal func _getCurrentTaskName() -> UnsafePointer<UInt8>?

@available(StdlibDeploymentTarget 6.4, *)
@usableFromInline
@_silgen_name("swift_task_getTaskName")
internal func _getTaskName(_ job: _AsyncTask) -> UnsafePointer<UInt8>?

@available(SwiftStdlib 6.2, *)
internal func _getCurrentTaskNameString() -> String? {
  if let stringPtr = unsafe _getCurrentTaskName() {
    unsafe String(cString: stringPtr)
  } else {
    nil
  }
}


#if SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY
@available(SwiftStdlib 5.8, *)
@usableFromInline
@_unavailableFromAsync(message: "Use _taskRunInline from a sync context to begin an async context.")
internal func _taskRunInline<T>(_ body: () async -> T) -> T {
#if compiler(>=5.5) && $BuiltinTaskRunInline
  return Builtin.taskRunInline(body)
#else
  fatalError("Unsupported Swift compiler")
#endif
}

@available(SwiftStdlib 5.8, *)
extension Task where Failure == Never {
  /// Start an async context within the current sync context and run the
  /// provided async closure, returning the value it produces.
  @available(SwiftStdlib 5.8, *)
  @_spi(_TaskToThreadModel)
  @_unavailableFromAsync(message: "Use Task.runInline from a sync context to begin an async context.")
  public static func runInline(_ body: () async -> Success) -> Success {
    return _taskRunInline(body)
  }
}

@available(SwiftStdlib 5.8, *)
extension Task where Failure == Error {
  @available(SwiftStdlib 5.8, *)
  @_alwaysEmitIntoClient
  @usableFromInline
  internal static func _runInlineHelper<T>(
    body: () async -> Result<T, Error>,
    rescue: (Result<T, Error>) throws -> T
  ) rethrows -> T {
    return try rescue(
      _taskRunInline(body)
    )
  }

  /// Start an async context within the current sync context and run the
  /// provided async closure, returning or throwing the value or error it
  /// produces.
  @available(SwiftStdlib 5.8, *)
  @_spi(_TaskToThreadModel)
  @_unavailableFromAsync(message: "Use Task.runInline from a sync context to begin an async context.")
  public static func runInline(_ body: () async throws -> Success) rethrows -> Success {
    return try _runInlineHelper(
      body: {
        do {
          let value = try await body()
          return Result.success(value)
        }
        catch let error {
          return Result.failure(error)
        }
    },
      rescue: { try $0.get() }
    )
  }
}
#endif

#if _runtime(_ObjC)

#if !SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY
/// Intrinsic used by SILGen to launch a task for bridging a Swift async method
/// which was called through its ObjC-exported completion-handler-based API.
@available(SwiftStdlib 5.1, *)
@_alwaysEmitIntoClient
@usableFromInline
internal func _runTaskForBridgedAsyncMethod(@_inheritActorContext _ body: __owned @Sendable @escaping () async -> Void) {
#if compiler(>=5.6)
  Task(operation: body)
#else
  Task<Int, Error> {
    await body()
    return 0
  }
#endif
}
#endif

#endif

