Skip to content

Commit

Permalink
feat(rust): support ability to disable boxed models in client (#17931)
Browse files Browse the repository at this point in the history
* feat(client): support ability to disable boxed models

Add new additional property `avoidBoxedModels` which can be configured to avoid `Box<..>` of models.

It's very nice to have such config, because it doesn't make a lot of sense for really simple models.

* test: rollback config of existed test
  • Loading branch information
DDtKey committed Feb 28, 2024
1 parent 2a4e60c commit 4b04e17
Show file tree
Hide file tree
Showing 78 changed files with 3,604 additions and 31 deletions.
2 changes: 1 addition & 1 deletion bin/configs/rust-hyper-oneOf.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ library: hyper
inputSpec: modules/openapi-generator/src/test/resources/3_0/oneof_polymorphism_and_inheritance.yaml
templateDir: modules/openapi-generator/src/main/resources/rust
additionalProperties:
supportAsync: "false"
supportAsync: false
packageName: oneof-hyper
11 changes: 11 additions & 0 deletions bin/configs/rust-reqwest-petstore-avoid-box.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
generatorName: rust
outputDir: samples/client/petstore/rust/reqwest/petstore-avoid-box
library: reqwest
inputSpec: modules/openapi-generator/src/test/resources/3_0/rust/petstore.yaml
templateDir: modules/openapi-generator/src/main/resources/rust
additionalProperties:
supportAsync: true
supportMultipleResponses: true
avoidBoxedModels: true
packageName: petstore-reqwest-avoid-box
useSingleRequestParameter: true
1 change: 1 addition & 0 deletions docs/generators/rust.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl

| Option | Description | Values | Default |
| ------ | ----------- | ------ | ------- |
|avoidBoxedModels|If set, `Box&lt;T&gt;` will not be used for models| |false|
|bestFitInt|Use best fitting integer type where minimum or maximum is set| |false|
|enumNameSuffix|Suffix that will be appended to all enum names.| ||
|hideGenerationTimestamp|Hides the generation timestamp when files are generated.| |true|
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ public class RustClientCodegen extends AbstractRustCodegen implements CodegenCon
private boolean withAWSV4Signature = false;
private boolean preferUnsignedInt = false;
private boolean bestFitInt = false;
private boolean avoidBoxedModels = false;

public static final String PACKAGE_NAME = "packageName";
public static final String PACKAGE_VERSION = "packageVersion";
Expand All @@ -60,6 +61,7 @@ public class RustClientCodegen extends AbstractRustCodegen implements CodegenCon
public static final String SUPPORT_MULTIPLE_RESPONSES = "supportMultipleResponses";
public static final String PREFER_UNSIGNED_INT = "preferUnsignedInt";
public static final String BEST_FIT_INT = "bestFitInt";
public static final String AVOID_BOXED_MODELS = "avoidBoxedModels";

protected String packageName = "openapi";
protected String packageVersion = "1.0.0";
Expand Down Expand Up @@ -192,6 +194,8 @@ public RustClientCodegen() {
.defaultValue(Boolean.FALSE.toString()));
cliOptions.add(new CliOption(BEST_FIT_INT, "Use best fitting integer type where minimum or maximum is set", SchemaTypeUtil.BOOLEAN_TYPE)
.defaultValue(Boolean.FALSE.toString()));
cliOptions.add(new CliOption(AVOID_BOXED_MODELS, "If set, `Box<T>` will not be used for models", SchemaTypeUtil.BOOLEAN_TYPE)
.defaultValue(Boolean.FALSE.toString()));

supportedLibraries.put(HYPER_LIBRARY, "HTTP client: Hyper.");
supportedLibraries.put(REQWEST_LIBRARY, "HTTP client: Reqwest.");
Expand Down Expand Up @@ -341,6 +345,11 @@ public void processOpts() {
}
writePropertyBack(BEST_FIT_INT, getBestFitInt());

if (additionalProperties.containsKey(AVOID_BOXED_MODELS)) {
this.setAvoidBoxedModels(convertPropertyToBoolean(AVOID_BOXED_MODELS));
}
writePropertyBack(AVOID_BOXED_MODELS, getAvoidBoxedModels());

additionalProperties.put(CodegenConstants.PACKAGE_NAME, packageName);
additionalProperties.put(CodegenConstants.PACKAGE_VERSION, packageVersion);

Expand Down Expand Up @@ -437,6 +446,14 @@ private void setUseSingleRequestParameter(boolean useSingleRequestParameter) {
this.useSingleRequestParameter = useSingleRequestParameter;
}

public boolean getAvoidBoxedModels() {
return avoidBoxedModels;
}

public void setAvoidBoxedModels(boolean avoidBoxedModels) {
this.avoidBoxedModels = avoidBoxedModels;
}

@Override
public String apiFileFolder() {
return (outputFolder + File.separator + apiFolder).replace("/", File.separator);
Expand Down Expand Up @@ -602,5 +619,4 @@ public String toDefaultValue(Schema p) {
return null;
}
}

}
14 changes: 7 additions & 7 deletions modules/openapi-generator/src/main/resources/rust/model.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ pub enum {{{classname}}} {
/// {{{.}}}
{{/description}}
#[serde(rename = "{{{baseName}}}"{{^required}}, skip_serializing_if = "Option::is_none"{{/required}})]
{{{name}}}: {{#required}}{{#isNullable}}Option<{{/isNullable}}{{/required}}{{^required}}Option<{{/required}}{{#isEnum}}{{{enumName}}}{{/isEnum}}{{^isEnum}}{{#isModel}}Box<{{{dataType}}}>{{/isModel}}{{^isModel}}{{{dataType}}}{{/isModel}}{{/isEnum}}{{#required}}{{#isNullable}}>{{/isNullable}}{{/required}}{{^required}}>{{/required}},
{{{name}}}: {{#required}}{{#isNullable}}Option<{{/isNullable}}{{/required}}{{^required}}Option<{{/required}}{{#isEnum}}{{{enumName}}}{{/isEnum}}{{^isEnum}}{{#isModel}}{{^avoidBoxedModels}}Box<{{/avoidBoxedModels}}{{{dataType}}}{{^avoidBoxedModels}}>{{/avoidBoxedModels}}{{/isModel}}{{^isModel}}{{{dataType}}}{{/isModel}}{{/isEnum}}{{#required}}{{#isNullable}}>{{/isNullable}}{{/required}}{{^required}}>{{/required}},
{{/vars}}
},
{{/mappedModels}}
Expand All @@ -65,7 +65,7 @@ pub enum {{{classname}}} {
{{#baseName}}
#[serde(rename="{{{.}}}")]
{{/baseName}}
{{{name}}}(Box<{{{dataType}}}>),
{{{name}}}({{#isModel}}{{^avoidBoxedModels}}Box<{{/avoidBoxedModels}}{{/isModel}}{{{dataType}}}{{#isModel}}{{^avoidBoxedModels}}>{{/avoidBoxedModels}}{{/isModel}}),
{{/composedSchemas.oneOf}}
{{/oneOf.isEmpty}}
}
Expand All @@ -77,7 +77,7 @@ impl Default for {{classname}} {
{{{name}}}: Default::default(),
{{/vars}}
}{{/-first}}{{/mappedModels}}
{{/oneOf}}{{^oneOf.isEmpty}}{{#composedSchemas.oneOf}}{{#-first}}Self::{{{name}}}(Box::default()){{/-first}}{{/composedSchemas.oneOf}}{{/oneOf.isEmpty}}
{{/oneOf}}{{^oneOf.isEmpty}}{{#composedSchemas.oneOf}}{{#-first}}Self::{{{name}}}(Default::default()){{/-first}}{{/composedSchemas.oneOf}}{{/oneOf.isEmpty}}
}
}

Expand All @@ -93,7 +93,7 @@ pub struct {{{classname}}} {
/// {{{.}}}
{{/description}}
#[serde(rename = "{{{baseName}}}"{{^required}}{{#isNullable}}, default, with = "::serde_with::rust::double_option"{{/isNullable}}{{/required}}{{^required}}, skip_serializing_if = "Option::is_none"{{/required}}{{#required}}{{#isNullable}}, deserialize_with = "Option::deserialize"{{/isNullable}}{{/required}})]
pub {{{name}}}: {{#isNullable}}Option<{{/isNullable}}{{^required}}Option<{{/required}}{{#isEnum}}{{#isArray}}{{#uniqueItems}}std::collections::HashSet<{{/uniqueItems}}{{^uniqueItems}}Vec<{{/uniqueItems}}{{/isArray}}{{{enumName}}}{{#isArray}}>{{/isArray}}{{/isEnum}}{{^isEnum}}{{#isModel}}Box<{{{dataType}}}>{{/isModel}}{{^isModel}}{{{dataType}}}{{/isModel}}{{/isEnum}}{{#isNullable}}>{{/isNullable}}{{^required}}>{{/required}},
pub {{{name}}}: {{#isNullable}}Option<{{/isNullable}}{{^required}}Option<{{/required}}{{#isEnum}}{{#isArray}}{{#uniqueItems}}std::collections::HashSet<{{/uniqueItems}}{{^uniqueItems}}Vec<{{/uniqueItems}}{{/isArray}}{{{enumName}}}{{#isArray}}>{{/isArray}}{{/isEnum}}{{^isEnum}}{{#isModel}}{{^avoidBoxedModels}}Box<{{/avoidBoxedModels}}{{{dataType}}}{{^avoidBoxedModels}}>{{/avoidBoxedModels}}{{/isModel}}{{^isModel}}{{{dataType}}}{{/isModel}}{{/isEnum}}{{#isNullable}}>{{/isNullable}}{{^required}}>{{/required}},
{{/vars}}
}

Expand All @@ -104,7 +104,7 @@ impl {{{classname}}} {
pub fn new({{#requiredVars}}{{{name}}}: {{#isNullable}}Option<{{/isNullable}}{{#isEnum}}{{#isArray}}{{#uniqueItems}}std::collections::HashSet<{{/uniqueItems}}{{^uniqueItems}}Vec<{{/uniqueItems}}{{/isArray}}{{{enumName}}}{{#isArray}}>{{/isArray}}{{/isEnum}}{{^isEnum}}{{{dataType}}}{{/isEnum}}{{#isNullable}}>{{/isNullable}}{{^-last}}, {{/-last}}{{/requiredVars}}) -> {{{classname}}} {
{{{classname}}} {
{{#vars}}
{{{name}}}{{^required}}: None{{/required}}{{#required}}{{#isModel}}: {{^isNullable}}Box::new({{{name}}}){{/isNullable}}{{#isNullable}}if let Some(x) = {{{name}}} {Some(Box::new(x))} else {None}{{/isNullable}}{{/isModel}}{{/required}},
{{{name}}}{{^required}}: None{{/required}}{{#required}}{{#isModel}}{{^avoidBoxedModels}}: {{^isNullable}}Box::new({{{name}}}){{/isNullable}}{{#isNullable}}if let Some(x) = {{{name}}} {Some(Box::new(x))} else {None}{{/isNullable}}{{/avoidBoxedModels}}{{/isModel}}{{/required}},
{{/vars}}
}
}
Expand All @@ -122,13 +122,13 @@ pub enum {{classname}} {
{{#description}}
/// {{{.}}}
{{/description}}
{{{name}}}(Box<{{{dataType}}}>),
{{{name}}}({{#isModel}}{{^avoidBoxedModels}}Box<{{/avoidBoxedModels}}{{/isModel}}{{{dataType}}}{{#isModel}}{{^avoidBoxedModels}}>{{/avoidBoxedModels}}{{/isModel}}),
{{/composedSchemas.oneOf}}
}

impl Default for {{classname}} {
fn default() -> Self {
{{#composedSchemas.oneOf}}{{#-first}}Self::{{{name}}}(Box::default()){{/-first}}{{/composedSchemas.oneOf}}
{{#composedSchemas.oneOf}}{{#-first}}Self::{{{name}}}(Default::default()){{/-first}}{{/composedSchemas.oneOf}}
}
}
{{/oneOf.isEmpty}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ public void testSettersForConfigValues() throws Exception {
codegen.setHideGenerationTimestamp(false);
codegen.setPreferUnsignedInt(true);
codegen.setBestFitInt(true);
codegen.setAvoidBoxedModels(true);
codegen.processOpts();

Assert.assertEquals(codegen.additionalProperties().get(CodegenConstants.HIDE_GENERATION_TIMESTAMP), Boolean.FALSE);
Expand All @@ -58,6 +59,9 @@ public void testSettersForConfigValues() throws Exception {

Assert.assertEquals(codegen.additionalProperties().get(RustClientCodegen.BEST_FIT_INT), Boolean.TRUE);
Assert.assertTrue(codegen.getBestFitInt());

Assert.assertEquals(codegen.additionalProperties().get(RustClientCodegen.AVOID_BOXED_MODELS), Boolean.TRUE);
Assert.assertTrue(codegen.getAvoidBoxedModels());
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ pub enum CreateStateRequest {

impl Default for CreateStateRequest {
fn default() -> Self {
Self::AType(Box::default())
Self::AType(Default::default())
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ pub enum CustomOneOfArraySchemaInner {

impl Default for CustomOneOfArraySchemaInner {
fn default() -> Self {
Self::AType(Box::default())
Self::AType(Default::default())
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ pub enum CustomOneOfSchema {

impl Default for CustomOneOfSchema {
fn default() -> Self {
Self::AType(Box::default())
Self::AType(Default::default())
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ pub enum GetState200Response {

impl Default for GetState200Response {
fn default() -> Self {
Self::AType(Box::default())
Self::AType(Default::default())
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@ use crate::models;
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(untagged)]
pub enum Fruit {
Apples(Box<std::collections::HashMap<String, models::Apple>>),
Grapes(Box<Vec<models::Grape>>),
Apples(std::collections::HashMap<String, models::Apple>),
Grapes(Vec<models::Grape>),
}

impl Default for Fruit {
fn default() -> Self {
Self::Apples(Box::default())
Self::Apples(Default::default())
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ pub enum Fruit {

impl Default for Fruit {
fn default() -> Self {
Self::GreenApple(Box::default())
Self::GreenApple(Default::default())
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ pub enum BarRefOrValue {

impl Default for BarRefOrValue {
fn default() -> Self {
Self::Bar(Box::default())
Self::Bar(Default::default())
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ pub enum FooRefOrValue {

impl Default for FooRefOrValue {
fn default() -> Self {
Self::Foo(Box::default())
Self::Foo(Default::default())
}
}

Expand Down
2 changes: 1 addition & 1 deletion samples/client/others/rust/hyper/oneOf/src/models/fruit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ pub enum Fruit {

impl Default for Fruit {
fn default() -> Self {
Self::Apple(Box::default())
Self::Apple(Default::default())
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ pub enum CreateStateRequest {

impl Default for CreateStateRequest {
fn default() -> Self {
Self::AType(Box::default())
Self::AType(Default::default())
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ pub enum CustomOneOfArraySchemaInner {

impl Default for CustomOneOfArraySchemaInner {
fn default() -> Self {
Self::AType(Box::default())
Self::AType(Default::default())
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ pub enum CustomOneOfSchema {

impl Default for CustomOneOfSchema {
fn default() -> Self {
Self::AType(Box::default())
Self::AType(Default::default())
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ pub enum GetState200Response {

impl Default for GetState200Response {
fn default() -> Self {
Self::AType(Box::default())
Self::AType(Default::default())
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@ use crate::models;
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(untagged)]
pub enum Fruit {
Apples(Box<std::collections::HashMap<String, models::Apple>>),
Grapes(Box<Vec<models::Grape>>),
Apples(std::collections::HashMap<String, models::Apple>),
Grapes(Vec<models::Grape>),
}

impl Default for Fruit {
fn default() -> Self {
Self::Apples(Box::default())
Self::Apples(Default::default())
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ pub enum Fruit {

impl Default for Fruit {
fn default() -> Self {
Self::GreenApple(Box::default())
Self::GreenApple(Default::default())
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ pub enum BarRefOrValue {

impl Default for BarRefOrValue {
fn default() -> Self {
Self::Bar(Box::default())
Self::Bar(Default::default())
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ pub enum FooRefOrValue {

impl Default for FooRefOrValue {
fn default() -> Self {
Self::Foo(Box::default())
Self::Foo(Default::default())
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ pub enum Fruit {

impl Default for Fruit {
fn default() -> Self {
Self::Apple(Box::default())
Self::Apple(Default::default())
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/target/
**/*.rs.bk
Cargo.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# OpenAPI Generator Ignore
# Generated by openapi-generator https://github.com/openapitools/openapi-generator

# Use this file to prevent files from being overwritten by the generator.
# The patterns follow closely to .gitignore or .dockerignore.

# As an example, the C# client generator defines ApiClient.cs.
# You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line:
#ApiClient.cs

# You can match any string of characters against a directory, file or extension with a single asterisk (*):
#foo/*/qux
# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux

# You can recursively match patterns against a directory, file or extension with a double asterisk (**):
#foo/**/qux
# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux

# You can also negate patterns with an exclamation (!).
# For example, you can ignore all files in a docs folder with the file extension .md:
#docs/*.md
# Then explicitly reverse the ignore rule for a single file:
#!docs/README.md
Loading

0 comments on commit 4b04e17

Please sign in to comment.