Skip to content

Commit

Permalink
Starting on Coder integration and setting up proper swift error type
Browse files Browse the repository at this point in the history
  • Loading branch information
Jerrad Thramer authored and Jerrad Thramer committed Oct 1, 2019
1 parent d2d54fc commit 9e7e860
Show file tree
Hide file tree
Showing 14 changed files with 1,247 additions and 785 deletions.
26 changes: 26 additions & 0 deletions MapboxDirections.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,18 @@
35EFD00C207DFACA00BF3873 /* MBVisualInstruction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 35EFD00A207DFACA00BF3873 /* MBVisualInstruction.swift */; };
35EFD00D207DFACA00BF3873 /* MBVisualInstruction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 35EFD00A207DFACA00BF3873 /* MBVisualInstruction.swift */; };
35EFD00E207DFACA00BF3873 /* MBVisualInstruction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 35EFD00A207DFACA00BF3873 /* MBVisualInstruction.swift */; };
43208BA72343F7C300D8BD89 /* Codable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43208BA62343F7C300D8BD89 /* Codable.swift */; };
43208BA92343F7E900D8BD89 /* CoreLocation.Swift in Sources */ = {isa = PBXBuildFile; fileRef = 43208BA82343F7E900D8BD89 /* CoreLocation.Swift */; };
43208BAB2343F81900D8BD89 /* GeoJSON.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43208BAA2343F81900D8BD89 /* GeoJSON.swift */; };
43208BAD2343FF5500D8BD89 /* DirectionsRespone.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43208BAC2343FF5500D8BD89 /* DirectionsRespone.swift */; };
438BFEC2233D854D00457294 /* DirectionsProfileIdentifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 438BFEC1233D854D00457294 /* DirectionsProfileIdentifier.swift */; };
438BFEC3233D854D00457294 /* DirectionsProfileIdentifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 438BFEC1233D854D00457294 /* DirectionsProfileIdentifier.swift */; };
438BFEC4233D854D00457294 /* DirectionsProfileIdentifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 438BFEC1233D854D00457294 /* DirectionsProfileIdentifier.swift */; };
438BFEC5233D854D00457294 /* DirectionsProfileIdentifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 438BFEC1233D854D00457294 /* DirectionsProfileIdentifier.swift */; };
439255772344113B006EEE88 /* DirectionsError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4392557523440EC2006EEE88 /* DirectionsError.swift */; };
439255792344113D006EEE88 /* DirectionsError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4392557523440EC2006EEE88 /* DirectionsError.swift */; };
4392557A2344113E006EEE88 /* DirectionsError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4392557523440EC2006EEE88 /* DirectionsError.swift */; };
4392557B2344113F006EEE88 /* DirectionsError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4392557523440EC2006EEE88 /* DirectionsError.swift */; };
8D381B611FD9F5B1008D5A58 /* noDestinationName.json in Resources */ = {isa = PBXBuildFile; fileRef = 8D381B601FD9F5B1008D5A58 /* noDestinationName.json */; };
8D381B631FDB01D1008D5A58 /* apiDestinationName.json in Resources */ = {isa = PBXBuildFile; fileRef = 8D381B621FDB01D1008D5A58 /* apiDestinationName.json */; };
8D381B641FDB0898008D5A58 /* noDestinationName.json in Resources */ = {isa = PBXBuildFile; fileRef = 8D381B601FD9F5B1008D5A58 /* noDestinationName.json */; };
Expand Down Expand Up @@ -302,9 +310,14 @@
35DBF013217E199E0009D2AE /* OfflineDirectionsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OfflineDirectionsTests.swift; sourceTree = "<group>"; };
35DBF018217F38A30009D2AE /* versions.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = versions.json; sourceTree = "<group>"; };
35EFD00A207DFACA00BF3873 /* MBVisualInstruction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MBVisualInstruction.swift; sourceTree = "<group>"; };
43208BA62343F7C300D8BD89 /* Codable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Codable.swift; sourceTree = "<group>"; };
43208BA82343F7E900D8BD89 /* CoreLocation.Swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoreLocation.Swift; sourceTree = "<group>"; };
43208BAA2343F81900D8BD89 /* GeoJSON.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GeoJSON.swift; sourceTree = "<group>"; };
43208BAC2343FF5500D8BD89 /* DirectionsRespone.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DirectionsRespone.swift; sourceTree = "<group>"; };
438BFEBC233D7FA900457294 /* Package.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Package.swift; sourceTree = "<group>"; };
438BFEC0233D805500457294 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
438BFEC1233D854D00457294 /* DirectionsProfileIdentifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DirectionsProfileIdentifier.swift; sourceTree = "<group>"; };
4392557523440EC2006EEE88 /* DirectionsError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DirectionsError.swift; sourceTree = "<group>"; };
8D381B601FD9F5B1008D5A58 /* noDestinationName.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = noDestinationName.json; sourceTree = "<group>"; };
8D381B621FDB01D1008D5A58 /* apiDestinationName.json */ = {isa = PBXFileReference; explicitFileType = text.json; path = apiDestinationName.json; sourceTree = "<group>"; };
8D381B691FDB101F008D5A58 /* String.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = String.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -503,6 +516,9 @@
isa = PBXGroup;
children = (
8D381B691FDB101F008D5A58 /* String.swift */,
43208BA62343F7C300D8BD89 /* Codable.swift */,
43208BA82343F7E900D8BD89 /* CoreLocation.Swift */,
43208BAA2343F81900D8BD89 /* GeoJSON.swift */,
C582BA2D2073ED6300647DAA /* Array.swift */,
35DBF009217E172C0009D2AE /* CLLocationCoordinate2D.swift */,
8D434678219E1167008B7BF3 /* Double.swift */,
Expand Down Expand Up @@ -569,7 +585,9 @@
C5DAAC9E20191683001F9261 /* Match */,
DA6C9D8A1CAE442B00094FBC /* MapboxDirections.h */,
DD6254731AE70CB700017857 /* MBDirections.swift */,
4392557523440EC2006EEE88 /* DirectionsError.swift */,
C59094C0203DE6BC00EB2417 /* MBDirectionsResult.swift */,
43208BAC2343FF5500D8BD89 /* DirectionsRespone.swift */,
DAC05F171CFC075300FA0071 /* MBRoute.swift */,
DAC05F191CFC077C00FA0071 /* MBRouteLeg.swift */,
DA2E03EA1CB0E13D00D1269A /* MBRouteOptions.swift */,
Expand Down Expand Up @@ -1160,6 +1178,7 @@
C54549FC2073F1EF002E273F /* Array.swift in Sources */,
C547EC691DB59F8F009817F3 /* MBLane.swift in Sources */,
AEDC212120B6125C0052DED8 /* MBComponentRepresentable.swift in Sources */,
439255792344113D006EEE88 /* DirectionsError.swift in Sources */,
DA1A10C71D00F969009F82FA /* MBDirections.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down Expand Up @@ -1221,6 +1240,7 @@
C54549FD2073F1F0002E273F /* Array.swift in Sources */,
C547EC6A1DB59F90009817F3 /* MBLane.swift in Sources */,
AEDC212220B6125D0052DED8 /* MBComponentRepresentable.swift in Sources */,
4392557A2344113E006EEE88 /* DirectionsError.swift in Sources */,
DA1A10ED1D010247009F82FA /* MBDirections.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down Expand Up @@ -1282,6 +1302,7 @@
C54549FE2073F1F1002E273F /* Array.swift in Sources */,
C547EC6B1DB59F91009817F3 /* MBLane.swift in Sources */,
AEDC212320B6125E0052DED8 /* MBComponentRepresentable.swift in Sources */,
4392557B2344113F006EEE88 /* DirectionsError.swift in Sources */,
DA1A11041D0103A3009F82FA /* MBDirections.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down Expand Up @@ -1321,6 +1342,7 @@
C56516841FE1A2DD00A0AD18 /* MBVisualInstructionType.swift in Sources */,
C57D55011DB5669600B94B74 /* MBIntersection.swift in Sources */,
AEDC211D20B6104B0052DED8 /* MBComponentRepresentable.swift in Sources */,
439255772344113B006EEE88 /* DirectionsError.swift in Sources */,
DA2E03E91CB0E0B000D1269A /* MBRouteStep.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down Expand Up @@ -1352,8 +1374,12 @@
buildActionMask = 2147483647;
files = (
DADD27BA1E5AAAD800D31FAD /* ViewController.swift in Sources */,
43208BA92343F7E900D8BD89 /* CoreLocation.Swift in Sources */,
C59094B5203B5C7F00EB2417 /* MBDrawingView.swift in Sources */,
43208BA72343F7C300D8BD89 /* Codable.swift in Sources */,
DADD27B81E5AAAD800D31FAD /* AppDelegate.swift in Sources */,
43208BAB2343F81900D8BD89 /* GeoJSON.swift in Sources */,
43208BAD2343FF5500D8BD89 /* DirectionsRespone.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down
78 changes: 78 additions & 0 deletions Sources/MapboxDirections/DirectionsError.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import Foundation
import CoreLocation


public enum DirectionsError: RawRepresentable {
public init?(rawValue: String) {
assertionFailure("Do not use init(rawValue:) for DirectionsError.")
return nil
}

public var rawValue: String {
return """
Error: \(String(describing: self))
Failure Reason: \(failureReason)
Recovery Suggestion: \(recoverySuggestion)
"""
}
public var failureReason: String {
switch self {
case .noData:
return "No data was returned from the server."
case .unableToRoute:
return "No route could be found between the specified locations."
case .unableToLocate:
return "A specified location could not be associated with a roadway or pathway."
case .profileNotFound:
return "Unrecognized profile identifier."
case .requestTooLarge:
return "The request is too large."
case let .rateLimited(rateLimitInterval: interval, rateLimit: limit, _):
let intervalFormatter = DateComponentsFormatter()
intervalFormatter.unitsStyle = .full
guard let interval = interval, let limit = limit else {
return "Too many requests."
}
let formattedInterval = intervalFormatter.string(from: interval) ?? "\(interval) seconds"
let formattedCount = NumberFormatter.localizedString(from: NSNumber(value: limit), number: .decimal)
return "More than \(formattedCount) requests have been made with this access token within a period of \(formattedInterval)"
case let .unknown(response: response, underlying: error):
return "Unknown Error. Response: \(response.debugDescription) Underlying Error: \(error.debugDescription)"

}
}

public var recoverySuggestion: String {
switch self {
case .noData:
return "Make sure you have an active internet connection."
case .unableToRoute:
return "Make sure it is possible to travel between the locations with the mode of transportation implied by the profileIdentifier option. For example, it is impossible to travel by car from one continent to another without either a land bridge or a ferry connection."
case .unableToLocate:
return "Make sure the locations are close enough to a roadway or pathway. Try setting the coordinateAccuracy property of all the waypoints to a negative value."
case .profileNotFound:
return "Make sure the profileIdentifier option is set to one of the provided constants, such as MBDirectionsProfileIdentifierAutomobile."
case .requestTooLarge:
return "Try specifying fewer waypoints or giving the waypoints shorter names."
case let .rateLimited(rateLimitInterval: _, rateLimit: _, resetTime: reset):
guard let reset = reset else {
return "Wait a little while before retrying."
}
let formattedDate: String = DateFormatter.localizedString(from: reset, dateStyle: .long, timeStyle: .long)
return "Wait until \(formattedDate) before retrying."
case .unknown(_,_):
return "Please contact Mapbox Support."
}
}
public typealias RawValue = String


case noData
case unableToRoute
case unableToLocate
case profileNotFound
case requestTooLarge
case rateLimited(rateLimitInterval: TimeInterval?, rateLimit: UInt?, resetTime: Date?)
case unknown(response: URLResponse?, underlying: Error?)

}
60 changes: 60 additions & 0 deletions Sources/MapboxDirections/DirectionsRespone.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import Foundation

struct DirectionsResponse: Codable {

enum CodingKeys: String, CodingKey {
case code
case message
case error
case uuid
case routes
case waypoints
}

var code: String?
var message: String?
var error: String?
let uuid: String?
let routes: [Route]?
let waypoints: [Waypoint]?

init(code: String?, message: String?, error: String?) {
self.code = code
self.message = message
self.error = error
self.uuid = nil
self.routes = nil
self.waypoints = nil
}

init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)

let uuid = try container.decodeIfPresent(String.self, forKey: .uuid)
self.uuid = uuid

let waypoints = try container.decodeIfPresent([Waypoint].self, forKey: .waypoints)
self.waypoints = waypoints

let rawRoutes = try container.decodeIfPresent([Route].self, forKey: .routes)
var routesWithDestinations: [Route]? = rawRoutes
if let destinations = waypoints?.dropFirst() {
routesWithDestinations = rawRoutes?.map({ (route) -> Route in
for (leg, destination) in zip(route.legs, destinations) {
if leg.destination?.name?.nonEmptyString == nil {
leg.destination = destination
}
}
return route
})
}

let routesWithIdentifiers = routesWithDestinations?.map({ (route) -> Route in
route.routeIdentifier = uuid
return route
})

self.routes = routesWithIdentifiers

}
}
26 changes: 2 additions & 24 deletions Sources/MapboxDirections/Extensions/CLLocationCoordinate2D.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import Foundation
import CoreLocation

#warning("Check this")
extension CLLocation {
/**
Initializes a CLLocation object with the given coordinate pair.
Expand All @@ -11,30 +12,7 @@ extension CLLocation {
}

extension CLLocationCoordinate2D {
/**
Initializes a coordinate pair based on the given GeoJSON coordinates array.
*/
internal init(geoJSON array: [Double]) {
assert(array.count == 2)
self.init(latitude: array[1], longitude: array[0])
}

