Skip to main content

mono_rt/types/
type_kind.rs

1/// The type discriminant returned by `mono_type_get_type`, corresponding to `MonoTypeEnum` in the
2/// Mono source (`mono/metadata/metadata.h`).
3///
4/// Annotated with `#[non_exhaustive]` so that adding named variants in the future is not a
5/// breaking change. The `Other` variant covers any discriminant not yet named here.
6#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
7#[non_exhaustive]
8pub enum TypeKind {
9    /// `MONO_TYPE_END` (0x00) — internal sentinel.
10    End,
11    /// `MONO_TYPE_VOID` (0x01)
12    Void,
13    /// `MONO_TYPE_BOOLEAN` (0x02)
14    Boolean,
15    /// `MONO_TYPE_CHAR` (0x03)
16    Char,
17    /// `MONO_TYPE_I1` (0x04) — `sbyte`
18    I1,
19    /// `MONO_TYPE_U1` (0x05) — `byte`
20    U1,
21    /// `MONO_TYPE_I2` (0x06) — `short`
22    I2,
23    /// `MONO_TYPE_U2` (0x07) — `ushort`
24    U2,
25    /// `MONO_TYPE_I4` (0x08) — `int`
26    I4,
27    /// `MONO_TYPE_U4` (0x09) — `uint`
28    U4,
29    /// `MONO_TYPE_I8` (0x0a) — `long`
30    I8,
31    /// `MONO_TYPE_U8` (0x0b) — `ulong`
32    U8,
33    /// `MONO_TYPE_R4` (0x0c) — `float`
34    R4,
35    /// `MONO_TYPE_R8` (0x0d) — `double`
36    R8,
37    /// `MONO_TYPE_STRING` (0x0e)
38    String,
39    /// `MONO_TYPE_PTR` (0x0f) — unmanaged pointer
40    Ptr,
41    /// `MONO_TYPE_BYREF` (0x10) — by-reference parameter
42    ByRef,
43    /// `MONO_TYPE_VALUETYPE` (0x11) — value type / struct
44    ValueType,
45    /// `MONO_TYPE_CLASS` (0x12) — reference type
46    Class,
47    /// `MONO_TYPE_VAR` (0x13) — generic type parameter (`T`)
48    Var,
49    /// `MONO_TYPE_ARRAY` (0x14) — multi-dimensional array
50    Array,
51    /// `MONO_TYPE_GENERICINST` (0x15) — instantiated generic type
52    GenericInst,
53    /// `MONO_TYPE_TYPEDBYREF` (0x16) — `TypedReference`
54    TypedByRef,
55    /// `MONO_TYPE_I` (0x18) — `nint`
56    I,
57    /// `MONO_TYPE_U` (0x19) — `nuint`
58    U,
59    /// `MONO_TYPE_FNPTR` (0x1b) — function pointer
60    FnPtr,
61    /// `MONO_TYPE_OBJECT` (0x1c) — `System.Object`
62    Object,
63    /// `MONO_TYPE_SZARRAY` (0x1d) — single-dimension zero-based array (most C# arrays)
64    SzArray,
65    /// `MONO_TYPE_MVAR` (0x1e) — generic method parameter (`M`)
66    MVar,
67    /// Any discriminant not covered by the named variants above.
68    Other(u32),
69}
70
71#[allow(clippy::too_many_lines)]
72impl From<u32> for TypeKind {
73    fn from(v: u32) -> Self {
74        match v {
75            0x00 => Self::End,
76            0x01 => Self::Void,
77            0x02 => Self::Boolean,
78            0x03 => Self::Char,
79            0x04 => Self::I1,
80            0x05 => Self::U1,
81            0x06 => Self::I2,
82            0x07 => Self::U2,
83            0x08 => Self::I4,
84            0x09 => Self::U4,
85            0x0a => Self::I8,
86            0x0b => Self::U8,
87            0x0c => Self::R4,
88            0x0d => Self::R8,
89            0x0e => Self::String,
90            0x0f => Self::Ptr,
91            0x10 => Self::ByRef,
92            0x11 => Self::ValueType,
93            0x12 => Self::Class,
94            0x13 => Self::Var,
95            0x14 => Self::Array,
96            0x15 => Self::GenericInst,
97            0x16 => Self::TypedByRef,
98            0x18 => Self::I,
99            0x19 => Self::U,
100            0x1b => Self::FnPtr,
101            0x1c => Self::Object,
102            0x1d => Self::SzArray,
103            0x1e => Self::MVar,
104            other => Self::Other(other),
105        }
106    }
107}
108
109#[cfg(test)]
110mod tests {
111    use std::collections::HashSet;
112
113    use super::TypeKind;
114
115    fn check(cases: &[(u32, TypeKind)]) {
116        for &(raw, ref expected) in cases {
117            assert_eq!(TypeKind::from(raw), *expected, "discriminant 0x{raw:02x}");
118        }
119    }
120
121    #[test]
122    fn primitive_variants_map_correctly() {
123        check(&[
124            (0x00, TypeKind::End),
125            (0x01, TypeKind::Void),
126            (0x02, TypeKind::Boolean),
127            (0x03, TypeKind::Char),
128            (0x04, TypeKind::I1),
129            (0x05, TypeKind::U1),
130            (0x06, TypeKind::I2),
131            (0x07, TypeKind::U2),
132            (0x08, TypeKind::I4),
133            (0x09, TypeKind::U4),
134            (0x0a, TypeKind::I8),
135            (0x0b, TypeKind::U8),
136            (0x0c, TypeKind::R4),
137            (0x0d, TypeKind::R8),
138        ]);
139    }
140
141    #[test]
142    fn reference_and_generic_variants_map_correctly() {
143        check(&[
144            (0x0e, TypeKind::String),
145            (0x0f, TypeKind::Ptr),
146            (0x10, TypeKind::ByRef),
147            (0x11, TypeKind::ValueType),
148            (0x12, TypeKind::Class),
149            (0x13, TypeKind::Var),
150            (0x14, TypeKind::Array),
151            (0x15, TypeKind::GenericInst),
152            (0x16, TypeKind::TypedByRef),
153            (0x18, TypeKind::I),
154            (0x19, TypeKind::U),
155            (0x1b, TypeKind::FnPtr),
156            (0x1c, TypeKind::Object),
157            (0x1d, TypeKind::SzArray),
158            (0x1e, TypeKind::MVar),
159        ]);
160    }
161
162    #[test]
163    fn gap_discriminants_produce_other() {
164        // 0x17 and 0x1a are intentional gaps in the MONO_TYPE_* numbering
165        assert_eq!(TypeKind::from(0x17), TypeKind::Other(0x17));
166        assert_eq!(TypeKind::from(0x1a), TypeKind::Other(0x1a));
167    }
168
169    #[test]
170    fn high_discriminant_produces_other() {
171        assert_eq!(TypeKind::from(0xFF), TypeKind::Other(0xFF));
172        assert_eq!(TypeKind::from(100), TypeKind::Other(100));
173    }
174
175    #[test]
176    fn other_variants_equality_uses_inner_value() {
177        assert_eq!(TypeKind::Other(7), TypeKind::Other(7));
178        assert_ne!(TypeKind::Other(7), TypeKind::Other(8));
179    }
180
181    #[test]
182    fn type_kind_is_hashable() {
183        let mut set = HashSet::new();
184        set.insert(TypeKind::I4);
185        set.insert(TypeKind::I4);
186        set.insert(TypeKind::U4);
187        assert_eq!(set.len(), 2);
188    }
189
190    #[test]
191    fn type_kind_is_copy() {
192        let a = TypeKind::Boolean;
193        let b = a;
194        // both are usable after copy
195        assert_eq!(a, b);
196    }
197
198    #[test]
199    fn type_kind_debug_contains_variant_name() {
200        assert!(format!("{:?}", TypeKind::I4).contains("I4"));
201        assert!(format!("{:?}", TypeKind::Other(99)).contains("Other"));
202    }
203}