1use heck::ToKebabCase;
4use proc_macro2::TokenStream;
5use quote::{format_ident, quote};
6use syn::{Data, DeriveInput, Fields, FieldsNamed, FieldsUnnamed, Generics, Ident, Type};
7
8use crate::utils::crate_ident_new;
9
10pub fn impl_variant(input: DeriveInput) -> syn::Result<TokenStream> {
11 match input.data {
12 Data::Struct(data_struct) => Ok(derive_variant_for_struct(
13 input.ident,
14 input.generics,
15 data_struct,
16 )),
17 Data::Enum(data_enum) => {
18 let mode = get_enum_mode(&input.attrs)?;
19 let has_data = data_enum
20 .variants
21 .iter()
22 .any(|v| !matches!(v.fields, syn::Fields::Unit));
23 if has_data {
24 derive_variant_for_enum(input.ident, input.generics, data_enum, mode)
25 } else {
26 Ok(derive_variant_for_c_enum(
27 input.ident,
28 input.generics,
29 data_enum,
30 mode,
31 ))
32 }
33 }
34 Data::Union(..) => Err(syn::Error::new_spanned(
35 input,
36 "#[derive(glib::Variant)] is not available for unions.",
37 )),
38 }
39}
40
41fn derive_variant_for_struct(
42 ident: Ident,
43 generics: Generics,
44 data_struct: syn::DataStruct,
45) -> TokenStream {
46 let glib = crate_ident_new();
47 let (impl_generics, type_generics, where_clause) = generics.split_for_impl();
48 let (static_variant_type, to_variant, from_variant) = match data_struct.fields {
49 Fields::Unnamed(FieldsUnnamed { unnamed, .. }) => {
50 let types = unnamed
51 .into_pairs()
52 .map(|pair| pair.into_value())
53 .map(|field| field.ty)
54 .collect::<Vec<_>>();
55
56 let idents = (0..types.len()).map(syn::Index::from).collect::<Vec<_>>();
57 let idents_len = idents.len();
58
59 let static_variant_type = quote! {
60 impl #impl_generics #glib::variant::StaticVariantType for #ident #type_generics #where_clause {
61 #[inline]
62 fn static_variant_type() -> ::std::borrow::Cow<'static, #glib::VariantTy> {
63 static TYP: ::std::sync::OnceLock<#glib::VariantType> = ::std::sync::OnceLock::new();
64 ::std::borrow::Cow::Borrowed(TYP.get_or_init(|| {
65
66 let mut builder = #glib::GStringBuilder::new("(");
67
68 #(
69 {
70 let typ = <#types as #glib::variant::StaticVariantType>::static_variant_type();
71 builder.append(typ.as_str());
72 }
73 )*
74 builder.append_c(')');
75
76 #glib::VariantType::from_string(builder.into_string()).unwrap()
77 }))
78 }
79 }
80 };
81
82 let to_variant = quote! {
83 impl #impl_generics #glib::variant::ToVariant for #ident #type_generics #where_clause {
84 fn to_variant(&self) -> #glib::Variant {
85 #glib::Variant::tuple_from_iter(::std::array::IntoIter::<#glib::Variant, #idents_len>::new([
86 #(
87 #glib::variant::ToVariant::to_variant(&self.#idents)
88 ),*
89 ]))
90 }
91 }
92
93 impl #impl_generics ::std::convert::From<#ident #type_generics> for #glib::Variant #where_clause {
94 fn from(v: #ident #type_generics) -> #glib::Variant {
95 #glib::Variant::tuple_from_iter(::std::array::IntoIter::<#glib::Variant, #idents_len>::new([
96 #(
97 <#glib::Variant as ::std::convert::From<_>>::from(v.#idents)
98 ),*
99 ]))
100 }
101 }
102 };
103
104 let from_variant = quote! {
105 impl #impl_generics #glib::variant::FromVariant for #ident #type_generics #where_clause {
106 fn from_variant(variant: &#glib::Variant) -> ::core::option::Option<Self> {
107 if !variant.is_container() {
108 return ::core::option::Option::None;
109 }
110 ::core::option::Option::Some(Self(
111 #(
112 match variant.try_child_get::<#types>(#idents) {
113 ::core::result::Result::Ok(::core::option::Option::Some(field)) => field,
114 _ => return ::core::option::Option::None,
115 }
116 ),*
117 ))
118 }
119 }
120 };
121
122 (static_variant_type, to_variant, from_variant)
123 }
124 Fields::Named(FieldsNamed { named, .. }) => {
125 let fields: Vec<(Ident, Type)> = named
126 .into_pairs()
127 .map(|pair| pair.into_value())
128 .map(|field| (field.ident.expect("Field ident is specified"), field.ty))
129 .collect();
130
131 let idents: Vec<_> = fields.iter().map(|(ident, _ty)| ident).collect();
132 let types: Vec<_> = fields.iter().map(|(_ident, ty)| ty).collect();
133 let counts = (0..types.len()).map(syn::Index::from).collect::<Vec<_>>();
134
135 let static_variant_type = quote! {
136 impl #impl_generics #glib::variant::StaticVariantType for #ident #type_generics #where_clause {
137 #[inline]
138 fn static_variant_type() -> ::std::borrow::Cow<'static, #glib::VariantTy> {
139 static TYP: ::std::sync::OnceLock<#glib::VariantType> = ::std::sync::OnceLock::new();
140 ::std::borrow::Cow::Borrowed(TYP.get_or_init(|| unsafe {
141 let ptr = #glib::ffi::g_string_sized_new(16);
142 #glib::ffi::g_string_append_c(ptr, b'(' as _);
143
144 #(
145 {
146 let typ = <#types as #glib::variant::StaticVariantType>::static_variant_type();
147 #glib::ffi::g_string_append_len(
148 ptr,
149 typ.as_str().as_ptr() as *const _,
150 typ.as_str().len() as isize,
151 );
152 }
153 )*
154 #glib::ffi::g_string_append_c(ptr, b')' as _);
155
156 #glib::translate::from_glib_full(
157 #glib::ffi::g_string_free(ptr, #glib::ffi::GFALSE) as *mut #glib::ffi::GVariantType
158 )
159 }))
160 }
161 }
162 };
163
164 let to_variant = quote! {
165 impl #impl_generics #glib::variant::ToVariant for #ident #type_generics #where_clause {
166 fn to_variant(&self) -> #glib::Variant {
167 #glib::Variant::tuple_from_iter(::std::iter::IntoIterator::into_iter([
168 #(
169 #glib::variant::ToVariant::to_variant(&self.#idents)
170 ),*
171 ]))
172 }
173 }
174
175 impl #impl_generics ::std::convert::From<#ident #type_generics> for #glib::Variant #where_clause {
176 fn from(v: #ident #type_generics) -> #glib::Variant {
177 #glib::Variant::tuple_from_iter(::std::iter::IntoIterator::into_iter([
178 #(
179 <#glib::Variant as ::std::convert::From<_>>::from(v.#idents)
180 ),*
181 ]))
182 }
183 }
184 };
185
186 let from_variant = quote! {
187 impl #impl_generics #glib::variant::FromVariant for #ident #type_generics #where_clause {
188 fn from_variant(variant: &#glib::Variant) -> ::core::option::Option<Self> {
189 if !variant.is_container() {
190 return ::core::option::Option::None;
191 }
192 ::core::option::Option::Some(Self {
193 #(
194 #idents: match variant.try_child_get::<#types>(#counts) {
195 ::core::result::Result::Ok(::core::option::Option::Some(field)) => field,
196 _ => return ::core::option::Option::None,
197 }
198 ),*
199 })
200 }
201 }
202 };
203
204 (static_variant_type, to_variant, from_variant)
205 }
206 Fields::Unit => {
207 let static_variant_type = quote! {
208 impl #impl_generics #glib::variant::StaticVariantType for #ident #type_generics #where_clause {
209 #[inline]
210 fn static_variant_type() -> ::std::borrow::Cow<'static, #glib::VariantTy> {
211 ::std::borrow::Cow::Borrowed(#glib::VariantTy::UNIT)
212 }
213 }
214 };
215
216 let to_variant = quote! {
217 impl #impl_generics #glib::variant::ToVariant for #ident #type_generics #where_clause {
218 #[inline]
219 fn to_variant(&self) -> #glib::Variant {
220 #glib::variant::ToVariant::to_variant(&())
221 }
222 }
223
224 impl #impl_generics ::std::convert::From<#ident #type_generics> for #glib::Variant #where_clause {
225 #[inline]
226 fn from(v: #ident #type_generics) -> #glib::Variant {
227 #glib::variant::ToVariant::to_variant(&())
228 }
229 }
230 };
231
232 let from_variant = quote! {
233 impl #impl_generics #glib::variant::FromVariant for #ident #type_generics #where_clause {
234 fn from_variant(variant: &#glib::Variant) -> ::core::option::Option<Self> {
235 ::core::option::Option::Some(Self)
236 }
237 }
238 };
239
240 (static_variant_type, to_variant, from_variant)
241 }
242 };
243
244 quote! {
245 #static_variant_type
246
247 #to_variant
248
249 #from_variant
250 }
251}
252
253enum EnumMode {
254 String,
255 Repr(Ident),
256 Enum { repr: bool },
257 Flags { repr: bool },
258}
259
260impl EnumMode {
261 fn tag_type(&self) -> char {
262 match self {
263 EnumMode::String => 's',
264 EnumMode::Repr(repr) => match repr.to_string().as_str() {
265 "i8" | "i16" => 'n',
266 "i32" => 'i',
267 "i64" => 'x',
268 "u8" => 'y',
269 "u16" => 'q',
270 "u32" => 'u',
271 "u64" => 't',
272 _ => unimplemented!(),
273 },
274 EnumMode::Enum { repr } => {
275 if *repr {
276 'i'
277 } else {
278 's'
279 }
280 }
281 EnumMode::Flags { repr } => {
282 if *repr {
283 'u'
284 } else {
285 's'
286 }
287 }
288 }
289 }
290}
291
292fn derive_variant_for_enum(
293 ident: Ident,
294 generics: Generics,
295 data_enum: syn::DataEnum,
296 mode: EnumMode,
297) -> syn::Result<TokenStream> {
298 let glib = crate_ident_new();
299 let static_variant_type = format!("({}v)", mode.tag_type());
300 let (impl_generics, type_generics, where_clause) = generics.split_for_impl();
301
302 let to = data_enum.variants.iter().enumerate().map(|(index, v)| {
303 let ident = &v.ident;
304 let tag = match &mode {
305 EnumMode::String => {
306 let nick = ToKebabCase::to_kebab_case(ident.to_string().as_str());
307 quote! { #nick }
308 },
309 EnumMode::Repr(repr) => quote! { #index as #repr },
310 _ => unimplemented!(),
311 };
312 if !matches!(v.fields, syn::Fields::Unit) {
313 match &mode {
314 EnumMode::Enum { .. } =>
315 return Err(syn::Error::new_spanned(v, "#[variant_enum(enum) only allowed with C-style enums using #[derive(glib::Enum)]")),
316 EnumMode::Flags { .. } =>
317 return Err(syn::Error::new_spanned(v, "#[variant_enum(flags) only allowed with bitflags using #[glib::flags]")),
318 _ => (),
319 }
320 }
321 Ok(match &v.fields {
322 syn::Fields::Named(FieldsNamed { named, .. }) => {
323 let field_names = named.iter().map(|f| f.ident.as_ref().unwrap());
324 let field_names2 = field_names.clone();
325 quote! {
326 Self::#ident { #(#field_names),* } => #glib::variant::ToVariant::to_variant(&(
327 #tag,
328 #glib::Variant::tuple_from_iter(::std::iter::IntoIterator::into_iter([
329 #(#glib::variant::ToVariant::to_variant(&#field_names2)),*
330 ]))
331 ))
332 }
333 },
334 syn::Fields::Unnamed(FieldsUnnamed { unnamed, .. }) => {
335 let field_names = unnamed.iter().enumerate().map(|(i, _)| {
336 format_ident!("field{}", i)
337 });
338 let field_names2 = field_names.clone();
339 quote! {
340 Self::#ident(#(#field_names),*) => #glib::variant::ToVariant::to_variant(&(
341 #tag,
342 #glib::Variant::tuple_from_iter(::std::iter::IntoIterator::into_iter([
343 #(#glib::variant::ToVariant::to_variant(&#field_names2)),*
344 ]))
345 ))
346 }
347 },
348 syn::Fields::Unit => {
349 quote! {
350 Self::#ident => #glib::variant::ToVariant::to_variant(&(
351 #tag,
352 #glib::variant::ToVariant::to_variant(&())
353 ))
354 }
355 },
356 })
357 }).collect::<Result<Vec<_>, _>>()?;
358 let into = data_enum.variants.iter().enumerate().map(|(index, v)| {
359 let field_ident = &v.ident;
360 let tag = match &mode {
361 EnumMode::String => {
362 let nick = ToKebabCase::to_kebab_case(field_ident.to_string().as_str());
363 quote! { #nick }
364 }
365 EnumMode::Repr(repr) => quote! { #index as #repr },
366 _ => unimplemented!(),
367 };
368 match &v.fields {
369 syn::Fields::Named(FieldsNamed { named, .. }) => {
370 let field_names = named.iter().map(|f| f.ident.as_ref().unwrap());
371 let field_names2 = field_names.clone();
372 quote! {
373 #ident::#field_ident { #(#field_names),* } => #glib::variant::ToVariant::to_variant(&(
374 #tag,
375 #glib::Variant::tuple_from_iter(::std::iter::IntoIterator::into_iter([
376 #(<#glib::Variant as ::std::convert::From<_>>::from(#field_names2)),*
377 ]))
378 ))
379 }
380 }
381 syn::Fields::Unnamed(FieldsUnnamed { unnamed, .. }) => {
382 let field_names = unnamed
383 .iter()
384 .enumerate()
385 .map(|(i, _)| format_ident!("field{}", i));
386 let field_names2 = field_names.clone();
387 quote! {
388 #ident::#field_ident(#(#field_names),*) => #glib::variant::ToVariant::to_variant(&(
389 #tag,
390 #glib::Variant::tuple_from_iter(::std::iter::IntoIterator::into_iter([
391 #(<#glib::Variant as ::std::convert::From<_>>::from(#field_names2)),*
392 ]))
393 ))
394 }
395 }
396 syn::Fields::Unit => {
397 quote! {
398 #ident::#field_ident => #glib::variant::ToVariant::to_variant(&(
399 #tag,
400 #glib::variant::ToVariant::to_variant(&())
401 ))
402 }
403 }
404 }
405 });
406 let from = data_enum.variants.iter().enumerate().map(|(index, v)| {
407 let ident = &v.ident;
408 let tag = match &mode {
409 EnumMode::String => {
410 let nick = ToKebabCase::to_kebab_case(ident.to_string().as_str());
411 quote! { #nick }
412 }
413 EnumMode::Repr(_) => quote! { #index },
414 _ => unimplemented!(),
415 };
416 match &v.fields {
417 syn::Fields::Named(FieldsNamed { named, .. }) => {
418 let fields = named.iter().enumerate().map(|(index, f)| {
419 let name = f.ident.as_ref().unwrap();
420 let repr = &f.ty;
421 quote! {
422 #name: <#repr as #glib::variant::FromVariant>::from_variant(
423 &#glib::Variant::try_child_value(&value, #index)?
424 )?
425 }
426 });
427 quote! { #tag => ::core::option::Option::Some(Self::#ident { #(#fields),* }), }
428 }
429 syn::Fields::Unnamed(FieldsUnnamed { unnamed, .. }) => {
430 let indices = 0..unnamed.iter().count();
431 let repr = unnamed.iter().map(|f| &f.ty);
432 quote! {
433 #tag => ::core::option::Option::Some(Self::#ident(
434 #(
435 <#repr as #glib::variant::FromVariant>::from_variant(
436 &#glib::Variant::try_child_value(&value, #indices)?
437 )?
438 ),*
439 )),
440 }
441 }
442 syn::Fields::Unit => {
443 quote! { #tag => ::core::option::Option::Some(Self::#ident), }
444 }
445 }
446 });
447
448 let (repr, tag_match) = match &mode {
449 EnumMode::String => (quote! { String }, quote! { tag.as_str() }),
450 EnumMode::Repr(repr) => (quote! { #repr }, quote! { tag as usize }),
451 _ => unimplemented!(),
452 };
453
454 Ok(quote! {
455 impl #impl_generics #glib::variant::StaticVariantType for #ident #type_generics #where_clause {
456 #[inline]
457 fn static_variant_type() -> ::std::borrow::Cow<'static, #glib::VariantTy> {
458 ::std::borrow::Cow::Borrowed(
459 unsafe {
460 #glib::VariantTy::from_str_unchecked(#static_variant_type)
461 }
462 )
463 }
464 }
465
466 impl #impl_generics #glib::variant::ToVariant for #ident #type_generics #where_clause {
467 fn to_variant(&self) -> #glib::Variant {
468 match self {
469 #(#to),*
470 }
471 }
472 }
473
474 impl #impl_generics ::std::convert::From<#ident #type_generics> for #glib::Variant #where_clause {
475 fn from(v: #ident #type_generics) -> #glib::Variant {
476 match v {
477 #(#into),*
478 }
479 }
480 }
481
482 impl #impl_generics #glib::variant::FromVariant for #ident #type_generics #where_clause {
483 fn from_variant(variant: &#glib::Variant) -> ::core::option::Option<Self> {
484 let (tag, value) = <(#repr, #glib::Variant) as #glib::variant::FromVariant>::from_variant(&variant)?;
485 if !#glib::VariantTy::is_tuple(#glib::Variant::type_(&value)) {
486 return ::core::option::Option::None;
487 }
488 match #tag_match {
489 #(#from)*
490 _ => ::core::option::Option::None
491 }
492 }
493 }
494 })
495}
496
497fn derive_variant_for_c_enum(
498 ident: Ident,
499 generics: Generics,
500 data_enum: syn::DataEnum,
501 mode: EnumMode,
502) -> TokenStream {
503 let glib = crate_ident_new();
504 let static_variant_type = mode.tag_type().to_string();
505 let (impl_generics, type_generics, where_clause) = generics.split_for_impl();
506
507 let (to_variant, from_variant) = match mode {
508 EnumMode::String => {
509 let idents = data_enum.variants.iter().map(|v| &v.ident);
510 let nicks = data_enum.variants.iter().map(|v| {
511 let nick = ToKebabCase::to_kebab_case(v.ident.to_string().as_str());
512 quote! { #nick }
513 });
514 let idents2 = idents.clone();
515 let nicks2 = nicks.clone();
516 (
517 quote! {
518 #glib::variant::ToVariant::to_variant(match self {
519 #(Self::#idents => #nicks),*
520 })
521 },
522 quote! {
523 let tag = #glib::Variant::str(&variant)?;
524 match tag {
525 #(#nicks2 => ::core::option::Option::Some(Self::#idents2),)*
526 _ => ::core::option::Option::None
527 }
528 },
529 )
530 }
531 EnumMode::Repr(repr) => {
532 let idents = data_enum.variants.iter().map(|v| &v.ident);
533 (
534 quote! {
535 #glib::variant::ToVariant::to_variant(&(*self as #repr))
536 },
537 quote! {
538 let value = <#repr as #glib::variant::FromVariant>::from_variant(&variant)?;
539 #(if value == Self::#idents as #repr {
540 return ::core::option::Option::Some(Self::#idents);
541 })*
542 ::core::option::Option::None
543 },
544 )
545 }
546 EnumMode::Enum { repr: true } => (
547 quote! {
548 #glib::variant::ToVariant::to_variant(&(*self as i32))
549 },
550 quote! {
551 let value = <i32 as #glib::variant::FromVariant>::from_variant(&variant)?;
552 unsafe { #glib::translate::try_from_glib(value) }.ok()
553 },
554 ),
555 EnumMode::Enum { repr: false } => (
556 quote! {
557 let enum_class = #glib::EnumClass::new::<Self>();
558 let value = <Self as #glib::translate::IntoGlib>::into_glib(*self);
559 let value = #glib::EnumClass::value(&enum_class, value);
560 let value = ::core::option::Option::unwrap(value);
561 let nick = #glib::EnumValue::nick(&value);
562 #glib::variant::ToVariant::to_variant(nick)
563 },
564 quote! {
565 let enum_class = #glib::EnumClass::new::<Self>();
566 let tag = #glib::Variant::str(&variant)?;
567 let value = #glib::EnumClass::value_by_nick(&enum_class, tag)?;
568 let value = #glib::EnumValue::value(&value);
569 unsafe { #glib::translate::try_from_glib(value) }.ok()
570 },
571 ),
572 EnumMode::Flags { repr: true } => (
573 quote! {
574 #glib::variant::ToVariant::to_variant(&self.bits())
575 },
576 quote! {
577 let value = <u32 as #glib::variant::FromVariant>::from_variant(&variant)?;
578 Self::from_bits(value)
579 },
580 ),
581 EnumMode::Flags { repr: false } => (
582 quote! {
583 let flags_class = #glib::FlagsClass::new::<Self>();
584 let value = <Self as #glib::translate::IntoGlib>::into_glib(*self);
585 let s = #glib::FlagsClass::to_nick_string(&flags_class, value);
586 #glib::variant::ToVariant::to_variant(&s)
587 },
588 quote! {
589 let flags_class = #glib::FlagsClass::new::<Self>();
590 let s = #glib::Variant::str(&variant)?;
591 let value = #glib::FlagsClass::from_nick_string(&flags_class, s).ok()?;
592 ::core::option::Option::Some(unsafe { #glib::translate::from_glib(value) })
593 },
594 ),
595 };
596
597 quote! {
598 impl #impl_generics #glib::variant::StaticVariantType for #ident #type_generics #where_clause {
599 #[inline]
600 fn static_variant_type() -> ::std::borrow::Cow<'static, #glib::VariantTy> {
601 ::std::borrow::Cow::Borrowed(
602 unsafe {
603 #glib::VariantTy::from_str_unchecked(#static_variant_type)
604 }
605 )
606 }
607 }
608
609 impl #impl_generics #glib::variant::ToVariant for #ident #type_generics #where_clause {
610 fn to_variant(&self) -> #glib::Variant {
611 #to_variant
612 }
613 }
614
615 impl #impl_generics ::std::convert::From<#ident #type_generics> for #glib::Variant #where_clause {
616 #[inline]
617 fn from(v: #ident #type_generics) -> #glib::Variant {
618 <#ident #type_generics as #glib::variant::ToVariant>::to_variant(&v)
619 }
620 }
621
622 impl #impl_generics #glib::variant::FromVariant for #ident #type_generics #where_clause {
623 fn from_variant(variant: &#glib::Variant) -> ::core::option::Option<Self> {
624 #from_variant
625 }
626 }
627 }
628}
629
630fn get_enum_mode(attrs: &[syn::Attribute]) -> syn::Result<EnumMode> {
631 let attr = attrs.iter().find(|a| a.path().is_ident("variant_enum"));
632
633 let Some(attr) = attr else {
634 return Ok(EnumMode::String);
635 };
636
637 let mut repr_attr = None;
638 let mut mode = EnumMode::String;
639 attr.parse_nested_meta(|meta| {
640 match meta.path.get_ident().map(|id| id.to_string()).as_deref() {
641 Some("repr") => {
642 repr_attr = Some(meta.path);
643 Ok(())
644 }
645 Some("enum") => {
646 mode = EnumMode::Enum { repr: false };
647 Ok(())
648 }
649 Some("flags") => {
650 mode = EnumMode::Flags { repr: false };
651 Ok(())
652 }
653 _ => Err(syn::Error::new_spanned(
654 meta.path,
655 "unknown type in #[variant_enum] attribute",
656 )),
657 }
658 })?;
659 Ok(match mode {
660 EnumMode::String if repr_attr.is_some() => {
661 let repr_attr = repr_attr.unwrap();
662 let repr = get_repr(attrs).ok_or_else(|| {
663 syn::Error::new_spanned(
664 repr_attr,
665 "Must have #[repr] attribute with one of i8, i16, i32, i64, u8, u16, u32, u64",
666 )
667 })?;
668 EnumMode::Repr(repr)
669 }
670 EnumMode::Enum { .. } => EnumMode::Enum {
671 repr: repr_attr.is_some(),
672 },
673 EnumMode::Flags { .. } => EnumMode::Flags {
674 repr: repr_attr.is_some(),
675 },
676 e => e,
677 })
678}
679
680fn get_repr(attrs: &[syn::Attribute]) -> Option<Ident> {
681 let attr = attrs.iter().find(|a| a.path().is_ident("repr"))?;
682 let mut repr_ty = None;
683 attr.parse_nested_meta(|meta| {
684 repr_ty = Some(meta.path.get_ident().unwrap().clone());
685 Ok(())
686 })
687 .unwrap();
688 match repr_ty.as_ref()?.to_string().as_str() {
689 "i8" | "i16" | "i32" | "i64" | "u8" | "u16" | "u32" | "u64" => Some(repr_ty?),
690 _ => None,
691 }
692}