-
-
Notifications
You must be signed in to change notification settings - Fork 7.5k
Open
Labels
Description
Bug Report Checklist
- Have you provided a full/minimal spec to reproduce the issue?
- Have you validated the input using an OpenAPI validator?
- Have you tested with the latest master to confirm the issue still exists?
- Have you searched for related issues/PRs?
- What's the actual output vs expected output?
- [Optional] Sponsorship to speed up the bug fix or feature request (example)
Description
rust-axum does not honor OpenAPI integer formats uint32 and uint64.
When a schema property is declared as:
type: integerformat: uint32orformat: uint64
the generated Rust code still uses signed i32 for model fields and also uses <i32 as std::str::FromStr> in generated query parsing code.
This causes incorrect Rust types in generated server models and can also lead to type mismatches in generated parsing code.
I found a related issue, but it appears to be different in scope:
- [BUG][rust-axum] Support for Unsigned Long Values in Integer Maximum Handling #19291 deals with unsigned long maximum handling/validation, not
uint32/uint64type mapping itself.
openapi-generator version
7.21.0
OpenAPI declaration file content or url
openapi: 3.0.3
info:
title: Rust Axum Integer Type Mapping Test
version: 1.0.0
paths:
/integers:
get:
parameters:
- name: legacy_uint32
in: query
required: true
schema:
type: integer
format: uint32
- name: legacy_uint64
in: query
required: true
schema:
type: integer
format: uint64Generation Details
openapi-generator generate -g rust-axum -I repro.yaml -o outSteps to reproduce
- Save the spec above as repro.yaml
- Run the openapi-generator generate command above
- Inspect out/src/models.rs
- Actual output
pub count32: i32, pub count64: i32,
- Expected output
pub count32: u32, pub count64: u64,
Related issues/PRs
- [BUG][rust-axum] Support for Unsigned Long Values in Integer Maximum Handling #19291 (related, but appears to be about unsigned maximum handling rather than direct
uint32/uint64Rust type mapping)
Suggest a fix
- Override
getSchemaTypeinRustAxumServerCodegenand handle integer schemas explicitly. - Treat legacy
format: uint32andformat: uint64asu32andu64for backward compatibility. - For standard OpenAPI integer formats:
type: integer, format: int32, minimum >= 0->u32type: integer, format: int64, minimum >= 0->u64
- If
x-unsigned: trueis present, mapint32/int64to unsigned Rust types as well. - If no format is provided, reuse the existing best-fit integer selection logic based on
minimum/maximum. - Apply the same logic consistently for:
- model properties
- parameter types
- array/map inner integer types
I also drafted a patch for the fix:
diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/RustAxumServerCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/RustAxumServerCodegen.java
index a6450d6f3f..d85b30c891 100644
--- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/RustAxumServerCodegen.java
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/RustAxumServerCodegen.java
@@ -44,6 +44,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
+import java.math.BigDecimal;
import java.math.BigInteger;
import java.nio.file.Path;
import java.util.*;
@@ -1024,6 +1025,62 @@ public class RustAxumServerCodegen extends AbstractRustCodegen implements Codege
return codegenParameter;
}
+ private String getIntegerDataType(String format,
+ BigInteger minimum,
+ boolean exclusiveMinimum,
+ BigInteger maximum,
+ boolean exclusiveMaximum,
+ boolean explicitUnsigned) {
+ boolean unsigned = explicitUnsigned || canFitIntoUnsigned(minimum, exclusiveMinimum);
+
+ if (StringUtils.isEmpty(format)) {
+ return bestFittingIntegerType(
+ minimum,
+ exclusiveMinimum,
+ maximum,
+ exclusiveMaximum,
+ true);
+ }
+
+ switch (format) {
+ case "uint32":
+ return "u32";
+ case "uint64":
+ return "u64";
+ case "int32":
+ return unsigned ? "u32" : "i32";
+ case "int64":
+ return unsigned ? "u64" : "i64";
+ default:
+ LOGGER.warn("The integer format '{}' is not recognized and will be ignored.", format);
+ return bestFittingIntegerType(
+ minimum,
+ exclusiveMinimum,
+ maximum,
+ exclusiveMaximum,
+ true);
+ }
+ }
+
+ @Override
+ public String getSchemaType(Schema p) {
+ if (Objects.equals(p.getType(), "integer")) {
+ BigInteger minimum = Optional.ofNullable(p.getMinimum()).map(BigDecimal::toBigInteger).orElse(null);
+ BigInteger maximum = Optional.ofNullable(p.getMaximum()).map(BigDecimal::toBigInteger).orElse(null);
+ boolean explicitUnsigned = ModelUtils.isUnsignedIntegerSchema(p) || ModelUtils.isUnsignedLongSchema(p);
+
+ return getIntegerDataType(
+ p.getFormat(),
+ minimum,
+ Optional.ofNullable(p.getExclusiveMinimum()).orElse(false),
+ maximum,
+ Optional.ofNullable(p.getExclusiveMaximum()).orElse(false),
+ explicitUnsigned);
+ }
+
+ return super.getSchemaType(p);
+ }
+
@Override
public String toInstantiationType(final Schema p) {
if (ModelUtils.isArraySchema(p)) {
@@ -1113,13 +1170,17 @@ public class RustAxumServerCodegen extends AbstractRustCodegen implements Codege
}
// Integer type fitting
- if (Objects.equals(property.baseType, "integer")) {
+ if (Boolean.TRUE.equals(property.isInteger) || Boolean.TRUE.equals(property.isLong) || Objects.equals(property.baseType, "UnsignedInteger") || Objects.equals(property.baseType, "UnsignedLong")) {
BigInteger minimum = Optional.ofNullable(property.getMinimum()).map(BigInteger::new).orElse(null);
BigInteger maximum = Optional.ofNullable(property.getMaximum()).map(BigInteger::new).orElse(null);
- property.dataType = bestFittingIntegerType(
- minimum, property.getExclusiveMinimum(),
- maximum, property.getExclusiveMaximum(),
- true);
+ boolean explicitUnsigned = Objects.equals(property.baseType, "UnsignedInteger") || Objects.equals(property.baseType, "UnsignedLong");
+ property.dataType = getIntegerDataType(
+ property.dataFormat,
+ minimum,
+ property.getExclusiveMinimum(),
+ maximum,
+ property.getExclusiveMaximum(),
+ explicitUnsigned);
}
property.name = underscore(property.name);Reactions are currently unavailable