Skip to content

Commit

Permalink
feat: add support for stream with no <T> (#1978)
Browse files Browse the repository at this point in the history
* feat: add support for `stream` with no `<T>`

Signed-off-by: Roman Volosatovs <[email protected]>

* test(wit-parser): add a test for `stream`

Signed-off-by: Roman Volosatovs <[email protected]>

---------

Signed-off-by: Roman Volosatovs <[email protected]>
  • Loading branch information
rvolosatovs authored Jan 17, 2025
1 parent a4cd054 commit ad33634
Show file tree
Hide file tree
Showing 25 changed files with 184 additions and 91 deletions.
13 changes: 8 additions & 5 deletions crates/wasm-compose/src/encoding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -813,8 +813,8 @@ impl<'a> TypeEncoder<'a> {
index
}

fn stream(&self, state: &mut TypeState<'a>, ty: ct::ComponentValType) -> u32 {
let ty = self.component_val_type(state, ty);
fn stream(&self, state: &mut TypeState<'a>, ty: Option<ct::ComponentValType>) -> u32 {
let ty = ty.map(|ty| self.component_val_type(state, ty));

let index = state.cur.encodable.type_count();
state.cur.encodable.ty().defined_type().stream(ty);
Expand Down Expand Up @@ -1255,9 +1255,7 @@ impl DependencyRegistrar<'_, '_> {
| ComponentDefinedType::Enum(_)
| ComponentDefinedType::Flags(_)
| ComponentDefinedType::ErrorContext => {}
ComponentDefinedType::List(t)
| ComponentDefinedType::Option(t)
| ComponentDefinedType::Stream(t) => self.val_type(*t),
ComponentDefinedType::List(t) | ComponentDefinedType::Option(t) => self.val_type(*t),
ComponentDefinedType::Own(r) | ComponentDefinedType::Borrow(r) => {
self.ty(ComponentAnyTypeId::Resource(*r))
}
Expand Down Expand Up @@ -1291,6 +1289,11 @@ impl DependencyRegistrar<'_, '_> {
self.val_type(*ty);
}
}
ComponentDefinedType::Stream(ty) => {
if let Some(ty) = ty {
self.val_type(*ty);
}
}
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion crates/wasm-encoder/src/component/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -680,7 +680,7 @@ impl ComponentDefinedTypeEncoder<'_> {
}

/// Define a `stream` type with the specified payload.
pub fn stream(self, payload: ComponentValType) {
pub fn stream(self, payload: Option<ComponentValType>) {
self.0.push(0x66);
payload.encode(self.0);
}
Expand Down
2 changes: 1 addition & 1 deletion crates/wasm-encoder/src/reencode/component.rs
Original file line number Diff line number Diff line change
Expand Up @@ -804,7 +804,7 @@ pub mod component_utils {
defined.future(t.map(|t| reencoder.component_val_type(t)));
}
wasmparser::ComponentDefinedType::Stream(t) => {
defined.stream(reencoder.component_val_type(t));
defined.stream(t.map(|t| reencoder.component_val_type(t)));
}
wasmparser::ComponentDefinedType::ErrorContext => defined.error_context(),
}
Expand Down
2 changes: 1 addition & 1 deletion crates/wasmparser/src/readers/component/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -508,7 +508,7 @@ pub enum ComponentDefinedType<'a> {
/// A future type with the specified payload type.
Future(Option<ComponentValType>),
/// A stream type with the specified payload type.
Stream(ComponentValType),
Stream(Option<ComponentValType>),
/// The error-context type.
ErrorContext,
}
Expand Down
14 changes: 10 additions & 4 deletions crates/wasmparser/src/validator/component.rs
Original file line number Diff line number Diff line change
Expand Up @@ -759,7 +759,10 @@ impl ComponentState {
.as_ref()
.map(|ty| types.type_named_valtype(ty, set))
.unwrap_or(true),
ComponentDefinedType::Stream(ty) => types.type_named_valtype(ty, set),
ComponentDefinedType::Stream(ty) => ty
.as_ref()
.map(|ty| types.type_named_valtype(ty, set))
.unwrap_or(true),
}
}

Expand Down Expand Up @@ -1255,7 +1258,9 @@ impl ComponentState {

let mut info = LoweringInfo::default();
info.requires_memory = true;
info.requires_realloc = payload_type.contains_ptr(types);
info.requires_realloc = payload_type
.map(|ty| ty.contains_ptr(types))
.unwrap_or_default();
self.check_options(None, &info, &options, types, offset, features, true)?;

self.core_funcs
Expand Down Expand Up @@ -1439,7 +1444,7 @@ impl ComponentState {
info.requires_memory = true;
info.requires_realloc = payload_type
.map(|ty| ty.contains_ptr(types))
.unwrap_or(false);
.unwrap_or_default();
self.check_options(None, &info, &options, types, offset, features, true)?;

self.core_funcs
Expand Down Expand Up @@ -3291,7 +3296,8 @@ impl ComponentState {
.transpose()?,
)),
crate::ComponentDefinedType::Stream(ty) => Ok(ComponentDefinedType::Stream(
self.create_component_val_type(ty, offset)?,
ty.map(|ty| self.create_component_val_type(ty, offset))
.transpose()?,
)),
crate::ComponentDefinedType::ErrorContext => Ok(ComponentDefinedType::ErrorContext),
}
Expand Down
39 changes: 25 additions & 14 deletions crates/wasmparser/src/validator/component_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1062,7 +1062,7 @@ pub enum ComponentDefinedType {
/// A future type with the specified payload type.
Future(Option<ComponentValType>),
/// A stream type with the specified payload type.
Stream(ComponentValType),
Stream(Option<ComponentValType>),
/// The error-context type.
ErrorContext,
}
Expand Down Expand Up @@ -1950,9 +1950,7 @@ impl TypeAlloc {
}
}
}
ComponentDefinedType::List(ty)
| ComponentDefinedType::Option(ty)
| ComponentDefinedType::Stream(ty) => {
ComponentDefinedType::List(ty) | ComponentDefinedType::Option(ty) => {
self.free_variables_valtype(ty, set);
}
ComponentDefinedType::Result { ok, err } => {
Expand All @@ -1971,6 +1969,11 @@ impl TypeAlloc {
self.free_variables_valtype(ty, set);
}
}
ComponentDefinedType::Stream(ty) => {
if let Some(ty) = ty {
self.free_variables_valtype(ty, set);
}
}
}
}

Expand Down Expand Up @@ -2094,9 +2097,9 @@ impl TypeAlloc {
.map(|t| self.type_named_valtype(t, set))
.unwrap_or(true)
}
ComponentDefinedType::List(ty)
| ComponentDefinedType::Option(ty)
| ComponentDefinedType::Stream(ty) => self.type_named_valtype(ty, set),
ComponentDefinedType::List(ty) | ComponentDefinedType::Option(ty) => {
self.type_named_valtype(ty, set)
}

// own/borrow themselves don't have to be named, but the resource
// they refer to must be named.
Expand All @@ -2108,6 +2111,11 @@ impl TypeAlloc {
.as_ref()
.map(|ty| self.type_named_valtype(ty, set))
.unwrap_or(true),

ComponentDefinedType::Stream(ty) => ty
.as_ref()
.map(|ty| self.type_named_valtype(ty, set))
.unwrap_or(true),
}
}

Expand Down Expand Up @@ -2277,9 +2285,7 @@ where
}
}
}
ComponentDefinedType::List(ty)
| ComponentDefinedType::Option(ty)
| ComponentDefinedType::Stream(ty) => {
ComponentDefinedType::List(ty) | ComponentDefinedType::Option(ty) => {
any_changed |= self.remap_valtype(ty, map);
}
ComponentDefinedType::Result { ok, err } => {
Expand All @@ -2293,7 +2299,7 @@ where
ComponentDefinedType::Own(id) | ComponentDefinedType::Borrow(id) => {
any_changed |= self.remap_resource_id(id, map);
}
ComponentDefinedType::Future(ty) => {
ComponentDefinedType::Future(ty) | ComponentDefinedType::Stream(ty) => {
if let Some(ty) = ty {
any_changed |= self.remap_valtype(ty, map);
}
Expand Down Expand Up @@ -3234,9 +3240,14 @@ impl<'a> SubtypeCx<'a> {
(Some(_), None) => bail!(offset, "expected future type to not be present"),
},
(Future(_), b) => bail!(offset, "expected {}, found future", b.desc()),
(Stream(a), Stream(b)) => self
.component_val_type(a, b, offset)
.with_context(|| "type mismatch in stream"),
(Stream(a), Stream(b)) => match (a, b) {
(None, None) => Ok(()),
(Some(a), Some(b)) => self
.component_val_type(a, b, offset)
.with_context(|| "type mismatch in stream"),
(None, Some(_)) => bail!(offset, "expected stream type, but found none"),
(Some(_), None) => bail!(offset, "expected stream type to not be present"),
},
(Stream(_), b) => bail!(offset, "expected {}, found stream", b.desc()),
(ErrorContext, ErrorContext) => Ok(()),
(ErrorContext, b) => bail!(offset, "expected {}, found error-context", b.desc()),
Expand Down
10 changes: 7 additions & 3 deletions crates/wasmprinter/src/component.rs
Original file line number Diff line number Diff line change
Expand Up @@ -240,10 +240,14 @@ impl Printer<'_, '_> {
Ok(())
}

fn print_stream_type(&mut self, state: &State, ty: ComponentValType) -> Result<()> {
fn print_stream_type(&mut self, state: &State, ty: Option<ComponentValType>) -> Result<()> {
self.start_group("stream")?;
self.result.write_str(" ")?;
self.print_component_val_type(state, &ty)?;

if let Some(ty) = ty {
self.result.write_str(" ")?;
self.print_component_val_type(state, &ty)?;
}

self.end_group()?;

Ok(())
Expand Down
2 changes: 1 addition & 1 deletion crates/wast/src/component/binary.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ fn encode_defined_type(encoder: ComponentDefinedTypeEncoder, ty: &ComponentDefin
}
ComponentDefinedType::Own(i) => encoder.own((*i).into()),
ComponentDefinedType::Borrow(i) => encoder.borrow((*i).into()),
ComponentDefinedType::Stream(s) => encoder.stream(s.element.as_ref().into()),
ComponentDefinedType::Stream(s) => encoder.stream(s.element.as_deref().map(Into::into)),
ComponentDefinedType::Future(f) => encoder.future(f.element.as_deref().map(Into::into)),
}
}
Expand Down
4 changes: 3 additions & 1 deletion crates/wast/src/component/expand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -762,7 +762,9 @@ impl<'a> Expander<'a> {
}
ComponentDefinedType::Own(_) | ComponentDefinedType::Borrow(_) => {}
ComponentDefinedType::Stream(t) => {
self.expand_component_val_ty(&mut t.element);
if let Some(ty) = &mut t.element {
self.expand_component_val_ty(ty);
}
}
ComponentDefinedType::Future(t) => {
if let Some(ty) = &mut t.element {
Expand Down
4 changes: 3 additions & 1 deletion crates/wast/src/component/resolve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -553,7 +553,9 @@ impl<'a> Resolver<'a> {
self.resolve_ns(t, Ns::Type)?;
}
ComponentDefinedType::Stream(s) => {
self.component_val_type(&mut s.element)?;
if let Some(ty) = &mut s.element {
self.component_val_type(ty)?;
}
}
ComponentDefinedType::Future(f) => {
if let Some(ty) = &mut f.element {
Expand Down
4 changes: 2 additions & 2 deletions crates/wast/src/component/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -694,14 +694,14 @@ impl<'a> Parse<'a> for ResultType<'a> {
#[derive(Debug)]
pub struct Stream<'a> {
/// The element type of the stream.
pub element: Box<ComponentValType<'a>>,
pub element: Option<Box<ComponentValType<'a>>>,
}

impl<'a> Parse<'a> for Stream<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
parser.parse::<kw::stream>()?;
Ok(Self {
element: Box::new(parser.parse()?),
element: parser.parse::<Option<ComponentValType>>()?.map(Box::new),
})
}
}
Expand Down
24 changes: 20 additions & 4 deletions crates/wit-component/src/encoding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1368,15 +1368,31 @@ impl<'a> EncodingState<'a> {
else {
unreachable!()
};
let options = options(self, vec![*payload_type], vec![])?;
let options = options(
self,
if let Some(payload_type) = payload_type {
vec![*payload_type]
} else {
vec![]
},
vec![],
)?;
self.component.stream_write(type_index, options)
}
PayloadFuncKind::StreamRead => {
let TypeDefKind::Stream(payload_type) = &resolve.types[info.ty].kind
else {
unreachable!()
};
let options = options(self, vec![], vec![*payload_type])?;
let options = options(
self,
vec![],
if let Some(payload_type) = payload_type {
vec![*payload_type]
} else {
vec![]
},
)?;
self.component.stream_read(type_index, options)
}
}
Expand Down Expand Up @@ -1443,8 +1459,8 @@ impl<'a> EncodingState<'a> {
fn owner(resolve: &Resolve, ty: TypeId) -> Option<InterfaceId> {
let def = &resolve.types[ty];
match &def.kind {
TypeDefKind::Future(Some(Type::Id(ty))) => owner(resolve, *ty),
TypeDefKind::Stream(Type::Id(ty)) => owner(resolve, *ty),
TypeDefKind::Future(Some(Type::Id(ty)))
| TypeDefKind::Stream(Some(Type::Id(ty))) => owner(resolve, *ty),
_ => match &def.owner {
TypeOwner::World(_) | TypeOwner::None => None,
TypeOwner::Interface(id) => Some(*id),
Expand Down
8 changes: 6 additions & 2 deletions crates/wit-component/src/encoding/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -322,8 +322,12 @@ pub trait ValtypeEncoder<'a> {
Ok(ComponentValType::Type(index))
}

fn encode_stream(&mut self, resolve: &'a Resolve, payload: &Type) -> Result<ComponentValType> {
let ty = self.encode_valtype(resolve, payload)?;
fn encode_stream(
&mut self,
resolve: &'a Resolve,
payload: &Option<Type>,
) -> Result<ComponentValType> {
let ty = self.encode_optional_valtype(resolve, payload.as_ref())?;
let (index, encoder) = self.defined_type();
encoder.stream(ty);
Ok(ComponentValType::Type(index))
Expand Down
27 changes: 19 additions & 8 deletions crates/wit-component/src/printing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -584,9 +584,13 @@ impl<O: Output> WitPrinter<O> {
}
}
TypeDefKind::Stream(ty) => {
self.output.push_str("stream<");
self.print_type_name(resolve, ty)?;
self.output.push_str(">");
if let Some(ty) = ty {
self.output.push_str("stream<");
self.print_type_name(resolve, ty)?;
self.output.push_str(">");
} else {
self.output.push_str("stream");
}
}
TypeDefKind::ErrorContext => self.output.push_str("error-context"),
TypeDefKind::Unknown => unreachable!(),
Expand Down Expand Up @@ -758,7 +762,7 @@ impl<O: Output> WitPrinter<O> {
self.declare_future(resolve, ty.name.as_deref(), inner.as_ref())?
}
TypeDefKind::Stream(inner) => {
self.declare_stream(resolve, ty.name.as_deref(), inner)?
self.declare_stream(resolve, ty.name.as_deref(), inner.as_ref())?
}
TypeDefKind::ErrorContext => self.declare_error_context(ty.name.as_deref())?,
TypeDefKind::Unknown => unreachable!(),
Expand Down Expand Up @@ -957,16 +961,23 @@ impl<O: Output> WitPrinter<O> {
Ok(())
}

fn declare_stream(&mut self, resolve: &Resolve, name: Option<&str>, ty: &Type) -> Result<()> {
fn declare_stream(
&mut self,
resolve: &Resolve,
name: Option<&str>,
ty: Option<&Type>,
) -> Result<()> {
if let Some(name) = name {
self.output.keyword("type");
self.output.str(" ");
self.print_name_type(name, TypeKind::Stream);
self.output.str(" = ");
self.output.ty("stream", TypeKind::BuiltIn);
self.output.str("<");
self.print_type_name(resolve, ty)?;
self.output.str(">");
if let Some(ty) = ty {
self.output.str("<");
self.print_type_name(resolve, ty)?;
self.output.str(">");
}
self.output.semicolon();
}

Expand Down
4 changes: 2 additions & 2 deletions crates/wit-encoder/src/from_parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ impl<'a> Converter<'a> {
TypeDefKind::Type(Type::future(self.convert_option_type(ty)))
}
wit_parser::TypeDefKind::Stream(ty) => {
TypeDefKind::Type(Type::stream(self.convert_type(ty)))
TypeDefKind::Type(Type::stream(self.convert_option_type(ty)))
}
wit_parser::TypeDefKind::ErrorContext => TypeDefKind::Type(Type::ErrorContext),
// all the following are just `type` declarations
Expand Down Expand Up @@ -309,7 +309,7 @@ impl<'a> Converter<'a> {
Type::future(self.convert_option_type(type_))
}
wit_parser::TypeDefKind::Stream(type_) => {
Type::stream(self.convert_type(type_))
Type::stream(self.convert_option_type(type_))
}
wit_parser::TypeDefKind::ErrorContext => Type::ErrorContext,
wit_parser::TypeDefKind::Record(_)
Expand Down
Loading

0 comments on commit ad33634

Please sign in to comment.