@azure-tools/typespec-rust 0.32.0 → 0.34.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 (64) hide show
  1. package/dist/src/codegen/clients.d.ts.map +1 -1
  2. package/dist/src/codegen/clients.js +153 -131
  3. package/dist/src/codegen/clients.js.map +1 -1
  4. package/dist/src/codegen/codeGenerator.js +16 -16
  5. package/dist/src/codegen/codeGenerator.js.map +1 -1
  6. package/dist/src/codegen/context.d.ts +3 -3
  7. package/dist/src/codegen/context.d.ts.map +1 -1
  8. package/dist/src/codegen/context.js +5 -5
  9. package/dist/src/codegen/context.js.map +1 -1
  10. package/dist/src/codegen/docTests.d.ts.map +1 -1
  11. package/dist/src/codegen/docTests.js +2 -1
  12. package/dist/src/codegen/docTests.js.map +1 -1
  13. package/dist/src/codegen/enums.d.ts +5 -5
  14. package/dist/src/codegen/enums.d.ts.map +1 -1
  15. package/dist/src/codegen/enums.js +11 -8
  16. package/dist/src/codegen/enums.js.map +1 -1
  17. package/dist/src/codegen/headerTraits.d.ts.map +1 -1
  18. package/dist/src/codegen/headerTraits.js +7 -4
  19. package/dist/src/codegen/headerTraits.js.map +1 -1
  20. package/dist/src/codegen/helpers.d.ts +23 -0
  21. package/dist/src/codegen/helpers.d.ts.map +1 -1
  22. package/dist/src/codegen/helpers.js +39 -18
  23. package/dist/src/codegen/helpers.js.map +1 -1
  24. package/dist/src/codegen/mod.d.ts.map +1 -1
  25. package/dist/src/codegen/mod.js +3 -1
  26. package/dist/src/codegen/mod.js.map +1 -1
  27. package/dist/src/codegen/models.d.ts +4 -6
  28. package/dist/src/codegen/models.d.ts.map +1 -1
  29. package/dist/src/codegen/models.js +132 -68
  30. package/dist/src/codegen/models.js.map +1 -1
  31. package/dist/src/codegen/unions.d.ts +8 -6
  32. package/dist/src/codegen/unions.d.ts.map +1 -1
  33. package/dist/src/codegen/unions.js +142 -9
  34. package/dist/src/codegen/unions.js.map +1 -1
  35. package/dist/src/codegen/use.d.ts +2 -2
  36. package/dist/src/codegen/use.d.ts.map +1 -1
  37. package/dist/src/codegen/use.js +3 -5
  38. package/dist/src/codegen/use.js.map +1 -1
  39. package/dist/src/codemodel/client.d.ts +9 -1
  40. package/dist/src/codemodel/client.d.ts.map +1 -1
  41. package/dist/src/codemodel/client.js +2 -1
  42. package/dist/src/codemodel/client.js.map +1 -1
  43. package/dist/src/codemodel/crate.d.ts +1 -1
  44. package/dist/src/codemodel/crate.d.ts.map +1 -1
  45. package/dist/src/codemodel/types.d.ts +39 -6
  46. package/dist/src/codemodel/types.d.ts.map +1 -1
  47. package/dist/src/codemodel/types.js +25 -1
  48. package/dist/src/codemodel/types.js.map +1 -1
  49. package/dist/src/tcgcadapter/adapter.d.ts +5 -2
  50. package/dist/src/tcgcadapter/adapter.d.ts.map +1 -1
  51. package/dist/src/tcgcadapter/adapter.js +259 -170
  52. package/dist/src/tcgcadapter/adapter.js.map +1 -1
  53. package/dist/src/tcgcadapter/naming.d.ts.map +1 -1
  54. package/dist/src/tcgcadapter/naming.js +2 -2
  55. package/dist/src/tcgcadapter/naming.js.map +1 -1
  56. package/dist/src/utils/utils.d.ts +99 -0
  57. package/dist/src/utils/utils.d.ts.map +1 -0
  58. package/dist/src/utils/utils.js +288 -0
  59. package/dist/src/utils/utils.js.map +1 -0
  60. package/package.json +16 -19
  61. package/dist/src/shared/shared.d.ts +0 -29
  62. package/dist/src/shared/shared.d.ts.map +0 -1
  63. package/dist/src/shared/shared.js +0 -109
  64. package/dist/src/shared/shared.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"clients.d.ts","sourceRoot":"","sources":["../../../src/codegen/clients.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,OAAO,MAAM,cAAc,CAAC;AAGxC,OAAO,KAAK,IAAI,MAAM,uBAAuB,CAAC;AAG9C,yBAAyB;AACzB,MAAM,WAAW,aAAa;IAC5B,iCAAiC;IACjC,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IAE/B,uCAAuC;IACvC,OAAO,EAAE,OAAO,CAAC,MAAM,CAAC;CACzB;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,GAAG,aAAa,GAAG,SAAS,CAuRxE"}
