fn create_builder_struct()

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)
                }
            }
        }
    }