@azure-tools/typespec-rust 0.24.1 → 0.26.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.
- package/dist/src/codegen/clients.d.ts.map +1 -1
- package/dist/src/codegen/clients.js +185 -119
- package/dist/src/codegen/clients.js.map +1 -1
- package/dist/src/codegen/context.d.ts.map +1 -1
- package/dist/src/codegen/context.js +3 -1
- package/dist/src/codegen/context.js.map +1 -1
- package/dist/src/codegen/enums.d.ts +2 -2
- package/dist/src/codegen/enums.js +173 -26
- package/dist/src/codegen/enums.js.map +1 -1
- package/dist/src/codegen/helpers.d.ts +10 -0
- package/dist/src/codegen/helpers.d.ts.map +1 -1
- package/dist/src/codegen/helpers.js +30 -4
- package/dist/src/codegen/helpers.js.map +1 -1
- package/dist/src/codegen/models.js +28 -23
- package/dist/src/codegen/models.js.map +1 -1
- package/dist/src/codemodel/client.d.ts +10 -8
- package/dist/src/codemodel/client.d.ts.map +1 -1
- package/dist/src/codemodel/client.js +1 -0
- package/dist/src/codemodel/client.js.map +1 -1
- package/dist/src/codemodel/crate.d.ts.map +1 -1
- package/dist/src/codemodel/crate.js +5 -2
- package/dist/src/codemodel/crate.js.map +1 -1
- package/dist/src/codemodel/types.d.ts +10 -13
- package/dist/src/codemodel/types.d.ts.map +1 -1
- package/dist/src/codemodel/types.js +4 -8
- package/dist/src/codemodel/types.js.map +1 -1
- package/dist/src/shared/shared.d.ts.map +1 -1
- package/dist/src/shared/shared.js +4 -1
- package/dist/src/shared/shared.js.map +1 -1
- package/dist/src/tcgcadapter/adapter.d.ts +9 -1
- package/dist/src/tcgcadapter/adapter.d.ts.map +1 -1
- package/dist/src/tcgcadapter/adapter.js +147 -79
- package/dist/src/tcgcadapter/adapter.js.map +1 -1
- package/package.json +8 -8
|
@@ -201,13 +201,20 @@ export function emitClients(crate) {
|
|
|
201
201
|
if (method.kind !== 'clientaccessor' && method.responseHeaders) {
|
|
202
202
|
body += getHeaderTraitDocComment(indent, crate, method);
|
|
203
203
|
}
|
|
204
|
+
const paramsInfo = getMethodParamsCountAndSig(method, use);
|
|
205
|
+
if (paramsInfo.count > 7) {
|
|
206
|
+
// clippy will by default warn on 7+ args in a method.
|
|
207
|
+
// note that this doesn't include self which is included
|
|
208
|
+
// in the count.
|
|
209
|
+
body += `${indent.get()}#[allow(clippy::too_many_arguments)]\n`;
|
|
210
|
+
}
|
|
204
211
|
if (isPublicApi) {
|
|
205
212
|
body += `${indent.get()}#[tracing::function("${method.languageIndependentName}")]\n`;
|
|
206
213
|
}
|
|
207
214
|
else if (isSubclientNew) {
|
|
208
215
|
body += `${indent.get()}#[tracing::subclient]\n`;
|
|
209
216
|
}
|
|
210
|
-
body += `${indent.get()}${helpers.emitVisibility(method.visibility)}${async}fn ${method.name}(${
|
|
217
|
+
body += `${indent.get()}${helpers.emitVisibility(method.visibility)}${async}fn ${method.name}(${paramsInfo.sig}) -> ${returnType} {\n`;
|
|
211
218
|
body += `${indent.push().get()}${methodBody(indent)}\n`;
|
|
212
219
|
body += `${indent.pop().get()}}\n`; // end method
|
|
213
220
|
if (i + 1 < client.methods.length) {
|
|
@@ -381,21 +388,24 @@ function getConstructorParamsSig(params, options, use) {
|
|
|
381
388
|
}
|
|
382
389
|
/**
|
|
383
390
|
* creates the parameter signature for a client method
|
|
384
|
-
* e.g. "foo: i32, bar: String, options: MethodOptions"
|
|
391
|
+
* e.g. "foo: i32, bar: String, options: MethodOptions".
|
|
392
|
+
* also returns the number of parameters in the sig.
|
|
385
393
|
*
|
|
386
394
|
* @param method the Rust method for which to create the param sig
|
|
387
395
|
* @param use the use statement builder currently in scope
|
|
388
|
-
* @returns the method params sig
|
|
396
|
+
* @returns the method params count and sig
|
|
389
397
|
*/
|
|
390
|
-
function
|
|
398
|
+
function getMethodParamsCountAndSig(method, use) {
|
|
391
399
|
const paramsSig = new Array();
|
|
392
400
|
paramsSig.push(formatParamTypeName(method.self));
|
|
401
|
+
let count = 1; // self
|
|
393
402
|
if (method.kind === 'clientaccessor') {
|
|
394
403
|
// client accessor params don't have a concept
|
|
395
404
|
// of optionality nor do they contain literals
|
|
396
405
|
for (const param of method.params) {
|
|
397
406
|
use.addForType(param.type);
|
|
398
407
|
paramsSig.push(`${param.name}: ${formatParamTypeName(param)}`);
|
|
408
|
+
++count;
|
|
399
409
|
}
|
|
400
410
|
}
|
|
401
411
|
else {
|
|
@@ -414,11 +424,13 @@ function getMethodParamsSig(method, use) {
|
|
|
414
424
|
if (param.location === 'method' && !param.optional) {
|
|
415
425
|
use.addForType(param.type);
|
|
416
426
|
paramsSig.push(`${param.name}: ${formatParamTypeName(param)}`);
|
|
427
|
+
++count;
|
|
417
428
|
}
|
|
418
429
|
}
|
|
419
430
|
paramsSig.push(`options: ${helpers.getTypeDeclaration(method.options, 'anonymous')}`);
|
|
431
|
+
++count;
|
|
420
432
|
}
|
|
421
|
-
return paramsSig.join(', ');
|
|
433
|
+
return { count: count, sig: paramsSig.join(', ') };
|
|
422
434
|
}
|
|
423
435
|
/**
|
|
424
436
|
* returns documentation for header trait access if the method has response headers.
|
|
@@ -473,12 +485,12 @@ function getAuthPolicy(ctor, use) {
|
|
|
473
485
|
for (const param of ctor.params) {
|
|
474
486
|
const arcTokenCred = shared.asTypeOf(param.type, 'tokenCredential', 'arc');
|
|
475
487
|
if (arcTokenCred) {
|
|
476
|
-
use.add('azure_core::http::policies', '
|
|
488
|
+
use.add('azure_core::http::policies', 'BearerTokenAuthorizationPolicy', 'Policy');
|
|
477
489
|
const scopes = new Array();
|
|
478
490
|
for (const scope of arcTokenCred.scopes) {
|
|
479
491
|
scopes.push(`"${scope}"`);
|
|
480
492
|
}
|
|
481
|
-
return `let auth_policy: Arc<dyn Policy> = Arc::new(
|
|
493
|
+
return `let auth_policy: Arc<dyn Policy> = Arc::new(BearerTokenAuthorizationPolicy::new(credential, vec![${scopes.join(', ')}]));`;
|
|
482
494
|
}
|
|
483
495
|
}
|
|
484
496
|
return undefined;
|
|
@@ -645,7 +657,7 @@ function getParamValueHelper(indent, param, inClosure, setter) {
|
|
|
645
657
|
if (param.optional && param.type.kind !== 'literal') {
|
|
646
658
|
// optional params are in the unwrapped options local var
|
|
647
659
|
const op = indent.get() + helpers.buildIfBlock(indent, {
|
|
648
|
-
condition: `let Some(${param.name}) = ${inClosure ? '&' : ''}options.${param.name}`,
|
|
660
|
+
condition: `let Some(${param.name}) = ${inClosure && nonCopyableType(param.type) ? '&' : ''}options.${param.name}`,
|
|
649
661
|
body: setter,
|
|
650
662
|
});
|
|
651
663
|
return op + '\n';
|
|
@@ -659,45 +671,37 @@ function getParamValueHelper(indent, param, inClosure, setter) {
|
|
|
659
671
|
* @param use the use statement builder currently in scope
|
|
660
672
|
* @param method the method for which we're building the body
|
|
661
673
|
* @param paramGroups the param groups for the provided method
|
|
662
|
-
* @param urlVarName the name of the var that contains the azure_core::Url
|
|
674
|
+
* @param urlVarName the name of the var that contains the azure_core::Url
|
|
663
675
|
* @returns the URL construction code
|
|
664
676
|
*/
|
|
665
|
-
function constructUrl(indent, use, method, paramGroups, urlVarName
|
|
677
|
+
function constructUrl(indent, use, method, paramGroups, urlVarName) {
|
|
666
678
|
// for paths that contain query parameters, we must set the query params separately.
|
|
667
679
|
// including them in the call to set_path() causes the chars to be path-escaped.
|
|
668
680
|
const pathChunks = method.httpPath.split('?');
|
|
669
681
|
if (pathChunks.length > 2) {
|
|
670
682
|
throw new CodegenError('InternalError', 'too many HTTP path chunks');
|
|
671
683
|
}
|
|
672
|
-
/** returns & if the param needs to be borrowed (which is the majority of cases), else the empty string */
|
|
673
|
-
const borrowOrNot = function (param) {
|
|
674
|
-
// for string-based enums we call .as_ref() which elides the need to borrow.
|
|
675
|
-
// for numeric-based enums the borrow will be necessary.
|
|
676
|
-
// TODO: https://github.com/Azure/typespec-rust/issues/25
|
|
677
|
-
if (param.type.kind !== 'enum' && (param.type.kind !== 'ref' || param.type.type.kind === 'encodedBytes' || param.type.type.kind === 'slice')) {
|
|
678
|
-
return '&';
|
|
679
|
-
}
|
|
680
|
-
return '';
|
|
681
|
-
};
|
|
682
684
|
let body = '';
|
|
683
685
|
// if path is just "/" no need to set it again, we're already there
|
|
684
686
|
if (pathChunks[0] !== '/') {
|
|
687
|
+
use.add('azure_core::http', 'UrlExt');
|
|
685
688
|
let path = `"${pathChunks[0]}"`;
|
|
686
689
|
if (paramGroups.path.length === 0) {
|
|
687
690
|
// no path params, just a static path
|
|
688
|
-
body += `${indent.get()}${urlVarName}
|
|
691
|
+
body += `${indent.get()}${urlVarName}.append_path(${path});\n`;
|
|
689
692
|
}
|
|
690
693
|
else if (paramGroups.path.length === 1 && pathChunks[0] === `{${paramGroups.path[0].segment}}`) {
|
|
691
694
|
// for a single path param (i.e. "{foo}") we can directly join the path param's value
|
|
692
695
|
const pathParam = paramGroups.path[0];
|
|
693
|
-
body += `${indent.get()}${urlVarName}
|
|
696
|
+
body += `${indent.get()}${urlVarName}.append_path(${getHeaderPathQueryParamValue(use, pathParam, true, false)});\n`;
|
|
694
697
|
}
|
|
695
698
|
else {
|
|
696
699
|
// we have path params that need to have their segments replaced with the param values
|
|
697
|
-
|
|
700
|
+
const pathVarName = helpers.getUniqueVarName(method.params, ['path', 'path_var']);
|
|
701
|
+
body += `${indent.get()}let mut ${pathVarName} = String::from(${path});\n`;
|
|
698
702
|
for (const pathParam of paramGroups.path) {
|
|
699
703
|
let wrapSortedVec = (s) => s;
|
|
700
|
-
let paramExpression
|
|
704
|
+
let paramExpression;
|
|
701
705
|
if (pathParam.kind === 'pathHashMap') {
|
|
702
706
|
wrapSortedVec = (s) => `${indent.get()}{`
|
|
703
707
|
+ `${indent.push().get()}let mut ${pathParam.name}_vec = ${pathParam.name}.iter().collect::<Vec<_>>();\n`
|
|
@@ -748,6 +752,8 @@ function constructUrl(indent, use, method, paramGroups, urlVarName = 'url') {
|
|
|
748
752
|
}
|
|
749
753
|
}
|
|
750
754
|
else {
|
|
755
|
+
// skip borrowing by default as we borrow from format!()
|
|
756
|
+
paramExpression = getHeaderPathQueryParamValue(use, pathParam, true, true);
|
|
751
757
|
switch (pathParam.style) {
|
|
752
758
|
case 'path':
|
|
753
759
|
paramExpression = `&format!("/{${paramExpression}}")`;
|
|
@@ -759,24 +765,25 @@ function constructUrl(indent, use, method, paramGroups, urlVarName = 'url') {
|
|
|
759
765
|
paramExpression = `&format!(";${pathParam.name}={${paramExpression}}")`;
|
|
760
766
|
break;
|
|
761
767
|
default:
|
|
762
|
-
|
|
768
|
+
// use default borrowing calculation logic
|
|
769
|
+
paramExpression = getHeaderPathQueryParamValue(use, pathParam, true, false);
|
|
763
770
|
}
|
|
764
771
|
}
|
|
765
772
|
if (pathParam.optional) {
|
|
766
|
-
body += `${indent.get()}
|
|
773
|
+
body += `${indent.get()}${pathVarName} = ${helpers.buildMatch(indent, `options.${pathParam.name}`, [{
|
|
767
774
|
pattern: `Some(${pathParam.name})`,
|
|
768
|
-
body: (indent) => wrapSortedVec(`${indent.get()}
|
|
775
|
+
body: (indent) => wrapSortedVec(`${indent.get()}${pathVarName}.replace("{${pathParam.segment}}", ${paramExpression})\n`),
|
|
769
776
|
}, {
|
|
770
777
|
pattern: `None`,
|
|
771
|
-
body: (indent) => `${indent.get()}
|
|
778
|
+
body: (indent) => `${indent.get()}${pathVarName}.replace("{${pathParam.segment}}", "")\n`,
|
|
772
779
|
}])};\n`;
|
|
773
780
|
}
|
|
774
781
|
else {
|
|
775
|
-
body += wrapSortedVec(`${indent.get()}
|
|
782
|
+
body += wrapSortedVec(`${indent.get()}${pathVarName} = ${pathVarName}.replace("{${pathParam.segment}}", ${paramExpression});\n`);
|
|
776
783
|
}
|
|
777
784
|
}
|
|
778
|
-
path =
|
|
779
|
-
body += `${indent.get()}${urlVarName}
|
|
785
|
+
path = `&${pathVarName}`;
|
|
786
|
+
body += `${indent.get()}${urlVarName}.append_path(${path});\n`;
|
|
780
787
|
}
|
|
781
788
|
}
|
|
782
789
|
if (pathChunks.length === 2) {
|
|
@@ -830,9 +837,7 @@ function constructUrl(indent, use, method, paramGroups, urlVarName = 'url') {
|
|
|
830
837
|
}
|
|
831
838
|
else {
|
|
832
839
|
body += getParamValueHelper(indent, queryParam, false, () => {
|
|
833
|
-
|
|
834
|
-
const borrow = queryParam.type.kind === 'enum' ? '' : borrowOrNot(queryParam);
|
|
835
|
-
return `${indent.get()}${urlVarName}.query_pairs_mut().append_pair("${queryParam.key}", ${borrow}${getHeaderPathQueryParamValue(use, queryParam, !queryParam.optional)});\n`;
|
|
840
|
+
return `${indent.get()}${urlVarName}.query_pairs_mut().append_pair("${queryParam.key}", ${getHeaderPathQueryParamValue(use, queryParam, !queryParam.optional, false)});\n`;
|
|
836
841
|
});
|
|
837
842
|
}
|
|
838
843
|
}
|
|
@@ -848,7 +853,7 @@ function constructUrl(indent, use, method, paramGroups, urlVarName = 'url') {
|
|
|
848
853
|
* @param inClosure indicates if the request is being constructed within a closure (e.g. pageable methods)
|
|
849
854
|
* @returns the code which sets HTTP headers for the request
|
|
850
855
|
*/
|
|
851
|
-
function applyHeaderParams(indent, use, method, paramGroups, inClosure) {
|
|
856
|
+
function applyHeaderParams(indent, use, method, paramGroups, inClosure, requestVarName) {
|
|
852
857
|
var _a, _b, _c;
|
|
853
858
|
let body = '';
|
|
854
859
|
for (const headerParam of paramGroups.header) {
|
|
@@ -868,7 +873,7 @@ function applyHeaderParams(indent, use, method, paramGroups, inClosure) {
|
|
|
868
873
|
]) + ';\n';
|
|
869
874
|
body += indent.get() + helpers.buildIfBlock(indent, {
|
|
870
875
|
condition: `let Some(${headerParam.name}) = ${headerParam.name}`,
|
|
871
|
-
body: (indent) => `${indent.get()}
|
|
876
|
+
body: (indent) => `${indent.get()}${requestVarName}.insert_header("${headerParam.header}", ${headerParam.name});\n`,
|
|
872
877
|
}) + '\n';
|
|
873
878
|
continue;
|
|
874
879
|
}
|
|
@@ -880,15 +885,12 @@ function applyHeaderParams(indent, use, method, paramGroups, inClosure) {
|
|
|
880
885
|
}
|
|
881
886
|
body += getParamValueHelper(indent, headerParam, inClosure, () => {
|
|
882
887
|
if (headerParam.kind === 'headerHashMap') {
|
|
883
|
-
let setter = `for (k, v) in
|
|
884
|
-
setter += `${indent.push().get()}
|
|
888
|
+
let setter = `for (k, v) in ${headerParam.type.kind === 'ref' ? '' : '&'}${headerParam.name} {\n`;
|
|
889
|
+
setter += `${indent.push().get()}${requestVarName}.insert_header(format!("${headerParam.header}-{k}"), v);\n`;
|
|
885
890
|
setter += `${indent.pop().get()}}\n`;
|
|
886
891
|
return setter;
|
|
887
892
|
}
|
|
888
|
-
|
|
889
|
-
// client or we're in a closure and the param is required (header params are always owned)
|
|
890
|
-
const borrow = nonCopyableType(headerParam.type) && (headerParam.location === 'client' || (inClosure && !headerParam.optional)) ? '&' : '';
|
|
891
|
-
return `${indent.get()}request.insert_header("${headerParam.header.toLowerCase()}", ${borrow}${getHeaderPathQueryParamValue(use, headerParam, !inClosure)});\n`;
|
|
893
|
+
return `${indent.get()}${requestVarName}.insert_header("${headerParam.header.toLowerCase()}", ${getHeaderPathQueryParamValue(use, headerParam, !inClosure, false)});\n`;
|
|
892
894
|
});
|
|
893
895
|
}
|
|
894
896
|
return body;
|
|
@@ -907,13 +909,17 @@ function isOptionalContentTypeHeader(headerParam) {
|
|
|
907
909
|
* @param method the method for which we're building the body
|
|
908
910
|
* @param paramGroups the param groups for the provided method
|
|
909
911
|
* @param inClosure indicates if the request is being constructed within a closure (e.g. pageable methods)
|
|
912
|
+
* @param urlVarName the name of var that contains the URL
|
|
910
913
|
* @param cloneUrl indicates if url should be cloned when it is passed to initialize request
|
|
911
914
|
* @param forceMut indicates whether request should get declared as 'mut' regardless of whether there are any headers to set
|
|
912
915
|
* @returns the request construction code
|
|
913
916
|
*/
|
|
914
|
-
function constructRequest(indent, use, method, paramGroups, inClosure, cloneUrl = false, forceMut = true) {
|
|
915
|
-
|
|
916
|
-
|
|
917
|
+
function constructRequest(indent, use, method, paramGroups, inClosure, urlVarName, cloneUrl = false, forceMut = true) {
|
|
918
|
+
// when constructing the request var name we need to ensure
|
|
919
|
+
// that it doesn't collide with any parameter name.
|
|
920
|
+
const requestVarName = helpers.getUniqueVarName(method.params, ['request', 'core_req']);
|
|
921
|
+
let body = `${indent.get()}let ${(forceMut || paramGroups.header.length > 0) ? 'mut ' : ''}${requestVarName} = Request::new(${urlVarName}${cloneUrl ? '.clone()' : ''}, Method::${codegen.capitalize(method.httpMethod)});\n`;
|
|
922
|
+
body += applyHeaderParams(indent, use, method, paramGroups, inClosure, requestVarName);
|
|
917
923
|
let optionalContentTypeParam;
|
|
918
924
|
for (const headerParam of paramGroups.header) {
|
|
919
925
|
// if the content-type header is optional, we need to emit it inside the "if let Some(body)" clause below.
|
|
@@ -926,9 +932,9 @@ function constructRequest(indent, use, method, paramGroups, inClosure, cloneUrl
|
|
|
926
932
|
body += getParamValueHelper(indent, bodyParam, inClosure, () => {
|
|
927
933
|
let bodyParamContent = '';
|
|
928
934
|
if (optionalContentTypeParam) {
|
|
929
|
-
bodyParamContent = `${indent.get()}
|
|
935
|
+
bodyParamContent = `${indent.get()}${requestVarName}.insert_header("${optionalContentTypeParam.header.toLowerCase()}", ${getHeaderPathQueryParamValue(use, optionalContentTypeParam, !inClosure, false)});\n`;
|
|
930
936
|
}
|
|
931
|
-
bodyParamContent += `${indent.get()}
|
|
937
|
+
bodyParamContent += `${indent.get()}${requestVarName}.set_body(${bodyParam.name}${inClosure ? '.clone()' : ''});\n`;
|
|
932
938
|
return bodyParamContent;
|
|
933
939
|
});
|
|
934
940
|
}
|
|
@@ -958,9 +964,12 @@ function constructRequest(indent, use, method, paramGroups, inClosure, cloneUrl
|
|
|
958
964
|
body += `${indent.get()}${initializer},\n`;
|
|
959
965
|
}
|
|
960
966
|
body += `${indent.pop().get()}}.try_into()?;\n`;
|
|
961
|
-
body += `${indent.get()}
|
|
967
|
+
body += `${indent.get()}${requestVarName}.set_body(body);\n`;
|
|
962
968
|
}
|
|
963
|
-
return
|
|
969
|
+
return {
|
|
970
|
+
requestVarName: requestVarName,
|
|
971
|
+
content: body
|
|
972
|
+
};
|
|
964
973
|
}
|
|
965
974
|
/**
|
|
966
975
|
* Returns 'mut ' if the Url local var needs to be mutable, else the empty string.
|
|
@@ -1037,13 +1046,15 @@ function emitEmptyPathParamCheck(indent, param) {
|
|
|
1037
1046
|
*/
|
|
1038
1047
|
function getAsyncMethodBody(indent, use, client, method) {
|
|
1039
1048
|
use.add('azure_core::http', 'Method', 'Request');
|
|
1049
|
+
const urlVarName = helpers.getUniqueVarName(method.params, ['url', 'url_var']);
|
|
1040
1050
|
const paramGroups = getMethodParamGroup(method);
|
|
1041
1051
|
let body = checkEmptyRequiredPathParams(indent, paramGroups.path);
|
|
1042
1052
|
body += 'let options = options.unwrap_or_default();\n';
|
|
1043
1053
|
body += `${indent.get()}let ctx = options.method_options.context.to_borrowed();\n`;
|
|
1044
|
-
body += `${indent.get()}let ${urlVarNeedsMut(paramGroups, method)}
|
|
1045
|
-
body += constructUrl(indent, use, method, paramGroups);
|
|
1046
|
-
|
|
1054
|
+
body += `${indent.get()}let ${urlVarNeedsMut(paramGroups, method)}${urlVarName} = self.${getEndpointFieldName(client)}.clone();\n`;
|
|
1055
|
+
body += constructUrl(indent, use, method, paramGroups, urlVarName);
|
|
1056
|
+
const requestResult = constructRequest(indent, use, method, paramGroups, false, urlVarName);
|
|
1057
|
+
body += requestResult.content;
|
|
1047
1058
|
let pipelineMethod;
|
|
1048
1059
|
switch (method.returns.type.kind) {
|
|
1049
1060
|
case 'asyncResponse':
|
|
@@ -1053,7 +1064,7 @@ function getAsyncMethodBody(indent, use, client, method) {
|
|
|
1053
1064
|
pipelineMethod = 'send';
|
|
1054
1065
|
break;
|
|
1055
1066
|
}
|
|
1056
|
-
body += `${indent.get()}let rsp = self.pipeline.${pipelineMethod}(&ctx, &mut
|
|
1067
|
+
body += `${indent.get()}let rsp = self.pipeline.${pipelineMethod}(&ctx, &mut ${requestResult.requestVarName}, ${getPipelineOptions(indent, use, method)}).await?;\n`;
|
|
1057
1068
|
body += `${indent.get()}Ok(rsp.into())\n`;
|
|
1058
1069
|
return body;
|
|
1059
1070
|
}
|
|
@@ -1073,7 +1084,7 @@ function getPageableMethodBody(indent, use, client, method) {
|
|
|
1073
1084
|
use.addForType(method.returns.type);
|
|
1074
1085
|
use.addForType(helpers.unwrapType(method.returns.type));
|
|
1075
1086
|
const paramGroups = getMethodParamGroup(method);
|
|
1076
|
-
const urlVar = method.strategy ? 'first_url' : 'url';
|
|
1087
|
+
const urlVar = method.strategy ? 'first_url' : helpers.getUniqueVarName(method.params, ['url', 'url_var']);
|
|
1077
1088
|
let body = checkEmptyRequiredPathParams(indent, paramGroups.path);
|
|
1078
1089
|
body += 'let options = options.unwrap_or_default().into_owned();\n';
|
|
1079
1090
|
body += `${indent.get()}let pipeline = self.pipeline.clone();\n`;
|
|
@@ -1082,9 +1093,13 @@ function getPageableMethodBody(indent, use, client, method) {
|
|
|
1082
1093
|
// passed to constructRequest. we only need to
|
|
1083
1094
|
// clone it for the non-continuation case.
|
|
1084
1095
|
let cloneUrl = false;
|
|
1096
|
+
// this will be either the inner URL var created
|
|
1097
|
+
// during paging or the initial URL var when there's
|
|
1098
|
+
// no paging strategy
|
|
1099
|
+
let srcUrlVar;
|
|
1085
1100
|
if (method.strategy) {
|
|
1086
1101
|
if (paramGroups.apiVersion) {
|
|
1087
|
-
body += `${indent.get()}let ${paramGroups.apiVersion.name} = ${getHeaderPathQueryParamValue(use, paramGroups.apiVersion, true)}.clone();\n`;
|
|
1102
|
+
body += `${indent.get()}let ${paramGroups.apiVersion.name} = ${getHeaderPathQueryParamValue(use, paramGroups.apiVersion, true, true)}.clone();\n`;
|
|
1088
1103
|
}
|
|
1089
1104
|
switch (method.strategy.kind) {
|
|
1090
1105
|
case 'continuationToken': {
|
|
@@ -1113,33 +1128,47 @@ function getPageableMethodBody(indent, use, client, method) {
|
|
|
1113
1128
|
}
|
|
1114
1129
|
})}\n`;
|
|
1115
1130
|
}
|
|
1131
|
+
srcUrlVar = 'url';
|
|
1116
1132
|
break;
|
|
1117
1133
|
}
|
|
1118
1134
|
case 'nextLink': {
|
|
1119
1135
|
const nextLinkName = method.strategy.nextLinkPath[method.strategy.nextLinkPath.length - 1].name;
|
|
1136
|
+
const reinjectedParams = method.strategy.reinjectedParams;
|
|
1120
1137
|
body += `${indent.get()}Ok(${method.returns.type.name}::from_callback(move |${nextLinkName}: PagerState<Url>| {\n`;
|
|
1121
1138
|
body += `${indent.push().get()}let url = ` + helpers.buildMatch(indent, nextLinkName, [{
|
|
1122
1139
|
pattern: `PagerState::More(${nextLinkName})`,
|
|
1123
1140
|
body: (indent) => {
|
|
1141
|
+
const cloneNextLink = `${indent.get()}let mut ${nextLinkName} = ${nextLinkName}.clone();\n`;
|
|
1142
|
+
let content = '';
|
|
1124
1143
|
if (paramGroups.apiVersion && paramGroups.apiVersion.kind === 'queryScalar') {
|
|
1125
1144
|
const apiVersionKey = `"${paramGroups.apiVersion.key}"`;
|
|
1126
1145
|
// there are no APIs to set/update an existing query parameter.
|
|
1127
1146
|
// so, we filter the existing query params to remove the api-version
|
|
1128
1147
|
// query param. we then add back the filtered set and then add the
|
|
1129
1148
|
// api-version as specified on the client.
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1149
|
+
content = `${indent.get()}let qp = ${nextLinkName}.query_pairs().filter(|(name, _)| name.ne(${apiVersionKey}));\n`;
|
|
1150
|
+
content += cloneNextLink;
|
|
1151
|
+
content += `${indent.get()}${nextLinkName}.query_pairs_mut().clear().extend_pairs(qp).append_pair(${apiVersionKey}, &${paramGroups.apiVersion.name});\n`;
|
|
1152
|
+
}
|
|
1153
|
+
else if (reinjectedParams.length > 0) {
|
|
1154
|
+
// if we didn't clone it above, we'll need to clone it for this case
|
|
1155
|
+
content += cloneNextLink;
|
|
1135
1156
|
}
|
|
1136
|
-
|
|
1157
|
+
// add query params for reinjection
|
|
1158
|
+
for (const reinjectedParam of reinjectedParams) {
|
|
1159
|
+
content += getParamValueHelper(indent, reinjectedParam, true, () => {
|
|
1160
|
+
return `${indent.get()}${nextLinkName}.query_pairs_mut().append_pair("${reinjectedParam.key}", ${getHeaderPathQueryParamValue(use, reinjectedParam, false, false)});\n`;
|
|
1161
|
+
});
|
|
1162
|
+
}
|
|
1163
|
+
content += `${indent.get()}${nextLinkName}\n`;
|
|
1164
|
+
return content;
|
|
1137
1165
|
}
|
|
1138
1166
|
}, {
|
|
1139
1167
|
pattern: 'PagerState::Initial',
|
|
1140
1168
|
body: (indent) => `${indent.get()}${urlVar}.clone()\n`
|
|
1141
1169
|
}]);
|
|
1142
1170
|
body += ';\n';
|
|
1171
|
+
srcUrlVar = 'url';
|
|
1143
1172
|
break;
|
|
1144
1173
|
}
|
|
1145
1174
|
}
|
|
@@ -1149,6 +1178,7 @@ function getPageableMethodBody(indent, use, client, method) {
|
|
|
1149
1178
|
body += `${indent.get()}Ok(Pager::from_callback(move |_: PagerState<Url>| {\n`;
|
|
1150
1179
|
indent.push();
|
|
1151
1180
|
cloneUrl = true;
|
|
1181
|
+
srcUrlVar = urlVar;
|
|
1152
1182
|
}
|
|
1153
1183
|
// Pipeline::send() returns a RawResponse, so no reason to declare the type if not something else.
|
|
1154
1184
|
let rspType = '';
|
|
@@ -1161,17 +1191,18 @@ function getPageableMethodBody(indent, use, client, method) {
|
|
|
1161
1191
|
rspType = `: ${rspTypeDecl}`;
|
|
1162
1192
|
rspInto = '.into()';
|
|
1163
1193
|
}
|
|
1164
|
-
|
|
1194
|
+
const requestResult = constructRequest(indent, use, method, paramGroups, true, srcUrlVar, cloneUrl);
|
|
1195
|
+
body += requestResult.content;
|
|
1165
1196
|
body += `${indent.get()}let ctx = options.method_options.context.clone();\n`;
|
|
1166
1197
|
body += `${indent.get()}let pipeline = pipeline.clone();\n`;
|
|
1167
1198
|
body += `${indent.get()}async move {\n`;
|
|
1168
|
-
body += `${indent.push().get()}let rsp${rspType} = pipeline.send(&ctx, &mut
|
|
1199
|
+
body += `${indent.push().get()}let rsp${rspType} = pipeline.send(&ctx, &mut ${requestResult.requestVarName}, ${getPipelineOptions(indent, use, method)}).await?${rspInto};\n`;
|
|
1169
1200
|
// check if we need to extract the next link field from the response model
|
|
1170
1201
|
if (method.strategy && (method.strategy.kind === 'nextLink' || method.strategy.responseToken.kind === 'nextLink')) {
|
|
1171
1202
|
const bodyFormat = helpers.convertResponseFormat(method.returns.type.type.format);
|
|
1172
1203
|
use.add('azure_core', bodyFormat, 'http::RawResponse');
|
|
1173
1204
|
body += `${indent.get()}let (status, headers, body) = rsp.deconstruct();\n`;
|
|
1174
|
-
const deserialize = bodyFormat
|
|
1205
|
+
const deserialize = `${bodyFormat}::from_${bodyFormat}`;
|
|
1175
1206
|
body += `${indent.get()}let res: ${helpers.getTypeDeclaration(helpers.unwrapType(method.returns.type))} = ${deserialize}(&body)?;\n`;
|
|
1176
1207
|
body += `${indent.get()}let rsp = RawResponse::from_bytes(status, headers, body).into();\n`;
|
|
1177
1208
|
}
|
|
@@ -1260,17 +1291,19 @@ function getLroMethodBody(indent, use, client, method) {
|
|
|
1260
1291
|
use.addForType(method.returns.type);
|
|
1261
1292
|
use.addForType(helpers.unwrapType(method.returns.type));
|
|
1262
1293
|
const paramGroups = getMethodParamGroup(method);
|
|
1263
|
-
const urlVar = 'url';
|
|
1294
|
+
const urlVar = helpers.getUniqueVarName(method.params, ['url', 'url_var']);
|
|
1264
1295
|
let body = 'let options = options.unwrap_or_default().into_owned();\n';
|
|
1265
1296
|
body += `${indent.get()}let pipeline = self.pipeline.clone();\n`;
|
|
1266
1297
|
body += `${indent.get()}let ${urlVarNeedsMut(paramGroups, method)}${urlVar} = self.${getEndpointFieldName(client)}.clone();\n`;
|
|
1267
1298
|
body += constructUrl(indent, use, method, paramGroups, urlVar);
|
|
1268
1299
|
if (paramGroups.apiVersion) {
|
|
1269
|
-
body += `${indent.get()}let ${paramGroups.apiVersion.name} = ${getHeaderPathQueryParamValue(use, paramGroups.apiVersion, true)}.clone();\n`;
|
|
1300
|
+
body += `${indent.get()}let ${paramGroups.apiVersion.name} = ${getHeaderPathQueryParamValue(use, paramGroups.apiVersion, true, true)}.clone();\n`;
|
|
1270
1301
|
}
|
|
1302
|
+
// we call this eagerly so that we have access to the request var name
|
|
1303
|
+
const initialRequestResult = constructRequest(indent, use, method, paramGroups, true, urlVar, true, false);
|
|
1271
1304
|
body += `${indent.get()}Ok(${method.returns.type.name}::from_callback(\n`;
|
|
1272
1305
|
body += `${indent.push().get()}move |next_link: PollerState<Url>| {\n`;
|
|
1273
|
-
body += `${indent.push().get()}let (mut
|
|
1306
|
+
body += `${indent.push().get()}let (mut ${initialRequestResult.requestVarName}, next_link) = ${helpers.buildMatch(indent, 'next_link', [{
|
|
1274
1307
|
pattern: `PollerState::More(next_link)`,
|
|
1275
1308
|
body: (indent) => {
|
|
1276
1309
|
var _a;
|
|
@@ -1286,33 +1319,27 @@ function getLroMethodBody(indent, use, client, method) {
|
|
|
1286
1319
|
if (paramGroups.header.length > 1 || (paramGroups.header.length === 1 && !isOptionalContentTypeHeader(paramGroups.header[0]))) {
|
|
1287
1320
|
mutRequest = 'mut ';
|
|
1288
1321
|
}
|
|
1289
|
-
body += `${indent.get()}let ${mutRequest}
|
|
1290
|
-
body += applyHeaderParams(indent, use, method, paramGroups, true);
|
|
1291
|
-
body += `${indent.get()}(
|
|
1322
|
+
body += `${indent.get()}let ${mutRequest}${initialRequestResult.requestVarName} = Request::new(next_link.clone(), Method::Get);\n`;
|
|
1323
|
+
body += applyHeaderParams(indent, use, method, paramGroups, true, initialRequestResult.requestVarName);
|
|
1324
|
+
body += `${indent.get()}(${initialRequestResult.requestVarName}, next_link)\n`;
|
|
1292
1325
|
return body;
|
|
1293
1326
|
},
|
|
1294
1327
|
}, {
|
|
1295
1328
|
pattern: 'PollerState::Initial',
|
|
1296
1329
|
body: (indent) => {
|
|
1297
|
-
let body =
|
|
1298
|
-
body += `${indent.get()}(
|
|
1330
|
+
let body = initialRequestResult.content;
|
|
1331
|
+
body += `${indent.get()}(${initialRequestResult.requestVarName}, url.clone())\n`;
|
|
1299
1332
|
return body;
|
|
1300
1333
|
},
|
|
1301
1334
|
}])};\n`;
|
|
1302
1335
|
body += `${indent.get()}let ctx = options.method_options.context.clone();\n`;
|
|
1303
1336
|
body += `${indent.get()}let pipeline = pipeline.clone();\n`;
|
|
1304
1337
|
body += `${indent.get()}async move {\n`;
|
|
1305
|
-
body += `${indent.push().get()}let rsp = pipeline.send(&ctx, &mut
|
|
1338
|
+
body += `${indent.push().get()}let rsp = pipeline.send(&ctx, &mut ${initialRequestResult.requestVarName}, ${getPipelineOptions(indent, use, method)}).await?;\n`;
|
|
1306
1339
|
body += `${indent.get()}let (status, headers, body) = rsp.deconstruct();\n`;
|
|
1307
1340
|
body += `${indent.get()}let retry_after = get_retry_after(&headers, &[X_MS_RETRY_AFTER_MS, RETRY_AFTER_MS, RETRY_AFTER], &options.poller_options);\n`;
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
use.add('azure_core', 'json');
|
|
1311
|
-
deserialize = 'json::from_json';
|
|
1312
|
-
}
|
|
1313
|
-
else {
|
|
1314
|
-
deserialize = 'xml::read_xml';
|
|
1315
|
-
}
|
|
1341
|
+
const deserialize = `${bodyFormat}::from_${bodyFormat}`;
|
|
1342
|
+
use.add('azure_core', bodyFormat);
|
|
1316
1343
|
body += `${indent.get()}let res: ${helpers.getTypeDeclaration(helpers.unwrapType(method.returns.type))} = ${deserialize}(&body)?;\n`;
|
|
1317
1344
|
body += `${indent.get()}let rsp = RawResponse::from_bytes(status, headers, body).into();\n`;
|
|
1318
1345
|
body += `${indent.get()}Ok(${helpers.buildMatch(indent, 'res.status()', [{
|
|
@@ -1361,8 +1388,9 @@ function getClientSupplementalEndpointParamValue(param) {
|
|
|
1361
1388
|
}
|
|
1362
1389
|
}
|
|
1363
1390
|
/**
|
|
1364
|
-
*
|
|
1365
|
-
* from a parameter of that type.
|
|
1391
|
+
* returns the code to use when populating a header/path/query value
|
|
1392
|
+
* from a parameter of that type. this will include any borrowing of
|
|
1393
|
+
* the parameter (or its calculated result) as required.
|
|
1366
1394
|
*
|
|
1367
1395
|
* if the param's type is a String, then the return value is simply the
|
|
1368
1396
|
* param's name. the non-String cases require some kind of conversion.
|
|
@@ -1372,9 +1400,10 @@ function getClientSupplementalEndpointParamValue(param) {
|
|
|
1372
1400
|
* @param use the use statement builder currently in scope
|
|
1373
1401
|
* @param param the param for which to get the value
|
|
1374
1402
|
* @param fromSelf applicable for client params. when true, the prefix "self." is included
|
|
1403
|
+
* @param neverBorrow indicates that the borrowing calculation should be skipped
|
|
1375
1404
|
* @returns the code to use for the param's value
|
|
1376
1405
|
*/
|
|
1377
|
-
function getHeaderPathQueryParamValue(use, param, fromSelf) {
|
|
1406
|
+
function getHeaderPathQueryParamValue(use, param, fromSelf, neverBorrow) {
|
|
1378
1407
|
let paramName = param.name;
|
|
1379
1408
|
// when fromSelf is false we assume that there's a local with the same name.
|
|
1380
1409
|
// e.g. in pageable methods where we need to clone the params so they can be
|
|
@@ -1389,64 +1418,101 @@ function getHeaderPathQueryParamValue(use, param, fromSelf) {
|
|
|
1389
1418
|
}
|
|
1390
1419
|
return encoding;
|
|
1391
1420
|
};
|
|
1392
|
-
const encodeDateTime = function (type,
|
|
1421
|
+
const encodeDateTime = function (type, paramName) {
|
|
1393
1422
|
const encoding = helpers.getDateTimeEncodingMethod(type.encoding, 'to', use);
|
|
1394
1423
|
switch (type.encoding) {
|
|
1395
1424
|
case 'rfc3339':
|
|
1396
1425
|
case 'rfc7231': {
|
|
1397
|
-
return `${encoding}(
|
|
1426
|
+
return `${encoding}(${param.type.kind === 'ref' ? '' : '&'}${paramName})`;
|
|
1398
1427
|
}
|
|
1399
1428
|
case 'unix_time':
|
|
1400
|
-
return `${
|
|
1429
|
+
return `${paramName}.${encoding}.to_string()`;
|
|
1401
1430
|
}
|
|
1402
1431
|
};
|
|
1432
|
+
// this will contain the final text for
|
|
1433
|
+
// retrieving the param value. this will include
|
|
1434
|
+
// any required conversions and/or borrowing
|
|
1435
|
+
let paramValue;
|
|
1436
|
+
// contains the result from calculating if the
|
|
1437
|
+
// param requires borrowing.
|
|
1438
|
+
let mustBorrow = true;
|
|
1403
1439
|
const paramType = helpers.unwrapType(param.type);
|
|
1404
1440
|
if (param.kind === 'headerCollection' || param.kind === 'queryCollection') {
|
|
1405
1441
|
if (param.format === 'multi') {
|
|
1406
1442
|
throw new CodegenError('InternalError', 'multi should have been handled outside getHeaderPathQueryParamValue');
|
|
1407
1443
|
}
|
|
1408
1444
|
else if (paramType.kind === 'String' || paramType.kind === 'str') {
|
|
1409
|
-
|
|
1445
|
+
paramValue = `${paramName}.join("${getCollectionDelimiter(param.format)}")`;
|
|
1410
1446
|
}
|
|
1411
|
-
|
|
1412
|
-
|
|
1447
|
+
else {
|
|
1448
|
+
// convert the items to strings
|
|
1449
|
+
let strConv;
|
|
1450
|
+
switch (paramType.kind) {
|
|
1451
|
+
case 'encodedBytes':
|
|
1452
|
+
strConv = encodeBytes(paramType);
|
|
1453
|
+
break;
|
|
1454
|
+
case 'offsetDateTime':
|
|
1455
|
+
strConv = `|i| ${encodeDateTime(paramType, 'i')}`;
|
|
1456
|
+
break;
|
|
1457
|
+
default:
|
|
1458
|
+
strConv = '|i| i.to_string()';
|
|
1459
|
+
}
|
|
1460
|
+
paramValue = `${param.name}.iter().map(${strConv}).collect::<Vec<String>>().join("${getCollectionDelimiter(param.format)}")`;
|
|
1461
|
+
}
|
|
1462
|
+
}
|
|
1463
|
+
else {
|
|
1413
1464
|
switch (paramType.kind) {
|
|
1465
|
+
case 'String':
|
|
1466
|
+
paramValue = paramName;
|
|
1467
|
+
// if the param is on the client, or it's optional, then we must borrow
|
|
1468
|
+
mustBorrow = (param.location === 'client' && fromSelf) || param.optional;
|
|
1469
|
+
break;
|
|
1470
|
+
case 'str':
|
|
1471
|
+
paramValue = paramName;
|
|
1472
|
+
// str is already borrowed
|
|
1473
|
+
mustBorrow = false;
|
|
1474
|
+
break;
|
|
1475
|
+
case 'decimal':
|
|
1476
|
+
paramValue = `${param.name}.to_string()`;
|
|
1477
|
+
break;
|
|
1414
1478
|
case 'encodedBytes':
|
|
1415
|
-
|
|
1479
|
+
paramValue = encodeBytes(paramType, paramName);
|
|
1480
|
+
break;
|
|
1481
|
+
case 'enum':
|
|
1482
|
+
case 'scalar':
|
|
1483
|
+
if (paramType.kind === 'enum' && (param.kind === 'pathScalar' || param.kind === 'queryScalar') && paramType.type === 'String') {
|
|
1484
|
+
// append_pair and path.replace() want a reference to the string
|
|
1485
|
+
paramValue = `${paramName}.as_ref()`;
|
|
1486
|
+
// as_ref() elides the need to borrow
|
|
1487
|
+
mustBorrow = false;
|
|
1488
|
+
}
|
|
1489
|
+
else {
|
|
1490
|
+
paramValue = `${paramName}.to_string()`;
|
|
1491
|
+
}
|
|
1492
|
+
break;
|
|
1493
|
+
case 'enumValue':
|
|
1494
|
+
paramValue = `${paramType.type.name}::${paramType.name}.to_string()`;
|
|
1495
|
+
break;
|
|
1496
|
+
case 'literal':
|
|
1497
|
+
paramValue = `"${paramType.value}"`;
|
|
1416
1498
|
break;
|
|
1417
1499
|
case 'offsetDateTime':
|
|
1418
|
-
|
|
1500
|
+
paramValue = encodeDateTime(paramType, param.name);
|
|
1419
1501
|
break;
|
|
1420
1502
|
default:
|
|
1421
|
-
|
|
1503
|
+
throw new CodegenError('InternalError', `unhandled ${param.kind} param type kind ${paramType.kind}`);
|
|
1422
1504
|
}
|
|
1423
|
-
return `${param.name}.iter().map(${strConv}).collect::<Vec<String>>().join("${getCollectionDelimiter(param.format)}")`;
|
|
1424
1505
|
}
|
|
1425
|
-
switch (
|
|
1426
|
-
case '
|
|
1427
|
-
case '
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
case 'enum':
|
|
1434
|
-
case 'scalar':
|
|
1435
|
-
if (paramType.kind === 'enum' && (param.kind === 'pathScalar' || param.kind === 'queryScalar')) {
|
|
1436
|
-
// append_pair and path.replace() want a reference to the string
|
|
1437
|
-
// TODO: https://github.com/Azure/typespec-rust/issues/25
|
|
1438
|
-
return `${paramName}.as_ref()`;
|
|
1439
|
-
}
|
|
1440
|
-
return `${paramName}.to_string()`;
|
|
1441
|
-
case 'enumValue':
|
|
1442
|
-
return `${paramType.type.name}::${paramType.name}.to_string()`;
|
|
1443
|
-
case 'literal':
|
|
1444
|
-
return `"${paramType.value}"`;
|
|
1445
|
-
case 'offsetDateTime':
|
|
1446
|
-
return encodeDateTime(paramType, param.name);
|
|
1447
|
-
default:
|
|
1448
|
-
throw new CodegenError('InternalError', `unhandled ${param.kind} param type kind ${paramType.kind}`);
|
|
1506
|
+
switch (param.kind) {
|
|
1507
|
+
case 'headerCollection':
|
|
1508
|
+
case 'headerHashMap':
|
|
1509
|
+
case 'headerScalar':
|
|
1510
|
+
// for non-copyable params (e.g. String), we need to borrow them if they're on the
|
|
1511
|
+
// client or we're in a closure and the param is required (header params are always owned)
|
|
1512
|
+
mustBorrow = nonCopyableType(param.type) && (param.location === 'client' || (!fromSelf && !param.optional));
|
|
1513
|
+
break;
|
|
1449
1514
|
}
|
|
1515
|
+
return `${mustBorrow && !neverBorrow ? '&' : ''}${paramValue}`;
|
|
1450
1516
|
}
|
|
1451
1517
|
/**
|
|
1452
1518
|
* returns the delimiter character for the provided format type
|
|
@@ -1466,7 +1532,7 @@ function getCollectionDelimiter(format) {
|
|
|
1466
1532
|
return '\t';
|
|
1467
1533
|
}
|
|
1468
1534
|
}
|
|
1469
|
-
/** returns true if the type isn't copyable thus needs to be cloned */
|
|
1535
|
+
/** returns true if the type isn't copyable thus needs to be cloned or borrowed */
|
|
1470
1536
|
function nonCopyableType(type) {
|
|
1471
1537
|
const unwrappedType = shared.unwrapOption(type);
|
|
1472
1538
|
switch (unwrappedType.kind) {
|