Skip to content

Commit 4cb6e03

Browse files
cpetigalexcrichton
andauthored
Fixed length list support (#1992)
* support fixed length lists, part 1 * more fixed size * fix tests for wit-parser * re-implement as two separate types (outside of WIT) * adapt the tests for the new type * handle reading correctly * wat parsing * generate fixed size lists in wit-smith * proper rustfmt (whitespace change) * implement Alex' suggetions, part one * implement roundtrip tests * limit the maximum size of a fixed list. to avoid memory explosion at parsing * separate list types, as proposed by Alex * post-rebase fixes * fix the tests * Move local test to CLI test * use same command line order as proposed by Alex * prefer the name chosen by Alex * apply missing changes by Alex (I should have fetched before rebase) * limit the size of flattened fixed size lists, forbid empty ones * test for zero and too high number * check for type mismatch during composition * clearly separate list from fixed-size-list in code * separate list types in encoder as well * manually run rustfmt --------- Co-authored-by: Alex Crichton <[email protected]>
1 parent 2dc1c57 commit 4cb6e03

File tree

46 files changed

+621
-44
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+621
-44
lines changed

crates/wasm-compose/src/encoding.rs

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -649,6 +649,9 @@ impl<'a> TypeEncoder<'a> {
649649
ComponentDefinedType::Record(r) => self.record(state, r),
650650
ComponentDefinedType::Variant(v) => self.variant(state, v),
651651
ComponentDefinedType::List(ty) => self.list(state, *ty),
652+
ComponentDefinedType::FixedSizeList(ty, elements) => {
653+
self.fixed_size_list(state, *ty, *elements)
654+
}
652655
ComponentDefinedType::Tuple(t) => self.tuple(state, t),
653656
ComponentDefinedType::Flags(names) => Self::flags(&mut state.cur.encodable, names),
654657
ComponentDefinedType::Enum(cases) => Self::enum_type(&mut state.cur.encodable, cases),
@@ -709,6 +712,23 @@ impl<'a> TypeEncoder<'a> {
709712
index
710713
}
711714

715+
fn fixed_size_list(
716+
&self,
717+
state: &mut TypeState<'a>,
718+
ty: ct::ComponentValType,
719+
elements: u32,
720+
) -> u32 {
721+
let ty = self.component_val_type(state, ty);
722+
let index = state.cur.encodable.type_count();
723+
state
724+
.cur
725+
.encodable
726+
.ty()
727+
.defined_type()
728+
.fixed_size_list(ty, elements);
729+
index
730+
}
731+
712732
fn tuple(&self, state: &mut TypeState<'a>, tuple: &TupleType) -> u32 {
713733
let types = tuple
714734
.types
@@ -1228,7 +1248,9 @@ impl DependencyRegistrar<'_, '_> {
12281248
ComponentDefinedType::Primitive(_)
12291249
| ComponentDefinedType::Enum(_)
12301250
| ComponentDefinedType::Flags(_) => {}
1231-
ComponentDefinedType::List(t) | ComponentDefinedType::Option(t) => self.val_type(*t),
1251+
ComponentDefinedType::List(t)
1252+
| ComponentDefinedType::FixedSizeList(t, _)
1253+
| ComponentDefinedType::Option(t) => self.val_type(*t),
12321254
ComponentDefinedType::Own(r) | ComponentDefinedType::Borrow(r) => {
12331255
self.ty(ComponentAnyTypeId::Resource(*r))
12341256
}

crates/wasm-encoder/src/component/types.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -593,6 +593,13 @@ impl ComponentDefinedTypeEncoder<'_> {
593593
ty.into().encode(self.0);
594594
}
595595

596+
/// Define a fixed size list type.
597+
pub fn fixed_size_list(self, ty: impl Into<ComponentValType>, elements: u32) {
598+
self.0.push(0x67);
599+
ty.into().encode(self.0);
600+
elements.encode(self.0);
601+
}
602+
596603
/// Define a tuple type.
597604
pub fn tuple<I, T>(self, types: I)
598605
where

crates/wasm-encoder/src/reencode/component.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -767,6 +767,9 @@ pub mod component_utils {
767767
wasmparser::ComponentDefinedType::List(t) => {
768768
defined.list(reencoder.component_val_type(t));
769769
}
770+
wasmparser::ComponentDefinedType::FixedSizeList(t, elements) => {
771+
defined.fixed_size_list(reencoder.component_val_type(t), elements);
772+
}
770773
wasmparser::ComponentDefinedType::Tuple(t) => {
771774
defined.tuple(t.iter().map(|t| reencoder.component_val_type(*t)));
772775
}

crates/wasm-wave/src/value/ty.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ pub struct Type(pub(super) TypeEnum);
1010
pub(super) enum TypeEnum {
1111
Simple(SimpleType),
1212
List(Arc<ListType>),
13+
FixedSizeList(Arc<ListType>, u32),
1314
Record(Arc<RecordType>),
1415
Tuple(Arc<TupleType>),
1516
Variant(Arc<VariantType>),
@@ -55,6 +56,15 @@ impl Type {
5556
Self(TypeEnum::List(Arc::new(ListType { element })))
5657
}
5758

59+
/// Returns a list type with the given element type.
60+
pub fn fixed_size_list(element_type: impl Into<Self>, elements: u32) -> Self {
61+
let element = element_type.into();
62+
Self(TypeEnum::FixedSizeList(
63+
Arc::new(ListType { element }),
64+
elements,
65+
))
66+
}
67+
5868
/// Returns a record type with the given field types. Returns None if
5969
/// `fields` is empty.
6070
pub fn record<T: Into<Box<str>>>(
@@ -189,6 +199,7 @@ impl WasmType for Type {
189199
match self.0 {
190200
TypeEnum::Simple(simple) => simple.0,
191201
TypeEnum::List(_) => WasmTypeKind::List,
202+
TypeEnum::FixedSizeList(_, _) => WasmTypeKind::FixedSizeList,
192203
TypeEnum::Record(_) => WasmTypeKind::Record,
193204
TypeEnum::Tuple(_) => WasmTypeKind::Tuple,
194205
TypeEnum::Variant(_) => WasmTypeKind::Variant,

crates/wasm-wave/src/value/wit.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,9 @@ impl<'a> TypeResolver<'a> {
7070
TypeDefKind::Option(some_type) => self.resolve_option(some_type),
7171
TypeDefKind::Result(result) => self.resolve_result(result),
7272
TypeDefKind::List(element_type) => self.resolve_list(element_type),
73+
TypeDefKind::FixedSizeList(element_type, elements) => {
74+
self.resolve_fixed_size_list(element_type, *elements)
75+
}
7376
TypeDefKind::Type(Type::Bool) => Ok(value::Type::BOOL),
7477
TypeDefKind::Type(Type::U8) => Ok(value::Type::U8),
7578
TypeDefKind::Type(Type::U16) => Ok(value::Type::U16),
@@ -145,6 +148,11 @@ impl<'a> TypeResolver<'a> {
145148
let element_type = self.resolve_type(*element_type)?;
146149
Ok(value::Type::list(element_type))
147150
}
151+
152+
fn resolve_fixed_size_list(&self, element_type: &Type, elements: u32) -> ValueResult {
153+
let element_type = self.resolve_type(*element_type)?;
154+
Ok(value::Type::fixed_size_list(element_type, elements))
155+
}
148156
}
149157

150158
#[cfg(test)]

crates/wasm-wave/src/wasm/ty.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ pub enum WasmTypeKind {
2020
Char,
2121
String,
2222
List,
23+
FixedSizeList,
2324
Record,
2425
Tuple,
2526
Variant,
@@ -48,6 +49,7 @@ impl std::fmt::Display for WasmTypeKind {
4849
WasmTypeKind::Char => "char",
4950
WasmTypeKind::String => "string",
5051
WasmTypeKind::List => "list",
52+
WasmTypeKind::FixedSizeList => "list<_,N>",
5153
WasmTypeKind::Record => "record",
5254
WasmTypeKind::Tuple => "tuple",
5355
WasmTypeKind::Variant => "variant",

crates/wasm-wave/src/writer.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,16 @@ impl<W: Write> Writer<W> {
7575
}
7676
self.write_str("]")
7777
}
78+
WasmTypeKind::FixedSizeList => {
79+
self.write_str("[")?;
80+
for (idx, val) in val.unwrap_list().enumerate() {
81+
if idx != 0 {
82+
self.write_str(", ")?;
83+
}
84+
self.write_value(&*val)?;
85+
}
86+
self.write_str("]")
87+
}
7888
WasmTypeKind::Record => {
7989
self.write_str("{")?;
8090
let mut first = true;

crates/wasmparser/src/features.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,11 @@ define_wasm_features! {
254254
/// Corresponds to the 📝 character in
255255
/// <https://github.com/WebAssembly/component-model/blob/main/design/mvp/Explainer.md>.
256256
pub cm_error_context: CM_ERROR_CONTEXT(1 << 30) = false;
257+
/// Support for fixed size lists
258+
///
259+
/// Corresponds to the 🔧 character in
260+
/// <https://github.com/WebAssembly/component-model/blob/main/design/mvp/Explainer.md>.
261+
pub cm_fixed_size_list: CM_FIXED_SIZE_LIST(1 << 31) = false;
257262
}
258263
}
259264

crates/wasmparser/src/readers/component/types.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -441,6 +441,8 @@ pub enum ComponentDefinedType<'a> {
441441
Variant(Box<[VariantCase<'a>]>),
442442
/// The type is a list of the given value type.
443443
List(ComponentValType),
444+
/// The type is a fixed size list of the given value type.
445+
FixedSizeList(ComponentValType, u32),
444446
/// The type is a tuple of the given value types.
445447
Tuple(Box<[ComponentValType]>),
446448
/// The type is flags with the given names.
@@ -503,8 +505,9 @@ impl<'a> ComponentDefinedType<'a> {
503505
},
504506
0x69 => ComponentDefinedType::Own(reader.read()?),
505507
0x68 => ComponentDefinedType::Borrow(reader.read()?),
506-
0x65 => ComponentDefinedType::Future(reader.read()?),
508+
0x67 => ComponentDefinedType::FixedSizeList(reader.read()?, reader.read_var_u32()?),
507509
0x66 => ComponentDefinedType::Stream(reader.read()?),
510+
0x65 => ComponentDefinedType::Future(reader.read()?),
508511
x => return reader.invalid_leading_byte(x, "component defined type"),
509512
})
510513
}

crates/wasmparser/src/validator/component.rs

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -724,9 +724,9 @@ impl ComponentState {
724724
.map(|t| types.type_named_valtype(t, set))
725725
.unwrap_or(true)
726726
}
727-
ComponentDefinedType::List(ty) | ComponentDefinedType::Option(ty) => {
728-
types.type_named_valtype(ty, set)
729-
}
727+
ComponentDefinedType::List(ty)
728+
| ComponentDefinedType::FixedSizeList(ty, _)
729+
| ComponentDefinedType::Option(ty) => types.type_named_valtype(ty, set),
730730

731731
// The resource referred to by own/borrow must be named.
732732
ComponentDefinedType::Own(id) | ComponentDefinedType::Borrow(id) => {
@@ -3475,6 +3475,21 @@ impl ComponentState {
34753475
crate::ComponentDefinedType::List(ty) => Ok(ComponentDefinedType::List(
34763476
self.create_component_val_type(ty, offset)?,
34773477
)),
3478+
crate::ComponentDefinedType::FixedSizeList(ty, elements) => {
3479+
if !self.features.cm_fixed_size_list() {
3480+
bail!(
3481+
offset,
3482+
"Fixed size lists require the component model fixed size list feature"
3483+
)
3484+
}
3485+
if elements < 1 {
3486+
bail!(offset, "Fixed size lists must have more than zero elements")
3487+
}
3488+
Ok(ComponentDefinedType::FixedSizeList(
3489+
self.create_component_val_type(ty, offset)?,
3490+
elements,
3491+
))
3492+
}
34783493
crate::ComponentDefinedType::Tuple(tys) => {
34793494
self.create_tuple_type(tys.as_ref(), types, offset)
34803495
}

0 commit comments

Comments
 (0)