Skip to content

Commit

Permalink
feat(rust): support various Rust integer types (#2)
Browse files Browse the repository at this point in the history
  • Loading branch information
thrykol authored May 26, 2022
1 parent a39d86c commit f861060
Show file tree
Hide file tree
Showing 11 changed files with 554 additions and 59 deletions.
2 changes: 2 additions & 0 deletions docs/generators/rust.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,13 @@ These options may be applied as additional-properties (cli) or configOptions (pl

| Option | Description | Values | Default |
| ------ | ----------- | ------ | ------- |
|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|
|library|library template (sub-template) to use.|<dl><dt>**hyper**</dt><dd>HTTP client: Hyper.</dd><dt>**reqwest**</dt><dd>HTTP client: Reqwest.</dd></dl>|reqwest|
|packageName|Rust package name (convention: lowercase).| |openapi|
|packageVersion|Rust package version.| |1.0.0|
|preferUnsignedInt|Prefer unsigned integers where minimum value is &gt;= 0| |false|
|supportAsync|If set, generate async function call instead. This option is for 'reqwest' library only| |true|
|supportMultipleResponses|If set, return type wraps an enum of all possible 2xx schemas. This option is for 'reqwest' library only| |false|
|useSingleRequestParameter|Setting this property to true will generate functions with a single argument containing all API endpoint parameters instead of one argument per parameter.| |false|
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ public HaskellServantCodegen() {
.wireFormatFeatures(EnumSet.of(WireFormatFeature.JSON, WireFormatFeature.XML))
.securityFeatures(EnumSet.of(
SecurityFeature.BasicAuth,
SecurityFeature.BearerToken,
SecurityFeature.ApiKey,
SecurityFeature.OAuth2_Implicit
))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
import java.io.File;
import java.io.IOException;
import java.io.Writer;
import java.math.BigDecimal;
import java.util.*;

import static org.openapitools.codegen.utils.StringUtils.camelize;
Expand All @@ -50,13 +51,17 @@ public class RustClientCodegen extends DefaultCodegen implements CodegenConfig {
private boolean supportAsync = true;
private boolean supportMultipleResponses = false;
private boolean withAWSV4Signature = false;
private boolean preferUnsignedInt = false;
private boolean bestFitInt = false;

public static final String PACKAGE_NAME = "packageName";
public static final String PACKAGE_VERSION = "packageVersion";
public static final String HYPER_LIBRARY = "hyper";
public static final String REQWEST_LIBRARY = "reqwest";
public static final String SUPPORT_ASYNC = "supportAsync";
public static final String SUPPORT_MULTIPLE_RESPONSES = "supportMultipleResponses";
public static final String PREFER_UNSIGNED_INT = "preferUnsignedInt";
public static final String BEST_FIT_INT = "bestFitInt";

protected String packageName = "openapi";
protected String packageVersion = "1.0.0";
Expand All @@ -65,6 +70,7 @@ public class RustClientCodegen extends DefaultCodegen implements CodegenConfig {
protected String apiFolder = "src/apis";
protected String modelFolder = "src/models";
protected String enumSuffix = ""; // default to empty string for backward compatibility
protected Map<String, String> unsignedMapping;

public CodegenType getTag() {
return CodegenType.CLIENT;
Expand Down Expand Up @@ -174,6 +180,12 @@ public RustClientCodegen() {
typeMapping.put("object", "serde_json::Value");
typeMapping.put("AnyType", "serde_json::Value");

unsignedMapping = new HashMap<>();
unsignedMapping.put("i8", "u8");
unsignedMapping.put("i16", "u16");
unsignedMapping.put("i32", "u32");
unsignedMapping.put("i64", "u64");

// no need for rust
//importMapping = new HashMap<String, String>();

Expand All @@ -193,6 +205,10 @@ public RustClientCodegen() {
cliOptions.add(new CliOption(CodegenConstants.ENUM_NAME_SUFFIX, CodegenConstants.ENUM_NAME_SUFFIX_DESC).defaultValue(this.enumSuffix));
cliOptions.add(new CliOption(CodegenConstants.WITH_AWSV4_SIGNATURE_COMMENT, CodegenConstants.WITH_AWSV4_SIGNATURE_COMMENT_DESC, SchemaTypeUtil.BOOLEAN_TYPE)
.defaultValue(Boolean.FALSE.toString()));
cliOptions.add(new CliOption(PREFER_UNSIGNED_INT, "Prefer unsigned integers where minimum value is >= 0", SchemaTypeUtil.BOOLEAN_TYPE)
.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()));

supportedLibraries.put(HYPER_LIBRARY, "HTTP client: Hyper.");
supportedLibraries.put(REQWEST_LIBRARY, "HTTP client: Reqwest.");
Expand Down Expand Up @@ -296,6 +312,16 @@ public void processOpts() {
}
writePropertyBack(SUPPORT_MULTIPLE_RESPONSES, getSupportMultipleReturns());

if (additionalProperties.containsKey(PREFER_UNSIGNED_INT)) {
this.setPreferUnsignedInt(convertPropertyToBoolean(PREFER_UNSIGNED_INT));
}
writePropertyBack(PREFER_UNSIGNED_INT, getPreferUnsignedInt());

if (additionalProperties.containsKey(BEST_FIT_INT)) {
this.setBestFitInt(convertPropertyToBoolean(BEST_FIT_INT));
}
writePropertyBack(BEST_FIT_INT, getBestFitInt());

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

Expand Down Expand Up @@ -360,6 +386,22 @@ public void setSupportMultipleReturns(boolean supportMultipleResponses) {
this.supportMultipleResponses = supportMultipleResponses;
}

public boolean getPreferUnsignedInt() {
return preferUnsignedInt;
}

public void setPreferUnsignedInt(boolean preferUnsignedInt) {
this.preferUnsignedInt = preferUnsignedInt;
}

public boolean getBestFitInt() {
return bestFitInt;
}

public void setBestFitInt(boolean bestFitInt) {
this.bestFitInt = bestFitInt;
}

private boolean getUseSingleRequestParameter() {
return useSingleRequestParameter;
}
Expand Down Expand Up @@ -414,7 +456,8 @@ public String toVarName(String name) {

@Override
public String toParamName(String name) {
return toVarName(name);
// $ref appears to be all uppercase which is contrary to rustfmt practice so lowercase parameters
return toVarName(name.toLowerCase());
}

@Override
Expand Down Expand Up @@ -525,10 +568,43 @@ public String getTypeDeclaration(Schema p) {
@Override
public String getSchemaType(Schema p) {
String schemaType = super.getSchemaType(p);
if (typeMapping.containsKey(schemaType)) {
return typeMapping.get(schemaType);
String type = typeMapping.getOrDefault(schemaType, schemaType);

if (convertPropertyToBoolean(BEST_FIT_INT)) {
try {
BigDecimal maximum = p.getMaximum();
BigDecimal minimum = p.getMinimum();
if (maximum != null && minimum != null) {
long max = maximum.longValueExact();
long min = minimum.longValueExact();

if (max <= 255 && min >= -256) {
type = "i8";
}
else if (max <= Short.MAX_VALUE && min >= Short.MIN_VALUE) {
type = "i16";
}
else if (max <= Integer.MAX_VALUE && min >= Integer.MIN_VALUE) {
type = "i32";
}
}
} catch (ArithmeticException a) {
// no-op: use the base type
}
}
return schemaType;

if (convertPropertyToBoolean(PREFER_UNSIGNED_INT) && unsignedMapping.containsKey(type)) {
try {
BigDecimal minimum = p.getMinimum();
if (minimum != null && minimum.longValueExact() >= 0) {
type = unsignedMapping.get(type);
}
} catch (ArithmeticException a) {
// no-op: use the base type
}
}

return type;
}

@Override
Expand Down Expand Up @@ -640,7 +716,6 @@ public String escapeUnsafeCharacters(String input) {
return input.replace("*/", "*_/").replace("/*", "/_*");
}


@Override
public String toEnumValue(String value, String datatype) {
if ("int".equals(datatype) || "double".equals(datatype) || "float".equals(datatype)) {
Expand Down
Loading

0 comments on commit f861060

Please # to comment.