From 3a7a2f545375b9e38d28fa66d59c8a350a03ee0c Mon Sep 17 00:00:00 2001 From: Joannis Orlandos Date: Wed, 8 May 2024 19:57:05 +0200 Subject: [PATCH 1/5] Allow specialization of the RouterResponder # Conflicts: # Sources/Hummingbird/Router/Trie/Trie+serialize.swift --- Sources/Hummingbird/Router/EndpointResponder.swift | 7 ++++++- Sources/Hummingbird/Router/RouterResponder.swift | 6 ++++++ Sources/Hummingbird/Router/Trie/RouterTrie.swift | 6 +++--- Sources/Hummingbird/Router/Trie/Trie+resolve.swift | 4 ++-- Sources/Hummingbird/Router/TrieRouter.swift | 2 +- 5 files changed, 18 insertions(+), 7 deletions(-) diff --git a/Sources/Hummingbird/Router/EndpointResponder.swift b/Sources/Hummingbird/Router/EndpointResponder.swift index b7495e069..ef84c7d38 100644 --- a/Sources/Hummingbird/Router/EndpointResponder.swift +++ b/Sources/Hummingbird/Router/EndpointResponder.swift @@ -15,13 +15,15 @@ import HTTPTypes /// Stores endpoint responders for each HTTP method +@usableFromInline struct EndpointResponders: Sendable { init(path: String) { self.path = path self.methods = [:] } - public func getResponder(for method: HTTPRequest.Method) -> (any HTTPResponder)? { + @inlinable + public func getResponder(for method: __shared HTTPRequest.Method) -> (any HTTPResponder)? { return self.methods[method] } @@ -41,6 +43,9 @@ struct EndpointResponders: Sendable { } } + @usableFromInline var methods: [HTTPRequest.Method: any HTTPResponder] + + @usableFromInline var path: String } diff --git a/Sources/Hummingbird/Router/RouterResponder.swift b/Sources/Hummingbird/Router/RouterResponder.swift index 83945ce33..07257af4b 100644 --- a/Sources/Hummingbird/Router/RouterResponder.swift +++ b/Sources/Hummingbird/Router/RouterResponder.swift @@ -15,8 +15,13 @@ import NIOCore public struct RouterResponder: HTTPResponder { + @usableFromInline let trie: RouterTrie> + + @usableFromInline let notFoundResponder: any HTTPResponder + + @usableFromInline let options: RouterOptions init( @@ -33,6 +38,7 @@ public struct RouterResponder: HTTPResponder { /// Respond to request by calling correct handler /// - Parameter request: HTTP request /// - Returns: EventLoopFuture that will be fulfilled with the Response + @inlinable public func respond(to request: Request, context: Context) async throws -> Response { let path: String if self.options.contains(.caseInsensitive) { diff --git a/Sources/Hummingbird/Router/Trie/RouterTrie.swift b/Sources/Hummingbird/Router/Trie/RouterTrie.swift index be93c497f..5d560f55a 100644 --- a/Sources/Hummingbird/Router/Trie/RouterTrie.swift +++ b/Sources/Hummingbird/Router/Trie/RouterTrie.swift @@ -56,15 +56,15 @@ struct Trie: Sendable { init() {} } -@_spi(Internal) public final class RouterTrie: Sendable { +@usableFromInline +internal final class RouterTrie: Sendable { @usableFromInline let trie: Trie @usableFromInline let values: [Value?] - @inlinable - @_spi(Internal) public init(base: RouterPathTrieBuilder) { + internal init(base: RouterPathTrieBuilder) { var trie = Trie() var values: [Value?] = [] diff --git a/Sources/Hummingbird/Router/Trie/Trie+resolve.swift b/Sources/Hummingbird/Router/Trie/Trie+resolve.swift index 7439a75e4..bcdfdad16 100644 --- a/Sources/Hummingbird/Router/Trie/Trie+resolve.swift +++ b/Sources/Hummingbird/Router/Trie/Trie+resolve.swift @@ -16,8 +16,8 @@ import NIOCore extension RouterTrie { /// Resolve a path to a `Value` if available - @inlinable - @_spi(Internal) public func resolve(_ path: String) -> (value: Value, parameters: Parameters)? { + @usableFromInline + internal func resolve(_ path: String) -> (value: Value, parameters: Parameters)? { let pathComponents = path.split(separator: "/", omittingEmptySubsequences: true) var pathComponentsIterator = pathComponents.makeIterator() var parameters = Parameters() diff --git a/Sources/Hummingbird/Router/TrieRouter.swift b/Sources/Hummingbird/Router/TrieRouter.swift index 71ef6b378..bef3d775e 100644 --- a/Sources/Hummingbird/Router/TrieRouter.swift +++ b/Sources/Hummingbird/Router/TrieRouter.swift @@ -41,7 +41,7 @@ import HummingbirdCore } } - @_spi(Internal) public func build() -> RouterTrie { + internal func build() -> RouterTrie { .init(base: self) } From ee0dce574bab6264e6f1338dc5175eb2e74eca10 Mon Sep 17 00:00:00 2001 From: Joannis Orlandos Date: Mon, 13 May 2024 13:48:40 +0200 Subject: [PATCH 2/5] Make the router's API public for use in benchmarks --- Benchmarks/Benchmarks/Router/RouterBenchmarks.swift | 2 +- Sources/Hummingbird/Router/Trie/RouterTrie.swift | 7 ++++--- Sources/Hummingbird/Router/Trie/Trie+resolve.swift | 4 ++-- Sources/Hummingbird/Router/TrieRouter.swift | 7 +++++-- Tests/HummingbirdTests/TrieRouterTests.swift | 2 +- 5 files changed, 13 insertions(+), 9 deletions(-) diff --git a/Benchmarks/Benchmarks/Router/RouterBenchmarks.swift b/Benchmarks/Benchmarks/Router/RouterBenchmarks.swift index d01659877..f1fcfd56c 100644 --- a/Benchmarks/Benchmarks/Router/RouterBenchmarks.swift +++ b/Benchmarks/Benchmarks/Router/RouterBenchmarks.swift @@ -17,7 +17,7 @@ import HTTPTypes import Hummingbird import NIOEmbedded import NIOHTTPTypes -@_spi(Internal) import HummingbirdCore +import HummingbirdCore import Logging import NIOCore import NIOPosix diff --git a/Sources/Hummingbird/Router/Trie/RouterTrie.swift b/Sources/Hummingbird/Router/Trie/RouterTrie.swift index 5d560f55a..c3f763a1a 100644 --- a/Sources/Hummingbird/Router/Trie/RouterTrie.swift +++ b/Sources/Hummingbird/Router/Trie/RouterTrie.swift @@ -56,15 +56,16 @@ struct Trie: Sendable { init() {} } -@usableFromInline -internal final class RouterTrie: Sendable { +@_documentation(visibility: internal) +public final class RouterTrie: Sendable { @usableFromInline let trie: Trie @usableFromInline let values: [Value?] - internal init(base: RouterPathTrieBuilder) { + @_documentation(visibility: internal) + public init(base: RouterPathTrieBuilder) { var trie = Trie() var values: [Value?] = [] diff --git a/Sources/Hummingbird/Router/Trie/Trie+resolve.swift b/Sources/Hummingbird/Router/Trie/Trie+resolve.swift index bcdfdad16..383f63ae2 100644 --- a/Sources/Hummingbird/Router/Trie/Trie+resolve.swift +++ b/Sources/Hummingbird/Router/Trie/Trie+resolve.swift @@ -16,8 +16,8 @@ import NIOCore extension RouterTrie { /// Resolve a path to a `Value` if available - @usableFromInline - internal func resolve(_ path: String) -> (value: Value, parameters: Parameters)? { + @inlinable + public func resolve(_ path: String) -> (value: Value, parameters: Parameters)? { let pathComponents = path.split(separator: "/", omittingEmptySubsequences: true) var pathComponentsIterator = pathComponents.makeIterator() var parameters = Parameters() diff --git a/Sources/Hummingbird/Router/TrieRouter.swift b/Sources/Hummingbird/Router/TrieRouter.swift index bef3d775e..885bfc48f 100644 --- a/Sources/Hummingbird/Router/TrieRouter.swift +++ b/Sources/Hummingbird/Router/TrieRouter.swift @@ -15,10 +15,12 @@ import HummingbirdCore /// URI Path Trie Builder -@_spi(Internal) public struct RouterPathTrieBuilder { +@_documentation(visibility: internal) +public struct RouterPathTrieBuilder { @usableFromInline var root: Node + @_documentation(visibility: internal) public init() { self.root = Node(key: .null, output: nil) } @@ -50,7 +52,8 @@ import HummingbirdCore } /// Trie Node. Each node represents one component of a URI path - @_spi(Internal) public final class Node { + @_documentation(visibility: internal) + public final class Node { @usableFromInline let key: RouterPath.Element diff --git a/Tests/HummingbirdTests/TrieRouterTests.swift b/Tests/HummingbirdTests/TrieRouterTests.swift index 60b44515d..73e61d80b 100644 --- a/Tests/HummingbirdTests/TrieRouterTests.swift +++ b/Tests/HummingbirdTests/TrieRouterTests.swift @@ -12,7 +12,7 @@ // //===----------------------------------------------------------------------===// -@_spi(Internal) import Hummingbird +@testable import Hummingbird import XCTest class TrieRouterTests: XCTestCase { From 3581986ae572b5e8c43454b9b249fc43de2a7e20 Mon Sep 17 00:00:00 2001 From: Joannis Orlandos Date: Mon, 13 May 2024 23:48:37 +0200 Subject: [PATCH 3/5] Fix formatting --- Benchmarks/Benchmarks/Router/RouterBenchmarks.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Benchmarks/Benchmarks/Router/RouterBenchmarks.swift b/Benchmarks/Benchmarks/Router/RouterBenchmarks.swift index f1fcfd56c..26bdc8582 100644 --- a/Benchmarks/Benchmarks/Router/RouterBenchmarks.swift +++ b/Benchmarks/Benchmarks/Router/RouterBenchmarks.swift @@ -15,11 +15,11 @@ import Benchmark import HTTPTypes import Hummingbird -import NIOEmbedded -import NIOHTTPTypes import HummingbirdCore import Logging import NIOCore +import NIOEmbedded +import NIOHTTPTypes import NIOPosix /// Implementation of a basic request context that supports everything the Hummingbird library needs From 9734c7e5c0660810eb4b6972345856ef1bca1672 Mon Sep 17 00:00:00 2001 From: Joannis Orlandos Date: Sun, 19 May 2024 22:03:53 +0200 Subject: [PATCH 4/5] Put router serialization under SPI again --- Sources/Hummingbird/Router/Trie/RouterTrie.swift | 3 +-- Sources/Hummingbird/Router/Trie/Trie+serialize.swift | 3 --- Sources/Hummingbird/Router/TrieRouter.swift | 12 +++--------- 3 files changed, 4 insertions(+), 14 deletions(-) diff --git a/Sources/Hummingbird/Router/Trie/RouterTrie.swift b/Sources/Hummingbird/Router/Trie/RouterTrie.swift index c3f763a1a..313374009 100644 --- a/Sources/Hummingbird/Router/Trie/RouterTrie.swift +++ b/Sources/Hummingbird/Router/Trie/RouterTrie.swift @@ -64,8 +64,7 @@ public final class RouterTrie: Sendable { @usableFromInline let values: [Value?] - @_documentation(visibility: internal) - public init(base: RouterPathTrieBuilder) { + @_spi(Internal) public init(base: RouterPathTrieBuilder) { var trie = Trie() var values: [Value?] = [] diff --git a/Sources/Hummingbird/Router/Trie/Trie+serialize.swift b/Sources/Hummingbird/Router/Trie/Trie+serialize.swift index 4fe1dbae7..9f0bad2d3 100644 --- a/Sources/Hummingbird/Router/Trie/Trie+serialize.swift +++ b/Sources/Hummingbird/Router/Trie/Trie+serialize.swift @@ -15,7 +15,6 @@ import NIOCore extension RouterTrie { - @inlinable static func serialize( _ node: RouterPathTrieBuilder.Node, trie: inout Trie, @@ -82,7 +81,6 @@ extension RouterTrie { trie.nodes[nodeIndex].nextSiblingNodeIndex = trie.nodes.count } - @inlinable static func serializeChildren( of node: RouterPathTrieBuilder.Node, trie: inout Trie, @@ -95,7 +93,6 @@ extension RouterTrie { } } - @inlinable internal static func highestPriorityFirst(lhs: RouterPathTrieBuilder.Node, rhs: RouterPathTrieBuilder.Node) -> Bool { lhs.key.priority > rhs.key.priority } diff --git a/Sources/Hummingbird/Router/TrieRouter.swift b/Sources/Hummingbird/Router/TrieRouter.swift index 885bfc48f..f182da8db 100644 --- a/Sources/Hummingbird/Router/TrieRouter.swift +++ b/Sources/Hummingbird/Router/TrieRouter.swift @@ -15,12 +15,10 @@ import HummingbirdCore /// URI Path Trie Builder -@_documentation(visibility: internal) -public struct RouterPathTrieBuilder { +@_spi(Internal) public struct RouterPathTrieBuilder { @usableFromInline var root: Node - @_documentation(visibility: internal) public init() { self.root = Node(key: .null, output: nil) } @@ -43,7 +41,7 @@ public struct RouterPathTrieBuilder { } } - internal func build() -> RouterTrie { + @_spi(Internal) public func build() -> RouterTrie { .init(base: self) } @@ -52,15 +50,11 @@ public struct RouterPathTrieBuilder { } /// Trie Node. Each node represents one component of a URI path - @_documentation(visibility: internal) - public final class Node { - @usableFromInline + @_spi(Internal) public final class Node { let key: RouterPath.Element - @usableFromInline var children: [Node] - @usableFromInline var value: Value? init(key: RouterPath.Element, output: Value?) { From 5815fa58e844fc2d12803f685d30effcc664daf0 Mon Sep 17 00:00:00 2001 From: Adam Fowler Date: Mon, 20 May 2024 07:57:18 +0100 Subject: [PATCH 5/5] Fix build error --- Sources/Hummingbird/Router/TrieRouter.swift | 4 ++-- Tests/HummingbirdTests/TrieRouterTests.swift | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Sources/Hummingbird/Router/TrieRouter.swift b/Sources/Hummingbird/Router/TrieRouter.swift index f182da8db..03b865115 100644 --- a/Sources/Hummingbird/Router/TrieRouter.swift +++ b/Sources/Hummingbird/Router/TrieRouter.swift @@ -19,7 +19,7 @@ import HummingbirdCore @usableFromInline var root: Node - public init() { + @_spi(Internal) public init() { self.root = Node(key: .null, output: nil) } @@ -28,7 +28,7 @@ import HummingbirdCore /// - entry: Path for entry /// - value: Value to add to this path if one does not exist already /// - onAdd: How to edit the value at this path - public func addEntry(_ entry: RouterPath, value: @autoclosure () -> Value, onAdd: (Node) -> Void = { _ in }) { + @_spi(Internal) public func addEntry(_ entry: RouterPath, value: @autoclosure () -> Value, onAdd: (Node) -> Void = { _ in }) { var node = self.root for key in entry { node = node.addChild(key: key, output: nil) diff --git a/Tests/HummingbirdTests/TrieRouterTests.swift b/Tests/HummingbirdTests/TrieRouterTests.swift index 73e61d80b..46c4134df 100644 --- a/Tests/HummingbirdTests/TrieRouterTests.swift +++ b/Tests/HummingbirdTests/TrieRouterTests.swift @@ -12,7 +12,7 @@ // //===----------------------------------------------------------------------===// -@testable import Hummingbird +@testable @_spi(Internal) import Hummingbird import XCTest class TrieRouterTests: XCTestCase {