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
136
137
138
139
140
141
142
143
//! Utilities for parsing of artifacts from byte streams.

use crate::{
    artifact::{
        Artifact, ArtifactData, ArtifactLocal, ArtifactMemory, ArtifactNamedImport,
        CompiledFunctionBytes, InstantiatedGlobals, InstantiatedTable,
    },
    parse::*,
    types::{BlockType, FuncIndex, FunctionType, GlobalInit, Name, TypeIndex, ValueType},
};
use anyhow::bail;
use std::{collections::BTreeMap, io::Cursor};

impl<'a, Ctx: Copy> Parseable<'a, Ctx> for ArtifactLocal {
    fn parse(ctx: Ctx, cursor: &mut Cursor<&'a [u8]>) -> ParseResult<Self> {
        let multiplicity = cursor.next(ctx)?;
        let ty = cursor.next(ctx)?;
        Ok(ArtifactLocal {
            multiplicity,
            ty,
        })
    }
}

impl<'a, Ctx: Copy> Parseable<'a, Ctx> for ArtifactNamedImport {
    fn parse(ctx: Ctx, cursor: &mut Cursor<&'a [u8]>) -> ParseResult<Self> {
        let mod_name = cursor.next(ctx)?;
        let item_name = cursor.next(ctx)?;
        let ty = cursor.next(ctx)?;
        Ok(ArtifactNamedImport {
            mod_name,
            item_name,
            ty,
        })
    }
}

impl<'a, Ctx: Copy> Parseable<'a, Ctx> for InstantiatedGlobals {
    fn parse(ctx: Ctx, cursor: &mut Cursor<&'a [u8]>) -> ParseResult<Self> {
        let len = u32::parse(ctx, cursor)?;
        let mut inits = Vec::with_capacity(len as usize);
        for _ in 0..len {
            match Byte::parse(ctx, cursor)? {
                0 => {
                    inits.push(GlobalInit::I32(cursor.next(ctx)?));
                }
                1 => {
                    inits.push(GlobalInit::I64(cursor.next(ctx)?));
                }
                _ => bail!("Unsupported global init tag."),
            }
        }
        Ok(InstantiatedGlobals {
            inits,
        })
    }
}

impl<'a, Ctx: Copy> Parseable<'a, Ctx> for CompiledFunctionBytes<'a> {
    fn parse(ctx: Ctx, cursor: &mut Cursor<&'a [u8]>) -> ParseResult<Self> {
        let type_idx = TypeIndex::parse(ctx, cursor)?;
        let return_type = BlockType::parse(ctx, cursor)?;
        let params: &'a [ValueType] = cursor.next(ctx)?;
        let num_locals: u32 = cursor.next(ctx)?;
        let locals: Vec<ArtifactLocal> = cursor.next(ctx)?;
        let code = cursor.next(ctx)?;
        Ok(CompiledFunctionBytes {
            type_idx,
            return_type,
            params,
            num_locals,
            locals,
            code,
        })
    }
}

impl<'a, Ctx: Copy> Parseable<'a, Ctx> for InstantiatedTable {
    fn parse(ctx: Ctx, cursor: &mut Cursor<&'a [u8]>) -> ParseResult<Self> {
        let functions = cursor.next(ctx)?;
        Ok(InstantiatedTable {
            functions,
        })
    }
}

impl<'a, Ctx: Copy> Parseable<'a, Ctx> for ArtifactMemory {
    fn parse(ctx: Ctx, cursor: &mut Cursor<&'a [u8]>) -> ParseResult<Self> {
        let init_size = cursor.next(ctx)?;
        let max_size = cursor.next(ctx)?;
        let init = Vec::<ArtifactData>::parse(ctx, cursor)?;
        Ok(ArtifactMemory {
            init_size,
            max_size,
            init,
        })
    }
}

impl<'a, Ctx: Copy> Parseable<'a, Ctx> for ArtifactData {
    fn parse(ctx: Ctx, cursor: &mut Cursor<&'a [u8]>) -> ParseResult<Self> {
        let offset = cursor.next(ctx)?;
        let init = cursor.next(ctx)?;
        Ok(Self {
            offset,
            init,
        })
    }
}

/// NB: This implementation is only meant to be used on trusted sources.
/// It optimistically allocates memory, which could lead to problems if the
/// input is untrusted.
impl<'a, Ctx: Copy, I: Parseable<'a, Ctx>> Parseable<'a, Ctx>
    for Artifact<I, CompiledFunctionBytes<'a>>
{
    fn parse(ctx: Ctx, cursor: &mut Cursor<&'a [u8]>) -> ParseResult<Self> {
        let imports: Vec<I> = Vec::parse(ctx, cursor)?;
        let ty: Vec<FunctionType> = Vec::parse(ctx, cursor)?;
        let table = InstantiatedTable::parse(ctx, cursor)?;
        let memory = cursor.next(ctx)?;
        let global = InstantiatedGlobals::parse(ctx, cursor)?;
        let export_len = u32::parse(ctx, cursor)?;
        let mut export = BTreeMap::new();
        for _ in 0..export_len {
            let name = Name::parse(ctx, cursor)?;
            let idx = FuncIndex::parse(ctx, cursor)?;
            if export.insert(name, idx).is_some() {
                bail!("Duplicate names in export list. This should not happen in artifacts.")
            }
        }
        let code = Vec::parse(ctx, cursor)?;
        Ok(Artifact {
            imports,
            ty,
            table,
            memory,
            global,
            export,
            code,
        })
    }
}