1#![no_std]
2
3extern crate alloc;
4
5#[cfg(feature = "std")]
6extern crate std;
7
8use crate::abi::AbiVariant;
9use alloc::format;
10use alloc::string::{String, ToString};
11use alloc::vec::Vec;
12#[cfg(feature = "std")]
13use anyhow::Context;
14use anyhow::{Result, bail};
15use id_arena::{Arena, Id};
16use semver::Version;
17
18#[cfg(feature = "std")]
19pub type IndexMap<K, V> = indexmap::IndexMap<K, V, std::hash::RandomState>;
20#[cfg(feature = "std")]
21pub type IndexSet<T> = indexmap::IndexSet<T, std::hash::RandomState>;
22#[cfg(not(feature = "std"))]
23pub type IndexMap<K, V> = indexmap::IndexMap<K, V, hashbrown::DefaultHashBuilder>;
24#[cfg(not(feature = "std"))]
25pub type IndexSet<T> = indexmap::IndexSet<T, hashbrown::DefaultHashBuilder>;
26
27#[cfg(feature = "std")]
28pub(crate) use std::collections::{HashMap, HashSet};
29
30#[cfg(not(feature = "std"))]
31pub(crate) use hashbrown::{HashMap, HashSet};
32
33use alloc::borrow::Cow;
34use core::fmt;
35use core::hash::{Hash, Hasher};
36#[cfg(feature = "std")]
37use std::path::Path;
38
39#[cfg(feature = "decoding")]
40pub mod decoding;
41#[cfg(feature = "decoding")]
42mod metadata;
43#[cfg(feature = "decoding")]
44pub use metadata::PackageMetadata;
45
46pub mod abi;
47mod ast;
48pub use ast::SourceMap;
49pub use ast::lex::Span;
50pub use ast::{ParsedUsePath, parse_use_path};
51mod sizealign;
52pub use sizealign::*;
53mod resolve;
54pub use resolve::*;
55mod live;
56pub use live::{LiveTypes, TypeIdVisitor};
57
58#[cfg(feature = "serde")]
59use serde_derive::Serialize;
60#[cfg(feature = "serde")]
61mod serde_;
62#[cfg(feature = "serde")]
63use serde_::*;
64
65pub fn validate_id(s: &str) -> Result<()> {
67 ast::validate_id(0, s)?;
68 Ok(())
69}
70
71pub type WorldId = Id<World>;
72pub type InterfaceId = Id<Interface>;
73pub type TypeId = Id<TypeDef>;
74
75#[derive(Clone)]
101pub struct UnresolvedPackage {
102 pub name: PackageName,
104
105 pub worlds: Arena<World>,
109
110 pub interfaces: Arena<Interface>,
117
118 pub types: Arena<TypeDef>,
125
126 pub foreign_deps: IndexMap<PackageName, IndexMap<String, (AstItem, Vec<Stability>)>>,
135
136 pub docs: Docs,
138
139 #[cfg_attr(not(feature = "std"), allow(dead_code))]
140 package_name_span: Span,
141 unknown_type_spans: Vec<Span>,
142 foreign_dep_spans: Vec<Span>,
143 required_resource_types: Vec<(TypeId, Span)>,
144}
145
146impl UnresolvedPackage {
147 pub(crate) fn adjust_spans(&mut self, offset: u32) {
152 self.package_name_span.adjust(offset);
154 for span in &mut self.unknown_type_spans {
155 span.adjust(offset);
156 }
157 for span in &mut self.foreign_dep_spans {
158 span.adjust(offset);
159 }
160 for (_, span) in &mut self.required_resource_types {
161 span.adjust(offset);
162 }
163
164 for (_, world) in self.worlds.iter_mut() {
166 world.adjust_spans(offset);
167 }
168 for (_, iface) in self.interfaces.iter_mut() {
169 iface.adjust_spans(offset);
170 }
171 for (_, ty) in self.types.iter_mut() {
172 ty.adjust_spans(offset);
173 }
174 }
175}
176
177#[derive(Clone)]
179pub struct UnresolvedPackageGroup {
180 pub main: UnresolvedPackage,
185
186 pub nested: Vec<UnresolvedPackage>,
188
189 pub source_map: SourceMap,
191}
192
193#[derive(Debug, Copy, Clone)]
194#[cfg_attr(feature = "serde", derive(Serialize))]
195#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
196pub enum AstItem {
197 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
198 Interface(InterfaceId),
199 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
200 World(WorldId),
201}
202
203#[derive(Debug, Clone, Hash, Eq, PartialEq, Ord, PartialOrd)]
209#[cfg_attr(feature = "serde", derive(Serialize))]
210#[cfg_attr(feature = "serde", serde(into = "String"))]
211pub struct PackageName {
212 pub namespace: String,
214 pub name: String,
216 pub version: Option<Version>,
218}
219
220impl From<PackageName> for String {
221 fn from(name: PackageName) -> String {
222 name.to_string()
223 }
224}
225
226impl PackageName {
227 pub fn interface_id(&self, interface: &str) -> String {
230 let mut s = String::new();
231 s.push_str(&format!("{}:{}/{interface}", self.namespace, self.name));
232 if let Some(version) = &self.version {
233 s.push_str(&format!("@{version}"));
234 }
235 s
236 }
237
238 pub fn version_compat_track(version: &Version) -> Version {
251 let mut version = version.clone();
252 version.build = semver::BuildMetadata::EMPTY;
253 if !version.pre.is_empty() {
254 return version;
255 }
256 if version.major != 0 {
257 version.minor = 0;
258 version.patch = 0;
259 return version;
260 }
261 if version.minor != 0 {
262 version.patch = 0;
263 return version;
264 }
265 version
266 }
267
268 pub fn version_compat_track_string(version: &Version) -> String {
272 let version = Self::version_compat_track(version);
273 if !version.pre.is_empty() {
274 return version.to_string();
275 }
276 if version.major != 0 {
277 return format!("{}", version.major);
278 }
279 if version.minor != 0 {
280 return format!("{}.{}", version.major, version.minor);
281 }
282 version.to_string()
283 }
284}
285
286impl fmt::Display for PackageName {
287 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
288 write!(f, "{}:{}", self.namespace, self.name)?;
289 if let Some(version) = &self.version {
290 write!(f, "@{version}")?;
291 }
292 Ok(())
293 }
294}
295
296#[derive(Debug)]
297struct Error {
298 span: Span,
299 msg: String,
300 highlighted: Option<String>,
301}
302
303impl Error {
304 fn new(span: Span, msg: impl Into<String>) -> Error {
305 Error {
306 span,
307 msg: msg.into(),
308 highlighted: None,
309 }
310 }
311
312 fn highlight(&mut self, source_map: &ast::SourceMap) {
314 if self.highlighted.is_none() {
315 self.highlighted = source_map.highlight_span(self.span, &self.msg);
316 }
317 }
318}
319
320impl fmt::Display for Error {
321 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
322 self.highlighted.as_ref().unwrap_or(&self.msg).fmt(f)
323 }
324}
325
326impl core::error::Error for Error {}
327
328#[derive(Debug)]
329struct PackageNotFoundError {
330 span: Span,
331 requested: PackageName,
332 known: Vec<PackageName>,
333 highlighted: Option<String>,
334}
335
336impl PackageNotFoundError {
337 pub fn new(span: Span, requested: PackageName, known: Vec<PackageName>) -> Self {
338 Self {
339 span,
340 requested,
341 known,
342 highlighted: None,
343 }
344 }
345
346 fn highlight(&mut self, source_map: &ast::SourceMap) {
348 if self.highlighted.is_none() {
349 self.highlighted = source_map.highlight_span(self.span, &format!("{self}"));
350 }
351 }
352}
353
354impl fmt::Display for PackageNotFoundError {
355 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
356 if let Some(highlighted) = &self.highlighted {
357 return highlighted.fmt(f);
358 }
359 if self.known.is_empty() {
360 write!(
361 f,
362 "package '{}' not found. no known packages.",
363 self.requested
364 )?;
365 } else {
366 write!(
367 f,
368 "package '{}' not found. known packages:\n",
369 self.requested
370 )?;
371 for known in self.known.iter() {
372 write!(f, " {known}\n")?;
373 }
374 }
375 Ok(())
376 }
377}
378
379impl core::error::Error for PackageNotFoundError {}
380
381impl UnresolvedPackageGroup {
382 #[cfg(feature = "std")]
388 pub fn parse(path: impl AsRef<Path>, contents: &str) -> Result<UnresolvedPackageGroup> {
389 let path = path
390 .as_ref()
391 .to_str()
392 .ok_or_else(|| anyhow::anyhow!("path is not valid utf-8: {:?}", path.as_ref()))?;
393 Self::parse_str(path, contents)
394 }
395
396 pub fn parse_str(path: &str, contents: &str) -> Result<UnresolvedPackageGroup> {
402 let mut map = SourceMap::default();
403 map.push_str(path, contents);
404 map.parse()
405 }
406
407 #[cfg(feature = "std")]
413 pub fn parse_path(path: impl AsRef<Path>) -> Result<UnresolvedPackageGroup> {
414 let path = path.as_ref();
415 if path.is_dir() {
416 UnresolvedPackageGroup::parse_dir(path)
417 } else {
418 UnresolvedPackageGroup::parse_file(path)
419 }
420 }
421
422 #[cfg(feature = "std")]
427 pub fn parse_file(path: impl AsRef<Path>) -> Result<UnresolvedPackageGroup> {
428 let path = path.as_ref();
429 let contents = std::fs::read_to_string(path)
430 .with_context(|| format!("failed to read file {path:?}"))?;
431 Self::parse(path, &contents)
432 }
433
434 #[cfg(feature = "std")]
441 pub fn parse_dir(path: impl AsRef<Path>) -> Result<UnresolvedPackageGroup> {
442 let path = path.as_ref();
443 let mut map = SourceMap::default();
444 let cx = || format!("failed to read directory {path:?}");
445 for entry in path.read_dir().with_context(&cx)? {
446 let entry = entry.with_context(&cx)?;
447 let path = entry.path();
448 let ty = entry.file_type().with_context(&cx)?;
449 if ty.is_dir() {
450 continue;
451 }
452 if ty.is_symlink() {
453 if path.is_dir() {
454 continue;
455 }
456 }
457 let filename = match path.file_name().and_then(|s| s.to_str()) {
458 Some(name) => name,
459 None => continue,
460 };
461 if !filename.ends_with(".wit") {
462 continue;
463 }
464 map.push_file(&path)?;
465 }
466 map.parse()
467 }
468}
469
470#[derive(Debug, Clone)]
471#[cfg_attr(feature = "serde", derive(Serialize))]
472pub struct World {
473 pub name: String,
475
476 pub imports: IndexMap<WorldKey, WorldItem>,
478
479 pub exports: IndexMap<WorldKey, WorldItem>,
481
482 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_optional_id"))]
484 pub package: Option<PackageId>,
485
486 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
488 pub docs: Docs,
489
490 #[cfg_attr(
492 feature = "serde",
493 serde(skip_serializing_if = "Stability::is_unknown")
494 )]
495 pub stability: Stability,
496
497 #[cfg_attr(feature = "serde", serde(skip))]
499 pub includes: Vec<WorldInclude>,
500
501 #[cfg_attr(feature = "serde", serde(skip))]
503 pub span: Span,
504}
505
506impl World {
507 pub(crate) fn adjust_spans(&mut self, offset: u32) {
509 self.span.adjust(offset);
510 for item in self.imports.values_mut().chain(self.exports.values_mut()) {
511 item.adjust_spans(offset);
512 }
513 for include in &mut self.includes {
514 include.span.adjust(offset);
515 }
516 }
517}
518
519#[derive(Debug, Clone)]
520pub struct IncludeName {
521 pub name: String,
523
524 pub as_: String,
526}
527
528#[derive(Debug, Clone)]
531pub struct WorldInclude {
532 pub stability: Stability,
534
535 pub id: WorldId,
537
538 pub names: Vec<IncludeName>,
540
541 pub span: Span,
543}
544
545#[derive(Debug, Clone, Eq)]
548#[cfg_attr(feature = "serde", derive(Serialize))]
549#[cfg_attr(feature = "serde", serde(into = "String"))]
550pub enum WorldKey {
551 Name(String),
553 Interface(InterfaceId),
555}
556
557impl Hash for WorldKey {
558 fn hash<H: Hasher>(&self, hasher: &mut H) {
559 match self {
560 WorldKey::Name(s) => {
561 0u8.hash(hasher);
562 s.as_str().hash(hasher);
563 }
564 WorldKey::Interface(i) => {
565 1u8.hash(hasher);
566 i.hash(hasher);
567 }
568 }
569 }
570}
571
572impl PartialEq for WorldKey {
573 fn eq(&self, other: &WorldKey) -> bool {
574 match (self, other) {
575 (WorldKey::Name(a), WorldKey::Name(b)) => a.as_str() == b.as_str(),
576 (WorldKey::Name(_), _) => false,
577 (WorldKey::Interface(a), WorldKey::Interface(b)) => a == b,
578 (WorldKey::Interface(_), _) => false,
579 }
580 }
581}
582
583impl From<WorldKey> for String {
584 fn from(key: WorldKey) -> String {
585 match key {
586 WorldKey::Name(name) => name,
587 WorldKey::Interface(id) => format!("interface-{}", id.index()),
588 }
589 }
590}
591
592impl WorldKey {
593 #[track_caller]
595 pub fn unwrap_name(self) -> String {
596 match self {
597 WorldKey::Name(name) => name,
598 WorldKey::Interface(_) => panic!("expected a name, found interface"),
599 }
600 }
601}
602
603#[derive(Debug, Clone, PartialEq)]
604#[cfg_attr(feature = "serde", derive(Serialize))]
605#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
606pub enum WorldItem {
607 Interface {
610 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
611 id: InterfaceId,
612 #[cfg_attr(
613 feature = "serde",
614 serde(skip_serializing_if = "Stability::is_unknown")
615 )]
616 stability: Stability,
617 #[cfg_attr(feature = "serde", serde(skip))]
618 span: Span,
619 },
620
621 Function(Function),
623
624 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id_ignore_span"))]
628 Type { id: TypeId, span: Span },
629}
630
631impl WorldItem {
632 pub fn stability<'a>(&'a self, resolve: &'a Resolve) -> &'a Stability {
633 match self {
634 WorldItem::Interface { stability, .. } => stability,
635 WorldItem::Function(f) => &f.stability,
636 WorldItem::Type { id, .. } => &resolve.types[*id].stability,
637 }
638 }
639
640 pub fn span(&self) -> Span {
641 match self {
642 WorldItem::Interface { span, .. } => *span,
643 WorldItem::Function(f) => f.span,
644 WorldItem::Type { span, .. } => *span,
645 }
646 }
647
648 pub(crate) fn adjust_spans(&mut self, offset: u32) {
649 match self {
650 WorldItem::Function(f) => f.adjust_spans(offset),
651 WorldItem::Interface { span, .. } => span.adjust(offset),
652 WorldItem::Type { span, .. } => span.adjust(offset),
653 }
654 }
655}
656
657#[derive(Debug, Clone)]
658#[cfg_attr(feature = "serde", derive(Serialize))]
659pub struct Interface {
660 pub name: Option<String>,
664
665 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id_map"))]
670 pub types: IndexMap<String, TypeId>,
671
672 pub functions: IndexMap<String, Function>,
674
675 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
677 pub docs: Docs,
678
679 #[cfg_attr(
681 feature = "serde",
682 serde(skip_serializing_if = "Stability::is_unknown")
683 )]
684 pub stability: Stability,
685
686 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_optional_id"))]
688 pub package: Option<PackageId>,
689
690 #[cfg_attr(feature = "serde", serde(skip))]
692 pub span: Span,
693
694 #[cfg_attr(
698 feature = "serde",
699 serde(
700 skip_serializing_if = "Option::is_none",
701 serialize_with = "serialize_optional_id",
702 )
703 )]
704 pub clone_of: Option<InterfaceId>,
705}
706
707impl Interface {
708 pub(crate) fn adjust_spans(&mut self, offset: u32) {
710 self.span.adjust(offset);
711 for func in self.functions.values_mut() {
712 func.adjust_spans(offset);
713 }
714 }
715}
716
717#[derive(Debug, Clone, PartialEq)]
718#[cfg_attr(feature = "serde", derive(Serialize))]
719pub struct TypeDef {
720 pub name: Option<String>,
721 pub kind: TypeDefKind,
722 pub owner: TypeOwner,
723 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
724 pub docs: Docs,
725 #[cfg_attr(
727 feature = "serde",
728 serde(skip_serializing_if = "Stability::is_unknown")
729 )]
730 pub stability: Stability,
731 #[cfg_attr(feature = "serde", serde(skip))]
733 pub span: Span,
734}
735
736impl TypeDef {
737 pub(crate) fn adjust_spans(&mut self, offset: u32) {
742 self.span.adjust(offset);
743 match &mut self.kind {
744 TypeDefKind::Record(r) => {
745 for field in &mut r.fields {
746 field.span.adjust(offset);
747 }
748 }
749 TypeDefKind::Variant(v) => {
750 for case in &mut v.cases {
751 case.span.adjust(offset);
752 }
753 }
754 TypeDefKind::Enum(e) => {
755 for case in &mut e.cases {
756 case.span.adjust(offset);
757 }
758 }
759 TypeDefKind::Flags(f) => {
760 for flag in &mut f.flags {
761 flag.span.adjust(offset);
762 }
763 }
764 _ => {}
765 }
766 }
767}
768
769#[derive(Debug, Clone, PartialEq, Hash, Eq)]
770#[cfg_attr(feature = "serde", derive(Serialize))]
771#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
772pub enum TypeDefKind {
773 Record(Record),
774 Resource,
775 Handle(Handle),
776 Flags(Flags),
777 Tuple(Tuple),
778 Variant(Variant),
779 Enum(Enum),
780 Option(Type),
781 Result(Result_),
782 List(Type),
783 Map(Type, Type),
784 FixedLengthList(Type, u32),
785 Future(Option<Type>),
786 Stream(Option<Type>),
787 Type(Type),
788
789 Unknown,
795}
796
797impl TypeDefKind {
798 pub fn as_str(&self) -> &'static str {
799 match self {
800 TypeDefKind::Record(_) => "record",
801 TypeDefKind::Resource => "resource",
802 TypeDefKind::Handle(handle) => match handle {
803 Handle::Own(_) => "own",
804 Handle::Borrow(_) => "borrow",
805 },
806 TypeDefKind::Flags(_) => "flags",
807 TypeDefKind::Tuple(_) => "tuple",
808 TypeDefKind::Variant(_) => "variant",
809 TypeDefKind::Enum(_) => "enum",
810 TypeDefKind::Option(_) => "option",
811 TypeDefKind::Result(_) => "result",
812 TypeDefKind::List(_) => "list",
813 TypeDefKind::Map(_, _) => "map",
814 TypeDefKind::FixedLengthList(..) => "fixed-length list",
815 TypeDefKind::Future(_) => "future",
816 TypeDefKind::Stream(_) => "stream",
817 TypeDefKind::Type(_) => "type",
818 TypeDefKind::Unknown => "unknown",
819 }
820 }
821}
822
823#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
824#[cfg_attr(feature = "serde", derive(Serialize))]
825#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
826pub enum TypeOwner {
827 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
829 World(WorldId),
830 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
832 Interface(InterfaceId),
833 #[cfg_attr(feature = "serde", serde(untagged, serialize_with = "serialize_none"))]
836 None,
837}
838
839#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone)]
840#[cfg_attr(feature = "serde", derive(Serialize))]
841#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
842pub enum Handle {
843 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
844 Own(TypeId),
845 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
846 Borrow(TypeId),
847}
848
849#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, Clone)]
850pub enum Type {
851 Bool,
852 U8,
853 U16,
854 U32,
855 U64,
856 S8,
857 S16,
858 S32,
859 S64,
860 F32,
861 F64,
862 Char,
863 String,
864 ErrorContext,
865 Id(TypeId),
866}
867
868#[derive(Debug, Copy, Clone, Eq, PartialEq)]
869pub enum Int {
870 U8,
871 U16,
872 U32,
873 U64,
874}
875
876#[derive(Debug, Clone, PartialEq, Hash, Eq)]
877#[cfg_attr(feature = "serde", derive(Serialize))]
878pub struct Record {
879 pub fields: Vec<Field>,
880}
881
882#[derive(Debug, Clone, PartialEq, Hash, Eq)]
883#[cfg_attr(feature = "serde", derive(Serialize))]
884pub struct Field {
885 pub name: String,
886 #[cfg_attr(feature = "serde", serde(rename = "type"))]
887 pub ty: Type,
888 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
889 pub docs: Docs,
890 #[cfg_attr(feature = "serde", serde(skip))]
892 pub span: Span,
893}
894
895#[derive(Debug, Clone, PartialEq, Hash, Eq)]
896#[cfg_attr(feature = "serde", derive(Serialize))]
897pub struct Flags {
898 pub flags: Vec<Flag>,
899}
900
901#[derive(Debug, Clone, PartialEq, Hash, Eq)]
902#[cfg_attr(feature = "serde", derive(Serialize))]
903pub struct Flag {
904 pub name: String,
905 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
906 pub docs: Docs,
907 #[cfg_attr(feature = "serde", serde(skip))]
909 pub span: Span,
910}
911
912#[derive(Debug, Clone, PartialEq)]
913pub enum FlagsRepr {
914 U8,
915 U16,
916 U32(usize),
917}
918
919impl Flags {
920 pub fn repr(&self) -> FlagsRepr {
921 match self.flags.len() {
922 0 => FlagsRepr::U32(0),
923 n if n <= 8 => FlagsRepr::U8,
924 n if n <= 16 => FlagsRepr::U16,
925 n => FlagsRepr::U32(sizealign::align_to(n, 32) / 32),
926 }
927 }
928}
929
930impl FlagsRepr {
931 pub fn count(&self) -> usize {
932 match self {
933 FlagsRepr::U8 => 1,
934 FlagsRepr::U16 => 1,
935 FlagsRepr::U32(n) => *n,
936 }
937 }
938}
939
940#[derive(Debug, Clone, PartialEq, Hash, Eq)]
941#[cfg_attr(feature = "serde", derive(Serialize))]
942pub struct Tuple {
943 pub types: Vec<Type>,
944}
945
946#[derive(Debug, Clone, PartialEq, Hash, Eq)]
947#[cfg_attr(feature = "serde", derive(Serialize))]
948pub struct Variant {
949 pub cases: Vec<Case>,
950}
951
952#[derive(Debug, Clone, PartialEq, Hash, Eq)]
953#[cfg_attr(feature = "serde", derive(Serialize))]
954pub struct Case {
955 pub name: String,
956 #[cfg_attr(feature = "serde", serde(rename = "type"))]
957 pub ty: Option<Type>,
958 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
959 pub docs: Docs,
960 #[cfg_attr(feature = "serde", serde(skip))]
962 pub span: Span,
963}
964
965impl Variant {
966 pub fn tag(&self) -> Int {
967 discriminant_type(self.cases.len())
968 }
969}
970
971#[derive(Debug, Clone, PartialEq, Hash, Eq)]
972#[cfg_attr(feature = "serde", derive(Serialize))]
973pub struct Enum {
974 pub cases: Vec<EnumCase>,
975}
976
977#[derive(Debug, Clone, PartialEq, Hash, Eq)]
978#[cfg_attr(feature = "serde", derive(Serialize))]
979pub struct EnumCase {
980 pub name: String,
981 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
982 pub docs: Docs,
983 #[cfg_attr(feature = "serde", serde(skip))]
985 pub span: Span,
986}
987
988impl Enum {
989 pub fn tag(&self) -> Int {
990 discriminant_type(self.cases.len())
991 }
992}
993
994fn discriminant_type(num_cases: usize) -> Int {
996 match num_cases.checked_sub(1) {
997 None => Int::U8,
998 Some(n) if n <= u8::max_value() as usize => Int::U8,
999 Some(n) if n <= u16::max_value() as usize => Int::U16,
1000 Some(n) if n <= u32::max_value() as usize => Int::U32,
1001 _ => panic!("too many cases to fit in a repr"),
1002 }
1003}
1004
1005#[derive(Debug, Clone, PartialEq, Hash, Eq)]
1006#[cfg_attr(feature = "serde", derive(Serialize))]
1007pub struct Result_ {
1008 pub ok: Option<Type>,
1009 pub err: Option<Type>,
1010}
1011
1012#[derive(Clone, Default, Debug, PartialEq, Eq, Hash)]
1013#[cfg_attr(feature = "serde", derive(Serialize))]
1014pub struct Docs {
1015 pub contents: Option<String>,
1016}
1017
1018impl Docs {
1019 pub fn is_empty(&self) -> bool {
1020 self.contents.is_none()
1021 }
1022}
1023
1024#[derive(Debug, Clone, PartialEq, Eq)]
1025#[cfg_attr(feature = "serde", derive(Serialize))]
1026pub struct Param {
1027 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "String::is_empty"))]
1028 pub name: String,
1029 #[cfg_attr(feature = "serde", serde(rename = "type"))]
1030 pub ty: Type,
1031 #[cfg_attr(feature = "serde", serde(skip))]
1032 pub span: Span,
1033}
1034
1035#[derive(Debug, Clone, PartialEq, Eq)]
1036#[cfg_attr(feature = "serde", derive(Serialize))]
1037pub struct Function {
1038 pub name: String,
1039 pub kind: FunctionKind,
1040 pub params: Vec<Param>,
1041 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
1042 pub result: Option<Type>,
1043 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
1044 pub docs: Docs,
1045 #[cfg_attr(
1047 feature = "serde",
1048 serde(skip_serializing_if = "Stability::is_unknown")
1049 )]
1050 pub stability: Stability,
1051
1052 #[cfg_attr(feature = "serde", serde(skip))]
1054 pub span: Span,
1055}
1056
1057#[derive(Debug, Clone, PartialEq, Eq)]
1058#[cfg_attr(feature = "serde", derive(Serialize))]
1059#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
1060pub enum FunctionKind {
1061 Freestanding,
1069
1070 AsyncFreestanding,
1078
1079 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
1090 Method(TypeId),
1091
1092 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
1103 AsyncMethod(TypeId),
1104
1105 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
1115 Static(TypeId),
1116
1117 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
1127 AsyncStatic(TypeId),
1128
1129 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
1139 Constructor(TypeId),
1140}
1141
1142impl FunctionKind {
1143 pub fn is_async(&self) -> bool {
1145 match self {
1146 FunctionKind::Freestanding
1147 | FunctionKind::Method(_)
1148 | FunctionKind::Static(_)
1149 | FunctionKind::Constructor(_) => false,
1150 FunctionKind::AsyncFreestanding
1151 | FunctionKind::AsyncMethod(_)
1152 | FunctionKind::AsyncStatic(_) => true,
1153 }
1154 }
1155
1156 pub fn resource(&self) -> Option<TypeId> {
1158 match self {
1159 FunctionKind::Freestanding | FunctionKind::AsyncFreestanding => None,
1160 FunctionKind::Method(id)
1161 | FunctionKind::Static(id)
1162 | FunctionKind::Constructor(id)
1163 | FunctionKind::AsyncMethod(id)
1164 | FunctionKind::AsyncStatic(id) => Some(*id),
1165 }
1166 }
1167
1168 pub fn resource_mut(&mut self) -> Option<&mut TypeId> {
1170 match self {
1171 FunctionKind::Freestanding | FunctionKind::AsyncFreestanding => None,
1172 FunctionKind::Method(id)
1173 | FunctionKind::Static(id)
1174 | FunctionKind::Constructor(id)
1175 | FunctionKind::AsyncMethod(id)
1176 | FunctionKind::AsyncStatic(id) => Some(id),
1177 }
1178 }
1179}
1180
1181#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1183pub enum Mangling {
1184 Standard32,
1187
1188 Legacy,
1193}
1194
1195impl core::str::FromStr for Mangling {
1196 type Err = anyhow::Error;
1197
1198 fn from_str(s: &str) -> Result<Mangling> {
1199 match s {
1200 "legacy" => Ok(Mangling::Legacy),
1201 "standard32" => Ok(Mangling::Standard32),
1202 _ => {
1203 bail!(
1204 "unknown name mangling `{s}`, \
1205 supported values are `legacy` or `standard32`"
1206 )
1207 }
1208 }
1209 }
1210}
1211
1212#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1214pub enum LiftLowerAbi {
1215 Sync,
1217
1218 AsyncCallback,
1221
1222 AsyncStackful,
1225}
1226
1227impl LiftLowerAbi {
1228 fn import_prefix(self) -> &'static str {
1229 match self {
1230 Self::Sync => "",
1231 Self::AsyncCallback | Self::AsyncStackful => "[async-lower]",
1232 }
1233 }
1234
1235 pub fn import_variant(self) -> AbiVariant {
1237 match self {
1238 Self::Sync => AbiVariant::GuestImport,
1239 Self::AsyncCallback | Self::AsyncStackful => AbiVariant::GuestImportAsync,
1240 }
1241 }
1242
1243 fn export_prefix(self) -> &'static str {
1244 match self {
1245 Self::Sync => "",
1246 Self::AsyncCallback => "[async-lift]",
1247 Self::AsyncStackful => "[async-lift-stackful]",
1248 }
1249 }
1250
1251 pub fn export_variant(self) -> AbiVariant {
1253 match self {
1254 Self::Sync => AbiVariant::GuestExport,
1255 Self::AsyncCallback => AbiVariant::GuestExportAsync,
1256 Self::AsyncStackful => AbiVariant::GuestExportAsyncStackful,
1257 }
1258 }
1259}
1260
1261#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1263pub enum ManglingAndAbi {
1264 Standard32,
1269
1270 Legacy(LiftLowerAbi),
1272}
1273
1274impl ManglingAndAbi {
1275 pub fn import_variant(self) -> AbiVariant {
1277 match self {
1278 Self::Standard32 => AbiVariant::GuestImport,
1279 Self::Legacy(abi) => abi.import_variant(),
1280 }
1281 }
1282
1283 pub fn export_variant(self) -> AbiVariant {
1285 match self {
1286 Self::Standard32 => AbiVariant::GuestExport,
1287 Self::Legacy(abi) => abi.export_variant(),
1288 }
1289 }
1290
1291 pub fn sync(self) -> Self {
1293 match self {
1294 Self::Standard32 | Self::Legacy(LiftLowerAbi::Sync) => self,
1295 Self::Legacy(LiftLowerAbi::AsyncCallback)
1296 | Self::Legacy(LiftLowerAbi::AsyncStackful) => Self::Legacy(LiftLowerAbi::Sync),
1297 }
1298 }
1299
1300 pub fn is_async(&self) -> bool {
1302 match self {
1303 Self::Standard32 | Self::Legacy(LiftLowerAbi::Sync) => false,
1304 Self::Legacy(LiftLowerAbi::AsyncCallback)
1305 | Self::Legacy(LiftLowerAbi::AsyncStackful) => true,
1306 }
1307 }
1308
1309 pub fn mangling(&self) -> Mangling {
1310 match self {
1311 Self::Standard32 => Mangling::Standard32,
1312 Self::Legacy(_) => Mangling::Legacy,
1313 }
1314 }
1315}
1316
1317impl Function {
1318 pub(crate) fn adjust_spans(&mut self, offset: u32) {
1320 self.span.adjust(offset);
1321 for param in &mut self.params {
1322 param.span.adjust(offset);
1323 }
1324 }
1325
1326 pub fn item_name(&self) -> &str {
1327 match &self.kind {
1328 FunctionKind::Freestanding | FunctionKind::AsyncFreestanding => &self.name,
1329 FunctionKind::Method(_)
1330 | FunctionKind::Static(_)
1331 | FunctionKind::AsyncMethod(_)
1332 | FunctionKind::AsyncStatic(_) => &self.name[self.name.find('.').unwrap() + 1..],
1333 FunctionKind::Constructor(_) => "constructor",
1334 }
1335 }
1336
1337 pub fn parameter_and_result_types(&self) -> impl Iterator<Item = Type> + '_ {
1342 self.params.iter().map(|p| p.ty).chain(self.result)
1343 }
1344
1345 pub fn standard32_core_export_name<'a>(&'a self, interface: Option<&str>) -> Cow<'a, str> {
1347 self.core_export_name(interface, Mangling::Standard32)
1348 }
1349
1350 pub fn legacy_core_export_name<'a>(&'a self, interface: Option<&str>) -> Cow<'a, str> {
1351 self.core_export_name(interface, Mangling::Legacy)
1352 }
1353 pub fn core_export_name<'a>(
1355 &'a self,
1356 interface: Option<&str>,
1357 mangling: Mangling,
1358 ) -> Cow<'a, str> {
1359 match interface {
1360 Some(interface) => match mangling {
1361 Mangling::Standard32 => Cow::Owned(format!("cm32p2|{interface}|{}", self.name)),
1362 Mangling::Legacy => Cow::Owned(format!("{interface}#{}", self.name)),
1363 },
1364 None => match mangling {
1365 Mangling::Standard32 => Cow::Owned(format!("cm32p2||{}", self.name)),
1366 Mangling::Legacy => Cow::Borrowed(&self.name),
1367 },
1368 }
1369 }
1370 pub fn find_futures_and_streams(&self, resolve: &Resolve) -> Vec<TypeId> {
1386 let mut results = Vec::new();
1387 for param in self.params.iter() {
1388 find_futures_and_streams(resolve, param.ty, &mut results);
1389 }
1390 if let Some(ty) = self.result {
1391 find_futures_and_streams(resolve, ty, &mut results);
1392 }
1393 results
1394 }
1395
1396 pub fn is_constructor_shorthand(&self, resolve: &Resolve) -> bool {
1399 let FunctionKind::Constructor(containing_resource_id) = self.kind else {
1400 return false;
1401 };
1402
1403 let Some(Type::Id(id)) = &self.result else {
1404 return false;
1405 };
1406
1407 let TypeDefKind::Handle(Handle::Own(returned_resource_id)) = resolve.types[*id].kind else {
1408 return false;
1409 };
1410
1411 return containing_resource_id == returned_resource_id;
1412 }
1413
1414 pub fn task_return_import(
1417 &self,
1418 resolve: &Resolve,
1419 interface: Option<&WorldKey>,
1420 mangling: Mangling,
1421 ) -> (String, String, abi::WasmSignature) {
1422 match mangling {
1423 Mangling::Standard32 => todo!(),
1424 Mangling::Legacy => {}
1425 }
1426 let module = match interface {
1428 Some(key) => format!("[export]{}", resolve.name_world_key(key)),
1429 None => "[export]$root".to_string(),
1430 };
1431 let name = format!("[task-return]{}", self.name);
1432
1433 let mut func_tmp = self.clone();
1434 func_tmp.params = Vec::new();
1435 func_tmp.result = None;
1436 if let Some(ty) = self.result {
1437 func_tmp.params.push(Param {
1438 name: "x".to_string(),
1439 ty,
1440 span: Default::default(),
1441 });
1442 }
1443 let sig = resolve.wasm_signature(AbiVariant::GuestImport, &func_tmp);
1444 (module, name, sig)
1445 }
1446
1447 }
1449
1450fn find_futures_and_streams(resolve: &Resolve, ty: Type, results: &mut Vec<TypeId>) {
1451 let Type::Id(id) = ty else {
1452 return;
1453 };
1454
1455 match &resolve.types[id].kind {
1456 TypeDefKind::Resource
1457 | TypeDefKind::Handle(_)
1458 | TypeDefKind::Flags(_)
1459 | TypeDefKind::Enum(_) => {}
1460 TypeDefKind::Record(r) => {
1461 for Field { ty, .. } in &r.fields {
1462 find_futures_and_streams(resolve, *ty, results);
1463 }
1464 }
1465 TypeDefKind::Tuple(t) => {
1466 for ty in &t.types {
1467 find_futures_and_streams(resolve, *ty, results);
1468 }
1469 }
1470 TypeDefKind::Variant(v) => {
1471 for Case { ty, .. } in &v.cases {
1472 if let Some(ty) = ty {
1473 find_futures_and_streams(resolve, *ty, results);
1474 }
1475 }
1476 }
1477 TypeDefKind::Option(ty)
1478 | TypeDefKind::List(ty)
1479 | TypeDefKind::FixedLengthList(ty, ..)
1480 | TypeDefKind::Type(ty) => {
1481 find_futures_and_streams(resolve, *ty, results);
1482 }
1483 TypeDefKind::Map(k, v) => {
1484 find_futures_and_streams(resolve, *k, results);
1485 find_futures_and_streams(resolve, *v, results);
1486 }
1487 TypeDefKind::Result(r) => {
1488 if let Some(ty) = r.ok {
1489 find_futures_and_streams(resolve, ty, results);
1490 }
1491 if let Some(ty) = r.err {
1492 find_futures_and_streams(resolve, ty, results);
1493 }
1494 }
1495 TypeDefKind::Future(ty) => {
1496 if let Some(ty) = ty {
1497 find_futures_and_streams(resolve, *ty, results);
1498 }
1499 results.push(id);
1500 }
1501 TypeDefKind::Stream(ty) => {
1502 if let Some(ty) = ty {
1503 find_futures_and_streams(resolve, *ty, results);
1504 }
1505 results.push(id);
1506 }
1507 TypeDefKind::Unknown => unreachable!(),
1508 }
1509}
1510
1511#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
1519#[cfg_attr(feature = "serde", derive(serde_derive::Deserialize, Serialize))]
1520#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
1521pub enum Stability {
1522 Unknown,
1524
1525 Unstable {
1530 feature: String,
1531 #[cfg_attr(
1532 feature = "serde",
1533 serde(
1534 skip_serializing_if = "Option::is_none",
1535 default,
1536 serialize_with = "serialize_optional_version",
1537 deserialize_with = "deserialize_optional_version"
1538 )
1539 )]
1540 deprecated: Option<Version>,
1541 },
1542
1543 Stable {
1548 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_version"))]
1549 #[cfg_attr(feature = "serde", serde(deserialize_with = "deserialize_version"))]
1550 since: Version,
1551 #[cfg_attr(
1552 feature = "serde",
1553 serde(
1554 skip_serializing_if = "Option::is_none",
1555 default,
1556 serialize_with = "serialize_optional_version",
1557 deserialize_with = "deserialize_optional_version"
1558 )
1559 )]
1560 deprecated: Option<Version>,
1561 },
1562}
1563
1564impl Stability {
1565 pub fn is_unknown(&self) -> bool {
1567 matches!(self, Stability::Unknown)
1568 }
1569
1570 pub fn is_stable(&self) -> bool {
1571 matches!(self, Stability::Stable { .. })
1572 }
1573}
1574
1575impl Default for Stability {
1576 fn default() -> Stability {
1577 Stability::Unknown
1578 }
1579}
1580
1581#[cfg(test)]
1582mod test {
1583 use super::*;
1584 use alloc::vec;
1585
1586 #[test]
1587 fn test_discriminant_type() {
1588 assert_eq!(discriminant_type(1), Int::U8);
1589 assert_eq!(discriminant_type(0x100), Int::U8);
1590 assert_eq!(discriminant_type(0x101), Int::U16);
1591 assert_eq!(discriminant_type(0x10000), Int::U16);
1592 assert_eq!(discriminant_type(0x10001), Int::U32);
1593 if let Ok(num_cases) = usize::try_from(0x100000000_u64) {
1594 assert_eq!(discriminant_type(num_cases), Int::U32);
1595 }
1596 }
1597
1598 #[test]
1599 fn test_find_futures_and_streams() {
1600 let mut resolve = Resolve::default();
1601 let t0 = resolve.types.alloc(TypeDef {
1602 name: None,
1603 kind: TypeDefKind::Future(Some(Type::U32)),
1604 owner: TypeOwner::None,
1605 docs: Docs::default(),
1606 stability: Stability::Unknown,
1607 span: Default::default(),
1608 });
1609 let t1 = resolve.types.alloc(TypeDef {
1610 name: None,
1611 kind: TypeDefKind::Future(Some(Type::Id(t0))),
1612 owner: TypeOwner::None,
1613 docs: Docs::default(),
1614 stability: Stability::Unknown,
1615 span: Default::default(),
1616 });
1617 let t2 = resolve.types.alloc(TypeDef {
1618 name: None,
1619 kind: TypeDefKind::Stream(Some(Type::U32)),
1620 owner: TypeOwner::None,
1621 docs: Docs::default(),
1622 stability: Stability::Unknown,
1623 span: Default::default(),
1624 });
1625 let found = Function {
1626 name: "foo".into(),
1627 kind: FunctionKind::Freestanding,
1628 params: vec![
1629 Param {
1630 name: "p1".into(),
1631 ty: Type::Id(t1),
1632 span: Default::default(),
1633 },
1634 Param {
1635 name: "p2".into(),
1636 ty: Type::U32,
1637 span: Default::default(),
1638 },
1639 ],
1640 result: Some(Type::Id(t2)),
1641 docs: Docs::default(),
1642 stability: Stability::Unknown,
1643 span: Default::default(),
1644 }
1645 .find_futures_and_streams(&resolve);
1646 assert_eq!(3, found.len());
1647 assert_eq!(t0, found[0]);
1648 assert_eq!(t1, found[1]);
1649 assert_eq!(t2, found[2]);
1650 }
1651}