{{! Copyright (c) Meta Platforms, Inc. and its affiliates. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. }} {{#service:interactions}}{{>lib/client}} {{/service:interactions}} /// Client definitions for `{{service:rust_name}}`. pub struct {{service:rust_name}}Impl { {{#service:extends}} parent: {{service:client_package}}::{{service:rust_name}}Impl, {{/service:extends}} {{^service:extends}} transport: T, _phantom: ::std::marker::PhantomData (P, S)>, {{/service:extends}} } impl {{service:rust_name}}Impl where P: ::fbthrift::Protocol, T: ::fbthrift::Transport, {{! require P::Frame and T to have compatible DecBuf and EncBuf::Final }} P::Frame: ::fbthrift::Framing>, ::fbthrift::ProtocolEncoded

: ::fbthrift::BufMutExt>, P::Deserializer: ::std::marker::Send, S: ::fbthrift::help::Spawner, { pub fn new( transport: T, ) -> Self { {{#service:extends}} let parent = {{service:client_package}}::{{service:rust_name}}Impl::::new(transport); Self { parent } {{/service:extends}} {{^service:extends}} Self { transport, _phantom: ::std::marker::PhantomData, } {{/service:extends}} } pub fn transport(&self) -> &T { {{#service:extends}} self.parent.transport() {{/service:extends}} {{^service:extends}} &self.transport {{/service:extends}} } {{#service:rustFunctions}} {{^function:starts_interaction?}}{{^function:sink?}} fn _{{function:name}}_impl( &self,{{! }}{{#function:args}} arg_{{field:name}}: {{>lib/arg}},{{! }}{{/function:args}} rpc_options: T::RpcOptions, ) -> {{>lib/client_return_type}} { use ::const_cstr::const_cstr; use ::tracing::Instrument as _; use ::futures::FutureExt as _; {{#function:stream?}} use ::futures::StreamExt as _; use ::fbthrift::Deserialize as _; {{/function:stream?}} const_cstr! { SERVICE_NAME = "{{service:parent_service_name}}"; SERVICE_METHOD_NAME = "{{service:parent_service_name}}.{{#service:interaction?}}{{service:name}}.{{/service:interaction?}}{{function:name}}"; {{#function:creates_interaction?}} INTERACTION_NAME = "{{function:interaction_name}}"; {{/function:creates_interaction?}} } let args = self::Args_{{service:rust_name}}_{{function:name}} { {{#function:args}} {{field:rust_name}}: arg_{{field:name}}, {{/function:args}} _phantom: ::std::marker::PhantomData, }; {{#function:creates_interaction?}} let interaction_transport = match self.transport().create_interaction(INTERACTION_NAME.as_cstr()) { ::std::result::Result::Ok(res) => res, ::std::result::Result::Err(err) => return ::futures::future::err(err.into()).boxed(), }; let interaction_impl = {{function:interaction_name}}Impl::::new(interaction_transport); let transport = interaction_impl.transport(); {{/function:creates_interaction?}}{{^function:creates_interaction?}} let transport = self.transport(); {{/function:creates_interaction?}} // need to do call setup outside of async block because T: Transport isn't Send let request_env = match ::fbthrift::help::serialize_request_envelope::("{{#service:interaction?}}{{service:name}}.{{/service:interaction?}}{{function:name}}", &args) { ::std::result::Result::Ok(res) => res, ::std::result::Result::Err(err) => return ::futures::future::err(err.into()).boxed(), }; {{#function:stream?}} let call_stream = transport .call_stream(SERVICE_NAME.as_cstr(), SERVICE_METHOD_NAME.as_cstr(), request_env, rpc_options) .instrument(::tracing::trace_span!("call_stream", method = "{{service:name}}.{{function:name}}")); {{/function:stream?}}{{^function:stream?}} let call = transport .call(SERVICE_NAME.as_cstr(), SERVICE_METHOD_NAME.as_cstr(), request_env, rpc_options) .instrument(::tracing::trace_span!("call", method = "{{service:name}}.{{function:name}}")); {{/function:stream?}} async move { {{#function:stream?}}{{! ****************************** ******* STREAMING BODY ******* ****************************** }} let (initial, stream) = call_stream.await?; let new_stream = stream.then(|item_res| { async move { match item_res { ::std::result::Result::Err(err) => ::std::result::Result::Err({{program:crate}}::errors::{{service:snake}}::{{function:upcamel}}StreamError::from(err)), ::std::result::Result::Ok(item_enc) => { S::spawn(move || { match item_enc { ::fbthrift::ClientStreamElement::Reply(payload) => { let mut de = P::deserializer(payload); <{{program:crate}}::errors::{{service:snake}}::{{function:upcamel}}StreamReader as ::fbthrift::help::DeserializeExn>::read_result(&mut de) } ::fbthrift::ClientStreamElement::ApplicationEx(payload) => { let mut de = P::deserializer(payload); let aexn = ::fbthrift::ApplicationException::read(&mut de)?; ::std::result::Result::Ok(::std::result::Result::Err({{program:crate}}::errors::{{service:snake}}::{{function:upcamel}}StreamError::ApplicationException(aexn))) } } }).await? } } } }) .boxed(); let de = P::deserializer(initial); let res = ::fbthrift::help::async_deserialize_response_envelope::(de) .await?? .map({{! }}{{#function:stream_has_first_response?}}move |initial| (initial, new_stream){{/function:stream_has_first_response?}}{{! }}{{^function:stream_has_first_response?}}move |_| new_stream{{/function:stream_has_first_response?}}{{! }}); {{/function:stream?}}{{^function:stream?}}{{! ****************************** **** SINGLE RESPONSE BODY **** ****************************** }} let reply_env = call.await?; let de = P::deserializer(reply_env); let res = ::fbthrift::help::async_deserialize_response_envelope::(de).await?; let res = match res { ::std::result::Result::Ok(res) => res, ::std::result::Result::Err(aexn) => { ::std::result::Result::Err({{program:crate}}::errors::{{service:snake}}::{{function:upcamel}}Error::ApplicationException(aexn)) } }; {{/function:stream?}} {{#function:return_type}}{{#function:creates_interaction?}}{{! *********************************** **** Add interaction to result **** *********************************** }} let interaction_client: {{program:crate}}::client::{{function:interaction_name}}Client = ::std::sync::Arc::new(interaction_impl); {{#type:void?}} res?; ::std::result::Result::Ok(interaction_client) {{/type:void?}}{{^type:void?}} ::std::result::Result::Ok((interaction_client, res?)) {{/type:void?}}{{! }}{{/function:creates_interaction?}}{{^function:creates_interaction?}} res {{/function:creates_interaction?}}{{/function:return_type}} } .instrument(::tracing::info_span!("stream", method = "{{service:name}}.{{function:name}}")) .boxed() } {{/function:sink?}}{{/function:starts_interaction?}} {{/service:rustFunctions}} } {{#service:extendedServers}} #[allow(deprecated)]{{! `dependencies` modules are deprecated other than for packagePrefix to use }} impl {{! }}{{#extendedService:service}}{{! }}::std::convert::AsRef {{! }}{{/extendedService:service}}{{! }}for {{service:rust_name}}Impl where P: ::fbthrift::Protocol, T: ::fbthrift::Transport, {{! require P::Frame and T to have compatible DecBuf and EncBuf::Final }} P::Frame: ::fbthrift::Framing>, ::fbthrift::ProtocolEncoded

: ::fbthrift::BufMutExt>, P::Deserializer: ::std::marker::Send, S: ::fbthrift::help::Spawner, { fn as_ref(&self) -> &(dyn {{#extendedService:service}}{{! }}{{extendedService:packagePrefix}}::{{service:rust_name}}{{! }}{{/extendedService:service}}{{! }} + 'static) { {{extendedService:asRefImpl}} } } #[allow(deprecated)]{{! `dependencies` modules are deprecated other than for packagePrefix to use }} impl {{! }}{{#extendedService:service}}{{! }}::std::convert::AsRef + 'static> {{! }}{{/extendedService:service}}{{! }}for {{service:rust_name}}Impl where P: ::fbthrift::Protocol, T: ::fbthrift::Transport, {{! require P::Frame and T to have compatible DecBuf and EncBuf::Final }} P::Frame: ::fbthrift::Framing>, ::fbthrift::ProtocolEncoded

: ::fbthrift::BufMutExt>, P::Deserializer: ::std::marker::Send, S: ::fbthrift::help::Spawner, { fn as_ref(&self) -> &(dyn {{#extendedService:service}}{{! }}{{extendedService:packagePrefix}}::{{service:rust_name}}Ext{{! }}{{/extendedService:service}}{{! }} + 'static) { {{extendedService:asRefImpl}} } } {{/service:extendedServers}} {{#service:docs?}} #[doc = {{service:docs}}] {{/service:docs?}} pub trait {{service:rust_name}}: {{! }}{{#service:extends}}{{service:client_package}}::{{service:rust_name}} + {{/service:extends}}{{! }}::std::marker::Send {{>lib/block}}{{! }}{{#service:rustFunctions}} {{#function:docs?}} #[doc = {{function:docs}}] {{/function:docs?}} {{^function:starts_interaction?}}{{^function:sink?}} fn {{function:rust_name}}( &self, {{#function:args}} arg_{{field:name}}: {{>lib/arg}}, {{/function:args}} ) -> {{>lib/client_return_type}}; {{/function:sink?}}{{/function:starts_interaction?}}{{#function:starts_interaction?}} fn {{function:rust_name}}( &self, ) -> ::std::result::Result<{{! }}{{function:interaction_name}}Client, {{! }}::anyhow::Error>; {{/function:starts_interaction?}}{{/service:rustFunctions}} } pub trait {{service:rust_name}}Ext: {{service:rust_name}}{{! }}{{#service:extends}} + {{service:client_package}}::{{service:rust_name}}Ext{{/service:extends}} where T: ::fbthrift::Transport, {{>lib/block}} {{#service:rustFunctions}} {{#function:docs?}} #[doc = {{function:docs}}] {{/function:docs?}} {{^function:starts_interaction?}}{{^function:sink?}} fn {{function:rust_name}}_with_rpc_opts( &self, {{#function:args}} arg_{{field:name}}: {{>lib/arg}}, {{/function:args}} rpc_options: T::RpcOptions, ) -> {{>lib/client_return_type}}; {{/function:sink?}}{{/function:starts_interaction?}} {{/service:rustFunctions}} fn transport(&self) -> &T; } {{#service:rustFunctions}}{{^function:starts_interaction?}}{{^function:sink?}} struct Args_{{service:rust_name}}_{{function:name}}<'a> { {{#function:args}} {{field:rust_name}}: {{>lib/arg_life}}, {{/function:args}} _phantom: ::std::marker::PhantomData<&'a ()>, } impl<'a, P: ::fbthrift::ProtocolWriter> ::fbthrift::Serialize

for self::Args_{{service:rust_name}}_{{function:name}}<'a> { #[inline]{{! No cost because there's only one caller; with luck will mitigate move cost of args. }} #[::tracing::instrument(skip_all, level = "trace", name = "serialize_args", fields(method = "{{service:name}}.{{function:name}}"))] fn write(&self, p: &mut P) { p.write_struct_begin("args");{{! }}{{#function:args}} p.write_field_begin({{! }}"{{field:name}}", {{! }}{{#field:type}}{{>lib/ttype}}{{/field:type}}, {{! }}{{field:key}}i16{{! }}); {{#field:type}}{{! }}{{#type:has_adapter?}}{{! }}::fbthrift::Serialize::write(&{{>lib/adapter/qualified}}::to_thrift_field::(&self.{{field:rust_name}}, {{field:key}}), p){{! }}{{/type:has_adapter?}}{{! }}{{^type:has_adapter?}}{{! }}{{>lib/write}}(&self.{{field:rust_name}}, p){{! }}{{/type:has_adapter?}}{{! }}{{/field:type}}; p.write_field_end();{{! }}{{/function:args}} p.write_field_stop(); p.write_struct_end(); } } {{/function:sink?}}{{/function:starts_interaction?}}{{/service:rustFunctions}} impl {{service:rust_name}} for {{service:rust_name}}Impl where P: ::fbthrift::Protocol, T: ::fbthrift::Transport, {{! require P::Frame and T to have compatible DecBuf and EncBuf::Final }} P::Frame: ::fbthrift::Framing>, ::fbthrift::ProtocolEncoded

: ::fbthrift::BufMutExt>, P::Deserializer: ::std::marker::Send, S: ::fbthrift::help::Spawner, {{>lib/block}} {{#service:rustFunctions}} {{^function:starts_interaction?}}{{^function:sink?}} fn {{function:rust_name}}( &self,{{! }}{{#function:args}} arg_{{field:name}}: {{>lib/arg}},{{! }}{{/function:args}} ) -> {{>lib/client_return_type}} { let rpc_options = T::RpcOptions::default(); self._{{function:name}}_impl( {{#function:args}} arg_{{field:name}}, {{/function:args}} rpc_options, ) } {{/function:sink?}}{{/function:starts_interaction?}}{{#function:starts_interaction?}} fn {{function:name}}( &self, ) -> ::std::result::Result<{{! }}{{function:interaction_name}}Client, {{! }}::anyhow::Error> { use ::const_cstr::const_cstr; const_cstr! { INTERACTION_NAME = "{{function:interaction_name}}"; } Ok( ::std::sync::Arc::new( {{function:interaction_name}}Impl::::new( self.transport().create_interaction(INTERACTION_NAME.as_cstr())? ) ) ) } {{/function:starts_interaction?}}{{/service:rustFunctions}} } impl {{service:rust_name}}Ext for {{service:rust_name}}Impl where P: ::fbthrift::Protocol, T: ::fbthrift::Transport, {{! require P::Frame and T to have compatible DecBuf and EncBuf::Final }} P::Frame: ::fbthrift::Framing>, ::fbthrift::ProtocolEncoded

: ::fbthrift::BufMutExt>, P::Deserializer: ::std::marker::Send, S: ::fbthrift::help::Spawner, {{>lib/block}} {{#service:rustFunctions}} {{^function:starts_interaction?}}{{^function:sink?}} fn {{function:rust_name}}_with_rpc_opts( &self,{{! }}{{#function:args}} arg_{{field:name}}: {{>lib/arg}},{{! }}{{/function:args}} rpc_options: T::RpcOptions, ) -> {{>lib/client_return_type}} { self._{{function:name}}_impl( {{#function:args}} arg_{{field:name}}, {{/function:args}} rpc_options, ) } {{/function:sink?}}{{/function:starts_interaction?}} {{/service:rustFunctions}} fn transport(&self) -> &T { self.transport() } } #[allow(deprecated)]{{! `dependencies` modules are deprecated other than for packagePrefix to use }} impl<'a, S> {{service:rust_name}} for S where S: ::std::convert::AsRef, {{#service:extendedServers}} {{#extendedService:service}} S: {{extendedService:packagePrefix}}::{{service:rust_name}}, {{/extendedService:service}} {{/service:extendedServers}} S: ::std::marker::Send, { {{#service:rustFunctions}} {{^function:starts_interaction?}}{{^function:sink?}} fn {{function:rust_name}}( &self,{{! }}{{#function:args}} arg_{{field:name}}: {{>lib/arg}},{{! }}{{/function:args}} ) -> {{>lib/client_return_type}} { self.as_ref().{{function:rust_name}}( {{#function:args}} arg_{{field:name}}, {{/function:args}} ) } {{/function:sink?}}{{/function:starts_interaction?}}{{#function:starts_interaction?}} fn {{function:rust_name}}( &self, ) -> ::std::result::Result<{{! }}{{function:interaction_name}}Client, {{! }}::anyhow::Error> { self.as_ref().{{function:rust_name}}() } {{/function:starts_interaction?}}{{/service:rustFunctions}} } #[allow(deprecated)]{{! `dependencies` modules are deprecated other than for packagePrefix to use }} impl {{service:rust_name}}Ext for S where S: ::std::convert::AsRef, S: ::std::convert::AsRef + 'static>, {{#service:extendedServers}} {{#extendedService:service}} S: {{extendedService:packagePrefix}}::{{service:rust_name}}, S: {{extendedService:packagePrefix}}::{{service:rust_name}}Ext, {{/extendedService:service}} {{/service:extendedServers}} S: ::std::marker::Send, T: ::fbthrift::Transport, { {{#service:rustFunctions}} {{^function:starts_interaction?}}{{^function:sink?}} fn {{function:rust_name}}_with_rpc_opts( &self,{{! }}{{#function:args}} arg_{{field:name}}: {{>lib/arg}},{{! }}{{/function:args}} rpc_options: T::RpcOptions, ) -> {{>lib/client_return_type}} { >>::as_ref(self).{{function:rust_name}}_with_rpc_opts( {{#function:args}} arg_{{field:name}}, {{/function:args}} rpc_options, ) } {{/function:sink?}}{{/function:starts_interaction?}} {{/service:rustFunctions}} fn transport(&self) -> &T { as {{service:rust_name}}Ext>::transport(>>::as_ref(self)) } } #[derive(Clone)] pub struct make_{{service:rust_name}}; /// To be called by user directly setting up a client. Avoids /// needing ClientFactory trait in scope, avoids unidiomatic /// make_Trait name. /// /// ``` /// # const _: &str = stringify! { /// use bgs::client::BuckGraphService; /// /// let protocol = BinaryProtocol::new(); /// let transport = HttpClient::new(); /// let client = ::new(protocol, transport); /// # }; /// ``` impl dyn {{service:rust_name}} { {{#service:annotations}} {{#annotation:value?}} pub const {{annotation:rust_name}}: &'static ::std::primitive::str = {{annotation:rust_value}}; {{/annotation:value?}} {{/service:annotations}} pub fn new( protocol: P, transport: T, ) -> ::std::sync::Arc where P: ::fbthrift::Protocol, T: ::fbthrift::Transport, P::Deserializer: ::std::marker::Send, { let spawner = ::fbthrift::help::NoopSpawner; Self::with_spawner(protocol, transport, spawner) } pub fn with_spawner( protocol: P, transport: T, spawner: S, ) -> ::std::sync::Arc where P: ::fbthrift::Protocol, T: ::fbthrift::Transport, P::Deserializer: ::std::marker::Send, S: ::fbthrift::help::Spawner, { let _ = protocol; let _ = spawner; ::std::sync::Arc::new({{service:rust_name}}Impl::::new(transport)) } } impl dyn {{service:rust_name}}Ext where T: ::fbthrift::Transport, { pub fn new

( protocol: P, transport: T, ) -> ::std::sync::Arc + ::std::marker::Send + ::std::marker::Sync + 'static> where P: ::fbthrift::Protocol, P::Deserializer: ::std::marker::Send, { let spawner = ::fbthrift::help::NoopSpawner; Self::with_spawner(protocol, transport, spawner) } pub fn with_spawner( protocol: P, transport: T, spawner: S, ) -> ::std::sync::Arc + ::std::marker::Send + ::std::marker::Sync + 'static> where P: ::fbthrift::Protocol, P::Deserializer: ::std::marker::Send, S: ::fbthrift::help::Spawner, { let _ = protocol; let _ = spawner; ::std::sync::Arc::new({{service:rust_name}}Impl::::new(transport)) } } pub type {{service:rust_name}}DynClient = ::Api; pub type {{service:rust_name}}Client = ::std::sync::Arc<{{service:rust_name}}DynClient>; /// The same thing, but to be called from generic contexts where we are /// working with a type parameter `C: ClientFactory` to produce clients. impl ::fbthrift::ClientFactory for make_{{service:rust_name}} { type Api = dyn {{service:rust_name}} + ::std::marker::Send + ::std::marker::Sync + 'static; fn with_spawner(protocol: P, transport: T, spawner: S) -> ::std::sync::Arc where P: ::fbthrift::Protocol, T: ::fbthrift::Transport, P::Deserializer: ::std::marker::Send, S: ::fbthrift::help::Spawner, { ::with_spawner(protocol, transport, spawner) } } {{!newline}}