1use crate::abi::AbiVariant;
2use anyhow::{Context, Result, bail};
3use id_arena::{Arena, Id};
4use indexmap::IndexMap;
5use semver::Version;
6use std::borrow::Cow;
7use std::fmt;
8use std::hash::{Hash, Hasher};
9use std::path::Path;
10
11#[cfg(feature = "decoding")]
12pub mod decoding;
13#[cfg(feature = "decoding")]
14mod metadata;
15#[cfg(feature = "decoding")]
16pub use metadata::PackageMetadata;
17
18pub mod abi;
19mod ast;
20pub use ast::SourceMap;
21use ast::lex::Span;
22pub use ast::{ParsedUsePath, parse_use_path};
23mod sizealign;
24pub use sizealign::*;
25mod resolve;
26pub use resolve::*;
27mod live;
28pub use live::{LiveTypes, TypeIdVisitor};
29
30#[cfg(feature = "serde")]
31use serde_derive::Serialize;
32#[cfg(feature = "serde")]
33mod serde_;
34#[cfg(feature = "serde")]
35use serde_::*;
36
37pub fn validate_id(s: &str) -> Result<()> {
39 ast::validate_id(0, s)?;
40 Ok(())
41}
42
43pub type WorldId = Id<World>;
44pub type InterfaceId = Id<Interface>;
45pub type TypeId = Id<TypeDef>;
46
47#[derive(Clone)]
73pub struct UnresolvedPackage {
74 pub name: PackageName,
76
77 pub worlds: Arena<World>,
81
82 pub interfaces: Arena<Interface>,
89
90 pub types: Arena<TypeDef>,
97
98 pub foreign_deps: IndexMap<PackageName, IndexMap<String, AstItem>>,
107
108 pub docs: Docs,
110
111 package_name_span: Span,
112 unknown_type_spans: Vec<Span>,
113 interface_spans: Vec<InterfaceSpan>,
114 world_spans: Vec<WorldSpan>,
115 type_spans: Vec<Span>,
116 foreign_dep_spans: Vec<Span>,
117 required_resource_types: Vec<(TypeId, Span)>,
118}
119
120#[derive(Clone)]
122pub struct UnresolvedPackageGroup {
123 pub main: UnresolvedPackage,
128
129 pub nested: Vec<UnresolvedPackage>,
131
132 pub source_map: SourceMap,
134}
135
136#[derive(Clone)]
137struct WorldSpan {
138 span: Span,
139 imports: Vec<Span>,
140 exports: Vec<Span>,
141 includes: Vec<Span>,
142}
143
144#[derive(Clone)]
145struct InterfaceSpan {
146 span: Span,
147 funcs: Vec<Span>,
148}
149
150#[derive(Debug, Copy, Clone)]
151#[cfg_attr(feature = "serde", derive(Serialize))]
152#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
153pub enum AstItem {
154 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
155 Interface(InterfaceId),
156 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
157 World(WorldId),
158}
159
160#[derive(Debug, Clone, Hash, Eq, PartialEq, Ord, PartialOrd)]
166#[cfg_attr(feature = "serde", derive(Serialize))]
167#[cfg_attr(feature = "serde", serde(into = "String"))]
168pub struct PackageName {
169 pub namespace: String,
171 pub name: String,
173 pub version: Option<Version>,
175}
176
177impl From<PackageName> for String {
178 fn from(name: PackageName) -> String {
179 name.to_string()
180 }
181}
182
183impl PackageName {
184 pub fn interface_id(&self, interface: &str) -> String {
187 let mut s = String::new();
188 s.push_str(&format!("{}:{}/{interface}", self.namespace, self.name));
189 if let Some(version) = &self.version {
190 s.push_str(&format!("@{version}"));
191 }
192 s
193 }
194
195 pub fn version_compat_track(version: &Version) -> Version {
208 let mut version = version.clone();
209 version.build = semver::BuildMetadata::EMPTY;
210 if !version.pre.is_empty() {
211 return version;
212 }
213 if version.major != 0 {
214 version.minor = 0;
215 version.patch = 0;
216 return version;
217 }
218 if version.minor != 0 {
219 version.patch = 0;
220 return version;
221 }
222 version
223 }
224
225 pub fn version_compat_track_string(version: &Version) -> String {
229 let version = Self::version_compat_track(version);
230 if !version.pre.is_empty() {
231 return version.to_string();
232 }
233 if version.major != 0 {
234 return format!("{}", version.major);
235 }
236 if version.minor != 0 {
237 return format!("{}.{}", version.major, version.minor);
238 }
239 version.to_string()
240 }
241}
242
243impl fmt::Display for PackageName {
244 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
245 write!(f, "{}:{}", self.namespace, self.name)?;
246 if let Some(version) = &self.version {
247 write!(f, "@{version}")?;
248 }
249 Ok(())
250 }
251}
252
253#[derive(Debug)]
254struct Error {
255 span: Span,
256 msg: String,
257 highlighted: Option<String>,
258}
259
260impl Error {
261 fn new(span: Span, msg: impl Into<String>) -> Error {
262 Error {
263 span,
264 msg: msg.into(),
265 highlighted: None,
266 }
267 }
268}
269
270impl fmt::Display for Error {
271 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
272 self.highlighted.as_ref().unwrap_or(&self.msg).fmt(f)
273 }
274}
275
276impl std::error::Error for Error {}
277
278#[derive(Debug)]
279struct PackageNotFoundError {
280 span: Span,
281 requested: PackageName,
282 known: Vec<PackageName>,
283 highlighted: Option<String>,
284}
285
286impl PackageNotFoundError {
287 pub fn new(span: Span, requested: PackageName, known: Vec<PackageName>) -> Self {
288 Self {
289 span,
290 requested,
291 known,
292 highlighted: None,
293 }
294 }
295}
296
297impl fmt::Display for PackageNotFoundError {
298 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
299 if let Some(highlighted) = &self.highlighted {
300 return highlighted.fmt(f);
301 }
302 if self.known.is_empty() {
303 write!(
304 f,
305 "package '{}' not found. no known packages.",
306 self.requested
307 )?;
308 } else {
309 write!(
310 f,
311 "package '{}' not found. known packages:\n",
312 self.requested
313 )?;
314 for known in self.known.iter() {
315 write!(f, " {known}\n")?;
316 }
317 }
318 Ok(())
319 }
320}
321
322impl std::error::Error for PackageNotFoundError {}
323
324impl UnresolvedPackageGroup {
325 pub fn parse(path: impl AsRef<Path>, contents: &str) -> Result<UnresolvedPackageGroup> {
331 let mut map = SourceMap::default();
332 map.push(path.as_ref(), contents);
333 map.parse()
334 }
335
336 pub fn parse_path(path: impl AsRef<Path>) -> Result<UnresolvedPackageGroup> {
342 let path = path.as_ref();
343 if path.is_dir() {
344 UnresolvedPackageGroup::parse_dir(path)
345 } else {
346 UnresolvedPackageGroup::parse_file(path)
347 }
348 }
349
350 pub fn parse_file(path: impl AsRef<Path>) -> Result<UnresolvedPackageGroup> {
355 let path = path.as_ref();
356 let contents = std::fs::read_to_string(path)
357 .with_context(|| format!("failed to read file {path:?}"))?;
358 Self::parse(path, &contents)
359 }
360
361 pub fn parse_dir(path: impl AsRef<Path>) -> Result<UnresolvedPackageGroup> {
368 let path = path.as_ref();
369 let mut map = SourceMap::default();
370 let cx = || format!("failed to read directory {path:?}");
371 for entry in path.read_dir().with_context(&cx)? {
372 let entry = entry.with_context(&cx)?;
373 let path = entry.path();
374 let ty = entry.file_type().with_context(&cx)?;
375 if ty.is_dir() {
376 continue;
377 }
378 if ty.is_symlink() {
379 if path.is_dir() {
380 continue;
381 }
382 }
383 let filename = match path.file_name().and_then(|s| s.to_str()) {
384 Some(name) => name,
385 None => continue,
386 };
387 if !filename.ends_with(".wit") {
388 continue;
389 }
390 map.push_file(&path)?;
391 }
392 map.parse()
393 }
394}
395
396#[derive(Debug, Clone)]
397#[cfg_attr(feature = "serde", derive(Serialize))]
398pub struct World {
399 pub name: String,
401
402 pub imports: IndexMap<WorldKey, WorldItem>,
404
405 pub exports: IndexMap<WorldKey, WorldItem>,
407
408 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_optional_id"))]
410 pub package: Option<PackageId>,
411
412 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
414 pub docs: Docs,
415
416 #[cfg_attr(
418 feature = "serde",
419 serde(skip_serializing_if = "Stability::is_unknown")
420 )]
421 pub stability: Stability,
422
423 #[cfg_attr(feature = "serde", serde(skip))]
425 pub includes: Vec<(Stability, WorldId)>,
426
427 #[cfg_attr(feature = "serde", serde(skip))]
429 pub include_names: Vec<Vec<IncludeName>>,
430}
431
432#[derive(Debug, Clone)]
433pub struct IncludeName {
434 pub name: String,
436
437 pub as_: String,
439}
440
441#[derive(Debug, Clone, Eq)]
444#[cfg_attr(feature = "serde", derive(Serialize))]
445#[cfg_attr(feature = "serde", serde(into = "String"))]
446pub enum WorldKey {
447 Name(String),
449 Interface(InterfaceId),
451}
452
453#[derive(PartialEq, Hash)]
460enum KebabDedupe<'a> {
461 Normal(&'a str),
462}
463
464impl<'a> From<&'a str> for KebabDedupe<'a> {
465 fn from(s: &'a str) -> KebabDedupe<'a> {
466 if let Some(s) = s.strip_prefix("[async]") {
469 return KebabDedupe::Normal(s);
470 }
471
472 KebabDedupe::Normal(s)
477 }
478}
479
480impl Hash for WorldKey {
481 fn hash<H: Hasher>(&self, hasher: &mut H) {
482 match self {
483 WorldKey::Name(s) => {
484 0u8.hash(hasher);
485 KebabDedupe::from(s.as_str()).hash(hasher);
486 }
487 WorldKey::Interface(i) => {
488 1u8.hash(hasher);
489 i.hash(hasher);
490 }
491 }
492 }
493}
494
495impl PartialEq for WorldKey {
496 fn eq(&self, other: &WorldKey) -> bool {
497 match (self, other) {
498 (WorldKey::Name(a), WorldKey::Name(b)) => {
499 KebabDedupe::from(a.as_str()) == KebabDedupe::from(b.as_str())
500 }
501 (WorldKey::Name(_), _) => false,
502 (WorldKey::Interface(a), WorldKey::Interface(b)) => a == b,
503 (WorldKey::Interface(_), _) => false,
504 }
505 }
506}
507
508impl From<WorldKey> for String {
509 fn from(key: WorldKey) -> String {
510 match key {
511 WorldKey::Name(name) => name,
512 WorldKey::Interface(id) => format!("interface-{}", id.index()),
513 }
514 }
515}
516
517impl WorldKey {
518 #[track_caller]
520 pub fn unwrap_name(self) -> String {
521 match self {
522 WorldKey::Name(name) => name,
523 WorldKey::Interface(_) => panic!("expected a name, found interface"),
524 }
525 }
526}
527
528#[derive(Debug, Clone, PartialEq)]
529#[cfg_attr(feature = "serde", derive(Serialize))]
530#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
531pub enum WorldItem {
532 Interface {
535 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
536 id: InterfaceId,
537 #[cfg_attr(
538 feature = "serde",
539 serde(skip_serializing_if = "Stability::is_unknown")
540 )]
541 stability: Stability,
542 },
543
544 Function(Function),
546
547 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
551 Type(TypeId),
552}
553
554impl WorldItem {
555 pub fn stability<'a>(&'a self, resolve: &'a Resolve) -> &'a Stability {
556 match self {
557 WorldItem::Interface { stability, .. } => stability,
558 WorldItem::Function(f) => &f.stability,
559 WorldItem::Type(id) => &resolve.types[*id].stability,
560 }
561 }
562}
563
564#[derive(Debug, Clone)]
565#[cfg_attr(feature = "serde", derive(Serialize))]
566pub struct Interface {
567 pub name: Option<String>,
571
572 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id_map"))]
577 pub types: IndexMap<String, TypeId>,
578
579 pub functions: IndexMap<String, Function>,
581
582 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
584 pub docs: Docs,
585
586 #[cfg_attr(
588 feature = "serde",
589 serde(skip_serializing_if = "Stability::is_unknown")
590 )]
591 pub stability: Stability,
592
593 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_optional_id"))]
595 pub package: Option<PackageId>,
596}
597
598#[derive(Debug, Clone, PartialEq)]
599#[cfg_attr(feature = "serde", derive(Serialize))]
600pub struct TypeDef {
601 pub name: Option<String>,
602 pub kind: TypeDefKind,
603 pub owner: TypeOwner,
604 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
605 pub docs: Docs,
606 #[cfg_attr(
608 feature = "serde",
609 serde(skip_serializing_if = "Stability::is_unknown")
610 )]
611 pub stability: Stability,
612}
613
614#[derive(Debug, Clone, PartialEq, Hash, Eq)]
615#[cfg_attr(feature = "serde", derive(Serialize))]
616#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
617pub enum TypeDefKind {
618 Record(Record),
619 Resource,
620 Handle(Handle),
621 Flags(Flags),
622 Tuple(Tuple),
623 Variant(Variant),
624 Enum(Enum),
625 Option(Type),
626 Result(Result_),
627 List(Type),
628 FixedSizeList(Type, u32),
629 Future(Option<Type>),
630 Stream(Option<Type>),
631 Type(Type),
632
633 Unknown,
639}
640
641impl TypeDefKind {
642 pub fn as_str(&self) -> &'static str {
643 match self {
644 TypeDefKind::Record(_) => "record",
645 TypeDefKind::Resource => "resource",
646 TypeDefKind::Handle(handle) => match handle {
647 Handle::Own(_) => "own",
648 Handle::Borrow(_) => "borrow",
649 },
650 TypeDefKind::Flags(_) => "flags",
651 TypeDefKind::Tuple(_) => "tuple",
652 TypeDefKind::Variant(_) => "variant",
653 TypeDefKind::Enum(_) => "enum",
654 TypeDefKind::Option(_) => "option",
655 TypeDefKind::Result(_) => "result",
656 TypeDefKind::List(_) => "list",
657 TypeDefKind::FixedSizeList(..) => "fixed size list",
658 TypeDefKind::Future(_) => "future",
659 TypeDefKind::Stream(_) => "stream",
660 TypeDefKind::Type(_) => "type",
661 TypeDefKind::Unknown => "unknown",
662 }
663 }
664}
665
666#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
667#[cfg_attr(feature = "serde", derive(Serialize))]
668#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
669pub enum TypeOwner {
670 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
672 World(WorldId),
673 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
675 Interface(InterfaceId),
676 #[cfg_attr(feature = "serde", serde(untagged, serialize_with = "serialize_none"))]
679 None,
680}
681
682#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone)]
683#[cfg_attr(feature = "serde", derive(Serialize))]
684#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
685pub enum Handle {
686 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
687 Own(TypeId),
688 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
689 Borrow(TypeId),
690}
691
692#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone)]
693pub enum Type {
694 Bool,
695 U8,
696 U16,
697 U32,
698 U64,
699 S8,
700 S16,
701 S32,
702 S64,
703 F32,
704 F64,
705 Char,
706 String,
707 ErrorContext,
708 Id(TypeId),
709}
710
711#[derive(Debug, Copy, Clone, Eq, PartialEq)]
712pub enum Int {
713 U8,
714 U16,
715 U32,
716 U64,
717}
718
719#[derive(Debug, Clone, PartialEq, Hash, Eq)]
720#[cfg_attr(feature = "serde", derive(Serialize))]
721pub struct Record {
722 pub fields: Vec<Field>,
723}
724
725#[derive(Debug, Clone, PartialEq, Hash, Eq)]
726#[cfg_attr(feature = "serde", derive(Serialize))]
727pub struct Field {
728 pub name: String,
729 #[cfg_attr(feature = "serde", serde(rename = "type"))]
730 pub ty: Type,
731 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
732 pub docs: Docs,
733}
734
735#[derive(Debug, Clone, PartialEq, Hash, Eq)]
736#[cfg_attr(feature = "serde", derive(Serialize))]
737pub struct Flags {
738 pub flags: Vec<Flag>,
739}
740
741#[derive(Debug, Clone, PartialEq, Hash, Eq)]
742#[cfg_attr(feature = "serde", derive(Serialize))]
743pub struct Flag {
744 pub name: String,
745 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
746 pub docs: Docs,
747}
748
749#[derive(Debug, Clone, PartialEq)]
750pub enum FlagsRepr {
751 U8,
752 U16,
753 U32(usize),
754}
755
756impl Flags {
757 pub fn repr(&self) -> FlagsRepr {
758 match self.flags.len() {
759 0 => FlagsRepr::U32(0),
760 n if n <= 8 => FlagsRepr::U8,
761 n if n <= 16 => FlagsRepr::U16,
762 n => FlagsRepr::U32(sizealign::align_to(n, 32) / 32),
763 }
764 }
765}
766
767impl FlagsRepr {
768 pub fn count(&self) -> usize {
769 match self {
770 FlagsRepr::U8 => 1,
771 FlagsRepr::U16 => 1,
772 FlagsRepr::U32(n) => *n,
773 }
774 }
775}
776
777#[derive(Debug, Clone, PartialEq, Hash, Eq)]
778#[cfg_attr(feature = "serde", derive(Serialize))]
779pub struct Tuple {
780 pub types: Vec<Type>,
781}
782
783#[derive(Debug, Clone, PartialEq, Hash, Eq)]
784#[cfg_attr(feature = "serde", derive(Serialize))]
785pub struct Variant {
786 pub cases: Vec<Case>,
787}
788
789#[derive(Debug, Clone, PartialEq, Hash, Eq)]
790#[cfg_attr(feature = "serde", derive(Serialize))]
791pub struct Case {
792 pub name: String,
793 #[cfg_attr(feature = "serde", serde(rename = "type"))]
794 pub ty: Option<Type>,
795 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
796 pub docs: Docs,
797}
798
799impl Variant {
800 pub fn tag(&self) -> Int {
801 discriminant_type(self.cases.len())
802 }
803}
804
805#[derive(Debug, Clone, PartialEq, Hash, Eq)]
806#[cfg_attr(feature = "serde", derive(Serialize))]
807pub struct Enum {
808 pub cases: Vec<EnumCase>,
809}
810
811#[derive(Debug, Clone, PartialEq, Hash, Eq)]
812#[cfg_attr(feature = "serde", derive(Serialize))]
813pub struct EnumCase {
814 pub name: String,
815 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
816 pub docs: Docs,
817}
818
819impl Enum {
820 pub fn tag(&self) -> Int {
821 discriminant_type(self.cases.len())
822 }
823}
824
825fn discriminant_type(num_cases: usize) -> Int {
827 match num_cases.checked_sub(1) {
828 None => Int::U8,
829 Some(n) if n <= u8::max_value() as usize => Int::U8,
830 Some(n) if n <= u16::max_value() as usize => Int::U16,
831 Some(n) if n <= u32::max_value() as usize => Int::U32,
832 _ => panic!("too many cases to fit in a repr"),
833 }
834}
835
836#[derive(Debug, Clone, PartialEq, Hash, Eq)]
837#[cfg_attr(feature = "serde", derive(Serialize))]
838pub struct Result_ {
839 pub ok: Option<Type>,
840 pub err: Option<Type>,
841}
842
843#[derive(Clone, Default, Debug, PartialEq, Eq, Hash)]
844#[cfg_attr(feature = "serde", derive(Serialize))]
845pub struct Docs {
846 pub contents: Option<String>,
847}
848
849impl Docs {
850 pub fn is_empty(&self) -> bool {
851 self.contents.is_none()
852 }
853}
854
855#[derive(Debug, Clone, PartialEq, Eq)]
856#[cfg_attr(feature = "serde", derive(Serialize))]
857pub struct Function {
858 pub name: String,
859 pub kind: FunctionKind,
860 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_params"))]
861 pub params: Vec<(String, Type)>,
862 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
863 pub result: Option<Type>,
864 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
865 pub docs: Docs,
866 #[cfg_attr(
868 feature = "serde",
869 serde(skip_serializing_if = "Stability::is_unknown")
870 )]
871 pub stability: Stability,
872}
873
874#[derive(Debug, Clone, PartialEq, Eq)]
875#[cfg_attr(feature = "serde", derive(Serialize))]
876#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
877pub enum FunctionKind {
878 Freestanding,
886
887 AsyncFreestanding,
895
896 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
907 Method(TypeId),
908
909 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
920 AsyncMethod(TypeId),
921
922 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
932 Static(TypeId),
933
934 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
944 AsyncStatic(TypeId),
945
946 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
956 Constructor(TypeId),
957}
958
959impl FunctionKind {
960 pub fn resource(&self) -> Option<TypeId> {
962 match self {
963 FunctionKind::Freestanding | FunctionKind::AsyncFreestanding => None,
964 FunctionKind::Method(id)
965 | FunctionKind::Static(id)
966 | FunctionKind::Constructor(id)
967 | FunctionKind::AsyncMethod(id)
968 | FunctionKind::AsyncStatic(id) => Some(*id),
969 }
970 }
971
972 pub fn resource_mut(&mut self) -> Option<&mut TypeId> {
974 match self {
975 FunctionKind::Freestanding | FunctionKind::AsyncFreestanding => None,
976 FunctionKind::Method(id)
977 | FunctionKind::Static(id)
978 | FunctionKind::Constructor(id)
979 | FunctionKind::AsyncMethod(id)
980 | FunctionKind::AsyncStatic(id) => Some(id),
981 }
982 }
983}
984
985#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
987pub enum Mangling {
988 Standard32,
991
992 Legacy,
997}
998
999impl std::str::FromStr for Mangling {
1000 type Err = anyhow::Error;
1001
1002 fn from_str(s: &str) -> Result<Mangling> {
1003 match s {
1004 "legacy" => Ok(Mangling::Legacy),
1005 "standard32" => Ok(Mangling::Standard32),
1006 _ => {
1007 bail!(
1008 "unknown name mangling `{s}`, \
1009 supported values are `legacy` or `standard32`"
1010 )
1011 }
1012 }
1013 }
1014}
1015
1016#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1018pub enum LiftLowerAbi {
1019 Sync,
1021
1022 AsyncCallback,
1025
1026 AsyncStackful,
1029}
1030
1031impl LiftLowerAbi {
1032 fn import_prefix(self) -> &'static str {
1033 match self {
1034 Self::Sync => "",
1035 Self::AsyncCallback | Self::AsyncStackful => "[async-lower]",
1036 }
1037 }
1038
1039 pub fn import_variant(self) -> AbiVariant {
1041 match self {
1042 Self::Sync => AbiVariant::GuestImport,
1043 Self::AsyncCallback | Self::AsyncStackful => AbiVariant::GuestImportAsync,
1044 }
1045 }
1046
1047 fn export_prefix(self) -> &'static str {
1048 match self {
1049 Self::Sync => "",
1050 Self::AsyncCallback => "[async-lift]",
1051 Self::AsyncStackful => "[async-lift-stackful]",
1052 }
1053 }
1054
1055 pub fn export_variant(self) -> AbiVariant {
1057 match self {
1058 Self::Sync => AbiVariant::GuestExport,
1059 Self::AsyncCallback => AbiVariant::GuestExportAsync,
1060 Self::AsyncStackful => AbiVariant::GuestExportAsyncStackful,
1061 }
1062 }
1063}
1064
1065#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1067pub enum ManglingAndAbi {
1068 Standard32,
1073
1074 Legacy(LiftLowerAbi),
1076}
1077
1078impl ManglingAndAbi {
1079 pub fn import_variant(self) -> AbiVariant {
1081 match self {
1082 Self::Standard32 => AbiVariant::GuestImport,
1083 Self::Legacy(abi) => abi.import_variant(),
1084 }
1085 }
1086
1087 pub fn export_variant(self) -> AbiVariant {
1089 match self {
1090 Self::Standard32 => AbiVariant::GuestExport,
1091 Self::Legacy(abi) => abi.export_variant(),
1092 }
1093 }
1094
1095 pub fn sync(self) -> Self {
1097 match self {
1098 Self::Standard32 | Self::Legacy(LiftLowerAbi::Sync) => self,
1099 Self::Legacy(LiftLowerAbi::AsyncCallback)
1100 | Self::Legacy(LiftLowerAbi::AsyncStackful) => Self::Legacy(LiftLowerAbi::Sync),
1101 }
1102 }
1103
1104 pub fn is_async(&self) -> bool {
1106 match self {
1107 Self::Standard32 | Self::Legacy(LiftLowerAbi::Sync) => false,
1108 Self::Legacy(LiftLowerAbi::AsyncCallback)
1109 | Self::Legacy(LiftLowerAbi::AsyncStackful) => true,
1110 }
1111 }
1112
1113 pub fn mangling(&self) -> Mangling {
1114 match self {
1115 Self::Standard32 => Mangling::Standard32,
1116 Self::Legacy(_) => Mangling::Legacy,
1117 }
1118 }
1119}
1120
1121impl Function {
1122 pub fn item_name(&self) -> &str {
1123 match &self.kind {
1124 FunctionKind::Freestanding => &self.name,
1125 FunctionKind::AsyncFreestanding => &self.name["[async]".len()..],
1126 FunctionKind::Method(_)
1127 | FunctionKind::Static(_)
1128 | FunctionKind::AsyncMethod(_)
1129 | FunctionKind::AsyncStatic(_) => &self.name[self.name.find('.').unwrap() + 1..],
1130 FunctionKind::Constructor(_) => "constructor",
1131 }
1132 }
1133
1134 pub fn parameter_and_result_types(&self) -> impl Iterator<Item = Type> + '_ {
1139 self.params.iter().map(|(_, t)| *t).chain(self.result)
1140 }
1141
1142 pub fn standard32_core_export_name<'a>(&'a self, interface: Option<&str>) -> Cow<'a, str> {
1144 self.core_export_name(interface, Mangling::Standard32)
1145 }
1146
1147 pub fn legacy_core_export_name<'a>(&'a self, interface: Option<&str>) -> Cow<'a, str> {
1148 self.core_export_name(interface, Mangling::Legacy)
1149 }
1150 pub fn core_export_name<'a>(
1152 &'a self,
1153 interface: Option<&str>,
1154 mangling: Mangling,
1155 ) -> Cow<'a, str> {
1156 match interface {
1157 Some(interface) => match mangling {
1158 Mangling::Standard32 => Cow::Owned(format!("cm32p2|{interface}|{}", self.name)),
1159 Mangling::Legacy => Cow::Owned(format!("{interface}#{}", self.name)),
1160 },
1161 None => match mangling {
1162 Mangling::Standard32 => Cow::Owned(format!("cm32p2||{}", self.name)),
1163 Mangling::Legacy => Cow::Borrowed(&self.name),
1164 },
1165 }
1166 }
1167 pub fn find_futures_and_streams(&self, resolve: &Resolve) -> Vec<TypeId> {
1183 let mut results = Vec::new();
1184 for (_, ty) in self.params.iter() {
1185 find_futures_and_streams(resolve, *ty, &mut results);
1186 }
1187 if let Some(ty) = self.result {
1188 find_futures_and_streams(resolve, ty, &mut results);
1189 }
1190 results
1191 }
1192
1193 pub fn is_constructor_shorthand(&self, resolve: &Resolve) -> bool {
1196 let FunctionKind::Constructor(containing_resource_id) = self.kind else {
1197 return false;
1198 };
1199
1200 let Some(Type::Id(id)) = &self.result else {
1201 return false;
1202 };
1203
1204 let TypeDefKind::Handle(Handle::Own(returned_resource_id)) = resolve.types[*id].kind else {
1205 return false;
1206 };
1207
1208 return containing_resource_id == returned_resource_id;
1209 }
1210
1211 pub fn task_return_import(
1214 &self,
1215 resolve: &Resolve,
1216 interface: Option<&WorldKey>,
1217 mangling: Mangling,
1218 ) -> (String, String, abi::WasmSignature) {
1219 match mangling {
1220 Mangling::Standard32 => todo!(),
1221 Mangling::Legacy => {}
1222 }
1223 let module = match interface {
1225 Some(key) => format!("[export]{}", resolve.name_world_key(key)),
1226 None => "[export]$root".to_string(),
1227 };
1228 let name = format!("[task-return]{}", self.name);
1229
1230 let mut func_tmp = self.clone();
1231 func_tmp.params = Vec::new();
1232 func_tmp.result = None;
1233 if let Some(ty) = self.result {
1234 func_tmp.params.push(("x".to_string(), ty));
1235 }
1236 let sig = resolve.wasm_signature(AbiVariant::GuestImport, &func_tmp);
1237 (module, name, sig)
1238 }
1239
1240 }
1242
1243fn find_futures_and_streams(resolve: &Resolve, ty: Type, results: &mut Vec<TypeId>) {
1244 let Type::Id(id) = ty else {
1245 return;
1246 };
1247
1248 match &resolve.types[id].kind {
1249 TypeDefKind::Resource
1250 | TypeDefKind::Handle(_)
1251 | TypeDefKind::Flags(_)
1252 | TypeDefKind::Enum(_) => {}
1253 TypeDefKind::Record(r) => {
1254 for Field { ty, .. } in &r.fields {
1255 find_futures_and_streams(resolve, *ty, results);
1256 }
1257 }
1258 TypeDefKind::Tuple(t) => {
1259 for ty in &t.types {
1260 find_futures_and_streams(resolve, *ty, results);
1261 }
1262 }
1263 TypeDefKind::Variant(v) => {
1264 for Case { ty, .. } in &v.cases {
1265 if let Some(ty) = ty {
1266 find_futures_and_streams(resolve, *ty, results);
1267 }
1268 }
1269 }
1270 TypeDefKind::Option(ty)
1271 | TypeDefKind::List(ty)
1272 | TypeDefKind::FixedSizeList(ty, ..)
1273 | TypeDefKind::Type(ty) => {
1274 find_futures_and_streams(resolve, *ty, results);
1275 }
1276 TypeDefKind::Result(r) => {
1277 if let Some(ty) = r.ok {
1278 find_futures_and_streams(resolve, ty, results);
1279 }
1280 if let Some(ty) = r.err {
1281 find_futures_and_streams(resolve, ty, results);
1282 }
1283 }
1284 TypeDefKind::Future(ty) => {
1285 if let Some(ty) = ty {
1286 find_futures_and_streams(resolve, *ty, results);
1287 }
1288 results.push(id);
1289 }
1290 TypeDefKind::Stream(ty) => {
1291 if let Some(ty) = ty {
1292 find_futures_and_streams(resolve, *ty, results);
1293 }
1294 results.push(id);
1295 }
1296 TypeDefKind::Unknown => unreachable!(),
1297 }
1298}
1299
1300#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
1308#[cfg_attr(feature = "serde", derive(serde_derive::Deserialize, Serialize))]
1309#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
1310pub enum Stability {
1311 Unknown,
1313
1314 Unstable {
1319 feature: String,
1320 #[cfg_attr(
1321 feature = "serde",
1322 serde(
1323 skip_serializing_if = "Option::is_none",
1324 default,
1325 serialize_with = "serialize_optional_version",
1326 deserialize_with = "deserialize_optional_version"
1327 )
1328 )]
1329 deprecated: Option<Version>,
1330 },
1331
1332 Stable {
1337 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_version"))]
1338 #[cfg_attr(feature = "serde", serde(deserialize_with = "deserialize_version"))]
1339 since: Version,
1340 #[cfg_attr(
1341 feature = "serde",
1342 serde(
1343 skip_serializing_if = "Option::is_none",
1344 default,
1345 serialize_with = "serialize_optional_version",
1346 deserialize_with = "deserialize_optional_version"
1347 )
1348 )]
1349 deprecated: Option<Version>,
1350 },
1351}
1352
1353impl Stability {
1354 pub fn is_unknown(&self) -> bool {
1356 matches!(self, Stability::Unknown)
1357 }
1358
1359 pub fn is_stable(&self) -> bool {
1360 matches!(self, Stability::Stable { .. })
1361 }
1362}
1363
1364impl Default for Stability {
1365 fn default() -> Stability {
1366 Stability::Unknown
1367 }
1368}
1369
1370#[cfg(test)]
1371mod test {
1372 use super::*;
1373
1374 #[test]
1375 fn test_discriminant_type() {
1376 assert_eq!(discriminant_type(1), Int::U8);
1377 assert_eq!(discriminant_type(0x100), Int::U8);
1378 assert_eq!(discriminant_type(0x101), Int::U16);
1379 assert_eq!(discriminant_type(0x10000), Int::U16);
1380 assert_eq!(discriminant_type(0x10001), Int::U32);
1381 if let Ok(num_cases) = usize::try_from(0x100000000_u64) {
1382 assert_eq!(discriminant_type(num_cases), Int::U32);
1383 }
1384 }
1385
1386 #[test]
1387 fn test_find_futures_and_streams() {
1388 let mut resolve = Resolve::default();
1389 let t0 = resolve.types.alloc(TypeDef {
1390 name: None,
1391 kind: TypeDefKind::Future(Some(Type::U32)),
1392 owner: TypeOwner::None,
1393 docs: Docs::default(),
1394 stability: Stability::Unknown,
1395 });
1396 let t1 = resolve.types.alloc(TypeDef {
1397 name: None,
1398 kind: TypeDefKind::Future(Some(Type::Id(t0))),
1399 owner: TypeOwner::None,
1400 docs: Docs::default(),
1401 stability: Stability::Unknown,
1402 });
1403 let t2 = resolve.types.alloc(TypeDef {
1404 name: None,
1405 kind: TypeDefKind::Stream(Some(Type::U32)),
1406 owner: TypeOwner::None,
1407 docs: Docs::default(),
1408 stability: Stability::Unknown,
1409 });
1410 let found = Function {
1411 name: "foo".into(),
1412 kind: FunctionKind::Freestanding,
1413 params: vec![("p1".into(), Type::Id(t1)), ("p2".into(), Type::U32)],
1414 result: Some(Type::Id(t2)),
1415 docs: Docs::default(),
1416 stability: Stability::Unknown,
1417 }
1418 .find_futures_and_streams(&resolve);
1419 assert_eq!(3, found.len());
1420 assert_eq!(t0, found[0]);
1421 assert_eq!(t1, found[1]);
1422 assert_eq!(t2, found[2]);
1423 }
1424}