def _generate_code_for_client(service: ProtoService, root: ProtoNode, output: OutputFile) -> None: """Outputs client code for an RPC service.""" output.write_line('namespace nanopb {') class_name = f'{service.cpp_namespace(root)}Client' output.write_line(f'\nclass {class_name} {{') output.write_line(' public:') with output.indent(): output.write_line('template <typename T>') output.write_line( f'using NanopbClientCall = {RPC_NAMESPACE}::NanopbClientCall<T>;') output.write_line('') output.write_line(f'{class_name}() = delete;') for method in service.methods(): _generate_code_for_client_method(method, output) service_name_hash = pw_rpc.ids.calculate(service.proto_path()) output.write_line('\n private:') with output.indent(): output.write_line(f'// Hash of "{service.proto_path()}".') output.write_line( f'static constexpr uint32_t kServiceId = 0x{service_name_hash:08x};' ) output.write_line('};') output.write_line('\n} // namespace nanopb\n')
def _generate_service_stub(service: ProtoService, output: OutputFile, unary_stub: StubFunction, server_streaming_stub: StubFunction) -> None: output.write_line() output.write_line( f'class {service.name()} ' f': public generated::{service.name()}<{service.name()}> {{') output.write_line(' public:') with output.indent(): blank_line = False for method in service.methods(): if blank_line: output.write_line() else: blank_line = True if method.type() is ProtoServiceMethod.Type.UNARY: unary_stub(method, output) elif method.type() is ProtoServiceMethod.Type.SERVER_STREAMING: server_streaming_stub(method, output) else: raise NotImplementedError( 'Client and bidirectional streaming not yet implemented') output.write_line('};\n')
def _method_lookup_table(service: ProtoService, output: OutputFile) -> None: """Generates array of method IDs for looking up methods at compile time.""" output.write_line('static constexpr std::array<uint32_t, ' f'{len(service.methods())}> kMethodIds = {{') with output.indent(4): for method in service.methods(): method_id = pw_rpc.ids.calculate(method.name()) output.write_line( f'0x{method_id:08x}, // Hash of "{method.name()}"') output.write_line('};\n')
def _generate_service_stubs(service: ProtoService, output: OutputFile, stub_generator: StubGenerator) -> None: output.write_line(f'// Method definitions for {service.proto_path()}.') blank_line = False for method in service.methods(): if blank_line: output.write_line() else: blank_line = True signature, stub = _select_stub_methods(stub_generator, method) output.write_line(signature(method, f'{service.name()}::') + ' {') with output.indent(): stub(method, output) output.write_line('}')
def _generate_service_class(service: ProtoService, output: OutputFile, stub_generator: StubGenerator) -> None: output.write_line(f'// Implementation class for {service.proto_path()}.') output.write_line( f'class {service.name()} ' f': public generated::{service.name()}<{service.name()}> {{') output.write_line(' public:') with output.indent(): blank_line = False for method in service.methods(): if blank_line: output.write_line() else: blank_line = True signature, _ = _select_stub_methods(stub_generator, method) output.write_line(signature(method, '') + ';') output.write_line('};\n')
def service_class(service: ProtoService, root: ProtoNode, output: OutputFile, server_writer_alias: ServerWriterGenerator, method_union: str, method_descriptor: MethodGenerator) -> None: """Generates a C++ derived class for a nanopb RPC service.""" output.write_line('namespace generated {') base_class = f'{RPC_NAMESPACE}::Service' output.write_line('\ntemplate <typename Implementation>') output.write_line( f'class {service.cpp_namespace(root)} : public {base_class} {{') output.write_line(' public:') with output.indent(): output.write_line( f'using ServerContext = {RPC_NAMESPACE}::ServerContext;') server_writer_alias(output) output.write_line() output.write_line(f'constexpr {service.name()}()') output.write_line(f' : {base_class}(kServiceId, kMethods) {{}}') output.write_line() output.write_line( f'{service.name()}(const {service.name()}&) = delete;') output.write_line(f'{service.name()}& operator=' f'(const {service.name()}&) = delete;') output.write_line() output.write_line(f'static constexpr const char* name() ' f'{{ return "{service.name()}"; }}') output.write_line() output.write_line( '// Used by MethodLookup to identify the generated service base.') output.write_line( 'constexpr void _PwRpcInternalGeneratedBase() const {}') service_name_hash = pw_rpc.ids.calculate(service.proto_path()) output.write_line('\n private:') with output.indent(): output.write_line('friend class ::pw::rpc::internal::MethodLookup;\n') output.write_line(f'// Hash of "{service.proto_path()}".') output.write_line( f'static constexpr uint32_t kServiceId = 0x{service_name_hash:08x};' ) output.write_line() # Generate the method table output.write_line('static constexpr std::array<' f'{RPC_NAMESPACE}::internal::{method_union},' f' {len(service.methods())}> kMethods = {{') with output.indent(4): for method in service.methods(): method_descriptor(method, pw_rpc.ids.calculate(method.name()), output) output.write_line('};\n') # Generate the method lookup table _method_lookup_table(service, output) output.write_line('};') output.write_line('\n} // namespace generated\n')