in api_generator/src/generator/code_gen/request/request_builder.rs [481:667]
fn create_builder_struct(
builder_name: &str,
endpoint: &ApiEndpoint,
common_params: &BTreeMap<String, Type>,
enum_builder: &EnumBuilder,
accepts_nd_body: bool,
) -> Tokens {
let mut common_fields: Vec<Field> = common_params
.iter()
.map(Self::create_struct_field)
.collect();
let mut common_builder_fns: Vec<ImplItem> =
common_params.iter().map(Self::create_impl_fn).collect();
let supports_body = endpoint.supports_body();
let builder_ident = ident(builder_name);
let (enum_ty, enum_struct, enum_impl) = enum_builder.clone().build();
// collect all the fields for the builder struct. Start with url parameters
let mut fields: Vec<Field> = endpoint
.params
.iter()
.map(Self::create_struct_field)
.collect();
let headers_field_ident = ident("headers");
let request_timeout_ident = ident("request_timeout");
// add a field for HTTP headers
fields.push(syn::Field {
ident: Some(headers_field_ident.clone()),
vis: syn::Visibility::Inherited,
attrs: vec![],
ty: syn::parse_type("HeaderMap").unwrap(),
});
fields.push(syn::Field {
ident: Some(request_timeout_ident.clone()),
vis: syn::Visibility::Inherited,
attrs: vec![],
ty: syn::parse_type("Option<Duration>").unwrap(),
});
if supports_body {
fields.push(syn::Field {
ident: Some(ident("body")),
vis: syn::Visibility::Inherited,
attrs: vec![],
ty: syn::parse_type("Option<B>").unwrap(),
})
}
// Combine common fields with struct fields, sort and deduplicate
fields.append(&mut common_fields);
fields.sort_by(|a, b| a.ident.cmp(&b.ident));
fields.dedup_by(|a, b| a.ident.eq(&b.ident));
let default_fields = {
fields
.iter()
.map(|f| f.ident.as_ref().unwrap())
.collect::<Vec<_>>()
};
// collect all the functions for the builder struct
let mut builder_fns: Vec<ImplItem> =
endpoint.params.iter().map(Self::create_impl_fn).collect();
builder_fns.push(Self::create_header_fn(&headers_field_ident));
builder_fns.push(Self::create_request_timeout_fn(&request_timeout_ident));
// add a body impl if supported
if supports_body {
let body_fn = Self::create_body_fn(
builder_name,
&builder_ident,
&default_fields,
accepts_nd_body,
);
builder_fns.push(body_fn);
}
// Combine common fns with builder fns, sort and deduplicate.
builder_fns.append(&mut common_builder_fns);
builder_fns.sort_by(|a, b| a.ident.cmp(&b.ident));
builder_fns.dedup_by(|a, b| a.ident.eq(&b.ident));
let new_fn =
Self::create_new_fn(builder_name, &builder_ident, enum_builder, &default_fields);
let method_expr = Self::create_method_expression(builder_name, endpoint);
let query_string_params = {
let mut p = endpoint.params.clone();
p.append(&mut common_params.clone());
p
};
let query_string_expr = Self::create_query_string_expression(&query_string_params);
let body_expr = {
if supports_body {
quote!(self.body)
} else {
quote!(Option::<()>::None)
}
};
let (builder_expr, builder_impl) = {
if supports_body {
(
quote!(#builder_ident<'a, 'b, B>),
quote!(impl<'a, 'b, B> #builder_ident<'a, 'b, B> where B: Body),
)
} else {
(
quote!(#builder_ident<'a, 'b>),
quote!(impl<'a, 'b> #builder_ident<'a, 'b>),
)
}
};
let api_name_for_docs = split_on_pascal_case(builder_name);
let builder_doc = match (
endpoint.documentation.description.as_ref(),
endpoint.documentation.url.as_ref(),
) {
(Some(d), Some(u)) if Url::parse(u).is_ok() => lit(format!(
"Builder for the [{} API]({})\n\n{}",
api_name_for_docs, u, d
)),
(Some(d), None) => lit(format!(
"Builder for the {} API\n\n{}",
api_name_for_docs, d
)),
(None, Some(u)) if Url::parse(u).is_ok() => lit(format!(
"Builder for the [{} API]({})",
api_name_for_docs, u
)),
_ => lit(format!("Builder for the {} API", api_name_for_docs)),
};
let send_doc = lit(format!(
"Creates an asynchronous call to the {} API that can be awaited",
api_name_for_docs
));
let cfg_attr = endpoint.stability.outer_cfg_attr();
let cfg_doc = stability_doc(endpoint.stability);
quote! {
#cfg_attr
#enum_struct
#cfg_attr
#enum_impl
#[doc = #builder_doc]
#cfg_doc
#cfg_attr
#[derive(Clone, Debug)]
pub struct #builder_expr {
transport: &'a Transport,
parts: #enum_ty,
#(#fields),*,
}
#cfg_attr
#builder_impl {
#new_fn
#(#builder_fns)*
#[doc = #send_doc]
pub async fn send(self) -> Result<Response, Error> {
let path = self.parts.url();
let method = #method_expr;
let headers = self.headers;
let timeout = self.request_timeout;
let query_string = #query_string_expr;
let body = #body_expr;
let response = self.transport.send(method, &path, headers, query_string.as_ref(), body, timeout).await?;
Ok(response)
}
}
}
}