oas3-gen 0.23.6

A rust type generator for OpenAPI v3.1.x specification.
use std::collections::BTreeMap;

use super::union_types::{CollisionStrategy, EnumValueEntry};
use crate::generator::{
  ast::{Documentation, EnumDef, EnumToken, EnumVariantToken, RustType, SerdeAttribute, VariantContent, VariantDef},
  naming::inference::NormalizedVariant,
};

#[derive(Clone, Debug)]
pub(crate) struct ValueEnumBuilder {
  case_insensitive: bool,
}

impl ValueEnumBuilder {
  pub(crate) fn new(case_insensitive: bool) -> Self {
    Self { case_insensitive }
  }

  pub(crate) fn build_enum_from_values(
    &self,
    name: &str,
    entries: &[EnumValueEntry],
    strategy: CollisionStrategy,
    docs: Documentation,
  ) -> RustType {
    let mut variants: Vec<VariantDef> = vec![];
    let mut seen_names: BTreeMap<String, usize> = BTreeMap::new();

    for (i, entry) in entries.iter().enumerate() {
      let Ok(normalized) = NormalizedVariant::try_from(&entry.value) else {
        continue;
      };

      match seen_names.get(&normalized.name) {
        Some(&existing_idx) if strategy == CollisionStrategy::Deduplicate => {
          variants[existing_idx].add_alias(normalized.rename_value);
        }
        Some(_) => {
          Self::handle_preserve_collision(&mut variants, &mut seen_names, &normalized, i, entry);
        }
        None => {
          Self::add_new_variant(&mut variants, &mut seen_names, normalized, entry);
        }
      }
    }

    RustType::Enum(
      EnumDef::builder()
        .name(EnumToken::from_raw(name))
        .docs(docs)
        .variants(variants)
        .case_insensitive(self.case_insensitive)
        .generate_display(true)
        .build(),
    )
  }

  fn handle_preserve_collision(
    variants: &mut Vec<VariantDef>,
    seen_names: &mut BTreeMap<String, usize>,
    normalized: &NormalizedVariant,
    index: usize,
    entry: &EnumValueEntry,
  ) {
    let unique_name = format!("{}{index}", normalized.name);
    let idx = variants.len();
    seen_names.insert(unique_name.clone(), idx);
    variants.push(
      VariantDef::builder()
        .name(EnumVariantToken::from(unique_name))
        .docs(entry.docs.clone())
        .content(VariantContent::Unit)
        .serde_attrs(vec![SerdeAttribute::Rename(normalized.rename_value.clone())])
        .deprecated(entry.deprecated)
        .build(),
    );
  }

  fn add_new_variant(
    variants: &mut Vec<VariantDef>,
    seen_names: &mut BTreeMap<String, usize>,
    normalized: NormalizedVariant,
    entry: &EnumValueEntry,
  ) {
    let idx = variants.len();
    seen_names.insert(normalized.name.clone(), idx);
    variants.push(
      VariantDef::builder()
        .name(EnumVariantToken::from(normalized.name))
        .docs(entry.docs.clone())
        .content(VariantContent::Unit)
        .serde_attrs(vec![SerdeAttribute::Rename(normalized.rename_value)])
        .deprecated(entry.deprecated)
        .build(),
    );
  }
}