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
123
124
125
126
127
128
129
130
131
132
133
134
135
use crate::{BinaryReader, ComponentTypeRef, FromReader, Result, SectionLimited};

/// Represents the kind of an external items of a WebAssembly component.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum ComponentExternalKind {
    /// The external kind is a core module.
    Module,
    /// The external kind is a function.
    Func,
    /// The external kind is a value.
    Value,
    /// The external kind is a type.
    Type,
    /// The external kind is an instance.
    Instance,
    /// The external kind is a component.
    Component,
}

impl ComponentExternalKind {
    pub(crate) fn from_bytes(
        byte1: u8,
        byte2: Option<u8>,
        offset: usize,
    ) -> Result<ComponentExternalKind> {
        Ok(match byte1 {
            0x00 => match byte2.unwrap() {
                0x11 => ComponentExternalKind::Module,
                x => {
                    return Err(BinaryReader::invalid_leading_byte_error(
                        x,
                        "component external kind",
                        offset + 1,
                    ))
                }
            },
            0x01 => ComponentExternalKind::Func,
            0x02 => ComponentExternalKind::Value,
            0x03 => ComponentExternalKind::Type,
            0x04 => ComponentExternalKind::Component,
            0x05 => ComponentExternalKind::Instance,
            x => {
                return Err(BinaryReader::invalid_leading_byte_error(
                    x,
                    "component external kind",
                    offset,
                ))
            }
        })
    }

    /// Returns a simple string description of this kind.
    pub fn desc(&self) -> &'static str {
        use ComponentExternalKind::*;
        match self {
            Module => "module",
            Func => "func",
            Value => "value",
            Type => "type",
            Instance => "instance",
            Component => "component",
        }
    }
}

/// Represents an export in a WebAssembly component.
#[derive(Debug, Clone)]
pub struct ComponentExport<'a> {
    /// The name of the exported item.
    pub name: ComponentExportName<'a>,
    /// The kind of the export.
    pub kind: ComponentExternalKind,
    /// The index of the exported item.
    pub index: u32,
    /// An optionally specified type ascribed to this export.
    pub ty: Option<ComponentTypeRef>,
}

/// A reader for the export section of a WebAssembly component.
pub type ComponentExportSectionReader<'a> = SectionLimited<'a, ComponentExport<'a>>;

impl<'a> FromReader<'a> for ComponentExport<'a> {
    fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> {
        Ok(ComponentExport {
            name: reader.read()?,
            kind: reader.read()?,
            index: reader.read()?,
            ty: match reader.read_u8()? {
                0x00 => None,
                0x01 => Some(reader.read()?),
                other => {
                    return Err(BinaryReader::invalid_leading_byte_error(
                        other,
                        "optional component export type",
                        reader.original_position() - 1,
                    ))
                }
            },
        })
    }
}

impl<'a> FromReader<'a> for ComponentExternalKind {
    fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> {
        let offset = reader.original_position();
        let byte1 = reader.read_u8()?;
        let byte2 = if byte1 == 0x00 {
            Some(reader.read_u8()?)
        } else {
            None
        };

        ComponentExternalKind::from_bytes(byte1, byte2, offset)
    }
}

/// Represents the name of a component export.
#[derive(Debug, Copy, Clone)]
#[allow(missing_docs)]
pub struct ComponentExportName<'a>(pub &'a str);

impl<'a> FromReader<'a> for ComponentExportName<'a> {
    fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> {
        match reader.read_u8()? {
            0x00 => {}
            // Historically export names used a discriminator byte of 0x01 to
            // indicate an "interface" of the form `a:b/c` but nowadays that's
            // inferred from string syntax. Ignore 0-vs-1 to continue to parse
            // older binaries. Eventually this will go away.
            0x01 => {}
            x => return reader.invalid_leading_byte(x, "export name"),
        }
        Ok(ComponentExportName(reader.read_string()?))
    }
}