@azure-tools/typespec-rust 0.41.5 → 0.42.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 (57) hide show
  1. package/README.md +39 -0
  2. package/dist/src/codegen/cargotoml.d.ts.map +1 -1
  3. package/dist/src/codegen/cargotoml.js +13 -3
  4. package/dist/src/codegen/cargotoml.js.map +1 -1
  5. package/dist/src/codegen/clients.d.ts.map +1 -1
  6. package/dist/src/codegen/clients.js +84 -186
  7. package/dist/src/codegen/clients.js.map +1 -1
  8. package/dist/src/codegen/codeGenerator.d.ts.map +1 -1
  9. package/dist/src/codegen/codeGenerator.js +8 -2
  10. package/dist/src/codegen/codeGenerator.js.map +1 -1
  11. package/dist/src/codegen/context.d.ts.map +1 -1
  12. package/dist/src/codegen/context.js +3 -2
  13. package/dist/src/codegen/context.js.map +1 -1
  14. package/dist/src/codegen/errors.d.ts.map +1 -1
  15. package/dist/src/codegen/fakes.d.ts +11 -0
  16. package/dist/src/codegen/fakes.d.ts.map +1 -0
  17. package/dist/src/codegen/fakes.js +431 -0
  18. package/dist/src/codegen/fakes.js.map +1 -0
  19. package/dist/src/codegen/headerTraits.js.map +1 -1
  20. package/dist/src/codegen/helpers.d.ts +3 -1
  21. package/dist/src/codegen/helpers.d.ts.map +1 -1
  22. package/dist/src/codegen/helpers.js.map +1 -1
  23. package/dist/src/codegen/mod.d.ts +3 -1
  24. package/dist/src/codegen/mod.d.ts.map +1 -1
  25. package/dist/src/codegen/mod.js +11 -5
  26. package/dist/src/codegen/mod.js.map +1 -1
  27. package/dist/src/codegen/models.js +3 -5
  28. package/dist/src/codegen/models.js.map +1 -1
  29. package/dist/src/codegen/parameters.d.ts +13 -0
  30. package/dist/src/codegen/parameters.d.ts.map +1 -0
  31. package/dist/src/codegen/parameters.js +64 -0
  32. package/dist/src/codegen/parameters.js.map +1 -0
  33. package/dist/src/codegen/use.d.ts.map +1 -1
  34. package/dist/src/codegen/use.js.map +1 -1
  35. package/dist/src/codemodel/client.d.ts +12 -0
  36. package/dist/src/codemodel/client.d.ts.map +1 -1
  37. package/dist/src/codemodel/client.js +1 -0
  38. package/dist/src/codemodel/client.js.map +1 -1
  39. package/dist/src/codemodel/crate.d.ts +2 -0
  40. package/dist/src/codemodel/crate.d.ts.map +1 -1
  41. package/dist/src/codemodel/crate.js +1 -0
  42. package/dist/src/codemodel/crate.js.map +1 -1
  43. package/dist/src/codemodel/customizations.d.ts.map +1 -1
  44. package/dist/src/codemodel/method.d.ts.map +1 -1
  45. package/dist/src/codemodel/types.d.ts.map +1 -1
  46. package/dist/src/codemodel/types.js +1 -1
  47. package/dist/src/codemodel/types.js.map +1 -1
  48. package/dist/src/lib.d.ts +2 -0
  49. package/dist/src/lib.d.ts.map +1 -1
  50. package/dist/src/lib.js +6 -0
  51. package/dist/src/lib.js.map +1 -1
  52. package/dist/src/tcgcadapter/adapter.d.ts +8 -0
  53. package/dist/src/tcgcadapter/adapter.d.ts.map +1 -1
  54. package/dist/src/tcgcadapter/adapter.js +137 -53
  55. package/dist/src/tcgcadapter/adapter.js.map +1 -1
  56. package/dist/src/utils/utils.js.map +1 -1
  57. package/package.json +36 -36
package/README.md CHANGED
@@ -1,6 +1,45 @@
1
1
  # TypeSpec Rust Generator
2
2
 
3
3
  The TypeSpec Rust generator is intended to be used with the TypeSpec compiler.
4
+ Generated crates should forward their `default` feature to `azure_core/default`
5
+ by setting `default = ["azure_core/default"]` in the `[features]` section of
6
+ `Cargo.toml`. Declare the `azure_core` dependency with `default-features = false`,
7
+ including in `[workspace.dependencies]` when inherited from a workspace.
8
+ Together, these settings enable the default HTTP transport while allowing callers
9
+ to disable it with `--no-default-features`.
10
+
11
+ ## Azure Resource Manager
12
+
13
+ ARM services are detected from TypeSpec metadata. Generated crates enable
14
+ `azure_core/unstable_resource_manager` and use Public cloud by default.
15
+ For other clouds, pass the same cloud configuration to the credential and client.
16
+ See the [default-cloud][default-cloud] and [custom-cloud][custom-cloud] examples.
17
+
18
+ Generated pagers and pollers use shared Azure Core helpers, keeping paging and
19
+ long-running operation behavior consistent with ARM conventions.
20
+
21
+ [default-cloud]: test/other/resource_manager/examples/default_cloud.rs
22
+ [custom-cloud]: test/other/resource_manager/examples/custom_cloud.rs
23
+
24
+ ## Fake servers
25
+
26
+ Fake server generation is disabled by default. Opt in for data-plane or Resource
27
+ Manager clients with the emitter option:
28
+
29
+ ```yaml
30
+ options:
31
+ "@azure-tools/typespec-rust":
32
+ generate-fakes: true
33
+ ```
34
+
35
+ Enable the generated crate's `unstable_fake` Cargo feature (which also enables
36
+ `test`), implement its `clients::fake::<Name>Server` trait, and construct the client
37
+ with `with_fake()`. No credential is needed. Fakes use the normal client pipeline,
38
+ pagers, and pollers. See the offline [Key Vault secrets example][secrets-fake] and
39
+ [Resource Manager LRO example][arm-fake].
40
+
41
+ [secrets-fake]: test/sdk/keyvault_secrets/examples/secret_client_fake.rs
42
+ [arm-fake]: test/other/resource_manager/examples/fake.rs
4
43
 
