@azure-tools/typespec-rust 0.28.0 → 0.30.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/dist/src/codegen/clients.d.ts.map +1 -1
  2. package/dist/src/codegen/clients.js +235 -112
  3. package/dist/src/codegen/clients.js.map +1 -1
  4. package/dist/src/codegen/codeGenerator.d.ts.map +1 -1
  5. package/dist/src/codegen/codeGenerator.js +3 -1
  6. package/dist/src/codegen/codeGenerator.js.map +1 -1
  7. package/dist/src/codegen/context.d.ts +1 -1
  8. package/dist/src/codegen/context.d.ts.map +1 -1
  9. package/dist/src/codegen/context.js +1 -1
  10. package/dist/src/codegen/context.js.map +1 -1
  11. package/dist/src/codegen/enums.js +0 -1
  12. package/dist/src/codegen/enums.js.map +1 -1
  13. package/dist/src/codegen/helpers.d.ts +4 -0
  14. package/dist/src/codegen/helpers.d.ts.map +1 -1
  15. package/dist/src/codegen/helpers.js +23 -2
  16. package/dist/src/codegen/helpers.js.map +1 -1
  17. package/dist/src/codegen/mod.d.ts.map +1 -1
  18. package/dist/src/codegen/mod.js +4 -1
  19. package/dist/src/codegen/mod.js.map +1 -1
  20. package/dist/src/codegen/models.js +23 -12
  21. package/dist/src/codegen/models.js.map +1 -1
  22. package/dist/src/codegen/unions.d.ts +8 -1
  23. package/dist/src/codegen/unions.d.ts.map +1 -1
  24. package/dist/src/codegen/unions.js +42 -13
  25. package/dist/src/codegen/unions.js.map +1 -1
  26. package/dist/src/codegen/use.d.ts.map +1 -1
  27. package/dist/src/codegen/use.js +2 -1
  28. package/dist/src/codegen/use.js.map +1 -1
  29. package/dist/src/codemodel/client.d.ts +5 -0
  30. package/dist/src/codemodel/client.d.ts.map +1 -1
  31. package/dist/src/codemodel/client.js +1 -0
  32. package/dist/src/codemodel/client.js.map +1 -1
  33. package/dist/src/codemodel/crate.d.ts +1 -1
  34. package/dist/src/codemodel/crate.d.ts.map +1 -1
  35. package/dist/src/codemodel/crate.js +1 -1
  36. package/dist/src/codemodel/crate.js.map +1 -1
  37. package/dist/src/codemodel/types.d.ts +24 -28
  38. package/dist/src/codemodel/types.d.ts.map +1 -1
  39. package/dist/src/codemodel/types.js +11 -13
  40. package/dist/src/codemodel/types.js.map +1 -1
  41. package/dist/src/emitter.d.ts.map +1 -1
  42. package/dist/src/emitter.js +18 -15
  43. package/dist/src/emitter.js.map +1 -1
  44. package/dist/src/lib.d.ts +2 -0
  45. package/dist/src/lib.d.ts.map +1 -1
  46. package/dist/src/lib.js +6 -0
  47. package/dist/src/lib.js.map +1 -1
  48. package/dist/src/tcgcadapter/adapter.d.ts +5 -13
  49. package/dist/src/tcgcadapter/adapter.d.ts.map +1 -1
  50. package/dist/src/tcgcadapter/adapter.js +89 -90
  51. package/dist/src/tcgcadapter/adapter.js.map +1 -1
  52. package/dist/src/tcgcadapter/naming.d.ts +2 -1
  53. package/dist/src/tcgcadapter/naming.d.ts.map +1 -1
  54. package/dist/src/tcgcadapter/naming.js +3 -2
  55. package/dist/src/tcgcadapter/naming.js.map +1 -1
  56. package/package.json +27 -27
@@ -10,6 +10,7 @@ import { CodegenError } from './errors.js';
10
10
  import * as helpers from './helpers.js';
11
11
  import queryString from 'query-string';
12
12
  import { Use } from './use.js';
13
+ import * as rust from '../codemodel/index.js';
13
14
  import * as shared from '../shared/shared.js';
14
15
  /**
15
16
  * emits the content for all client files
@@ -43,7 +44,7 @@ export function emitClients(crate) {
43
44
  body += `${indent.get()}${helpers.emitVisibility(field.visibility)}${field.name}: ${helpers.getTypeDeclaration(field.type)},\n`;
44
45
  }
45
46
  body += '}\n\n'; // end client
46
- if (client.constructable) {
47
+ if (client.constructable && !client.constructable.suppressed) {
47
48
  // if client options doesn't require an impl for Default then just derive it
48
49
  let deriveDefault = 'Default, ';
49
50
  if (clientOptionsImplDefault(client.constructable)) {
@@ -67,7 +68,7 @@ export function emitClients(crate) {
67
68
  }
68
69
  }
69
70
  body += `impl ${client.name} {\n`;
70
- if (client.constructable) {
71
+ if (client.constructable && !client.constructable.suppressed) {
71
72
  // this is an instantiable client, so we need to emit client options and constructors
72
73
  use.add('azure_core', 'Result');
73
74
  for (let i = 0; i < client.constructable.constructors.length; ++i) {
@@ -90,11 +91,17 @@ export function emitClients(crate) {
90
91
  // construct the supplemental path and join it to the endpoint
91
92
  if (client.constructable.endpoint) {
92
93
  const supplementalEndpoint = client.constructable.endpoint;
93
- body += `${indent.get()}let mut host = String::from("${supplementalEndpoint.path}");\n`;
94
- for (const param of supplementalEndpoint.parameters) {
95
- body += `${indent.get()}host = host.replace("{${param.segment}}", ${getClientSupplementalEndpointParamValue(param)});\n`;
94
+ if (supplementalEndpoint.parameters.length > 0) {
95
+ body += `${indent.get()}let mut host = String::from("${supplementalEndpoint.path}");\n`;
96
+ for (const param of supplementalEndpoint.parameters) {
97
+ body += `${indent.get()}host = host.replace("{${param.segment}}", ${getClientSupplementalEndpointParamValue(param)});\n`;
98
+ }
99
+ body += `${indent.push().get()}${endpointParamName} = ${endpointParamName}.join(&host)?;\n`;
100
+ }
101
+ else {
102
+ // there are no params for the supplemental host, so just append it
103
+ body += `${indent.push().get()}${endpointParamName} = ${endpointParamName}.join("${supplementalEndpoint.path}")?;\n`;
96
104
  }
97
- body += `${indent.push().get()}${endpointParamName} = ${endpointParamName}.join(&host)?;\n`;
98
105
  }
99
106
  // if there's a credential param, create the necessary auth policy
100
107
  const authPolicy = getAuthPolicy(constructor, use);
@@ -182,7 +189,7 @@ export function emitClients(crate) {
182
189
  case 'lro':
183
190
  isPublicApi = true;
184
191
  methodBody = (indentation) => {
185
- return getLroMethodBody(indentation, use, client, method);
192
+ return getLroMethodBody(crate, indentation, use, client, method);
186
193
  };
187
194
  break;
188
195
  case 'clientaccessor':
@@ -299,9 +306,7 @@ function getMethodOptions(crate) {
299
306
  if (field.type.kind === 'external' && (field.type.name === 'ClientMethodOptions' || field.type.name === 'PagerOptions' || field.type.name === 'PollerOptions')) {
300
307
  body += `${indent.get()}${field.name}: ${field.type.name} {\n`;
301
308
  body += `${indent.push().get()}context: self.${field.name}.context.into_owned(),\n`;
302
- if (field.type.name === 'PollerOptions') {
303
- body += `${indent.get()}frequency: self.${field.name}.frequency,\n`;
304
- }
309
+ body += `${indent.get()}..self.${field.name}\n`;
305
310
  body += `${indent.pop().get()}},\n`;
306
311
  continue;
307
312
  }
@@ -653,14 +658,15 @@ function getMethodParamGroup(method) {
653
658
  * @param indent the indentation helper currently in scope
654
659
  * @param param the parameter to which the contents of setter apply
655
660
  * @param setter the callback that emits the code to read from a param var
656
- * @param inClosure indicates if the value is being read from within a closure (e.g. pageable methods)
661
+ * @param optionsPrefix Syntax to access the options structure, including the dot
657
662
  * @returns
658
663
  */
