create _upb_EnumDef_MiniDescriptor()
delete upb_EnumDef_IsSorted()

We now have a simple internal function for returning a mini descriptor directly from an enum def.

PiperOrigin-RevId: 461208352
diff --git a/upb/def.c b/upb/def.c
index c1a9d21..4a1254d 100644
--- a/upb/def.c
+++ b/upb/def.c
@@ -322,10 +322,12 @@
   return ret;
 }
 
-int cmp_fields(const void* p1, const void* p2) {
-  const upb_FieldDef* f1 = *(upb_FieldDef* const*)p1;
-  const upb_FieldDef* f2 = *(upb_FieldDef* const*)p2;
-  return field_rank(f1) - field_rank(f2);
+static int cmp_values(const void* a, const void* b) {
+  const upb_EnumValueDef* A = *(const upb_EnumValueDef**)a;
+  const upb_EnumValueDef* B = *(const upb_EnumValueDef**)b;
+  if ((uint32_t)A->number < (uint32_t)B->number) return -1;
+  if ((uint32_t)A->number > (uint32_t)B->number) return 1;
+  return 0;
 }
 
 static void upb_Status_setoom(upb_Status* status) {
@@ -404,8 +406,6 @@
 
 int upb_EnumDef_ValueCount(const upb_EnumDef* e) { return e->value_count; }
 
-bool upb_EnumDef_IsSorted(const upb_EnumDef* e) { return e->is_sorted; }
-
 const upb_EnumValueDef* upb_EnumDef_FindValueByNameWithSize(
     const upb_EnumDef* def, const char* name, size_t len) {
   upb_value v;
@@ -432,6 +432,21 @@
   return &e->values[i];
 }
 
+const char* _upb_EnumDef_MiniDescriptor(const upb_EnumDef* e, upb_Arena* a) {
+  if (e->is_sorted) return upb_MiniDescriptor_EncodeEnum(e, NULL, a);
+
+  const upb_EnumValueDef** sorted = (const upb_EnumValueDef**)upb_Arena_Malloc(
+      a, e->value_count * sizeof(void*));
+  if (!sorted) return NULL;
+
+  for (size_t i = 0; i < e->value_count; i++) {
+    sorted[i] = upb_EnumDef_Value(e, i);
+  }
+  qsort(sorted, e->value_count, sizeof(void*), cmp_values);
+
+  return upb_MiniDescriptor_EncodeEnum(e, sorted, a);
+}
+
 /* upb_EnumValueDef ***********************************************************/
 
 const google_protobuf_EnumValueOptions* upb_EnumValueDef_Options(
@@ -2459,26 +2474,22 @@
 
 static upb_MiniTable_Enum* create_enumlayout(symtab_addctx* ctx,
                                              const upb_EnumDef* e) {
-  char* data;
-  size_t size;
-  bool ok = upb_MiniDescriptor_EncodeEnum(e, &data, &size, ctx->tmp_arena);
-  CHK_OOM(ok);
+  const char* desc = _upb_EnumDef_MiniDescriptor(e, ctx->tmp_arena);
+  if (!desc) symtab_errf(ctx, "OOM while building enum MiniDescriptor");
 
   upb_Status status;
   upb_MiniTable_Enum* layout =
-      upb_MiniTable_BuildEnum(data, size, ctx->arena, &status);
+      upb_MiniTable_BuildEnum(desc, strlen(desc), ctx->arena, &status);
   if (!layout)
     symtab_errf(ctx, "Error building enum MiniTable: %s", status.msg);
   return layout;
 }
 
-static void create_enumvaldef(
-    symtab_addctx* ctx, const char* prefix,
-    const google_protobuf_EnumValueDescriptorProto* val_proto, upb_EnumDef* e,
-    int i) {
+static void create_enumvaldef(symtab_addctx* ctx, const char* prefix,
+                              const google_protobuf_EnumValueDescriptorProto* val_proto,
+                              upb_EnumDef* e, int i) {
   upb_EnumValueDef* val = (upb_EnumValueDef*)&e->values[i];
-  upb_StringView name =
-      google_protobuf_EnumValueDescriptorProto_name(val_proto);
+  upb_StringView name = google_protobuf_EnumValueDescriptorProto_name(val_proto);
   upb_value v = upb_value_constptr(val);
 
   val->parent = e; /* Must happen prior to symtab_add(). */
diff --git a/upb/def.h b/upb/def.h
index 8dd696d..5fd5fb7 100644
--- a/upb/def.h
+++ b/upb/def.h
@@ -268,7 +268,6 @@
 const upb_MessageDef* upb_EnumDef_ContainingType(const upb_EnumDef* e);
 int32_t upb_EnumDef_Default(const upb_EnumDef* e);
 int upb_EnumDef_ValueCount(const upb_EnumDef* e);
-bool upb_EnumDef_IsSorted(const upb_EnumDef* e);
 const upb_EnumValueDef* upb_EnumDef_Value(const upb_EnumDef* e, int i);
 
 const upb_EnumValueDef* upb_EnumDef_FindValueByNameWithSize(
@@ -283,6 +282,9 @@
   return upb_EnumDef_FindValueByNameWithSize(e, name, strlen(name));
 }
 
+// Builds and returns a mini descriptor, or NULL if OOM.
+const char* _upb_EnumDef_MiniDescriptor(const upb_EnumDef* e, upb_Arena* a);
+
 /* upb_EnumValueDef ***********************************************************/
 
 const google_protobuf_EnumValueOptions* upb_EnumValueDef_Options(
diff --git a/upb/mini_descriptor.c b/upb/mini_descriptor.c
index ba2f022..9be560a 100644
--- a/upb/mini_descriptor.c
+++ b/upb/mini_descriptor.c
@@ -113,19 +113,6 @@
 
 /******************************************************************************/
 
-// Sort by enum value.
-static int upb_MiniDescriptor_CompareEnums(const void* a, const void* b) {
-  const upb_EnumValueDef* A = *(void**)a;
-  const upb_EnumValueDef* B = *(void**)b;
-  if ((uint32_t)upb_EnumValueDef_Number(A) <
-      (uint32_t)upb_EnumValueDef_Number(B))
-    return -1;
-  if ((uint32_t)upb_EnumValueDef_Number(A) >
-      (uint32_t)upb_EnumValueDef_Number(B))
-    return 1;
-  return 0;
-}
-
 // Sort by field number.
 static int upb_MiniDescriptor_CompareFields(const void* a, const void* b) {
   const upb_FieldDef* A = *(void**)a;
@@ -135,55 +122,39 @@
   return 0;
 }
 
-bool upb_MiniDescriptor_EncodeEnum(const upb_EnumDef* e, char** data,
-                                   size_t* size, upb_Arena* a) {
-  const size_t len = upb_EnumDef_ValueCount(e);
-
+const char* upb_MiniDescriptor_EncodeEnum(const upb_EnumDef* e,
+                                          const upb_EnumValueDef** sorted,
+                                          upb_Arena* a) {
   DescState s;
   upb_DescState_Init(&s);
 
+  upb_MtDataEncoder_StartEnum(&s.e);
+
+  const size_t value_count = upb_EnumDef_ValueCount(e);
+
   // Duplicate values are allowed but we only encode each value once.
   uint32_t previous = 0;
 
-  upb_MtDataEncoder_StartEnum(&s.e);
+  for (size_t i = 0; i < value_count; i++) {
+    const uint32_t current =
+        upb_EnumValueDef_Number(sorted ? sorted[i] : upb_EnumDef_Value(e, i));
+    if (i != 0 && previous == current) continue;
 
-  if (upb_EnumDef_IsSorted(e)) {
-    // The enum is well behaved so no need to copy/sort the pointers here.
-    for (size_t i = 0; i < len; i++) {
-      const uint32_t current = upb_EnumValueDef_Number(upb_EnumDef_Value(e, i));
-      if (i != 0 && previous == current) continue;
-
-      if (!upb_DescState_Grow(&s, a)) return false;
-      s.ptr = upb_MtDataEncoder_PutEnumValue(&s.e, s.ptr, current);
-      previous = current;
-    }
-  } else {
-    // The enum fields are unsorted.
-    const upb_EnumValueDef** sorted =
-        (const upb_EnumValueDef**)upb_Arena_Malloc(a, len * sizeof(void*));
-    if (!sorted) return false;
-
-    for (size_t i = 0; i < len; i++) {
-      sorted[i] = upb_EnumDef_Value(e, i);
-    }
-    qsort(sorted, len, sizeof(void*), upb_MiniDescriptor_CompareEnums);
-
-    for (size_t i = 0; i < len; i++) {
-      const uint32_t current = upb_EnumValueDef_Number(sorted[i]);
-      if (i != 0 && previous == current) continue;
-
-      if (!upb_DescState_Grow(&s, a)) return false;
-      s.ptr = upb_MtDataEncoder_PutEnumValue(&s.e, s.ptr, current);
-      previous = current;
-    }
+    if (!upb_DescState_Grow(&s, a)) return false;
+    s.ptr = upb_MtDataEncoder_PutEnumValue(&s.e, s.ptr, current);
+    previous = current;
   }
 
   if (!upb_DescState_Grow(&s, a)) return false;
   s.ptr = upb_MtDataEncoder_EndEnum(&s.e, s.ptr);
 
-  *data = s.buf;
-  *size = s.ptr - s.buf;
-  return true;
+  // NULL-terminate the mini descriptor so we can return it as a C string.
+  // There will always be room for this in the encoder buffer because
+  // kUpb_MtDataEncoder_MinSize is overkill for upb_MtDataEncoder_EndEnum().
+  UPB_ASSERT(s.ptr < s.buf + s.bufsize);
+  *s.ptr++ = '\0';
+
+  return s.buf;
 }
 
 bool upb_MiniDescriptor_EncodeField(const upb_FieldDef* f, char** data,
@@ -213,23 +184,23 @@
   upb_DescState_Init(&s);
 
   // Make a copy.
-  const size_t len = upb_MessageDef_FieldCount(m);
+  const size_t field_count = upb_MessageDef_FieldCount(m);
   const upb_FieldDef** sorted =
-      (const upb_FieldDef**)upb_Arena_Malloc(a, len * sizeof(void*));
+      (const upb_FieldDef**)upb_Arena_Malloc(a, field_count * sizeof(void*));
   if (!sorted) return false;
 
   // Sort the copy.
-  for (size_t i = 0; i < len; i++) {
+  for (size_t i = 0; i < field_count; i++) {
     sorted[i] = upb_MessageDef_Field(m, i);
   }
-  qsort(sorted, len, sizeof(void*), upb_MiniDescriptor_CompareFields);
+  qsort(sorted, field_count, sizeof(void*), upb_MiniDescriptor_CompareFields);
 
   // Start encoding.
   if (!upb_DescState_Grow(&s, a)) return false;
   upb_MtDataEncoder_StartMessage(&s.e, s.ptr, upb_Message_Modifiers(m));
 
   // Encode the fields.
-  for (size_t i = 0; i < len; i++) {
+  for (size_t i = 0; i < field_count; i++) {
     const upb_FieldDef* field_def = sorted[i];
     const upb_FieldType type = upb_FieldDef_Type(field_def);
     const int number = upb_FieldDef_Number(field_def);
diff --git a/upb/mini_descriptor.h b/upb/mini_descriptor.h
index 73fbae3..50f55f3 100644
--- a/upb/mini_descriptor.h
+++ b/upb/mini_descriptor.h
@@ -40,15 +40,21 @@
 
 /** upb_MiniDescriptor ********************************************************/
 
-// All of these functions return true on success, false on failure.
-// Failure always means an OOM error.
+// Creates and returns a mini descriptor string for an enum, or NULL on error.
+// If the values in the enum happen to be defined in ascending order (when cast
+// to uint32_t) then |sorted| should be NULL. Otherwise it must point to an
+// array containing pointers to the enum values in sorted order.
+const char* upb_MiniDescriptor_EncodeEnum(const upb_EnumDef* e,
+                                          const upb_EnumValueDef** sorted,
+                                          upb_Arena* a);
 
-bool upb_MiniDescriptor_EncodeEnum(const upb_EnumDef* e, char** data,
-                                   size_t* size, upb_Arena* a);
+// TODO(salo): Change the following two functions to match the above function.
 
+// Returns true on success, false on error (OOM).
 bool upb_MiniDescriptor_EncodeField(const upb_FieldDef* f, char** data,
                                     size_t* size, upb_Arena* a);
 
+// Returns true on success, false on error (OOM).
 bool upb_MiniDescriptor_EncodeMessage(const upb_MessageDef* m, char** data,
                                       size_t* size, upb_Arena* a);
 
diff --git a/upbc/code_generator_request.c b/upbc/code_generator_request.c
index 1ac0c4e..54f05d0 100644
--- a/upbc/code_generator_request.c
+++ b/upbc/code_generator_request.c
@@ -85,12 +85,10 @@
 static void upbc_Scrape_Message(upbc_State*, const upb_MessageDef*);
 
 static void upbc_Scrape_Enum(upbc_State* s, const upb_EnumDef* e) {
-  char* data;
-  size_t size;
-  bool ok = upb_MiniDescriptor_EncodeEnum(e, &data, &size, s->arena);
-  if (!ok) upbc_Error(s, __func__, "could not encode enum");
+  const char* desc = _upb_EnumDef_MiniDescriptor(e, s->arena);
+  if (!desc) upbc_Error(s, __func__, "could not encode enum");
 
-  upbc_State_Emit(s, upb_EnumDef_FullName(e), data, size);
+  upbc_State_Emit(s, upb_EnumDef_FullName(e), desc, strlen(desc));
 }
 
 static void upbc_Scrape_Extension(upbc_State* s, const upb_FieldDef* f) {