Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
30 changes: 29 additions & 1 deletion modules/openapi-generator/src/main/resources/rust/model.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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}}} {
Expand All @@ -210,6 +237,7 @@ pub enum {{{enumName}}} {
{{/enumVars}}
{{/allowableValues}}
}
{{/isInteger}}

impl Default for {{{enumName}}} {
fn default() -> {{{enumName}}} {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Loading