Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- //
- // Activity.swift
- //
- // Created by Zachary Waldowski on 8/21/16.
- // Copyright © 2016 Zachary Waldowski. Licensed under MIT.
- //
- import os.activity
- private final class LegacyActivityContext {
- let dsoHandle: UnsafeRawPointer?
- let description: UnsafePointer<CChar>
- let flags: os_activity_flag_t
- init(dsoHandle: UnsafeRawPointer?, description: UnsafePointer<CChar>, flags: os_activity_flag_t) {
- self.dsoHandle = dsoHandle
- self.description = description
- self.flags = flags
- }
- }
- @available(OSX 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *)
- @_silgen_name("_os_activity_create") private func _os_activity_create(_ dso: UnsafeRawPointer?, _ description: UnsafePointer<Int8>, _ parent : Unmanaged<AnyObject>?, _ flags: os_activity_flag_t) -> AnyObject!
- @available(OSX 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *)
- @_silgen_name("os_activity_apply") private func _os_activity_apply(_ storage: AnyObject, _ block: @convention(block) () -> ())
- @_silgen_name("_os_activity_initiate") private func __os_activity_initiate(_ dso: UnsafeRawPointer?, _ description: UnsafePointer<Int8>, _ flags: os_activity_flag_t, _ block: @convention(block) () -> ())
- @available(OSX 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *)
- @_silgen_name("os_activity_scope_enter") private func _os_activity_scope_enter(_ storage: AnyObject, _ state: UnsafeMutablePointer<os_activity_scope_state_s>)
- @_silgen_name("_os_activity_start") private func __os_activity_start(_ dso: UnsafeRawPointer?, _ description: UnsafePointer<Int8>, _ flags: os_activity_flag_t) -> UInt64
- @available(OSX 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *)
- @_silgen_name("os_activity_scope_leave") private func _os_activity_scope_leave(_ state: UnsafeMutablePointer<os_activity_scope_state_s>)
- @_silgen_name("os_activity_end") private func __os_activity_end(_ state: UInt64)
- @available(OSX 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *)
- private let OS_ACTIVITY_NONE = unsafeBitCast(dlsym(UnsafeMutableRawPointer(bitPattern: -2), "_os_activity_none"), to: Unmanaged<AnyObject>.self)
- @available(OSX 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *)
- private let OS_ACTIVITY_CURRENT = unsafeBitCast(dlsym(UnsafeMutableRawPointer(bitPattern: -2), "_os_activity_current"), to: Unmanaged<AnyObject>.self)
- public struct Activity {
- /// Support flags for OSActivity.
- public struct Options: OptionSet {
- public let rawValue: UInt32
- public init(rawValue: UInt32) {
- self.rawValue = rawValue
- }
- /// Detach a newly created activity from a parent activity, if any.
- ///
- /// If passed in conjunction with a parent activity, the activity will
- /// only note what activity "created" the new one, but will make the
- /// new activity a top level activity. This allows seeing what
- /// activity triggered work without actually relating the activities.
- public static let detached = Options(rawValue: OS_ACTIVITY_FLAG_DETACHED.rawValue)
- /// Will only create a new activity if none present.
- ///
- /// If an activity ID is already present, a new activity will be
- /// returned with the same underlying activity ID.
- @available(OSX 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *)
- public static let ifNonePresent = Options(rawValue: OS_ACTIVITY_FLAG_IF_NONE_PRESENT.rawValue)
- }
- private let opaque: AnyObject
- /// Creates an activity.
- public init(_ description: StaticString, dso: UnsafeRawPointer? = #dsohandle, options: Options = []) {
- self.opaque = description.withUTF8Buffer { (buf: UnsafeBufferPointer<UInt8>) -> AnyObject in
- let str = buf.baseAddress!.withMemoryRebound(to: Int8.self, capacity: 8, { $0 })
- let flags = os_activity_flag_t(rawValue: options.rawValue)
- if #available(OSX 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *), OS_ACTIVITY_OBJECT_API != 0 {
- return _os_activity_create(dso, str, OS_ACTIVITY_CURRENT, flags)
- } else {
- return LegacyActivityContext(dsoHandle: dso, description: str, flags: flags)
- }
- }
- }
- private func active(execute body: @convention(block) () -> ()) {
- if #available(OSX 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *), OS_ACTIVITY_OBJECT_API != 0 {
- _os_activity_apply(opaque, body)
- } else {
- let context = opaque as! LegacyActivityContext
- __os_activity_initiate(context.dsoHandle, context.description, context.flags, body)
- }
- }
- /// Executes a function body within the context of the activity.
- public func active<Return>(execute body: () throws -> Return) rethrows -> Return {
- func impl(execute work: () throws -> Return, recover: (Error) throws -> Return) rethrows -> Return {
- var result: Return?
- var error: Error?
- active {
- do {
- result = try work()
- } catch let e {
- error = e
- }
- }
- if let e = error {
- return try recover(e)
- } else {
- return result!
- }
- }
- return try impl(execute: body, recover: { throw $0 })
- }
- /// Opaque structure created by `Activity.enter()` and restored using
- /// `leave()`.
- public struct Scope {
- fileprivate var state = os_activity_scope_state_s()
- fileprivate init() {}
- /// Pops activity state to `self`.
- public mutating func leave() {
- if #available(OSX 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *), OS_ACTIVITY_OBJECT_API != 0 {
- _os_activity_scope_leave(&state)
- } else {
- UnsafeRawPointer(bitPattern: Int(state.opaque.0)).map(Unmanaged<AnyObject>.fromOpaque)?.release()
- __os_activity_end(state.opaque.1)
- }
- }
- }
- /// Changes the current execution context to the activity.
- ///
- /// An activity can be created and applied to the current scope by doing:
- ///
- /// var scope = OSActivity("my new activity").enter()
- /// defer { scope.leave() }
- /// ... do some work ...
- ///
- public func enter() -> Scope {
- var scope = Scope()
- if #available(OSX 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *), OS_ACTIVITY_OBJECT_API != 0 {
- _os_activity_scope_enter(opaque, &scope.state)
- } else {
- let context = opaque as! LegacyActivityContext
- scope.state.opaque.0 = numericCast(Int(bitPattern: Unmanaged.passRetained(context).toOpaque()))
- scope.state.opaque.1 = __os_activity_start(context.dsoHandle, context.description, context.flags)
- }
- return scope
- }
- /// Creates an activity.
- @available(OSX 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *)
- public init(_ description: StaticString, dso: UnsafeRawPointer? = #dsohandle, parent: Activity, options: Options = []) {
- self.opaque = description.withUTF8Buffer { (buf: UnsafeBufferPointer<UInt8>) -> AnyObject in
- let str = buf.baseAddress!.withMemoryRebound(to: Int8.self, capacity: 8, { $0 })
- let flags = os_activity_flag_t(rawValue: options.rawValue)
- return _os_activity_create(dso, str, Unmanaged.passRetained(parent.opaque), flags)
- }
- }
- private init(_ opaque: AnyObject) {
- self.opaque = opaque
- }
- /// An activity with no traits; as a parent, it is equivalent to a
- /// detached activity.
- @available(OSX 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *)
- public static var none: Activity {
- return Activity(OS_ACTIVITY_NONE.takeUnretainedValue())
- }
- /// The running activity.
- ///
- /// As a parent, the new activity is linked to the current activity, if one
- /// is present. If no activity is present, it behaves the same as `.none`.
- @available(OSX 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *)
- public static var current: Activity {
- return Activity(OS_ACTIVITY_CURRENT.takeUnretainedValue())
- }
- /// Label an activity auto-generated by UI with a name that is useful for
- /// debugging macro-level user actions.
- ///
- /// This function should be called early within the scope of an `IBAction`,
- /// before any sub-activities are created. The name provided will be shown
- /// in tools in addition to the system-provided name. This API should only
- /// be called once, and only on an activity created by the system. These
- /// actions help determine workflow of the user in order to reproduce
- /// problems that occur.
- ///
- /// For example, a control press and/or menu item selection can be labeled:
- ///
- /// OSActivity.labelUserAction("New mail message")
- /// OSActivity.labelUserAction("Empty trash")
- ///
- /// Where the underlying name will be "gesture:" or "menuSelect:".
- @available(OSX 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *)
- public static func labelUserAction(_ description: StaticString, dso: UnsafeRawPointer? = #dsohandle) {
- description.withUTF8Buffer { (buf: UnsafeBufferPointer<UInt8>) in
- let str = buf.baseAddress!.withMemoryRebound(to: Int8.self, capacity: 8, { $0 })
- _os_activity_label_useraction(UnsafeMutableRawPointer(mutating: dso!), str)
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement