-
Notifications
You must be signed in to change notification settings - Fork 312
Impl imports #1146
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
Impl imports #1146
Conversation
I noticed that currently in bytecodealliance#1146 the CI there is green but some files are unformatted which got me wondering why that was the case. Turns out that `cargo fmt` won't find files that are referenced through macro-expanded macros, meaning that most of `wast` isn't actually checked for formatting on CI. This commit fixes that.
alexcrichton
left a comment
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.
Thanks! I think it would be good to add a suite of tests for this too. Adding files to tests/local/component-model/*.wast should be good enough. It'll be good to exercise the text parsing, binary encoding, binary validation, and text printing for all of this.
|
Oh one other comment I'd recommend is to configure your text editor to rustfmt-on-save since there's some un-formatted files here which will get flagged on CI once #1174 merges |
I noticed that currently in #1146 the CI there is green but some files are unformatted which got me wondering why that was the case. Turns out that `cargo fmt` won't find files that are referenced through macro-expanded macros, meaning that most of `wast` isn't actually checked for formatting on CI. This commit fixes that.
e932d23 to
a10792e
Compare
ff75590 to
298aeef
Compare
| pub trait AsComponentExternName { | ||
| /// Converts this receiver into a `ComponentExternName`. | ||
| fn as_component_extern_name(&self) -> ComponentExternName<'_>; | ||
| pub trait AsComponentImportName { |
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.
This made sense beforehand since the kebab/interface distinction was easy to differentiate between. Now though it's slightly more complicated where a single-string as an import could either be Kebab, Interface, or Unlocked. While / or : means it's definitely not Kebab I don't believe there's any means, in isolation, to tell the difference between Unlocked and Interface. For example a:b/c could be either I believe.
In that sense I think this trait should be removed and consumers relying on it are going to have to use the more verbose form to select which import form they intended to use.
| pub fn from_export(name: ComponentExportName<'_>, offset: usize) -> Result<KebabName> { | ||
| let validate_kebab = |s: &str| { | ||
| if KebabStr::new(s).is_none() { | ||
| bail!(offset, "`{s}` is not in kebab case") | ||
| } else { | ||
| Ok(()) | ||
| } | ||
| }; | ||
| let find = |s: &str, c: char| match s.find(c) { | ||
| Some(i) => Ok(i), | ||
| None => bail!(offset, "failed to find `{c}` character"), | ||
| }; | ||
|
|
||
| let parsed = match name { | ||
| ComponentExportName::Kebab(s) => { | ||
| if let Some(s) = s.strip_prefix(CONSTRUCTOR) { | ||
| validate_kebab(s)?; | ||
| ParsedKebabName::Constructor | ||
| } else if let Some(s) = s.strip_prefix(METHOD) { | ||
| let dot = find(s, '.')?; | ||
| validate_kebab(&s[..dot])?; | ||
| validate_kebab(&s[dot + 1..])?; | ||
| ParsedKebabName::Method { dot: dot as u32 } | ||
| } else if let Some(s) = s.strip_prefix(STATIC) { | ||
| let dot = find(s, '.')?; | ||
| validate_kebab(&s[..dot])?; | ||
| validate_kebab(&s[dot + 1..])?; | ||
| ParsedKebabName::Static { dot: dot as u32 } | ||
| } else { | ||
| validate_kebab(s)?; | ||
| ParsedKebabName::Normal | ||
| } | ||
| } | ||
| ComponentExportName::Interface(s) => { | ||
| let colon = find(s, ':')?; | ||
| validate_kebab(&s[..colon])?; | ||
| let slash = find(s, '/')?; | ||
| let at = s[slash..].find('@').map(|i| i + slash); | ||
| validate_kebab(&s[colon + 1..slash])?; | ||
| validate_kebab(&s[slash + 1..at.unwrap_or(s.len())])?; | ||
| if let Some(at) = at { | ||
| let version = &s[at + 1..]; | ||
| let version = version.parse::<Version>(); | ||
| match version { | ||
| Ok(ver) => ParsedKebabName::RegistryId { | ||
| colon: colon as u32, | ||
| slash: Some(slash as u32), | ||
| at: Some(At { | ||
| index: at as u32, | ||
| semver: Semver::Semver(ver), | ||
| }), | ||
| }, | ||
| Err(e) => { | ||
| bail!(offset, "failed to parse version: {e}") | ||
| } | ||
| } | ||
| } else { | ||
| ParsedKebabName::RegistryId { | ||
| colon: colon as u32, | ||
| slash: Some(slash as u32), | ||
| at: None, | ||
| } | ||
| } | ||
| } | ||
| }; | ||
| Ok(KebabName { | ||
| raw: name.as_str().to_string(), | ||
| parsed, | ||
| }) | ||
| } |
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.
I believe this method is largely duplicated with the one below, but could the duplication be removed?
| package: &'a KebabStr, | ||
| interface: &'a KebabStr, | ||
| version: Option<Version>, | ||
| interface: Option<&'a KebabStr>, |
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.
To keep things somewhat simpler for now could this be left as &'a KebabStr and effectively only a:b/c works today?
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.
The primary motivator here was that when actually using the new implementation imports, there is no / generally. For example, unlocked imports tend to look something like
(import (unlocked-dep "foo:five@{>=2.0.0 <3.0.0}") (instance (;0;) (type 1)))
It definitely would be nice to simplify if possible, as I added a lot of checks elsewhere to enable the optionality here, but I'm not sure the best way to go about that while simultaneously supporting this use case.
| ComponentImportName::Unlocked(name) => { | ||
| let colon = find(name, ':')?; | ||
| validate_kebab(&name[..colon])?; | ||
| let slash = maybe_find(name, '/'); | ||
| if let Some(sl) = slash { | ||
| let at = name[sl..].find('@').map(|i| i + sl); | ||
| validate_kebab(&name[colon + 1..sl])?; | ||
| if let Some(at) = at { | ||
| validate_kebab(&name[sl + 1..at])?; | ||
| let version_string = validate_version_range(&name[at + 1..])?; | ||
| ParsedKebabName::RegistryId { | ||
| colon: colon as u32, | ||
| slash: Some(sl as u32), | ||
| at: Some(At { | ||
| index: at as u32, | ||
| semver: Semver::SemverRange(version_string), | ||
| }), | ||
| } | ||
| } else { | ||
| ParsedKebabName::RegistryId { | ||
| colon: colon as u32, | ||
| slash: Some(sl as u32), | ||
| at: None, | ||
| } | ||
| } | ||
| } else { | ||
| let at = name[colon..].find('@').map(|i| i + colon); | ||
| if let Some(at) = at { | ||
| validate_kebab(&name[colon + 1..at])?; | ||
| let version_string = validate_version_range(&name[at + 1..])?; | ||
| ParsedKebabName::RegistryId { | ||
| colon: colon as u32, | ||
| slash: None, | ||
| at: Some(At { | ||
| index: at as u32, | ||
| semver: Semver::SemverRange(version_string), | ||
| }), | ||
| } | ||
| } else { | ||
| ParsedKebabName::RegistryId { | ||
| colon: colon as u32, | ||
| slash: None, | ||
| at: None, | ||
| } | ||
| } | ||
| } |
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.
I believe this is the more-or-less the same parsing code as Locked, so could those be deduplicated?
| impl PartialEq for Semver { | ||
| fn eq(&self, other: &Semver) -> bool { | ||
| match self { | ||
| Self::Semver(version) => match other { | ||
| Semver::Semver(other_version) => version == other_version, | ||
| Semver::SemverRange(_) => false, | ||
| }, | ||
| Self::SemverRange(version_range) => match other { | ||
| Semver::Semver(_) => false, | ||
| Semver::SemverRange(other_range) => version_range == other_range, | ||
| }, | ||
| } | ||
| } | ||
| } |
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.
I think this can be replaced with #[derive(PartialEq)] on the type?
|
If you'd like I don't mind taking it from here and landing this as well. Implementing these sorts of changes can be pretty tricky so I don't want to put too much on you by accident |
* Fold the `Naked` case into the preexisting `Kebab` case with a new payload. * Parse `integrity` with surrounding parens * Make the `integrity` field on `Locked` optional
|
If it's ok with you @macovedj I'd prefer to hold off on this until WebAssembly/component-model#253 is resolved since that will change the binary and textual syntax of imports again. Additionally it will likely change the internals of representation within |
Makes sense to me! |
|
I've opened up #1262 which is intended to be the successor to this PR which catches up with other component model developments as well |
This PR can serve as an implementation of what is proposed here.