1use super::{
4 check_max, combine_type_sizes,
5 core::Module,
6 types::{
7 ComponentFuncType, ComponentInstanceType, ComponentInstanceTypeKind, ComponentType,
8 ComponentValType, EntityType, InstanceType, KebabString, ModuleType, RecordType, Type,
9 TypeAlloc, TypeId, TypeList, VariantCase,
10 },
11};
12use crate::{
13 limits::*,
14 types::{
15 ComponentDefinedType, ComponentEntityType, InstanceTypeKind, KebabStr, LoweringInfo,
16 TupleType, UnionType, VariantType,
17 },
18 BinaryReaderError, CanonicalOption, ComponentExternalKind, ComponentOuterAliasKind,
19 ComponentTypeRef, ExternalKind, FuncType, GlobalType, InstantiationArgKind, MemoryType, Result,
20 TableType, TypeBounds, ValType, WasmFeatures,
21};
22use indexmap::{map::Entry, IndexMap, IndexSet};
23use std::{collections::HashSet, mem};
24use url::Url;
25
26fn to_kebab_str<'a>(s: &'a str, desc: &str, offset: usize) -> Result<&'a KebabStr> {
27 match KebabStr::new(s) {
28 Some(s) => Ok(s),
29 None => {
30 if s.is_empty() {
31 bail!(offset, "{desc} name cannot be empty");
32 }
33
34 bail!(offset, "{desc} name `{s}` is not in kebab case");
35 }
36 }
37}
38
39fn parse_url(url: &str, offset: usize) -> Result<Option<Url>> {
40 if url.is_empty() {
41 return Ok(None);
42 }
43
44 Url::parse(url)
45 .map(Some)
46 .map_err(|e| BinaryReaderError::new(e.to_string(), offset))
47}
48
49pub(crate) struct ComponentState {
50 pub core_types: Vec<TypeId>,
52 pub core_modules: Vec<TypeId>,
53 pub core_instances: Vec<TypeId>,
54 pub core_funcs: Vec<TypeId>,
55 pub core_memories: Vec<MemoryType>,
56 pub core_tables: Vec<TableType>,
57 pub core_globals: Vec<GlobalType>,
58 pub core_tags: Vec<TypeId>,
59
60 pub types: Vec<TypeId>,
62 pub funcs: Vec<TypeId>,
63 pub values: Vec<(ComponentValType, bool)>,
64 pub instances: Vec<TypeId>,
65 pub components: Vec<TypeId>,
66
67 pub externs: IndexMap<KebabString, (Option<Url>, ComponentEntityType, ExternKind)>,
69
70 import_urls: HashSet<String>,
73 export_urls: HashSet<String>,
74
75 has_start: bool,
76 type_size: u32,
77}
78
79pub enum ExternKind {
80 Import,
81 Export,
82}
83
84impl ExternKind {
85 fn desc(&self) -> &'static str {
86 match self {
87 ExternKind::Import => "import",
88 ExternKind::Export => "export",
89 }
90 }
91}
92
93impl ComponentState {
94 pub fn type_count(&self) -> usize {
95 self.core_types.len() + self.types.len()
96 }
97
98 pub fn instance_count(&self) -> usize {
99 self.core_instances.len() + self.instances.len()
100 }
101
102 pub fn function_count(&self) -> usize {
103 self.core_funcs.len() + self.funcs.len()
104 }
105
106 pub fn add_core_type(
107 components: &mut [Self],
108 ty: crate::CoreType,
109 features: &WasmFeatures,
110 types: &mut TypeAlloc,
111 offset: usize,
112 check_limit: bool,
113 ) -> Result<()> {
114 let ty = match ty {
115 crate::CoreType::Func(ty) => Type::Func(ty),
116 crate::CoreType::Module(decls) => Type::Module(Self::create_module_type(
117 components,
118 decls.into_vec(),
119 features,
120 types,
121 offset,
122 )?),
123 };
124
125 let current = components.last_mut().unwrap();
126
127 if check_limit {
128 check_max(current.type_count(), 1, MAX_WASM_TYPES, "types", offset)?;
129 }
130
131 let id = types.push_defined(ty);
132 current.core_types.push(id);
133
134 Ok(())
135 }
136
137 pub fn add_core_module(
138 &mut self,
139 module: &Module,
140 types: &mut TypeAlloc,
141 offset: usize,
142 ) -> Result<()> {
143 let imports = module.imports_for_module_type(offset)?;
144
145 let ty = Type::Module(ModuleType {
149 type_size: module.type_size,
150 imports,
151 exports: module.exports.clone(),
152 });
153
154 let id = types.push_anon(ty);
155 self.core_modules.push(id);
156
157 Ok(())
158 }
159
160 pub fn add_core_instance(
161 &mut self,
162 instance: crate::Instance,
163 types: &mut TypeAlloc,
164 offset: usize,
165 ) -> Result<()> {
166 let instance = match instance {
167 crate::Instance::Instantiate { module_index, args } => {
168 self.instantiate_module(module_index, args.into_vec(), types, offset)?
169 }
170 crate::Instance::FromExports(exports) => {
171 self.instantiate_core_exports(exports.into_vec(), types, offset)?
172 }
173 };
174
175 self.core_instances.push(instance);
176
177 Ok(())
178 }
179
180 pub fn add_type(
181 components: &mut Vec<Self>,
182 ty: crate::ComponentType,
183 features: &WasmFeatures,
184 types: &mut TypeAlloc,
185 offset: usize,
186 check_limit: bool,
187 ) -> Result<()> {
188 assert!(!components.is_empty());
189 let ty = match ty {
190 crate::ComponentType::Defined(ty) => Type::Defined(
191 components
192 .last_mut()
193 .unwrap()
194 .create_defined_type(ty, types, offset)?,
195 ),
196 crate::ComponentType::Func(ty) => Type::ComponentFunc(
197 components
198 .last_mut()
199 .unwrap()
200 .create_function_type(ty, types, offset)?,
201 ),
202 crate::ComponentType::Component(decls) => Type::Component(Self::create_component_type(
203 components,
204 decls.into_vec(),
205 features,
206 types,
207 offset,
208 )?),
209 crate::ComponentType::Instance(decls) => Type::ComponentInstance(
210 Self::create_instance_type(components, decls.into_vec(), features, types, offset)?,
211 ),
212 };
213
214 let current = components.last_mut().unwrap();
215 if check_limit {
216 check_max(current.type_count(), 1, MAX_WASM_TYPES, "types", offset)?;
217 }
218
219 let id = types.push_defined(ty);
220 current.types.push(id);
221
222 Ok(())
223 }
224
225 pub fn add_import(
226 &mut self,
227 import: crate::ComponentImport,
228 types: &mut TypeAlloc,
229 offset: usize,
230 ) -> Result<()> {
231 let entity = self.check_type_ref(&import.ty, types, offset)?;
232 self.add_entity(entity, false, offset)?;
233 let name = to_kebab_str(import.name, "import", offset)?;
234
235 match self.externs.entry(name.to_owned()) {
236 Entry::Occupied(e) => {
237 bail!(
238 offset,
239 "import name `{name}` conflicts with previous {desc} name `{prev}`",
240 name = import.name,
241 prev = e.key(),
242 desc = e.get().2.desc(),
243 );
244 }
245 Entry::Vacant(e) => {
246 let url = parse_url(import.url, offset)?;
247 if let Some(url) = url.as_ref() {
248 if !self.import_urls.insert(url.to_string()) {
249 bail!(offset, "duplicate import URL `{url}`");
250 }
251 }
252
253 self.type_size = combine_type_sizes(self.type_size, entity.type_size(), offset)?;
254 e.insert((url, entity, ExternKind::Import));
255 }
256 }
257
258 Ok(())
259 }
260
261 fn add_entity(
262 &mut self,
263 ty: ComponentEntityType,
264 value_used: bool,
265 offset: usize,
266 ) -> Result<()> {
267 let (len, max, desc) = match ty {
268 ComponentEntityType::Module(id) => {
269 self.core_modules.push(id);
270 (self.core_modules.len(), MAX_WASM_MODULES, "modules")
271 }
272 ComponentEntityType::Component(id) => {
273 self.components.push(id);
274 (self.components.len(), MAX_WASM_COMPONENTS, "components")
275 }
276 ComponentEntityType::Instance(id) => {
277 self.instances.push(id);
278 (self.instance_count(), MAX_WASM_INSTANCES, "instances")
279 }
280 ComponentEntityType::Func(id) => {
281 self.funcs.push(id);
282 (self.function_count(), MAX_WASM_FUNCTIONS, "functions")
283 }
284 ComponentEntityType::Value(ty) => {
285 self.values.push((ty, value_used));
286 (self.values.len(), MAX_WASM_VALUES, "values")
287 }
288 ComponentEntityType::Type { created, .. } => {
289 self.types.push(created);
290 (self.types.len(), MAX_WASM_TYPES, "types")
291 }
292 };
293
294 check_max(len, 0, max, desc, offset)?;
295 Ok(())
296 }
297
298 pub fn add_export(
299 &mut self,
300 name: &str,
301 url: &str,
302 ty: ComponentEntityType,
303 offset: usize,
304 check_limit: bool,
305 ) -> Result<()> {
306 if check_limit {
307 check_max(
308 self.externs.len(),
309 1,
310 MAX_WASM_EXPORTS,
311 "imports and exports",
312 offset,
313 )?;
314 }
315 self.add_entity(ty, true, offset)?;
316
317 let name = to_kebab_str(name, "export", offset)?;
318
319 match self.externs.entry(name.to_owned()) {
320 Entry::Occupied(e) => {
321 bail!(
322 offset,
323 "export name `{name}` conflicts with previous {desc} name `{prev}`",
324 prev = e.key(),
325 desc = e.get().2.desc(),
326 );
327 }
328 Entry::Vacant(e) => {
329 let url = parse_url(url, offset)?;
330 if let Some(url) = url.as_ref() {
331 if !self.export_urls.insert(url.to_string()) {
332 bail!(offset, "duplicate export URL `{url}`");
333 }
334 }
335
336 self.type_size = combine_type_sizes(self.type_size, ty.type_size(), offset)?;
337 e.insert((url, ty, ExternKind::Export));
338 }
339 }
340
341 Ok(())
342 }
343
344 pub fn lift_function(
345 &mut self,
346 core_func_index: u32,
347 type_index: u32,
348 options: Vec<CanonicalOption>,
349 types: &TypeList,
350 offset: usize,
351 ) -> Result<()> {
352 let ty = self.function_type_at(type_index, types, offset)?;
353 let core_ty = types[self.core_function_at(core_func_index, offset)?]
354 .as_func_type()
355 .unwrap();
356
357 let info = ty.lower(types, false);
360 self.check_options(Some(core_ty), &info, &options, types, offset)?;
361
362 if core_ty.params() != info.params.as_slice() {
363 bail!(
364 offset,
365 "lowered parameter types `{:?}` do not match parameter types \
366 `{:?}` of core function {core_func_index}",
367 info.params.as_slice(),
368 core_ty.params(),
369 );
370 }
371
372 if core_ty.results() != info.results.as_slice() {
373 bail!(
374 offset,
375 "lowered result types `{:?}` do not match result types \
376 `{:?}` of core function {core_func_index}",
377 info.results.as_slice(),
378 core_ty.results()
379 );
380 }
381
382 self.funcs.push(self.types[type_index as usize]);
383
384 Ok(())
385 }
386
387 pub fn lower_function(
388 &mut self,
389 func_index: u32,
390 options: Vec<CanonicalOption>,
391 types: &mut TypeAlloc,
392 offset: usize,
393 ) -> Result<()> {
394 let ty = types[self.function_at(func_index, offset)?]
395 .as_component_func_type()
396 .unwrap();
397
398 let info = ty.lower(types, true);
401
402 self.check_options(None, &info, &options, types, offset)?;
403
404 let lowered_ty = Type::Func(info.into_func_type());
405
406 let id = types.push_anon(lowered_ty);
407 self.core_funcs.push(id);
408
409 Ok(())
410 }
411
412 pub fn add_component(&mut self, component: &mut Self, types: &mut TypeAlloc) {
413 let ty = Type::Component(component.take_component_type());
414 let id = types.push_anon(ty);
415 self.components.push(id);
416 }
417
418 pub fn add_instance(
419 &mut self,
420 instance: crate::ComponentInstance,
421 types: &mut TypeAlloc,
422 offset: usize,
423 ) -> Result<()> {
424 let instance = match instance {
425 crate::ComponentInstance::Instantiate {
426 component_index,
427 args,
428 } => self.instantiate_component(component_index, args.into_vec(), types, offset)?,
429 crate::ComponentInstance::FromExports(exports) => {
430 self.instantiate_exports(exports.into_vec(), types, offset)?
431 }
432 };
433
434 self.instances.push(instance);
435
436 Ok(())
437 }
438
439 pub fn add_alias(
440 components: &mut [Self],
441 alias: crate::ComponentAlias,
442 types: &mut TypeAlloc,
443 offset: usize,
444 ) -> Result<()> {
445 match alias {
446 crate::ComponentAlias::InstanceExport {
447 instance_index,
448 kind,
449 name,
450 } => components.last_mut().unwrap().alias_instance_export(
451 instance_index,
452 kind,
453 name,
454 types,
455 offset,
456 ),
457 crate::ComponentAlias::CoreInstanceExport {
458 instance_index,
459 kind,
460 name,
461 } => components.last_mut().unwrap().alias_core_instance_export(
462 instance_index,
463 kind,
464 name,
465 types,
466 offset,
467 ),
468 crate::ComponentAlias::Outer { kind, count, index } => match kind {
469 ComponentOuterAliasKind::CoreModule => {
470 Self::alias_module(components, count, index, offset)
471 }
472 ComponentOuterAliasKind::CoreType => {
473 Self::alias_core_type(components, count, index, types, offset)
474 }
475 ComponentOuterAliasKind::Type => {
476 Self::alias_type(components, count, index, types, offset)
477 }
478 ComponentOuterAliasKind::Component => {
479 Self::alias_component(components, count, index, offset)
480 }
481 },
482 }
483 }
484
485 pub fn add_start(
486 &mut self,
487 func_index: u32,
488 args: &[u32],
489 results: u32,
490 types: &TypeList,
491 offset: usize,
492 ) -> Result<()> {
493 if self.has_start {
494 return Err(BinaryReaderError::new(
495 "component cannot have more than one start function",
496 offset,
497 ));
498 }
499
500 let ft = types[self.function_at(func_index, offset)?]
501 .as_component_func_type()
502 .unwrap();
503
504 if ft.params.len() != args.len() {
505 bail!(
506 offset,
507 "component start function requires {} arguments but was given {}",
508 ft.params.len(),
509 args.len()
510 );
511 }
512
513 if ft.results.len() as u32 != results {
514 bail!(
515 offset,
516 "component start function has a result count of {results} \
517 but the function type has a result count of {type_results}",
518 type_results = ft.results.len(),
519 );
520 }
521
522 for (i, ((_, ty), arg)) in ft.params.iter().zip(args).enumerate() {
523 if !ComponentValType::internal_is_subtype_of(
525 self.value_at(*arg, offset)?,
526 types,
527 ty,
528 types,
529 ) {
530 bail!(
531 offset,
532 "value type mismatch for component start function argument {i}"
533 );
534 }
535 }
536
537 for (_, ty) in ft.results.iter() {
538 self.values.push((*ty, false));
539 }
540
541 self.has_start = true;
542
543 Ok(())
544 }
545
546 fn check_options(
547 &self,
548 core_ty: Option<&FuncType>,
549 info: &LoweringInfo,
550 options: &[CanonicalOption],
551 types: &TypeList,
552 offset: usize,
553 ) -> Result<()> {
554 fn display(option: CanonicalOption) -> &'static str {
555 match option {
556 CanonicalOption::UTF8 => "utf8",
557 CanonicalOption::UTF16 => "utf16",
558 CanonicalOption::CompactUTF16 => "latin1-utf16",
559 CanonicalOption::Memory(_) => "memory",
560 CanonicalOption::Realloc(_) => "realloc",
561 CanonicalOption::PostReturn(_) => "post-return",
562 }
563 }
564
565 let mut encoding = None;
566 let mut memory = None;
567 let mut realloc = None;
568 let mut post_return = None;
569
570 for option in options {
571 match option {
572 CanonicalOption::UTF8 | CanonicalOption::UTF16 | CanonicalOption::CompactUTF16 => {
573 match encoding {
574 Some(existing) => {
575 bail!(
576 offset,
577 "canonical encoding option `{}` conflicts with option `{}`",
578 display(existing),
579 display(*option),
580 )
581 }
582 None => encoding = Some(*option),
583 }
584 }
585 CanonicalOption::Memory(idx) => {
586 memory = match memory {
587 None => {
588 self.memory_at(*idx, offset)?;
589 Some(*idx)
590 }
591 Some(_) => {
592 return Err(BinaryReaderError::new(
593 "canonical option `memory` is specified more than once",
594 offset,
595 ))
596 }
597 }
598 }
599 CanonicalOption::Realloc(idx) => {
600 realloc = match realloc {
601 None => {
602 let ty = types[self.core_function_at(*idx, offset)?]
603 .as_func_type()
604 .unwrap();
605 if ty.params()
606 != [ValType::I32, ValType::I32, ValType::I32, ValType::I32]
607 || ty.results() != [ValType::I32]
608 {
609 return Err(BinaryReaderError::new(
610 "canonical option `realloc` uses a core function with an incorrect signature",
611 offset,
612 ));
613 }
614 Some(*idx)
615 }
616 Some(_) => {
617 return Err(BinaryReaderError::new(
618 "canonical option `realloc` is specified more than once",
619 offset,
620 ))
621 }
622 }
623 }
624 CanonicalOption::PostReturn(idx) => {
625 post_return = match post_return {
626 None => {
627 let core_ty = core_ty.ok_or_else(|| {
628 BinaryReaderError::new(
629 "canonical option `post-return` cannot be specified for lowerings",
630 offset,
631 )
632 })?;
633
634 let ty = types[self.core_function_at(*idx, offset)?]
635 .as_func_type()
636 .unwrap();
637
638 if ty.params() != core_ty.results() || !ty.results().is_empty() {
639 return Err(BinaryReaderError::new(
640 "canonical option `post-return` uses a core function with an incorrect signature",
641 offset,
642 ));
643 }
644 Some(*idx)
645 }
646 Some(_) => {
647 return Err(BinaryReaderError::new(
648 "canonical option `post-return` is specified more than once",
649 offset,
650 ))
651 }
652 }
653 }
654 }
655 }
656
657 if info.requires_memory && memory.is_none() {
658 return Err(BinaryReaderError::new(
659 "canonical option `memory` is required",
660 offset,
661 ));
662 }
663
664 if info.requires_realloc && realloc.is_none() {
665 return Err(BinaryReaderError::new(
666 "canonical option `realloc` is required",
667 offset,
668 ));
669 }
670
671 Ok(())
672 }
673
674 fn check_type_ref(
675 &self,
676 ty: &ComponentTypeRef,
677 types: &mut TypeAlloc,
678 offset: usize,
679 ) -> Result<ComponentEntityType> {
680 Ok(match ty {
681 ComponentTypeRef::Module(index) => {
682 let id = self.type_at(*index, true, offset)?;
683 types[id].as_module_type().ok_or_else(|| {
684 format_err!(offset, "core type index {index} is not a module type")
685 })?;
686 ComponentEntityType::Module(id)
687 }
688 ComponentTypeRef::Func(index) => {
689 let id = self.type_at(*index, false, offset)?;
690 types[id].as_component_func_type().ok_or_else(|| {
691 format_err!(offset, "type index {index} is not a function type")
692 })?;
693 ComponentEntityType::Func(id)
694 }
695 ComponentTypeRef::Value(ty) => {
696 let ty = match ty {
697 crate::ComponentValType::Primitive(ty) => ComponentValType::Primitive(*ty),
698 crate::ComponentValType::Type(index) => {
699 ComponentValType::Type(self.defined_type_at(*index, types, offset)?)
700 }
701 };
702 ComponentEntityType::Value(ty)
703 }
704 ComponentTypeRef::Type(TypeBounds::Eq, index) => {
705 let referenced = self.type_at(*index, false, offset)?;
706 let created = types.with_unique(referenced);
707 ComponentEntityType::Type {
708 referenced,
709 created,
710 }
711 }
712 ComponentTypeRef::Instance(index) => {
713 let id = self.type_at(*index, false, offset)?;
714 types[id].as_component_instance_type().ok_or_else(|| {
715 format_err!(offset, "type index {index} is not an instance type")
716 })?;
717 ComponentEntityType::Instance(id)
718 }
719 ComponentTypeRef::Component(index) => {
720 let id = self.type_at(*index, false, offset)?;
721 types[id].as_component_type().ok_or_else(|| {
722 format_err!(offset, "type index {index} is not a component type")
723 })?;
724 ComponentEntityType::Component(id)
725 }
726 })
727 }
728
729 pub fn export_to_entity_type(
730 &mut self,
731 export: &crate::ComponentExport,
732 types: &mut TypeAlloc,
733 offset: usize,
734 ) -> Result<ComponentEntityType> {
735 let actual = match export.kind {
736 ComponentExternalKind::Module => {
737 ComponentEntityType::Module(self.module_at(export.index, offset)?)
738 }
739 ComponentExternalKind::Func => {
740 ComponentEntityType::Func(self.function_at(export.index, offset)?)
741 }
742 ComponentExternalKind::Value => {
743 ComponentEntityType::Value(*self.value_at(export.index, offset)?)
744 }
745 ComponentExternalKind::Type => {
746 let referenced = self.type_at(export.index, false, offset)?;
747 let created = types.with_unique(referenced);
748 ComponentEntityType::Type {
749 referenced,
750 created,
751 }
752 }
753 ComponentExternalKind::Instance => {
754 ComponentEntityType::Instance(self.instance_at(export.index, offset)?)
755 }
756 ComponentExternalKind::Component => {
757 ComponentEntityType::Component(self.component_at(export.index, offset)?)
758 }
759 };
760
761 let ascribed = match &export.ty {
762 Some(ty) => self.check_type_ref(ty, types, offset)?,
763 None => return Ok(actual),
764 };
765
766 if !ComponentEntityType::internal_is_subtype_of(&actual, types, &ascribed, types) {
767 bail!(
768 offset,
769 "ascribed type of export is not compatible with item's type"
770 );
771 }
772
773 Ok(ascribed)
774 }
775
776 fn create_module_type(
777 components: &[Self],
778 decls: Vec<crate::ModuleTypeDeclaration>,
779 features: &WasmFeatures,
780 types: &mut TypeAlloc,
781 offset: usize,
782 ) -> Result<ModuleType> {
783 let mut state = Module::default();
784
785 for decl in decls {
786 match decl {
787 crate::ModuleTypeDeclaration::Type(ty) => {
788 state.add_type(ty, features, types, offset, true)?;
789 }
790 crate::ModuleTypeDeclaration::Export { name, ty } => {
791 let ty = state.check_type_ref(&ty, features, types, offset)?;
792 state.add_export(name, ty, features, offset, true)?;
793 }
794 crate::ModuleTypeDeclaration::OuterAlias { kind, count, index } => {
795 if count > 1 {
796 return Err(BinaryReaderError::new(
797 "outer type aliases in module type declarations are limited to a maximum count of 1",
798 offset,
799 ));
800 }
801 match kind {
802 crate::OuterAliasKind::Type => {
803 let ty = if count == 0 {
804 state.type_at(index, offset)?
806 } else {
807 let component =
809 Self::check_alias_count(components, count - 1, offset)?;
810 component.type_at(index, true, offset)?
811 };
812
813 check_max(state.types.len(), 1, MAX_WASM_TYPES, "types", offset)?;
814
815 state.types.push(ty);
816 }
817 }
818 }
819 crate::ModuleTypeDeclaration::Import(import) => {
820 state.add_import(import, features, types, offset)?;
821 }
822 }
823 }
824
825 let imports = state.imports_for_module_type(offset)?;
826
827 Ok(ModuleType {
828 type_size: state.type_size,
829 imports,
830 exports: state.exports,
831 })
832 }
833
834 fn create_component_type(
835 components: &mut Vec<Self>,
836 decls: Vec<crate::ComponentTypeDeclaration>,
837 features: &WasmFeatures,
838 types: &mut TypeAlloc,
839 offset: usize,
840 ) -> Result<ComponentType> {
841 components.push(ComponentState::default());
842
843 for decl in decls {
844 match decl {
845 crate::ComponentTypeDeclaration::CoreType(ty) => {
846 Self::add_core_type(components, ty, features, types, offset, true)?;
847 }
848 crate::ComponentTypeDeclaration::Type(ty) => {
849 Self::add_type(components, ty, features, types, offset, true)?;
850 }
851 crate::ComponentTypeDeclaration::Export { name, url, ty } => {
852 let current = components.last_mut().unwrap();
853 let ty = current.check_type_ref(&ty, types, offset)?;
854 current.add_export(name, url, ty, offset, true)?;
855 }
856 crate::ComponentTypeDeclaration::Import(import) => {
857 components
858 .last_mut()
859 .unwrap()
860 .add_import(import, types, offset)?;
861 }
862 crate::ComponentTypeDeclaration::Alias(alias) => {
863 Self::add_alias(components, alias, types, offset)?;
864 }
865 };
866 }
867
868 let mut state = components.pop().unwrap();
869
870 Ok(state.take_component_type())
871 }
872
873 fn create_instance_type(
874 components: &mut Vec<Self>,
875 decls: Vec<crate::InstanceTypeDeclaration>,
876 features: &WasmFeatures,
877 types: &mut TypeAlloc,
878 offset: usize,
879 ) -> Result<ComponentInstanceType> {
880 components.push(ComponentState::default());
881
882 for decl in decls {
883 match decl {
884 crate::InstanceTypeDeclaration::CoreType(ty) => {
885 Self::add_core_type(components, ty, features, types, offset, true)?;
886 }
887 crate::InstanceTypeDeclaration::Type(ty) => {
888 Self::add_type(components, ty, features, types, offset, true)?;
889 }
890 crate::InstanceTypeDeclaration::Export { name, url, ty } => {
891 let current = components.last_mut().unwrap();
892 let ty = current.check_type_ref(&ty, types, offset)?;
893 current.add_export(name, url, ty, offset, true)?;
894 }
895 crate::InstanceTypeDeclaration::Alias(alias) => {
896 Self::add_alias(components, alias, types, offset)?;
897 }
898 };
899 }
900
901 let state = components.pop().unwrap();
902
903 Ok(ComponentInstanceType {
904 type_size: state.type_size,
905 kind: ComponentInstanceTypeKind::Defined(
906 state
907 .externs
908 .into_iter()
909 .filter_map(|(name, (url, ty, kind))| match kind {
910 ExternKind::Export => Some((name, (url, ty))),
911 ExternKind::Import => None,
912 })
913 .collect(),
914 ),
915 })
916 }
917
918 fn create_function_type(
919 &self,
920 ty: crate::ComponentFuncType,
921 types: &TypeList,
922 offset: usize,
923 ) -> Result<ComponentFuncType> {
924 let mut type_size = 1;
925
926 let mut set =
927 HashSet::with_capacity(std::cmp::max(ty.params.len(), ty.results.type_count()));
928
929 let params = ty
930 .params
931 .iter()
932 .map(|(name, ty)| {
933 let name = to_kebab_str(name, "function parameter", offset)?;
934 if !set.insert(name) {
935 bail!(
936 offset,
937 "function parameter name `{name}` conflicts with previous parameter name `{prev}`",
938 prev = set.get(&name).unwrap(),
939 );
940 }
941
942 let ty = self.create_component_val_type(*ty, types, offset)?;
943 type_size = combine_type_sizes(type_size, ty.type_size(), offset)?;
944 Ok((name.to_owned(), ty))
945 })
946 .collect::<Result<_>>()?;
947
948 set.clear();
949
950 let results = ty
951 .results
952 .iter()
953 .map(|(name, ty)| {
954 let name = name
955 .map(|name| {
956 let name = to_kebab_str(name, "function result", offset)?;
957 if !set.insert(name) {
958 bail!(
959 offset,
960 "function result name `{name}` conflicts with previous result name `{prev}`",
961 prev = set.get(name).unwrap(),
962 );
963 }
964
965 Ok(name.to_owned())
966 })
967 .transpose()?;
968
969 let ty = self.create_component_val_type(*ty, types, offset)?;
970 type_size = combine_type_sizes(type_size, ty.type_size(), offset)?;
971 Ok((name, ty))
972 })
973 .collect::<Result<_>>()?;
974
975 Ok(ComponentFuncType {
976 type_size,
977 params,
978 results,
979 })
980 }
981
982 fn instantiate_module(
983 &self,
984 module_index: u32,
985 module_args: Vec<crate::InstantiationArg>,
986 types: &mut TypeAlloc,
987 offset: usize,
988 ) -> Result<TypeId> {
989 fn insert_arg<'a>(
990 name: &'a str,
991 arg: &'a InstanceType,
992 args: &mut IndexMap<&'a str, &'a InstanceType>,
993 offset: usize,
994 ) -> Result<()> {
995 if args.insert(name, arg).is_some() {
996 bail!(
997 offset,
998 "duplicate module instantiation argument named `{name}`"
999 );
1000 }
1001
1002 Ok(())
1003 }
1004
1005 let module_type_id = self.module_at(module_index, offset)?;
1006 let mut args = IndexMap::new();
1007
1008 for module_arg in module_args {
1010 match module_arg.kind {
1011 InstantiationArgKind::Instance => {
1012 let instance_type = types[self.core_instance_at(module_arg.index, offset)?]
1013 .as_instance_type()
1014 .unwrap();
1015 insert_arg(module_arg.name, instance_type, &mut args, offset)?;
1016 }
1017 }
1018 }
1019
1020 let module_type = types[module_type_id].as_module_type().unwrap();
1022 for ((module, name), expected) in module_type.imports.iter() {
1023 let instance = args.get(module.as_str()).ok_or_else(|| {
1024 format_err!(
1025 offset,
1026 "missing module instantiation argument named `{module}`"
1027 )
1028 })?;
1029
1030 let arg = instance
1031 .internal_exports(types)
1032 .get(name.as_str())
1033 .ok_or_else(|| {
1034 format_err!(
1035 offset,
1036 "module instantiation argument `{module}` does not \
1037 export an item named `{name}`",
1038 )
1039 })?;
1040
1041 match (arg, expected) {
1042 (EntityType::Func(_), EntityType::Func(_))
1043 | (EntityType::Table(_), EntityType::Table(_))
1044 | (EntityType::Memory(_), EntityType::Memory(_))
1045 | (EntityType::Global(_), EntityType::Global(_))
1046 | (EntityType::Tag(_), EntityType::Tag(_)) => {}
1047 _ => {
1048 bail!(
1049 offset,
1050 "module instantiation argument `{module}` exports \
1051 an item named `{name}` but it is not a {}",
1052 expected.desc()
1053 )
1054 }
1055 }
1056
1057 if !EntityType::internal_is_subtype_of(arg, types, expected, types) {
1058 bail!(
1059 offset,
1060 "{} type mismatch for export `{name}` of module \
1061 instantiation argument `{module}`",
1062 expected.desc(),
1063 );
1064 }
1065 }
1066
1067 let ty = Type::Instance(InstanceType {
1068 type_size: module_type
1069 .exports
1070 .iter()
1071 .fold(1, |acc, (_, ty)| acc + ty.type_size()),
1072 kind: InstanceTypeKind::Instantiated(module_type_id),
1073 });
1074
1075 Ok(types.push_anon(ty))
1076 }
1077
1078 fn instantiate_component(
1079 &mut self,
1080 component_index: u32,
1081 component_args: Vec<crate::ComponentInstantiationArg>,
1082 types: &mut TypeAlloc,
1083 offset: usize,
1084 ) -> Result<TypeId> {
1085 fn insert_arg<'a>(
1086 name: &'a str,
1087 arg: ComponentEntityType,
1088 args: &mut IndexMap<&'a KebabStr, ComponentEntityType>,
1089 offset: usize,
1090 ) -> Result<()> {
1091 let name = to_kebab_str(name, "instantiation argument", offset)?;
1092 match args.entry(name) {
1093 Entry::Occupied(e) => {
1094 bail!(
1095 offset,
1096 "instantiation argument `{name}` conflicts with previous argument `{prev}`",
1097 prev = e.key()
1098 );
1099 }
1100 Entry::Vacant(e) => {
1101 e.insert(arg);
1102 }
1103 }
1104
1105 Ok(())
1106 }
1107
1108 let component_type_id = self.component_at(component_index, offset)?;
1109 let mut args = IndexMap::new();
1110
1111 for component_arg in component_args {
1113 match component_arg.kind {
1114 ComponentExternalKind::Module => {
1115 insert_arg(
1116 component_arg.name,
1117 ComponentEntityType::Module(self.module_at(component_arg.index, offset)?),
1118 &mut args,
1119 offset,
1120 )?;
1121 }
1122 ComponentExternalKind::Component => {
1123 insert_arg(
1124 component_arg.name,
1125 ComponentEntityType::Component(
1126 self.component_at(component_arg.index, offset)?,
1127 ),
1128 &mut args,
1129 offset,
1130 )?;
1131 }
1132 ComponentExternalKind::Instance => {
1133 insert_arg(
1134 component_arg.name,
1135 ComponentEntityType::Instance(
1136 self.instance_at(component_arg.index, offset)?,
1137 ),
1138 &mut args,
1139 offset,
1140 )?;
1141 }
1142 ComponentExternalKind::Func => {
1143 insert_arg(
1144 component_arg.name,
1145 ComponentEntityType::Func(self.function_at(component_arg.index, offset)?),
1146 &mut args,
1147 offset,
1148 )?;
1149 }
1150 ComponentExternalKind::Value => {
1151 insert_arg(
1152 component_arg.name,
1153 ComponentEntityType::Value(*self.value_at(component_arg.index, offset)?),
1154 &mut args,
1155 offset,
1156 )?;
1157 }
1158 ComponentExternalKind::Type => {
1159 let ty = self.type_at(component_arg.index, false, offset)?;
1160 insert_arg(
1161 component_arg.name,
1162 ComponentEntityType::Type {
1163 referenced: ty,
1164 created: ty,
1165 },
1166 &mut args,
1167 offset,
1168 )?;
1169 }
1170 }
1171 }
1172
1173 let component_type = types[component_type_id].as_component_type().unwrap();
1175 for (name, (_, expected)) in component_type.imports.iter() {
1176 match args.get(&name.as_kebab_str()) {
1177 Some(arg) => {
1178 match (arg, expected) {
1179 (ComponentEntityType::Module(_), ComponentEntityType::Module(_))
1180 | (ComponentEntityType::Component(_), ComponentEntityType::Component(_))
1181 | (ComponentEntityType::Instance(_), ComponentEntityType::Instance(_))
1182 | (ComponentEntityType::Func(_), ComponentEntityType::Func(_))
1183 | (ComponentEntityType::Value(_), ComponentEntityType::Value(_))
1184 | (ComponentEntityType::Type { .. }, ComponentEntityType::Type { .. }) => {}
1185 _ => {
1186 bail!(
1187 offset,
1188 "expected component instantiation argument `{name}` to be a {desc}",
1189 desc = expected.desc()
1190 )
1191 }
1192 };
1193
1194 if !ComponentEntityType::internal_is_subtype_of(arg, types, expected, types) {
1195 bail!(
1196 offset,
1197 "type mismatch for component instantiation argument `{name}`"
1198 );
1199 }
1200 }
1201 None => {
1202 bail!(
1203 offset,
1204 "missing component instantiation argument named `{name}`"
1205 );
1206 }
1207 }
1208 }
1209
1210 let ty = Type::ComponentInstance(ComponentInstanceType {
1211 type_size: component_type
1212 .exports
1213 .iter()
1214 .fold(1, |acc, (_, (_, ty))| acc + ty.type_size()),
1215 kind: ComponentInstanceTypeKind::Instantiated(component_type_id),
1216 });
1217
1218 Ok(types.push_anon(ty))
1219 }
1220
1221 fn instantiate_exports(
1222 &mut self,
1223 exports: Vec<crate::ComponentExport>,
1224 types: &mut TypeAlloc,
1225 offset: usize,
1226 ) -> Result<TypeId> {
1227 fn insert_export(
1228 name: &str,
1229 export: ComponentEntityType,
1230 exports: &mut IndexMap<KebabString, (Option<Url>, ComponentEntityType)>,
1231 type_size: &mut u32,
1232 offset: usize,
1233 ) -> Result<()> {
1234 let name = to_kebab_str(name, "instance export", offset)?;
1235 match exports.entry(name.to_owned()) {
1236 Entry::Occupied(e) => bail!(
1237 offset,
1238 "instance export name `{name}` conflicts with previous export name `{prev}`",
1239 prev = e.key()
1240 ),
1241 Entry::Vacant(e) => {
1242 *type_size = combine_type_sizes(*type_size, export.type_size(), offset)?;
1243 e.insert((None, export));
1244 }
1245 }
1246
1247 Ok(())
1248 }
1249
1250 let mut type_size = 1;
1251 let mut inst_exports = IndexMap::new();
1252 for export in exports {
1253 assert!(export.ty.is_none());
1254 match export.kind {
1255 ComponentExternalKind::Module => {
1256 insert_export(
1257 export.name,
1258 ComponentEntityType::Module(self.module_at(export.index, offset)?),
1259 &mut inst_exports,
1260 &mut type_size,
1261 offset,
1262 )?;
1263 }
1264 ComponentExternalKind::Component => {
1265 insert_export(
1266 export.name,
1267 ComponentEntityType::Component(self.component_at(export.index, offset)?),
1268 &mut inst_exports,
1269 &mut type_size,
1270 offset,
1271 )?;
1272 }
1273 ComponentExternalKind::Instance => {
1274 insert_export(
1275 export.name,
1276 ComponentEntityType::Instance(self.instance_at(export.index, offset)?),
1277 &mut inst_exports,
1278 &mut type_size,
1279 offset,
1280 )?;
1281 }
1282 ComponentExternalKind::Func => {
1283 insert_export(
1284 export.name,
1285 ComponentEntityType::Func(self.function_at(export.index, offset)?),
1286 &mut inst_exports,
1287 &mut type_size,
1288 offset,
1289 )?;
1290 }
1291 ComponentExternalKind::Value => {
1292 insert_export(
1293 export.name,
1294 ComponentEntityType::Value(*self.value_at(export.index, offset)?),
1295 &mut inst_exports,
1296 &mut type_size,
1297 offset,
1298 )?;
1299 }
1300 ComponentExternalKind::Type => {
1301 let ty = self.type_at(export.index, false, offset)?;
1302 insert_export(
1303 export.name,
1304 ComponentEntityType::Type {
1305 referenced: ty,
1306 created: ty,
1312 },
1313 &mut inst_exports,
1314 &mut type_size,
1315 offset,
1316 )?;
1317 }
1318 }
1319 }
1320
1321 let ty = Type::ComponentInstance(ComponentInstanceType {
1322 type_size,
1323 kind: ComponentInstanceTypeKind::Exports(inst_exports),
1324 });
1325
1326 Ok(types.push_anon(ty))
1327 }
1328
1329 fn instantiate_core_exports(
1330 &mut self,
1331 exports: Vec<crate::Export>,
1332 types: &mut TypeAlloc,
1333 offset: usize,
1334 ) -> Result<TypeId> {
1335 fn insert_export(
1336 name: &str,
1337 export: EntityType,
1338 exports: &mut IndexMap<String, EntityType>,
1339 type_size: &mut u32,
1340 offset: usize,
1341 ) -> Result<()> {
1342 *type_size = combine_type_sizes(*type_size, export.type_size(), offset)?;
1343
1344 if exports.insert(name.to_string(), export).is_some() {
1345 bail!(
1346 offset,
1347 "duplicate instantiation export name `{name}` already defined",
1348 )
1349 }
1350
1351 Ok(())
1352 }
1353
1354 let mut type_size = 1;
1355 let mut inst_exports = IndexMap::new();
1356 for export in exports {
1357 match export.kind {
1358 ExternalKind::Func => {
1359 insert_export(
1360 export.name,
1361 EntityType::Func(self.core_function_at(export.index, offset)?),
1362 &mut inst_exports,
1363 &mut type_size,
1364 offset,
1365 )?;
1366 }
1367 ExternalKind::Table => insert_export(
1368 export.name,
1369 EntityType::Table(*self.table_at(export.index, offset)?),
1370 &mut inst_exports,
1371 &mut type_size,
1372 offset,
1373 )?,
1374 ExternalKind::Memory => insert_export(
1375 export.name,
1376 EntityType::Memory(*self.memory_at(export.index, offset)?),
1377 &mut inst_exports,
1378 &mut type_size,
1379 offset,
1380 )?,
1381 ExternalKind::Global => {
1382 insert_export(
1383 export.name,
1384 EntityType::Global(*self.global_at(export.index, offset)?),
1385 &mut inst_exports,
1386 &mut type_size,
1387 offset,
1388 )?;
1389 }
1390 ExternalKind::Tag => insert_export(
1391 export.name,
1392 EntityType::Tag(self.core_function_at(export.index, offset)?),
1393 &mut inst_exports,
1394 &mut type_size,
1395 offset,
1396 )?,
1397 }
1398 }
1399
1400 let ty = Type::Instance(InstanceType {
1401 type_size,
1402 kind: InstanceTypeKind::Exports(inst_exports),
1403 });
1404
1405 Ok(types.push_anon(ty))
1406 }
1407
1408 fn alias_core_instance_export(
1409 &mut self,
1410 instance_index: u32,
1411 kind: ExternalKind,
1412 name: &str,
1413 types: &TypeList,
1414 offset: usize,
1415 ) -> Result<()> {
1416 macro_rules! push_module_export {
1417 ($expected:path, $collection:ident, $ty:literal) => {{
1418 match self.core_instance_export(instance_index, name, types, offset)? {
1419 $expected(ty) => {
1420 self.$collection.push(*ty);
1421 Ok(())
1422 }
1423 _ => {
1424 bail!(
1425 offset,
1426 "export `{name}` for core instance {instance_index} is not a {}",
1427 $ty
1428 )
1429 }
1430 }
1431 }};
1432 }
1433
1434 match kind {
1435 ExternalKind::Func => {
1436 check_max(
1437 self.function_count(),
1438 1,
1439 MAX_WASM_FUNCTIONS,
1440 "functions",
1441 offset,
1442 )?;
1443 push_module_export!(EntityType::Func, core_funcs, "function")
1444 }
1445 ExternalKind::Table => {
1446 check_max(self.core_tables.len(), 1, MAX_WASM_TABLES, "tables", offset)?;
1447 push_module_export!(EntityType::Table, core_tables, "table")
1448 }
1449 ExternalKind::Memory => {
1450 check_max(
1451 self.core_memories.len(),
1452 1,
1453 MAX_WASM_MEMORIES,
1454 "memories",
1455 offset,
1456 )?;
1457 push_module_export!(EntityType::Memory, core_memories, "memory")
1458 }
1459 ExternalKind::Global => {
1460 check_max(
1461 self.core_globals.len(),
1462 1,
1463 MAX_WASM_GLOBALS,
1464 "globals",
1465 offset,
1466 )?;
1467 push_module_export!(EntityType::Global, core_globals, "global")
1468 }
1469 ExternalKind::Tag => {
1470 check_max(self.core_tags.len(), 1, MAX_WASM_TAGS, "tags", offset)?;
1471 push_module_export!(EntityType::Tag, core_tags, "tag")
1472 }
1473 }
1474 }
1475
1476 fn alias_instance_export(
1477 &mut self,
1478 instance_index: u32,
1479 kind: ComponentExternalKind,
1480 name: &str,
1481 types: &mut TypeAlloc,
1482 offset: usize,
1483 ) -> Result<()> {
1484 let name = to_kebab_str(name, "alias export", offset)?;
1485
1486 macro_rules! push_component_export {
1487 ($expected:path, $collection:ident, $ty:literal) => {{
1488 match self.instance_export(instance_index, name, types, offset)? {
1489 $expected(ty) => {
1490 self.$collection.push(*ty);
1491 Ok(())
1492 }
1493 _ => {
1494 bail!(
1495 offset,
1496 "export `{name}` for instance {instance_index} is not a {}",
1497 $ty
1498 )
1499 }
1500 }
1501 }};
1502 }
1503
1504 match kind {
1505 ComponentExternalKind::Module => {
1506 check_max(
1507 self.core_modules.len(),
1508 1,
1509 MAX_WASM_MODULES,
1510 "modules",
1511 offset,
1512 )?;
1513 push_component_export!(ComponentEntityType::Module, core_modules, "module")
1514 }
1515 ComponentExternalKind::Component => {
1516 check_max(
1517 self.components.len(),
1518 1,
1519 MAX_WASM_COMPONENTS,
1520 "components",
1521 offset,
1522 )?;
1523 push_component_export!(ComponentEntityType::Component, components, "component")
1524 }
1525 ComponentExternalKind::Instance => {
1526 check_max(
1527 self.instance_count(),
1528 1,
1529 MAX_WASM_INSTANCES,
1530 "instances",
1531 offset,
1532 )?;
1533 push_component_export!(ComponentEntityType::Instance, instances, "instance")
1534 }
1535 ComponentExternalKind::Func => {
1536 check_max(
1537 self.function_count(),
1538 1,
1539 MAX_WASM_FUNCTIONS,
1540 "functions",
1541 offset,
1542 )?;
1543 push_component_export!(ComponentEntityType::Func, funcs, "function")
1544 }
1545 ComponentExternalKind::Value => {
1546 check_max(self.values.len(), 1, MAX_WASM_VALUES, "values", offset)?;
1547 match self.instance_export(instance_index, name, types, offset)? {
1548 ComponentEntityType::Value(ty) => {
1549 self.values.push((*ty, false));
1550 Ok(())
1551 }
1552 _ => bail!(
1553 offset,
1554 "export `{name}` for instance {instance_index} is not a value",
1555 ),
1556 }
1557 }
1558 ComponentExternalKind::Type => {
1559 check_max(self.type_count(), 1, MAX_WASM_TYPES, "types", offset)?;
1560 match *self.instance_export(instance_index, name, types, offset)? {
1561 ComponentEntityType::Type { created, .. } => {
1562 let id = types.with_unique(created);
1563 self.types.push(id);
1564 Ok(())
1565 }
1566 _ => {
1567 bail!(
1568 offset,
1569 "export `{name}` for instance {instance_index} is not a type",
1570 )
1571 }
1572 }
1573 }
1574 }
1575 }
1576
1577 fn alias_module(components: &mut [Self], count: u32, index: u32, offset: usize) -> Result<()> {
1578 let component = Self::check_alias_count(components, count, offset)?;
1579 let ty = component.module_at(index, offset)?;
1580
1581 let current = components.last_mut().unwrap();
1582 check_max(
1583 current.core_modules.len(),
1584 1,
1585 MAX_WASM_MODULES,
1586 "modules",
1587 offset,
1588 )?;
1589
1590 current.core_modules.push(ty);
1591 Ok(())
1592 }
1593
1594 fn alias_component(
1595 components: &mut [Self],
1596 count: u32,
1597 index: u32,
1598 offset: usize,
1599 ) -> Result<()> {
1600 let component = Self::check_alias_count(components, count, offset)?;
1601 let ty = component.component_at(index, offset)?;
1602
1603 let current = components.last_mut().unwrap();
1604 check_max(
1605 current.components.len(),
1606 1,
1607 MAX_WASM_COMPONENTS,
1608 "components",
1609 offset,
1610 )?;
1611
1612 current.components.push(ty);
1613 Ok(())
1614 }
1615
1616 fn alias_core_type(
1617 components: &mut [Self],
1618 count: u32,
1619 index: u32,
1620 types: &mut TypeAlloc,
1621 offset: usize,
1622 ) -> Result<()> {
1623 let component = Self::check_alias_count(components, count, offset)?;
1624 let ty = component.type_at(index, true, offset)?;
1625
1626 let current = components.last_mut().unwrap();
1627 check_max(current.type_count(), 1, MAX_WASM_TYPES, "types", offset)?;
1628
1629 let id = types.with_unique(ty);
1630 current.core_types.push(id);
1631
1632 Ok(())
1633 }
1634
1635 fn alias_type(
1636 components: &mut [Self],
1637 count: u32,
1638 index: u32,
1639 types: &mut TypeAlloc,
1640 offset: usize,
1641 ) -> Result<()> {
1642 let component = Self::check_alias_count(components, count, offset)?;
1643 let ty = component.type_at(index, false, offset)?;
1644
1645 let current = components.last_mut().unwrap();
1646 check_max(current.type_count(), 1, MAX_WASM_TYPES, "types", offset)?;
1647
1648 let id = types.with_unique(ty);
1649 current.types.push(id);
1650
1651 Ok(())
1652 }
1653
1654 fn check_alias_count(components: &[Self], count: u32, offset: usize) -> Result<&Self> {
1655 let count = count as usize;
1656 if count >= components.len() {
1657 bail!(offset, "invalid outer alias count of {count}");
1658 }
1659
1660 Ok(&components[components.len() - count - 1])
1661 }
1662
1663 fn create_defined_type(
1664 &self,
1665 ty: crate::ComponentDefinedType,
1666 types: &TypeList,
1667 offset: usize,
1668 ) -> Result<ComponentDefinedType> {
1669 match ty {
1670 crate::ComponentDefinedType::Primitive(ty) => Ok(ComponentDefinedType::Primitive(ty)),
1671 crate::ComponentDefinedType::Record(fields) => {
1672 self.create_record_type(fields.as_ref(), types, offset)
1673 }
1674 crate::ComponentDefinedType::Variant(cases) => {
1675 self.create_variant_type(cases.as_ref(), types, offset)
1676 }
1677 crate::ComponentDefinedType::List(ty) => Ok(ComponentDefinedType::List(
1678 self.create_component_val_type(ty, types, offset)?,
1679 )),
1680 crate::ComponentDefinedType::Tuple(tys) => {
1681 self.create_tuple_type(tys.as_ref(), types, offset)
1682 }
1683 crate::ComponentDefinedType::Flags(names) => {
1684 self.create_flags_type(names.as_ref(), offset)
1685 }
1686 crate::ComponentDefinedType::Enum(cases) => {
1687 self.create_enum_type(cases.as_ref(), offset)
1688 }
1689 crate::ComponentDefinedType::Union(tys) => {
1690 self.create_union_type(tys.as_ref(), types, offset)
1691 }
1692 crate::ComponentDefinedType::Option(ty) => Ok(ComponentDefinedType::Option(
1693 self.create_component_val_type(ty, types, offset)?,
1694 )),
1695 crate::ComponentDefinedType::Result { ok, err } => Ok(ComponentDefinedType::Result {
1696 ok: ok
1697 .map(|ty| self.create_component_val_type(ty, types, offset))
1698 .transpose()?,
1699 err: err
1700 .map(|ty| self.create_component_val_type(ty, types, offset))
1701 .transpose()?,
1702 }),
1703 }
1704 }
1705
1706 fn create_record_type(
1707 &self,
1708 fields: &[(&str, crate::ComponentValType)],
1709 types: &TypeList,
1710 offset: usize,
1711 ) -> Result<ComponentDefinedType> {
1712 let mut type_size = 1;
1713 let mut field_map = IndexMap::with_capacity(fields.len());
1714
1715 for (name, ty) in fields {
1716 let name = to_kebab_str(name, "record field", offset)?;
1717 let ty = self.create_component_val_type(*ty, types, offset)?;
1718
1719 match field_map.entry(name.to_owned()) {
1720 Entry::Occupied(e) => bail!(
1721 offset,
1722 "record field name `{name}` conflicts with previous field name `{prev}`",
1723 prev = e.key()
1724 ),
1725 Entry::Vacant(e) => {
1726 type_size = combine_type_sizes(type_size, ty.type_size(), offset)?;
1727 e.insert(ty);
1728 }
1729 }
1730 }
1731
1732 Ok(ComponentDefinedType::Record(RecordType {
1733 type_size,
1734 fields: field_map,
1735 }))
1736 }
1737
1738 fn create_variant_type(
1739 &self,
1740 cases: &[crate::VariantCase],
1741 types: &TypeList,
1742 offset: usize,
1743 ) -> Result<ComponentDefinedType> {
1744 let mut type_size = 1;
1745 let mut case_map: IndexMap<KebabString, VariantCase> = IndexMap::with_capacity(cases.len());
1746
1747 if cases.is_empty() {
1748 return Err(BinaryReaderError::new(
1749 "variant type must have at least one case",
1750 offset,
1751 ));
1752 }
1753
1754 if cases.len() > u32::MAX as usize {
1755 return Err(BinaryReaderError::new(
1756 "variant type cannot be represented with a 32-bit discriminant value",
1757 offset,
1758 ));
1759 }
1760
1761 for (i, case) in cases.iter().enumerate() {
1762 if let Some(refines) = case.refines {
1763 if refines >= i as u32 {
1764 return Err(BinaryReaderError::new(
1765 "variant case can only refine a previously defined case",
1766 offset,
1767 ));
1768 }
1769 }
1770
1771 let name = to_kebab_str(case.name, "variant case", offset)?;
1772
1773 let ty = case
1774 .ty
1775 .map(|ty| self.create_component_val_type(ty, types, offset))
1776 .transpose()?;
1777
1778 match case_map.entry(name.to_owned()) {
1779 Entry::Occupied(e) => bail!(
1780 offset,
1781 "variant case name `{name}` conflicts with previous case name `{prev}`",
1782 name = case.name,
1783 prev = e.key()
1784 ),
1785 Entry::Vacant(e) => {
1786 type_size = combine_type_sizes(
1787 type_size,
1788 ty.map(|ty| ty.type_size()).unwrap_or(1),
1789 offset,
1790 )?;
1791
1792 e.insert(VariantCase {
1795 ty,
1796 refines: case
1797 .refines
1798 .map(|i| KebabStr::new_unchecked(cases[i as usize].name).to_owned()),
1799 });
1800 }
1801 }
1802 }
1803
1804 Ok(ComponentDefinedType::Variant(VariantType {
1805 type_size,
1806 cases: case_map,
1807 }))
1808 }
1809
1810 fn create_tuple_type(
1811 &self,
1812 tys: &[crate::ComponentValType],
1813 types: &TypeList,
1814 offset: usize,
1815 ) -> Result<ComponentDefinedType> {
1816 let mut type_size = 1;
1817 let types = tys
1818 .iter()
1819 .map(|ty| {
1820 let ty = self.create_component_val_type(*ty, types, offset)?;
1821 type_size = combine_type_sizes(type_size, ty.type_size(), offset)?;
1822 Ok(ty)
1823 })
1824 .collect::<Result<_>>()?;
1825
1826 Ok(ComponentDefinedType::Tuple(TupleType { type_size, types }))
1827 }
1828
1829 fn create_flags_type(&self, names: &[&str], offset: usize) -> Result<ComponentDefinedType> {
1830 let mut names_set = IndexSet::with_capacity(names.len());
1831
1832 for name in names {
1833 let name = to_kebab_str(name, "flag", offset)?;
1834 if !names_set.insert(name.to_owned()) {
1835 bail!(
1836 offset,
1837 "flag name `{name}` conflicts with previous flag name `{prev}`",
1838 prev = names_set.get(name).unwrap()
1839 );
1840 }
1841 }
1842
1843 Ok(ComponentDefinedType::Flags(names_set))
1844 }
1845
1846 fn create_enum_type(&self, cases: &[&str], offset: usize) -> Result<ComponentDefinedType> {
1847 if cases.len() > u32::MAX as usize {
1848 return Err(BinaryReaderError::new(
1849 "enumeration type cannot be represented with a 32-bit discriminant value",
1850 offset,
1851 ));
1852 }
1853
1854 let mut tags = IndexSet::with_capacity(cases.len());
1855
1856 for tag in cases {
1857 let tag = to_kebab_str(tag, "enum tag", offset)?;
1858 if !tags.insert(tag.to_owned()) {
1859 bail!(
1860 offset,
1861 "enum tag name `{tag}` conflicts with previous tag name `{prev}`",
1862 prev = tags.get(tag).unwrap()
1863 );
1864 }
1865 }
1866
1867 Ok(ComponentDefinedType::Enum(tags))
1868 }
1869
1870 fn create_union_type(
1871 &self,
1872 tys: &[crate::ComponentValType],
1873 types: &TypeList,
1874 offset: usize,
1875 ) -> Result<ComponentDefinedType> {
1876 let mut type_size = 1;
1877 let types = tys
1878 .iter()
1879 .map(|ty| {
1880 let ty = self.create_component_val_type(*ty, types, offset)?;
1881 type_size = combine_type_sizes(type_size, ty.type_size(), offset)?;
1882 Ok(ty)
1883 })
1884 .collect::<Result<_>>()?;
1885
1886 Ok(ComponentDefinedType::Union(UnionType { type_size, types }))
1887 }
1888
1889 fn create_component_val_type(
1890 &self,
1891 ty: crate::ComponentValType,
1892 types: &TypeList,
1893 offset: usize,
1894 ) -> Result<ComponentValType> {
1895 Ok(match ty {
1896 crate::ComponentValType::Primitive(pt) => ComponentValType::Primitive(pt),
1897 crate::ComponentValType::Type(idx) => {
1898 ComponentValType::Type(self.defined_type_at(idx, types, offset)?)
1899 }
1900 })
1901 }
1902
1903 pub fn type_at(&self, idx: u32, core: bool, offset: usize) -> Result<TypeId> {
1904 let types = if core { &self.core_types } else { &self.types };
1905 types
1906 .get(idx as usize)
1907 .copied()
1908 .ok_or_else(|| format_err!(offset, "unknown type {idx}: type index out of bounds"))
1909 }
1910
1911 fn function_type_at<'a>(
1912 &self,
1913 idx: u32,
1914 types: &'a TypeList,
1915 offset: usize,
1916 ) -> Result<&'a ComponentFuncType> {
1917 types[self.type_at(idx, false, offset)?]
1918 .as_component_func_type()
1919 .ok_or_else(|| format_err!(offset, "type index {idx} is not a function type"))
1920 }
1921
1922 fn function_at(&self, idx: u32, offset: usize) -> Result<TypeId> {
1923 self.funcs.get(idx as usize).copied().ok_or_else(|| {
1924 format_err!(
1925 offset,
1926 "unknown function {idx}: function index out of bounds"
1927 )
1928 })
1929 }
1930
1931 fn component_at(&self, idx: u32, offset: usize) -> Result<TypeId> {
1932 self.components.get(idx as usize).copied().ok_or_else(|| {
1933 format_err!(
1934 offset,
1935 "unknown component {idx}: component index out of bounds"
1936 )
1937 })
1938 }
1939
1940 fn instance_at(&self, idx: u32, offset: usize) -> Result<TypeId> {
1941 self.instances.get(idx as usize).copied().ok_or_else(|| {
1942 format_err!(
1943 offset,
1944 "unknown instance {idx}: instance index out of bounds"
1945 )
1946 })
1947 }
1948
1949 fn instance_export<'a>(
1950 &self,
1951 instance_index: u32,
1952 name: &KebabStr,
1953 types: &'a TypeList,
1954 offset: usize,
1955 ) -> Result<&'a ComponentEntityType> {
1956 match types[self.instance_at(instance_index, offset)?]
1957 .as_component_instance_type()
1958 .unwrap()
1959 .internal_exports(types)
1960 .get(name)
1961 {
1962 Some((_, ty)) => Ok(ty),
1963 None => bail!(
1964 offset,
1965 "instance {instance_index} has no export named `{name}`"
1966 ),
1967 }
1968 }
1969
1970 fn value_at(&mut self, idx: u32, offset: usize) -> Result<&ComponentValType> {
1971 match self.values.get_mut(idx as usize) {
1972 Some((ty, used)) if !*used => {
1973 *used = true;
1974 Ok(ty)
1975 }
1976 Some(_) => bail!(offset, "value {idx} cannot be used more than once"),
1977 None => bail!(offset, "unknown value {idx}: value index out of bounds"),
1978 }
1979 }
1980
1981 fn defined_type_at(&self, idx: u32, types: &TypeList, offset: usize) -> Result<TypeId> {
1982 let id = self.type_at(idx, false, offset)?;
1983 match &types[id] {
1984 Type::Defined(_) => Ok(id),
1985 _ => bail!(offset, "type index {} is not a defined type", idx),
1986 }
1987 }
1988
1989 fn core_function_at(&self, idx: u32, offset: usize) -> Result<TypeId> {
1990 match self.core_funcs.get(idx as usize) {
1991 Some(id) => Ok(*id),
1992 None => bail!(
1993 offset,
1994 "unknown core function {idx}: function index out of bounds"
1995 ),
1996 }
1997 }
1998
1999 fn module_at(&self, idx: u32, offset: usize) -> Result<TypeId> {
2000 match self.core_modules.get(idx as usize) {
2001 Some(id) => Ok(*id),
2002 None => bail!(offset, "unknown module {idx}: module index out of bounds"),
2003 }
2004 }
2005
2006 fn core_instance_at(&self, idx: u32, offset: usize) -> Result<TypeId> {
2007 match self.core_instances.get(idx as usize) {
2008 Some(id) => Ok(*id),
2009 None => bail!(
2010 offset,
2011 "unknown core instance {idx}: instance index out of bounds"
2012 ),
2013 }
2014 }
2015
2016 fn core_instance_export<'a>(
2017 &self,
2018 instance_index: u32,
2019 name: &str,
2020 types: &'a TypeList,
2021 offset: usize,
2022 ) -> Result<&'a EntityType> {
2023 match types[self.core_instance_at(instance_index, offset)?]
2024 .as_instance_type()
2025 .unwrap()
2026 .internal_exports(types)
2027 .get(name)
2028 {
2029 Some(export) => Ok(export),
2030 None => bail!(
2031 offset,
2032 "core instance {instance_index} has no export named `{name}`"
2033 ),
2034 }
2035 }
2036
2037 fn global_at(&self, idx: u32, offset: usize) -> Result<&GlobalType> {
2038 match self.core_globals.get(idx as usize) {
2039 Some(t) => Ok(t),
2040 None => bail!(offset, "unknown global {idx}: global index out of bounds"),
2041 }
2042 }
2043
2044 fn table_at(&self, idx: u32, offset: usize) -> Result<&TableType> {
2045 match self.core_tables.get(idx as usize) {
2046 Some(t) => Ok(t),
2047 None => bail!(offset, "unknown table {idx}: table index out of bounds"),
2048 }
2049 }
2050
2051 fn memory_at(&self, idx: u32, offset: usize) -> Result<&MemoryType> {
2052 match self.core_memories.get(idx as usize) {
2053 Some(t) => Ok(t),
2054 None => bail!(offset, "unknown memory {idx}: memory index out of bounds"),
2055 }
2056 }
2057
2058 fn take_component_type(&mut self) -> ComponentType {
2059 let mut ty = ComponentType {
2060 type_size: self.type_size,
2061 imports: Default::default(),
2062 exports: Default::default(),
2063 };
2064
2065 for (name, (url, t, kind)) in mem::take(&mut self.externs) {
2066 let map = match kind {
2067 ExternKind::Import => &mut ty.imports,
2068 ExternKind::Export => &mut ty.exports,
2069 };
2070 let prev = map.insert(name, (url, t));
2071 assert!(prev.is_none());
2072 }
2073
2074 ty
2075 }
2076}
2077
2078impl Default for ComponentState {
2079 fn default() -> Self {
2080 Self {
2081 core_types: Default::default(),
2082 core_modules: Default::default(),
2083 core_instances: Default::default(),
2084 core_funcs: Default::default(),
2085 core_memories: Default::default(),
2086 core_tables: Default::default(),
2087 core_globals: Default::default(),
2088 core_tags: Default::default(),
2089 types: Default::default(),
2090 funcs: Default::default(),
2091 values: Default::default(),
2092 instances: Default::default(),
2093 components: Default::default(),
2094 externs: Default::default(),
2095 export_urls: Default::default(),
2096 import_urls: Default::default(),
2097 has_start: Default::default(),
2098 type_size: 1,
2099 }
2100 }
2101}