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
use super::*;

#[derive(Clone)]
pub struct Attribute(pub Row);

impl Attribute {
    pub fn name(&self) -> &'static str {
        if let AttributeType::MemberRef(method) = self.0.decode(1) {
            return method.parent().name();
        }

        unimplemented!();
    }

    pub fn args(&self) -> Vec<(String, ConstantValue)> {
        let reader = TypeReader::get();

        let (mut sig, mut values) = match self.0.decode(1) {
            AttributeType::MethodDef(method) => (method.0.blob(4), self.0.blob(2)),
            AttributeType::MemberRef(method) => (method.0.blob(2), self.0.blob(2)),
        };

        let _prolog = values.read_u16();
        let _this_and_gen_param_count = sig.read_unsigned();
        let fixed_arg_count = sig.read_unsigned();
        let _ret_type = sig.read_unsigned();

        let mut args: Vec<(String, ConstantValue)> = Vec::with_capacity(fixed_arg_count as usize);

        for _ in 0..fixed_arg_count {
            let arg = match reader.type_from_blob(&mut sig, None, &[]) {
                ElementType::I8 => ConstantValue::I8(values.read_i8()),
                ElementType::U8 => ConstantValue::U8(values.read_u8()),
                ElementType::I16 => ConstantValue::I16(values.read_i16()),
                ElementType::U16 => ConstantValue::U16(values.read_u16()),
                ElementType::I32 => ConstantValue::I32(values.read_i32()),
                ElementType::U32 => ConstantValue::U32(values.read_u32()),
                ElementType::I64 => ConstantValue::I64(values.read_i64()),
                ElementType::U64 => ConstantValue::U64(values.read_u64()),
                ElementType::String => ConstantValue::String(values.read_str().to_string()),
                ElementType::TypeName => {
                    let name = values.read_str();
                    ConstantValue::TypeDef(reader.expect_type_def(TypeName::parse(name)).clone())
                }
                ElementType::TypeDef(def) => match def.underlying_type() {
                    ElementType::I8 => ConstantValue::I8(values.read_i8()),
                    ElementType::U8 => ConstantValue::U8(values.read_u8()),
                    ElementType::I16 => ConstantValue::I16(values.read_i16()),
                    ElementType::U16 => ConstantValue::U16(values.read_u16()),
                    ElementType::I32 => ConstantValue::I32(values.read_i32()),
                    ElementType::U32 => ConstantValue::U32(values.read_u32()),
                    ElementType::I64 => ConstantValue::I64(values.read_i64()),
                    ElementType::U64 => ConstantValue::U64(values.read_u64()),
                    _ => unimplemented!(),
                },
                _ => unimplemented!(),
            };

            args.push((String::new(), arg));
        }

        let named_arg_count = values.read_u16();
        args.reserve(named_arg_count as usize);

        for _ in 0..named_arg_count {
            let _id = values.read_u8();
            let arg_type = values.read_u8();
            let name = values.read_str().to_string();
            let arg = match arg_type {
                0x02 => ConstantValue::Bool(values.read_u8() != 0),
                0x08 => ConstantValue::I32(values.read_i32()),
                0x09 => ConstantValue::U32(values.read_u32()),
                0x0E => ConstantValue::String(values.read_str().to_string()),
                0x50 => {
                    let name = values.read_str();
                    ConstantValue::TypeDef(reader.expect_type_def(TypeName::parse(name)).clone())
                }
                _ => unimplemented!(),
            };
            args.push((name, arg));
        }

        args
    }

    // Extracts the public type, if any, of a ComposableAttribute blob.
    pub fn composable_type(&self) -> Option<TypeDef> {
        let mut public = false;
        let mut def = None;

        // One of the arguments is a CompositionType enum and the Public variant
        // has a value of 2 as a signed 32-bit integer.

        for (_, arg) in self.args() {
            match arg {
                ConstantValue::I32(2) => public = true,
                ConstantValue::TypeDef(value) => def = Some(value),
                _ => {}
            }
        }

        if public {
            def
        } else {
            None
        }
    }
}