/**
Initializes a coordinate pair based on the given GeoJSON point object.
*/
internal init(geoJSON point: JSONDictionary) {
assert(point["type"] as? String == "Point")
self.init(geoJSON: point["coordinates"] as! [Double])
}

internal static func coordinates(geoJSON lineString: JSONDictionary) -> [CLLocationCoordinate2D] {
let type = lineString["type"] as? String
assert(type == "LineString" || type == "Point")
let coordinates = lineString["coordinates"] as! [[Double]]
return coordinates.map { self.init(geoJSON: $0) }
}

/**
/**
A string representation of the coordinate suitable for insertion in a Directions API request URL.
*/
internal var stringForRequestURL: String? {
Expand Down
53 changes: 53 additions & 0 deletions Sources/MapboxDirections/Extensions/Codable.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import Foundation
import Polyline
import CoreLocation


extension Decodable {
static internal func from<T: Decodable>(json: String, using encoding: String.Encoding = .utf8) -> T? {
guard let data = json.data(using: encoding) else { return nil }
return from(data: data) as T?
}

static internal func from<T: Decodable>(data: Data) -> T? {
let decoder = JSONDecoder()
return try! decoder.decode(T.self, from: data) as T?
}
}

struct UncertainCodable<T: Codable, U: Codable>: Codable {
var t: T?
var u: U?

var value: Codable? {
return t ?? u
}

var coordinates: [CLLocationCoordinate2D] {
if let geo = value as? Geometry {
return geo.coordinates
} else if let geo = value as? String {
return decodePolyline(geo, precision: 1e5)!
} else {
return []
}
}

init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
t = try? container.decode(T.self)
if t == nil {
u = try? container.decode(U.self)
}
}

func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
if let t = t {
try? container.encode(t)
}
if let u = u {
try? container.encode(u)
}
}
}
29 changes: 29 additions & 0 deletions Sources/MapboxDirections/Extensions/CoreLocation.Swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import Foundation
import CoreLocation

extension CLLocationCoordinate2D: Codable {
public func encode(to encoder: Encoder) throws {
var container = encoder.unkeyedContainer()
try container.encode(longitude)
try container.encode(latitude)
}

public init(from decoder: Decoder) throws {
var container = try decoder.unkeyedContainer()
longitude = try container.decode(CLLocationDegrees.self)
latitude = try container.decode(CLLocationDegrees.self)
}

static func == (lhs: CLLocationCoordinate2D, rhs: CLLocationCoordinate2D) -> Bool {
return lhs.latitude == rhs.latitude && lhs.longitude == rhs.longitude
}
}

extension CLLocation {
/**
Initializes a CLLocation object with the given coordinate pair.
*/
internal convenience init(coordinate: CLLocationCoordinate2D) {
self.init(latitude: coordinate.latitude, longitude: coordinate.longitude)
}
}
Loading

0 comments on commit 9e7e860

Please sign in to comment.