Coverage Report

Created: 2024-11-19 11:03

/build/cargo-vendor-dir/wasm-encoder-0.200.0/src/component/imports.rs
Line
Count
Source (jump to first uncovered line)
1
use crate::{
2
    encode_section, ComponentExportKind, ComponentSection, ComponentSectionId, ComponentValType,
3
    Encode,
4
};
5
6
/// Represents the possible type bounds for type references.
7
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
8
pub enum TypeBounds {
9
    /// The type is bounded by equality to the type index specified.
10
    Eq(u32),
11
    /// This type is a fresh resource type,
12
    SubResource,
13
}
14
15
impl Encode for TypeBounds {
16
0
    fn encode(&self, sink: &mut Vec<u8>) {
17
0
        match self {
18
0
            Self::Eq(i) => {
19
0
                sink.push(0x00);
20
0
                i.encode(sink);
21
0
            }
22
0
            Self::SubResource => sink.push(0x01),
23
        }
24
0
    }
25
}
26
27
/// Represents a reference to a type.
28
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
29
pub enum ComponentTypeRef {
30
    /// The reference is to a core module type.
31
    ///
32
    /// The index is expected to be core type index to a core module type.
33
    Module(u32),
34
    /// The reference is to a function type.
35
    ///
36
    /// The index is expected to be a type index to a function type.
37
    Func(u32),
38
    /// The reference is to a value type.
39
    Value(ComponentValType),
40
    /// The reference is to a bounded type.
41
    Type(TypeBounds),
42
    /// The reference is to an instance type.
43
    ///
44
    /// The index is expected to be a type index to an instance type.
45
    Instance(u32),
46
    /// The reference is to a component type.
47
    ///
48
    /// The index is expected to be a type index to a component type.
49
    Component(u32),
50
}
51
52
impl ComponentTypeRef {
53
    /// Gets the export kind of the reference.
54
0
    pub fn kind(&self) -> ComponentExportKind {
55
0
        match self {
56
0
            Self::Module(_) => ComponentExportKind::Module,
57
0
            Self::Func(_) => ComponentExportKind::Func,
58
0
            Self::Value(_) => ComponentExportKind::Value,
59
0
            Self::Type(..) => ComponentExportKind::Type,
60
0
            Self::Instance(_) => ComponentExportKind::Instance,
61
0
            Self::Component(_) => ComponentExportKind::Component,
62
        }
63
0
    }
64
}
65
66
impl Encode for ComponentTypeRef {
67
0
    fn encode(&self, sink: &mut Vec<u8>) {
68
0
        self.kind().encode(sink);
69
0
70
0
        match self {
71
0
            Self::Module(idx) | Self::Func(idx) | Self::Instance(idx) | Self::Component(idx) => {
72
0
                idx.encode(sink);
73
0
            }
74
0
            Self::Value(ty) => ty.encode(sink),
75
0
            Self::Type(bounds) => bounds.encode(sink),
76
        }
77
0
    }
78
}
79
80
/// An encoder for the import section of WebAssembly components.
81
///
82
/// # Example
83
///
84
/// ```rust
85
/// use wasm_encoder::{Component, ComponentTypeSection, PrimitiveValType, ComponentImportSection, ComponentTypeRef};
86
///
87
/// let mut types = ComponentTypeSection::new();
88
///
89
/// // Define a function type of `[string, string] -> string`.
90
/// types
91
///   .function()
92
///   .params(
93
///     [
94
///       ("a", PrimitiveValType::String),
95
///       ("b", PrimitiveValType::String)
96
///     ]
97
///   )
98
///   .result(PrimitiveValType::String);
99
///
100
/// // This imports a function named `f` with the type defined above
101
/// let mut imports = ComponentImportSection::new();
102
/// imports.import("f", ComponentTypeRef::Func(0));
103
///
104
/// let mut component = Component::new();
105
/// component.section(&types);
106
/// component.section(&imports);
107
///
108
/// let bytes = component.finish();
109
/// ```
110
#[derive(Clone, Debug, Default)]
111
pub struct ComponentImportSection {
112
    bytes: Vec<u8>,
113
    num_added: u32,
114
}
115
116
impl ComponentImportSection {
117
    /// Create a new component import section encoder.
118
0
    pub fn new() -> Self {
119
0
        Self::default()
120
0
    }
121
122
    /// The number of imports in the section.
123
0
    pub fn len(&self) -> u32 {
124
0
        self.num_added
125
0
    }
126
127
    /// Determines if the section is empty.
128
0
    pub fn is_empty(&self) -> bool {
129
0
        self.num_added == 0
130
0
    }
131
132
    /// Define an import in the component import section.
133
0
    pub fn import(&mut self, name: &str, ty: ComponentTypeRef) -> &mut Self {
134
0
        push_extern_name_byte(&mut self.bytes, name);
135
0
        name.encode(&mut self.bytes);
136
0
        ty.encode(&mut self.bytes);
137
0
        self.num_added += 1;
138
0
        self
139
0
    }
140
}
141
142
impl Encode for ComponentImportSection {
143
0
    fn encode(&self, sink: &mut Vec<u8>) {
144
0
        encode_section(sink, self.num_added, &self.bytes);
145
0
    }
146
}
147
148
impl ComponentSection for ComponentImportSection {
149
0
    fn id(&self) -> u8 {
150
0
        ComponentSectionId::Import.into()
151
0
    }
152
}
153
154
/// Prior to WebAssembly/component-model#263 import and export names were
155
/// discriminated with a leading byte indicating what kind of import they are.
156
/// After that PR though names are always prefixed with a 0x00 byte.
157
///
158
/// This function is a compatibility shim for the time being while this change
159
/// is being rolled out. That PR is technically a spec-breaking change relative
160
/// to prior but we want old tooling to continue to work with new modules. To
161
/// handle that names that look like IDs, `a:b/c`, get an 0x01 prefix instead of
162
/// the spec-defined 0x00 prefix. That makes components produced by current
163
/// versions of this crate compatible with older parsers.
164
///
165
/// Note that wasmparser has a similar case where it parses either 0x01 or 0x00.
166
/// That means that the selection of a byte here doesn't actually matter for
167
/// wasmparser's own validation. Eventually this will go away and an 0x00 byte
168
/// will always be emitted to align with the spec.
169
0
pub(crate) fn push_extern_name_byte(bytes: &mut Vec<u8>, name: &str) {
170
0
    if name.contains(':') {
171
0
        bytes.push(0x01);
172
0
    } else {
173
0
        bytes.push(0x00);
174
0
    }
175
0
}