5
44
  ## Contributing
6
45
 
@@ -1 +1 @@
1
- {"version":3,"file":"cargotoml.d.ts","sourceRoot":"","sources":["../../../src/codegen/cargotoml.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,IAAI,MAAM,uBAAuB,CAAC;AAE9C;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,GAAG,MAAM,CAkBvD"}
1
+ {"version":3,"file":"cargotoml.d.ts","sourceRoot":"","sources":["../../../src/codegen/cargotoml.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,IAAI,MAAM,uBAAuB,CAAC;AAE9C;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,GAAG,MAAM,CA4BvD"}
@@ -14,15 +14,25 @@ export function emitCargoToml(crate) {
14
14
  content += 'edition.workspace = true\n';
15
15
  content += 'license.workspace = true\n';
16
16
  content += 'repository.workspace = true\n';
17
- content += 'rust-version.workspace = true\n\n';
17
+ content += 'rust-version.workspace = true\n';
18
+ content += 'exclude.workspace = true\n\n';
18
19
  content += '[features]\n';
19
20
  content += 'default = ["azure_core/default"]\n';
21
+ if (crate.generateFakes) {
22
+ content += 'test = ["azure_core/test"]\n';
23
+ content += 'unstable_fake = ["test", "azure_core/unstable_fake"]\n';
24
+ }
20
25
  if (crate.dependencies.length > 0) {
21
26
  content += '\n[dependencies]\n';
22
27
  for (const dependency of crate.dependencies) {
23
28
  // dependency versions are managed by the workspace's Cargo.toml file
24
- const features = dependency.features.length > 0 ? `, features = [${dependency.features.sort().map(f => `"${f}"`).join(', ')}]` : '';
25
- content += `${dependency.name} = { workspace = true${features} }\n`;
29
+ const featureNames = new Set(dependency.features);
30
+ if (dependency.name === 'azure_core' && crate.type === 'azure-arm') {
31
+ featureNames.add('unstable_resource_manager');
32
+ }
33
+ const features = featureNames.size > 0 ? `, features = [${[...featureNames].sort().map(f => `"${f}"`).join(', ')}]` : '';
34
+ const defaults = dependency.name === 'azure_core' ? ', default-features = false' : '';
35
+ content += `${dependency.name} = { workspace = true${defaults}${features} }\n`;
26
36
  }
27
37
  }
28
38
  return content;
@@ -1 +1 @@
1
- {"version":3,"file":"cargotoml.js","sourceRoot":"","sources":["../../../src/codegen/cargotoml.ts"],"names":[],"mappings":"AAAA;;;+FAG+F;AAI/F;;;;;GAKG;AACH,MAAM,UAAU,aAAa,CAAC,KAAiB;IAC7C,IAAI,OAAO,GAAG,sBAAsB,KAAK,CAAC,IAAI,iBAAiB,KAAK,CAAC,OAAO,KAAK,CAAC;IAClF,OAAO,IAAI,4BAA4B,CAAC;IACxC,OAAO,IAAI,4BAA4B,CAAC;IACxC,OAAO,IAAI,4BAA4B,CAAC;IACxC,OAAO,IAAI,+BAA+B,CAAC;IAC3C,OAAO,IAAI,mCAAmC,CAAC;IAC/C,OAAO,IAAI,cAAc,CAAC;IAC1B,OAAO,IAAI,oCAAoC,CAAC;IAChD,IAAI,KAAK,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAClC,OAAO,IAAI,oBAAoB,CAAC;QAChC,KAAK,MAAM,UAAU,IAAI,KAAK,CAAC,YAAY,EAAE,CAAC;YAC5C,qEAAqE;YACrE,MAAM,QAAQ,GAAG,UAAU,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,iBAAiB,UAAU,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;YACpI,OAAO,IAAI,GAAG,UAAU,CAAC,IAAI,wBAAwB,QAAQ,MAAM,CAAC;QACtE,CAAC;IACH,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC"}
1
+ {"version":3,"file":"cargotoml.js","sourceRoot":"","sources":["../../../src/codegen/cargotoml.ts"],"names":[],"mappings":"AAAA;;;+FAG+F;AAI/F;;;;;GAKG;AACH,MAAM,UAAU,aAAa,CAAC,KAAiB;IAC7C,IAAI,OAAO,GAAG,sBAAsB,KAAK,CAAC,IAAI,iBAAiB,KAAK,CAAC,OAAO,KAAK,CAAC;IAClF,OAAO,IAAI,4BAA4B,CAAC;IACxC,OAAO,IAAI,4BAA4B,CAAC;IACxC,OAAO,IAAI,4BAA4B,CAAC;IACxC,OAAO,IAAI,+BAA+B,CAAC;IAC3C,OAAO,IAAI,iCAAiC,CAAC;IAC7C,OAAO,IAAI,8BAA8B,CAAC;IAC1C,OAAO,IAAI,cAAc,CAAC;IAC1B,OAAO,IAAI,oCAAoC,CAAC;IAChD,IAAI,KAAK,CAAC,aAAa,EAAE,CAAC;QACxB,OAAO,IAAI,8BAA8B,CAAC;QAC1C,OAAO,IAAI,wDAAwD,CAAC;IACtE,CAAC;IACD,IAAI,KAAK,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAClC,OAAO,IAAI,oBAAoB,CAAC;QAChC,KAAK,MAAM,UAAU,IAAI,KAAK,CAAC,YAAY,EAAE,CAAC;YAC5C,qEAAqE;YACrE,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;YAClD,IAAI,UAAU,CAAC,IAAI,KAAK,YAAY,IAAI,KAAK,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;gBACnE,YAAY,CAAC,GAAG,CAAC,2BAA2B,CAAC,CAAC;YAChD,CAAC;YACD,MAAM,QAAQ,GAAG,YAAY,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,iBAAiB,CAAC,GAAG,YAAY,CAAC,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;YACzH,MAAM,QAAQ,GAAG,UAAU,CAAC,IAAI,KAAK,YAAY,CAAC,CAAC,CAAC,4BAA4B,CAAC,CAAC,CAAC,EAAE,CAAC;YACtF,OAAO,IAAI,GAAG,UAAU,CAAC,IAAI,wBAAwB,QAAQ,GAAG,QAAQ,MAAM,CAAC;QACjF,CAAC;IACH,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC"}
@@ -1 +1 @@
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,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC;CAC1B;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,IAAI,CAAC,eAAe,GAAG,aAAa,GAAG,SAAS,CAwYnF"}
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;AAK9C,yBAAyB;AACzB,MAAM,WAAW,aAAa;IAC5B,iCAAiC;IACjC,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IAE/B,uCAAuC;IACvC,OAAO,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC;CAC1B;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,IAAI,CAAC,eAAe,GAAG,aAAa,GAAG,SAAS,CA0VnF"}
@@ -10,6 +10,8 @@ import queryString from 'query-string';
10
10
  import { Use } from './use.js';
11
11
  import * as rust from '../codemodel/index.js';
12
12
  import * as utils from '../utils/utils.js';
13
+ import { emitFakeCapture } from './fakes.js';
14
+ import { methodParameters, requiredConstructorParameters, supplementalEndpoint } from './parameters.js';
13
15
  /**
14
16
  * emits the content for all client files
15
17
  *
@@ -88,46 +90,13 @@ export function emitClients(module) {
88
90
  if (crate.type === 'azure-arm') {
89
91
  use.add('azure_core', 'Error');
90
92
  use.add('azure_core::error', 'ErrorKind');
91
- use.add('crate', 'Audience');
92
- // for ARM, derive endpoint and scope from cloud config
93
- use.add('azure_core::cloud', 'CloudConfiguration');
93
+ use.add('azure_core::cloud::resource_manager', 'CloudConfigurationExt as _');
94
94
  use.add('azure_core::http::policies', 'auth::BearerTokenAuthorizationPolicy', 'Policy');
95
- body += `${indent.push().get()}let (endpoint, scope) = ${helpers.buildMatch(indent, 'options.client_options.cloud.as_deref()', [
96
- {
97
- pattern: 'Some(CloudConfiguration::AzurePublic)',
98
- body: (indent) => `${indent.get()}(\n`
99
- + `${indent.push().get()}"https://management.azure.com".to_string(),`
100
- + `\n${indent.get()}"https://management.azure.com/.default".to_string(),`
101
- + `\n${indent.pop().get()})\n`
102
- },
103
- {
104
- pattern: 'Some(CloudConfiguration::AzureGovernment)',
105
- body: (indent) => `${indent.get()}`
106
- + `(\n${indent.push().get()}"https://management.usgovcloudapi.net".to_string(),`
107
- + `\n${indent.get()}"https://management.usgovcloudapi.net/.default".to_string(),`
108
- + `\n${indent.pop().get()})\n`
109
- },
110
- {
111
- pattern: 'Some(CloudConfiguration::AzureChina)',
112
- body: (indent) => `${indent.get()}`
113
- + `(\n${indent.push().get()}"https://management.chinacloudapi.cn".to_string(),`
114
- + `\n${indent.get()}"https://management.chinacloudapi.cn/.default".to_string(),`
115
- + `\n${indent.pop().get()})\n`
116
- },
117
- {
118
- pattern: 'Some(CloudConfiguration::Custom(custom))',
119
- body: (indent) => `${indent.get()}{\n`
120
- + `${indent.push().get()}let audience = custom.audiences.get::<Audience>().ok_or_else(|| { Error::new(ErrorKind::Credential, "missing custom cloud configuration audience")})?;\n`
121
- + `${indent.get()}(audience.to_string(), format!("{}/.default", audience))\n`
122
- + `${indent.pop().get()}}\n`
123
- },
124
- {
125
- pattern: '_',
126
- body: (indent) => `${indent.get()}unreachable!()\n`
127
- },
128
- ])};\n`;
129
- body += `${indent.get()}let endpoint = Url::parse(&endpoint)?;\n`;
130
- body += `${indent.get()}let auth_policy: Arc<dyn Policy> = Arc::new(BearerTokenAuthorizationPolicy::new(credential, vec![scope]));\n`;
95
+ body += `${indent.push().get()}let cloud = options.client_options.cloud.as_deref().unwrap_or_default();\n`;
96
+ body += `${indent.get()}let endpoint = cloud.endpoint().ok_or_else(|| Error::new(ErrorKind::Other, "missing Resource Manager endpoint"))?;\n`;
97
+ body += `${indent.get()}let endpoint = Url::parse(endpoint)?;\n`;
98
+ body += `${indent.get()}let scope = cloud.default_scope()?.into_owned();\n`;
99
+ body += `${indent.get()}let auth_policy: Arc<dyn Policy> = Arc::new(BearerTokenAuthorizationPolicy::new(credential, vec![scope]).with_options((&options.client_options).into()));\n`;
131
100
  hasAuthPolicy = true;
132
101
  }
133
102
  else {
@@ -138,21 +107,7 @@ export function emitClients(module) {
138
107
  condition: `!${endpointParamName}.scheme().starts_with("http")`,
139
108
  body: (indent) => `${indent.get()}return Err(azure_core::Error::with_message(azure_core::error::ErrorKind::Other, format!("{${endpointParamName}} must use http(s)")));\n`,
140
109
  })}`;
141
- // construct the supplemental path and join it to the endpoint
142
- if (client.constructable.endpoint) {
143
- const supplementalEndpoint = client.constructable.endpoint;
144
- if (supplementalEndpoint.parameters.length > 0) {
145
- body += `${indent.get()}let mut host = String::from("${supplementalEndpoint.path}");\n`;
146
- for (const param of supplementalEndpoint.parameters) {
147
- body += `${indent.get()}host = host.replace("{${param.segment}}", ${getClientSupplementalEndpointParamValue(param)});\n`;
148
- }
149
- body += `${indent.push().get()}${endpointParamName} = ${endpointParamName}.join(&host)?;\n`;
150
- }
151
- else {
152
- // there are no params for the supplemental host, so just append it
153
- body += `${indent.push().get()}${endpointParamName} = ${endpointParamName}.join("${supplementalEndpoint.path}")?;\n`;
154
- }
155
- }
110
+ body += supplementalEndpoint(indent, endpointParamName, client.constructable.endpoint);
156
111
  // if there's a credential param, create the necessary auth policy
157
112
  const authPolicy = getAuthPolicy(constructor, use);
158
113
  if (authPolicy) {
@@ -548,11 +503,7 @@ function getParamsBlockDocComment(indent, callable) {
548
503
  */
549
504
  function getConstructorParamsSig(params, options, use) {
550
505
  const paramsSig = new Array();
551
- for (const param of params) {
552
- if (param.optional) {
553
- // optional params will be in the client options type
554
- continue;
555
- }
506
+ for (const param of requiredConstructorParameters(params)) {
556
507
  use.addForType(param.type);
557
508
  paramsSig.push(`${param.name}: ${helpers.getTypeDeclaration(param.type)}`);
558
509
  }
@@ -582,34 +533,18 @@ function getMethodParamsCountAndSig(method, use) {
582
533
  }
583
534
  }
584
535
  else {
585
- const emittedGroups = new Set();
586
536
  for (const param of method.params) {
587
- if (param.group) {
588
- if (!emittedGroups.has(param.group.name)) {
589
- emittedGroups.add(param.group.name);
590
- // required parameter group appears as a single struct parameter in the method signature
591
- paramsSig.push(`${param.group.name}: ${helpers.getTypeDeclaration(param.group.type, 'anonymous')}`);
592
- ++count;
593
- }
594
- continue;
595
- }
596
537
  const paramType = helpers.unwrapType(param.type);
597
- if (paramType.kind === 'literal') {
598
- // literal params are embedded directly in the code (e.g. accept header param)
599
- continue;
600
- }
601
- else if (paramType.kind === 'enumValue') {
602
- // enum values are treated like literals, we just need to use their type
538
+ if (!param.group && paramType.kind === 'enumValue') {
603
539
  use.addForType(paramType.type);
604
- continue;
605
- }
606
- // don't add client or optional params to the method param sig
607
- if (param.location === 'method' && !param.optional) {
608
- use.addForType(param.kind === 'partialBody' ? param.paramType : param.type);
609
- paramsSig.push(`${param.name}: ${formatParamTypeName(param)}`);
610
- ++count;
611
540
  }
612
541
  }
542
+ for (const param of methodParameters(method)) {
543
+ use.addForType(param.type);
544
+ const grouped = method.params.some(p => { var _a; return ((_a = p.group) === null || _a === void 0 ? void 0 : _a.name) === param.name; });
545
+ paramsSig.push(`${param.name}: ${param.mut ? 'mut ' : ''}${helpers.getTypeDeclaration(param.type, grouped ? 'anonymous' : undefined)}`);
546
+ ++count;
547
+ }
613
548
  paramsSig.push(`${method.options.name}: ${helpers.getTypeDeclaration(method.options.type, 'anonymous')}`);
614
549
  ++count;
615
550
  }
@@ -673,7 +608,7 @@ function getAuthPolicy(ctor, use) {
673
608
  for (const scope of arcTokenCred.scopes) {
674
609
  scopes.push(`"${scope}"`);
675
610
  }
676
- return `let auth_policy: Arc<dyn Policy> = Arc::new(BearerTokenAuthorizationPolicy::new(credential, vec![${scopes.join(', ')}]));`;
611
+ return `let auth_policy: Arc<dyn Policy> = Arc::new(BearerTokenAuthorizationPolicy::new(credential, vec![${scopes.join(', ')}]).with_options((&options.client_options).into()));`;
677
612
  }
678
613
  }
679
614
  return undefined;
@@ -812,10 +747,10 @@ function getMethodParamGroup(method) {
812
747
  };
813
748
  }
814
749
  /**
815
- * wraps the emitted code emitted by setter in a "let Some" block
750
+ * wraps the code emitted by setter in a presence check
816
751
  * if the parameter is optional, else the value of setter is returned.
817
752
  *
818
- * NOTE: for optional params, by convention, we'll create a local named param.name.
753
+ * NOTE: for optional non-constant params, we'll create a local named param.name.
819
754
  * setter MUST reference by param.name so it works for optional and required params.
820
755
  *
821
756
  * @param indent the indentation helper currently in scope
@@ -834,8 +769,9 @@ function getParamValueHelper(indent, param, setter, optionsPrefix = 'options.')
834
769
  asRefOrClone = '.as_ref()';
835
770
  }
836
771
  // optional params are in the unwrapped options local var
772
+ const paramRef = `${param.location === 'client' ? 'self.' : optionsPrefix}${param.name}`;
837
773
  const op = indent.get() + helpers.buildIfBlock(indent, {
838
- condition: `let Some(${param.name}) = ${param.location === 'client' ? 'self.' : optionsPrefix}${param.name}${asRefOrClone}`,
774
+ condition: param.type.kind === 'enumValue' ? `${paramRef}.is_some()` : `let Some(${param.name}) = ${paramRef}${asRefOrClone}`,
839
775
  body: setter,
840
776
  });
841
777
  return op + '\n';
@@ -1280,6 +1216,7 @@ function getAsyncMethodBody(indent, use, client, method) {
1280
1216
  const paramGroups = getMethodParamGroup(method);
1281
1217
  let body = checkEmptyRequiredPathParams(indent, paramGroups.path);
1282
1218
  body += 'let options = options.unwrap_or_default();\n';
1219
+ body += emitFakeCapture(client, method);
1283
1220
  body += `${indent.get()}let ctx = options.method_options.context.to_borrowed();\n`;
1284
1221
  body += `${indent.get()}let ${urlVarNeedsMut(paramGroups, method)}${urlVarName} = self.${client.endpoint.name}.clone();\n`;
1285
1222
  body += constructUrl(indent, use, method, paramGroups, urlVarName);
@@ -1412,7 +1349,8 @@ function getLroMonitorHelperStruct(indent: helpers.indentation, client: rust.Cli
1412
1349
  * @returns the contents of the method body
1413
1350
  */
1414
1351
  function getPageableMethodBody(indent, use, client, method) {
1415
- var _a, _b, _c;
1352
+ var _a, _b;
1353
+ var _c;
1416
1354
  use.add('azure_core::http', 'Method', 'Request', 'Url');
1417
1355
  use.add('azure_core::http::pager', 'PagerResult', 'PagerState');
1418
1356
  use.add('azure_core', 'Result');
@@ -1423,6 +1361,7 @@ function getPageableMethodBody(indent, use, client, method) {
1423
1361
  const pageableResponseHelperStruct = getPageableResponseHelperStruct(indent, client, method);
1424
1362
  let body = checkEmptyRequiredPathParams(indent, paramGroups.path);
1425
1363
  body += 'let options = options.unwrap_or_default().into_owned();\n';
1364
+ body += emitFakeCapture(client, method);
1426
1365
  body += `${indent.get()}let pipeline = self.pipeline.clone();\n`;
1427
1366
  body += `${indent.get()}let ${urlVarNeedsMut(paramGroups, method)}${urlVar} = self.${client.endpoint.name}.clone();\n`;
1428
1367
  body += constructUrl(indent, use, method, paramGroups, urlVar);
@@ -1547,7 +1486,7 @@ function getPageableMethodBody(indent, use, client, method) {
1547
1486
  use.add('azure_core', bodyFormat, 'http::RawResponse');
1548
1487
  body += `${indent.get()}let (status, headers, body) = rsp.deconstruct();\n`;
1549
1488
  const deserialize = `${bodyFormat}::from_${bodyFormat}`;
1550
- body += `${indent.get()}let res: ${(_b = pageableResponseHelperStruct === null || pageableResponseHelperStruct === void 0 ? void 0 : pageableResponseHelperStruct.typeName) !== null && _b !== void 0 ? _b : helpers.getTypeDeclaration(helpers.unwrapType(method.returns.type))} = ${deserialize}(&body)?;\n`;
1489
+ body += `${indent.get()}let res: ${(_c = pageableResponseHelperStruct === null || pageableResponseHelperStruct === void 0 ? void 0 : pageableResponseHelperStruct.typeName) !== null && _c !== void 0 ? _c : helpers.getTypeDeclaration(helpers.unwrapType(method.returns.type))} = ${deserialize}(&body)?;\n`;
1551
1490
  body += `${indent.get()}let rsp = RawResponse::from_bytes(status, headers, body).into();\n`;
1552
1491
  }
1553
1492
  if (method.strategy) {
@@ -1615,7 +1554,7 @@ function getPageableMethodBody(indent, use, client, method) {
1615
1554
  // non-continuation case, so we don't need to worry about next links, continuation tokens, etc...
1616
1555
  body += `${indent.get()}Ok(PagerResult::Done { response: rsp.into() })\n`;
1617
1556
  }
1618
- if (((_c = method.strategy) === null || _c === void 0 ? void 0 : _c.kind) === 'nextLink') {
1557
+ if (((_b = method.strategy) === null || _b === void 0 ? void 0 : _b.kind) === 'nextLink') {
1619
1558
  body += `${indent.pop().get()}}\n`;
1620
1559
  }
1621
1560
  body += `${indent.pop().get()}})\n`; // end Box::pin(async move {
@@ -1633,8 +1572,60 @@ function getPageableMethodBody(indent, use, client, method) {
1633
1572
  * @param method the method for the body to build
1634
1573
  * @returns the contents of the method body
1635
1574
  */
1575
+ function getResourceManagerLroMethodBody(crate, indent, use, client, method) {
1576
+ use.add('azure_core::http', 'Method', 'Request');
1577
+ use.addForType(helpers.unwrapType(method.returns.type));
1578
+ use.add('azure_core::http::poller::resource_manager', 'new_poller');
1579
+ const params = getMethodParamGroup(method);
1580
+ const url = helpers.getUniqueVarName(method.params, ['url', 'url_var']);
1581
+ let body = 'let options = options.unwrap_or_default().into_owned();\n';
1582
+ body += emitFakeCapture(client, method);
1583
+ body += `${indent.get()}let ${urlVarNeedsMut(params, method)}${url} = self.${client.endpoint.name}.clone();\n`;
1584
+ body += constructUrl(indent, use, method, params, url);
1585
+ const request = constructRequest(indent, use, method, params, false, url, false, params.body !== undefined || params.partialBody.length > 0);
1586
+ body += request.content;
1587
+ let finalState = 'None';
1588
+ const selection = method.resourceManagerFinalState;
1589
+ if (selection) {
1590
+ use.add('azure_core::http::poller::resource_manager', 'FinalStateVia');
1591
+ let callback = '';
1592
+ if (selection.selector === 'OperationLocation') {
1593
+ const path = selection.resultPath;
1594
+ callback = '( |response| {\n';
1595
+ if (path.length > 0) {
1596
+ crate.addDependency(new rust.CrateDependency('serde_json', ['raw_value']));
1597
+ use.add('azure_core', 'Bytes');
1598
+ use.add('azure_core::http', 'RawResponse');
1599
+ indent.push();
1600
+ for (let i = 0; i < path.length; ++i) {
1601
+ callback += `${indent.get()}#[derive(serde::Deserialize)]\n`;
1602
+ callback += `${indent.get()}struct ResultEnvelope${i}<'a> {\n`;
1603
+ callback += `${indent.push().get()}#[serde(borrow, rename = ${JSON.stringify(path[i])})]\n`;
1604
+ callback += `${indent.get()}value: ${i === path.length - 1 ? "&'a serde_json::value::RawValue" : `ResultEnvelope${i + 1}<'a>`},\n`;
1605
+ callback += `${indent.pop().get()}}\n`;
1606
+ }
1607
+ callback += `${indent.get()}let (status, headers, body) = response.deconstruct();\n`;
1608
+ callback += `${indent.get()}let bytes = Bytes::from(body);\n`;
1609
+ callback += `${indent.get()}let envelope: ResultEnvelope0<'_> = serde_json::from_slice(&bytes)?;\n`;
1610
+ callback += `${indent.get()}let result = bytes.slice_ref(envelope${'.value'.repeat(path.length)}.get().as_bytes());\n`;
1611
+ callback += `${indent.get()}Ok(RawResponse::from_bytes(status, headers, result).into())\n`;
1612
+ indent.pop();
1613
+ }
1614
+ else {
1615
+ callback += `${indent.get()}Ok(response.to_raw_response().into())\n`;
1616
+ }
1617
+ callback += `${indent.get()}})`;
1618
+ }
1619
+ finalState = `Some(FinalStateVia::${selection.selector}${callback})`;
1620
+ }
1621
+ body += `${indent.get()}Ok(new_poller(self.pipeline.clone(), ${request.requestVarName}, ${finalState}, Some(options.method_options)))\n`;
1622
+ return body;
1623
+ }
1636
1624
  function getLroMethodBody(crate, indent, use, client, method) {
1637
1625
  var _a;
1626
+ if (crate.type === 'azure-arm') {
1627
+ return getResourceManagerLroMethodBody(crate, indent, use, client, method);
1628
+ }
1638
1629
  let pollingStepHeaderName = undefined;
1639
1630
  for (const header of ['operation-location', 'azure-asyncoperation', 'location']) {
1640
1631
  if ((_a = method.responseHeaders) === null || _a === void 0 ? void 0 : _a.headers.some(h => h.header.toLowerCase() === header)) {
@@ -1654,6 +1645,7 @@ function getLroMethodBody(crate, indent, use, client, method) {
1654
1645
  const paramGroups = getMethodParamGroup(method);
1655
1646
  const urlVar = helpers.getUniqueVarName(method.params, ['url', 'url_var']);
1656
1647
  let body = 'let options = options.unwrap_or_default().into_owned();\n';
1648
+ body += emitFakeCapture(client, method);
1657
1649
  body += `${indent.get()}let pipeline = self.pipeline.clone();\n`;
1658
1650
  body += `${indent.get()}let ${urlVarNeedsMut(paramGroups, method)}${urlVar} = self.${client.endpoint.name}.clone();\n`;
1659
1651
  body += constructUrl(indent, use, method, paramGroups, urlVar);
@@ -1730,64 +1722,13 @@ function getLroMethodBody(crate, indent, use, client, method) {
1730
1722
  }
1731
1723
  }
1732
1724
  }
1733
- // Match an ARM PUT operation ("create or update"), which may have immediate 200 OK response with no headers and no poller status
1734
- const isArmPutLro = bodyFormat === 'json'
1735
- && method.httpMethod === 'put'
1736
- && method.returns.type.resultType !== undefined
1737
- && method.finalResultStrategy.kind === 'header'
1738
- && method.finalResultStrategy.headerName === 'azure-asyncoperation'
1739
- && pollingStepHeaderName === 'azure-asyncoperation'
1740
- && method.statusCodes.some(sc => sc == 200)
1741
- && method.statusCodes.some(sc => sc == 201);
1742
- // Match an ARM PATCH operation ("update"), which may have immediate 200 OK response with no headers and no poller status
1743
- const isArmPatchLro = bodyFormat === 'json'
1744
- && method.httpMethod === 'patch'
1745
- && method.returns.type.resultType !== undefined
1746
- && method.finalResultStrategy.kind === 'header'
1747
- && method.finalResultStrategy.headerName === 'location'
1748
- && pollingStepHeaderName === 'location'
1749
- && method.statusCodes.some(sc => sc == 200)
1750
- && method.statusCodes.some(sc => sc == 202);
1751
- // Match an ARM POST operation ("export"), which may have empty initial response
1752
- const isArmPostLro = bodyFormat === 'json'
1753
- && method.httpMethod === 'post'
1754
- && method.returns.type.resultType !== undefined
1755
- && method.finalResultStrategy.kind === 'header'
1756
- && method.finalResultStrategy.headerName === 'location'
1757
- && pollingStepHeaderName === 'azure-asyncoperation'
1758
- && method.statusCodes.some(sc => sc == 200)
1759
- && method.statusCodes.some(sc => sc == 202);
1760
- // Match an ARM DELETE operation, which may have empty responses and only communicate via status codes
1761
- const isArmDeleteLro = bodyFormat === 'json'
1762
- && method.httpMethod === 'delete'
1763
- && method.returns.type.resultType === undefined
1764
- && method.finalResultStrategy.kind === 'header'
1765
- && method.finalResultStrategy.headerName === 'location'
1766
- && pollingStepHeaderName === 'location'
1767
- && method.statusCodes.some(sc => sc == 200)
1768
- && method.statusCodes.some(sc => sc == 202)
1769
- && method.statusCodes.some(sc => sc == 204);
1770
- if (isArmPutLro || isArmPatchLro) {
1771
- body += 'let original_url = url.clone();\n';
1772
- }
1773
1725
  body += `${indent.get()}Box::pin(async move {\n`;
1774
1726
  if (fallibleInitialPollerRequest) {
1775
1727
  body += `${indent.push().get()}let (mut ${initialRequestResult.requestVarName}, continuation) = poller_request?;\n`;
1776
1728
  indent.pop();
1777
1729
  }
1778
1730
  body += `${indent.push().get()}let rsp = pipeline.send(&ctx, &mut ${initialRequestResult.requestVarName}, ${getPipelineOptions(indent, use, method)}).await?;\n`;
1779
- const needsMutBody = isArmPutLro || isArmPatchLro || isArmPostLro || isArmDeleteLro;
1780
- body += `${indent.get()}let (status, headers, ${needsMutBody ? 'mut' : ''} body) = rsp.deconstruct();\n`;
1781
- if (isArmPostLro || isArmDeleteLro) {
1782
- body += `${indent.get()}if body.is_empty() {\n`;
1783
- let emptyBodyExpr = '"{}"';
1784
- if (isArmDeleteLro) {
1785
- use.add('azure_core::http', 'StatusCode');
1786
- emptyBodyExpr = `if status == StatusCode::NoContent { "{\\"status\\":\\"Succeeded\\"}" } else { "{}" }`;
1787
- }
1788
- body += `${indent.push().get()}body = azure_core::http::response::ResponseBody::from_bytes(${emptyBodyExpr});\n`;
1789
- body += `${indent.pop().get()}}\n`;
1790
- }
1731
+ body += `${indent.get()}let (status, headers, body) = rsp.deconstruct();\n`;
1791
1732
  if (pollingStepHeaderName !== undefined) {
1792
1733
  body += `${indent.get()}let continuation = ${helpers.buildIfBlock(indent, {
1793
1734
  condition: `let Some(operation_location) = headers.get_optional_string(&HeaderName::from_static("${pollingStepHeaderName}"))`,
@@ -1806,21 +1747,6 @@ function getLroMethodBody(crate, indent, use, client, method) {
1806
1747
  body: (indent) => `${indent.get()}continuation\n`
1807
1748
  })};\n`;
1808
1749
  }
1809
- if (isArmPutLro || isArmPatchLro) {
1810
- use.add('azure_core::http', 'StatusCode');
1811
- body += `${indent.get()}let next_link = ${helpers.buildMatch(indent, '&continuation', [{
1812
- pattern: 'PollerContinuation::Links { next_link, .. }',
1813
- body: (indent) => `${indent.get()}next_link\n`,
1814
- }, {
1815
- pattern: '_',
1816
- body: (indent) => `${indent.get()}unreachable!()\n`,
1817
- }])};\n`;
1818
- body += `${indent.get()}let mut final_body = None;\n`;
1819
- body += `${indent.get()}if status == StatusCode::Ok && next_link.as_str() == original_url.as_str() {\n`;
1820
- body += `${indent.push().get()}final_body = Some(body);\n`;
1821
- body += `${indent.get()}body = azure_core::http::response::ResponseBody::from_bytes("{\\"status\\":\\"Succeeded\\"}");\n`;
1822
- body += `${indent.pop().get()}}\n`;
1823
- }
1824
1750
  if (method.finalResultStrategy.kind === 'header' && method.finalResultStrategy.headerName !== pollingStepHeaderName) { // separate link for picking up the result
1825
1751
  body += `${indent.get()}let continuation = ${helpers.buildIfBlock(indent, {
1826
1752
  condition: `let Some(final_link) = headers.get_optional_string(&HeaderName::from_static("${method.finalResultStrategy.headerName}"))`,
@@ -1854,10 +1780,7 @@ function getLroMethodBody(crate, indent, use, client, method) {
1854
1780
  body += `${indent.get()}let mut final_rsp: Option<RawResponse> = None;\n`;
1855
1781
  body += `if res.status() == PollerStatus::Succeeded {\n`;
1856
1782
  let responseBodyExpr = 'body.clone()';
1857
- if (isArmPutLro || isArmPatchLro) {
1858
- responseBodyExpr = 'if let Some(final_body) = final_body { final_body } else { body.clone() }';
1859
- }
1860
- else if (method.finalResultStrategy.propertyName !== undefined) {
1783
+ if (method.finalResultStrategy.propertyName !== undefined) {
1861
1784
  responseBodyExpr = 'body';
1862
1785
  if (bodyFormat === 'json') {
1863
1786
  crate.addDependency(new rust.CrateDependency('serde_json'));
@@ -1912,32 +1835,6 @@ function getLroMethodBody(crate, indent, use, client, method) {
1912
1835
  body += `${indent.pop().get()} Some(options.method_options),))`; // end Ok/Poller::new
1913
1836
  return body;
1914
1837
  }
1915
- /**
1916
- * contains the code to use when populating a client endpoint parameter value
1917
- * from a parameter of that type.
1918
- * @param param the param for which to get the value
1919
- * @returns the code to use for the param's value
1920
- */
1921
- function getClientSupplementalEndpointParamValue(param) {
1922
- let paramName = param.name;
1923
- if (param.optional) {
1924
- paramName = 'options.' + paramName;
1925
- }
1926
- const unwrappedType = helpers.unwrapType(param.type);
1927
- switch (unwrappedType.kind) {
1928
- case 'String':
1929
- return `&${paramName}`;
1930
- case 'enum':
1931
- return `${paramName}.as_ref()`;
1932
- case 'offsetDateTime':
1933
- case 'scalar':
1934
- return `&${paramName}.to_string()`;
1935
- case 'str':
1936
- return paramName;
1937
- default:
1938
- throw new CodegenError('InternalError', `unhandled ${param.kind} param type kind ${param.type.kind}`);
1939
- }
1940
- }
1941
1838
  /**
1942
1839
  * returns the code to use when populating a header/path/query value
1943
1840
  * from a parameter of that type. this will include any borrowing of
@@ -2058,6 +1955,7 @@ function getHeaderPathQueryParamValue(use, param, fromSelf, neverBorrow, overrid
2058
1955
  break;
2059
1956
  case 'literal':
2060
1957
  paramValue = `"${paramType.value}"`;
1958
+ mustBorrow = false;
2061
1959
  break;
2062
1960
  case 'offsetDateTime':
2063
1961
  paramValue = encodeDateTime(paramType, paramName);