Avatar
Kishikawa Katsumi 12/4/2024 8:46 AM
private func send<Request: Message.Request>(_ message: Request) async throws -> Request.Response { let packet = message.encoded() let data = try await connection.send(sign(packet)) let response = Request.Response(data: data) return response } 上記のコードはSMB2のメッセージを送る処理です。 let request = SessionSetup.Request( messageId: messageId.next(), sessionId: response.header.sessionId, securityMode: [.signingEnabled], capabilities: [], previousSessionId: 0, securityBuffer: authenticateMessage.encoded() ) let response = try await send(request) // ^ SessionSetup.Request.Response ^ このように使ってresponseはリクエストに対応するレスポンス型が返ります。 SMB2には複合リクエストという仕組みがあって、一度に複数のリクエストをまとめて送れて往復のオーバーヘッドを減らせます。 それをVariadic GenericsとParameter Packsで書こうと思って次のようなシグネチャの関数を考えたのですが、 private func send<each Request: Message.Request>(_ messages: repeat each Request) async throws -> (repeat (each Request).Response) 複合リクエストの処理は各リクエストメッセージを8バイト境界に揃えて連結して、各リクエストのヘッダーに次のメッセージのオフセット位置を設定する、というものなので、これは現在のParameter Packsだと書けないですよね? private func send<each Request: Message.Request>(_ messages: repeat each Request) async throws -> (repeat (each Request).Response) { let responses: (repeat (each Request).Response) for message in repeat each messages { ... // messageをエンコードして8バイトに揃えながら連結してオフセットをセット } ... // 連結したメッセージを送ってレスポンスを受け取る(ここまではできる) responses = ??? // ^ 受け取ったレスポンスをリクエストに対応するレスポンス型に格納したい(できない?) return responses } 引数のmessagesをループすることはできるけどそれを処理した後で戻り値の(repeat (each Request).Response)に詰め直す方法がないように見える。 使うほうは let (createResponse, queryInfoResponse, closeResponse) = try await send(createRequest, queryInfoRequest, closeRequest) // createResponse: Create.Request.Response // queryInfoResponse: QueryInfo.Request.Response // closeResponse: Close.Request.Response こんな感じで送ったリクエストに対応する型のレスポンスが返るようにしたい。