From d7943816116a2721c78d6b262df5c94345773d3c Mon Sep 17 00:00:00 2001 From: "jonas.hao" Date: Mon, 23 Jun 2025 23:34:03 +0800 Subject: [PATCH] feat(Rust): Add integer type inference option 1. Added IntegerType enum 2. Introduced integerType configuration option - Supports forced i32/i64 usage - Enables automatic selection based on numerical range --- .../src/language/Rust/RustRenderer.ts | 31 ++++++++++++- .../src/language/Rust/language.ts | 16 +++++++ test/inputs/schema/integer-type.1.json | 8 ++++ test/inputs/schema/integer-type.schema | 43 +++++++++++++++++++ test/languages.ts | 5 +++ 5 files changed, 102 insertions(+), 1 deletion(-) create mode 100644 test/inputs/schema/integer-type.1.json create mode 100644 test/inputs/schema/integer-type.schema diff --git a/packages/quicktype-core/src/language/Rust/RustRenderer.ts b/packages/quicktype-core/src/language/Rust/RustRenderer.ts index 22e81babc..052a4a6a1 100644 --- a/packages/quicktype-core/src/language/Rust/RustRenderer.ts +++ b/packages/quicktype-core/src/language/Rust/RustRenderer.ts @@ -27,8 +27,10 @@ import { removeNullFromUnion, } from "../../Type/TypeUtils"; +import { minMaxValueForType } from "../../attributes/Constraints"; import { keywords } from "./constants"; import type { rustOptions } from "./language"; +import { IntegerType } from "./language"; import { Density, type NamingStyleKey, @@ -96,6 +98,33 @@ export class RustRenderer extends ConvenienceRenderer { return "/// "; } + private getIntegerType(integerType: Type): string { + switch (this._options.integerType) { + case IntegerType.ForceI32: + return "i32"; + case IntegerType.ForceI64: + return "i64"; + case IntegerType.Conservative: + default: { + const minMax = minMaxValueForType(integerType); + if (minMax !== undefined) { + const [min, max] = minMax; + // Check if values fit in i32 range: [-2147483648, 2147483647] + const i32Min = -2147483648; + const i32Max = 2147483647; + + if ( + (min === undefined || min >= i32Min) && + (max === undefined || max <= i32Max) + ) { + return "i32"; + } + } + return "i64"; + } + } + } + private nullableRustType(t: Type, withIssues: boolean): Sourcelike { return ["Option<", this.breakCycle(t, withIssues), ">"]; } @@ -121,7 +150,7 @@ export class RustRenderer extends ConvenienceRenderer { "Option", ), (_boolType) => "bool", - (_integerType) => "i64", + (integerType) => this.getIntegerType(integerType), (_doubleType) => "f64", (_stringType) => "String", (arrayType) => [ diff --git a/packages/quicktype-core/src/language/Rust/language.ts b/packages/quicktype-core/src/language/Rust/language.ts index 4981d6a6f..60abb790e 100644 --- a/packages/quicktype-core/src/language/Rust/language.ts +++ b/packages/quicktype-core/src/language/Rust/language.ts @@ -10,6 +10,12 @@ import type { LanguageName, RendererOptions } from "../../types"; import { RustRenderer } from "./RustRenderer"; import { Density, Visibility } from "./utils"; +export enum IntegerType { + Conservative = "conservative", + ForceI32 = "force-i32", + ForceI64 = "force-i64", +} + export const rustOptions = { density: new EnumOption( "density", @@ -30,6 +36,16 @@ export const rustOptions = { } as const, "private", ), + integerType: new EnumOption( + "integer-type", + "Integer type inference", + { + conservative: IntegerType.Conservative, + "force-i32": IntegerType.ForceI32, + "force-i64": IntegerType.ForceI64, + } as const, + "conservative", + ), deriveDebug: new BooleanOption("derive-debug", "Derive Debug impl", false), deriveClone: new BooleanOption("derive-clone", "Derive Clone impl", false), derivePartialEq: new BooleanOption( diff --git a/test/inputs/schema/integer-type.1.json b/test/inputs/schema/integer-type.1.json new file mode 100644 index 000000000..eb9b68143 --- /dev/null +++ b/test/inputs/schema/integer-type.1.json @@ -0,0 +1,8 @@ +{ + "small_positive": 50, + "large_positive": 2500000000, + "small_negative": -50, + "large_negative": -2500000000, + "i32_range": 1000000000, + "beyond_i32": 9000000000000000000 +} diff --git a/test/inputs/schema/integer-type.schema b/test/inputs/schema/integer-type.schema new file mode 100644 index 000000000..b096a3443 --- /dev/null +++ b/test/inputs/schema/integer-type.schema @@ -0,0 +1,43 @@ +{ + "type": "object", + "properties": { + "small_positive": { + "type": "integer", + "minimum": 0, + "maximum": 100 + }, + "large_positive": { + "type": "integer", + "minimum": 0, + "maximum": 5000000000 + }, + "small_negative": { + "type": "integer", + "minimum": -100, + "maximum": 0 + }, + "large_negative": { + "type": "integer", + "minimum": -5000000000, + "maximum": 0 + }, + "i32_range": { + "type": "integer", + "minimum": -2147483648, + "maximum": 2147483647 + }, + "beyond_i32": { + "type": "integer", + "minimum": -9223372036854775808, + "maximum": 9223372036854775807 + } + }, + "required": [ + "small_positive", + "large_positive", + "small_negative", + "large_negative", + "i32_range", + "beyond_i32" + ] +} diff --git a/test/languages.ts b/test/languages.ts index 9573f3e57..ee795909f 100644 --- a/test/languages.ts +++ b/test/languages.ts @@ -260,6 +260,9 @@ export const RustLanguage: Language = { { visibility: "crate" }, { visibility: "private" }, { visibility: "public" }, + { "integer-type": "conservative" }, + { "integer-type": "force-i32" }, + { "integer-type": "force-i64" }, ], sourceFiles: ["src/language/Rust/index.ts"], }; @@ -584,6 +587,8 @@ export const CPlusPlusLanguage: Language = { skipSchema: [ // uses too much memory "keyword-unions.schema", + // seems like a problem with integer range check + "integer-type.schema", ], rendererOptions: {}, quickTestRendererOptions: [