1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
/*!
Learn more about Rust for Windows here: <https://github.com/microsoft/windows-rs>
*/

#![doc(hidden)]

use std::cmp::Ordering;
use std::collections::*;

mod attributes;
mod bindings;
mod blob;
mod codes;
mod column;
mod file;
mod filter;
mod reader;
mod row;
mod table;
mod tables;
mod r#type;
mod type_name;

pub use attributes::*;
pub use bindings::*;
pub use blob::*;
pub use codes::*;
use column::*;
pub use file::*;
use filter::*;
pub use r#type::*;
pub use reader::*;
pub use row::*;
use table::*;
pub use tables::*;
pub use type_name::*;

#[repr(C)]
#[derive(Default)]
pub struct METADATA_HEADER {
    pub signature: u32,
    pub major_version: u16,
    pub minor_version: u16,
    pub reserved: u32,
    pub length: u32,
    pub version: [u8; 20],
    pub flags: u16,
    pub streams: u16,
}

pub const METADATA_SIGNATURE: u32 = 0x424A_5342;

/// A coded index (see codes.rs) is a table index that may refer to different tables. The size of the column in memory
/// must therefore be large enough to hold an index for a row in the largest possible table. This function determines
/// this size for the given winmd file.
pub fn coded_index_size(tables: &[usize]) -> usize {
    fn small(row_count: usize, bits: u8) -> bool {
        (row_count as u64) < (1u64 << (16 - bits))
    }

    fn bits_needed(value: usize) -> u8 {
        let mut value = value - 1;
        let mut bits: u8 = 1;
        while {
            value >>= 1;
            value != 0
        } {
            bits += 1;
        }
        bits
    }

    let bits_needed = bits_needed(tables.len());

    if tables.iter().all(|table| small(*table, bits_needed)) {
        2
    } else {
        4
    }
}

#[derive(Debug)]
pub enum Value {
    Bool(bool),
    U8(u8),
    I8(i8),
    U16(u16),
    I16(i16),
    U32(u32),
    I32(i32),
    U64(u64),
    I64(i64),
    F32(f32),
    F64(f64),
    String(String),
    TypeName(TypeName),
    EnumDef(TypeDef, Box<Self>),
}

#[derive(Debug)]
pub struct MethodDefSig {
    pub call_flags: MethodCallAttributes,
    pub return_type: Type,
    pub params: Vec<Type>,
}

impl MethodDefSig {
    pub fn size(&self) -> usize {
        self.params
            .iter()
            .fold(0, |sum, param| sum + std::cmp::max(4, param.size()))
    }
}

#[derive(Copy, Clone, PartialEq, Eq, Debug, PartialOrd, Ord)]
pub enum TypeKind {
    Interface,
    Class,
    Enum,
    Struct,
    Delegate,
}