-
Notifications
You must be signed in to change notification settings - Fork 1
/
XPCValue.swift
191 lines (183 loc) · 7.6 KB
/
XPCValue.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
// Copyright © 2015 Indragie Karunaratne. All rights reserved.
import Foundation
/// A value that can be serialized over an XPC connection.
public enum XPCValue {
case Array([XPCValue]) // XPC_TYPE_ARRAY
case Boolean(Bool) // XPC_TYPE_BOOL
case Data(NSData) // XPC_TYPE_DATA
case Date(NSDate) // XPC_TYPE_DATE
case Dictionary([Swift.String: XPCValue]) // XPC_TYPE_DICTIONARY
case Double(Swift.Double) // XPC_TYPE_DOUBLE
case FileHandle(NSFileHandle) // XPC_TYPE_FD
case Int64(Swift.Int64) // XPC_TYPE_INT64
case Null // XPC_TYPE_NULL
case String(Swift.String) // XPC_TYPE_STRING
case UInt64(Swift.UInt64) // XPC_TYPE_UINT64
case UUID(NSUUID) // XPC_TYPE_UUID
// This isn't to save a character, it's because using Swift.String
// directly in the implementations below result in "Type of expression
// is ambiguous without more context" (Swift 2.0)
private typealias SwiftString = Swift.String
/// Initializes an `XPCValue` using an `xpc_object_t`. This initializer
/// will fail and return `nil` for unsupported XPC object types. See
/// the list of cases above for the types that are supported.
public init?(_ xpcObject: xpc_object_t) {
switch xpc_get_type(xpcObject) {
case RXPCType(.Array):
var array = [XPCValue]()
xpc_array_apply(xpcObject) { (_, value) in
if let message = XPCValue(value) {
array.append(message)
}
return true
}
self = .Array(array)
case RXPCType(.Boolean):
self = .Boolean(xpc_bool_get_value(xpcObject))
case RXPCType(.Data):
let data = NSData(bytes: xpc_data_get_bytes_ptr(xpcObject), length: xpc_data_get_length(xpcObject))
self = XPCValue.Data(data)
case RXPCType(.Date):
let interval = NSTimeInterval(xpc_date_get_value(xpcObject))
self = .Date(NSDate(timeIntervalSince1970: interval))
case RXPCType(.Dictionary):
var dictionary = [SwiftString: XPCValue]()
xpc_dictionary_apply(xpcObject) { (key, value) in
if let message = XPCValue(value), key = SwiftString.fromCString(key) {
dictionary[key] = message
}
return true
}
self = .Dictionary(dictionary)
case RXPCType(.Double):
self = .Double(xpc_double_get_value(xpcObject))
case RXPCType(.FileHandle):
let fileHandle = NSFileHandle(fileDescriptor: xpc_fd_dup(xpcObject), closeOnDealloc: true)
self = .FileHandle(fileHandle)
case RXPCType(.Int64):
self = .Int64(xpc_int64_get_value(xpcObject))
case RXPCType(.Null):
self = .Null
case RXPCType(.String):
if let string = SwiftString.fromCString(xpc_string_get_string_ptr(xpcObject)) {
self = .String(string)
} else {
return nil
}
case RXPCType(.UInt64):
self = .UInt64(xpc_uint64_get_value(xpcObject))
case RXPCType(.UUID):
self = .UUID(NSUUID(UUIDBytes: xpc_uuid_get_bytes(xpcObject)))
default:
return nil
}
}
/// Converts the receiver to an `xpc_object_t`.
public func toDarwinXPCObject() -> xpc_object_t {
switch self {
case .Array(let objects):
let xpcArray = xpc_array_create(nil, 0)
for (index, value) in objects.enumerate() {
xpc_array_set_value(xpcArray, index, value.toDarwinXPCObject())
}
return xpcArray
case .Boolean(let value):
return xpc_bool_create(value)
case .Data(let data):
return xpc_data_create(data.bytes, data.length)
case .Date(let date):
return xpc_date_create(Swift.Int64(date.timeIntervalSince1970))
case .Dictionary(let dictionary):
let xpcDictionary = xpc_dictionary_create(nil, nil, 0)
for (key, value) in dictionary {
xpc_dictionary_set_value(xpcDictionary, key, value.toDarwinXPCObject())
}
return xpcDictionary
case .Double(let value):
return xpc_double_create(value)
case .FileHandle(let handle):
return xpc_fd_create(handle.fileDescriptor)
case .Int64(let value):
return xpc_int64_create(value)
case .Null:
return xpc_null_create()
case .String(let string):
return xpc_string_create(string)
case .UInt64(let value):
return xpc_uint64_create(value)
case .UUID(let UUID):
var bytes = [UInt8](count: 16, repeatedValue: 0)
UUID.getUUIDBytes(&bytes)
return xpc_uuid_create(bytes)
}
}
}
extension XPCValue: CustomStringConvertible {
public var description: Swift.String {
switch self {
case .Array(let array):
return "XPCValue.Array: \(array)"
case .Boolean(let value):
return "XPCValue.Boolean: \(value)"
case .Data(let data):
return "XPCValue.Data: \(data)"
case .Date(let date):
return "XPCValue.Date: \(date)"
case .Dictionary(let dictionary):
return "XPCValue.Dictionary: \(dictionary)"
case .Double(let value):
return "XPCValue.Double: \(value)"
case .FileHandle(let handle):
return "XPCValue.FileHandle: \(handle)"
case .Int64(let value):
return "XPCValue.Int64: \(value)"
case .Null:
return "XPCValue.Null"
case .String(let string):
return "XPCValue.String: \(string)"
case .UInt64(let value):
return "XPCValue.UInt64: \(value)"
case .UUID(let UUID):
return "XPCValue.UUID: \(UUID)"
}
}
}
extension XPCValue: Equatable {}
public func ==(lhs: XPCValue, rhs: XPCValue) -> Bool {
switch (lhs, rhs) {
case (.Array(let lhsArray), .Array(let rhsArray)):
return lhsArray == rhsArray
case (.Boolean(let lhsValue), .Boolean(let rhsValue)):
return lhsValue == rhsValue
case (.Data(let lhsData), .Data(let rhsData)):
return lhsData == rhsData
case (.Date(let lhsDate), .Date(let rhsDate)):
return lhsDate == rhsDate
case (.Dictionary(let lhsDictionary), .Dictionary(let rhsDictionary)):
return lhsDictionary == rhsDictionary
case (.Double(let lhsValue), .Double(let rhsValue)):
return lhsValue == rhsValue
case (.FileHandle(let lhsHandle), .FileHandle(let rhsHandle)):
var lhsStat = stat()
if (fstat(lhsHandle.fileDescriptor, &lhsStat) < 0) {
return false
}
var rhsStat = stat()
if (fstat(rhsHandle.fileDescriptor, &rhsStat) < 0) {
return false
}
return (lhsStat.st_dev == rhsStat.st_dev) && (lhsStat.st_ino == rhsStat.st_ino)
case (.Int64(let lhsValue), .Int64(let rhsValue)):
return lhsValue == rhsValue
case (.Null, .Null):
return true
case (.String(let lhsString), .String(let rhsString)):
return lhsString == rhsString
case (.UInt64(let lhsValue), .UInt64(let rhsValue)):
return lhsValue == rhsValue
case (.UUID(let lhsUUID), .UUID(let rhsUUID)):
return lhsUUID == rhsUUID
default:
return false
}
}