@@ -473,3 +473,289 @@ extension ExtensionDescription {
473473 )
474474 }
475475}
476+
477+ extension FunctionSignatureDescription {
478+ /// ```
479+ /// func <Name>(
480+ /// request: <Input>,
481+ /// context: GRPCCore.ServerContext,
482+ /// ) async throws -> <Output>
483+ /// ```
484+ ///
485+ /// ```
486+ /// func <Name>(
487+ /// request: GRPCCore.RPCAsyncSequence<Input, any Error>,
488+ /// response: GRPCCore.RPCAsyncWriter<Output>
489+ /// context: GRPCCore.ServerContext,
490+ /// ) async throws
491+ /// ```
492+ static func simpleServerMethod(
493+ accessLevel: AccessModifier ? = nil ,
494+ name: String ,
495+ input: String ,
496+ output: String ,
497+ streamingInput: Bool ,
498+ streamingOutput: Bool
499+ ) -> Self {
500+ var parameters : [ ParameterDescription ] = [
501+ ParameterDescription (
502+ label: " request " ,
503+ type: streamingInput ? . rpcAsyncSequence( forType: input) : . member( input)
504+ )
505+ ]
506+
507+ if streamingOutput {
508+ parameters. append ( ParameterDescription ( label: " response " , type: . rpcWriter( forType: output) ) )
509+ }
510+
511+ parameters. append ( ParameterDescription ( label: " context " , type: . serverContext) )
512+
513+ return FunctionSignatureDescription (
514+ accessModifier: accessLevel,
515+ kind: . function( name: name) ,
516+ parameters: parameters,
517+ keywords: [ . async, . throws] ,
518+ returnType: streamingOutput ? nil : . identifier( . pattern( output) )
519+ )
520+ }
521+ }
522+
523+ extension ProtocolDescription {
524+ /// ```
525+ /// protocol SimpleServiceProtocol: <ServiceProtocol> {
526+ /// ...
527+ /// }
528+ /// ```
529+ static func simpleServiceProtocol(
530+ accessModifier: AccessModifier ? = nil ,
531+ name: String ,
532+ serviceProtocol: String ,
533+ methods: [ MethodDescriptor ]
534+ ) -> Self {
535+ func docs( for method: MethodDescriptor ) -> String {
536+ let summary = """
537+ /// Handle the " \( method. name. normalizedBase) " method.
538+ """
539+
540+ let requestText =
541+ method. isInputStreaming
542+ ? " A stream of ` \( method. inputType) ` messages. "
543+ : " A ` \( method. inputType) ` message. "
544+
545+ var parameters = """
546+ /// - Parameters:
547+ /// - request: \( requestText)
548+ """
549+
550+ if method. isOutputStreaming {
551+ parameters += " \n "
552+ parameters += """
553+ /// - response: A response stream of ` \( method. outputType) ` messages.
554+ """
555+ }
556+
557+ parameters += " \n "
558+ parameters += """
559+ /// - context: Context providing information about the RPC.
560+ /// - Throws: Any error which occurred during the processing of the request. Thrown errors
561+ /// of type `RPCError` are mapped to appropriate statuses. All other errors are converted
562+ /// to an internal error.
563+ """
564+
565+ if !method. isOutputStreaming {
566+ parameters += " \n "
567+ parameters += """
568+ /// - Returns: A ` \( method. outputType) ` to respond with.
569+ """
570+ }
571+
572+ return Docs . interposeDocs ( method. documentation, between: summary, and: parameters)
573+ }
574+
575+ return ProtocolDescription (
576+ accessModifier: accessModifier,
577+ name: name,
578+ conformances: [ serviceProtocol] ,
579+ members: methods. map { method in
580+ . commentable(
581+ . preFormatted( docs ( for: method) ) ,
582+ . function(
583+ signature: . simpleServerMethod(
584+ name: method. name. generatedLowerCase,
585+ input: method. inputType,
586+ output: method. outputType,
587+ streamingInput: method. isInputStreaming,
588+ streamingOutput: method. isOutputStreaming
589+ )
590+ )
591+ )
592+ }
593+ )
594+ }
595+ }
596+
597+ extension FunctionCallDescription {
598+ /// ```
599+ /// try await self.<Name>(
600+ /// request: request.message,
601+ /// response: writer,
602+ /// context: context
603+ /// )
604+ /// ```
605+ static func serviceMethodCallingSimpleMethod(
606+ name: String ,
607+ input: String ,
608+ output: String ,
609+ streamingInput: Bool ,
610+ streamingOutput: Bool
611+ ) -> Self {
612+ var arguments : [ FunctionArgumentDescription ] = [
613+ FunctionArgumentDescription (
614+ label: " request " ,
615+ expression: . identifierPattern( " request " ) . dot ( streamingInput ? " messages " : " message " )
616+ )
617+ ]
618+
619+ if streamingOutput {
620+ arguments. append (
621+ FunctionArgumentDescription (
622+ label: " response " ,
623+ expression: . identifierPattern( " writer " )
624+ )
625+ )
626+ }
627+
628+ arguments. append (
629+ FunctionArgumentDescription (
630+ label: " context " ,
631+ expression: . identifierPattern( " context " )
632+ )
633+ )
634+
635+ return FunctionCallDescription (
636+ calledExpression: . try ( . await ( . identifierPattern( " self " ) . dot ( name) ) ) ,
637+ arguments: arguments
638+ )
639+ }
640+ }
641+
642+ extension FunctionDescription {
643+ /// ```
644+ /// func <Name>(
645+ /// request: GRPCCore.ServerRequest<Input>,
646+ /// context: GRPCCore.ServerContext
647+ /// ) async throws -> GRPCCore.ServerResponse<Output> {
648+ /// return GRPCCore.ServerResponse<Output>(
649+ /// message: try await self.<Name>(
650+ /// request: request.message,
651+ /// context: context
652+ /// )
653+ /// metadata: [:]
654+ /// )
655+ /// }
656+ /// ```
657+ static func serviceProtocolDefaultImplementation(
658+ accessModifier: AccessModifier ? = nil ,
659+ name: String ,
660+ input: String ,
661+ output: String ,
662+ streamingInput: Bool ,
663+ streamingOutput: Bool
664+ ) -> Self {
665+ func makeUnaryOutputArguments( ) -> [ FunctionArgumentDescription ] {
666+ return [
667+ FunctionArgumentDescription (
668+ label: " message " ,
669+ expression: . functionCall(
670+ . serviceMethodCallingSimpleMethod(
671+ name: name,
672+ input: input,
673+ output: output,
674+ streamingInput: streamingInput,
675+ streamingOutput: streamingOutput
676+ )
677+ )
678+ ) ,
679+ FunctionArgumentDescription ( label: " metadata " , expression: . literal( . dictionary( [ ] ) ) ) ,
680+ ]
681+ }
682+
683+ func makeStreamingOutputArguments( ) -> [ FunctionArgumentDescription ] {
684+ return [
685+ FunctionArgumentDescription ( label: " metadata " , expression: . literal( . dictionary( [ ] ) ) ) ,
686+ FunctionArgumentDescription (
687+ label: " producer " ,
688+ expression: . closureInvocation(
689+ argumentNames: [ " writer " ] ,
690+ body: [
691+ . expression(
692+ . functionCall(
693+ . serviceMethodCallingSimpleMethod(
694+ name: name,
695+ input: input,
696+ output: output,
697+ streamingInput: streamingInput,
698+ streamingOutput: streamingOutput
699+ )
700+ )
701+ ) ,
702+ . expression( . return( . literal( . dictionary( [ ] ) ) ) ) ,
703+ ]
704+ )
705+ ) ,
706+ ]
707+ }
708+
709+ return FunctionDescription (
710+ signature: . serverMethod(
711+ accessLevel: accessModifier,
712+ name: name,
713+ input: input,
714+ output: output,
715+ streamingInput: streamingInput,
716+ streamingOutput: streamingOutput
717+ ) ,
718+ body: [
719+ . expression(
720+ . functionCall(
721+ calledExpression: . return(
722+ . identifierType(
723+ . serverResponse( forType: output, streaming: streamingOutput)
724+ )
725+ ) ,
726+ arguments: streamingOutput ? makeStreamingOutputArguments ( ) : makeUnaryOutputArguments ( )
727+ )
728+ )
729+ ]
730+ )
731+ }
732+ }
733+
734+ extension ExtensionDescription {
735+ /// ```
736+ /// extension ServiceProtocol {
737+ /// ...
738+ /// }
739+ /// ```
740+ static func serviceProtocolDefaultImplementation(
741+ accessModifier: AccessModifier ? = nil ,
742+ on extensionName: String ,
743+ methods: [ MethodDescriptor ]
744+ ) -> Self {
745+ ExtensionDescription (
746+ onType: extensionName,
747+ declarations: methods. map { method in
748+ . function(
749+ . serviceProtocolDefaultImplementation(
750+ accessModifier: accessModifier,
751+ name: method. name. generatedLowerCase,
752+ input: method. inputType,
753+ output: method. outputType,
754+ streamingInput: method. isInputStreaming,
755+ streamingOutput: method. isOutputStreaming
756+ )
757+ )
758+ }
759+ )
760+ }
761+ }
0 commit comments