wit-bindgen-core
Advanced tools
| { | ||
| "git": { | ||
| "sha1": "3dfc82a753ac7e514802a618ddedb24dd51048fe" | ||
| "sha1": "51080a08cafd3e056abf17f75bf9b7a01a98a8a7" | ||
| }, | ||
| "path_in_vcs": "crates/core" | ||
| } |
+17
-7
@@ -120,2 +120,8 @@ # This file is automatically @generated by Cargo. | ||
| [[package]] | ||
| name = "foldhash" | ||
| version = "0.2.0" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" | ||
| [[package]] | ||
| name = "hashbrown" | ||
@@ -125,2 +131,5 @@ version = "0.16.1" | ||
| checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" | ||
| dependencies = [ | ||
| "foldhash", | ||
| ] | ||
@@ -135,5 +144,5 @@ [[package]] | ||
| name = "id-arena" | ||
| version = "2.2.1" | ||
| version = "2.3.0" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "25a2bc672d1148e28034f176e01fffebb08b35768468cc954630da77a1449005" | ||
| checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" | ||
@@ -286,5 +295,5 @@ [[package]] | ||
| name = "wasmparser" | ||
| version = "0.244.0" | ||
| version = "0.245.0" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" | ||
| checksum = "48a767a48974f0c8b66f211b96e01aa77feed58b8ccce4e7f0cff0ae55b174d4" | ||
| dependencies = [ | ||
@@ -313,3 +322,3 @@ "bitflags", | ||
| name = "wit-bindgen-core" | ||
| version = "0.52.0" | ||
| version = "0.53.0" | ||
| dependencies = [ | ||
@@ -325,7 +334,8 @@ "anyhow", | ||
| name = "wit-parser" | ||
| version = "0.244.0" | ||
| version = "0.245.0" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" | ||
| checksum = "b5cda4f69fdc5a8d54f7032262217dd89410a933e3f86fdad854f5833caf3ccb" | ||
| dependencies = [ | ||
| "anyhow", | ||
| "hashbrown", | ||
| "id-arena", | ||
@@ -332,0 +342,0 @@ "indexmap", |
+2
-2
@@ -16,3 +16,3 @@ # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO | ||
| name = "wit-bindgen-core" | ||
| version = "0.52.0" | ||
| version = "0.53.0" | ||
| authors = ["Alex Crichton <alex@alexcrichton.com>"] | ||
@@ -61,3 +61,3 @@ build = false | ||
| [dependencies.wit-parser] | ||
| version = "0.244.0" | ||
| version = "0.245.0" | ||
@@ -64,0 +64,0 @@ [lints.clippy] |
+40
-23
@@ -26,3 +26,6 @@ use std::fmt::Write; | ||
| pub trait WorldGenerator { | ||
| fn generate(&mut self, resolve: &Resolve, id: WorldId, files: &mut Files) -> Result<()> { | ||
| fn generate(&mut self, resolve: &mut Resolve, id: WorldId, files: &mut Files) -> Result<()> { | ||
| if self.uses_nominal_type_ids() { | ||
| resolve.generate_nominal_type_ids(id); | ||
| } | ||
| let world = &resolve.worlds[id]; | ||
@@ -46,3 +49,3 @@ self.preprocess(resolve, id); | ||
| } | ||
| WorldItem::Type(id) => types.push((unwrap_name(name), *id)), | ||
| WorldItem::Type { id, .. } => types.push((unwrap_name(name), *id)), | ||
| } | ||
@@ -71,3 +74,3 @@ } | ||
| WorldItem::Interface { id, .. } => interfaces.push((name, id)), | ||
| WorldItem::Type(_) => unreachable!(), | ||
| WorldItem::Type { .. } => unreachable!(), | ||
| } | ||
@@ -87,2 +90,9 @@ } | ||
| /// Whether or not this bindings generator expects | ||
| /// [`Resolve::generate_nominal_type_ids`] to be used before generating | ||
| /// bindings. | ||
| fn uses_nominal_type_ids(&self) -> bool { | ||
| true | ||
| } | ||
| fn finish_imports(&mut self, resolve: &Resolve, world: WorldId, files: &mut Files) { | ||
@@ -173,24 +183,31 @@ let _ = (resolve, world, files); | ||
| fn define_type(&mut self, name: &str, id: TypeId) { | ||
| let ty = &self.resolve().types[id]; | ||
| match &ty.kind { | ||
| TypeDefKind::Record(record) => self.type_record(id, name, record, &ty.docs), | ||
| TypeDefKind::Resource => self.type_resource(id, name, &ty.docs), | ||
| TypeDefKind::Flags(flags) => self.type_flags(id, name, flags, &ty.docs), | ||
| TypeDefKind::Tuple(tuple) => self.type_tuple(id, name, tuple, &ty.docs), | ||
| TypeDefKind::Enum(enum_) => self.type_enum(id, name, enum_, &ty.docs), | ||
| TypeDefKind::Variant(variant) => self.type_variant(id, name, variant, &ty.docs), | ||
| TypeDefKind::Option(t) => self.type_option(id, name, t, &ty.docs), | ||
| TypeDefKind::Result(r) => self.type_result(id, name, r, &ty.docs), | ||
| TypeDefKind::List(t) => self.type_list(id, name, t, &ty.docs), | ||
| TypeDefKind::Type(t) => self.type_alias(id, name, t, &ty.docs), | ||
| TypeDefKind::Future(t) => self.type_future(id, name, t, &ty.docs), | ||
| TypeDefKind::Stream(t) => self.type_stream(id, name, t, &ty.docs), | ||
| TypeDefKind::Handle(_) => panic!("handle types do not require definition"), | ||
| TypeDefKind::FixedSizeList(..) => todo!(), | ||
| TypeDefKind::Map(..) => todo!(), | ||
| TypeDefKind::Unknown => unreachable!(), | ||
| } | ||
| define_type(self, name, id) | ||
| } | ||
| } | ||
| pub fn define_type<'a, T>(generator: &mut T, name: &str, id: TypeId) | ||
| where | ||
| T: InterfaceGenerator<'a> + ?Sized, | ||
| { | ||
| let ty = &generator.resolve().types[id]; | ||
| match &ty.kind { | ||
| TypeDefKind::Record(record) => generator.type_record(id, name, record, &ty.docs), | ||
| TypeDefKind::Resource => generator.type_resource(id, name, &ty.docs), | ||
| TypeDefKind::Flags(flags) => generator.type_flags(id, name, flags, &ty.docs), | ||
| TypeDefKind::Tuple(tuple) => generator.type_tuple(id, name, tuple, &ty.docs), | ||
| TypeDefKind::Enum(enum_) => generator.type_enum(id, name, enum_, &ty.docs), | ||
| TypeDefKind::Variant(variant) => generator.type_variant(id, name, variant, &ty.docs), | ||
| TypeDefKind::Option(t) => generator.type_option(id, name, t, &ty.docs), | ||
| TypeDefKind::Result(r) => generator.type_result(id, name, r, &ty.docs), | ||
| TypeDefKind::List(t) => generator.type_list(id, name, t, &ty.docs), | ||
| TypeDefKind::Type(t) => generator.type_alias(id, name, t, &ty.docs), | ||
| TypeDefKind::Future(t) => generator.type_future(id, name, t, &ty.docs), | ||
| TypeDefKind::Stream(t) => generator.type_stream(id, name, t, &ty.docs), | ||
| TypeDefKind::Handle(_) => panic!("handle types do not require definition"), | ||
| TypeDefKind::FixedLengthList(..) => todo!(), | ||
| TypeDefKind::Map(..) => todo!(), | ||
| TypeDefKind::Unknown => unreachable!(), | ||
| } | ||
| } | ||
| pub trait AnonymousTypeGenerator<'a> { | ||
@@ -227,3 +244,3 @@ fn resolve(&self) -> &'a Resolve; | ||
| TypeDefKind::Handle(handle) => self.anonymous_type_handle(id, handle, &ty.docs), | ||
| TypeDefKind::FixedSizeList(t, size) => { | ||
| TypeDefKind::FixedLengthList(t, size) => { | ||
| self.anonymous_type_fixed_length_list(id, t, *size, &ty.docs) | ||
@@ -230,0 +247,0 @@ } |
+223
-4
@@ -8,2 +8,3 @@ use std::collections::HashMap; | ||
| type_info: HashMap<TypeId, TypeInfo>, | ||
| equal_types: UnionFind, | ||
| } | ||
@@ -85,3 +86,5 @@ | ||
| } | ||
| WorldItem::Interface { id, stability: _ } => { | ||
| WorldItem::Interface { | ||
| id, stability: _, .. | ||
| } => { | ||
| for (_, f) in resolve.interfaces[*id].functions.iter() { | ||
@@ -91,3 +94,3 @@ self.type_info_func(resolve, f, import); | ||
| } | ||
| WorldItem::Type(_) => {} | ||
| WorldItem::Type { .. } => {} | ||
| } | ||
@@ -98,5 +101,40 @@ } | ||
| /// Populates the return value of [`Types::get_representative_type`] with | ||
| /// the `resolve` passed in. | ||
| /// | ||
| /// The `may_alias_another_type` closure is used to determine whether the | ||
| /// language's definition of the provided `TypeId` might possibly alias | ||
| /// some other type in a language. This is a language-specific deduction | ||
| /// which can also be affected by options to a binding generator. If a type | ||
| /// can't be aliased by anything else then it can't be considered equal to | ||
| /// anything else. Note that in this situations other types may still | ||
| /// be equal to it, such as aliased types at the WIT level (e.g. `type foo | ||
| /// = some-record`). | ||
| pub fn collect_equal_types( | ||
| &mut self, | ||
| resolve: &Resolve, | ||
| may_alias_another_type: &dyn Fn(TypeId) -> bool, | ||
| ) { | ||
| for (i, (ty, _)) in resolve.types.iter().enumerate() { | ||
| if !may_alias_another_type(ty) { | ||
| continue; | ||
| } | ||
| // TODO: we could define a hash function for TypeDefKind to prevent the inner loop. | ||
| for (earlier, _) in resolve.types.iter().take(i) { | ||
| if self.equal_types.find(ty) == self.equal_types.find(earlier) { | ||
| continue; | ||
| } | ||
| // The correctness of is_structurally_equal relies on the fact | ||
| // that resolve.types.iter() is in topological order. | ||
| if self.is_structurally_equal(resolve, ty, earlier) { | ||
| self.equal_types.union(ty, earlier); | ||
| break; | ||
| } | ||
| } | ||
| } | ||
| } | ||
| fn type_info_func(&mut self, resolve: &Resolve, func: &Function, import: bool) { | ||
| let mut live = LiveTypes::default(); | ||
| for (_, ty) in func.params.iter() { | ||
| for Param { ty, .. } in func.params.iter() { | ||
| self.type_info(resolve, ty); | ||
@@ -210,3 +248,3 @@ live.add_type(resolve, ty); | ||
| } | ||
| TypeDefKind::FixedSizeList(ty, _) => { | ||
| TypeDefKind::FixedLengthList(ty, _) => { | ||
| info = self.type_info(resolve, ty); | ||
@@ -239,2 +277,183 @@ } | ||
| } | ||
| fn is_structurally_equal(&mut self, resolve: &Resolve, a: TypeId, b: TypeId) -> bool { | ||
| let a_def = &resolve.types[a].kind; | ||
| let b_def = &resolve.types[b].kind; | ||
| if self.equal_types.find(a) == self.equal_types.find(b) { | ||
| return true; | ||
| } | ||
| match (a_def, b_def) { | ||
| // Peel off typedef layers and continue recursing. | ||
| (TypeDefKind::Type(a), _) => self.type_id_equal_to_type(resolve, b, a), | ||
| (_, TypeDefKind::Type(b)) => self.type_id_equal_to_type(resolve, a, b), | ||
| (TypeDefKind::Record(ra), TypeDefKind::Record(rb)) => { | ||
| ra.fields.len() == rb.fields.len() | ||
| // Fields are ordered in WIT, so record {a: T, b: U} is different from {b: U, a: T} | ||
| && ra.fields.iter().zip(rb.fields.iter()).all(|(fa, fb)| { | ||
| fa.name == fb.name && self.types_equal(resolve, &fa.ty, &fb.ty) | ||
| }) | ||
| } | ||
| (TypeDefKind::Record(_), _) => false, | ||
| (TypeDefKind::Variant(va), TypeDefKind::Variant(vb)) => { | ||
| va.cases.len() == vb.cases.len() | ||
| && va.cases.iter().zip(vb.cases.iter()).all(|(ca, cb)| { | ||
| ca.name == cb.name && self.optional_types_equal(resolve, &ca.ty, &cb.ty) | ||
| }) | ||
| } | ||
| (TypeDefKind::Variant(_), _) => false, | ||
| (TypeDefKind::Enum(ea), TypeDefKind::Enum(eb)) => { | ||
| ea.cases.len() == eb.cases.len() | ||
| && ea | ||
| .cases | ||
| .iter() | ||
| .zip(eb.cases.iter()) | ||
| .all(|(ca, cb)| ca.name == cb.name) | ||
| } | ||
| (TypeDefKind::Enum(_), _) => false, | ||
| (TypeDefKind::Flags(fa), TypeDefKind::Flags(fb)) => { | ||
| fa.flags.len() == fb.flags.len() | ||
| && fa | ||
| .flags | ||
| .iter() | ||
| .zip(fb.flags.iter()) | ||
| .all(|(fa, fb)| fa.name == fb.name) | ||
| } | ||
| (TypeDefKind::Flags(_), _) => false, | ||
| (TypeDefKind::Tuple(ta), TypeDefKind::Tuple(tb)) => { | ||
| ta.types.len() == tb.types.len() | ||
| && ta | ||
| .types | ||
| .iter() | ||
| .zip(tb.types.iter()) | ||
| .all(|(a, b)| self.types_equal(resolve, a, b)) | ||
| } | ||
| (TypeDefKind::Tuple(_), _) => false, | ||
| (TypeDefKind::List(la), TypeDefKind::List(lb)) => self.types_equal(resolve, la, lb), | ||
| (TypeDefKind::List(_), _) => false, | ||
| (TypeDefKind::FixedLengthList(ta, sa), TypeDefKind::FixedLengthList(tb, sb)) => { | ||
| sa == sb && self.types_equal(resolve, ta, tb) | ||
| } | ||
| (TypeDefKind::FixedLengthList(..), _) => false, | ||
| (TypeDefKind::Option(oa), TypeDefKind::Option(ob)) => self.types_equal(resolve, oa, ob), | ||
| (TypeDefKind::Option(_), _) => false, | ||
| (TypeDefKind::Result(ra), TypeDefKind::Result(rb)) => { | ||
| self.optional_types_equal(resolve, &ra.ok, &rb.ok) | ||
| && self.optional_types_equal(resolve, &ra.err, &rb.err) | ||
| } | ||
| (TypeDefKind::Result(_), _) => false, | ||
| (TypeDefKind::Map(ak, av), TypeDefKind::Map(bk, bv)) => { | ||
| self.types_equal(resolve, ak, bk) && self.types_equal(resolve, av, bv) | ||
| } | ||
| (TypeDefKind::Map(..), _) => false, | ||
| (TypeDefKind::Future(a), TypeDefKind::Future(b)) => { | ||
| self.optional_types_equal(resolve, a, b) | ||
| } | ||
| (TypeDefKind::Future(..), _) => false, | ||
| (TypeDefKind::Stream(a), TypeDefKind::Stream(b)) => { | ||
| self.optional_types_equal(resolve, a, b) | ||
| } | ||
| (TypeDefKind::Stream(..), _) => false, | ||
| (TypeDefKind::Handle(a), TypeDefKind::Handle(b)) => match (a, b) { | ||
| (Handle::Own(a), Handle::Own(b)) | (Handle::Borrow(a), Handle::Borrow(b)) => { | ||
| self.is_structurally_equal(resolve, *a, *b) | ||
| } | ||
| (Handle::Own(_) | Handle::Borrow(_), _) => false, | ||
| }, | ||
| (TypeDefKind::Handle(_), _) => false, | ||
| (TypeDefKind::Unknown, _) => unreachable!(), | ||
| // Resources are only equal if their original ids are equal, | ||
| // otherwise all resources are un-equal to each other. | ||
| (TypeDefKind::Resource, TypeDefKind::Resource) => a == b, | ||
| (TypeDefKind::Resource, _) => false, | ||
| } | ||
| } | ||
| fn types_equal(&mut self, resolve: &Resolve, a: &Type, b: &Type) -> bool { | ||
| match (a, b) { | ||
| // Peel off typedef layers and continue recursing. | ||
| (Type::Id(a), b) => self.type_id_equal_to_type(resolve, *a, b), | ||
| (a, Type::Id(b)) => self.type_id_equal_to_type(resolve, *b, a), | ||
| // When both a and b are primitives, they're only equal of | ||
| // the primitives are the same. | ||
| ( | ||
| Type::Bool | ||
| | Type::U8 | ||
| | Type::S8 | ||
| | Type::U16 | ||
| | Type::S16 | ||
| | Type::U32 | ||
| | Type::S32 | ||
| | Type::U64 | ||
| | Type::S64 | ||
| | Type::F32 | ||
| | Type::F64 | ||
| | Type::Char | ||
| | Type::String | ||
| | Type::ErrorContext, | ||
| _, | ||
| ) => a == b, | ||
| } | ||
| } | ||
| fn type_id_equal_to_type(&mut self, resolve: &Resolve, a: TypeId, b: &Type) -> bool { | ||
| let ak = &resolve.types[a].kind; | ||
| match (ak, b) { | ||
| (TypeDefKind::Type(a), b) => self.types_equal(resolve, a, b), | ||
| (_, Type::Id(b)) => self.is_structurally_equal(resolve, a, *b), | ||
| // Type `a` isn't a typedef, and type `b` is a primitive, so it's no | ||
| // longer possible for them to be equal. | ||
| _ => false, | ||
| } | ||
| } | ||
| fn optional_types_equal( | ||
| &mut self, | ||
| resolve: &Resolve, | ||
| a: &Option<Type>, | ||
| b: &Option<Type>, | ||
| ) -> bool { | ||
| match (a, b) { | ||
| (Some(a), Some(b)) => self.types_equal(resolve, a, b), | ||
| (Some(_), None) | (None, Some(_)) => false, | ||
| (None, None) => true, | ||
| } | ||
| } | ||
| pub fn get_representative_type(&mut self, id: TypeId) -> TypeId { | ||
| self.equal_types.find(id) | ||
| } | ||
| } | ||
| #[derive(Default)] | ||
| pub struct UnionFind { | ||
| parent: HashMap<TypeId, TypeId>, | ||
| } | ||
| impl UnionFind { | ||
| fn find(&mut self, id: TypeId) -> TypeId { | ||
| // Path compression | ||
| let parent = self.parent.get(&id).copied().unwrap_or(id); | ||
| if parent != id { | ||
| let root = self.find(parent); | ||
| self.parent.insert(id, root); | ||
| root | ||
| } else { | ||
| id | ||
| } | ||
| } | ||
| fn union(&mut self, a: TypeId, b: TypeId) { | ||
| let ra = self.find(a); | ||
| let rb = self.find(b); | ||
| if ra != rb { | ||
| // Use smaller id as root for determinism | ||
| if ra < rb { | ||
| self.parent.insert(rb, ra); | ||
| } else { | ||
| self.parent.insert(ra, rb); | ||
| } | ||
| } | ||
| } | ||
| } |
Sorry, the diff of this file is too big to display