HelpingMapper.swift 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. /*
  2. * Copyright 1999-2101 Alibaba Group.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. // Created by zhouzhuo on 9/20/16.
  17. //
  18. import Foundation
  19. public typealias CustomMappingKeyValueTuple = (Int, MappingPropertyHandler)
  20. struct MappingPath {
  21. var segments: [String]
  22. static func buildFrom(rawPath: String) -> MappingPath {
  23. let regex = try! NSRegularExpression(pattern: "(?<![\\\\])\\.")
  24. let nsString = rawPath as NSString
  25. let results = regex.matches(in: rawPath, range: NSRange(location: 0, length: nsString.length))
  26. var splitPoints = results.map { $0.range.location }
  27. var curPos = 0
  28. var pathArr = [String]()
  29. splitPoints.append(nsString.length)
  30. splitPoints.forEach({ (point) in
  31. let start = rawPath.index(rawPath.startIndex, offsetBy: curPos)
  32. let end = rawPath.index(rawPath.startIndex, offsetBy: point)
  33. let subPath = String(rawPath[start ..< end]).replacingOccurrences(of: "\\.", with: ".")
  34. if !subPath.isEmpty {
  35. pathArr.append(subPath)
  36. }
  37. curPos = point + 1
  38. })
  39. return MappingPath(segments: pathArr)
  40. }
  41. }
  42. extension Dictionary where Key == String, Value: Any {
  43. func findValueBy(path: MappingPath) -> Any? {
  44. var currentDict: [String: Any]? = self
  45. var lastValue: Any?
  46. path.segments.forEach { (segment) in
  47. lastValue = currentDict?[segment]
  48. currentDict = currentDict?[segment] as? [String: Any]
  49. }
  50. return lastValue
  51. }
  52. }
  53. public class MappingPropertyHandler {
  54. var mappingPaths: [MappingPath]?
  55. var assignmentClosure: ((Any?) -> (Any?))?
  56. var takeValueClosure: ((Any?) -> (Any?))?
  57. public init(rawPaths: [String]?, assignmentClosure: ((Any?) -> (Any?))?, takeValueClosure: ((Any?) -> (Any?))?) {
  58. let mappingPaths = rawPaths?.map({ (rawPath) -> MappingPath in
  59. if HandyJSONConfiguration.deserializeOptions.contains(.caseInsensitive) {
  60. return MappingPath.buildFrom(rawPath: rawPath.lowercased())
  61. }
  62. return MappingPath.buildFrom(rawPath: rawPath)
  63. }).filter({ (mappingPath) -> Bool in
  64. return mappingPath.segments.count > 0
  65. })
  66. if let count = mappingPaths?.count, count > 0 {
  67. self.mappingPaths = mappingPaths
  68. }
  69. self.assignmentClosure = assignmentClosure
  70. self.takeValueClosure = takeValueClosure
  71. }
  72. }
  73. public class HelpingMapper {
  74. private var mappingHandlers = [Int: MappingPropertyHandler]()
  75. private var excludeProperties = [Int]()
  76. internal func getMappingHandler(key: Int) -> MappingPropertyHandler? {
  77. return self.mappingHandlers[key]
  78. }
  79. internal func propertyExcluded(key: Int) -> Bool {
  80. return self.excludeProperties.contains(key)
  81. }
  82. public func specify<T>(property: inout T, name: String) {
  83. self.specify(property: &property, name: name, converter: nil)
  84. }
  85. public func specify<T>(property: inout T, converter: @escaping (String) -> T) {
  86. self.specify(property: &property, name: nil, converter: converter)
  87. }
  88. public func specify<T>(property: inout T, name: String?, converter: ((String) -> T)?) {
  89. let pointer = withUnsafePointer(to: &property, { return $0 })
  90. let key = Int(bitPattern: pointer)
  91. let names = (name == nil ? nil : [name!])
  92. if let _converter = converter {
  93. let assignmentClosure = { (jsonValue: Any?) -> Any? in
  94. if let _value = jsonValue{
  95. if let object = _value as? NSObject {
  96. if let str = String.transform(from: object){
  97. return _converter(str)
  98. }
  99. }
  100. }
  101. return nil
  102. }
  103. self.mappingHandlers[key] = MappingPropertyHandler(rawPaths: names, assignmentClosure: assignmentClosure, takeValueClosure: nil)
  104. } else {
  105. self.mappingHandlers[key] = MappingPropertyHandler(rawPaths: names, assignmentClosure: nil, takeValueClosure: nil)
  106. }
  107. }
  108. public func exclude<T>(property: inout T) {
  109. self._exclude(property: &property)
  110. }
  111. fileprivate func addCustomMapping(key: Int, mappingInfo: MappingPropertyHandler) {
  112. self.mappingHandlers[key] = mappingInfo
  113. }
  114. fileprivate func _exclude<T>(property: inout T) {
  115. let pointer = withUnsafePointer(to: &property, { return $0 })
  116. self.excludeProperties.append(Int(bitPattern: pointer))
  117. }
  118. }
  119. infix operator <-- : LogicalConjunctionPrecedence
  120. public func <-- <T>(property: inout T, name: String) -> CustomMappingKeyValueTuple {
  121. return property <-- [name]
  122. }
  123. public func <-- <T>(property: inout T, names: [String]) -> CustomMappingKeyValueTuple {
  124. let pointer = withUnsafePointer(to: &property, { return $0 })
  125. let key = Int(bitPattern: pointer)
  126. return (key, MappingPropertyHandler(rawPaths: names, assignmentClosure: nil, takeValueClosure: nil))
  127. }
  128. // MARK: non-optional properties
  129. public func <-- <Transform: TransformType>(property: inout Transform.Object, transformer: Transform) -> CustomMappingKeyValueTuple {
  130. return property <-- (nil, transformer)
  131. }
  132. public func <-- <Transform: TransformType>(property: inout Transform.Object, transformer: (String?, Transform?)) -> CustomMappingKeyValueTuple {
  133. let names = (transformer.0 == nil ? [] : [transformer.0!])
  134. return property <-- (names, transformer.1)
  135. }
  136. public func <-- <Transform: TransformType>(property: inout Transform.Object, transformer: ([String], Transform?)) -> CustomMappingKeyValueTuple {
  137. let pointer = withUnsafePointer(to: &property, { return $0 })
  138. let key = Int(bitPattern: pointer)
  139. let assignmentClosure = { (jsonValue: Any?) -> Transform.Object? in
  140. return transformer.1?.transformFromJSON(jsonValue)
  141. }
  142. let takeValueClosure = { (objectValue: Any?) -> Any? in
  143. if let _value = objectValue as? Transform.Object {
  144. return transformer.1?.transformToJSON(_value) as Any
  145. }
  146. return nil
  147. }
  148. return (key, MappingPropertyHandler(rawPaths: transformer.0, assignmentClosure: assignmentClosure, takeValueClosure: takeValueClosure))
  149. }
  150. // MARK: optional properties
  151. public func <-- <Transform: TransformType>(property: inout Transform.Object?, transformer: Transform) -> CustomMappingKeyValueTuple {
  152. return property <-- (nil, transformer)
  153. }
  154. public func <-- <Transform: TransformType>(property: inout Transform.Object?, transformer: (String?, Transform?)) -> CustomMappingKeyValueTuple {
  155. let names = (transformer.0 == nil ? [] : [transformer.0!])
  156. return property <-- (names, transformer.1)
  157. }
  158. public func <-- <Transform: TransformType>(property: inout Transform.Object?, transformer: ([String], Transform?)) -> CustomMappingKeyValueTuple {
  159. let pointer = withUnsafePointer(to: &property, { return $0 })
  160. let key = Int(bitPattern: pointer)
  161. let assignmentClosure = { (jsonValue: Any?) -> Any? in
  162. return transformer.1?.transformFromJSON(jsonValue)
  163. }
  164. let takeValueClosure = { (objectValue: Any?) -> Any? in
  165. if let _value = objectValue as? Transform.Object {
  166. return transformer.1?.transformToJSON(_value) as Any
  167. }
  168. return nil
  169. }
  170. return (key, MappingPropertyHandler(rawPaths: transformer.0, assignmentClosure: assignmentClosure, takeValueClosure: takeValueClosure))
  171. }
  172. infix operator <<< : AssignmentPrecedence
  173. public func <<< (mapper: HelpingMapper, mapping: CustomMappingKeyValueTuple) {
  174. mapper.addCustomMapping(key: mapping.0, mappingInfo: mapping.1)
  175. }
  176. public func <<< (mapper: HelpingMapper, mappings: [CustomMappingKeyValueTuple]) {
  177. mappings.forEach { (mapping) in
  178. mapper.addCustomMapping(key: mapping.0, mappingInfo: mapping.1)
  179. }
  180. }
  181. infix operator >>> : AssignmentPrecedence
  182. public func >>> <T> (mapper: HelpingMapper, property: inout T) {
  183. mapper._exclude(property: &property)
  184. }