1
+ {"version":3,"file":"clients.d.ts","sourceRoot":"","sources":["../../../src/codegen/clients.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,OAAO,MAAM,cAAc,CAAC;AAGxC,OAAO,KAAK,IAAI,MAAM,uBAAuB,CAAC;AAG9C,yBAAyB;AACzB,MAAM,WAAW,aAAa;IAC5B,iCAAiC;IACjC,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IAE/B,uCAAuC;IACvC,OAAO,EAAE,OAAO,CAAC,MAAM,CAAC;CACzB;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,GAAG,aAAa,GAAG,SAAS,CA+RxE"}
@@ -3,15 +3,13 @@
3
3
  * Licensed under the MIT License. See License.txt in the project root for license information.
4
4
  *--------------------------------------------------------------------------------------------*/
5
5
  // cspell: ignore conv
6
- import * as codegen from '@azure-tools/codegen';
7
- import { values } from '@azure-tools/linq';
8
6
  import { emitHeaderTraitDocExample } from './docTests.js';
9
7
  import { CodegenError } from './errors.js';
10
8
  import * as helpers from './helpers.js';
11
9
  import queryString from 'query-string';
12
10
  import { Use } from './use.js';
13
11
  import * as rust from '../codemodel/index.js';
14
- import * as shared from '../shared/shared.js';
12
+ import * as utils from '../utils/utils.js';
15
13
  /**
16
14
  * emits the content for all client files
17
15
  *
@@ -26,9 +24,13 @@ export function emitClients(crate) {
26
24
  const clientOptionsImplDefault = function (constructable) {
27
25
  // only implement Default when there's more than one field (i.e. more than just client_options)
28
26
  // and the field(s) contain a client default value.
29
- return constructable.options.type.fields.length > 1 && values(constructable.options.type.fields)
30
- .where((field) => field.name !== 'client_options')
31
- .where((field) => field.defaultValue !== undefined).any();
27
+ if (constructable.suppressed) {
28
+ return false;
29
+ }
30
+ const optionsType = constructable.options.type;
31
+ return optionsType.fields.length > 1 && optionsType.fields.some((field) => {
32
+ return field.name !== 'client_options' && field.defaultValue !== undefined;
33
+ });
32
34
  };
33
35
  const clientModules = new Array();
34
36
  // emit the clients, one file per client
@@ -113,9 +115,9 @@ export function emitClients(crate) {
113
115
  // propagate the required client params to the initializer
114
116
  // NOTE: we do this on a sorted copy of the client params as we must preserve their order.
115
117
  // exclude endpoint params as they aren't propagated to clients (they're consumed when creating the complete endpoint)
116
- const sortedParams = values([...constructor.params]
117
- .sort((a, b) => { return helpers.sortAscending(a.name, b.name); }))
118
- .where((each) => each.kind !== 'clientSupplementalEndpoint' && each.kind !== 'clientCredential').toArray();
118
+ const sortedParams = [...constructor.params]
119
+ .filter((each) => each.kind !== 'clientSupplementalEndpoint' && each.kind !== 'clientCredential')
120
+ .sort((a, b) => { return helpers.sortAscending(a.name, b.name); });
119
121
  for (const param of sortedParams) {
120
122
  if (param.optional) {
121
123
  continue;
@@ -159,7 +161,7 @@ export function emitClients(crate) {
159
161
  // we don't model this as the implementation isn't dynamic.
160
162
  body += `${indent.get()}/// Returns the Url associated with this client.\n`;
161
163
  body += `${indent.get()}pub fn endpoint(&self) -> &Url {\n`;
162
- body += `${indent.push().get()}&self.${getEndpointFieldName(client)}\n`;
164
+ body += `${indent.push().get()}&self.${client.endpoint.name}\n`;
163
165
  body += `${indent.pop().get()}}\n\n`;
164
166
  for (let i = 0; i < client.methods.length; ++i) {
165
167
  const method = client.methods[i];
@@ -260,8 +262,12 @@ export function emitClients(crate) {
260
262
  let content = helpers.contentPreamble();
261
263
  content += use.text();
262
264
  content += body;
263
- const clientMod = codegen.deconstruct(client.name).join('_');
264
- clientModules.push({ name: clientMod, content: content });
265
+ const clientMod = utils.deconstruct(client.name).join('_');
266
+ clientModules.push({
267
+ name: clientMod,
268
+ content: content,
269
+ visibility: 'pubUse',
270
+ });
265
271
  }
266
272
  return {
267
273
  modules: clientModules,
@@ -271,6 +277,7 @@ export function emitClients(crate) {
271
277
  function getMethodOptions(crate) {
272
278
  const use = new Use('modelsOther');
273
279
  const indent = new helpers.indentation();
280
+ const visTracker = new helpers.VisibilityTracker();
274
281
  let body = '';
275
282
  for (const client of crate.clients) {
276
283
  for (let i = 0; i < client.methods.length; ++i) {
@@ -281,7 +288,8 @@ function getMethodOptions(crate) {
281
288
  body += helpers.formatDocComment(method.options.type.docs);
282
289
  use.add('azure_core::fmt', 'SafeDebug');
283
290
  body += '#[derive(Clone, Default, SafeDebug)]\n';
284
- body += `${helpers.emitVisibility(method.visibility)}struct ${helpers.getTypeDeclaration(method.options.type)} {\n`;
291
+ body += `${helpers.emitVisibility(method.options.type.visibility)}struct ${helpers.getTypeDeclaration(method.options.type)} {\n`;
292
+ visTracker.update(method.options.type.visibility);
285
293
  for (let i = 0; i < method.options.type.fields.length; ++i) {
286
294
  const field = method.options.type.fields[i];
287
295
  use.addForType(field.type);
@@ -327,6 +335,7 @@ function getMethodOptions(crate) {
327
335
  return {
328
336
  name: 'method_options',
329
337
  content: content,
338
+ visibility: visTracker.get(),
330
339
  };
331
340
  }
332
341
  /**
@@ -430,7 +439,7 @@ function getMethodParamsCountAndSig(method, use) {
430
439
  }
431
440
  // don't add client or optional params to the method param sig
432
441
  if (param.location === 'method' && !param.optional) {
433
- use.addForType(param.type);
442
+ use.addForType(param.kind === 'partialBody' ? param.paramType : param.type);
434
443
  paramsSig.push(`${param.name}: ${formatParamTypeName(param)}`);
435
444
  ++count;
436
445
  }
@@ -491,7 +500,7 @@ function getHeaderTraitDocComment(indent, crate, method) {
491
500
  */
492
501
  function getAuthPolicy(ctor, use) {
493
502
  for (const param of ctor.params) {
494
- const arcTokenCred = shared.asTypeOf(param.type, 'tokenCredential', 'arc');
503
+ const arcTokenCred = utils.asTypeOf(param.type, 'tokenCredential', 'arc');
495
504
  if (arcTokenCred) {
496
505
  use.add('azure_core::http::policies', 'auth::BearerTokenAuthorizationPolicy', 'Policy');
497
506
  const scopes = new Array();
@@ -533,29 +542,6 @@ function formatParamTypeName(param) {
533
542
  }
534
543
  return format;
535
544
  }
536
- /**
537
- * returns the name of the endpoint field within the client
538
- *
539
- * @param client the client in which to find the endpoint field
540
- * @returns the name of the endpoint field
541
- */
542
- function getEndpointFieldName(client) {
543
- // find the endpoint field. it's the only one that's
544
- // a Url. the name will be uniform across clients
545
- let endpointFieldName;
546
- for (const field of client.fields) {
547
- if (field.type.kind === 'Url') {
548
- if (endpointFieldName) {
549
- throw new CodegenError('InternalError', `found multiple URL fields in client ${client.name} which is unexpected`);
550
- }
551
- endpointFieldName = field.name;
552
- }
553
- }
554
- if (!endpointFieldName) {
555
- throw new CodegenError('InternalError', `didn't find URI field for client ${client.name}`);
556
- }
557
- return endpointFieldName;
558
- }
559
545
  /**
560
546
  * constructs the body for a client accessor method
561
547
  *
@@ -663,10 +649,16 @@ function getMethodParamGroup(method) {
663
649
  */
664
650
  function getParamValueHelper(indent, param, setter, optionsPrefix = 'options.') {
665
651
  if (param.optional && param.type.kind !== 'literal') {
666
- const asRef = nonCopyableType(param.type) || isEnumString(param.type) ? '.as_ref()' : '';
652
+ let asRefOrClone = ''; // Empty value is ok as well, depending on what is needed.
653
+ if (param.type.kind === 'requestContent') {
654
+ asRefOrClone = '.clone()';
655
+ }
656
+ else if (nonCopyableType(param.type) || isEnumString(param.type)) {
657
+ asRefOrClone = '.as_ref()';
658
+ }
667
659
  // optional params are in the unwrapped options local var
668
660
  const op = indent.get() + helpers.buildIfBlock(indent, {
669
- condition: `let Some(${param.name}) = ${param.location === 'client' ? 'self.' : optionsPrefix}${param.name}${asRef}`,
661
+ condition: `let Some(${param.name}) = ${param.location === 'client' ? 'self.' : optionsPrefix}${param.name}${asRefOrClone}`,
670
662
  body: setter,
671
663
  });
672
664
  return op + '\n';
@@ -833,7 +825,7 @@ function constructUrl(indent, use, method, paramGroups, urlVarName) {
833
825
  const valueVar = queryParam.name[0];
834
826
  let text = `${indent.get()}for ${valueVar} in ${queryParam.name}.iter() {\n`;
835
827
  // if queryParam is a &[&str] then we'll need to deref the iterator
836
- const deref = shared.asTypeOf(queryParam.type, 'str', 'ref', 'slice', 'ref') ? '*' : '';
828
+ const deref = utils.asTypeOf(queryParam.type, 'str', 'ref', 'slice', 'ref') ? '*' : '';
837
829
  text += `${indent.push().get()}query_builder.append_pair("${queryParam.key}", ${deref}${getHeaderPathQueryParamValue(use, queryParam, !queryParam.optional, false, valueVar)});\n`;
838
830
  text += `${indent.pop().get()}}\n`;
839
831
  return text;
@@ -890,7 +882,7 @@ function applyHeaderParams(indent, use, method, paramGroups, inClosure, requestV
890
882
  body += `${indent.get()}let ${headerParam.name} = ` + helpers.buildMatch(indent, headerParam.name, [
891
883
  {
892
884
  pattern: `PagerState::More(${headerParam.name})`,
893
- body: (indent) => `${indent.get()}&Some(${headerParam.name})\n`,
885
+ body: (indent) => `${indent.get()}&Some(${headerParam.name}.into())\n`,
894
886
  },
895
887
  {
896
888
  pattern: 'PagerState::Initial',
@@ -944,7 +936,7 @@ function constructRequest(indent, use, method, paramGroups, inClosure, urlVarNam
944
936
  // when constructing the request var name we need to ensure
945
937
  // that it doesn't collide with any parameter name.
946
938
  const requestVarName = helpers.getUniqueVarName(method.params, ['request', 'core_req']);
947
- let body = `${indent.get()}let ${(forceMut || paramGroups.header.length > 0) ? 'mut ' : ''}${requestVarName} = Request::new(${urlVarName}${cloneUrl ? '.clone()' : ''}, Method::${codegen.capitalize(method.httpMethod)});\n`;
939
+ let body = `${indent.get()}let ${(forceMut || paramGroups.header.length > 0) ? 'mut ' : ''}${requestVarName} = Request::new(${urlVarName}${cloneUrl ? '.clone()' : ''}, Method::${utils.capitalize(method.httpMethod)});\n`;
948
940
  body += applyHeaderParams(indent, use, method, paramGroups, inClosure, requestVarName);
949
941
  let optionalContentTypeParam;
950
942
  for (const headerParam of paramGroups.header) {
@@ -968,17 +960,25 @@ function constructRequest(indent, use, method, paramGroups, inClosure, urlVarNam
968
960
  // all partial body params should point to the same underlying model type.
969
961
  const requestContentType = paramGroups.partialBody[0].type;
970
962
  use.addForType(requestContentType);
971
- body += `${indent.get()}let body: ${helpers.getTypeDeclaration(requestContentType)} = ${requestContentType.content.type.name} {\n`;
963
+ if (inClosure) {
964
+ body += `${indent.get()}let body: Result<${helpers.getTypeDeclaration(requestContentType)}> = ${requestContentType.content.type.name} {\n`;
965
+ }
966
+ else {
967
+ body += `${indent.get()}let body: ${helpers.getTypeDeclaration(requestContentType)} = ${requestContentType.content.type.name} {\n`;
968
+ }
972
969
  indent.push();
973
970
  for (const partialBodyParam of paramGroups.partialBody) {
974
971
  if (partialBodyParam.type.content.type !== requestContentType.content.type) {
975
972
  throw new CodegenError('InternalError', `spread param ${partialBodyParam.name} has conflicting model type ${partialBodyParam.type.content.type.name}, expected model type ${requestContentType.content.type.name}`);
976
973
  }
977
974
  if (partialBodyParam.optional) {
978
- body += `${indent.get()}${partialBodyParam.name}: options.${partialBodyParam.name},\n`;
975
+ body += `${indent.get()}${partialBodyParam.name}: options.${partialBodyParam.name}${inClosure ? '.clone()' : ''},\n`;
979
976
  continue;
980
977
  }
981
978
  let initializer = partialBodyParam.name;
979
+ if (inClosure) {
980
+ initializer = initializer + '.clone()';
981
+ }
982
982
  if (requestContentType.content.type.visibility === 'pub') {
983
983
  // spread param maps to a non-internal model, so it must be wrapped in Some()
984
984
  initializer = `Some(${initializer})`;
@@ -989,8 +989,14 @@ function constructRequest(indent, use, method, paramGroups, inClosure, urlVarNam
989
989
  }
990
990
  body += `${indent.get()}${initializer},\n`;
991
991
  }
992
- body += `${indent.pop().get()}}.try_into()?;\n`;
993
- body += `${indent.get()}${requestVarName}.set_body(body);\n`;
992
+ if (inClosure) {
993
+ body += `${indent.pop().get()}}.try_into();\n`;
994
+ body += `${indent.get()}if let Ok(body) = body { ${requestVarName}.set_body(body); }\n`;
995
+ }
996
+ else {
997
+ body += `${indent.pop().get()}}.try_into()?;\n`;
998
+ body += `${indent.get()}${requestVarName}.set_body(body);\n`;
999
+ }
994
1000
  }
995
1001
  return {
996
1002
  requestVarName: requestVarName,
@@ -1077,7 +1083,7 @@ function getAsyncMethodBody(indent, use, client, method) {
1077
1083
  let body = checkEmptyRequiredPathParams(indent, paramGroups.path);
1078
1084
  body += 'let options = options.unwrap_or_default();\n';
1079
1085
  body += `${indent.get()}let ctx = options.method_options.context.to_borrowed();\n`;
1080
- body += `${indent.get()}let ${urlVarNeedsMut(paramGroups, method)}${urlVarName} = self.${getEndpointFieldName(client)}.clone();\n`;
1086
+ body += `${indent.get()}let ${urlVarNeedsMut(paramGroups, method)}${urlVarName} = self.${client.endpoint.name}.clone();\n`;
1081
1087
  body += constructUrl(indent, use, method, paramGroups, urlVarName);
1082
1088
  const requestResult = constructRequest(indent, use, method, paramGroups, false, urlVarName);
1083
1089
  body += requestResult.content;
@@ -1114,7 +1120,7 @@ function getPageableMethodBody(indent, use, client, method) {
1114
1120
  let body = checkEmptyRequiredPathParams(indent, paramGroups.path);
1115
1121
  body += 'let options = options.unwrap_or_default().into_owned();\n';
1116
1122
  body += `${indent.get()}let pipeline = self.pipeline.clone();\n`;
1117
- body += `${indent.get()}let ${urlVarNeedsMut(paramGroups, method)}${urlVar} = self.${getEndpointFieldName(client)}.clone();\n`;
1123
+ body += `${indent.get()}let ${urlVarNeedsMut(paramGroups, method)}${urlVar} = self.${client.endpoint.name}.clone();\n`;
1118
1124
  body += constructUrl(indent, use, method, paramGroups, urlVar);
1119
1125
  // passed to constructRequest. we only need to
1120
1126
  // clone it for the non-continuation case.
@@ -1130,7 +1136,7 @@ function getPageableMethodBody(indent, use, client, method) {
1130
1136
  switch (method.strategy.kind) {
1131
1137
  case 'continuationToken': {
1132
1138
  const reqTokenParam = method.strategy.requestToken.name;
1133
- body += `${indent.get()}Ok(${method.returns.type.name}::new(move |${reqTokenParam}: PagerState<String>, pager_options| {\n`;
1139
+ body += `${indent.get()}Ok(${method.returns.type.name}::new(move |${reqTokenParam}: PagerState, pager_options| {\n`;
1134
1140
  body += `${indent.push().get()}let ${method.strategy.requestToken.kind === 'queryScalar' ? 'mut ' : ''}url = first_url.clone();\n`;
1135
1141
  if (method.strategy.requestToken.kind === 'queryScalar') {
1136
1142
  // if the url already contains the token query param,
@@ -1142,7 +1148,7 @@ function getPageableMethodBody(indent, use, client, method) {
1142
1148
  condition: `let PagerState::More(${reqTokenParam}) = ${reqTokenParam}`,
1143
1149
  body: (indent) => {
1144
1150
  return `${indent.get()}let mut query_builder = url.query_builder();\n`
1145
- + `${indent.get()}query_builder.set_pair("${reqTokenValue}", &${reqTokenParam});\n`
1151
+ + `${indent.get()}query_builder.set_pair("${reqTokenValue}", ${reqTokenParam}.as_ref());\n`
1146
1152
  + `${indent.get()}query_builder.build();\n`;
1147
1153
  }
1148
1154
  })}\n`;
@@ -1153,22 +1159,25 @@ function getPageableMethodBody(indent, use, client, method) {
1153
1159
  case 'nextLink': {
1154
1160
  const nextLinkName = method.strategy.nextLinkPath[method.strategy.nextLinkPath.length - 1].name;
1155
1161
  const reinjectedParams = method.strategy.reinjectedParams;
1156
- body += `${indent.get()}Ok(${method.returns.type.name}::new(move |${nextLinkName}: PagerState<Url>, pager_options| {\n`;
1162
+ body += `${indent.get()}Ok(${method.returns.type.name}::new(move |${nextLinkName}: PagerState, pager_options| {\n`;
1157
1163
  body += `${indent.push().get()}let url = ` + helpers.buildMatch(indent, nextLinkName, [{
1158
1164
  pattern: `PagerState::More(${nextLinkName})`,
1159
1165
  body: (indent) => {
1160
- const cloneNextLink = `${indent.get()}let mut ${nextLinkName} = ${nextLinkName}.clone();\n`;
1166
+ const cloneNextLink = `${indent.get()}let mut ${nextLinkName}: Url = ${nextLinkName}.try_into().expect("expected Url");\n`;
1161
1167
  let content = '';
1162
1168
  let hasQueryBuilder = false;
1169
+ let needsTryInto = true;
1163
1170
  if (paramGroups.apiVersion && paramGroups.apiVersion.kind === 'queryScalar') {
1164
1171
  content += cloneNextLink;
1165
1172
  hasQueryBuilder = true;
1173
+ needsTryInto = false;
1166
1174
  use.add('azure_core::http', 'UrlExt');
1167
1175
  content += `${indent.get()}let mut query_builder = ${nextLinkName}.query_builder();\n`;
1168
1176
  content += `${indent.get()}query_builder.set_pair("${paramGroups.apiVersion.key}", &${paramGroups.apiVersion.name});\n`;
1169
1177
  }
1170
1178
  else if (reinjectedParams.length > 0) {
1171
- // if we didn't clone it above, we'll need to clone it for this case
1179
+ // if we didn't try_into above, we'll need to do it for this case
1180
+ needsTryInto = false;
1172
1181
  content += cloneNextLink;
1173
1182
  }
1174
1183
  // add query params for reinjection
@@ -1185,7 +1194,7 @@ function getPageableMethodBody(indent, use, client, method) {
1185
1194
  if (hasQueryBuilder) {
1186
1195
  content += `${indent.get()}query_builder.build();\n`;
1187
1196
  }
1188
- content += `${indent.get()}${nextLinkName}\n`;
1197
+ content += `${indent.get()}${nextLinkName}${needsTryInto ? '.try_into().expect("expected Url")' : ''}\n`;
1189
1198
  return content;
1190
1199
  }
1191
1200
  }, {
@@ -1200,7 +1209,7 @@ function getPageableMethodBody(indent, use, client, method) {
1200
1209
  }
1201
1210
  else {
1202
1211
  // no next link when there's no strategy
1203
- body += `${indent.get()}Ok(${method.returns.type.name}::new(move |_: PagerState<Url>, pager_options| {\n`;
1212
+ body += `${indent.get()}Ok(${method.returns.type.name}::new(move |_: PagerState, pager_options| {\n`;
1204
1213
  indent.push();
1205
1214
  cloneUrl = true;
1206
1215
  srcUrlVar = urlVar;
@@ -1243,6 +1252,7 @@ function getPageableMethodBody(indent, use, client, method) {
1243
1252
  }
1244
1253
  return fullPath;
1245
1254
  };
1255
+ use.add('azure_core::http::pager', 'PagerContinuation');
1246
1256
  let srcNextPage;
1247
1257
  let nextPageValue;
1248
1258
  let continuation;
@@ -1262,13 +1272,13 @@ function getPageableMethodBody(indent, use, client, method) {
1262
1272
  srcNextPage = `rsp.${method.strategy.responseToken.name}()?`;
1263
1273
  break;
1264
1274
  }
1265
- continuation = nextPageValue;
1275
+ continuation = `PagerContinuation::Token(${nextPageValue})`;
1266
1276
  break;
1267
1277
  case 'nextLink': {
1268
1278
  const lastFieldName = method.strategy.nextLinkPath[method.strategy.nextLinkPath.length - 1].name;
1269
1279
  nextPageValue = lastFieldName;
1270
1280
  srcNextPage = `res.${buildNextLinkPath(method.strategy.nextLinkPath)}`;
1271
- continuation = `${lastFieldName}.parse()?`;
1281
+ continuation = `PagerContinuation::Link(${lastFieldName}.parse()?)`;
1272
1282
  break;
1273
1283
  }
1274
1284
  }
@@ -1321,7 +1331,7 @@ function getLroMethodBody(crate, indent, use, client, method) {
1321
1331
  const bodyFormat = helpers.convertResponseFormat(method.returns.type.type.format);
1322
1332
  use.add('azure_core::http', 'Method', 'RawResponse', 'Request', 'Url');
1323
1333
  use.add('azure_core::http::headers', 'RETRY_AFTER', 'X_MS_RETRY_AFTER_MS', 'RETRY_AFTER_MS');
1324
- use.add('azure_core::http::poller', 'get_retry_after', 'PollerResult', 'PollerState', 'PollerStatus', 'StatusMonitor as _');
1334
+ use.add('azure_core::http::poller', 'get_retry_after', 'PollerContinuation', 'PollerResult', 'PollerState', 'PollerStatus', 'StatusMonitor');
1325
1335
  if (pollingStepHeaderName !== undefined || method.finalResultStrategy.kind !== 'originalUri') {
1326
1336
  use.add('azure_core::http::headers', 'HeaderName');
1327
1337
  }
@@ -1331,24 +1341,13 @@ function getLroMethodBody(crate, indent, use, client, method) {
1331
1341
  const urlVar = helpers.getUniqueVarName(method.params, ['url', 'url_var']);
1332
1342
  let body = 'let options = options.unwrap_or_default().into_owned();\n';
1333
1343
  body += `${indent.get()}let pipeline = self.pipeline.clone();\n`;
1334
- body += `${indent.get()}let ${urlVarNeedsMut(paramGroups, method)}${urlVar} = self.${getEndpointFieldName(client)}.clone();\n`;
1344
+ body += `${indent.get()}let ${urlVarNeedsMut(paramGroups, method)}${urlVar} = self.${client.endpoint.name}.clone();\n`;
1335
1345
  body += constructUrl(indent, use, method, paramGroups, urlVar);
1336
1346
  if (paramGroups.apiVersion) {
1337
1347
  body += `${indent.get()}let ${paramGroups.apiVersion.name} = ${getHeaderPathQueryParamValue(use, paramGroups.apiVersion, true, true)}.clone();\n`;
1338
1348
  }
1339
1349
  // we call this eagerly so that we have access to the request var name
1340
1350
  const initialRequestResult = constructRequest(indent, use, method, paramGroups, true, urlVar, true, false);
1341
- const applyApiVersionParam = function (indent, paramGroups, newLinkVarName, existingLinkVarAccessor) {
1342
- var _a;
1343
- if (((_a = paramGroups.apiVersion) === null || _a === void 0 ? void 0 : _a.kind) === 'queryScalar') {
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`;
1349
- }
1350
- return '';
1351
- };
1352
1351
  const declareRequest = function (indent, use, method, paramGroups, requestVarName, linkExpr, forceMut, optionsPrefix) {
1353
1352
  let mutRequest = '';
1354
1353
  // if the only header is optional Content-Type it will not be used
@@ -1359,48 +1358,46 @@ function getLroMethodBody(crate, indent, use, client, method) {
1359
1358
  return `${indent.get()}let ${mutRequest}${requestVarName} = Request::new(${linkExpr}, Method::Get);\n`
1360
1359
  + applyHeaderParams(indent, use, method, paramGroups, true, requestVarName, optionsPrefix);
1361
1360
  };
1362
- let stateVarName = 'next_link';
1363
- let stateVarType = 'Url';
1364
- let progressVarName = 'next_link';
1365
- let stateNextLinkAccessor = 'next_link';
1366
- let pollerStateMoreReturn = 'next_link';
1367
- let pollerStateInitialReturn = `${urlVar}.clone()`;
1368
- let pollerStatusInProgressReturn = 'next_link';
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, }`;
1376
- body += `${indent.get()}impl AsRef<str> for Progress{ fn as_ref(&self) -> &str{ self.next_link.as_ref() }}\n`;
1377
- stateVarName = 'state';
1378
- stateVarType = 'Progress';
1379
- progressVarName = 'progress';
1380
- stateNextLinkAccessor = 'progress.next_link';
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}';
1384
- }
1385
- body += `${indent.get()}Ok(${method.returns.type.name}::from_callback(\n`;
1386
- body += `${indent.push().get()}move |${stateVarName}: PollerState<${stateVarType}>, poller_options| {\n`;
1387
- body += `${indent.push().get()}let (mut ${initialRequestResult.requestVarName}, ${progressVarName}) = ${helpers.buildMatch(indent, stateVarName, [{
1388
- pattern: `PollerState::More(${progressVarName})`,
1361
+ body += `${indent.get()}Ok(${method.returns.type.name}::new(\n`;
1362
+ body += `${indent.push().get()}move |poller_state: PollerState, poller_options| {\n`;
1363
+ body += `${indent.push().get()}let (mut ${initialRequestResult.requestVarName}, continuation) = ${helpers.buildMatch(indent, 'poller_state', [{
1364
+ pattern: `PollerState::More(continuation)`,
1389
1365
  body: (indent) => {
1390
- return applyApiVersionParam(indent, paramGroups, 'next_link', stateNextLinkAccessor)
1391
- + declareRequest(indent, use, method, paramGroups, initialRequestResult.requestVarName, 'next_link.clone()')
1392
- + `${indent.get()}(${initialRequestResult.requestVarName}, ${pollerStateMoreReturn})\n`;
1366
+ var _a, _b;
1367
+ const mutNextLink = ((_a = paramGroups.apiVersion) === null || _a === void 0 ? void 0 : _a.kind) === 'queryScalar' ? 'mut ' : '';
1368
+ const continuationMatchExpr = (!paramGroups.body && paramGroups.partialBody.length === 0) ? 'continuation.clone()' : 'continuation';
1369
+ let body = `${indent.get()}let (${mutNextLink}next_link, final_link) = ${helpers.buildMatch(indent, continuationMatchExpr, [{
1370
+ pattern: 'PollerContinuation::Links { next_link, final_link }',
1371
+ body: (indent) => `${indent.get()}(next_link, final_link)\n`,
1372
+ }, {
1373
+ pattern: '_',
1374
+ body: (indent) => `${indent.get()}unreachable!()\n`,
1375
+ }])};\n`;
1376
+ if (((_b = paramGroups.apiVersion) === null || _b === void 0 ? void 0 : _b.kind) === 'queryScalar') {
1377
+ use.add('azure_core::http', 'UrlExt');
1378
+ body += `${indent.get()}let mut query_builder = next_link.query_builder();\n`;
1379
+ body += `${indent.get()}query_builder.set_pair("${paramGroups.apiVersion.key}", &${paramGroups.apiVersion.name});\n`;
1380
+ body += `${indent.get()}query_builder.build();\n`;
1381
+ }
1382
+ body += declareRequest(indent, use, method, paramGroups, initialRequestResult.requestVarName, 'next_link.clone()');
1383
+ body += `${indent.get()}(${initialRequestResult.requestVarName}, PollerContinuation::Links { next_link, final_link })\n`;
1384
+ return body;
1393
1385
  },
1394
1386
  }, {
1395
1387
  pattern: 'PollerState::Initial',
1396
1388
  body: (indent) => {
1397
1389
  let body = initialRequestResult.content;
1398
- body += `${indent.get()}(${initialRequestResult.requestVarName}, ${pollerStateInitialReturn})\n`;
1390
+ body += `${indent.get()}(${initialRequestResult.requestVarName}, PollerContinuation::Links { next_link: url.clone(), final_link: None, })\n`;
1399
1391
  return body;
1400
1392
  },
1401
1393
  }])};\n`;
1402
1394
  body += `${indent.get()}let ctx = poller_options.context.clone();\n`;
1403
1395
  body += `${indent.get()}let pipeline = pipeline.clone();\n`;
1396
+ if (method.finalResultStrategy.kind === 'header' && method.finalResultStrategy.headerName !== pollingStepHeaderName) {
1397
+ // Avoid moving the poller closure's captured `url` into the async block.
1398
+ // We shadow it with a per-iteration clone so the outer closure can remain `Fn`.
1399
+ body += `${indent.get()}let url = url.clone();\n`;
1400
+ }
1404
1401
  if (method.finalResultStrategy.kind === 'originalUri') {
1405
1402
  body += `${indent.get()}let final_link = url.clone();\n`;
1406
1403
  for (const headerParam of paramGroups.header.filter(h => h.type.kind !== 'literal' && !isOptionalContentTypeHeader(h))) {
@@ -1450,7 +1447,7 @@ function getLroMethodBody(crate, indent, use, client, method) {
1450
1447
  if (isArmPutLro || isArmPatchLro) {
1451
1448
  body += 'let original_url = url.clone();\n';
1452
1449
  }
1453
- body += `${indent.get()}async move {\n`;
1450
+ body += `${indent.get()}Box::pin(async move {\n`;
1454
1451
  body += `${indent.push().get()}let rsp = pipeline.send(&ctx, &mut ${initialRequestResult.requestVarName}, ${getPipelineOptions(indent, use, method)}).await?;\n`;
1455
1452
  const needsMutBody = isArmPutLro || isArmPatchLro || isArmPostLro || isArmDeleteLro;
1456
1453
  body += `${indent.get()}let (status, headers, ${needsMutBody ? 'mut' : ''} body) = rsp.deconstruct();\n`;
@@ -1465,20 +1462,32 @@ function getLroMethodBody(crate, indent, use, client, method) {
1465
1462
  body += `${indent.pop().get()}}\n`;
1466
1463
  }
1467
1464
  if (pollingStepHeaderName !== undefined) {
1468
- body += `${indent.get()}let next_link = ${helpers.buildMatch(indent, `headers.get_optional_string(&HeaderName::from_static("${pollingStepHeaderName}"))`, [{
1469
- pattern: 'Some(operation_location)',
1470
- body: (indent) => {
1471
- return `${indent.get()}Url::parse(&operation_location)?\n`;
1472
- }
1473
- }, {
1474
- pattern: 'None',
1475
- body: (indent) => {
1476
- return `${indent.get()}${stateNextLinkAccessor}`;
1477
- }
1478
- }])};\n`;
1465
+ body += `${indent.get()}let continuation = ${helpers.buildIfBlock(indent, {
1466
+ condition: `let Some(operation_location) = headers.get_optional_string(&HeaderName::from_static("${pollingStepHeaderName}"))`,
1467
+ body: (indent) => {
1468
+ let body = `${indent.get()}let next_link = Url::parse(&operation_location)?;\n`;
1469
+ body += `${indent.get()}${helpers.buildMatch(indent, 'continuation', [{
1470
+ pattern: 'PollerContinuation::Links { final_link, .. }',
1471
+ body: (indent) => `${indent.get()}PollerContinuation::Links { next_link, final_link }\n`,
1472
+ }, {
1473
+ pattern: '_',
1474
+ body: (indent) => `${indent.get()}unreachable!()\n`,
1475
+ }])}\n`;
1476
+ return body;
1477
+ }
1478
+ }, {
1479
+ body: (indent) => `${indent.get()}continuation\n`
1480
+ })};\n`;
1479
1481
  }
1480
1482
  if (isArmPutLro || isArmPatchLro) {
1481
1483
  use.add('azure_core::http', 'StatusCode');
1484
+ body += `${indent.get()}let next_link = ${helpers.buildMatch(indent, '&continuation', [{
1485
+ pattern: 'PollerContinuation::Links { next_link, .. }',
1486
+ body: (indent) => `${indent.get()}next_link\n`,
1487
+ }, {
1488
+ pattern: '_',
1489
+ body: (indent) => `${indent.get()}unreachable!()\n`,
1490
+ }])};\n`;
1482
1491
  body += `${indent.get()}let mut final_body = None;\n`;
1483
1492
  body += `${indent.get()}if status == StatusCode::Ok && next_link.as_str() == original_url.as_str() {\n`;
1484
1493
  body += `${indent.push().get()}final_body = Some(body);\n`;
@@ -1486,16 +1495,28 @@ function getLroMethodBody(crate, indent, use, client, method) {
1486
1495
  body += `${indent.pop().get()}}\n`;
1487
1496
  }
1488
1497
  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
- }
1498
+ body += `${indent.get()}let continuation = ${helpers.buildIfBlock(indent, {
1499
+ condition: `let Some(final_link) = headers.get_optional_string(&HeaderName::from_static("${method.finalResultStrategy.headerName}"))`,
1500
+ body: (indent) => {
1501
+ let body = `${indent.get()}let final_link = Url::parse(&final_link)?;\n`;
1502
+ body += `${indent.get()}${helpers.buildMatch(indent, 'continuation', [{
1503
+ pattern: 'PollerContinuation::Links { next_link, .. }',
1504
+ body: (indent) => `${indent.get()}PollerContinuation::Links { next_link, final_link: Some(final_link) }\n`,
1505
+ }, {
1506
+ pattern: '_',
1507
+ body: (indent) => `${indent.get()}unreachable!()\n`,
1508
+ }])}\n`;
1509
+ return body;
1510
+ }
1511
+ }, {
1512
+ body: (indent) => `${indent.get()}continuation\n`
1513
+ })};\n`;
1514
+ body += `${indent.get()}let final_link = ${helpers.buildMatch(indent, '&continuation', [{
1515
+ pattern: 'PollerContinuation::Links { final_link, .. }',
1516
+ body: (indent) => `${indent.get()}final_link.clone().unwrap_or_else(|| url.clone())\n`,
1494
1517
  }, {
1495
- pattern: 'None',
1496
- body: (indent) => {
1497
- return `${indent.get()}progress.final_link`;
1498
- }
1518
+ pattern: '_',
1519
+ body: (indent) => `${indent.get()}unreachable!()\n`,
1499
1520
  }])};\n`;
1500
1521
  }
1501
1522
  body += `${indent.get()}let retry_after = get_retry_after(&headers, &[X_MS_RETRY_AFTER_MS, RETRY_AFTER_MS, RETRY_AFTER], &poller_options);\n`;
@@ -1524,7 +1545,7 @@ function getLroMethodBody(crate, indent, use, client, method) {
1524
1545
  const arms = [{
1525
1546
  pattern: `PollerStatus::InProgress`,
1526
1547
  body: (indent) => {
1527
- return `${indent.get()}response: rsp, retry_after, next: ${pollerStatusInProgressReturn}\n`;
1548
+ return `${indent.get()}response: rsp, retry_after, continuation\n`;
1528
1549
  },
1529
1550
  returns: 'PollerResult::InProgress'
1530
1551
  }];
@@ -1559,9 +1580,9 @@ function getLroMethodBody(crate, indent, use, client, method) {
1559
1580
  returns: 'PollerResult::Done'
1560
1581
  });
1561
1582
  body += `${indent.get()}Ok(${helpers.buildMatch(indent, 'res.status()', arms)})\n`;
1562
- body += `${indent.pop().get()}}\n`; // end async move
1583
+ body += `${indent.pop().get()}})\n`; // end async move
1563
1584
  body += `${indent.pop().get()}},\n`; // end move
1564
- body += `${indent.pop().get()} Some(options.method_options),))`; // end Ok/Poller::from_callback
1585
+ body += `${indent.pop().get()} Some(options.method_options),))`; // end Ok/Poller::new
1565
1586
  return body;
1566
1587
  }
1567
1588
  /**
@@ -1665,7 +1686,7 @@ function getHeaderPathQueryParamValue(use, param, fromSelf, neverBorrow, overrid
1665
1686
  default:
1666
1687
  strConv = '|i| i.to_string()';
1667
1688
  }
1668
- paramValue = `${param.name}.iter().map(${strConv}).collect::<Vec<String>>().join("${getCollectionDelimiter(param.format)}")`;
1689
+ paramValue = `${paramName}.iter().map(${strConv}).collect::<Vec<String>>().join("${getCollectionDelimiter(param.format)}")`;
1669
1690
  }
1670
1691
  }
1671
1692
  else {
@@ -1681,7 +1702,8 @@ function getHeaderPathQueryParamValue(use, param, fromSelf, neverBorrow, overrid
1681
1702
  mustBorrow = false;
1682
1703
  break;
1683
1704
  case 'decimal':
1684
- paramValue = `${param.name}.to_string()`;
1705
+ case 'Etag':
1706
+ paramValue = `${paramName}.to_string()`;
1685
1707
  break;
1686
1708
  case 'encodedBytes':
1687
1709
  paramValue = encodeBytes(paramType, paramName);
@@ -1690,7 +1712,7 @@ function getHeaderPathQueryParamValue(use, param, fromSelf, neverBorrow, overrid
1690
1712
  case 'scalar':
1691
1713
  if (isEnumString(paramType) && (helpers.isPathParameter(param) || helpers.isQueryParameter(param))) {
1692
1714
  // append_pair and path.replace() want a reference to the string
1693
- paramValue = `${paramName}.as_ref()`;
1715
+ paramValue = (param.location === 'client' && fromSelf) ? `${paramName}.as_str()` : `${paramName}.as_ref()`;
1694
1716
  // as_ref() elides the need to borrow
1695
1717
  mustBorrow = false;
1696
1718
  }
@@ -1705,7 +1727,7 @@ function getHeaderPathQueryParamValue(use, param, fromSelf, neverBorrow, overrid
1705
1727
  paramValue = `"${paramType.value}"`;
1706
1728
  break;
1707
1729
  case 'offsetDateTime':
1708
- paramValue = encodeDateTime(paramType, param.name);
1730
+ paramValue = encodeDateTime(paramType, paramName);
1709
1731
  break;
1710
1732
  default:
1711
1733
  throw new CodegenError('InternalError', `unhandled ${param.kind} param type kind ${paramType.kind}`);
@@ -1742,7 +1764,7 @@ function getCollectionDelimiter(format) {
1742
1764
  }
1743
1765
  /** returns true if the type isn't copyable thus needs to be cloned or borrowed */
1744
1766
  function nonCopyableType(type) {
1745
- const unwrappedType = shared.unwrapOption(type);
1767
+ const unwrappedType = utils.unwrapOption(type);
1746
1768
  switch (unwrappedType.kind) {
1747
1769
  case 'String':
1748
1770
  case 'Url':