-
Notifications
You must be signed in to change notification settings - Fork 345
Implement canonical interface names in wit-component #2622
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 10 commits
ffbcaab
43279e9
85c1f27
33eb861
2eec02e
b5eddd3
7524b35
54492be
523adc4
c056255
83a647f
a46e340
3ba5de1
0b6fa64
637d04a
b5b707a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -25,7 +25,16 @@ use wit_parser::*; | |
| /// The binary returned can be [`decode`d](crate::decode) to recover the WIT | ||
| /// package provided. | ||
| pub fn encode(resolve: &Resolve, package: PackageId) -> Result<Vec<u8>> { | ||
| let mut component = encode_component(resolve, package)?; | ||
| encode_with_options(resolve, package, false) | ||
| } | ||
|
|
||
| /// Same as [`encode`] but with an option to emit canonical interface names. | ||
| pub fn encode_with_options( | ||
| resolve: &Resolve, | ||
| package: PackageId, | ||
| canonical_names: bool, | ||
|
alexcrichton marked this conversation as resolved.
Outdated
|
||
| ) -> Result<Vec<u8>> { | ||
| let mut component = encode_component_with_options(resolve, package, canonical_names)?; | ||
| component.raw_custom_section(&crate::base_producers().raw_custom_section()); | ||
| Ok(component.finish()) | ||
| } | ||
|
|
@@ -48,11 +57,16 @@ pub fn encode(resolve: &Resolve, package: PackageId) -> Result<Vec<u8>> { | |
| /// | ||
| /// The binary returned can be [`decode`d](crate::decode) to recover the WIT | ||
| /// package provided. | ||
| pub fn encode_component(resolve: &Resolve, package: PackageId) -> Result<ComponentBuilder> { | ||
| pub fn encode_component_with_options( | ||
| resolve: &Resolve, | ||
| package: PackageId, | ||
| canonical_names: bool, | ||
| ) -> Result<ComponentBuilder> { | ||
| let mut encoder = Encoder { | ||
| component: ComponentBuilder::default(), | ||
| resolve, | ||
| package, | ||
| canonical_names, | ||
| }; | ||
| encoder.run()?; | ||
|
|
||
|
|
@@ -67,6 +81,15 @@ pub fn encode_component(resolve: &Resolve, package: PackageId) -> Result<Compone | |
|
|
||
| /// Encodes a `world` as a component type. | ||
| pub fn encode_world(resolve: &Resolve, world_id: WorldId) -> Result<ComponentType> { | ||
| encode_world_with_options(resolve, world_id, false) | ||
| } | ||
|
|
||
| /// Same as [`encode_world`] but with an option to emit canonical names. | ||
| pub fn encode_world_with_options( | ||
| resolve: &Resolve, | ||
| world_id: WorldId, | ||
| canonical_names: bool, | ||
| ) -> Result<ComponentType> { | ||
| let mut component = InterfaceEncoder::new(resolve); | ||
| let world = &resolve.worlds[world_id]; | ||
| log::trace!("encoding world {}", world.name); | ||
|
|
@@ -93,9 +116,10 @@ pub fn encode_world(resolve: &Resolve, world_id: WorldId) -> Result<ComponentTyp | |
| continue; | ||
| } | ||
| }; | ||
| component | ||
| .outer | ||
| .import(component_extern_name(resolve, key, import), ty); | ||
| component.outer.import( | ||
| component_extern_name(resolve, key, import, canonical_names), | ||
| ty, | ||
| ); | ||
| } | ||
| // Encode the exports | ||
| for (key, export) in world.exports.iter() { | ||
|
|
@@ -113,9 +137,10 @@ pub fn encode_world(resolve: &Resolve, world_id: WorldId) -> Result<ComponentTyp | |
| } | ||
| WorldItem::Type { .. } => unreachable!(), | ||
| }; | ||
| component | ||
| .outer | ||
| .export(component_extern_name(resolve, key, export), ty); | ||
| component.outer.export( | ||
| component_extern_name(resolve, key, export, canonical_names), | ||
| ty, | ||
| ); | ||
| } | ||
|
|
||
| Ok(component.outer) | ||
|
|
@@ -125,19 +150,31 @@ fn component_extern_name( | |
| resolve: &Resolve, | ||
| key: &WorldKey, | ||
| item: &WorldItem, | ||
| canonical_names: bool, | ||
| ) -> wasm_encoder::ComponentExternName<'static> { | ||
| ComponentExternName { | ||
| name: resolve.name_world_key(key).into(), | ||
| implements: resolve.implements_value(key, item).map(|s| s.into()), | ||
| external_id: resolve.external_id_value(key, item).map(|s| s.into()), | ||
| version_suffix: None, | ||
| let implements = resolve.implements_interface(key, item); | ||
| if canonical_names { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In a previous review I was curiuos if it would be possible to deduplicate the number of places that a canonical-names option was taken into account and a
Were you able to take a look and see if these locations could be unified? Is there perhaps one, or maybe two at most, helpers that could be used to construct these names?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Will think about it tomorrow. |
||
| ComponentExternName { | ||
| name: resolve.name_canonicalized_world_key(key).into(), | ||
| implements: implements.map(|id| resolve.canonicalized_id_of(id).unwrap().into()), | ||
| external_id: resolve.external_id_value(key, item).map(|s| s.into()), | ||
| version_suffix: resolve.version_suffix_value(key, item).map(|s| s.into()), | ||
| } | ||
| } else { | ||
| ComponentExternName { | ||
| name: resolve.name_world_key(key).into(), | ||
| implements: implements.map(|id| resolve.id_of(id).unwrap().into()), | ||
| external_id: resolve.external_id_value(key, item).map(|s| s.into()), | ||
| version_suffix: None, | ||
| } | ||
| } | ||
| } | ||
|
|
||
| struct Encoder<'a> { | ||
| component: ComponentBuilder, | ||
| resolve: &'a Resolve, | ||
| package: PackageId, | ||
| canonical_names: bool, | ||
| } | ||
|
|
||
| impl Encoder<'_> { | ||
|
|
@@ -153,7 +190,8 @@ impl Encoder<'_> { | |
| // For each `world` encode it directly as a component and then create a | ||
| // wrapper component that exports that component. | ||
| for (name, &world) in self.resolve.packages[self.package].worlds.iter() { | ||
| let component_ty = encode_world(self.resolve, world)?; | ||
| let component_ty = | ||
| encode_world_with_options(self.resolve, world, self.canonical_names)?; | ||
|
|
||
| let world = &self.resolve.worlds[world]; | ||
| let mut wrapper = ComponentType::new(); | ||
|
|
@@ -197,11 +235,24 @@ impl Encoder<'_> { | |
| for interface in interfaces { | ||
| encoder.interface = Some(interface); | ||
| let iface = &self.resolve.interfaces[interface]; | ||
| let name = self.resolve.id_of(interface).unwrap(); | ||
| let extern_name = if self.canonical_names { | ||
| let name = self.resolve.canonicalized_id_of(interface).unwrap(); | ||
| let version_suffix = self.resolve.version_suffix_of(interface); | ||
| ComponentExternName { | ||
| name: name.into(), | ||
| implements: None, | ||
| external_id: None, | ||
| version_suffix: version_suffix.map(|s| s.into()), | ||
| } | ||
| } else { | ||
| ComponentExternName::from(self.resolve.id_of(interface).unwrap()) | ||
| }; | ||
| if interface == id { | ||
| let idx = encoder.encode_instance(interface)?; | ||
| log::trace!("exporting self as {idx}"); | ||
| encoder.outer.export(name, ComponentTypeRef::Instance(idx)); | ||
| encoder | ||
| .outer | ||
| .export(extern_name, ComponentTypeRef::Instance(idx)); | ||
| } else { | ||
| encoder.push_instance(); | ||
| for (_, id) in iface.types.iter() { | ||
|
|
@@ -212,7 +263,9 @@ impl Encoder<'_> { | |
| encoder.outer.ty().instance(&instance); | ||
| encoder.import_map.insert(interface, encoder.instances); | ||
| encoder.instances += 1; | ||
| encoder.outer.import(name, ComponentTypeRef::Instance(idx)); | ||
| encoder | ||
| .outer | ||
| .import(extern_name, ComponentTypeRef::Instance(idx)); | ||
| } | ||
| } | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could this validation move up to the above method? I think it'd be a bit clearer to perform this validation when
implementsis specified rather than deferring it to happen later here. That'd probably require validating theversion_suffixfield beforeimplementsand reorderin the aboveifstatements, but that should be fine to do.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done. Neither way is perfect. We validate
version_suffixwithComponentNamehere. Ideally, we would also validate the suffix with implements here. But moving up does make a smaller diff.