/* * Copyright 1999-2101 Alibaba Group. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ // Created by zhouzhuo on 7/7/16. // import Foundation protocol _BuiltInBasicType: _Transformable { static func _transform(from object: Any) -> Self? func _plainValue() -> Any? } // Suppport integer type protocol IntegerPropertyProtocol: FixedWidthInteger, _BuiltInBasicType { init?(_ text: String, radix: Int) init(_ number: NSNumber) } extension IntegerPropertyProtocol { static func _transform(from object: Any) -> Self? { switch object { case let str as String: return Self(str, radix: 10) case let num as NSNumber: return Self(num) default: return nil } } func _plainValue() -> Any? { return self } } extension Int: IntegerPropertyProtocol {} extension UInt: IntegerPropertyProtocol {} extension Int8: IntegerPropertyProtocol {} extension Int16: IntegerPropertyProtocol {} extension Int32: IntegerPropertyProtocol {} extension Int64: IntegerPropertyProtocol {} extension UInt8: IntegerPropertyProtocol {} extension UInt16: IntegerPropertyProtocol {} extension UInt32: IntegerPropertyProtocol {} extension UInt64: IntegerPropertyProtocol {} extension Bool: _BuiltInBasicType { static func _transform(from object: Any) -> Bool? { switch object { case let str as NSString: let lowerCase = str.lowercased if ["0", "false"].contains(lowerCase) { return false } if ["1", "true"].contains(lowerCase) { return true } return nil case let num as NSNumber: return num.boolValue default: return nil } } func _plainValue() -> Any? { return self } } // Support float type protocol FloatPropertyProtocol: _BuiltInBasicType, LosslessStringConvertible { init(_ number: NSNumber) } extension FloatPropertyProtocol { static func _transform(from object: Any) -> Self? { switch object { case let str as String: return Self(str) case let num as NSNumber: return Self(num) default: return nil } } func _plainValue() -> Any? { return self } } extension Float: FloatPropertyProtocol {} extension Double: FloatPropertyProtocol {} fileprivate let formatter: NumberFormatter = { let formatter = NumberFormatter() formatter.usesGroupingSeparator = false formatter.numberStyle = .decimal formatter.maximumFractionDigits = 16 return formatter }() extension String: _BuiltInBasicType { static func _transform(from object: Any) -> String? { switch object { case let str as String: return str case let num as NSNumber: // Boolean Type Inside if NSStringFromClass(type(of: num)) == "__NSCFBoolean" { if num.boolValue { return "true" } else { return "false" } } return formatter.string(from: num) case _ as NSNull: return nil default: return "\(object)" } } func _plainValue() -> Any? { return self } } // MARK: Optional Support extension Optional: _BuiltInBasicType { static func _transform(from object: Any) -> Optional? { if let value = (Wrapped.self as? _Transformable.Type)?.transform(from: object) as? Wrapped { return Optional(value) } else if let value = object as? Wrapped { return Optional(value) } return nil } func _getWrappedValue() -> Any? { return self.map( { (wrapped) -> Any in return wrapped as Any }) } func _plainValue() -> Any? { if let value = _getWrappedValue() { if let transformable = value as? _Transformable { return transformable.plainValue() } else { return value } } return nil } } // MARK: Collection Support : Array & Set extension Collection { static func _collectionTransform(from object: Any) -> [Iterator.Element]? { guard let arr = object as? [Any] else { InternalLogger.logDebug("Expect object to be an array but it's not") return nil } typealias Element = Iterator.Element var result: [Element] = [Element]() arr.forEach { (each) in if let element = (Element.self as? _Transformable.Type)?.transform(from: each) as? Element { result.append(element) } else if let element = each as? Element { result.append(element) } } return result } func _collectionPlainValue() -> Any? { typealias Element = Iterator.Element var result: [Any] = [Any]() self.forEach { (each) in if let transformable = each as? _Transformable, let transValue = transformable.plainValue() { result.append(transValue) } else { InternalLogger.logError("value: \(each) isn't transformable type!") } } return result } } extension Array: _BuiltInBasicType { static func _transform(from object: Any) -> [Element]? { return self._collectionTransform(from: object) } func _plainValue() -> Any? { return self._collectionPlainValue() } } extension Set: _BuiltInBasicType { static func _transform(from object: Any) -> Set? { if let arr = self._collectionTransform(from: object) { return Set(arr) } return nil } func _plainValue() -> Any? { return self._collectionPlainValue() } } // MARK: Dictionary Support extension Dictionary: _BuiltInBasicType { static func _transform(from object: Any) -> [Key: Value]? { guard let dict = object as? [String: Any] else { InternalLogger.logDebug("Expect object to be an NSDictionary but it's not") return nil } var result = [Key: Value]() for (key, value) in dict { if let sKey = key as? Key { if let nValue = (Value.self as? _Transformable.Type)?.transform(from: value) as? Value { result[sKey] = nValue } else if let nValue = value as? Value { result[sKey] = nValue } } } return result } func _plainValue() -> Any? { var result = [String: Any]() for (key, value) in self { if let key = key as? String { if let transformable = value as? _Transformable { if let transValue = transformable.plainValue() { result[key] = transValue } } } } return result } }