Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add useCow option for Rust #2490

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
48 changes: 43 additions & 5 deletions packages/quicktype-core/src/language/Rust.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ export const rustOptions = {
["crate", Visibility.Crate],
["public", Visibility.Public]
]),
useCow: new BooleanOption("use-cow", "Use Cow<'_, str> instead of String", false),
deriveDebug: new BooleanOption("derive-debug", "Derive Debug impl", false),
deriveClone: new BooleanOption("derive-clone", "Derive Clone impl", false),
derivePartialEq: new BooleanOption("derive-partial-eq", "Derive PartialEq impl", false),
Expand Down Expand Up @@ -124,6 +125,7 @@ export class RustTargetLanguage extends TargetLanguage {
return [
rustOptions.density,
rustOptions.visibility,
rustOptions.useCow,
rustOptions.deriveDebug,
rustOptions.deriveClone,
rustOptions.derivePartialEq,
Expand Down Expand Up @@ -315,6 +317,13 @@ export class RustRenderer extends ConvenienceRenderer {
return kind === "array" || kind === "map";
}

private nameForNamedTypeWithLifetimes(t: Type): Sourcelike {
return [
this.nameForNamedType(t),
this.lifetimeTagForType(t)
]
}

private rustType(t: Type, withIssues = false): Sourcelike {
return matchType<Sourcelike>(
t,
Expand All @@ -323,9 +332,9 @@ export class RustRenderer extends ConvenienceRenderer {
_boolType => "bool",
_integerType => "i64",
_doubleType => "f64",
_stringType => "String",
_stringType => this.stringType(),
arrayType => ["Vec<", this.rustType(arrayType.items, withIssues), ">"],
classType => this.nameForNamedType(classType),
classType => this.nameForNamedTypeWithLifetimes(classType),
mapType => ["HashMap<String, ", this.rustType(mapType.values, withIssues), ">"],
enumType => this.nameForNamedType(enumType),
unionType => {
Expand All @@ -338,8 +347,8 @@ export class RustRenderer extends ConvenienceRenderer {
const isCycleBreaker = this.isCycleBreakerType(unionType);

const name = isCycleBreaker
? ["Box<", this.nameForNamedType(unionType), ">"]
: this.nameForNamedType(unionType);
? ["Box<", this.nameForNamedTypeWithLifetimes(unionType), ">"]
: this.nameForNamedTypeWithLifetimes(unionType);

return hasNull !== null ? (["Option<", name, ">"] as Sourcelike) : name;
}
Expand Down Expand Up @@ -374,6 +383,13 @@ export class RustRenderer extends ConvenienceRenderer {
if (nullable !== null) this.emitLine('#[serde(skip_serializing_if = "Option::is_none")]');
}
}

private stringType(): string {
if(this._options.useCow) {
return "Cow<'a, str>";
}
return "String";
}

private get visibility(): string {
if (this._options.visibility === Visibility.Crate) {
Expand Down Expand Up @@ -416,9 +432,27 @@ export class RustRenderer extends ConvenienceRenderer {
this.emitLine(this.visibility, name, ": ", this.breakCycle(prop.type, true), ",");
});

this.emitBlock(["pub struct ", className], structBody);
this.emitBlock(["pub struct ", className, this.lifetimeTagForType(c)], structBody);
}

protected lifetimeTagForType(t: Type): Sourcelike{
const lifetimes = this.lifetimesForType(t);
if(lifetimes.size <= 0) return [];
return `<${[...lifetimes].join(", ")}>`;
}

protected lifetimesForType(t: Type): Set<string> {
if(t.isPrimitive() && t.kind == "string") return new Set(["'a"]);
const lifetimes = new Set<string>();
for(const child of t.getChildren()) {
for(const child_lifetime of this.lifetimesForType(child)) {
lifetimes.add(child_lifetime);
}
}
return lifetimes;
}


protected emitBlock(line: Sourcelike, f: () => void): void {
this.emitLine(line, " {");
this.indent(f);
Expand Down Expand Up @@ -527,6 +561,10 @@ export class RustRenderer extends ConvenienceRenderer {
this.emitLine("use std::collections::HashMap;");
}

if (this._options.useCow) {
this.emitLine("use std::borrow::Cow;");
}

this.forEachTopLevel(
"leading",
(t, name) => this.emitTopLevelAlias(t, name),
Expand Down
Loading