659
- function getParamValueHelper(indent, param, inClosure, setter) {
664
+ function getParamValueHelper(indent, param, setter, optionsPrefix = 'options.') {
660
665
  if (param.optional && param.type.kind !== 'literal') {
666
+ const asRef = nonCopyableType(param.type) || isEnumString(param.type) ? '.as_ref()' : '';
661
667
  // optional params are in the unwrapped options local var
662
668
  const op = indent.get() + helpers.buildIfBlock(indent, {
663
- condition: `let Some(${param.name}) = ${inClosure && nonCopyableType(param.type) ? '&' : ''}options.${param.name}`,
669
+ condition: `let Some(${param.name}) = ${param.location === 'client' ? 'self.' : optionsPrefix}${param.name}${asRef}`,
664
670
  body: setter,
665
671
  });
666
672
  return op + '\n';
@@ -773,7 +779,7 @@ function constructUrl(indent, use, method, paramGroups, urlVarName) {
773
779
  }
774
780
  }
775
781
  if (pathParam.optional) {
776
- body += `${indent.get()}${pathVarName} = ${helpers.buildMatch(indent, `options.${pathParam.name}`, [{
782
+ body += `${indent.get()}${pathVarName} = ${helpers.buildMatch(indent, `options.${pathParam.name}${nonCopyableType(pathParam.type) ? '.as_ref()' : ''}`, [{
777
783
  pattern: `Some(${pathParam.name})`,
778
784
  body: (indent) => wrapSortedVec(`${indent.get()}${pathVarName}.replace("{${pathParam.segment}}", ${paramExpression})\n`),
779
785
  }, {
@@ -789,8 +795,15 @@ function constructUrl(indent, use, method, paramGroups, urlVarName) {
789
795
  body += `${indent.get()}${urlVarName}.append_path(${path});\n`;
790
796
  }
791
797
  }
798
+ let hasQueryBuilder = false;
799
+ const getQueryBuilder = function () {
800
+ hasQueryBuilder = true;
801
+ use.add('azure_core::http', 'UrlExt');
802
+ return `${indent.get()}let mut query_builder = ${urlVarName}.query_builder();\n`;
803
+ };
792
804
  if (pathChunks.length === 2) {
793
- body += `${indent.get()}${urlVarName}.query_pairs_mut()`;
805
+ body += getQueryBuilder();
806
+ body += `${indent.get()}query_builder`;
794
807
  // set the query params that were in the path
795
808
  const qps = queryString.parse(pathChunks[1]);
796
809
  for (const qp of Object.keys(qps)) {
@@ -811,39 +824,47 @@ function constructUrl(indent, use, method, paramGroups, urlVarName) {
811
824
  }
812
825
  body += ';\n';
813
826
  }
827
+ if (paramGroups.query.length > 0 && !hasQueryBuilder) {
828
+ body += getQueryBuilder();
829
+ }
814
830
  for (const queryParam of paramGroups.query) {
815
831
  if (queryParam.kind === 'queryCollection' && queryParam.format === 'multi') {
816
- body += getParamValueHelper(indent, queryParam, false, () => {
832
+ body += getParamValueHelper(indent, queryParam, () => {
817
833
  const valueVar = queryParam.name[0];
818
834
  let text = `${indent.get()}for ${valueVar} in ${queryParam.name}.iter() {\n`;
819
- text += `${indent.push().get()}${urlVarName}.query_pairs_mut().append_pair("${queryParam.key}", ${valueVar});\n`;
835
+ // if queryParam is a &[&str] then we'll need to deref the iterator
836
+ const deref = shared.asTypeOf(queryParam.type, 'str', 'ref', 'slice', 'ref') ? '*' : '';
837
+ text += `${indent.push().get()}query_builder.append_pair("${queryParam.key}", ${deref}${getHeaderPathQueryParamValue(use, queryParam, !queryParam.optional, false, valueVar)});\n`;
820
838
  text += `${indent.pop().get()}}\n`;
821
839
  return text;
822
840
  });
823
841
  }
824
842
  else if (queryParam.kind === 'queryHashMap') {
825
- body += getParamValueHelper(indent, queryParam, false, () => {
843
+ body += getParamValueHelper(indent, queryParam, () => {
826
844
  let text = `${indent.get()}{\n`;
827
845
  text += `${indent.push().get()}let mut ${queryParam.name}_vec = ${queryParam.name}.iter().collect::<Vec<_>>();\n`;
828
846
  text += `${indent.get()}${queryParam.name}_vec.sort_by_key(|p| p.0);\n`;
829
847
  if (queryParam.explode) {
830
848
  text += `${indent.get()}for (k, v) in ${queryParam.name}_vec.iter() {\n`;
831
- text += `${indent.push().get()}${urlVarName}.query_pairs_mut().append_pair(k, &v.to_string());\n`;
849
+ text += `${indent.push().get()}query_builder.append_pair(*k, v.to_string());\n`;
832
850
  text += `${indent.pop().get()}}\n`;
833
851
  }
834
852
  else {
835
- text += `${indent.get()}${urlVarName}.query_pairs_mut().append_pair("${queryParam.key}", ${queryParam.name}_vec.iter().map(|(k, v)| format!("{k},{v}")).collect::<Vec<String>>().join(",").as_str());\n`;
853
+ text += `${indent.get()}query_builder.set_pair("${queryParam.key}", ${queryParam.name}_vec.iter().map(|(k, v)| format!("{k},{v}")).collect::<Vec<String>>().join(","));\n`;
836
854
  }
837
855
  text += `${indent.pop().get()}}\n`;
838
856
  return text;
839
857
  });
840
858
  }
841
859
  else {
842
- body += getParamValueHelper(indent, queryParam, false, () => {
843
- return `${indent.get()}${urlVarName}.query_pairs_mut().append_pair("${queryParam.key}", ${getHeaderPathQueryParamValue(use, queryParam, !queryParam.optional, false)});\n`;
860
+ body += getParamValueHelper(indent, queryParam, () => {
861
+ return `${indent.get()}query_builder.set_pair("${queryParam.key}", ${getHeaderPathQueryParamValue(use, queryParam, !queryParam.optional, false)});\n`;
844
862
  });
845
863
  }
846
864
  }
865
+ if (hasQueryBuilder) {
866
+ body += `${indent.get()}query_builder.build();\n`;
867
+ }
847
868
  return body;
848
869
  }
849
870
  /**
@@ -854,9 +875,11 @@ function constructUrl(indent, use, method, paramGroups, urlVarName) {
854
875
  * @param method the method for which we're building the body
855
876
  * @param paramGroups the param groups for the provided method
856
877
  * @param inClosure indicates if the request is being constructed within a closure (e.g. pageable methods)
878
+ * @param requestVarName name for the request variable
879
+ * @param optionsPrefix Syntax to access the options structure, including the dot
857
880
  * @returns the code which sets HTTP headers for the request
858
881
  */
859
- function applyHeaderParams(indent, use, method, paramGroups, inClosure, requestVarName) {
882
+ function applyHeaderParams(indent, use, method, paramGroups, inClosure, requestVarName, optionsPrefix = 'options.') {
860
883
  var _a, _b, _c;
861
884
  let body = '';
862
885
  for (const headerParam of paramGroups.header) {
@@ -871,7 +894,7 @@ function applyHeaderParams(indent, use, method, paramGroups, inClosure, requestV
871
894
  },
872
895
  {
873
896
  pattern: 'PagerState::Initial',
874
- body: (indent) => `${indent.get()}&options.${headerParam.name}\n`,
897
+ body: (indent) => `${indent.get()}&${optionsPrefix}${headerParam.name}\n`,
875
898
  }
876
899
  ]) + ';\n';
877
900
  body += indent.get() + helpers.buildIfBlock(indent, {
@@ -886,15 +909,15 @@ function applyHeaderParams(indent, use, method, paramGroups, inClosure, requestV
886
909
  // this logic happens elsewhere so we skip it here.
887
910
  continue;
888
911
  }
889
- body += getParamValueHelper(indent, headerParam, inClosure, () => {
912
+ body += getParamValueHelper(indent, headerParam, () => {
890
913
  if (headerParam.kind === 'headerHashMap') {
891
- let setter = `for (k, v) in ${headerParam.type.kind === 'ref' ? '' : '&'}${headerParam.name} {\n`;
914
+ let setter = `for (k, v) in ${headerParam.name} {\n`;
892
915
  setter += `${indent.push().get()}${requestVarName}.insert_header(format!("${headerParam.header}-{k}"), v);\n`;
893
916
  setter += `${indent.pop().get()}}\n`;
894
917
  return setter;
895
918
  }
896
919
  return `${indent.get()}${requestVarName}.insert_header("${headerParam.header.toLowerCase()}", ${getHeaderPathQueryParamValue(use, headerParam, !inClosure, false)});\n`;
897
- });
920
+ }, optionsPrefix);
898
921
  }
899
922
  return body;
900
923
  }
@@ -932,7 +955,7 @@ function constructRequest(indent, use, method, paramGroups, inClosure, urlVarNam
932
955
  }
933
956
  const bodyParam = paramGroups.body;
934
957
  if (bodyParam) {
935
- body += getParamValueHelper(indent, bodyParam, inClosure, () => {
958
+ body += getParamValueHelper(indent, bodyParam, () => {
936
959
  let bodyParamContent = '';
937
960
  if (optionalContentTypeParam) {
938
961
  bodyParamContent = `${indent.get()}${requestVarName}.insert_header("${optionalContentTypeParam.header.toLowerCase()}", ${getHeaderPathQueryParamValue(use, optionalContentTypeParam, !inClosure, false)});\n`;
@@ -1035,7 +1058,7 @@ function emitEmptyPathParamCheck(indent, param) {
1035
1058
  }
1036
1059
  return helpers.buildIfBlock(indent, {
1037
1060
  condition: `${param.name}${toString}.is_empty()`,
1038
- body: (indent) => `${indent.get()}return Err(azure_core::Error::with_message(azure_core::error::ErrorKind::Other, "parameter ${param.name} cannot be empty"));`,
1061
+ body: (indent) => `${indent.get()}return Err(azure_core::Error::with_message(azure_core::error::ErrorKind::Other, "parameter ${param.name} cannot be empty"));\n`,
1039
1062
  });
1040
1063
  }
1041
1064
  /**
@@ -1107,27 +1130,20 @@ function getPageableMethodBody(indent, use, client, method) {
1107
1130
  switch (method.strategy.kind) {
1108
1131
  case 'continuationToken': {
1109
1132
  const reqTokenParam = method.strategy.requestToken.name;
1110
- body += `${indent.get()}Ok(${method.returns.type.name}::from_callback(move |${reqTokenParam}: PagerState<String>, ctx| {\n`;
1133
+ body += `${indent.get()}Ok(${method.returns.type.name}::from_callback(move |${reqTokenParam}: PagerState<String>, pager_options| {\n`;
1111
1134
  body += `${indent.push().get()}let ${method.strategy.requestToken.kind === 'queryScalar' ? 'mut ' : ''}url = first_url.clone();\n`;
1112
1135
  if (method.strategy.requestToken.kind === 'queryScalar') {
1113
1136
  // if the url already contains the token query param,
1114
1137
  // e.g. we started on some page, then we need to remove
1115
1138
  // it before appending the token for the next page.
1139
+ use.add('azure_core::http', 'UrlExt');
1116
1140
  const reqTokenValue = method.strategy.requestToken.key;
1117
1141
  body += `${indent.get()}${helpers.buildIfBlock(indent, {
1118
1142
  condition: `let PagerState::More(${reqTokenParam}) = ${reqTokenParam}`,
1119
1143
  body: (indent) => {
1120
- let body = indent.get() + helpers.buildIfBlock(indent, {
1121
- condition: `url.query_pairs().any(|(name, _)| name.eq("${reqTokenValue}"))`,
1122
- body: (indent) => {
1123
- let body = `${indent.get()}let mut new_url = url.clone();\n`;
1124
- body += `${indent.get()}new_url.query_pairs_mut().clear().extend_pairs(url.query_pairs().filter(|(name, _)| name.ne("${reqTokenValue}")));\n`;
1125
- body += `${indent.get()}url = new_url;\n`;
1126
- return body;
1127
- },
1128
- }) + '\n';
1129
- body += `${indent.get()}url.query_pairs_mut().append_pair("${reqTokenValue}", &${reqTokenParam});\n`;
1130
- return body;
1144
+ return `${indent.get()}let mut query_builder = url.query_builder();\n`
1145
+ + `${indent.get()}query_builder.set_pair("${reqTokenValue}", &${reqTokenParam});\n`
1146
+ + `${indent.get()}query_builder.build();\n`;
1131
1147
  }
1132
1148
  })}\n`;
1133
1149
  }
@@ -1137,32 +1153,38 @@ function getPageableMethodBody(indent, use, client, method) {
1137
1153
  case 'nextLink': {
1138
1154
  const nextLinkName = method.strategy.nextLinkPath[method.strategy.nextLinkPath.length - 1].name;
1139
1155
  const reinjectedParams = method.strategy.reinjectedParams;
1140
- body += `${indent.get()}Ok(${method.returns.type.name}::from_callback(move |${nextLinkName}: PagerState<Url>, ctx| {\n`;
1156
+ body += `${indent.get()}Ok(${method.returns.type.name}::from_callback(move |${nextLinkName}: PagerState<Url>, pager_options| {\n`;
1141
1157
  body += `${indent.push().get()}let url = ` + helpers.buildMatch(indent, nextLinkName, [{
1142
1158
  pattern: `PagerState::More(${nextLinkName})`,
1143
1159
  body: (indent) => {
1144
1160
  const cloneNextLink = `${indent.get()}let mut ${nextLinkName} = ${nextLinkName}.clone();\n`;
1145
1161
  let content = '';
1162
+ let hasQueryBuilder = false;
1146
1163
  if (paramGroups.apiVersion && paramGroups.apiVersion.kind === 'queryScalar') {
1147
- const apiVersionKey = `"${paramGroups.apiVersion.key}"`;
1148
- // there are no APIs to set/update an existing query parameter.
1149
- // so, we filter the existing query params to remove the api-version
1150
- // query param. we then add back the filtered set and then add the
1151
- // api-version as specified on the client.
1152
- content = `${indent.get()}let qp = ${nextLinkName}.query_pairs().filter(|(name, _)| name.ne(${apiVersionKey}));\n`;
1153
1164
  content += cloneNextLink;
1154
- content += `${indent.get()}${nextLinkName}.query_pairs_mut().clear().extend_pairs(qp).append_pair(${apiVersionKey}, &${paramGroups.apiVersion.name});\n`;
1165
+ hasQueryBuilder = true;
1166
+ use.add('azure_core::http', 'UrlExt');
1167
+ content += `${indent.get()}let mut query_builder = ${nextLinkName}.query_builder();\n`;
1168
+ content += `${indent.get()}query_builder.set_pair("${paramGroups.apiVersion.key}", &${paramGroups.apiVersion.name});\n`;
1155
1169
  }
1156
1170
  else if (reinjectedParams.length > 0) {
1157
1171
  // if we didn't clone it above, we'll need to clone it for this case
1158
1172
  content += cloneNextLink;
1159
1173
  }
1160
1174
  // add query params for reinjection
1175
+ if (reinjectedParams.length > 0 && !hasQueryBuilder) {
1176
+ hasQueryBuilder = true;
1177
+ use.add('azure_core::http', 'UrlExt');
1178
+ content += `${indent.get()}let mut query_builder = ${nextLinkName}.query_builder();\n`;
1179
+ }
1161
1180
  for (const reinjectedParam of reinjectedParams) {
1162
- content += getParamValueHelper(indent, reinjectedParam, true, () => {
1163
- return `${indent.get()}${nextLinkName}.query_pairs_mut().append_pair("${reinjectedParam.key}", ${getHeaderPathQueryParamValue(use, reinjectedParam, false, false)});\n`;
1181
+ content += getParamValueHelper(indent, reinjectedParam, () => {
1182
+ return `${indent.get()}query_builder.set_pair("${reinjectedParam.key}", ${getHeaderPathQueryParamValue(use, reinjectedParam, false, false)});\n`;
1164
1183
  });
1165
1184
  }
1185
+ if (hasQueryBuilder) {
1186
+ content += `${indent.get()}query_builder.build();\n`;
1187
+ }
1166
1188
  content += `${indent.get()}${nextLinkName}\n`;
1167
1189
  return content;
1168
1190
  }
@@ -1178,7 +1200,7 @@ function getPageableMethodBody(indent, use, client, method) {
1178
1200
  }
1179
1201
  else {
1180
1202
  // no next link when there's no strategy
1181
- body += `${indent.get()}Ok(Pager::from_callback(move |_: PagerState<Url>, ctx| {\n`;
1203
+ body += `${indent.get()}Ok(Pager::from_callback(move |_: PagerState<Url>, pager_options| {\n`;
1182
1204
  indent.push();
1183
1205
  cloneUrl = true;
1184
1206
  srcUrlVar = urlVar;
@@ -1198,7 +1220,7 @@ function getPageableMethodBody(indent, use, client, method) {
1198
1220
  body += requestResult.content;
1199
1221
  body += `${indent.get()}let pipeline = pipeline.clone();\n`;
1200
1222
  body += `${indent.get()}async move {\n`;
1201
- body += `${indent.push().get()}let rsp${rspType} = pipeline.send(&ctx, &mut ${requestResult.requestVarName}, ${getPipelineOptions(indent, use, method)}).await?${rspInto};\n`;
1223
+ body += `${indent.push().get()}let rsp${rspType} = pipeline.send(&pager_options.context, &mut ${requestResult.requestVarName}, ${getPipelineOptions(indent, use, method)}).await?${rspInto};\n`;
1202
1224
  // check if we need to extract the next link field from the response model
1203
1225
  if (method.strategy && (method.strategy.kind === 'nextLink' || method.strategy.responseToken.kind === 'nextLink')) {
1204
1226
  const bodyFormat = helpers.convertResponseFormat(method.returns.type.type.format);
@@ -1280,18 +1302,22 @@ function getPageableMethodBody(indent, use, client, method) {
1280
1302
  /**
1281
1303
  * constructs the body for an LRO client method
1282
1304
  *
1305
+ * @param crate the crate to which method belongs
1283
1306
  * @param indent the indentation helper currently in scope
1284
1307
  * @param use the use statement builder currently in scope
1285
1308
  * @param client the client to which the method belongs
1286
1309
  * @param method the method for the body to build
1287
1310
  * @returns the contents of the method body
1288
1311
  */
1289
- function getLroMethodBody(indent, use, client, method) {
1290
- var _a, _b;
1291
- const pollingStepHeaderName = ((_a = method.responseHeaders) === null || _a === void 0 ? void 0 : _a.headers.some(h => h.header.toLowerCase() === 'operation-location'))
1292
- ? 'operation-location'
1293
- : ((_b = method.responseHeaders) === null || _b === void 0 ? void 0 : _b.headers.some(h => h.header.toLowerCase() === 'azure-asyncoperation'))
1294
- ? 'azure-asyncoperation' : undefined;
1312
+ function getLroMethodBody(crate, indent, use, client, method) {
1313
+ var _a;
1314
+ let pollingStepHeaderName = undefined;
1315
+ for (const header of ['operation-location', 'azure-asyncoperation', 'location']) {
1316
+ if ((_a = method.responseHeaders) === null || _a === void 0 ? void 0 : _a.headers.some(h => h.header.toLowerCase() === header)) {
1317
+ pollingStepHeaderName = header;
1318
+ break;
1319
+ }
1320
+ }
1295
1321
  const bodyFormat = helpers.convertResponseFormat(method.returns.type.type.format);
1296
1322
  use.add('azure_core::http', 'Method', 'RawResponse', 'Request', 'Url');
1297
1323
  use.add('azure_core::http::headers', 'RETRY_AFTER', 'X_MS_RETRY_AFTER_MS', 'RETRY_AFTER_MS');
@@ -1305,7 +1331,6 @@ function getLroMethodBody(indent, use, client, method) {
1305
1331
  const urlVar = helpers.getUniqueVarName(method.params, ['url', 'url_var']);
1306
1332
  let body = 'let options = options.unwrap_or_default().into_owned();\n';
1307
1333
  body += `${indent.get()}let pipeline = self.pipeline.clone();\n`;
1308
- body += `${indent.get()}let method_options = options.method_options.to_owned();\n`;
1309
1334
  body += `${indent.get()}let ${urlVarNeedsMut(paramGroups, method)}${urlVar} = self.${getEndpointFieldName(client)}.clone();\n`;
1310
1335
  body += constructUrl(indent, use, method, paramGroups, urlVar);
1311
1336
  if (paramGroups.apiVersion) {
@@ -1316,39 +1341,46 @@ function getLroMethodBody(indent, use, client, method) {
1316
1341
  const applyApiVersionParam = function (indent, paramGroups, newLinkVarName, existingLinkVarAccessor) {
1317
1342
  var _a;
1318
1343
  if (((_a = paramGroups.apiVersion) === null || _a === void 0 ? void 0 : _a.kind) === 'queryScalar') {
1319
- return `${indent.get()}let qp = ${existingLinkVarAccessor}.query_pairs().filter(|(name, _)| name.ne("${paramGroups.apiVersion.key}"));\n`
1320
- + `${indent.get()}let mut ${newLinkVarName} = ${existingLinkVarAccessor}.clone();\n`
1321
- + `${indent.get()}${newLinkVarName}.query_pairs_mut().clear().extend_pairs(qp).append_pair("${paramGroups.apiVersion.key}", &${paramGroups.apiVersion.name});\n`;
1344
+ use.add('azure_core::http', 'UrlExt');
1345
+ return `${indent.get()}let mut ${newLinkVarName} = ${existingLinkVarAccessor}.clone();\n`
1346
+ + `${indent.get()}let mut query_builder = ${newLinkVarName}.query_builder();\n`
1347
+ + `${indent.get()}query_builder.set_pair("${paramGroups.apiVersion.key}", &${paramGroups.apiVersion.name});\n`
1348
+ + `${indent.get()}query_builder.build();\n`;
1322
1349
  }
1323
1350
  return '';
1324
1351
  };
1325
- const declareRequest = function (indent, use, method, paramGroups, requestVarName, linkVarName, forceMut) {
1352
+ const declareRequest = function (indent, use, method, paramGroups, requestVarName, linkExpr, forceMut, optionsPrefix) {
1326
1353
  let mutRequest = '';
1327
1354
  // if the only header is optional Content-Type it will not be used
1328
1355
  // by applyHeaderParams() in this case so don't make request mutable
1329
1356
  if (forceMut || paramGroups.header.length > 1 || (paramGroups.header.length === 1 && !isOptionalContentTypeHeader(paramGroups.header[0]))) {
1330
1357
  mutRequest = 'mut ';
1331
1358
  }
1332
- return `${indent.get()}let ${mutRequest}${requestVarName} = Request::new(${linkVarName}.clone(), Method::Get);\n`
1333
- + applyHeaderParams(indent, use, method, paramGroups, true, requestVarName);
1359
+ return `${indent.get()}let ${mutRequest}${requestVarName} = Request::new(${linkExpr}, Method::Get);\n`
1360
+ + applyHeaderParams(indent, use, method, paramGroups, true, requestVarName, optionsPrefix);
1334
1361
  };
1335
1362
  let stateVarName = 'next_link';
1336
1363
  let stateVarType = 'Url';
1337
1364
  let progressVarName = 'next_link';
1338
1365
  let stateNextLinkAccessor = 'next_link';
1339
1366
  let pollerStateMoreReturn = 'next_link';
1340
- let pollerStateInitialReturn = 'url.clone()';
1367
+ let pollerStateInitialReturn = `${urlVar}.clone()`;
1341
1368
  let pollerStatusInProgressReturn = 'next_link';
1342
- if (method.finalResultStrategy.kind === 'originalUri') {
1343
- body += `${indent.get()}struct Progress{ next_link: Url, first_rsp: Option<RawResponse>, }`;
1369
+ if (method.finalResultStrategy.kind === 'header' && method.finalResultStrategy.headerName !== pollingStepHeaderName) {
1370
+ // A case when the initial response contains two headers - one (usually, 'azure-asyncoperation') to poll operation status
1371
+ // and another (usually, 'location') to collect the final result. Both values are URLs.
1372
+ // But only the initial response will have these headers, i.e. responses from 'azure-asyncoperation' URL won't have the 'location'.
1373
+ // Therefore, we need to preserve both URLs and pass them between poller states, up to the moment when the operation status
1374
+ // is Succeeded, so that when operation is Succeeded, the poller can send a request to 'location' to collect the result.
1375
+ body += `${indent.get()}struct Progress{ next_link: Url, final_link: Url, }`;
1344
1376
  body += `${indent.get()}impl AsRef<str> for Progress{ fn as_ref(&self) -> &str{ self.next_link.as_ref() }}\n`;
1345
1377
  stateVarName = 'state';
1346
1378
  stateVarType = 'Progress';
1347
1379
  progressVarName = 'progress';
1348
1380
  stateNextLinkAccessor = 'progress.next_link';
1349
- pollerStateMoreReturn = 'Progress{next_link, first_rsp: progress.first_rsp}';
1350
- pollerStateInitialReturn = 'Progress{next_link: url.clone(), first_rsp: None}';
1351
- pollerStatusInProgressReturn = 'Progress{next_link, first_rsp}';
1381
+ pollerStateMoreReturn = 'Progress{next_link, final_link: progress.final_link}';
1382
+ pollerStateInitialReturn = `Progress{next_link: ${urlVar}.clone(), final_link: ${urlVar}.clone()}`;
1383
+ pollerStatusInProgressReturn = 'Progress{next_link, final_link}';
1352
1384
  }
1353
1385
  body += `${indent.get()}Ok(${method.returns.type.name}::from_callback(\n`;
1354
1386
  body += `${indent.push().get()}move |${stateVarName}: PollerState<${stateVarType}>, poller_options| {\n`;
@@ -1356,7 +1388,7 @@ function getLroMethodBody(indent, use, client, method) {
1356
1388
  pattern: `PollerState::More(${progressVarName})`,
1357
1389
  body: (indent) => {
1358
1390
  return applyApiVersionParam(indent, paramGroups, 'next_link', stateNextLinkAccessor)
1359
- + declareRequest(indent, use, method, paramGroups, initialRequestResult.requestVarName, 'next_link')
1391
+ + declareRequest(indent, use, method, paramGroups, initialRequestResult.requestVarName, 'next_link.clone()')
1360
1392
  + `${indent.get()}(${initialRequestResult.requestVarName}, ${pollerStateMoreReturn})\n`;
1361
1393
  },
1362
1394
  }, {
@@ -1367,14 +1399,74 @@ function getLroMethodBody(indent, use, client, method) {
1367
1399
  return body;
1368
1400
  },
1369
1401
  }])};\n`;
1370
- body += `${indent.get()}let ctx = options.method_options.context.clone();\n`;
1402
+ body += `${indent.get()}let ctx = poller_options.context.clone();\n`;
1371
1403
  body += `${indent.get()}let pipeline = pipeline.clone();\n`;
1404
+ if (method.finalResultStrategy.kind === 'originalUri') {
1405
+ body += `${indent.get()}let final_link = url.clone();\n`;
1406
+ for (const headerParam of paramGroups.header.filter(h => h.type.kind !== 'literal' && !isOptionalContentTypeHeader(h))) {
1407
+ if (headerParam.type.kind !== 'enum') {
1408
+ const optionsPrefix = headerParam.optional ? 'options.' : '';
1409
+ body += `${indent.get()}let ${headerParam.name} = ${optionsPrefix}${headerParam.name}.clone();\n`;
1410
+ }
1411
+ }
1412
+ }
1413
+ // Match an ARM PUT operation ("create or update"), which may have immediate 200 OK response with no headers and no poller status
1414
+ const isArmPutLro = bodyFormat === 'json'
1415
+ && method.httpMethod === 'put'
1416
+ && method.returns.type.resultType !== undefined
1417
+ && method.finalResultStrategy.kind === 'header'
1418
+ && method.finalResultStrategy.headerName === 'azure-asyncoperation'
1419
+ && pollingStepHeaderName === 'azure-asyncoperation'
1420
+ && method.statusCodes.some(sc => sc == 200)
1421
+ && method.statusCodes.some(sc => sc == 201);
1422
+ // Match an ARM PATCH operation ("update"), which may have immediate 200 OK response with no headers and no poller status
1423
+ const isArmPatchLro = bodyFormat === 'json'
1424
+ && method.httpMethod === 'patch'
1425
+ && method.returns.type.resultType !== undefined
1426
+ && method.finalResultStrategy.kind === 'header'
1427
+ && method.finalResultStrategy.headerName === 'location'
1428
+ && pollingStepHeaderName === 'location'
1429
+ && method.statusCodes.some(sc => sc == 200)
1430
+ && method.statusCodes.some(sc => sc == 202);
1431
+ // Match an ARM POST operation ("export"), which may have empty initial response
1432
+ const isArmPostLro = bodyFormat === 'json'
1433
+ && method.httpMethod === 'post'
1434
+ && method.returns.type.resultType !== undefined
1435
+ && method.finalResultStrategy.kind === 'header'
1436
+ && method.finalResultStrategy.headerName === 'location'
1437
+ && pollingStepHeaderName === 'azure-asyncoperation'
1438
+ && method.statusCodes.some(sc => sc == 200)
1439
+ && method.statusCodes.some(sc => sc == 202);
1440
+ // Match an ARM DELETE operation, which may have empty responses and only communicate via status codes
1441
+ const isArmDeleteLro = bodyFormat === 'json'
1442
+ && method.httpMethod === 'delete'
1443
+ && method.returns.type.resultType === undefined
1444
+ && method.finalResultStrategy.kind === 'header'
1445
+ && method.finalResultStrategy.headerName === 'location'
1446
+ && pollingStepHeaderName === 'location'
1447
+ && method.statusCodes.some(sc => sc == 200)
1448
+ && method.statusCodes.some(sc => sc == 202)
1449
+ && method.statusCodes.some(sc => sc == 204);
1450
+ if (isArmPutLro || isArmPatchLro) {
1451
+ body += 'let original_url = url.clone();\n';
1452
+ }
1372
1453
  body += `${indent.get()}async move {\n`;
1373
1454
  body += `${indent.push().get()}let rsp = pipeline.send(&ctx, &mut ${initialRequestResult.requestVarName}, ${getPipelineOptions(indent, use, method)}).await?;\n`;
1374
- body += `${indent.get()}let (status, headers, body) = rsp.deconstruct();\n`;
1455
+ const needsMutBody = isArmPutLro || isArmPatchLro || isArmPostLro || isArmDeleteLro;
1456
+ body += `${indent.get()}let (status, headers, ${needsMutBody ? 'mut' : ''} body) = rsp.deconstruct();\n`;
1457
+ if (isArmPostLro || isArmDeleteLro) {
1458
+ body += `${indent.get()}if body.is_empty() {\n`;
1459
+ let emptyBodyExpr = '"{}"';
1460
+ if (isArmDeleteLro) {
1461
+ use.add('azure_core::http', 'StatusCode');
1462
+ emptyBodyExpr = `if status == StatusCode::NoContent { "{\\"status\\":\\"Succeeded\\"}" } else { "{}" }`;
1463
+ }
1464
+ body += `${indent.push().get()}body = azure_core::http::response::ResponseBody::from_bytes(${emptyBodyExpr});\n`;
1465
+ body += `${indent.pop().get()}}\n`;
1466
+ }
1375
1467
  if (pollingStepHeaderName !== undefined) {
1376
1468
  body += `${indent.get()}let next_link = ${helpers.buildMatch(indent, `headers.get_optional_string(&HeaderName::from_static("${pollingStepHeaderName}"))`, [{
1377
- pattern: `Some(operation_location)`,
1469
+ pattern: 'Some(operation_location)',
1378
1470
  body: (indent) => {
1379
1471
  return `${indent.get()}Url::parse(&operation_location)?\n`;
1380
1472
  }
@@ -1385,32 +1477,48 @@ function getLroMethodBody(indent, use, client, method) {
1385
1477
  }
1386
1478
  }])};\n`;
1387
1479
  }
1388
- let resultRspVarName = 'first_rsp';
1389
- if (method.finalResultStrategy.kind === 'header' && method.finalResultStrategy.headerName !== pollingStepHeaderName) { // separate link for picking up the result
1390
- body += `${indent.get()}let final_link = Url::parse(headers.get_str(&HeaderName::from_static("${method.finalResultStrategy.headerName}"))?)?;\n`;
1480
+ if (isArmPutLro || isArmPatchLro) {
1481
+ use.add('azure_core::http', 'StatusCode');
1482
+ body += `${indent.get()}let mut final_body = None;\n`;
1483
+ body += `${indent.get()}if status == StatusCode::Ok && next_link.as_str() == original_url.as_str() {\n`;
1484
+ body += `${indent.push().get()}final_body = Some(body);\n`;
1485
+ body += `${indent.get()}body = azure_core::http::response::ResponseBody::from_bytes("{\\"status\\":\\"Succeeded\\"}");\n`;
1486
+ body += `${indent.pop().get()}}\n`;
1391
1487
  }
1392
- else if (method.finalResultStrategy.kind === 'originalUri') { // result available via original request immediately
1393
- resultRspVarName = 'first_rsp';
1394
- body += `${indent.get()}let mut ${resultRspVarName} = progress.first_rsp;\n`;
1395
- body += `${indent.get()}if first_rsp.is_none() { ${resultRspVarName} = Some(RawResponse::from_bytes(status, headers.clone(), body.clone())); }\n`;
1488
+ if (method.finalResultStrategy.kind === 'header' && method.finalResultStrategy.headerName !== pollingStepHeaderName) { // separate link for picking up the result
1489
+ body += `${indent.get()}let final_link = ${helpers.buildMatch(indent, `headers.get_optional_string(&HeaderName::from_static("${method.finalResultStrategy.headerName}"))`, [{
1490
+ pattern: 'Some(final_link)',
1491
+ body: (indent) => {
1492
+ return `${indent.get()}Url::parse(&final_link)?\n`;
1493
+ }
1494
+ }, {
1495
+ pattern: 'None',
1496
+ body: (indent) => {
1497
+ return `${indent.get()}progress.final_link`;
1498
+ }
1499
+ }])};\n`;
1396
1500
  }
1397
1501
  body += `${indent.get()}let retry_after = get_retry_after(&headers, &[X_MS_RETRY_AFTER_MS, RETRY_AFTER_MS, RETRY_AFTER], &poller_options);\n`;
1398
1502
  const deserialize = `${bodyFormat}::from_${bodyFormat}`;
1399
1503
  use.add('azure_core', bodyFormat);
1400
- body += `${indent.get()}let res: ${helpers.getTypeDeclaration(helpers.unwrapType(method.returns.type))} = ${deserialize}(&body)?;\n`;
1401
- if (method.finalResultStrategy.kind === 'header' && method.finalResultStrategy.headerName === pollingStepHeaderName) { // result available at the poll step link when finished
1402
- resultRspVarName = 'final_rsp';
1403
- body += `${indent.get()}let mut ${resultRspVarName} = None;\n`;
1404
- body += `${indent.get()}if res.status() == PollerStatus::Succeeded {\n`;
1405
- indent.push();
1504
+ body += `${indent.push().get()}let res: ${helpers.getTypeDeclaration(helpers.unwrapType(method.returns.type))} = ${deserialize}(&body)?;\n`;
1505
+ if (method.finalResultStrategy.kind === 'header' && method.finalResultStrategy.headerName === pollingStepHeaderName) {
1506
+ body += `${indent.get()}let mut final_rsp: Option<RawResponse> = None;\n`;
1507
+ body += `if res.status() == PollerStatus::Succeeded {\n`;
1406
1508
  let responseBodyExpr = 'body.clone()';
1407
- if (method.finalResultStrategy.propertyName !== undefined) {
1509
+ if (isArmPutLro || isArmPatchLro) {
1510
+ responseBodyExpr = 'if let Some(final_body) = final_body { final_body } else { body.clone() }';
1511
+ }
1512
+ else if (method.finalResultStrategy.propertyName !== undefined) {
1408
1513
  responseBodyExpr = 'body';
1409
- body += `${indent.get()}let ${responseBodyExpr} = azure_core::http::response::ResponseBody::from_bytes(`
1410
- + `serde_json::from_str::<azure_core::Value>(body.clone().into_string()?.as_str())?["${method.finalResultStrategy.propertyName}"].to_string());\n`;
1514
+ if (bodyFormat === 'json') {
1515
+ crate.addDependency(new rust.CrateDependency('serde_json'));
1516
+ body += `${indent.get()}let body = azure_core::http::response::ResponseBody::from_bytes(`
1517
+ + `serde_json::from_str::<azure_core::Value>(body.clone().into_string()?.as_str())?["${method.finalResultStrategy.propertyName}"].to_string());\n`;
1518
+ }
1411
1519
  }
1412
- body += `${indent.get()}${resultRspVarName} = Some(RawResponse::from_bytes(status, headers.clone(), ${responseBodyExpr}));\n`;
1413
- body += `${indent.pop().get()}}\n`;
1520
+ body += `${indent.get()}final_rsp = Some(RawResponse::from_bytes(status, headers.clone(), ${responseBodyExpr}));\n`;
1521
+ body += `}\n`;
1414
1522
  }
1415
1523
  body += `${indent.get()}let rsp = RawResponse::from_bytes(status, headers, body).into();\n`;
1416
1524
  const arms = [{
@@ -1423,19 +1531,24 @@ function getLroMethodBody(indent, use, client, method) {
1423
1531
  arms.push({
1424
1532
  pattern: `PollerStatus::Succeeded`,
1425
1533
  body: (indent) => {
1426
- return `{\n`
1534
+ let body = `{\n`
1427
1535
  + `${indent.push().get()}PollerResult::Succeeded {\n`
1428
1536
  + `${indent.push().get()}response: rsp,\n`
1429
1537
  + `${indent.get()}target: Box::new(move || {\n`
1430
- + `${indent.push().get()}Box::pin(async move {\n`
1431
- + ((method.finalResultStrategy.kind === 'header' && method.finalResultStrategy.headerName !== pollingStepHeaderName)
1432
- ? (declareRequest(indent, use, method, paramGroups, initialRequestResult.requestVarName, 'final_link', true)
1433
- + `Ok(pipeline.send(&ctx, &mut ${initialRequestResult.requestVarName}, None).await?.into())\n`)
1434
- : `Ok(${resultRspVarName}.unwrap().into())\n`)
1435
- + `${indent.pop().get()}})\n`
1538
+ + `${indent.push().get()}Box::pin(async move {\n`;
1539
+ if (method.finalResultStrategy.kind === 'header' && method.finalResultStrategy.headerName === pollingStepHeaderName) {
1540
+ use.add('azure_core::error', 'Error', 'ErrorKind');
1541
+ body += `Ok(final_rsp.ok_or_else(|| { Error::new(ErrorKind::Other, "missing final response")})?.into())\n`;
1542
+ }
1543
+ else {
1544
+ body += declareRequest(indent, use, method, paramGroups, initialRequestResult.requestVarName, 'final_link', true, '')
1545
+ + `Ok(pipeline.send(&ctx, &mut ${initialRequestResult.requestVarName}, None).await?.into())\n`;
1546
+ }
1547
+ body += `${indent.pop().get()}})\n`
1436
1548
  + `${indent.get()}}),\n`
1437
1549
  + `${indent.pop().get()}}`
1438
1550
  + `${indent.pop().get()}}`;
1551
+ return body;
1439
1552
  }
1440
1553
  });
1441
1554
  arms.push({
@@ -1448,7 +1561,7 @@ function getLroMethodBody(indent, use, client, method) {
1448
1561
  body += `${indent.get()}Ok(${helpers.buildMatch(indent, 'res.status()', arms)})\n`;
1449
1562
  body += `${indent.pop().get()}}\n`; // end async move
1450
1563
  body += `${indent.pop().get()}},\n`; // end move
1451
- body += `${indent.pop().get()} Some(method_options),))`; // end Ok/Poller::from_callback
1564
+ body += `${indent.pop().get()} Some(options.method_options),))`; // end Ok/Poller::from_callback
1452
1565
  return body;
1453
1566
  }
1454
1567
  /**
@@ -1491,9 +1604,10 @@ function getClientSupplementalEndpointParamValue(param) {
1491
1604
  * @param param the param for which to get the value
1492
1605
  * @param fromSelf applicable for client params. when true, the prefix "self." is included
1493
1606
  * @param neverBorrow indicates that the borrowing calculation should be skipped
1607
+ * @param overrideParamName optional value to use as the parameter name instead of param.name
1494
1608
  * @returns the code to use for the param's value
1495
1609
  */
1496
- function getHeaderPathQueryParamValue(use, param, fromSelf, neverBorrow) {
1610
+ function getHeaderPathQueryParamValue(use, param, fromSelf, neverBorrow, overrideParamName) {
1497
1611
  let paramName = param.name;
1498
1612
  // when fromSelf is false we assume that there's a local with the same name.
1499
1613
  // e.g. in pageable methods where we need to clone the params so they can be
@@ -1501,6 +1615,9 @@ function getHeaderPathQueryParamValue(use, param, fromSelf, neverBorrow) {
1501
1615
  if (param.location === 'client' && fromSelf) {
1502
1616
  paramName = 'self.' + paramName;
1503
1617
  }
1618
+ else if (overrideParamName) {
1619
+ paramName = overrideParamName;
1620
+ }
1504
1621
  const encodeBytes = function (type, param) {
1505
1622
  const encoding = helpers.getBytesEncodingMethod(type.encoding, 'encode', use);
1506
1623
  if (param) {
@@ -1517,6 +1634,9 @@ function getHeaderPathQueryParamValue(use, param, fromSelf, neverBorrow) {
1517
1634
  }
1518
1635
  case 'unix_time':
1519
1636
  return `${paramName}.${encoding}.to_string()`;
1637
+ default:
1638
+ // rfc3339-fixed-width isn't applicable here (it has a very specific use case)
1639
+ throw new CodegenError('InternalError', `unexpected date-time encoding ${type.encoding}`);
1520
1640
  }
1521
1641
  };
1522
1642
  // this will contain the final text for
@@ -1525,13 +1645,11 @@ function getHeaderPathQueryParamValue(use, param, fromSelf, neverBorrow) {
1525
1645
  let paramValue;
1526
1646
  // contains the result from calculating if the
1527
1647
  // param requires borrowing.
1528
- let mustBorrow = true;
1648
+ let mustBorrow = !helpers.isQueryParameter(param);
1529
1649
  const paramType = helpers.unwrapType(param.type);
1530
- if (param.kind === 'headerCollection' || param.kind === 'queryCollection') {
1531
- if (param.format === 'multi') {
1532
- throw new CodegenError('InternalError', 'multi should have been handled outside getHeaderPathQueryParamValue');
1533
- }
1534
- else if (paramType.kind === 'String' || paramType.kind === 'str') {
1650
+ // we want multi to hit the else case so the necessary conversions etc can happen
1651
+ if ((param.kind === 'headerCollection' || param.kind === 'queryCollection') && param.format !== 'multi') {
1652
+ if (paramType.kind === 'String' || paramType.kind === 'str') {
1535
1653
  paramValue = `${paramName}.join("${getCollectionDelimiter(param.format)}")`;
1536
1654
  }
1537
1655
  else {
@@ -1554,8 +1672,8 @@ function getHeaderPathQueryParamValue(use, param, fromSelf, neverBorrow) {
1554
1672
  switch (paramType.kind) {
1555
1673
  case 'String':
1556
1674
  paramValue = paramName;
1557
- // if the param is on the client, or it's optional, then we must borrow
1558
- mustBorrow = (param.location === 'client' && fromSelf) || param.optional;
1675
+ // if the param is on the client, then we must borrow
1676
+ mustBorrow = param.location === 'client' && fromSelf;
1559
1677
  break;
1560
1678
  case 'str':
1561
1679
  paramValue = paramName;
@@ -1570,7 +1688,7 @@ function getHeaderPathQueryParamValue(use, param, fromSelf, neverBorrow) {
1570
1688
  break;
1571
1689
  case 'enum':
1572
1690
  case 'scalar':
1573
- if (paramType.kind === 'enum' && (param.kind === 'pathScalar' || param.kind === 'queryScalar') && paramType.type === 'String') {
1691
+ if (isEnumString(paramType) && (helpers.isPathParameter(param) || helpers.isQueryParameter(param))) {
1574
1692
  // append_pair and path.replace() want a reference to the string
1575
1693
  paramValue = `${paramName}.as_ref()`;
1576
1694
  // as_ref() elides the need to borrow
@@ -1670,4 +1788,9 @@ function getPipelineOptions(indent, use, method) {
1670
1788
  return 'None';
1671
1789
  }
1672
1790
  }
1791
+ /** narrows type to an Enum type IFF its underlying type is String within the conditional block */
1792
+ function isEnumString(type) {
1793
+ const unwrapped = helpers.unwrapType(type);
1794
+ return unwrapped.kind === 'enum' && unwrapped.type === 'String';
1795
+ }
1673
1796
  //# sourceMappingURL=clients.js.map