0001
0025 @_exported import HTTP
0026
0027 public struct TrieRouteMatcherTrieRouteMatcher.swift:219 | extension TrieRouteMatcher: CustomStringConvertible { |
: RouteMatcherType {
0028 private var componentsTrieTrieRouteMatcher.swift:221 | return componentsTrie.description + "\n" + routesTrie.description |
= Trie<Character, Int>()
0029 private var routesTrie = Trie<Int, Route>()
0030 public let routes: [Route]
0031 private var parameterDictionary = [Int:String]()
0032
0033 public init(routes: [Route]) {
0034 self.routes = routes
0035
0036 var nextComponentId = 1
0037
0038 for route in routes {
0039
0040 for method in route.methods {
0041
0042 let path = method.description + route.path
0044
0045 let componentIds = path.split("/").map { component -> Int in
0047
0048 if let id = componentsTrie.findPayload(component.characters) {
0050 return id
0051 }
0052
0053 let id: Int
0054
0055 if component.characters.first == ":" {
0056 id = -nextComponentId
0058 } else {
0059 id = nextComponentId
0061 }
0062
0063 if id < 0 {
0064 let parameter = String(component.characters.dropFirst())
0066 parameterDictionary[id] = parameter
0067 }
0068
0069 nextComponentId += 1
0071
0072 componentsTrie.insert(component.characters, payload: id)
0074
0075 return id
0076 }
0077
0078 routesTrie.insert(componentIds, payload: route)
0080 }
0081 }
0082 }
0083
0084 func searchForRoute(head head: Trie<Int, Route>, components: [String], componentIndex startingIndex: Int, inout parameters: [String:String]) -> Route? {
0085
0086 var head = head
0089
0090 var alternatives: [(Int, Trie<Int, Route>)] = []
0095
0096 componentLoop: for (componentIndex, component) in components[startingIndex..<components.count].enumerate() {
0099
0100 let id = componentsTrie.findPayload(component.characters)
0102
0103 if id == nil {
0105
0106 for child in head.children {
0107
0108 if child.prefix < 0 {
0111 head = child
0112 let parameter = parameterDictionary[child.prefix!]
0113 parameters[parameter!] = component
0114 continue componentLoop
0115 }
0116 }
0117
0118 return nil
0120 }
0121
0122 head.children.sortInPlace { n1, n2 in
0126 n1.prefix > n2.prefix
0127 }
0128
0129 var preferredHead: Trie<Int, Route>? = nil
0133
0134 for child in head.children {
0136
0137 if child.prefix == id {
0139 if preferredHead == nil { preferredHead = child }
0140 else { alternatives.append((componentIndex + 1, child)) }
0141 continue
0142 }
0143
0144 if child.prefix < 0 {
0148 if preferredHead == nil {
0149 preferredHead = child
0150 let parameter = parameterDictionary[child.prefix!]
0151 parameters[parameter!] = component
0152 } else {
0153 alternatives.append((componentIndex + 1, child))
0154 }
0155 }
0156 }
0157
0158 if let preferredHead = preferredHead {
0160 head = preferredHead
0161 continue
0162 }
0163
0164 for alternative in alternatives {
0167
0168 let matched = searchForRoute(head: alternative.1, components: components, componentIndex: alternative.0, parameters: ¶meters)
0169
0170 if matched != nil { return matched }
0171 }
0172
0173 return nil
0175 }
0176
0177 return head.payload
0179 }
0180
0181 public func match(request: Request) -> Route? {
0182 guard let path = request.path else {
0183 return nil
0184 }
0185
0186 let components = [request.method.description] + path.unicodeScalars.split("/").map(String.init)
0187
0188 var parameters = [String:String]()
0189
0190 let matched = searchForRoute(head: routesTrie, components: components, componentIndex: 0, parameters: ¶meters)
0192
0193 guard let route = matched else { return nil }
0195
0196 if parameters.isEmpty {
0198 return route
0199 }
0200
0201 let wrappedRoute = Route(
0203 methods: route.methods,
0204 path: route.path,
0205 middleware: route.middleware,
0206 responder: Responder { req in
0207 var req = req
0208 for (key, parameter) in parameters {
0209 req.pathParameters[key] = parameter
0210 }
0211 return try route.respond(req)
0212 }
0213 )
0214
0215 return wrappedRoute
0216 }
0217 }
0218
0219 extension TrieRouteMatcher: CustomStringConvertible {
0220 public var description: String {
0221 return componentsTrie.description + "\n" + routesTrie.description
0222 }
0223 }
0224