Просмотр исходного кода

[ObjC] Add ability to introspect list of enum values (#4678)

Added new API to GPBEnumDescriptor to enable introspection of enum values.

Refactored implementation so that this contains a minimum of added code.

Clarified comments regarding behavior in the presence of the alias_allowed option.

Added unit tests for new functionality and for the alias case.
leovitch 7 лет назад
Родитель
Сommit
2804902446
4 измененных файлов с 119 добавлено и 14 удалено
  1. 32 2
      objectivec/GPBDescriptor.h
  2. 26 9
      objectivec/GPBDescriptor.m
  3. 4 3
      objectivec/README.md
  4. 57 0
      objectivec/Tests/GPBDescriptorTests.m

+ 32 - 2
objectivec/GPBDescriptor.h

@@ -223,9 +223,12 @@ typedef NS_ENUM(uint8_t, GPBFieldType) {
 /**
 /**
  * Returns the enum value name for the given raw enum.
  * Returns the enum value name for the given raw enum.
  *
  *
+ * Note that there can be more than one name corresponding to a given value
+ * if the allow_alias option is used.
+ *
  * @param number The raw enum value.
  * @param number The raw enum value.
  *
  *
- * @return The name of the enum value passed, or nil if not valid.
+ * @return The first name that matches the enum value passed, or nil if not valid.
  **/
  **/
 - (nullable NSString *)enumNameForValue:(int32_t)number;
 - (nullable NSString *)enumNameForValue:(int32_t)number;
 
 
@@ -244,7 +247,7 @@ typedef NS_ENUM(uint8_t, GPBFieldType) {
  *
  *
  * @param number The raw enum value.
  * @param number The raw enum value.
  *
  *
- * @return The text format name for the raw enum value, or nil if not valid.
+ * @return The first text format name which matches the enum value, or nil if not valid.
  **/
  **/
 - (nullable NSString *)textFormatNameForValue:(int32_t)number;
 - (nullable NSString *)textFormatNameForValue:(int32_t)number;
 
 
@@ -258,6 +261,33 @@ typedef NS_ENUM(uint8_t, GPBFieldType) {
  **/
  **/
 - (BOOL)getValue:(nullable int32_t *)outValue forEnumTextFormatName:(NSString *)textFormatName;
 - (BOOL)getValue:(nullable int32_t *)outValue forEnumTextFormatName:(NSString *)textFormatName;
 
 
+/**
+ * Gets the number of defined enum names.
+ *
+ * @return Count of the number of enum names, including any aliases.
+ */
+@property(nonatomic, readonly) uint32_t enumNameCount;
+
+/**
+ * Gets the enum name corresponding to the given index.
+ *
+ * @param index Index into the available names.  The defined range is from 0
+ *              to self.enumNameCount - 1.
+ *
+ * @returns The enum name at the given index, or nil if the index is out of range.
+ */
+- (nullable NSString *)getEnumNameForIndex:(uint32_t)index;
+
+/**
+ * Gets the enum text format name corresponding to the given index.
+ *
+ * @param index Index into the available names.  The defined range is from 0
+ *              to self.enumNameCount - 1.
+ *
+ * @returns The text format name at the given index, or nil if the index is out of range.
+ */
+- (nullable NSString *)getEnumTextFormatNameForIndex:(uint32_t)index;
+
 @end
 @end
 
 
 /**
 /**

+ 26 - 9
objectivec/GPBDescriptor.m

@@ -830,13 +830,9 @@ uint32_t GPBFieldAlternateTag(GPBFieldDescriptor *self) {
 }
 }
 
 
 - (NSString *)enumNameForValue:(int32_t)number {
 - (NSString *)enumNameForValue:(int32_t)number {
-  if (nameOffsets_ == NULL) [self calcValueNameOffsets];
-
   for (uint32_t i = 0; i < valueCount_; ++i) {
   for (uint32_t i = 0; i < valueCount_; ++i) {
     if (values_[i] == number) {
     if (values_[i] == number) {
-      const char *valueName = valueNames_ + nameOffsets_[i];
-      NSString *fullName = [NSString stringWithFormat:@"%@_%s", name_, valueName];
-      return fullName;
+      return [self getEnumNameForIndex:i];
     }
     }
   }
   }
   return nil;
   return nil;
@@ -886,8 +882,6 @@ uint32_t GPBFieldAlternateTag(GPBFieldDescriptor *self) {
 }
 }
 
 
 - (NSString *)textFormatNameForValue:(int32_t)number {
 - (NSString *)textFormatNameForValue:(int32_t)number {
-  if (nameOffsets_ == NULL) [self calcValueNameOffsets];
-
   // Find the EnumValue descriptor and its index.
   // Find the EnumValue descriptor and its index.
   BOOL foundIt = NO;
   BOOL foundIt = NO;
   uint32_t valueDescriptorIndex;
   uint32_t valueDescriptorIndex;
@@ -902,16 +896,39 @@ uint32_t GPBFieldAlternateTag(GPBFieldDescriptor *self) {
   if (!foundIt) {
   if (!foundIt) {
     return nil;
     return nil;
   }
   }
+  return [self getEnumTextFormatNameForIndex:valueDescriptorIndex];
+}
+
+- (uint32_t)enumNameCount {
+  return valueCount_;
+}
+
+- (NSString *)getEnumNameForIndex:(uint32_t)index {
+  if (nameOffsets_ == NULL) [self calcValueNameOffsets];
 
 
+  if (index >= valueCount_) {
+    return nil;
+  }
+  const char *valueName = valueNames_ + nameOffsets_[index];
+  NSString *fullName = [NSString stringWithFormat:@"%@_%s", name_, valueName];
+  return fullName;
+}
+
+- (NSString *)getEnumTextFormatNameForIndex:(uint32_t)index {
+  if (nameOffsets_ == NULL) [self calcValueNameOffsets];
+
+  if (index >= valueCount_) {
+    return nil;
+  }
   NSString *result = nil;
   NSString *result = nil;
   // Naming adds an underscore between enum name and value name, skip that also.
   // Naming adds an underscore between enum name and value name, skip that also.
-  const char *valueName = valueNames_ + nameOffsets_[valueDescriptorIndex];
+  const char *valueName = valueNames_ + nameOffsets_[index];
   NSString *shortName = @(valueName);
   NSString *shortName = @(valueName);
 
 
   // See if it is in the map of special format handling.
   // See if it is in the map of special format handling.
   if (extraTextFormatInfo_) {
   if (extraTextFormatInfo_) {
     result = GPBDecodeTextFormatName(extraTextFormatInfo_,
     result = GPBDecodeTextFormatName(extraTextFormatInfo_,
-                                     (int32_t)valueDescriptorIndex, shortName);
+                                     (int32_t)index, shortName);
   }
   }
   // Logic here needs to match what objectivec_enum.cc does in the proto
   // Logic here needs to match what objectivec_enum.cc does in the proto
   // compiler.
   // compiler.

+ 4 - 3
objectivec/README.md

@@ -20,9 +20,10 @@ The Objective C implementation requires:
 Installation
 Installation
 ------------
 ------------
 
 
-The full distribution pulled from github includes the sources for both the
-compiler (protoc) and the runtime (this directory). To build the compiler
-and run the runtime tests, you can use:
+The distribution pulled from github includes the sources for both the
+compiler (protoc) and the runtime (this directory). After cloning the distribution
+and needed submodules ([see the src directory's README](../src/README.md)),
+to build the compiler and run the runtime tests, you can use:
 
 
      $ objectivec/DevTools/full_mac_build.sh
      $ objectivec/DevTools/full_mac_build.sh
 
 

+ 57 - 0
objectivec/Tests/GPBDescriptorTests.m

@@ -190,6 +190,63 @@
   XCTAssertFalse([descriptor getValue:&value forEnumTextFormatName:@"Unknown"]);
   XCTAssertFalse([descriptor getValue:&value forEnumTextFormatName:@"Unknown"]);
 }
 }
 
 
+- (void)testEnumDescriptorIntrospection {
+  GPBEnumDescriptor *descriptor = TestAllTypes_NestedEnum_EnumDescriptor();
+
+  XCTAssertEqual(descriptor.enumNameCount, 4U);
+  XCTAssertEqualObjects([descriptor getEnumNameForIndex:0],
+                        @"TestAllTypes_NestedEnum_Foo");
+  XCTAssertEqualObjects([descriptor getEnumTextFormatNameForIndex:0], @"FOO");
+  XCTAssertEqualObjects([descriptor getEnumNameForIndex:1],
+                 @"TestAllTypes_NestedEnum_Bar");
+  XCTAssertEqualObjects([descriptor getEnumTextFormatNameForIndex:1], @"BAR");
+  XCTAssertEqualObjects([descriptor getEnumNameForIndex:2],
+                 @"TestAllTypes_NestedEnum_Baz");
+  XCTAssertEqualObjects([descriptor getEnumTextFormatNameForIndex:2], @"BAZ");
+  XCTAssertEqualObjects([descriptor getEnumNameForIndex:3],
+                 @"TestAllTypes_NestedEnum_Neg");
+  XCTAssertEqualObjects([descriptor getEnumTextFormatNameForIndex:3], @"NEG");
+}
+
+- (void)testEnumDescriptorIntrospectionWithAlias {
+  GPBEnumDescriptor *descriptor = TestEnumWithDupValue_EnumDescriptor();
+  NSString *enumName;
+  int32_t value;
+
+  XCTAssertEqual(descriptor.enumNameCount, 5U);
+
+  enumName = [descriptor getEnumNameForIndex:0];
+  XCTAssertEqualObjects(enumName, @"TestEnumWithDupValue_Foo1");
+  XCTAssertTrue([descriptor getValue:&value forEnumName:enumName]);
+  XCTAssertEqual(value, 1);
+  XCTAssertEqualObjects([descriptor getEnumTextFormatNameForIndex:0], @"FOO1");
+
+  enumName = [descriptor getEnumNameForIndex:1];
+  XCTAssertEqualObjects(enumName, @"TestEnumWithDupValue_Bar1");
+  XCTAssertTrue([descriptor getValue:&value forEnumName:enumName]);
+  XCTAssertEqual(value, 2);
+  XCTAssertEqualObjects([descriptor getEnumTextFormatNameForIndex:1], @"BAR1");
+
+  enumName = [descriptor getEnumNameForIndex:2];
+  XCTAssertEqualObjects(enumName, @"TestEnumWithDupValue_Baz");
+  XCTAssertTrue([descriptor getValue:&value forEnumName:enumName]);
+  XCTAssertEqual(value, 3);
+  XCTAssertEqualObjects([descriptor getEnumTextFormatNameForIndex:2], @"BAZ");
+
+  enumName = [descriptor getEnumNameForIndex:3];
+  XCTAssertEqualObjects(enumName, @"TestEnumWithDupValue_Foo2");
+  XCTAssertTrue([descriptor getValue:&value forEnumName:enumName]);
+  XCTAssertEqual(value, 1);
+  XCTAssertEqualObjects([descriptor getEnumTextFormatNameForIndex:3], @"FOO2");
+
+  enumName = [descriptor getEnumNameForIndex:4];
+  XCTAssertEqualObjects(enumName, @"TestEnumWithDupValue_Bar2");
+  XCTAssertTrue([descriptor getValue:&value forEnumName:enumName]);
+  XCTAssertEqual(value, 2);
+  XCTAssertEqualObjects([descriptor getEnumTextFormatNameForIndex:4], @"BAR2");
+
+}
+
 - (void)testEnumValueValidator {
 - (void)testEnumValueValidator {
   GPBDescriptor *descriptor = [TestAllTypes descriptor];
   GPBDescriptor *descriptor = [TestAllTypes descriptor];
   GPBFieldDescriptor *fieldDescriptor =
   GPBFieldDescriptor *fieldDescriptor =