Bug 1965313 - Reimplement enum discriminents, r=bgruber

Differential Revision: https://phabricator.services.mozilla.com/D248491
This commit is contained in:
Ben Dean-Kawamura
2025-05-14 18:41:55 +00:00
committed by bdeankawamura@mozilla.com
parent 90368cc237
commit 02d50105b9
14 changed files with 348 additions and 38 deletions

View File

@@ -1268,47 +1268,47 @@ export const Interest = {
/** /**
* INCONCLUSIVE * INCONCLUSIVE
*/ */
INCONCLUSIVE: 1, INCONCLUSIVE: 0,
/** /**
* ANIMALS * ANIMALS
*/ */
ANIMALS: 2, ANIMALS: 1,
/** /**
* ARTS * ARTS
*/ */
ARTS: 3, ARTS: 2,
/** /**
* AUTOS * AUTOS
*/ */
AUTOS: 4, AUTOS: 3,
/** /**
* BUSINESS * BUSINESS
*/ */
BUSINESS: 5, BUSINESS: 4,
/** /**
* CAREER * CAREER
*/ */
CAREER: 6, CAREER: 5,
/** /**
* EDUCATION * EDUCATION
*/ */
EDUCATION: 7, EDUCATION: 6,
/** /**
* FASHION * FASHION
*/ */
FASHION: 8, FASHION: 7,
/** /**
* FINANCE * FINANCE
*/ */
FINANCE: 9, FINANCE: 8,
/** /**
* FOOD * FOOD
*/ */
FOOD: 10, FOOD: 9,
/** /**
* GOVERNMENT * GOVERNMENT
*/ */
GOVERNMENT: 11, GOVERNMENT: 10,
/** /**
* HOBBIES * HOBBIES
*/ */
@@ -1347,6 +1347,7 @@ Object.freeze(Interest);
// Export the FFIConverter object to make external types work. // Export the FFIConverter object to make external types work.
export class FfiConverterTypeInterest extends FfiConverterArrayBuffer { export class FfiConverterTypeInterest extends FfiConverterArrayBuffer {
static read(dataStream) { static read(dataStream) {
// Use sequential indices (1-based) for the wire format to match the Rust scaffolding
switch (dataStream.readInt32()) { switch (dataStream.readInt32()) {
case 1: case 1:
return Interest.INCONCLUSIVE return Interest.INCONCLUSIVE
@@ -1392,6 +1393,7 @@ export class FfiConverterTypeInterest extends FfiConverterArrayBuffer {
} }
static write(dataStream, value) { static write(dataStream, value) {
// Use sequential indices (1-based) for the wire format to match the Rust scaffolding
if (value === Interest.INCONCLUSIVE) { if (value === Interest.INCONCLUSIVE) {
dataStream.writeInt32(1); dataStream.writeInt32(1);
return; return;

View File

@@ -591,6 +591,7 @@ RemoteSettingsServer.Custom = class extends RemoteSettingsServer{
// Export the FFIConverter object to make external types work. // Export the FFIConverter object to make external types work.
export class FfiConverterTypeRemoteSettingsServer extends FfiConverterArrayBuffer { export class FfiConverterTypeRemoteSettingsServer extends FfiConverterArrayBuffer {
static read(dataStream) { static read(dataStream) {
// Use sequential indices (1-based) for the wire format to match the Rust scaffolding
switch (dataStream.readInt32()) { switch (dataStream.readInt32()) {
case 1: case 1:
return new RemoteSettingsServer.Prod( return new RemoteSettingsServer.Prod(
@@ -611,6 +612,7 @@ export class FfiConverterTypeRemoteSettingsServer extends FfiConverterArrayBuffe
} }
static write(dataStream, value) { static write(dataStream, value) {
// Use sequential indices (1-based) for the wire format to match the Rust scaffolding
if (value instanceof RemoteSettingsServer.Prod) { if (value instanceof RemoteSettingsServer.Prod) {
dataStream.writeInt32(1); dataStream.writeInt32(1);
return; return;

View File

@@ -356,17 +356,18 @@ export const JsonEngineMethod = {
/** /**
* POST * POST
*/ */
POST: 1, POST: 2,
/** /**
* GET * GET
*/ */
GET: 2, GET: 1,
}; };
Object.freeze(JsonEngineMethod); Object.freeze(JsonEngineMethod);
// Export the FFIConverter object to make external types work. // Export the FFIConverter object to make external types work.
export class FfiConverterTypeJSONEngineMethod extends FfiConverterArrayBuffer { export class FfiConverterTypeJSONEngineMethod extends FfiConverterArrayBuffer {
static read(dataStream) { static read(dataStream) {
// Use sequential indices (1-based) for the wire format to match the Rust scaffolding
switch (dataStream.readInt32()) { switch (dataStream.readInt32()) {
case 1: case 1:
return JsonEngineMethod.POST return JsonEngineMethod.POST
@@ -378,6 +379,7 @@ export class FfiConverterTypeJSONEngineMethod extends FfiConverterArrayBuffer {
} }
static write(dataStream, value) { static write(dataStream, value) {
// Use sequential indices (1-based) for the wire format to match the Rust scaffolding
if (value === JsonEngineMethod.POST) { if (value === JsonEngineMethod.POST) {
dataStream.writeInt32(1); dataStream.writeInt32(1);
return; return;
@@ -1039,17 +1041,18 @@ export const SearchEngineClassification = {
/** /**
* GENERAL * GENERAL
*/ */
GENERAL: 1, GENERAL: 2,
/** /**
* UNKNOWN * UNKNOWN
*/ */
UNKNOWN: 2, UNKNOWN: 1,
}; };
Object.freeze(SearchEngineClassification); Object.freeze(SearchEngineClassification);
// Export the FFIConverter object to make external types work. // Export the FFIConverter object to make external types work.
export class FfiConverterTypeSearchEngineClassification extends FfiConverterArrayBuffer { export class FfiConverterTypeSearchEngineClassification extends FfiConverterArrayBuffer {
static read(dataStream) { static read(dataStream) {
// Use sequential indices (1-based) for the wire format to match the Rust scaffolding
switch (dataStream.readInt32()) { switch (dataStream.readInt32()) {
case 1: case 1:
return SearchEngineClassification.GENERAL return SearchEngineClassification.GENERAL
@@ -1061,6 +1064,7 @@ export class FfiConverterTypeSearchEngineClassification extends FfiConverterArra
} }
static write(dataStream, value) { static write(dataStream, value) {
// Use sequential indices (1-based) for the wire format to match the Rust scaffolding
if (value === SearchEngineClassification.GENERAL) { if (value === SearchEngineClassification.GENERAL) {
dataStream.writeInt32(1); dataStream.writeInt32(1);
return; return;
@@ -2044,6 +2048,7 @@ Object.freeze(SearchUpdateChannel);
// Export the FFIConverter object to make external types work. // Export the FFIConverter object to make external types work.
export class FfiConverterTypeSearchUpdateChannel extends FfiConverterArrayBuffer { export class FfiConverterTypeSearchUpdateChannel extends FfiConverterArrayBuffer {
static read(dataStream) { static read(dataStream) {
// Use sequential indices (1-based) for the wire format to match the Rust scaffolding
switch (dataStream.readInt32()) { switch (dataStream.readInt32()) {
case 1: case 1:
return SearchUpdateChannel.NIGHTLY return SearchUpdateChannel.NIGHTLY
@@ -2063,6 +2068,7 @@ export class FfiConverterTypeSearchUpdateChannel extends FfiConverterArrayBuffer
} }
static write(dataStream, value) { static write(dataStream, value) {
// Use sequential indices (1-based) for the wire format to match the Rust scaffolding
if (value === SearchUpdateChannel.NIGHTLY) { if (value === SearchUpdateChannel.NIGHTLY) {
dataStream.writeInt32(1); dataStream.writeInt32(1);
return; return;
@@ -2131,6 +2137,7 @@ Object.freeze(SearchApplicationName);
// Export the FFIConverter object to make external types work. // Export the FFIConverter object to make external types work.
export class FfiConverterTypeSearchApplicationName extends FfiConverterArrayBuffer { export class FfiConverterTypeSearchApplicationName extends FfiConverterArrayBuffer {
static read(dataStream) { static read(dataStream) {
// Use sequential indices (1-based) for the wire format to match the Rust scaffolding
switch (dataStream.readInt32()) { switch (dataStream.readInt32()) {
case 1: case 1:
return SearchApplicationName.FIREFOX_ANDROID return SearchApplicationName.FIREFOX_ANDROID
@@ -2148,6 +2155,7 @@ export class FfiConverterTypeSearchApplicationName extends FfiConverterArrayBuff
} }
static write(dataStream, value) { static write(dataStream, value) {
// Use sequential indices (1-based) for the wire format to match the Rust scaffolding
if (value === SearchApplicationName.FIREFOX_ANDROID) { if (value === SearchApplicationName.FIREFOX_ANDROID) {
dataStream.writeInt32(1); dataStream.writeInt32(1);
return; return;
@@ -2204,6 +2212,7 @@ Object.freeze(SearchDeviceType);
// Export the FFIConverter object to make external types work. // Export the FFIConverter object to make external types work.
export class FfiConverterTypeSearchDeviceType extends FfiConverterArrayBuffer { export class FfiConverterTypeSearchDeviceType extends FfiConverterArrayBuffer {
static read(dataStream) { static read(dataStream) {
// Use sequential indices (1-based) for the wire format to match the Rust scaffolding
switch (dataStream.readInt32()) { switch (dataStream.readInt32()) {
case 1: case 1:
return SearchDeviceType.SMARTPHONE return SearchDeviceType.SMARTPHONE
@@ -2217,6 +2226,7 @@ export class FfiConverterTypeSearchDeviceType extends FfiConverterArrayBuffer {
} }
static write(dataStream, value) { static write(dataStream, value) {
// Use sequential indices (1-based) for the wire format to match the Rust scaffolding
if (value === SearchDeviceType.SMARTPHONE) { if (value === SearchDeviceType.SMARTPHONE) {
dataStream.writeInt32(1); dataStream.writeInt32(1);
return; return;

View File

@@ -755,21 +755,22 @@ export const GeonameMatchType = {
/** /**
* For U.S. states, abbreviations are the usual two-letter codes ("CA"). * For U.S. states, abbreviations are the usual two-letter codes ("CA").
*/ */
ABBREVIATION: 1, ABBREVIATION: 0,
/** /**
* AIRPORT_CODE * AIRPORT_CODE
*/ */
AIRPORT_CODE: 2, AIRPORT_CODE: 1,
/** /**
* This includes any names that aren't abbreviations or airport codes. * This includes any names that aren't abbreviations or airport codes.
*/ */
NAME: 3, NAME: 2,
}; };
Object.freeze(GeonameMatchType); Object.freeze(GeonameMatchType);
// Export the FFIConverter object to make external types work. // Export the FFIConverter object to make external types work.
export class FfiConverterTypeGeonameMatchType extends FfiConverterArrayBuffer { export class FfiConverterTypeGeonameMatchType extends FfiConverterArrayBuffer {
static read(dataStream) { static read(dataStream) {
// Use sequential indices (1-based) for the wire format to match the Rust scaffolding
switch (dataStream.readInt32()) { switch (dataStream.readInt32()) {
case 1: case 1:
return GeonameMatchType.ABBREVIATION return GeonameMatchType.ABBREVIATION
@@ -783,6 +784,7 @@ export class FfiConverterTypeGeonameMatchType extends FfiConverterArrayBuffer {
} }
static write(dataStream, value) { static write(dataStream, value) {
// Use sequential indices (1-based) for the wire format to match the Rust scaffolding
if (value === GeonameMatchType.ABBREVIATION) { if (value === GeonameMatchType.ABBREVIATION) {
dataStream.writeInt32(1); dataStream.writeInt32(1);
return; return;
@@ -1455,6 +1457,7 @@ Suggestion.Dynamic = class extends Suggestion{
// Export the FFIConverter object to make external types work. // Export the FFIConverter object to make external types work.
export class FfiConverterTypeSuggestion extends FfiConverterArrayBuffer { export class FfiConverterTypeSuggestion extends FfiConverterArrayBuffer {
static read(dataStream) { static read(dataStream) {
// Use sequential indices (1-based) for the wire format to match the Rust scaffolding
switch (dataStream.readInt32()) { switch (dataStream.readInt32()) {
case 1: case 1:
return new Suggestion.Amp( return new Suggestion.Amp(
@@ -1552,6 +1555,7 @@ export class FfiConverterTypeSuggestion extends FfiConverterArrayBuffer {
} }
static write(dataStream, value) { static write(dataStream, value) {
// Use sequential indices (1-based) for the wire format to match the Rust scaffolding
if (value instanceof Suggestion.Amp) { if (value instanceof Suggestion.Amp) {
dataStream.writeInt32(1); dataStream.writeInt32(1);
FfiConverterString.write(dataStream, value.title); FfiConverterString.write(dataStream, value.title);
@@ -2070,6 +2074,7 @@ Object.freeze(SuggestionProvider);
// Export the FFIConverter object to make external types work. // Export the FFIConverter object to make external types work.
export class FfiConverterTypeSuggestionProvider extends FfiConverterArrayBuffer { export class FfiConverterTypeSuggestionProvider extends FfiConverterArrayBuffer {
static read(dataStream) { static read(dataStream) {
// Use sequential indices (1-based) for the wire format to match the Rust scaffolding
switch (dataStream.readInt32()) { switch (dataStream.readInt32()) {
case 1: case 1:
return SuggestionProvider.AMP return SuggestionProvider.AMP
@@ -2095,6 +2100,7 @@ export class FfiConverterTypeSuggestionProvider extends FfiConverterArrayBuffer
} }
static write(dataStream, value) { static write(dataStream, value) {
// Use sequential indices (1-based) for the wire format to match the Rust scaffolding
if (value === SuggestionProvider.AMP) { if (value === SuggestionProvider.AMP) {
dataStream.writeInt32(1); dataStream.writeInt32(1);
return; return;
@@ -2327,6 +2333,7 @@ Object.freeze(AmpMatchingStrategy);
// Export the FFIConverter object to make external types work. // Export the FFIConverter object to make external types work.
export class FfiConverterTypeAmpMatchingStrategy extends FfiConverterArrayBuffer { export class FfiConverterTypeAmpMatchingStrategy extends FfiConverterArrayBuffer {
static read(dataStream) { static read(dataStream) {
// Use sequential indices (1-based) for the wire format to match the Rust scaffolding
switch (dataStream.readInt32()) { switch (dataStream.readInt32()) {
case 1: case 1:
return AmpMatchingStrategy.NO_KEYWORD_EXPANSION return AmpMatchingStrategy.NO_KEYWORD_EXPANSION
@@ -2340,6 +2347,7 @@ export class FfiConverterTypeAmpMatchingStrategy extends FfiConverterArrayBuffer
} }
static write(dataStream, value) { static write(dataStream, value) {
// Use sequential indices (1-based) for the wire format to match the Rust scaffolding
if (value === AmpMatchingStrategy.NO_KEYWORD_EXPANSION) { if (value === AmpMatchingStrategy.NO_KEYWORD_EXPANSION) {
dataStream.writeInt32(1); dataStream.writeInt32(1);
return; return;
@@ -2925,17 +2933,18 @@ export const GeonameType = {
/** /**
* CITY * CITY
*/ */
CITY: 1, CITY: 0,
/** /**
* REGION * REGION
*/ */
REGION: 2, REGION: 1,
}; };
Object.freeze(GeonameType); Object.freeze(GeonameType);
// Export the FFIConverter object to make external types work. // Export the FFIConverter object to make external types work.
export class FfiConverterTypeGeonameType extends FfiConverterArrayBuffer { export class FfiConverterTypeGeonameType extends FfiConverterArrayBuffer {
static read(dataStream) { static read(dataStream) {
// Use sequential indices (1-based) for the wire format to match the Rust scaffolding
switch (dataStream.readInt32()) { switch (dataStream.readInt32()) {
case 1: case 1:
return GeonameType.CITY return GeonameType.CITY
@@ -2947,6 +2956,7 @@ export class FfiConverterTypeGeonameType extends FfiConverterArrayBuffer {
} }
static write(dataStream, value) { static write(dataStream, value) {
// Use sequential indices (1-based) for the wire format to match the Rust scaffolding
if (value === GeonameType.CITY) { if (value === GeonameType.CITY) {
dataStream.writeInt32(1); dataStream.writeInt32(1);
return; return;
@@ -2976,22 +2986,23 @@ export const InterruptKind = {
/** /**
* Interrupt read operations like [SuggestStore::query] * Interrupt read operations like [SuggestStore::query]
*/ */
READ: 1, READ: 0,
/** /**
* Interrupt write operations. This mostly means [SuggestStore::ingest], but * Interrupt write operations. This mostly means [SuggestStore::ingest], but
* other operations may also be interrupted. * other operations may also be interrupted.
*/ */
WRITE: 2, WRITE: 1,
/** /**
* Interrupt both read and write operations, * Interrupt both read and write operations,
*/ */
READ_WRITE: 3, READ_WRITE: 2,
}; };
Object.freeze(InterruptKind); Object.freeze(InterruptKind);
// Export the FFIConverter object to make external types work. // Export the FFIConverter object to make external types work.
export class FfiConverterTypeInterruptKind extends FfiConverterArrayBuffer { export class FfiConverterTypeInterruptKind extends FfiConverterArrayBuffer {
static read(dataStream) { static read(dataStream) {
// Use sequential indices (1-based) for the wire format to match the Rust scaffolding
switch (dataStream.readInt32()) { switch (dataStream.readInt32()) {
case 1: case 1:
return InterruptKind.READ return InterruptKind.READ
@@ -3005,6 +3016,7 @@ export class FfiConverterTypeInterruptKind extends FfiConverterArrayBuffer {
} }
static write(dataStream, value) { static write(dataStream, value) {
// Use sequential indices (1-based) for the wire format to match the Rust scaffolding
if (value === InterruptKind.READ) { if (value === InterruptKind.READ) {
dataStream.writeInt32(1); dataStream.writeInt32(1);
return; return;
@@ -3197,6 +3209,7 @@ SuggestProviderConfig.Weather = class extends SuggestProviderConfig{
// Export the FFIConverter object to make external types work. // Export the FFIConverter object to make external types work.
export class FfiConverterTypeSuggestProviderConfig extends FfiConverterArrayBuffer { export class FfiConverterTypeSuggestProviderConfig extends FfiConverterArrayBuffer {
static read(dataStream) { static read(dataStream) {
// Use sequential indices (1-based) for the wire format to match the Rust scaffolding
switch (dataStream.readInt32()) { switch (dataStream.readInt32()) {
case 1: case 1:
return new SuggestProviderConfig.Weather( return new SuggestProviderConfig.Weather(
@@ -3209,6 +3222,7 @@ export class FfiConverterTypeSuggestProviderConfig extends FfiConverterArrayBuff
} }
static write(dataStream, value) { static write(dataStream, value) {
// Use sequential indices (1-based) for the wire format to match the Rust scaffolding
if (value instanceof SuggestProviderConfig.Weather) { if (value instanceof SuggestProviderConfig.Weather) {
dataStream.writeInt32(1); dataStream.writeInt32(1);
FfiConverterFloat64.write(dataStream, value.score); FfiConverterFloat64.write(dataStream, value.score);

View File

@@ -293,33 +293,34 @@ export const DeviceType = {
/** /**
* DESKTOP * DESKTOP
*/ */
DESKTOP: 1, DESKTOP: 0,
/** /**
* MOBILE * MOBILE
*/ */
MOBILE: 2, MOBILE: 1,
/** /**
* TABLET * TABLET
*/ */
TABLET: 3, TABLET: 2,
/** /**
* VR * VR
*/ */
VR: 4, VR: 3,
/** /**
* TV * TV
*/ */
TV: 5, TV: 4,
/** /**
* UNKNOWN * UNKNOWN
*/ */
UNKNOWN: 6, UNKNOWN: 5,
}; };
Object.freeze(DeviceType); Object.freeze(DeviceType);
// Export the FFIConverter object to make external types work. // Export the FFIConverter object to make external types work.
export class FfiConverterTypeDeviceType extends FfiConverterArrayBuffer { export class FfiConverterTypeDeviceType extends FfiConverterArrayBuffer {
static read(dataStream) { static read(dataStream) {
// Use sequential indices (1-based) for the wire format to match the Rust scaffolding
switch (dataStream.readInt32()) { switch (dataStream.readInt32()) {
case 1: case 1:
return DeviceType.DESKTOP return DeviceType.DESKTOP
@@ -339,6 +340,7 @@ export class FfiConverterTypeDeviceType extends FfiConverterArrayBuffer {
} }
static write(dataStream, value) { static write(dataStream, value) {
// Use sequential indices (1-based) for the wire format to match the Rust scaffolding
if (value === DeviceType.DESKTOP) { if (value === DeviceType.DESKTOP) {
dataStream.writeInt32(1); dataStream.writeInt32(1);
return; return;

View File

@@ -842,6 +842,7 @@ RemoteCommand.CloseTab = class extends RemoteCommand{
// Export the FFIConverter object to make external types work. // Export the FFIConverter object to make external types work.
export class FfiConverterTypeRemoteCommand extends FfiConverterArrayBuffer { export class FfiConverterTypeRemoteCommand extends FfiConverterArrayBuffer {
static read(dataStream) { static read(dataStream) {
// Use sequential indices (1-based) for the wire format to match the Rust scaffolding
switch (dataStream.readInt32()) { switch (dataStream.readInt32()) {
case 1: case 1:
return new RemoteCommand.CloseTab( return new RemoteCommand.CloseTab(
@@ -853,6 +854,7 @@ export class FfiConverterTypeRemoteCommand extends FfiConverterArrayBuffer {
} }
static write(dataStream, value) { static write(dataStream, value) {
// Use sequential indices (1-based) for the wire format to match the Rust scaffolding
if (value instanceof RemoteCommand.CloseTab) { if (value instanceof RemoteCommand.CloseTab) {
dataStream.writeInt32(1); dataStream.writeInt32(1);
FfiConverterString.write(dataStream, value.url); FfiConverterString.write(dataStream, value.url);

View File

@@ -693,21 +693,22 @@ export const QuotaReason = {
/** /**
* TOTAL_BYTES * TOTAL_BYTES
*/ */
TOTAL_BYTES: 1, TOTAL_BYTES: 0,
/** /**
* ITEM_BYTES * ITEM_BYTES
*/ */
ITEM_BYTES: 2, ITEM_BYTES: 1,
/** /**
* MAX_ITEMS * MAX_ITEMS
*/ */
MAX_ITEMS: 3, MAX_ITEMS: 2,
}; };
Object.freeze(QuotaReason); Object.freeze(QuotaReason);
// Export the FFIConverter object to make external types work. // Export the FFIConverter object to make external types work.
export class FfiConverterTypeQuotaReason extends FfiConverterArrayBuffer { export class FfiConverterTypeQuotaReason extends FfiConverterArrayBuffer {
static read(dataStream) { static read(dataStream) {
// Use sequential indices (1-based) for the wire format to match the Rust scaffolding
switch (dataStream.readInt32()) { switch (dataStream.readInt32()) {
case 1: case 1:
return QuotaReason.TOTAL_BYTES return QuotaReason.TOTAL_BYTES
@@ -721,6 +722,7 @@ export class FfiConverterTypeQuotaReason extends FfiConverterArrayBuffer {
} }
static write(dataStream, value) { static write(dataStream, value) {
// Use sequential indices (1-based) for the wire format to match the Rust scaffolding
if (value === QuotaReason.TOTAL_BYTES) { if (value === QuotaReason.TOTAL_BYTES) {
dataStream.writeInt32(1); dataStream.writeInt32(1);
return; return;

View File

@@ -0,0 +1,63 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use super::*;
pub fn pass(en: &mut Enum) -> Result<()> {
// Determine the actual discriminants for each variant.
//
// TODO: the UniFFI general pipeline should probably do this. If this was introduced earlier
// in the pipeline, we wouldn't need to hand-code so many fields.
en.resolved_discr_type = match &en.discr_type {
Some(type_node) => type_node.clone(),
None => TypeNode {
ty: Type::UInt8,
canonical_name: "UInt8".to_string(),
ffi_converter: "FfiConverterUInt8".to_string(),
is_used_as_error: false,
ffi_type: FfiTypeNode {
ty: FfiType::UInt8,
type_name: "uint8_t".to_string(),
},
},
};
let discr_type = &en.resolved_discr_type;
let mut last_variant: Option<&Variant> = None;
for variant in en.variants.iter_mut() {
match &variant.discr {
None => {
let lit = match last_variant {
None => match &discr_type.ty {
Type::UInt8 | Type::UInt16 | Type::UInt32 | Type::UInt64 => {
Literal::UInt(0, Radix::Decimal, discr_type.clone())
}
Type::Int8 | Type::Int16 | Type::Int32 | Type::Int64 => {
Literal::Int(0, Radix::Decimal, discr_type.clone())
}
ty => bail!("Invalid enum discriminant type: {ty:?}"),
},
Some(variant) => match &variant.resolved_discr.lit {
Literal::UInt(val, _, _) => {
Literal::UInt(val + 1, Radix::Decimal, discr_type.clone())
}
Literal::Int(val, _, _) => {
Literal::Int(val + 1, Radix::Decimal, discr_type.clone())
}
lit => bail!("Invalid enum discriminant literal: {lit:?}"),
},
};
variant.resolved_discr = LiteralNode {
lit,
..LiteralNode::default()
};
}
Some(lit_node) => {
variant.resolved_discr = lit_node.clone();
}
}
last_variant = Some(variant);
}
Ok(())
}

View File

@@ -12,6 +12,7 @@ mod cpp_ffi_types;
mod cpp_names; mod cpp_names;
mod cpp_scaffolding_calls; mod cpp_scaffolding_calls;
mod docs; mod docs;
mod enums;
mod interfaces; mod interfaces;
mod js_docstrings; mod js_docstrings;
mod js_filename; mod js_filename;
@@ -21,7 +22,7 @@ mod modules;
mod types; mod types;
use crate::Config; use crate::Config;
use anyhow::Result; use anyhow::{bail, Result};
pub use nodes::*; pub use nodes::*;
use std::collections::HashMap; use std::collections::HashMap;
use uniffi_bindgen::pipeline::{general, initial}; use uniffi_bindgen::pipeline::{general, initial};
@@ -33,6 +34,7 @@ pub fn gecko_js_pipeline(pipeline_map: HashMap<String, Config>) -> GeckoPipeline
general::pipeline() general::pipeline()
.convert_ir_pass::<Root>() .convert_ir_pass::<Root>()
.pass(modules::pass(pipeline_map)) .pass(modules::pass(pipeline_map))
.pass(enums::pass)
.pass(callables::pass) .pass(callables::pass)
.pass(interfaces::pass) .pass(interfaces::pass)
.pass(callback_interfaces::pass) .pass(callback_interfaces::pass)

View File

@@ -301,6 +301,7 @@ pub struct Enum {
pub remote: bool, pub remote: bool,
pub variants: Vec<Variant>, pub variants: Vec<Variant>,
pub discr_type: Option<TypeNode>, pub discr_type: Option<TypeNode>,
pub resolved_discr_type: TypeNode,
pub non_exhaustive: bool, pub non_exhaustive: bool,
pub js_docstring: String, pub js_docstring: String,
pub docstring: Option<String>, pub docstring: Option<String>,
@@ -312,6 +313,7 @@ pub struct Enum {
pub struct Variant { pub struct Variant {
pub name: String, pub name: String,
pub discr: Option<LiteralNode>, pub discr: Option<LiteralNode>,
pub resolved_discr: LiteralNode,
pub fields: Vec<Field>, pub fields: Vec<Field>,
pub docstring: Option<String>, pub docstring: Option<String>,
pub js_docstring: String, pub js_docstring: String,

View File

@@ -4,7 +4,7 @@
export const {{ enum_.name }} = { export const {{ enum_.name }} = {
{%- for variant in enum_.variants %} {%- for variant in enum_.variants %}
{{ variant.js_docstring|indent(4) }} {{ variant.js_docstring|indent(4) }}
{{ variant.name }}: {{loop.index}}, {{ variant.name }}: {{ variant.resolved_discr.js_lit }},
{%- endfor %} {%- endfor %}
}; };
Object.freeze({{ enum_.name }}); Object.freeze({{ enum_.name }});
@@ -12,6 +12,7 @@ Object.freeze({{ enum_.name }});
// Export the FFIConverter object to make external types work. // Export the FFIConverter object to make external types work.
export class {{ enum_|ffi_converter }} extends FfiConverterArrayBuffer { export class {{ enum_|ffi_converter }} extends FfiConverterArrayBuffer {
static read(dataStream) { static read(dataStream) {
// Use sequential indices (1-based) for the wire format to match the Rust scaffolding
switch (dataStream.readInt32()) { switch (dataStream.readInt32()) {
{%- for variant in enum_.variants %} {%- for variant in enum_.variants %}
case {{ loop.index }}: case {{ loop.index }}:
@@ -23,6 +24,7 @@ export class {{ enum_|ffi_converter }} extends FfiConverterArrayBuffer {
} }
static write(dataStream, value) { static write(dataStream, value) {
// Use sequential indices (1-based) for the wire format to match the Rust scaffolding
{%- for variant in enum_.variants %} {%- for variant in enum_.variants %}
if (value === {{ enum_.name }}.{{ variant.name }}) { if (value === {{ enum_.name }}.{{ variant.name }}) {
dataStream.writeInt32({{ loop.index }}); dataStream.writeInt32({{ loop.index }});
@@ -67,6 +69,7 @@ export class {{ enum_.name }} {}
// Export the FFIConverter object to make external types work. // Export the FFIConverter object to make external types work.
export class {{ enum_|ffi_converter }} extends FfiConverterArrayBuffer { export class {{ enum_|ffi_converter }} extends FfiConverterArrayBuffer {
static read(dataStream) { static read(dataStream) {
// Use sequential indices (1-based) for the wire format to match the Rust scaffolding
switch (dataStream.readInt32()) { switch (dataStream.readInt32()) {
{%- for variant in enum_.variants %} {%- for variant in enum_.variants %}
case {{ loop.index }}: case {{ loop.index }}:
@@ -82,6 +85,7 @@ export class {{ enum_|ffi_converter }} extends FfiConverterArrayBuffer {
} }
static write(dataStream, value) { static write(dataStream, value) {
// Use sequential indices (1-based) for the wire format to match the Rust scaffolding
{%- for variant in enum_.variants %} {%- for variant in enum_.variants %}
if (value instanceof {{ enum_.name }}.{{ variant.name }}) { if (value instanceof {{ enum_.name }}.{{ variant.name }}) {
dataStream.writeInt32({{ loop.index }}); dataStream.writeInt32({{ loop.index }});

View File

@@ -2264,21 +2264,22 @@ export const EnumNoData = {
/** /**
* A * A
*/ */
A: 1, A: 0,
/** /**
* B * B
*/ */
B: 2, B: 1,
/** /**
* C * C
*/ */
C: 3, C: 2,
}; };
Object.freeze(EnumNoData); Object.freeze(EnumNoData);
// Export the FFIConverter object to make external types work. // Export the FFIConverter object to make external types work.
export class FfiConverterTypeEnumNoData extends FfiConverterArrayBuffer { export class FfiConverterTypeEnumNoData extends FfiConverterArrayBuffer {
static read(dataStream) { static read(dataStream) {
// Use sequential indices (1-based) for the wire format to match the Rust scaffolding
switch (dataStream.readInt32()) { switch (dataStream.readInt32()) {
case 1: case 1:
return EnumNoData.A return EnumNoData.A
@@ -2292,6 +2293,7 @@ export class FfiConverterTypeEnumNoData extends FfiConverterArrayBuffer {
} }
static write(dataStream, value) { static write(dataStream, value) {
// Use sequential indices (1-based) for the wire format to match the Rust scaffolding
if (value === EnumNoData.A) { if (value === EnumNoData.A) {
dataStream.writeInt32(1); dataStream.writeInt32(1);
return; return;
@@ -2357,6 +2359,7 @@ EnumWithData.C = class extends EnumWithData{
// Export the FFIConverter object to make external types work. // Export the FFIConverter object to make external types work.
export class FfiConverterTypeEnumWithData extends FfiConverterArrayBuffer { export class FfiConverterTypeEnumWithData extends FfiConverterArrayBuffer {
static read(dataStream) { static read(dataStream) {
// Use sequential indices (1-based) for the wire format to match the Rust scaffolding
switch (dataStream.readInt32()) { switch (dataStream.readInt32()) {
case 1: case 1:
return new EnumWithData.A( return new EnumWithData.A(
@@ -2375,6 +2378,7 @@ export class FfiConverterTypeEnumWithData extends FfiConverterArrayBuffer {
} }
static write(dataStream, value) { static write(dataStream, value) {
// Use sequential indices (1-based) for the wire format to match the Rust scaffolding
if (value instanceof EnumWithData.A) { if (value instanceof EnumWithData.A) {
dataStream.writeInt32(1); dataStream.writeInt32(1);
FfiConverterUInt8.write(dataStream, value.value); FfiConverterUInt8.write(dataStream, value.value);
@@ -2457,6 +2461,7 @@ ComplexEnum.C = class extends ComplexEnum{
// Export the FFIConverter object to make external types work. // Export the FFIConverter object to make external types work.
export class FfiConverterTypeComplexEnum extends FfiConverterArrayBuffer { export class FfiConverterTypeComplexEnum extends FfiConverterArrayBuffer {
static read(dataStream) { static read(dataStream) {
// Use sequential indices (1-based) for the wire format to match the Rust scaffolding
switch (dataStream.readInt32()) { switch (dataStream.readInt32()) {
case 1: case 1:
return new ComplexEnum.A( return new ComplexEnum.A(
@@ -2476,6 +2481,7 @@ export class FfiConverterTypeComplexEnum extends FfiConverterArrayBuffer {
} }
static write(dataStream, value) { static write(dataStream, value) {
// Use sequential indices (1-based) for the wire format to match the Rust scaffolding
if (value instanceof ComplexEnum.A) { if (value instanceof ComplexEnum.A) {
dataStream.writeInt32(1); dataStream.writeInt32(1);
FfiConverterTypeEnumNoData.write(dataStream, value.value); FfiConverterTypeEnumNoData.write(dataStream, value.value);
@@ -2519,6 +2525,162 @@ export class FfiConverterTypeComplexEnum extends FfiConverterArrayBuffer {
} }
} }
/**
* ExplicitValuedEnum
*/
export const ExplicitValuedEnum = {
/**
* FIRST
*/
FIRST: 1,
/**
* SECOND
*/
SECOND: 2,
/**
* FOURTH
*/
FOURTH: 4,
/**
* TENTH
*/
TENTH: 10,
/**
* ELEVENTH
*/
ELEVENTH: 11,
/**
* THIRTEENTH
*/
THIRTEENTH: 13,
};
Object.freeze(ExplicitValuedEnum);
// Export the FFIConverter object to make external types work.
export class FfiConverterTypeExplicitValuedEnum extends FfiConverterArrayBuffer {
static read(dataStream) {
// Use sequential indices (1-based) for the wire format to match the Rust scaffolding
switch (dataStream.readInt32()) {
case 1:
return ExplicitValuedEnum.FIRST
case 2:
return ExplicitValuedEnum.SECOND
case 3:
return ExplicitValuedEnum.FOURTH
case 4:
return ExplicitValuedEnum.TENTH
case 5:
return ExplicitValuedEnum.ELEVENTH
case 6:
return ExplicitValuedEnum.THIRTEENTH
default:
throw new UniFFITypeError("Unknown ExplicitValuedEnum variant");
}
}
static write(dataStream, value) {
// Use sequential indices (1-based) for the wire format to match the Rust scaffolding
if (value === ExplicitValuedEnum.FIRST) {
dataStream.writeInt32(1);
return;
}
if (value === ExplicitValuedEnum.SECOND) {
dataStream.writeInt32(2);
return;
}
if (value === ExplicitValuedEnum.FOURTH) {
dataStream.writeInt32(3);
return;
}
if (value === ExplicitValuedEnum.TENTH) {
dataStream.writeInt32(4);
return;
}
if (value === ExplicitValuedEnum.ELEVENTH) {
dataStream.writeInt32(5);
return;
}
if (value === ExplicitValuedEnum.THIRTEENTH) {
dataStream.writeInt32(6);
return;
}
throw new UniFFITypeError("Unknown ExplicitValuedEnum variant");
}
static computeSize(value) {
return 4;
}
static checkType(value) {
if (!Number.isInteger(value) || value < 1 || value > 6) {
throw new UniFFITypeError(`${value} is not a valid value for ExplicitValuedEnum`);
}
}
}
/**
* GappedEnum
*/
export const GappedEnum = {
/**
* ONE
*/
ONE: 10,
/**
* TWO
*/
TWO: 11,
/**
* THREE
*/
THREE: 14,
};
Object.freeze(GappedEnum);
// Export the FFIConverter object to make external types work.
export class FfiConverterTypeGappedEnum extends FfiConverterArrayBuffer {
static read(dataStream) {
// Use sequential indices (1-based) for the wire format to match the Rust scaffolding
switch (dataStream.readInt32()) {
case 1:
return GappedEnum.ONE
case 2:
return GappedEnum.TWO
case 3:
return GappedEnum.THREE
default:
throw new UniFFITypeError("Unknown GappedEnum variant");
}
}
static write(dataStream, value) {
// Use sequential indices (1-based) for the wire format to match the Rust scaffolding
if (value === GappedEnum.ONE) {
dataStream.writeInt32(1);
return;
}
if (value === GappedEnum.TWO) {
dataStream.writeInt32(2);
return;
}
if (value === GappedEnum.THREE) {
dataStream.writeInt32(3);
return;
}
throw new UniFFITypeError("Unknown GappedEnum variant");
}
static computeSize(value) {
return 4;
}
static checkType(value) {
if (!Number.isInteger(value) || value < 1 || value > 3) {
throw new UniFFITypeError(`${value} is not a valid value for GappedEnum`);
}
}
}
/** /**
* Error enum * Error enum
*/ */

View File

@@ -5,9 +5,11 @@ const {
roundtripEnumNoData, roundtripEnumNoData,
roundtripEnumWithData, roundtripEnumWithData,
roundtripComplexEnum, roundtripComplexEnum,
ComplexEnum,
EnumNoData, EnumNoData,
EnumWithData, EnumWithData,
ComplexEnum, ExplicitValuedEnum,
GappedEnum,
SimpleRec, SimpleRec,
} = ChromeUtils.importESModule( } = ChromeUtils.importESModule(
"resource://gre/modules/RustUniffiBindingsTests.sys.mjs" "resource://gre/modules/RustUniffiBindingsTests.sys.mjs"
@@ -40,3 +42,23 @@ Assert.deepEqual(
roundtripComplexEnum(new ComplexEnum.C(new SimpleRec({ a: 30 }))), roundtripComplexEnum(new ComplexEnum.C(new SimpleRec({ a: 30 }))),
new ComplexEnum.C(new SimpleRec({ a: 30 })) new ComplexEnum.C(new SimpleRec({ a: 30 }))
); );
// Test that the enum discriminant values
// No discriminant specified, start at 0 then increment by 1
Assert.equal(EnumNoData.A, 0);
Assert.equal(EnumNoData.B, 1);
Assert.equal(EnumNoData.C, 2);
// All discriminants specified, use the specified values
Assert.equal(ExplicitValuedEnum.FIRST, 1);
Assert.equal(ExplicitValuedEnum.SECOND, 2);
Assert.equal(ExplicitValuedEnum.FOURTH, 4);
Assert.equal(ExplicitValuedEnum.TENTH, 10);
Assert.equal(ExplicitValuedEnum.ELEVENTH, 11);
Assert.equal(ExplicitValuedEnum.THIRTEENTH, 13);
// Some discriminants specified, increment by one for any unspecified variants
Assert.equal(GappedEnum.ONE, 10);
Assert.equal(GappedEnum.TWO, 11); // Sequential value after ONE (10+1)
Assert.equal(GappedEnum.THREE, 14); // Explicit value again

View File

@@ -25,6 +25,27 @@ pub enum ComplexEnum {
C { value: SimpleRec }, C { value: SimpleRec },
} }
// Test enum with explicit discriminant values and gaps
#[repr(u8)]
#[derive(Debug, Clone, Copy, uniffi::Enum)]
pub enum ExplicitValuedEnum {
First = 1,
Second = 2,
Fourth = 4,
Tenth = 10,
Eleventh = 11,
Thirteenth = 13,
}
// Example with sequential and explicit values mixed
#[repr(u8)]
#[derive(Debug, Clone, Copy, uniffi::Enum)]
pub enum GappedEnum {
One = 10,
Two, // should be 11
Three = 14,
}
#[uniffi::export] #[uniffi::export]
pub fn roundtrip_enum_no_data(en: EnumNoData) -> EnumNoData { pub fn roundtrip_enum_no_data(en: EnumNoData) -> EnumNoData {
en en