krabka_protocol_codegen/emit/
api_key_enum_quote.rs1use std::collections::BTreeMap;
24
25use proc_macro2::Literal;
26use quote::{format_ident, quote};
27
28use crate::{
29 emit::{EmitError, common::validate},
30 ir::{MessageSpec, MessageType},
31};
32
33pub fn emit(specs: &[MessageSpec], schemas_version: &str) -> Result<String, EmitError> {
37 let mut by_key: BTreeMap<i16, &MessageSpec> = BTreeMap::new();
39 for s in specs {
40 if matches!(s.message_type, MessageType::Request)
41 && let Some(k) = s.api_key
42 && !s.valid_versions.is_empty()
43 {
44 by_key.insert(k, s);
45 }
46 }
47
48 let variants = by_key.iter().map(|(k, s)| {
49 let pascal = s.name.trim_end_matches("Request");
50 let ident = format_ident!("{pascal}");
51 let disc = Literal::i16_unsuffixed(*k);
52 let r = s.valid_versions;
53 let max = if r.max == i16::MAX {
54 String::from("\u{221e}")
55 } else {
56 r.max.to_string()
57 };
58 let doc = format!(
59 " `{pascal}Request` (versions {min}\u{2013}{max}).",
60 min = r.min
61 );
62 quote! {
63 #[doc = #doc]
64 #ident = #disc,
65 }
66 });
67
68 let all_entries = by_key.values().map(|s| {
69 let ident = format_ident!("{}", s.name.trim_end_matches("Request"));
70 quote!(Self::#ident,)
71 });
72
73 let match_arms = by_key.iter().map(|(k, s)| {
74 let ident = format_ident!("{}", s.name.trim_end_matches("Request"));
75 let lit = Literal::i16_unsuffixed(*k);
76 quote!(#lit => Some(Self::#ident),)
77 });
78
79 let tokens = quote! {
80 #[doc = " Kafka API key registry generated from the vendored schemas."]
81 #[doc = ""]
82 #[doc = " Each variant corresponds to a request/response pair defined in the schemas."]
83 #[doc = " Variants with `validVersions = \"none\"` are omitted (reserved keys with no"]
84 #[doc = " currently-valid wire version)."]
85 #[doc = ""]
86 #[doc = " The enum is `#[non_exhaustive]` so that adding variants for new Kafka API"]
87 #[doc = " keys in future schema updates is non-breaking."]
88 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, strum::IntoStaticStr)]
89 #[repr(i16)]
90 #[non_exhaustive]
91 pub enum ApiKey {
92 #(#variants)*
93 }
94
95 impl ApiKey {
96 #[doc = " All known API keys, in ascending numeric order."]
97 pub const ALL: &'static [Self] = &[
98 #(#all_entries)*
99 ];
100
101 #[doc = " Resolve from numeric key; returns `None` for unknown keys."]
102 #[must_use]
103 pub fn from_i16(k: i16) -> Option<Self> {
104 match k {
105 #(#match_arms)*
106 _ => None,
107 }
108 }
109 }
110 };
111
112 validate::<syn::File>(&tokens, "ApiKey enum")?;
115 let banner = format!(
116 "// AUTO-GENERATED by krabka-protocol-codegen against {schemas_version}. Do not edit.\n\
117 // To regenerate: ./tools/regenerate.sh\n\n"
118 );
119 Ok(format!("{banner}{tokens}"))
120}