Skip to content

Commit ba8122e

Browse files
committed
Use ServiceDescriptor within MethodDescriptor
Motivation: MethodDescriptor uses a string to represent the fully qualified name of the service the method belongs to. ServiceDescriptor also represents a fully qualified name of a service. It'd make more sense for MethodDescriptor to use a ServiceDescriptor instead of a string to describe the service. Modifications: - ServiceDescriptor now stores the fully qualified service name (as this is generally more useful) and computes the package and unqualified service name. - ServiceDescriptor can now be created from the fully qualified name or from a separate package and service name. - MethodDescriptor now holds a ServiceDescriptor instead of a String for the service Result: More coherent API
1 parent 3b0fe70 commit ba8122e

20 files changed

+141
-90
lines changed

Sources/GRPCCore/Call/Client/ClientInterceptorPipelineOperation.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ public struct ClientInterceptorPipelineOperation: Sendable {
6161
return true
6262

6363
case .services(let services):
64-
return services.map({ $0.fullyQualifiedService }).contains(descriptor.service)
64+
return services.contains(descriptor.service)
6565

6666
case .methods(let methods):
6767
return methods.contains(descriptor)

Sources/GRPCCore/Call/Server/ServerInterceptorPipelineOperation.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ public struct ServerInterceptorPipelineOperation: Sendable {
6161
return true
6262

6363
case .services(let services):
64-
return services.map({ $0.fullyQualifiedService }).contains(descriptor.service)
64+
return services.contains(descriptor.service)
6565

6666
case .methods(let methods):
6767
return methods.contains(descriptor)

Sources/GRPCCore/Internal/MethodConfigs.swift

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,10 @@ package struct MethodConfigs: Sendable, Hashable {
5151
/// - descriptor: The ``MethodDescriptor`` for which to get or set a ``MethodConfig``.
5252
package subscript(_ descriptor: MethodDescriptor) -> MethodConfig? {
5353
get {
54-
var name = MethodConfig.Name(service: descriptor.service, method: descriptor.method)
54+
var name = MethodConfig.Name(
55+
service: descriptor.service.fullyQualifiedService,
56+
method: descriptor.method
57+
)
5558

5659
if let configuration = self.elements[name] {
5760
return configuration
@@ -70,7 +73,10 @@ package struct MethodConfigs: Sendable, Hashable {
7073
}
7174

7275
set {
73-
let name = MethodConfig.Name(service: descriptor.service, method: descriptor.method)
76+
let name = MethodConfig.Name(
77+
service: descriptor.service.fullyQualifiedService,
78+
method: descriptor.method
79+
)
7480
self.elements[name] = newValue
7581
}
7682
}

Sources/GRPCCore/MethodDescriptor.swift

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,8 @@
1616

1717
/// A description of a method on a service.
1818
public struct MethodDescriptor: Sendable, Hashable {
19-
/// The name of the service, including the package name.
20-
///
21-
/// For example, the name of the "Greeter" service in "helloworld" package
22-
/// is "helloworld.Greeter".
23-
public var service: String
19+
/// A description of the service, including its package name.
20+
public var service: ServiceDescriptor
2421

2522
/// The name of the method in the service, excluding the service name.
2623
public var method: String
@@ -39,8 +36,30 @@ public struct MethodDescriptor: Sendable, Hashable {
3936
/// - service: The name of the service, including the package name. For example,
4037
/// "helloworld.Greeter".
4138
/// - method: The name of the method. For example, "SayHello".
42-
public init(service: String, method: String) {
39+
public init(service: ServiceDescriptor, method: String) {
4340
self.service = service
4441
self.method = method
4542
}
43+
44+
/// Creates a new method descriptor.
45+
///
46+
/// - Parameters:
47+
/// - fullyQualifiedService: The fully qualified name of the service, including the package
48+
/// name. For example, "helloworld.Greeter".
49+
/// - method: The name of the method. For example, "SayHello".
50+
public init(fullyQualifiedService: String, method: String) {
51+
self.service = ServiceDescriptor(fullyQualifiedService: fullyQualifiedService)
52+
self.method = method
53+
}
54+
55+
@available(*, deprecated, renamed: "init(fullyQualifiedService:method:)")
56+
/// Creates a new method descriptor.
57+
///
58+
/// - Parameters:
59+
/// - service: The fully qualified name of the service, including the package
60+
/// name. For example, "helloworld.Greeter".
61+
/// - method: The name of the method. For example, "SayHello".
62+
public init(service: String, method: String) {
63+
self.init(fullyQualifiedService: service, method: method)
64+
}
4665
}

Sources/GRPCCore/ServiceDescriptor.swift

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,28 +18,44 @@
1818
public struct ServiceDescriptor: Sendable, Hashable {
1919
/// The name of the package the service belongs to. For example, "helloworld".
2020
/// An empty string means that the service does not belong to any package.
21-
public var package: String
21+
public var package: String {
22+
if let index = self.fullyQualifiedService.utf8.lastIndex(of: UInt8(ascii: ".")) {
23+
return String(self.fullyQualifiedService[..<index])
24+
} else {
25+
return ""
26+
}
27+
}
2228

2329
/// The name of the service. For example, "Greeter".
24-
public var service: String
30+
public var service: String {
31+
if var index = self.fullyQualifiedService.utf8.lastIndex(of: UInt8(ascii: ".")) {
32+
self.fullyQualifiedService.utf8.formIndex(after: &index)
33+
return String(self.fullyQualifiedService[index...])
34+
} else {
35+
return self.fullyQualifiedService
36+
}
37+
}
2538

2639
/// The fully qualified service name in the format:
2740
/// - "package.service": if a package name is specified. For example, "helloworld.Greeter".
2841
/// - "service": if a package name is not specified. For example, "Greeter".
29-
public var fullyQualifiedService: String {
30-
if self.package.isEmpty {
31-
return self.service
32-
}
42+
public var fullyQualifiedService: String
3343

34-
return "\(self.package).\(self.service)"
44+
/// Create a new descriptor from the fully qualified service name.
45+
/// - Parameter fullyQualifiedService: The fully qualified service name.
46+
public init(fullyQualifiedService: String) {
47+
self.fullyQualifiedService = fullyQualifiedService
3548
}
3649

3750
/// - Parameters:
3851
/// - package: The name of the package the service belongs to. For example, "helloworld".
3952
/// An empty string means that the service does not belong to any package.
4053
/// - service: The name of the service. For example, "Greeter".
4154
public init(package: String, service: String) {
42-
self.package = package
43-
self.service = service
55+
if package.isEmpty {
56+
self.fullyQualifiedService = service
57+
} else {
58+
self.fullyQualifiedService = package + "." + service
59+
}
4460
}
4561
}

Tests/GRPCCoreTests/Call/Client/ClientInterceptorPipelineOperationTests.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,8 @@ struct ClientInterceptorPipelineOperationTests {
6161
}
6262

6363
extension MethodDescriptor {
64-
fileprivate static let fooBar = Self(service: "pkg.foo", method: "bar")
65-
fileprivate static let fooBaz = Self(service: "pkg.foo", method: "baz")
66-
fileprivate static let barFoo = Self(service: "pkg.bar", method: "foo")
67-
fileprivate static let barBaz = Self(service: "pkg.bar", method: "Baz")
64+
fileprivate static let fooBar = Self(fullyQualifiedService: "pkg.foo", method: "bar")
65+
fileprivate static let fooBaz = Self(fullyQualifiedService: "pkg.foo", method: "baz")
66+
fileprivate static let barFoo = Self(fullyQualifiedService: "pkg.bar", method: "foo")
67+
fileprivate static let barBaz = Self(fullyQualifiedService: "pkg.bar", method: "Baz")
6868
}

Tests/GRPCCoreTests/Call/Client/Internal/ClientRPCExecutorTestSupport/ClientRPCExecutorTestHarness.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ struct ClientRPCExecutorTestHarness {
136136
// Execute the request.
137137
try await ClientRPCExecutor.execute(
138138
request: request,
139-
method: MethodDescriptor(service: "foo", method: "bar"),
139+
method: MethodDescriptor(fullyQualifiedService: "foo", method: "bar"),
140140
options: options,
141141
serializer: serializer,
142142
deserializer: deserializer,

Tests/GRPCCoreTests/Call/Server/Internal/ServerRPCExecutorTestSupport/ServerRPCExecutorTestHarness.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ struct ServerRPCExecutorTestHarness {
101101
group.addTask {
102102
await withServerContextRPCCancellationHandle { cancellation in
103103
let context = ServerContext(
104-
descriptor: MethodDescriptor(service: "foo", method: "bar"),
104+
descriptor: MethodDescriptor(fullyQualifiedService: "foo", method: "bar"),
105105
cancellation: cancellation
106106
)
107107

Tests/GRPCCoreTests/Call/Server/RPCRouterTests.swift

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,17 @@ final class RPCRouterTests: XCTestCase {
2222
var router = RPCRouter()
2323
XCTAssertEqual(router.count, 0)
2424
XCTAssertEqual(router.methods, [])
25-
XCTAssertFalse(router.hasHandler(forMethod: MethodDescriptor(service: "foo", method: "bar")))
26-
XCTAssertFalse(router.removeHandler(forMethod: MethodDescriptor(service: "foo", method: "bar")))
25+
XCTAssertFalse(
26+
router.hasHandler(forMethod: MethodDescriptor(fullyQualifiedService: "foo", method: "bar"))
27+
)
28+
XCTAssertFalse(
29+
router.removeHandler(forMethod: MethodDescriptor(fullyQualifiedService: "foo", method: "bar"))
30+
)
2731
}
2832

2933
func testRegisterMethod() async throws {
3034
var router = RPCRouter()
31-
let method = MethodDescriptor(service: "foo", method: "bar")
35+
let method = MethodDescriptor(fullyQualifiedService: "foo", method: "bar")
3236
router.registerHandler(
3337
forMethod: method,
3438
deserializer: IdentityDeserializer(),
@@ -44,7 +48,7 @@ final class RPCRouterTests: XCTestCase {
4448

4549
func testRemoveMethod() async throws {
4650
var router = RPCRouter()
47-
let method = MethodDescriptor(service: "foo", method: "bar")
51+
let method = MethodDescriptor(fullyQualifiedService: "foo", method: "bar")
4852
router.registerHandler(
4953
forMethod: method,
5054
deserializer: IdentityDeserializer(),

Tests/GRPCCoreTests/Call/Server/ServerInterceptorPipelineOperation.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,8 @@ struct ServerInterceptorPipelineOperationTests {
6161
}
6262

6363
extension MethodDescriptor {
64-
fileprivate static let fooBar = Self(service: "pkg.foo", method: "bar")
65-
fileprivate static let fooBaz = Self(service: "pkg.foo", method: "baz")
66-
fileprivate static let barFoo = Self(service: "pkg.bar", method: "foo")
67-
fileprivate static let barBaz = Self(service: "pkg.bar", method: "Baz")
64+
fileprivate static let fooBar = Self(fullyQualifiedService: "pkg.foo", method: "bar")
65+
fileprivate static let fooBaz = Self(fullyQualifiedService: "pkg.foo", method: "baz")
66+
fileprivate static let barFoo = Self(fullyQualifiedService: "pkg.bar", method: "foo")
67+
fileprivate static let barBaz = Self(fullyQualifiedService: "pkg.bar", method: "Baz")
6868
}

0 commit comments

Comments
 (0)