diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractRustCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractRustCodegen.java index 39e888bae0f7..362c35e388f2 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractRustCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractRustCodegen.java @@ -391,8 +391,14 @@ public String toEnumName(CodegenProperty property) { @Override public String toEnumValue(String value, String datatype) { - // This is the representation of the enum that will be serialized / deserialized - // Note: generators currently only support string enums, so checking the type here is pointless + if ("integer".equals(datatype) || "number".equals(datatype) + || "i8".equals(datatype) || "i16".equals(datatype) + || "i32".equals(datatype) || "i64".equals(datatype) + || "u8".equals(datatype) || "u16".equals(datatype) + || "u32".equals(datatype) || "u64".equals(datatype) + || "f32".equals(datatype) || "f64".equals(datatype)) { + return value; + } return escapeText(value); } diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/RustClientCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/RustClientCodegen.java index f1efbcc5d816..fca7809c3b33 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/RustClientCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/RustClientCodegen.java @@ -379,6 +379,16 @@ public ModelsMap postProcessModels(ModelsMap objs) { } } + // Flag structs with integer-enum properties so the template can emit serde_repr import once + if (!cm.isEnum) { + for (CodegenProperty cp : cm.vars) { + if (cp.isEnum && cp.isInteger) { + cm.vendorExtensions.put("x-rust-has-integer-property-enum", true); + break; + } + } + } + // Compute documentation type for each property // This matches the actual generated code type, including HashSet for uniqueItems for (CodegenProperty cp : cm.vars) { diff --git a/modules/openapi-generator/src/main/resources/rust/model.mustache b/modules/openapi-generator/src/main/resources/rust/model.mustache index 42e9f2efe1cc..a2c60b117a45 100644 --- a/modules/openapi-generator/src/main/resources/rust/model.mustache +++ b/modules/openapi-generator/src/main/resources/rust/model.mustache @@ -5,7 +5,9 @@ use serde::{Deserialize, Serialize}; {{#model}} {{^isEnum}}{{#vendorExtensions.x-rust-has-byte-array}} use serde_with::serde_as; -{{/vendorExtensions.x-rust-has-byte-array}}{{/isEnum}} +{{/vendorExtensions.x-rust-has-byte-array}}{{#vendorExtensions.x-rust-has-integer-property-enum}} +use serde_repr::{Serialize_repr,Deserialize_repr}; +{{/vendorExtensions.x-rust-has-integer-property-enum}}{{/isEnum}} {{#isEnum}} {{#isInteger}} use serde_repr::{Serialize_repr,Deserialize_repr}; @@ -200,6 +202,31 @@ impl Default for {{classname}} { {{!-- for properties that are of enum type --}} {{#vars}} {{#isEnum}} +{{#isInteger}} +/// {{{description}}} +#[repr(i64)] +#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize_repr, Deserialize_repr)] +pub enum {{{enumName}}} { +{{#allowableValues}} +{{#enumVars}} + {{{name}}} = {{{value}}}, +{{/enumVars}} +{{/allowableValues}} +} + +impl std::fmt::Display for {{{enumName}}} { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", match self { + {{#allowableValues}} + {{#enumVars}} + Self::{{{name}}} => "{{{value}}}", + {{/enumVars}} + {{/allowableValues}} + }) + } +} +{{/isInteger}} +{{^isInteger}} /// {{{description}}} #[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)] pub enum {{{enumName}}} { @@ -210,6 +237,7 @@ pub enum {{{enumName}}} { {{/enumVars}} {{/allowableValues}} } +{{/isInteger}} impl Default for {{{enumName}}} { fn default() -> {{{enumName}}} { diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/rust/RustClientCodegenTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/rust/RustClientCodegenTest.java index a73e8773387a..d4bc7c1845ec 100644 --- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/rust/RustClientCodegenTest.java +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/rust/RustClientCodegenTest.java @@ -272,6 +272,27 @@ public void testMultipleArrayTypesEnum() throws IOException { TestUtils.assertFileContains(outputPath, enumSpec); } + @Test + public void testIntegerPropertyEnum() throws IOException { + Path target = Files.createTempDirectory("test"); + target.toFile().deleteOnExit(); + final CodegenConfigurator configurator = new CodegenConfigurator() + .setGeneratorName("rust") + .setInputSpec("src/test/resources/3_1/rust_integer_property_enum.yaml") + .setSkipOverwrite(false) + .setOutputDir(target.toAbsolutePath().toString().replace("\\", "/")); + new DefaultGenerator().opts(configurator.toClientOptInput()).generate(); + Path outputPath = Path.of(target.toString(), "/src/models/signed_message_signature.rs"); + TestUtils.assertFileExists(outputPath); + // The integer-enum property must use serde_repr (not string rename) + TestUtils.assertFileContains(outputPath, "use serde_repr::{Serialize_repr,Deserialize_repr}"); + TestUtils.assertFileContains(outputPath, "Serialize_repr, Deserialize_repr"); + TestUtils.assertFileContains(outputPath, "= 0"); + TestUtils.assertFileContains(outputPath, "= 1"); + // Must NOT contain a string rename for an integer variant + TestUtils.assertFileNotContains(outputPath, linearize("#[serde(rename = \"0\")]")); + } + @Test public void testArrayWithObjectEnumValues() throws IOException { Path target = Files.createTempDirectory("test"); diff --git a/modules/openapi-generator/src/test/resources/3_1/rust_integer_property_enum.yaml b/modules/openapi-generator/src/test/resources/3_1/rust_integer_property_enum.yaml new file mode 100644 index 000000000000..8c6993e2d4ff --- /dev/null +++ b/modules/openapi-generator/src/test/resources/3_1/rust_integer_property_enum.yaml @@ -0,0 +1,18 @@ +openapi: 3.1.0 +info: + title: Integer property enum + description: Struct with a type:integer property constrained to an enum should use serde_repr, not string rename. + version: 1.0.0 +paths: {} +components: + schemas: + SignedMessageSignature: + type: object + properties: + v: + type: integer + enum: [0, 1] + r: + type: string + s: + type: string