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, Vec<Stability>)>>,
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
453impl Hash for WorldKey {
454 fn hash<H: Hasher>(&self, hasher: &mut H) {
455 match self {
456 WorldKey::Name(s) => {
457 0u8.hash(hasher);
458 s.as_str().hash(hasher);
459 }
460 WorldKey::Interface(i) => {
461 1u8.hash(hasher);
462 i.hash(hasher);
463 }
464 }
465 }
466}
467
468impl PartialEq for WorldKey {
469 fn eq(&self, other: &WorldKey) -> bool {
470 match (self, other) {
471 (WorldKey::Name(a), WorldKey::Name(b)) => a.as_str() == b.as_str(),
472 (WorldKey::Name(_), _) => false,
473 (WorldKey::Interface(a), WorldKey::Interface(b)) => a == b,
474 (WorldKey::Interface(_), _) => false,
475 }
476 }
477}
478
479impl From<WorldKey> for String {
480 fn from(key: WorldKey) -> String {
481 match key {
482 WorldKey::Name(name) => name,
483 WorldKey::Interface(id) => format!("interface-{}", id.index()),
484 }
485 }
486}
487
488impl WorldKey {
489 #[track_caller]
491 pub fn unwrap_name(self) -> String {
492 match self {
493 WorldKey::Name(name) => name,
494 WorldKey::Interface(_) => panic!("expected a name, found interface"),
495 }
496 }
497}
498
499#[derive(Debug, Clone, PartialEq)]
500#[cfg_attr(feature = "serde", derive(Serialize))]
501#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
502pub enum WorldItem {
503 Interface {
506 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
507 id: InterfaceId,
508 #[cfg_attr(
509 feature = "serde",
510 serde(skip_serializing_if = "Stability::is_unknown")
511 )]
512 stability: Stability,
513 },
514
515 Function(Function),
517
518 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
522 Type(TypeId),
523}
524
525impl WorldItem {
526 pub fn stability<'a>(&'a self, resolve: &'a Resolve) -> &'a Stability {
527 match self {
528 WorldItem::Interface { stability, .. } => stability,
529 WorldItem::Function(f) => &f.stability,
530 WorldItem::Type(id) => &resolve.types[*id].stability,
531 }
532 }
533}
534
535#[derive(Debug, Clone)]
536#[cfg_attr(feature = "serde", derive(Serialize))]
537pub struct Interface {
538 pub name: Option<String>,
542
543 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id_map"))]
548 pub types: IndexMap<String, TypeId>,
549
550 pub functions: IndexMap<String, Function>,
552
553 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
555 pub docs: Docs,
556
557 #[cfg_attr(
559 feature = "serde",
560 serde(skip_serializing_if = "Stability::is_unknown")
561 )]
562 pub stability: Stability,
563
564 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_optional_id"))]
566 pub package: Option<PackageId>,
567}
568
569#[derive(Debug, Clone, PartialEq)]
570#[cfg_attr(feature = "serde", derive(Serialize))]
571pub struct TypeDef {
572 pub name: Option<String>,
573 pub kind: TypeDefKind,
574 pub owner: TypeOwner,
575 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
576 pub docs: Docs,
577 #[cfg_attr(
579 feature = "serde",
580 serde(skip_serializing_if = "Stability::is_unknown")
581 )]
582 pub stability: Stability,
583}
584
585#[derive(Debug, Clone, PartialEq, Hash, Eq)]
586#[cfg_attr(feature = "serde", derive(Serialize))]
587#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
588pub enum TypeDefKind {
589 Record(Record),
590 Resource,
591 Handle(Handle),
592 Flags(Flags),
593 Tuple(Tuple),
594 Variant(Variant),
595 Enum(Enum),
596 Option(Type),
597 Result(Result_),
598 List(Type),
599 Map(Type, Type),
600 FixedSizeList(Type, u32),
601 Future(Option<Type>),
602 Stream(Option<Type>),
603 Type(Type),
604
605 Unknown,
611}
612
613impl TypeDefKind {
614 pub fn as_str(&self) -> &'static str {
615 match self {
616 TypeDefKind::Record(_) => "record",
617 TypeDefKind::Resource => "resource",
618 TypeDefKind::Handle(handle) => match handle {
619 Handle::Own(_) => "own",
620 Handle::Borrow(_) => "borrow",
621 },
622 TypeDefKind::Flags(_) => "flags",
623 TypeDefKind::Tuple(_) => "tuple",
624 TypeDefKind::Variant(_) => "variant",
625 TypeDefKind::Enum(_) => "enum",
626 TypeDefKind::Option(_) => "option",
627 TypeDefKind::Result(_) => "result",
628 TypeDefKind::List(_) => "list",
629 TypeDefKind::Map(_, _) => "map",
630 TypeDefKind::FixedSizeList(..) => "fixed size list",
631 TypeDefKind::Future(_) => "future",
632 TypeDefKind::Stream(_) => "stream",
633 TypeDefKind::Type(_) => "type",
634 TypeDefKind::Unknown => "unknown",
635 }
636 }
637}
638
639#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
640#[cfg_attr(feature = "serde", derive(Serialize))]
641#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
642pub enum TypeOwner {
643 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
645 World(WorldId),
646 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
648 Interface(InterfaceId),
649 #[cfg_attr(feature = "serde", serde(untagged, serialize_with = "serialize_none"))]
652 None,
653}
654
655#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone)]
656#[cfg_attr(feature = "serde", derive(Serialize))]
657#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
658pub enum Handle {
659 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
660 Own(TypeId),
661 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
662 Borrow(TypeId),
663}
664
665#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone)]
666pub enum Type {
667 Bool,
668 U8,
669 U16,
670 U32,
671 U64,
672 S8,
673 S16,
674 S32,
675 S64,
676 F32,
677 F64,
678 Char,
679 String,
680 ErrorContext,
681 Id(TypeId),
682}
683
684#[derive(Debug, Copy, Clone, Eq, PartialEq)]
685pub enum Int {
686 U8,
687 U16,
688 U32,
689 U64,
690}
691
692#[derive(Debug, Clone, PartialEq, Hash, Eq)]
693#[cfg_attr(feature = "serde", derive(Serialize))]
694pub struct Record {
695 pub fields: Vec<Field>,
696}
697
698#[derive(Debug, Clone, PartialEq, Hash, Eq)]
699#[cfg_attr(feature = "serde", derive(Serialize))]
700pub struct Field {
701 pub name: String,
702 #[cfg_attr(feature = "serde", serde(rename = "type"))]
703 pub ty: Type,
704 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
705 pub docs: Docs,
706}
707
708#[derive(Debug, Clone, PartialEq, Hash, Eq)]
709#[cfg_attr(feature = "serde", derive(Serialize))]
710pub struct Flags {
711 pub flags: Vec<Flag>,
712}
713
714#[derive(Debug, Clone, PartialEq, Hash, Eq)]
715#[cfg_attr(feature = "serde", derive(Serialize))]
716pub struct Flag {
717 pub name: String,
718 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
719 pub docs: Docs,
720}
721
722#[derive(Debug, Clone, PartialEq)]
723pub enum FlagsRepr {
724 U8,
725 U16,
726 U32(usize),
727}
728
729impl Flags {
730 pub fn repr(&self) -> FlagsRepr {
731 match self.flags.len() {
732 0 => FlagsRepr::U32(0),
733 n if n <= 8 => FlagsRepr::U8,
734 n if n <= 16 => FlagsRepr::U16,
735 n => FlagsRepr::U32(sizealign::align_to(n, 32) / 32),
736 }
737 }
738}
739
740impl FlagsRepr {
741 pub fn count(&self) -> usize {
742 match self {
743 FlagsRepr::U8 => 1,
744 FlagsRepr::U16 => 1,
745 FlagsRepr::U32(n) => *n,
746 }
747 }
748}
749
750#[derive(Debug, Clone, PartialEq, Hash, Eq)]
751#[cfg_attr(feature = "serde", derive(Serialize))]
752pub struct Tuple {
753 pub types: Vec<Type>,
754}
755
756#[derive(Debug, Clone, PartialEq, Hash, Eq)]
757#[cfg_attr(feature = "serde", derive(Serialize))]
758pub struct Variant {
759 pub cases: Vec<Case>,
760}
761
762#[derive(Debug, Clone, PartialEq, Hash, Eq)]
763#[cfg_attr(feature = "serde", derive(Serialize))]
764pub struct Case {
765 pub name: String,
766 #[cfg_attr(feature = "serde", serde(rename = "type"))]
767 pub ty: Option<Type>,
768 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
769 pub docs: Docs,
770}
771
772impl Variant {
773 pub fn tag(&self) -> Int {
774 discriminant_type(self.cases.len())
775 }
776}
777
778#[derive(Debug, Clone, PartialEq, Hash, Eq)]
779#[cfg_attr(feature = "serde", derive(Serialize))]
780pub struct Enum {
781 pub cases: Vec<EnumCase>,
782}
783
784#[derive(Debug, Clone, PartialEq, Hash, Eq)]
785#[cfg_attr(feature = "serde", derive(Serialize))]
786pub struct EnumCase {
787 pub name: String,
788 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
789 pub docs: Docs,
790}
791
792impl Enum {
793 pub fn tag(&self) -> Int {
794 discriminant_type(self.cases.len())
795 }
796}
797
798fn discriminant_type(num_cases: usize) -> Int {
800 match num_cases.checked_sub(1) {
801 None => Int::U8,
802 Some(n) if n <= u8::max_value() as usize => Int::U8,
803 Some(n) if n <= u16::max_value() as usize => Int::U16,
804 Some(n) if n <= u32::max_value() as usize => Int::U32,
805 _ => panic!("too many cases to fit in a repr"),
806 }
807}
808
809#[derive(Debug, Clone, PartialEq, Hash, Eq)]
810#[cfg_attr(feature = "serde", derive(Serialize))]
811pub struct Result_ {
812 pub ok: Option<Type>,
813 pub err: Option<Type>,
814}
815
816#[derive(Clone, Default, Debug, PartialEq, Eq, Hash)]
817#[cfg_attr(feature = "serde", derive(Serialize))]
818pub struct Docs {
819 pub contents: Option<String>,
820}
821
822impl Docs {
823 pub fn is_empty(&self) -> bool {
824 self.contents.is_none()
825 }
826}
827
828#[derive(Debug, Clone, PartialEq, Eq)]
829#[cfg_attr(feature = "serde", derive(Serialize))]
830pub struct Function {
831 pub name: String,
832 pub kind: FunctionKind,
833 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_params"))]
834 pub params: Vec<(String, Type)>,
835 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
836 pub result: Option<Type>,
837 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
838 pub docs: Docs,
839 #[cfg_attr(
841 feature = "serde",
842 serde(skip_serializing_if = "Stability::is_unknown")
843 )]
844 pub stability: Stability,
845}
846
847#[derive(Debug, Clone, PartialEq, Eq)]
848#[cfg_attr(feature = "serde", derive(Serialize))]
849#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
850pub enum FunctionKind {
851 Freestanding,
859
860 AsyncFreestanding,
868
869 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
880 Method(TypeId),
881
882 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
893 AsyncMethod(TypeId),
894
895 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
905 Static(TypeId),
906
907 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
917 AsyncStatic(TypeId),
918
919 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
929 Constructor(TypeId),
930}
931
932impl FunctionKind {
933 pub fn is_async(&self) -> bool {
935 match self {
936 FunctionKind::Freestanding
937 | FunctionKind::Method(_)
938 | FunctionKind::Static(_)
939 | FunctionKind::Constructor(_) => false,
940 FunctionKind::AsyncFreestanding
941 | FunctionKind::AsyncMethod(_)
942 | FunctionKind::AsyncStatic(_) => true,
943 }
944 }
945
946 pub fn resource(&self) -> Option<TypeId> {
948 match self {
949 FunctionKind::Freestanding | FunctionKind::AsyncFreestanding => None,
950 FunctionKind::Method(id)
951 | FunctionKind::Static(id)
952 | FunctionKind::Constructor(id)
953 | FunctionKind::AsyncMethod(id)
954 | FunctionKind::AsyncStatic(id) => Some(*id),
955 }
956 }
957
958 pub fn resource_mut(&mut self) -> Option<&mut TypeId> {
960 match self {
961 FunctionKind::Freestanding | FunctionKind::AsyncFreestanding => None,
962 FunctionKind::Method(id)
963 | FunctionKind::Static(id)
964 | FunctionKind::Constructor(id)
965 | FunctionKind::AsyncMethod(id)
966 | FunctionKind::AsyncStatic(id) => Some(id),
967 }
968 }
969}
970
971#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
973pub enum Mangling {
974 Standard32,
977
978 Legacy,
983}
984
985impl std::str::FromStr for Mangling {
986 type Err = anyhow::Error;
987
988 fn from_str(s: &str) -> Result<Mangling> {
989 match s {
990 "legacy" => Ok(Mangling::Legacy),
991 "standard32" => Ok(Mangling::Standard32),
992 _ => {
993 bail!(
994 "unknown name mangling `{s}`, \
995 supported values are `legacy` or `standard32`"
996 )
997 }
998 }
999 }
1000}
1001
1002#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1004pub enum LiftLowerAbi {
1005 Sync,
1007
1008 AsyncCallback,
1011
1012 AsyncStackful,
1015}
1016
1017impl LiftLowerAbi {
1018 fn import_prefix(self) -> &'static str {
1019 match self {
1020 Self::Sync => "",
1021 Self::AsyncCallback | Self::AsyncStackful => "[async-lower]",
1022 }
1023 }
1024
1025 pub fn import_variant(self) -> AbiVariant {
1027 match self {
1028 Self::Sync => AbiVariant::GuestImport,
1029 Self::AsyncCallback | Self::AsyncStackful => AbiVariant::GuestImportAsync,
1030 }
1031 }
1032
1033 fn export_prefix(self) -> &'static str {
1034 match self {
1035 Self::Sync => "",
1036 Self::AsyncCallback => "[async-lift]",
1037 Self::AsyncStackful => "[async-lift-stackful]",
1038 }
1039 }
1040
1041 pub fn export_variant(self) -> AbiVariant {
1043 match self {
1044 Self::Sync => AbiVariant::GuestExport,
1045 Self::AsyncCallback => AbiVariant::GuestExportAsync,
1046 Self::AsyncStackful => AbiVariant::GuestExportAsyncStackful,
1047 }
1048 }
1049}
1050
1051#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1053pub enum ManglingAndAbi {
1054 Standard32,
1059
1060 Legacy(LiftLowerAbi),
1062}
1063
1064impl ManglingAndAbi {
1065 pub fn import_variant(self) -> AbiVariant {
1067 match self {
1068 Self::Standard32 => AbiVariant::GuestImport,
1069 Self::Legacy(abi) => abi.import_variant(),
1070 }
1071 }
1072
1073 pub fn export_variant(self) -> AbiVariant {
1075 match self {
1076 Self::Standard32 => AbiVariant::GuestExport,
1077 Self::Legacy(abi) => abi.export_variant(),
1078 }
1079 }
1080
1081 pub fn sync(self) -> Self {
1083 match self {
1084 Self::Standard32 | Self::Legacy(LiftLowerAbi::Sync) => self,
1085 Self::Legacy(LiftLowerAbi::AsyncCallback)
1086 | Self::Legacy(LiftLowerAbi::AsyncStackful) => Self::Legacy(LiftLowerAbi::Sync),
1087 }
1088 }
1089
1090 pub fn is_async(&self) -> bool {
1092 match self {
1093 Self::Standard32 | Self::Legacy(LiftLowerAbi::Sync) => false,
1094 Self::Legacy(LiftLowerAbi::AsyncCallback)
1095 | Self::Legacy(LiftLowerAbi::AsyncStackful) => true,
1096 }
1097 }
1098
1099 pub fn mangling(&self) -> Mangling {
1100 match self {
1101 Self::Standard32 => Mangling::Standard32,
1102 Self::Legacy(_) => Mangling::Legacy,
1103 }
1104 }
1105}
1106
1107impl Function {
1108 pub fn item_name(&self) -> &str {
1109 match &self.kind {
1110 FunctionKind::Freestanding | FunctionKind::AsyncFreestanding => &self.name,
1111 FunctionKind::Method(_)
1112 | FunctionKind::Static(_)
1113 | FunctionKind::AsyncMethod(_)
1114 | FunctionKind::AsyncStatic(_) => &self.name[self.name.find('.').unwrap() + 1..],
1115 FunctionKind::Constructor(_) => "constructor",
1116 }
1117 }
1118
1119 pub fn parameter_and_result_types(&self) -> impl Iterator<Item = Type> + '_ {
1124 self.params.iter().map(|(_, t)| *t).chain(self.result)
1125 }
1126
1127 pub fn standard32_core_export_name<'a>(&'a self, interface: Option<&str>) -> Cow<'a, str> {
1129 self.core_export_name(interface, Mangling::Standard32)
1130 }
1131
1132 pub fn legacy_core_export_name<'a>(&'a self, interface: Option<&str>) -> Cow<'a, str> {
1133 self.core_export_name(interface, Mangling::Legacy)
1134 }
1135 pub fn core_export_name<'a>(
1137 &'a self,
1138 interface: Option<&str>,
1139 mangling: Mangling,
1140 ) -> Cow<'a, str> {
1141 match interface {
1142 Some(interface) => match mangling {
1143 Mangling::Standard32 => Cow::Owned(format!("cm32p2|{interface}|{}", self.name)),
1144 Mangling::Legacy => Cow::Owned(format!("{interface}#{}", self.name)),
1145 },
1146 None => match mangling {
1147 Mangling::Standard32 => Cow::Owned(format!("cm32p2||{}", self.name)),
1148 Mangling::Legacy => Cow::Borrowed(&self.name),
1149 },
1150 }
1151 }
1152 pub fn find_futures_and_streams(&self, resolve: &Resolve) -> Vec<TypeId> {
1168 let mut results = Vec::new();
1169 for (_, ty) in self.params.iter() {
1170 find_futures_and_streams(resolve, *ty, &mut results);
1171 }
1172 if let Some(ty) = self.result {
1173 find_futures_and_streams(resolve, ty, &mut results);
1174 }
1175 results
1176 }
1177
1178 pub fn is_constructor_shorthand(&self, resolve: &Resolve) -> bool {
1181 let FunctionKind::Constructor(containing_resource_id) = self.kind else {
1182 return false;
1183 };
1184
1185 let Some(Type::Id(id)) = &self.result else {
1186 return false;
1187 };
1188
1189 let TypeDefKind::Handle(Handle::Own(returned_resource_id)) = resolve.types[*id].kind else {
1190 return false;
1191 };
1192
1193 return containing_resource_id == returned_resource_id;
1194 }
1195
1196 pub fn task_return_import(
1199 &self,
1200 resolve: &Resolve,
1201 interface: Option<&WorldKey>,
1202 mangling: Mangling,
1203 ) -> (String, String, abi::WasmSignature) {
1204 match mangling {
1205 Mangling::Standard32 => todo!(),
1206 Mangling::Legacy => {}
1207 }
1208 let module = match interface {
1210 Some(key) => format!("[export]{}", resolve.name_world_key(key)),
1211 None => "[export]$root".to_string(),
1212 };
1213 let name = format!("[task-return]{}", self.name);
1214
1215 let mut func_tmp = self.clone();
1216 func_tmp.params = Vec::new();
1217 func_tmp.result = None;
1218 if let Some(ty) = self.result {
1219 func_tmp.params.push(("x".to_string(), ty));
1220 }
1221 let sig = resolve.wasm_signature(AbiVariant::GuestImport, &func_tmp);
1222 (module, name, sig)
1223 }
1224
1225 }
1227
1228fn find_futures_and_streams(resolve: &Resolve, ty: Type, results: &mut Vec<TypeId>) {
1229 let Type::Id(id) = ty else {
1230 return;
1231 };
1232
1233 match &resolve.types[id].kind {
1234 TypeDefKind::Resource
1235 | TypeDefKind::Handle(_)
1236 | TypeDefKind::Flags(_)
1237 | TypeDefKind::Enum(_) => {}
1238 TypeDefKind::Record(r) => {
1239 for Field { ty, .. } in &r.fields {
1240 find_futures_and_streams(resolve, *ty, results);
1241 }
1242 }
1243 TypeDefKind::Tuple(t) => {
1244 for ty in &t.types {
1245 find_futures_and_streams(resolve, *ty, results);
1246 }
1247 }
1248 TypeDefKind::Variant(v) => {
1249 for Case { ty, .. } in &v.cases {
1250 if let Some(ty) = ty {
1251 find_futures_and_streams(resolve, *ty, results);
1252 }
1253 }
1254 }
1255 TypeDefKind::Option(ty)
1256 | TypeDefKind::List(ty)
1257 | TypeDefKind::FixedSizeList(ty, ..)
1258 | TypeDefKind::Type(ty) => {
1259 find_futures_and_streams(resolve, *ty, results);
1260 }
1261 TypeDefKind::Map(k, v) => {
1262 find_futures_and_streams(resolve, *k, results);
1263 find_futures_and_streams(resolve, *v, results);
1264 }
1265 TypeDefKind::Result(r) => {
1266 if let Some(ty) = r.ok {
1267 find_futures_and_streams(resolve, ty, results);
1268 }
1269 if let Some(ty) = r.err {
1270 find_futures_and_streams(resolve, ty, results);
1271 }
1272 }
1273 TypeDefKind::Future(ty) => {
1274 if let Some(ty) = ty {
1275 find_futures_and_streams(resolve, *ty, results);
1276 }
1277 results.push(id);
1278 }
1279 TypeDefKind::Stream(ty) => {
1280 if let Some(ty) = ty {
1281 find_futures_and_streams(resolve, *ty, results);
1282 }
1283 results.push(id);
1284 }
1285 TypeDefKind::Unknown => unreachable!(),
1286 }
1287}
1288
1289#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
1297#[cfg_attr(feature = "serde", derive(serde_derive::Deserialize, Serialize))]
1298#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
1299pub enum Stability {
1300 Unknown,
1302
1303 Unstable {
1308 feature: String,
1309 #[cfg_attr(
1310 feature = "serde",
1311 serde(
1312 skip_serializing_if = "Option::is_none",
1313 default,
1314 serialize_with = "serialize_optional_version",
1315 deserialize_with = "deserialize_optional_version"
1316 )
1317 )]
1318 deprecated: Option<Version>,
1319 },
1320
1321 Stable {
1326 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_version"))]
1327 #[cfg_attr(feature = "serde", serde(deserialize_with = "deserialize_version"))]
1328 since: Version,
1329 #[cfg_attr(
1330 feature = "serde",
1331 serde(
1332 skip_serializing_if = "Option::is_none",
1333 default,
1334 serialize_with = "serialize_optional_version",
1335 deserialize_with = "deserialize_optional_version"
1336 )
1337 )]
1338 deprecated: Option<Version>,
1339 },
1340}
1341
1342impl Stability {
1343 pub fn is_unknown(&self) -> bool {
1345 matches!(self, Stability::Unknown)
1346 }
1347
1348 pub fn is_stable(&self) -> bool {
1349 matches!(self, Stability::Stable { .. })
1350 }
1351}
1352
1353impl Default for Stability {
1354 fn default() -> Stability {
1355 Stability::Unknown
1356 }
1357}
1358
1359#[cfg(test)]
1360mod test {
1361 use super::*;
1362
1363 #[test]
1364 fn test_discriminant_type() {
1365 assert_eq!(discriminant_type(1), Int::U8);
1366 assert_eq!(discriminant_type(0x100), Int::U8);
1367 assert_eq!(discriminant_type(0x101), Int::U16);
1368 assert_eq!(discriminant_type(0x10000), Int::U16);
1369 assert_eq!(discriminant_type(0x10001), Int::U32);
1370 if let Ok(num_cases) = usize::try_from(0x100000000_u64) {
1371 assert_eq!(discriminant_type(num_cases), Int::U32);
1372 }
1373 }
1374
1375 #[test]
1376 fn test_find_futures_and_streams() {
1377 let mut resolve = Resolve::default();
1378 let t0 = resolve.types.alloc(TypeDef {
1379 name: None,
1380 kind: TypeDefKind::Future(Some(Type::U32)),
1381 owner: TypeOwner::None,
1382 docs: Docs::default(),
1383 stability: Stability::Unknown,
1384 });
1385 let t1 = resolve.types.alloc(TypeDef {
1386 name: None,
1387 kind: TypeDefKind::Future(Some(Type::Id(t0))),
1388 owner: TypeOwner::None,
1389 docs: Docs::default(),
1390 stability: Stability::Unknown,
1391 });
1392 let t2 = resolve.types.alloc(TypeDef {
1393 name: None,
1394 kind: TypeDefKind::Stream(Some(Type::U32)),
1395 owner: TypeOwner::None,
1396 docs: Docs::default(),
1397 stability: Stability::Unknown,
1398 });
1399 let found = Function {
1400 name: "foo".into(),
1401 kind: FunctionKind::Freestanding,
1402 params: vec![("p1".into(), Type::Id(t1)), ("p2".into(), Type::U32)],
1403 result: Some(Type::Id(t2)),
1404 docs: Docs::default(),
1405 stability: Stability::Unknown,
1406 }
1407 .find_futures_and_streams(&resolve);
1408 assert_eq!(3, found.len());
1409 assert_eq!(t0, found[0]);
1410 assert_eq!(t1, found[1]);
1411 assert_eq!(t2, found[2]);
1412 }
1413}