123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219 |
- /*
- * 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 9/20/16.
- //
- import Foundation
- public typealias CustomMappingKeyValueTuple = (Int, MappingPropertyHandler)
- struct MappingPath {
- var segments: [String]
- static func buildFrom(rawPath: String) -> MappingPath {
- let regex = try! NSRegularExpression(pattern: "(?<![\\\\])\\.")
- let nsString = rawPath as NSString
- let results = regex.matches(in: rawPath, range: NSRange(location: 0, length: nsString.length))
- var splitPoints = results.map { $0.range.location }
- var curPos = 0
- var pathArr = [String]()
- splitPoints.append(nsString.length)
- splitPoints.forEach({ (point) in
- let start = rawPath.index(rawPath.startIndex, offsetBy: curPos)
- let end = rawPath.index(rawPath.startIndex, offsetBy: point)
- let subPath = String(rawPath[start ..< end]).replacingOccurrences(of: "\\.", with: ".")
- if !subPath.isEmpty {
- pathArr.append(subPath)
- }
- curPos = point + 1
- })
- return MappingPath(segments: pathArr)
- }
- }
- extension Dictionary where Key == String, Value: Any {
- func findValueBy(path: MappingPath) -> Any? {
- var currentDict: [String: Any]? = self
- var lastValue: Any?
- path.segments.forEach { (segment) in
- lastValue = currentDict?[segment]
- currentDict = currentDict?[segment] as? [String: Any]
- }
- return lastValue
- }
- }
- public class MappingPropertyHandler {
- var mappingPaths: [MappingPath]?
- var assignmentClosure: ((Any?) -> (Any?))?
- var takeValueClosure: ((Any?) -> (Any?))?
-
- public init(rawPaths: [String]?, assignmentClosure: ((Any?) -> (Any?))?, takeValueClosure: ((Any?) -> (Any?))?) {
- let mappingPaths = rawPaths?.map({ (rawPath) -> MappingPath in
- if HandyJSONConfiguration.deserializeOptions.contains(.caseInsensitive) {
- return MappingPath.buildFrom(rawPath: rawPath.lowercased())
- }
- return MappingPath.buildFrom(rawPath: rawPath)
- }).filter({ (mappingPath) -> Bool in
- return mappingPath.segments.count > 0
- })
- if let count = mappingPaths?.count, count > 0 {
- self.mappingPaths = mappingPaths
- }
- self.assignmentClosure = assignmentClosure
- self.takeValueClosure = takeValueClosure
- }
- }
- public class HelpingMapper {
-
- private var mappingHandlers = [Int: MappingPropertyHandler]()
- private var excludeProperties = [Int]()
-
- internal func getMappingHandler(key: Int) -> MappingPropertyHandler? {
- return self.mappingHandlers[key]
- }
-
- internal func propertyExcluded(key: Int) -> Bool {
- return self.excludeProperties.contains(key)
- }
-
- public func specify<T>(property: inout T, name: String) {
- self.specify(property: &property, name: name, converter: nil)
- }
-
- public func specify<T>(property: inout T, converter: @escaping (String) -> T) {
- self.specify(property: &property, name: nil, converter: converter)
- }
-
- public func specify<T>(property: inout T, name: String?, converter: ((String) -> T)?) {
- let pointer = withUnsafePointer(to: &property, { return $0 })
- let key = Int(bitPattern: pointer)
- let names = (name == nil ? nil : [name!])
-
- if let _converter = converter {
- let assignmentClosure = { (jsonValue: Any?) -> Any? in
- if let _value = jsonValue{
- if let object = _value as? NSObject {
- if let str = String.transform(from: object){
- return _converter(str)
- }
- }
- }
- return nil
- }
- self.mappingHandlers[key] = MappingPropertyHandler(rawPaths: names, assignmentClosure: assignmentClosure, takeValueClosure: nil)
- } else {
- self.mappingHandlers[key] = MappingPropertyHandler(rawPaths: names, assignmentClosure: nil, takeValueClosure: nil)
- }
- }
-
- public func exclude<T>(property: inout T) {
- self._exclude(property: &property)
- }
-
- fileprivate func addCustomMapping(key: Int, mappingInfo: MappingPropertyHandler) {
- self.mappingHandlers[key] = mappingInfo
- }
-
- fileprivate func _exclude<T>(property: inout T) {
- let pointer = withUnsafePointer(to: &property, { return $0 })
- self.excludeProperties.append(Int(bitPattern: pointer))
- }
- }
- infix operator <-- : LogicalConjunctionPrecedence
- public func <-- <T>(property: inout T, name: String) -> CustomMappingKeyValueTuple {
- return property <-- [name]
- }
- public func <-- <T>(property: inout T, names: [String]) -> CustomMappingKeyValueTuple {
- let pointer = withUnsafePointer(to: &property, { return $0 })
- let key = Int(bitPattern: pointer)
- return (key, MappingPropertyHandler(rawPaths: names, assignmentClosure: nil, takeValueClosure: nil))
- }
- // MARK: non-optional properties
- public func <-- <Transform: TransformType>(property: inout Transform.Object, transformer: Transform) -> CustomMappingKeyValueTuple {
- return property <-- (nil, transformer)
- }
- public func <-- <Transform: TransformType>(property: inout Transform.Object, transformer: (String?, Transform?)) -> CustomMappingKeyValueTuple {
- let names = (transformer.0 == nil ? [] : [transformer.0!])
- return property <-- (names, transformer.1)
- }
- public func <-- <Transform: TransformType>(property: inout Transform.Object, transformer: ([String], Transform?)) -> CustomMappingKeyValueTuple {
- let pointer = withUnsafePointer(to: &property, { return $0 })
- let key = Int(bitPattern: pointer)
- let assignmentClosure = { (jsonValue: Any?) -> Transform.Object? in
- return transformer.1?.transformFromJSON(jsonValue)
- }
- let takeValueClosure = { (objectValue: Any?) -> Any? in
- if let _value = objectValue as? Transform.Object {
- return transformer.1?.transformToJSON(_value) as Any
- }
- return nil
- }
- return (key, MappingPropertyHandler(rawPaths: transformer.0, assignmentClosure: assignmentClosure, takeValueClosure: takeValueClosure))
- }
- // MARK: optional properties
- public func <-- <Transform: TransformType>(property: inout Transform.Object?, transformer: Transform) -> CustomMappingKeyValueTuple {
- return property <-- (nil, transformer)
- }
- public func <-- <Transform: TransformType>(property: inout Transform.Object?, transformer: (String?, Transform?)) -> CustomMappingKeyValueTuple {
- let names = (transformer.0 == nil ? [] : [transformer.0!])
- return property <-- (names, transformer.1)
- }
- public func <-- <Transform: TransformType>(property: inout Transform.Object?, transformer: ([String], Transform?)) -> CustomMappingKeyValueTuple {
- let pointer = withUnsafePointer(to: &property, { return $0 })
- let key = Int(bitPattern: pointer)
- let assignmentClosure = { (jsonValue: Any?) -> Any? in
- return transformer.1?.transformFromJSON(jsonValue)
- }
- let takeValueClosure = { (objectValue: Any?) -> Any? in
- if let _value = objectValue as? Transform.Object {
- return transformer.1?.transformToJSON(_value) as Any
- }
- return nil
- }
- return (key, MappingPropertyHandler(rawPaths: transformer.0, assignmentClosure: assignmentClosure, takeValueClosure: takeValueClosure))
- }
- infix operator <<< : AssignmentPrecedence
- public func <<< (mapper: HelpingMapper, mapping: CustomMappingKeyValueTuple) {
- mapper.addCustomMapping(key: mapping.0, mappingInfo: mapping.1)
- }
- public func <<< (mapper: HelpingMapper, mappings: [CustomMappingKeyValueTuple]) {
- mappings.forEach { (mapping) in
- mapper.addCustomMapping(key: mapping.0, mappingInfo: mapping.1)
- }
- }
- infix operator >>> : AssignmentPrecedence
- public func >>> <T> (mapper: HelpingMapper, property: inout T) {
- mapper._exclude(property: &property)
- }
|