Note: This document covers API impact only. For more details, see the ABI compatibility page

Change a union from flexible to strict

Overview

- init step 1 step 2 step 3
fidl link link
dart link link link
go link link
hlcpp link link link
llcpp link link link
rust link link link

Initial State {#init}

FIDL {#fidl-init}

  1. flexible union JsonValue {
  2. 1: int32 int_value;
  3. 2: string:MAX string_value;
  4. };

Dart {#dart-init}

  1. void useUnion(fidllib.JsonValue value) {
  2. switch (value.$tag) {
  3. case fidllib.JsonValueTag.intValue:
  4. print('int value: ${value.intValue}');
  5. break;
  6. case fidllib.JsonValueTag.stringValue:
  7. print('string value: ${value.stringValue}');
  8. break;
  9. case fidllib.JsonValueTag.$unknown:
  10. print('unknown variant: ${value.$unknownData}');
  11. break;
  12. }
  13. }

Go {#go-init}

  1. func useUnion(value lib.JsonValue) {
  2. switch value.Which() {
  3. case lib.JsonValueIntValue:
  4. fmt.Printf("int value: %d\n", value.IntValue)
  5. case lib.JsonValueStringValue:
  6. fmt.Printf("string value: %s\n", value.StringValue)
  7. case lib.JsonValue_unknownData:
  8. fmt.Printf("unknown data: %+v\n", value.GetUnknownData())
  9. default:
  10. fmt.Println("<unknown tag>")
  11. }
  12. }

HLCPP {#hlcpp-init}

  1. void use_union(fidl_test::JsonValue value) {
  2. switch (value.Which()) {
  3. case fidl_test::JsonValue::Tag::kIntValue:
  4. printf("int value: %d\n", value.int_value());
  5. break;
  6. case fidl_test::JsonValue::Tag::kStringValue:
  7. printf("string value: %s\n", value.string_value().c_str());
  8. break;
  9. case fidl_test::JsonValue::Tag::Invalid:
  10. printf("<uninitialized union>\n");
  11. break;
  12. case fidl_test::JsonValue::Tag::kUnknown:
  13. printf("<%lu unknown bytes>\n", value.UnknownBytes()->size());
  14. break;
  15. }
  16. }

LLCPP {#llcpp-init}

  1. void use_union(fidl_test::JsonValue* value) {
  2. switch (value->which()) {
  3. case fidl_test::JsonValue::Tag::kIntValue:
  4. printf("int value: %d\n", value->int_value());
  5. break;
  6. case fidl_test::JsonValue::Tag::kStringValue:
  7. printf("string value: %s\n", value->string_value().data());
  8. break;
  9. case fidl_test::JsonValue::Tag::kUnknown:
  10. printf("<unknown data>\n");
  11. break;
  12. }
  13. }

Rust {#rust-init}

  1. fn use_union(value: &fidl_lib::JsonValue) {
  2. match value {
  3. fidl_lib::JsonValue::IntValue(n) => println!("int value: {}", n),
  4. fidl_lib::JsonValue::StringValue(s) => println!("string: {}", s),
  5. fidl_lib::JsonValueUnknown!() => println!("<unknown union>"),
  6. };
  7. }

Update Source Code {#step-1}

Dart {#dart-1}

  • Replace the unknown tag with a default case in any switch statements
  1. void useUnion(fidllib.JsonValue value) {
  2. switch (value.$tag) {
  3. case fidllib.JsonValueTag.intValue:
  4. print('int value: ${value.intValue}');
  5. break;
  6. case fidllib.JsonValueTag.stringValue:
  7. print('string value: ${value.stringValue}');
  8. break;
  9. - case fidllib.JsonValueTag.$unknown:
  10. + default:
  11. + // Note: unknown variants will fail to decode until the union is marked flexible
  12. print('unknown variant: ${value.$unknownData}');
  13. break;
  14. }
  15. }

Go {#go-1}

  • Remove usages of any flexible union specific APIs
  1. func useUnion(value lib.JsonValue) {
  2. switch value.Which() {
  3. case lib.JsonValueIntValue:
  4. fmt.Printf("int value: %d\n", value.IntValue)
  5. case lib.JsonValueStringValue:
  6. fmt.Printf("string value: %s\n", value.StringValue)
  7. - case lib.JsonValue_unknownData:
  8. - fmt.Printf("unknown data: %+v\n", value.GetUnknownData())
  9. default:
  10. fmt.Println("<unknown tag>")
  11. }
  12. }

HLCPP {#hlcpp-1}

  • Replace the kUnknown tag with a default case in any switch statements
  • Remove usages of any flexible union specific APIs
  1. void use_union(fidl_test::JsonValue value) {
  2. switch (value.Which()) {
  3. case fidl_test::JsonValue::Tag::kIntValue:
  4. printf("int value: %d\n", value.int_value());
  5. break;
  6. case fidl_test::JsonValue::Tag::kStringValue:
  7. printf("string value: %s\n", value.string_value().c_str());
  8. break;
  9. case fidl_test::JsonValue::Tag::Invalid:
  10. printf("<uninitialized union>\n");
  11. break;
  12. - case fidl_test::JsonValue::Tag::kUnknown:
  13. - printf("<%lu unknown bytes>\n", value.UnknownBytes()->size());
  14. - break;
  15. + default:
  16. + printf("<unknown variant>\n");
  17. }
  18. }

LLCPP {#llcpp-1}

  • Replace the kUnknown tag with a default case in any switch statements
  • Remove usages of any flexible union specific APIs
  1. void use_union(fidl_test::JsonValue* value) {
  2. switch (value->which()) {
  3. case fidl_test::JsonValue::Tag::kIntValue:
  4. printf("int value: %d\n", value->int_value());
  5. break;
  6. case fidl_test::JsonValue::Tag::kStringValue:
  7. printf("string value: %s\n", value->string_value().data());
  8. break;
  9. - case fidl_test::JsonValue::Tag::kUnknown:
  10. - printf("<unknown data>\n");
  11. - break;
  12. + default:
  13. + printf("<unknown variant>\n");
  14. }
  15. }

Rust {#rust-1}

  • Add [allow(unreachable_patterns)] and an underscore arm to match statements on the union
  1. fn use_union(value: &fidl_lib::JsonValue) {
  2. + #[allow(unreachable_patterns)]
  3. match value {
  4. fidl_lib::JsonValue::IntValue(n) => println!("int value: {}", n),
  5. fidl_lib::JsonValue::StringValue(s) => println!("string: {}", s),
  6. - fidl_lib::JsonValueUnknown!() => println!("<unknown union>"),
  7. + _ => {}
  8. };
  9. }

Update FIDL Library {#step-2}

  • Change the union from flexible to strict
  1. - flexible union JsonValue {
  2. + strict union JsonValue {
  3. 1: int32 int_value;
  4. 2: string:MAX string_value;
  5. };

Update Source Code {#step-3}

Dart {#dart-3}

  • You can now remove the default case in any switch statements
  1. void useUnion(fidllib.JsonValue value) {
  2. + assert(value.$unknownData == null);
  3. switch (value.$tag) {
  4. case fidllib.JsonValueTag.intValue:
  5. print('int value: ${value.intValue}');
  6. break;
  7. case fidllib.JsonValueTag.stringValue:
  8. print('string value: ${value.stringValue}');
  9. break;
  10. - default:
  11. - // Note: unknown variants will fail to decode until the union is marked flexible
  12. - print('unknown variant: ${value.$unknownData}');
  13. - break;
  14. }
  15. }

HLCPP {#hlcpp-3}

  • You can now remove the default case
  1. void use_union(fidl_test::JsonValue value) {
  2. switch (value.Which()) {
  3. case fidl_test::JsonValue::Tag::kIntValue:
  4. printf("int value: %d\n", value.int_value());
  5. break;
  6. case fidl_test::JsonValue::Tag::kStringValue:
  7. printf("string value: %s\n", value.string_value().c_str());
  8. break;
  9. case fidl_test::JsonValue::Tag::Invalid:
  10. printf("<uninitialized union>\n");
  11. break;
  12. - default:
  13. - printf("<unknown variant>\n");
  14. }
  15. }

LLCPP {#llcpp-3}

  • You can now remove the default case
  1. void use_union(fidl_test::JsonValue* value) {
  2. switch (value->which()) {
  3. case fidl_test::JsonValue::Tag::kIntValue:
  4. printf("int value: %d\n", value->int_value());
  5. break;
  6. case fidl_test::JsonValue::Tag::kStringValue:
  7. printf("string value: %s\n", value->string_value().data());
  8. break;
  9. - default:
  10. - printf("<unknown variant>\n");
  11. }
  12. }

Rust {#rust-3}

  • Remove the attribute and underscore arm
  1. fn use_union(value: &fidl_lib::JsonValue) {
  2. - #[allow(unreachable_patterns)]
  3. match value {
  4. fidl_lib::JsonValue::IntValue(n) => println!("int value: {}", n),
  5. fidl_lib::JsonValue::StringValue(s) => println!("string: {}", s),
  6. - _ => {}
  7. };
  8. }