mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
[Distributed] Add more tests for implicit Codable on distributed actors
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
// RUN: %empty-directory(%t)
|
||||
// RUN: %target-swift-frontend-emit-module -emit-module-path %t/FakeDistributedActorSystems.swiftmodule -module-name FakeDistributedActorSystems -disable-availability-checking %S/../Inputs/FakeDistributedActorSystems.swift
|
||||
// RUN: %target-build-swift -module-name main -Xfrontend -disable-availability-checking -j2 -parse-as-library -I %t %s %S/../Inputs/FakeDistributedActorSystems.swift -o %t/a.out
|
||||
// RUN: %target-codesign %t/a.out
|
||||
// RUN: %target-run %t/a.out | %FileCheck %s --dump-input=always
|
||||
|
||||
// REQUIRES: executable_test
|
||||
// REQUIRES: concurrency
|
||||
// REQUIRES: distributed
|
||||
|
||||
// rdar://76038845
|
||||
// UNSUPPORTED: use_os_stdlib
|
||||
// UNSUPPORTED: back_deployment_runtime
|
||||
|
||||
// UNSUPPORTED: OS=windows-msvc
|
||||
|
||||
import Distributed
|
||||
|
||||
extension UInt8: CustomSerializationProtocol {
|
||||
public func toBytes() throws -> [UInt8] {
|
||||
[self]
|
||||
}
|
||||
public static func fromBytes(_ bytes: [UInt8]) throws -> Self {
|
||||
bytes.first!
|
||||
}
|
||||
}
|
||||
|
||||
distributed actor Tester {
|
||||
typealias ActorSystem = FakeCustomSerializationRoundtripActorSystem
|
||||
|
||||
distributed func echo(param: UInt8) -> UInt8 {
|
||||
param
|
||||
}
|
||||
}
|
||||
|
||||
// ==== ------------------------------------------------------------------------
|
||||
|
||||
func test() async throws {
|
||||
let system = FakeCustomSerializationRoundtripActorSystem()
|
||||
|
||||
let local = Tester(actorSystem: system)
|
||||
let ref = try Tester.resolve(id: local.id, using: system)
|
||||
|
||||
let reply = try await ref.echo(param: 2)
|
||||
// CHECK: >> remoteCall: on:main.Tester, target:main.Tester.echo(param:), invocation:FakeCustomSerializationInvocationEncoder(genericSubs: [], arguments: [2], returnType: Optional(Swift.UInt8), errorType: nil), throwing:Swift.Never, returning:Swift.UInt8
|
||||
|
||||
// CHECK: << remoteCall return: 2
|
||||
print("reply: \(reply)")
|
||||
// CHECK: reply: 2
|
||||
}
|
||||
|
||||
@main struct Main {
|
||||
static func main() async {
|
||||
try! await test()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,169 @@
|
||||
// RUN: %empty-directory(%t)
|
||||
// RUN: %target-swift-frontend-emit-module -emit-module-path %t/FakeDistributedActorSystems.swiftmodule -module-name FakeDistributedActorSystems -disable-availability-checking %S/../Inputs/FakeDistributedActorSystems.swift
|
||||
// RUN: %target-build-swift -module-name main -Xfrontend -disable-availability-checking -j2 -parse-as-library -I %t %s %S/../Inputs/FakeDistributedActorSystems.swift -o %t/a.out
|
||||
// RUN: %target-codesign %t/a.out
|
||||
// RUN: %target-run %t/a.out | %FileCheck %s --color
|
||||
|
||||
// REQUIRES: executable_test
|
||||
// REQUIRES: concurrency
|
||||
// REQUIRES: distributed
|
||||
|
||||
// We're using Foundation for the JSON Encoder, could be done without but good enough
|
||||
// REQUIRES: objc_interop
|
||||
|
||||
|
||||
// rdar://76038845
|
||||
// UNSUPPORTED: use_os_stdlib
|
||||
// UNSUPPORTED: back_deployment_runtime
|
||||
|
||||
import Foundation
|
||||
import Distributed
|
||||
|
||||
final class LocalActorSystem : DistributedActorSystem {
|
||||
typealias ActorID = LocalTestingActorID
|
||||
typealias ResultHandler = LocalTestingInvocationResultHandler
|
||||
typealias InvocationEncoder = LocalTestingInvocationEncoder
|
||||
typealias InvocationDecoder = LocalTestingInvocationDecoder
|
||||
typealias SerializationRequirement = any Codable
|
||||
|
||||
func makeInvocationEncoder() -> InvocationEncoder { LocalTestingDistributedActorSystem().makeInvocationEncoder() }
|
||||
|
||||
func resolve<Act>(id: ActorID, as actorType: Act.Type) throws -> Act? where Act: DistributedActor {
|
||||
nil
|
||||
}
|
||||
|
||||
func actorReady<Act>(_ actor: Act) where Act: DistributedActor, Act.ID == ActorID {
|
||||
}
|
||||
|
||||
func resignID(_ id: ActorID) {}
|
||||
|
||||
func assignID<Act>(_ actorType: Act.Type) -> ActorID
|
||||
where Act: DistributedActor {
|
||||
.init(id: "42")
|
||||
}
|
||||
|
||||
func remoteCall<Act, Err, Res>(on actor: Act,
|
||||
target: RemoteCallTarget,
|
||||
invocation: inout InvocationEncoder,
|
||||
throwing: Err.Type,
|
||||
returning: Res.Type) async throws -> Res
|
||||
where Act: DistributedActor,
|
||||
Act.ID == ActorID,
|
||||
Err: Error,
|
||||
Res: Codable {
|
||||
let decoder = JSONDecoder()
|
||||
return try! decoder.decode(Res.self, from: await fetchData())
|
||||
}
|
||||
|
||||
func remoteCallVoid<Act, Err>(on actor: Act,
|
||||
target: RemoteCallTarget,
|
||||
invocation: inout InvocationEncoder,
|
||||
throwing errorType: Err.Type) async throws
|
||||
where Act: DistributedActor,
|
||||
Act.ID == ActorID,
|
||||
Err: Error {
|
||||
fatalError("not implemented: \(#function)")
|
||||
}
|
||||
|
||||
func fetchData() async -> Data {
|
||||
"42".data(using: .ascii)!
|
||||
}
|
||||
}
|
||||
|
||||
distributed actor NotCodableDA<ActorSystem>
|
||||
where ActorSystem: DistributedActorSystem<any Codable> {
|
||||
|
||||
init(actorSystem: ActorSystem) async {
|
||||
self.actorSystem = actorSystem
|
||||
|
||||
print(try! await self.request())
|
||||
}
|
||||
|
||||
func request() async throws -> Int {
|
||||
let target = RemoteCallTarget("test.request")
|
||||
var encoder = actorSystem.makeInvocationEncoder()
|
||||
return try await actorSystem.remoteCall(on: self,
|
||||
target: target,
|
||||
invocation: &encoder,
|
||||
throwing: Error.self,
|
||||
returning: Int.self)
|
||||
}
|
||||
}
|
||||
|
||||
distributed actor CodableDA<ActorSystem>: Codable
|
||||
where ActorSystem: DistributedActorSystem<any Codable>,
|
||||
ActorSystem.ActorID: Codable {
|
||||
|
||||
init(actorSystem: ActorSystem) async {
|
||||
self.actorSystem = actorSystem
|
||||
|
||||
print(try! await self.request())
|
||||
}
|
||||
|
||||
func request() async throws -> Int {
|
||||
let target = RemoteCallTarget("test.request")
|
||||
var encoder = actorSystem.makeInvocationEncoder()
|
||||
return try await actorSystem.remoteCall(on: self,
|
||||
target: target,
|
||||
invocation: &encoder,
|
||||
throwing: Error.self,
|
||||
returning: Int.self)
|
||||
}
|
||||
}
|
||||
|
||||
distributed actor CodableIDDA<ActorSystem>
|
||||
where ActorSystem: DistributedActorSystem<any Codable>,
|
||||
ActorSystem.ActorID: Codable {
|
||||
|
||||
init(actorSystem: ActorSystem) async {
|
||||
self.actorSystem = actorSystem
|
||||
|
||||
print(try! await self.request())
|
||||
}
|
||||
|
||||
func request() async throws -> Int {
|
||||
let target = RemoteCallTarget("test.request")
|
||||
var encoder = actorSystem.makeInvocationEncoder()
|
||||
return try await actorSystem.remoteCall(on: self,
|
||||
target: target,
|
||||
invocation: &encoder,
|
||||
throwing: Error.self,
|
||||
returning: Int.self)
|
||||
}
|
||||
}
|
||||
|
||||
@main struct Main {
|
||||
static func main() async throws {
|
||||
if #available(SwiftStdlib 5.9, *) {
|
||||
let system = LocalActorSystem()
|
||||
let ncda = await NotCodableDA(actorSystem: system)
|
||||
let cidda = await CodableIDDA(actorSystem: system)
|
||||
let cda = await CodableDA(actorSystem: system)
|
||||
|
||||
try await ncda.whenLocal {
|
||||
let got = try await $0.request()
|
||||
|
||||
// CHECK: got = 42
|
||||
print("got = \(got)")
|
||||
}
|
||||
|
||||
try await cidda.whenLocal {
|
||||
let got = try await $0.request()
|
||||
|
||||
// CHECK: got = 42
|
||||
print("got = \(got)")
|
||||
}
|
||||
|
||||
let _: any (DistributedActor & Codable) = cda
|
||||
try await cda.whenLocal {
|
||||
let got = try await $0.request()
|
||||
|
||||
// CHECK: got = 42
|
||||
print("got = \(got)")
|
||||
}
|
||||
|
||||
// CHECK: OK
|
||||
print("OK")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,3 +17,48 @@ func take<A: Codable>(actor: A) {}
|
||||
func test(actorSystem: FakeActorSystem) {
|
||||
take(actor: DA(actorSystem: actorSystem)) // ok
|
||||
}
|
||||
|
||||
func takeCodable<A: Codable>(actor: A) {}
|
||||
|
||||
func test_DA(actorSystem: FakeActorSystem) {
|
||||
takeCodable(actor: DA(actorSystem: actorSystem)) // ok
|
||||
}
|
||||
|
||||
// ==== Generic actors
|
||||
|
||||
distributed actor DAG<ActorSystem>
|
||||
where ActorSystem: DistributedActorSystem<any Codable> {
|
||||
}
|
||||
func test_DAG(actorSystem: FakeActorSystem) {
|
||||
takeCodable(actor: DAG<FakeActorSystem>(actorSystem: actorSystem)) // ok
|
||||
}
|
||||
|
||||
distributed actor DAG_ID<ActorSystem>
|
||||
where ActorSystem: DistributedActorSystem<any Codable>,
|
||||
ID: Codable { // expected-error{{cannot find type 'ID' in scope}}
|
||||
}
|
||||
func test_DAG_ID(actorSystem: FakeActorSystem) {
|
||||
takeCodable(actor: DAG_ID<FakeActorSystem>(actorSystem: actorSystem)) // ok
|
||||
}
|
||||
|
||||
distributed actor DAG_ActorSystem_ActorID<ActorSystem>
|
||||
where ActorSystem: DistributedActorSystem<any Codable>,
|
||||
ActorSystem.ActorID: Codable {
|
||||
}
|
||||
func test_DAG_ActorSystem_ActorID(actorSystem: FakeActorSystem) {
|
||||
takeCodable(actor: DAG_ActorSystem_ActorID<FakeActorSystem>(actorSystem: actorSystem)) // ok
|
||||
}
|
||||
|
||||
// ==== Not codable cases
|
||||
|
||||
protocol SerializableButNotCodable {}
|
||||
|
||||
distributed actor DAG_ActorSystem_ActorID_Custom<ActorSystem>
|
||||
where ActorSystem: DistributedActorSystem<any SerializableButNotCodable> {
|
||||
// expected-note@-2{{requirement specified as 'ActorSystem.SerializationRequirement' == 'any SerializableButNotCodable'}}
|
||||
}
|
||||
|
||||
func test_DAG_ActorSystem_ActorID_Custom(actorSystem: FakeActorSystem) {
|
||||
takeCodable(actor: DAG_ActorSystem_ActorID_Custom<FakeActorSystem>(actorSystem: actorSystem))
|
||||
// expected-error@-1{{'DAG_ActorSystem_ActorID_Custom' requires the types 'any FakeActorSystem.SerializationRequirement' (aka 'any Decodable & Encodable') and 'any SerializableButNotCodable' be equivalent}}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user