1use std::ffi::OsStr;
4use std::fmt;
5use std::fmt::Display;
6use std::ops::Deref;
7
8use super::BtfKind;
9use super::BtfType;
10use super::HasSize;
11use super::ReferencesType;
12use super::TypeId;
13
14macro_rules! gen_fieldless_concrete_type {
17 (
18 $(#[$docs:meta])*
19 $name:ident $(with $trait:ident)?
20 ) => {
21 $(#[$docs])*
22 #[derive(Clone, Copy, Debug)]
23 pub struct $name<'btf> {
24 source: BtfType<'btf>,
25 }
26
27 impl<'btf> TryFrom<BtfType<'btf>> for $name<'btf> {
28 type Error = BtfType<'btf>;
29
30 fn try_from(t: BtfType<'btf>) -> ::core::result::Result<Self, Self::Error> {
31 if t.kind() == BtfKind::$name {
32 Ok($name { source: t })
33 } else {
34 Err(t)
35 }
36 }
37 }
38
39 impl<'btf> ::std::ops::Deref for $name<'btf> {
40 type Target = BtfType<'btf>;
41 fn deref(&self) -> &Self::Target {
42 &self.source
43 }
44 }
45
46 $(
47 impl super::sealed::Sealed for $name<'_> {}
48 unsafe impl<'btf> $trait<'btf> for $name<'btf> {}
49 )*
50 };
51}
52
53macro_rules! gen_concrete_type {
56 (
57 $(#[$docs:meta])*
58 $libbpf_ty:ident as $name:ident $(with $trait:ident)?
59 ) => {
60 $(#[$docs])*
61 #[derive(Clone, Copy, Debug)]
62 pub struct $name<'btf> {
63 source: BtfType<'btf>,
64 ptr: &'btf libbpf_sys::$libbpf_ty,
65 }
66
67 impl<'btf> TryFrom<BtfType<'btf>> for $name<'btf> {
68 type Error = BtfType<'btf>;
69
70 fn try_from(t: BtfType<'btf>) -> ::core::result::Result<Self, Self::Error> {
71 if t.kind() == BtfKind::$name {
72 let ptr = unsafe {
73 (t.ty as *const libbpf_sys::btf_type).offset(1)
78 };
79 let ptr = ptr.cast::<libbpf_sys::$libbpf_ty>();
80 Ok($name {
81 source: t,
82 ptr: unsafe { &*ptr },
93 })
94 } else {
95 Err(t)
96 }
97 }
98 }
99
100 impl<'btf> ::std::ops::Deref for $name<'btf> {
101 type Target = BtfType<'btf>;
102 fn deref(&self) -> &Self::Target {
103 &self.source
104 }
105 }
106
107 $(
108 impl super::sealed::Sealed for $name<'_> {}
109 unsafe impl<'btf> $trait<'btf> for $name<'btf> {}
110 )*
111 };
112}
113
114macro_rules! gen_collection_members_concrete_type {
115 (
116 $libbpf_ty:ident as $name:ident $(with $trait:ident)?;
117
118 $(#[$docs:meta])*
119 struct $member_name:ident $(<$lt:lifetime>)? {
120 $(
121 $(#[$field_docs:meta])*
122 pub $field:ident : $type:ty
123 ),* $(,)?
124 }
125
126 |$btf:ident, $member:ident $(, $kind_flag:ident)?| $convert:expr
127 ) => {
128 impl<'btf> ::std::ops::Deref for $name<'btf> {
129 type Target = BtfType<'btf>;
130 fn deref(&self) -> &Self::Target {
131 &self.source
132 }
133 }
134
135 impl<'btf> $name<'btf> {
136 #[inline]
138 pub fn is_empty(&self) -> bool {
139 self.members.is_empty()
140 }
141
142 #[doc = ::core::concat!("How many members this [`", ::core::stringify!($name), "`] has")]
143 #[inline]
144 pub fn len(&self) -> usize {
145 self.members.len()
146 }
147
148 #[doc = ::core::concat!("Get a [`", ::core::stringify!($member_name), "`] at a given index")]
149 pub fn get(&self, index: usize) -> Option<$member_name$(<$lt>)*> {
153 self.members.get(index).map(|m| self.c_to_rust_member(m))
154 }
155
156 #[doc = ::core::concat!("Returns an iterator over the [`", ::core::stringify!($member_name), "`]'s of the [`", ::core::stringify!($name), "`]")]
157 pub fn iter(&'btf self) -> impl ExactSizeIterator<Item = $member_name$(<$lt>)*> + 'btf {
158 self.members.iter().map(|m| self.c_to_rust_member(m))
159 }
160
161 fn c_to_rust_member(&self, member: &libbpf_sys::$libbpf_ty) -> $member_name$(<$lt>)* {
162 let $btf = self.source.source;
163 let $member = member;
164 $(let $kind_flag = self.source.kind_flag();)*
165 $convert
166 }
167 }
168
169 $(#[$docs])*
170 #[derive(Clone, Copy, Debug)]
171 pub struct $member_name $(<$lt>)? {
172 $(
173 $(#[$field_docs])*
174 pub $field: $type
175 ),*
176 }
177
178 $(
179 impl $crate::btf::sealed::Sealed for $name<'_> {}
180 unsafe impl<'btf> $trait<'btf> for $name<'btf> {}
181 )*
182 };
183}
184
185macro_rules! gen_collection_concrete_type {
186 (
187 $(#[$docs:meta])*
188 $libbpf_ty:ident as $name:ident $(with $trait:ident)?;
189
190 $($rest:tt)+
191 ) => {
192 $(#[$docs])*
193 #[derive(Clone, Copy, Debug)]
194 pub struct $name<'btf> {
195 source: BtfType<'btf>,
196 members: &'btf [libbpf_sys::$libbpf_ty],
197 }
198
199 impl<'btf> TryFrom<BtfType<'btf>> for $name<'btf> {
200 type Error = BtfType<'btf>;
201
202 fn try_from(t: BtfType<'btf>) -> ::core::result::Result<Self, Self::Error> {
203 if t.kind() == BtfKind::$name {
204 let base_ptr = unsafe {
205 (t.ty as *const libbpf_sys::btf_type).offset(1)
210 };
211 let members = unsafe {
212 std::slice::from_raw_parts(base_ptr.cast(), t.vlen() as usize)
225 };
226 Ok(Self { source: t, members })
227 } else {
228 Err(t)
229 }
230 }
231 }
232
233 gen_collection_members_concrete_type!{
234 $libbpf_ty as $name $(with $trait)?;
235 $($rest)*
236 }
237 };
238}
239
240#[derive(Clone, Copy, Debug)]
242pub enum MemberAttr {
243 Normal {
245 offset: u32,
247 },
248 BitField {
250 size: u8,
252 offset: u32,
254 },
255}
256
257impl MemberAttr {
258 #[inline]
259 fn new(kflag: bool, offset: u32) -> Self {
260 if kflag {
261 let size = (offset >> 24) as u8;
262 if size != 0 {
263 Self::BitField {
264 size,
265 offset: offset & 0x00_ff_ff_ff,
266 }
267 } else {
268 Self::Normal { offset }
269 }
270 } else {
271 Self::Normal { offset }
272 }
273 }
274}
275
276#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
278#[repr(u32)]
279#[doc(alias = "btf_func_linkage")]
280pub enum Linkage {
281 Static = 0,
283 Global,
285 Extern,
287 Unknown,
289}
290
291impl From<u32> for Linkage {
292 fn from(value: u32) -> Self {
293 use Linkage::*;
294
295 match value {
296 x if x == Static as u32 => Static,
297 x if x == Global as u32 => Global,
298 x if x == Extern as u32 => Extern,
299 _ => Unknown,
300 }
301 }
302}
303
304impl From<Linkage> for u32 {
305 fn from(value: Linkage) -> Self {
306 value as Self
307 }
308}
309
310impl Display for Linkage {
311 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
312 write!(
313 f,
314 "{}",
315 match self {
316 Self::Static => "static",
317 Self::Global => "global",
318 Self::Extern => "extern",
319 Self::Unknown => "(unknown)",
320 }
321 )
322 }
323}
324
325gen_fieldless_concrete_type! {
327 #[doc(alias = "BTF_KIND_UNKN")]
329 Void
330}
331
332#[derive(Clone, Copy, Debug)]
338#[doc(alias = "BTF_KIND_INT")]
339pub struct Int<'btf> {
340 source: BtfType<'btf>,
341 pub encoding: IntEncoding,
343 pub offset: u8,
346 pub bits: u8,
348}
349
350#[derive(Clone, Copy, Debug)]
352pub enum IntEncoding {
353 None,
355 Signed,
357 Char,
359 Bool,
361}
362
363impl<'btf> TryFrom<BtfType<'btf>> for Int<'btf> {
364 type Error = BtfType<'btf>;
365
366 fn try_from(t: BtfType<'btf>) -> Result<Self, Self::Error> {
367 if t.kind() == BtfKind::Int {
368 let int = {
369 let base_ptr = t.ty as *const libbpf_sys::btf_type;
370 let u32_ptr = unsafe {
371 base_ptr.offset(1).cast::<u32>()
376 };
377 unsafe {
378 *u32_ptr
389 }
390 };
391 let encoding = match (int & 0x0f_00_00_00) >> 24 {
392 0b1 => IntEncoding::Signed,
393 0b10 => IntEncoding::Char,
394 0b100 => IntEncoding::Bool,
395 _ => IntEncoding::None,
396 };
397 Ok(Self {
398 source: t,
399 encoding,
400 offset: ((int & 0x00_ff_00_00) >> 24) as u8,
401 bits: (int & 0x00_00_00_ff) as u8,
402 })
403 } else {
404 Err(t)
405 }
406 }
407}
408
409impl<'btf> Deref for Int<'btf> {
410 type Target = BtfType<'btf>;
411 fn deref(&self) -> &Self::Target {
412 &self.source
413 }
414}
415
416impl super::sealed::Sealed for Int<'_> {}
418unsafe impl<'btf> HasSize<'btf> for Int<'btf> {}
419
420gen_fieldless_concrete_type! {
422 #[doc(alias = "BTF_KIND_PTR")]
426 Ptr with ReferencesType
427}
428
429gen_concrete_type! {
431 #[doc(alias = "BTF_KIND_ARRAY")]
435 #[doc(alias = "btf_array")]
436 btf_array as Array
437}
438
439impl<'s> Array<'s> {
440 #[inline]
442 pub fn ty(&self) -> TypeId {
443 self.ptr.type_.into()
444 }
445
446 #[inline]
448 pub fn index_ty(&self) -> TypeId {
449 self.ptr.index_type.into()
450 }
451
452 #[inline]
454 pub fn capacity(&self) -> usize {
455 self.ptr.nelems as usize
456 }
457
458 #[inline]
460 pub fn contained_type(&self) -> BtfType<'s> {
461 self.source
462 .source
463 .type_by_id(self.ty())
464 .expect("arrays should always reference an existing type")
465 }
466}
467
468gen_collection_concrete_type! {
470 #[doc(alias = "BTF_KIND_STRUCT")]
474 btf_member as Struct with HasSize;
475
476 #[doc(alias = "btf_member")]
478 struct StructMember<'btf> {
479 pub name: Option<&'btf OsStr>,
481 pub ty: TypeId,
483 pub attr: MemberAttr,
485 }
486
487 |btf, member, kflag| StructMember {
488 name: btf.name_at(member.name_off),
489 ty: member.type_.into(),
490 attr: MemberAttr::new(kflag, member.offset),
491 }
492}
493
494gen_collection_concrete_type! {
496 #[doc(alias = "BTF_KIND_UNION")]
500 btf_member as Union with HasSize;
501
502 #[doc(alias = "btf_member")]
504 struct UnionMember<'btf> {
505 pub name: Option<&'btf OsStr>,
507 pub ty: TypeId,
509 pub attr: MemberAttr,
511 }
512
513 |btf, member, kflag| UnionMember {
514 name: btf.name_at(member.name_off),
515 ty: member.type_.into(),
516 attr: MemberAttr::new(kflag, member.offset),
517 }
518}
519
520#[derive(Clone, Copy, Debug)]
525pub struct Composite<'btf> {
526 source: BtfType<'btf>,
527 pub is_struct: bool,
529 members: &'btf [libbpf_sys::btf_member],
530}
531
532impl<'btf> From<Struct<'btf>> for Composite<'btf> {
533 fn from(s: Struct<'btf>) -> Self {
534 Self {
535 source: s.source,
536 is_struct: true,
537 members: s.members,
538 }
539 }
540}
541
542impl<'btf> From<Union<'btf>> for Composite<'btf> {
543 fn from(s: Union<'btf>) -> Self {
544 Self {
545 source: s.source,
546 is_struct: false,
547 members: s.members,
548 }
549 }
550}
551
552impl<'btf> TryFrom<BtfType<'btf>> for Composite<'btf> {
553 type Error = BtfType<'btf>;
554
555 fn try_from(t: BtfType<'btf>) -> Result<Self, Self::Error> {
556 Struct::try_from(t)
557 .map(Self::from)
558 .or_else(|_| Union::try_from(t).map(Self::from))
559 }
560}
561
562impl<'btf> TryFrom<Composite<'btf>> for Struct<'btf> {
563 type Error = Composite<'btf>;
564
565 fn try_from(value: Composite<'btf>) -> Result<Self, Self::Error> {
566 if value.is_struct {
567 Ok(Self {
568 source: value.source,
569 members: value.members,
570 })
571 } else {
572 Err(value)
573 }
574 }
575}
576
577impl<'btf> TryFrom<Composite<'btf>> for Union<'btf> {
578 type Error = Composite<'btf>;
579
580 fn try_from(value: Composite<'btf>) -> Result<Self, Self::Error> {
581 if !value.is_struct {
582 Ok(Self {
583 source: value.source,
584 members: value.members,
585 })
586 } else {
587 Err(value)
588 }
589 }
590}
591
592impl Composite<'_> {
593 pub fn is_empty_union(&self) -> bool {
595 !self.is_struct && self.is_empty()
596 }
597}
598
599gen_collection_members_concrete_type! {
601 btf_member as Composite with HasSize;
602
603 struct CompositeMember<'btf> {
605 pub name: Option<&'btf OsStr>,
607 pub ty: TypeId,
609 pub attr: MemberAttr
611 }
612
613 |btf, member, kflag| CompositeMember {
614 name: btf.name_at(member.name_off),
615 ty: member.type_.into(),
616 attr: MemberAttr::new(kflag, member.offset),
617 }
618}
619
620gen_collection_concrete_type! {
622 #[doc(alias = "BTF_KIND_ENUM")]
626 btf_enum as Enum with HasSize;
627
628 #[doc(alias = "btf_enum")]
630 struct EnumMember<'btf> {
631 pub name: Option<&'btf OsStr>,
633 pub value: i64,
635 }
636
637 |btf, member, signed| {
638 EnumMember {
639 name: btf.name_at(member.name_off),
640 value: if signed {
641 member.val.into()
642 } else {
643 u32::from_ne_bytes(member.val.to_ne_bytes()).into()
644 }
645 }
646 }
647}
648
649impl Enum<'_> {
650 #[inline]
652 pub fn is_signed(&self) -> bool {
653 self.kind_flag()
654 }
655}
656
657
658gen_fieldless_concrete_type! {
660 #[doc(alias = "BTF_KIND_FWD")]
664 Fwd
665}
666
667impl Fwd<'_> {
668 pub fn kind(&self) -> FwdKind {
670 if self.source.kind_flag() {
671 FwdKind::Union
672 } else {
673 FwdKind::Struct
674 }
675 }
676}
677
678#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
680pub enum FwdKind {
681 Struct,
683 Union,
685}
686
687gen_fieldless_concrete_type! {
689 #[doc(alias = "BTF_KIND_TYPEDEF")]
695 Typedef with ReferencesType
696}
697
698gen_fieldless_concrete_type! {
700 #[doc(alias = "BTF_KIND_VOLATILE")]
704 Volatile with ReferencesType
705}
706
707gen_fieldless_concrete_type! {
709 #[doc(alias = "BTF_KIND_CONST")]
713 Const with ReferencesType
714}
715
716gen_fieldless_concrete_type! {
718 #[doc(alias = "BTF_KIND_RESTRICT")]
722 Restrict with ReferencesType
723}
724
725gen_fieldless_concrete_type! {
727 #[doc(alias = "BTF_KIND_FUNC")]
731 Func with ReferencesType
732}
733
734impl Func<'_> {
735 #[inline]
737 pub fn linkage(&self) -> Linkage {
738 self.source.vlen().into()
739 }
740}
741
742gen_collection_concrete_type! {
744 #[doc(alias = "BTF_KIND_FUNC_PROTO")]
748 btf_param as FuncProto with ReferencesType;
749
750 #[doc(alias = "btf_param")]
752 struct FuncProtoParam<'btf> {
753 pub name: Option<&'btf OsStr>,
755 pub ty: TypeId,
757 }
758
759 |btf, member| FuncProtoParam {
760 name: btf.name_at(member.name_off),
761 ty: member.type_.into()
762 }
763}
764
765gen_concrete_type! {
767 #[doc(alias = "BTF_KIND_VAR")]
771 #[doc(alias = "btf_var")]
772 btf_var as Var with ReferencesType
773}
774
775impl Var<'_> {
776 #[inline]
778 pub fn linkage(&self) -> Linkage {
779 self.ptr.linkage.into()
780 }
781}
782
783gen_collection_concrete_type! {
785 #[doc(alias = "BTF_KIND_DATASEC")]
789 btf_var_secinfo as DataSec with HasSize;
790
791 #[doc(alias = "btf_var_secinfo")]
795 struct VarSecInfo {
796 pub ty: TypeId,
798 pub offset: u32,
800 pub size: usize,
802 }
803
804 |_btf, member| VarSecInfo {
805 ty: member.type_.into(),
806 offset: member.offset,
807 size: member.size as usize
808 }
809}
810
811gen_fieldless_concrete_type! {
813 #[doc(alias = "BTF_KIND_FLOAT")]
817 Float with HasSize
818}
819
820gen_concrete_type! {
822 #[doc(alias = "BTF_KIND_DECL_TAG")]
830 #[doc(alias = "btf_decl_tag")]
831 btf_decl_tag as DeclTag with ReferencesType
832}
833
834impl DeclTag<'_> {
835 #[inline]
839 pub fn component_index(&self) -> Option<u32> {
840 self.ptr.component_idx.try_into().ok()
841 }
842}
843
844gen_fieldless_concrete_type! {
846 #[doc(alias = "BTF_KIND_TYPE_TAG")]
850 TypeTag with ReferencesType
851}
852
853gen_collection_concrete_type! {
855 #[doc(alias = "BTF_KIND_ENUM64")]
859 btf_enum64 as Enum64 with HasSize;
860
861 #[doc(alias = "btf_enum64")]
863 struct Enum64Member<'btf> {
864 pub name: Option<&'btf OsStr>,
866 pub value: i128,
868 }
869
870 |btf, member, signed| Enum64Member {
871 name: btf.name_at(member.name_off),
872 value: {
873 let hi: u64 = member.val_hi32.into();
874 let lo: u64 = member.val_lo32.into();
875 let val = (hi << 32) | lo;
876 if signed {
877 i64::from_ne_bytes(val.to_ne_bytes()).into()
878 } else {
879 val.into()
880 }
881 },
882 }
883}
884
885impl Enum64<'_> {
886 #[inline]
888 pub fn is_signed(&self) -> bool {
889 self.kind_flag()
890 }
891}
892
893
894#[macro_export]
948macro_rules! btf_type_match {
949 (
951 match $ty:ident {
952 $($pattern:tt)+
953 }
954 ) => {{
955 let ty: $crate::btf::BtfType<'_> = $ty;
956 $crate::__btf_type_match!(match ty.kind() { } $($pattern)*)
957 }};
958}
959
960#[doc(hidden)]
961#[macro_export]
962macro_rules! __btf_type_match {
963 (
970 match $ty:ident.kind() { $($p:pat => $a:expr),* }
971 BtfKind::Composite $( ($var:ident) )? => $action:expr,
972 $($rest:tt)*
973 ) => {
974 $crate::__btf_type_match!(match $ty.kind() { $($p => $a,)* }
975 BtfKind::Composite $( ($var) )* => { $action }
976 $($rest)*
977 )
978 };
979 (
980 match $ty:ident.kind() { $($p:pat => $a:expr),* }
981 BtfKind::Composite $(($var:ident))? => $action:block
982 $($rest:tt)*
983 ) => {
984 $crate::__btf_type_match!(match $ty.kind() {
985 $($p => $a,)*
986 $crate::btf::BtfKind::Struct | $crate::btf::BtfKind::Union => {
987 $(let $var = $crate::btf::types::Composite::try_from($ty).unwrap();)*
988 $action
989 }
990 }
991 $($rest)*
992 )
993 };
994 (
996 match $ty:ident.kind() { $($p:pat => $a:expr),* }
997 BtfKind::$name:ident $(($var:ident))? => $action:expr,
998 $($rest:tt)*
999 ) => {
1000 $crate::__btf_type_match!(
1001 match $ty.kind() { $($p => $a),* }
1002 BtfKind::$name $(($var))? => { $action }
1003 $($rest)*
1004 )
1005 };
1006 (
1008 match $ty:ident.kind() { $($p:pat => $a:expr),* }
1009 BtfKind::$name:ident $(($var:ident))? => $action:block
1010 $($rest:tt)*
1011 ) => {
1012 $crate::__btf_type_match!(match $ty.kind() {
1013 $($p => $a,)*
1014 $crate::btf::BtfKind::$name => {
1015 $(let $var = $crate::btf::types::$name::try_from($ty).unwrap();)*
1016 $action
1017 }
1018 }
1019 $($rest)*
1020 )
1021 };
1022 (
1025 match $ty:ident.kind() { $($p:pat => $a:expr),* }
1026 $(BtfKind::$name:ident)|+ => $action:expr,
1027 $($rest:tt)*
1028 ) => {
1029 $crate::__btf_type_match!(
1030 match $ty.kind() { $($p => $a),* }
1031 $(BtfKind::$name)|* => { $action }
1032 $($rest)*
1033 )
1034 };
1035 (
1036 match $ty:ident.kind() { $($p:pat => $a:expr),* }
1037 $(BtfKind::$name:ident)|+ => $action:block
1038 $($rest:tt)*
1039 ) => {
1040 $crate::__btf_type_match!(match $ty.kind() {
1041 $($p => $a,)*
1042 $($crate::btf::BtfKind::$name)|* => {
1043 $action
1044 }
1045 }
1046 $($rest)*
1047 )
1048 };
1049 (
1054 match $ty:ident.kind() { $($p:pat => $a:expr),* }
1055 _ => $action:expr $(,)?
1056 ) => {
1057 $crate::__btf_type_match!(match $ty.kind() {
1058 $($p => $a,)*
1059 _ => { $action }
1060 }
1061
1062 )
1063 };
1064 (match $ty:ident.kind() { $($p:pat => $a:expr),* } ) => {
1066 match $ty.kind() {
1067 $($p => $a),*
1068 }
1069 }
1070}
1071
1072#[cfg(test)]
1073mod test {
1074 use super::*;
1075
1076 macro_rules! dummy_type {
1079 ($ty:ident) => {
1080 let btf = $crate::Btf {
1081 ptr: std::ptr::NonNull::dangling(),
1082 drop_policy: $crate::btf::DropPolicy::Nothing,
1083 _marker: std::marker::PhantomData,
1084 };
1085 let $ty = BtfType {
1086 type_id: $crate::btf::TypeId::from(1),
1087 name: None,
1088 source: &btf,
1089 ty: &libbpf_sys::btf_type::default(),
1090 };
1091 };
1092 }
1093
1094 fn foo(_: super::Int<'_>) -> &'static str {
1095 "int"
1096 }
1097
1098 #[test]
1099 fn full_switch_case() {
1100 dummy_type!(ty);
1101 btf_type_match!(match ty {
1102 BtfKind::Int(i) => foo(i),
1103 BtfKind::Struct => "it's a struct",
1104 BtfKind::Void => "",
1105 BtfKind::Ptr => "",
1106 BtfKind::Array => "",
1107 BtfKind::Union => "",
1108 BtfKind::Enum => "",
1109 BtfKind::Fwd => "",
1110 BtfKind::Typedef => "",
1111 BtfKind::Volatile => "",
1112 BtfKind::Const => "",
1113 BtfKind::Restrict => "",
1114 BtfKind::Func => "",
1115 BtfKind::FuncProto => "",
1116 BtfKind::Var => "",
1117 BtfKind::DataSec => "",
1118 BtfKind::Float => "",
1119 BtfKind::DeclTag => "",
1120 BtfKind::TypeTag => "",
1121 BtfKind::Enum64 => "",
1122 });
1123 }
1124
1125 #[test]
1126 fn partial_match() {
1127 dummy_type!(ty);
1128 btf_type_match!(match ty {
1129 BtfKind::Int => "int",
1130 _ => "default",
1131 });
1132 }
1133
1134 #[test]
1135 fn or_pattern_match() {
1136 dummy_type!(ty);
1137 #[rustfmt::skip]
1140 btf_type_match!(match ty {
1141 BtfKind::Int => "int",
1142 BtfKind::Struct | BtfKind::Union => "composite",
1143 BtfKind::Typedef | BtfKind::Volatile => {
1144 "qualifier"
1145 }
1146 BtfKind::Const | BtfKind::Restrict => {
1147 "const or restrict"
1148 },
1149 _ => "default",
1150 });
1151 }
1152
1153 #[test]
1154 fn match_arm_with_brackets() {
1155 dummy_type!(ty);
1156 #[rustfmt::skip]
1159 btf_type_match!(match ty {
1160 BtfKind::Void => {
1161 "void"
1162 }
1163 BtfKind::Int => {
1164 "int"
1165 },
1166 BtfKind::Struct => "struct",
1167 _ => "default",
1168 });
1169 }
1170
1171 #[test]
1172 fn match_on_composite() {
1173 dummy_type!(ty);
1174 btf_type_match!(match ty {
1175 BtfKind::Composite(c) => c.is_struct,
1176 _ => false,
1177 });
1178 btf_type_match!(match ty {
1179 BtfKind::Composite(c) => {
1180 c.is_struct
1181 }
1182 _ => false,
1183 });
1184 #[rustfmt::skip]
1187 btf_type_match!(match ty {
1188 BtfKind::Composite(c) => {
1189 c.is_struct
1190 },
1191 _ => false,
1192 });
1193 }
1194
1195 #[test]
1196 fn match_arm_with_multiple_statements() {
1197 dummy_type!(ty);
1198
1199 btf_type_match!(match ty {
1200 BtfKind::Int(i) => {
1201 let _ = i;
1202 "int"
1203 }
1204 _ => {
1205 let _ = 1;
1206 "default"
1207 }
1208 });
1209 }
1210
1211 #[test]
1212 fn non_expression_guards() {
1213 dummy_type!(ty);
1214
1215 btf_type_match!(match ty {
1216 BtfKind::Int => {
1217 let _ = 1;
1218 "int"
1219 }
1220 BtfKind::Typedef | BtfKind::Const => {
1221 let _ = 1;
1222 "qualifier"
1223 }
1224 _ => {
1225 let _ = 1;
1226 "default"
1227 }
1228 });
1229
1230 btf_type_match!(match ty {
1231 BtfKind::Int => {
1232 let _ = 1;
1233 }
1234 BtfKind::Typedef | BtfKind::Const => {
1235 let _ = 1;
1236 }
1237 _ => {
1238 let _ = 1;
1239 }
1240 });
1241 }
1242
1243 #[test]
1244 fn linkage_type() {
1245 use std::mem::discriminant;
1246 use Linkage::*;
1247
1248 for t in [Static, Global, Extern, Unknown] {
1249 assert_eq!(discriminant(&t), discriminant(&Linkage::from(t as u32)));
1251 }
1252 }
1253}