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 as _;
14use id_arena::{Arena, Id};
15use semver::Version;
16
17#[cfg(feature = "std")]
18pub type IndexMap<K, V> = indexmap::IndexMap<K, V, std::hash::RandomState>;
19#[cfg(feature = "std")]
20pub type IndexSet<T> = indexmap::IndexSet<T, std::hash::RandomState>;
21#[cfg(not(feature = "std"))]
22pub type IndexMap<K, V> = indexmap::IndexMap<K, V, hashbrown::DefaultHashBuilder>;
23#[cfg(not(feature = "std"))]
24pub type IndexSet<T> = indexmap::IndexSet<T, hashbrown::DefaultHashBuilder>;
25
26#[cfg(feature = "std")]
27pub(crate) use std::collections::{HashMap, HashSet};
28
29#[cfg(not(feature = "std"))]
30pub(crate) use hashbrown::{HashMap, HashSet};
31
32use alloc::borrow::Cow;
33use core::fmt;
34use core::hash::{Hash, Hasher};
35#[cfg(feature = "std")]
36use std::path::Path;
37
38#[cfg(feature = "decoding")]
39pub mod decoding;
40#[cfg(feature = "decoding")]
41mod metadata;
42#[cfg(feature = "decoding")]
43pub use metadata::PackageMetadata;
44
45pub mod abi;
46mod ast;
47pub use ast::error::*;
48pub use ast::lex::Span;
49pub use ast::{ItemName, SourceMap};
50pub use ast::{ParsedUsePath, parse_use_path};
51mod sizealign;
52pub use sizealign::*;
53mod resolve;
54pub use resolve::error::*;
55pub use resolve::*;
56mod live;
57pub use live::{LiveTypes, TypeIdVisitor};
58
59#[cfg(feature = "serde")]
60use serde_derive::Serialize;
61#[cfg(feature = "serde")]
62mod serde_;
63#[cfg(feature = "serde")]
64use serde_::*;
65
66pub fn validate_id(s: &str) -> anyhow::Result<()> {
68 ast::validate_id(0, s)?;
69 Ok(())
70}
71
72#[cfg(feature = "std")]
84pub fn render_anyhow_error(err: &anyhow::Error, source_map: &SourceMap) -> String {
85 err.chain()
86 .map(|layer| {
87 if let Some(re) = layer.downcast_ref::<ResolveError>() {
88 re.highlight(source_map)
89 } else if let Some(pe) = layer.downcast_ref::<ParseError>() {
90 pe.highlight(source_map)
91 } else {
92 layer.to_string()
93 }
94 })
95 .collect::<Vec<_>>()
96 .join(": ")
97}
98
99pub type WorldId = Id<World>;
100pub type InterfaceId = Id<Interface>;
101pub type TypeId = Id<TypeDef>;
102
103#[derive(Clone, PartialEq, Eq)]
129pub struct UnresolvedPackage {
130 pub name: PackageName,
132
133 pub worlds: Arena<World>,
137
138 pub interfaces: Arena<Interface>,
145
146 pub types: Arena<TypeDef>,
153
154 pub foreign_deps: IndexMap<PackageName, IndexMap<String, (AstItem, Vec<Stability>)>>,
163
164 pub docs: Docs,
166
167 #[cfg_attr(not(feature = "std"), allow(dead_code))]
168 package_name_span: Span,
169 unknown_type_spans: Vec<Span>,
170 foreign_dep_spans: Vec<Span>,
171 required_resource_types: Vec<(TypeId, Span)>,
172}
173
174impl UnresolvedPackage {
175 pub(crate) fn adjust_spans(&mut self, offset: u32) {
180 self.package_name_span.adjust(offset);
182 for span in &mut self.unknown_type_spans {
183 span.adjust(offset);
184 }
185 for span in &mut self.foreign_dep_spans {
186 span.adjust(offset);
187 }
188 for (_, span) in &mut self.required_resource_types {
189 span.adjust(offset);
190 }
191
192 for (_, world) in self.worlds.iter_mut() {
194 world.adjust_spans(offset);
195 }
196 for (_, iface) in self.interfaces.iter_mut() {
197 iface.adjust_spans(offset);
198 }
199 for (_, ty) in self.types.iter_mut() {
200 ty.adjust_spans(offset);
201 }
202 }
203}
204
205#[derive(Clone, PartialEq, Eq)]
207pub struct UnresolvedPackageGroup {
208 pub main: UnresolvedPackage,
213
214 pub nested: Vec<UnresolvedPackage>,
216
217 pub source_map: SourceMap,
219}
220
221#[derive(Debug, Copy, Clone, PartialEq, Eq)]
222#[cfg_attr(feature = "serde", derive(Serialize))]
223#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
224pub enum AstItem {
225 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
226 Interface(InterfaceId),
227 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
228 World(WorldId),
229}
230
231#[derive(Debug, Clone, Hash, Eq, PartialEq, Ord, PartialOrd)]
237#[cfg_attr(feature = "serde", derive(Serialize))]
238#[cfg_attr(feature = "serde", serde(into = "String"))]
239pub struct PackageName {
240 pub namespace: String,
242 pub name: String,
244 pub version: Option<Version>,
246}
247
248impl From<PackageName> for String {
249 fn from(name: PackageName) -> String {
250 name.to_string()
251 }
252}
253
254impl PackageName {
255 pub fn interface_id(&self, interface: &str) -> String {
258 let mut s = String::new();
259 s.push_str(&format!("{}:{}/{interface}", self.namespace, self.name));
260 if let Some(version) = &self.version {
261 s.push_str(&format!("@{version}"));
262 }
263 s
264 }
265
266 pub fn version_compat_track(version: &Version) -> Version {
279 let mut version = version.clone();
280 version.build = semver::BuildMetadata::EMPTY;
281 if !version.pre.is_empty() {
282 return version;
283 }
284 if version.major != 0 {
285 version.minor = 0;
286 version.patch = 0;
287 return version;
288 }
289 if version.minor != 0 {
290 version.patch = 0;
291 return version;
292 }
293 version
294 }
295
296 pub fn version_compat_track_string(version: &Version) -> String {
300 let version = Self::version_compat_track(version);
301 if !version.pre.is_empty() {
302 return version.to_string();
303 }
304 if version.major != 0 {
305 return format!("{}", version.major);
306 }
307 if version.minor != 0 {
308 return format!("{}.{}", version.major, version.minor);
309 }
310 version.to_string()
311 }
312}
313
314impl fmt::Display for PackageName {
315 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
316 write!(f, "{}:{}", self.namespace, self.name)?;
317 if let Some(version) = &self.version {
318 write!(f, "@{version}")?;
319 }
320 Ok(())
321 }
322}
323
324impl UnresolvedPackageGroup {
325 #[cfg(feature = "std")]
331 pub fn parse(path: impl AsRef<Path>, contents: &str) -> anyhow::Result<UnresolvedPackageGroup> {
332 let path = path
333 .as_ref()
334 .to_str()
335 .ok_or_else(|| anyhow::anyhow!("path is not valid utf-8: {:?}", path.as_ref()))?;
336 let mut map = SourceMap::default();
337 map.push_str(path, contents);
338 map.parse()
339 .map_err(|(map, e)| anyhow::anyhow!("{}", e.highlight(&map)))
340 }
341
342 #[cfg(feature = "std")]
349 pub fn parse_dir(path: impl AsRef<Path>) -> anyhow::Result<UnresolvedPackageGroup> {
350 let path = path.as_ref();
351 let mut map = SourceMap::default();
352 let cx = || format!("failed to read directory {path:?}");
353 for entry in path.read_dir().with_context(&cx)? {
354 let entry = entry.with_context(&cx)?;
355 let path = entry.path();
356 let ty = entry.file_type().with_context(&cx)?;
357 if ty.is_dir() {
358 continue;
359 }
360 if ty.is_symlink() {
361 if path.is_dir() {
362 continue;
363 }
364 }
365 let filename = match path.file_name().and_then(|s| s.to_str()) {
366 Some(name) => name,
367 None => continue,
368 };
369 if !filename.ends_with(".wit") {
370 continue;
371 }
372 map.push_file(&path)?;
373 }
374 map.parse()
375 .map_err(|(map, e)| anyhow::anyhow!("{}", e.highlight(&map)))
376 }
377}
378
379#[derive(Debug, Clone, PartialEq, Eq)]
380#[cfg_attr(feature = "serde", derive(Serialize))]
381pub struct World {
382 pub name: String,
384
385 pub imports: IndexMap<WorldKey, WorldItem>,
387
388 pub exports: IndexMap<WorldKey, WorldItem>,
390
391 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_optional_id"))]
393 pub package: Option<PackageId>,
394
395 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
397 pub docs: Docs,
398
399 #[cfg_attr(
401 feature = "serde",
402 serde(skip_serializing_if = "Stability::is_unknown")
403 )]
404 pub stability: Stability,
405
406 #[cfg_attr(feature = "serde", serde(skip))]
408 pub includes: Vec<WorldInclude>,
409
410 #[cfg_attr(feature = "serde", serde(skip))]
412 pub span: Span,
413}
414
415impl World {
416 pub(crate) fn adjust_spans(&mut self, offset: u32) {
418 self.span.adjust(offset);
419 for item in self.imports.values_mut().chain(self.exports.values_mut()) {
420 item.adjust_spans(offset);
421 }
422 for include in &mut self.includes {
423 include.span.adjust(offset);
424 }
425 }
426}
427
428#[derive(Debug, Clone, PartialEq, Eq)]
429pub struct IncludeName {
430 pub name: String,
432
433 pub as_: String,
435}
436
437#[derive(Debug, Clone, PartialEq, Eq)]
440pub struct WorldInclude {
441 pub stability: Stability,
443
444 pub id: WorldId,
446
447 pub names: Vec<IncludeName>,
449
450 pub span: Span,
452}
453
454#[derive(Debug, Clone, Eq)]
457#[cfg_attr(feature = "serde", derive(Serialize))]
458#[cfg_attr(feature = "serde", serde(into = "String"))]
459pub enum WorldKey {
460 Name(String),
462 Interface(InterfaceId),
464}
465
466impl Hash for WorldKey {
467 fn hash<H: Hasher>(&self, hasher: &mut H) {
468 match self {
469 WorldKey::Name(s) => {
470 0u8.hash(hasher);
471 s.as_str().hash(hasher);
472 }
473 WorldKey::Interface(i) => {
474 1u8.hash(hasher);
475 i.hash(hasher);
476 }
477 }
478 }
479}
480
481impl PartialEq for WorldKey {
482 fn eq(&self, other: &WorldKey) -> bool {
483 match (self, other) {
484 (WorldKey::Name(a), WorldKey::Name(b)) => a.as_str() == b.as_str(),
485 (WorldKey::Name(_), _) => false,
486 (WorldKey::Interface(a), WorldKey::Interface(b)) => a == b,
487 (WorldKey::Interface(_), _) => false,
488 }
489 }
490}
491
492impl From<WorldKey> for String {
493 fn from(key: WorldKey) -> String {
494 match key {
495 WorldKey::Name(name) => name,
496 WorldKey::Interface(id) => format!("interface-{}", id.index()),
497 }
498 }
499}
500
501impl WorldKey {
502 #[track_caller]
504 pub fn unwrap_name(self) -> String {
505 match self {
506 WorldKey::Name(name) => name,
507 WorldKey::Interface(_) => panic!("expected a name, found interface"),
508 }
509 }
510}
511
512#[derive(Debug, Clone, PartialEq, Eq)]
513#[cfg_attr(feature = "serde", derive(Serialize))]
514#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
515pub enum WorldItem {
516 Interface {
519 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
520 id: InterfaceId,
521 #[cfg_attr(
522 feature = "serde",
523 serde(skip_serializing_if = "Stability::is_unknown")
524 )]
525 stability: Stability,
526 #[cfg_attr(
528 feature = "serde",
529 serde(default, skip_serializing_if = "Docs::is_empty")
530 )]
531 docs: Docs,
532 #[cfg_attr(feature = "serde", serde(skip))]
533 span: Span,
534 },
535
536 Function(Function),
538
539 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id_ignore_span"))]
543 Type { id: TypeId, span: Span },
544}
545
546impl WorldItem {
547 pub fn stability<'a>(&'a self, resolve: &'a Resolve) -> &'a Stability {
548 match self {
549 WorldItem::Interface { stability, .. } => stability,
550 WorldItem::Function(f) => &f.stability,
551 WorldItem::Type { id, .. } => &resolve.types[*id].stability,
552 }
553 }
554
555 pub fn span(&self) -> Span {
556 match self {
557 WorldItem::Interface { span, .. } => *span,
558 WorldItem::Function(f) => f.span,
559 WorldItem::Type { span, .. } => *span,
560 }
561 }
562
563 pub(crate) fn adjust_spans(&mut self, offset: u32) {
564 match self {
565 WorldItem::Function(f) => f.adjust_spans(offset),
566 WorldItem::Interface { span, .. } => span.adjust(offset),
567 WorldItem::Type { span, .. } => span.adjust(offset),
568 }
569 }
570}
571
572#[derive(Debug, Clone, PartialEq, Eq)]
573#[cfg_attr(feature = "serde", derive(Serialize))]
574pub struct Interface {
575 pub name: Option<String>,
579
580 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id_map"))]
585 pub types: IndexMap<String, TypeId>,
586
587 pub functions: IndexMap<String, Function>,
589
590 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
592 pub docs: Docs,
593
594 #[cfg_attr(
596 feature = "serde",
597 serde(skip_serializing_if = "Stability::is_unknown")
598 )]
599 pub stability: Stability,
600
601 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_optional_id"))]
603 pub package: Option<PackageId>,
604
605 #[cfg_attr(feature = "serde", serde(skip))]
607 pub span: Span,
608
609 #[cfg_attr(
613 feature = "serde",
614 serde(
615 skip_serializing_if = "Option::is_none",
616 serialize_with = "serialize_optional_id",
617 )
618 )]
619 pub clone_of: Option<InterfaceId>,
620}
621
622impl Interface {
623 pub(crate) fn adjust_spans(&mut self, offset: u32) {
625 self.span.adjust(offset);
626 for func in self.functions.values_mut() {
627 func.adjust_spans(offset);
628 }
629 }
630}
631
632#[derive(Debug, Clone, PartialEq, Eq)]
633#[cfg_attr(feature = "serde", derive(Serialize))]
634pub struct TypeDef {
635 pub name: Option<String>,
636 pub kind: TypeDefKind,
637 pub owner: TypeOwner,
638 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
639 pub docs: Docs,
640 #[cfg_attr(
642 feature = "serde",
643 serde(skip_serializing_if = "Stability::is_unknown")
644 )]
645 pub stability: Stability,
646 #[cfg_attr(feature = "serde", serde(skip))]
648 pub span: Span,
649}
650
651impl TypeDef {
652 pub(crate) fn adjust_spans(&mut self, offset: u32) {
657 self.span.adjust(offset);
658 match &mut self.kind {
659 TypeDefKind::Record(r) => {
660 for field in &mut r.fields {
661 field.span.adjust(offset);
662 }
663 }
664 TypeDefKind::Variant(v) => {
665 for case in &mut v.cases {
666 case.span.adjust(offset);
667 }
668 }
669 TypeDefKind::Enum(e) => {
670 for case in &mut e.cases {
671 case.span.adjust(offset);
672 }
673 }
674 TypeDefKind::Flags(f) => {
675 for flag in &mut f.flags {
676 flag.span.adjust(offset);
677 }
678 }
679 _ => {}
680 }
681 }
682}
683
684#[derive(Debug, Clone, PartialEq, Hash, Eq)]
685#[cfg_attr(feature = "serde", derive(Serialize))]
686#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
687pub enum TypeDefKind {
688 Record(Record),
689 Resource,
690 Handle(Handle),
691 Flags(Flags),
692 Tuple(Tuple),
693 Variant(Variant),
694 Enum(Enum),
695 Option(Type),
696 Result(Result_),
697 List(Type),
698 Map(Type, Type),
699 FixedLengthList(Type, u32),
700 Future(Option<Type>),
701 Stream(Option<Type>),
702 Type(Type),
703
704 Unknown,
710}
711
712impl TypeDefKind {
713 pub fn as_str(&self) -> &'static str {
714 match self {
715 TypeDefKind::Record(_) => "record",
716 TypeDefKind::Resource => "resource",
717 TypeDefKind::Handle(handle) => match handle {
718 Handle::Own(_) => "own",
719 Handle::Borrow(_) => "borrow",
720 },
721 TypeDefKind::Flags(_) => "flags",
722 TypeDefKind::Tuple(_) => "tuple",
723 TypeDefKind::Variant(_) => "variant",
724 TypeDefKind::Enum(_) => "enum",
725 TypeDefKind::Option(_) => "option",
726 TypeDefKind::Result(_) => "result",
727 TypeDefKind::List(_) => "list",
728 TypeDefKind::Map(_, _) => "map",
729 TypeDefKind::FixedLengthList(..) => "fixed-length list",
730 TypeDefKind::Future(_) => "future",
731 TypeDefKind::Stream(_) => "stream",
732 TypeDefKind::Type(_) => "type",
733 TypeDefKind::Unknown => "unknown",
734 }
735 }
736}
737
738#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
739#[cfg_attr(feature = "serde", derive(Serialize))]
740#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
741pub enum TypeOwner {
742 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
744 World(WorldId),
745 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
747 Interface(InterfaceId),
748 #[cfg_attr(feature = "serde", serde(untagged, serialize_with = "serialize_none"))]
751 None,
752}
753
754#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone)]
755#[cfg_attr(feature = "serde", derive(Serialize))]
756#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
757pub enum Handle {
758 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
759 Own(TypeId),
760 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
761 Borrow(TypeId),
762}
763
764#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, Clone)]
765pub enum Type {
766 Bool,
767 U8,
768 U16,
769 U32,
770 U64,
771 S8,
772 S16,
773 S32,
774 S64,
775 F32,
776 F64,
777 Char,
778 String,
779 ErrorContext,
780 Id(TypeId),
781}
782
783#[derive(Debug, Copy, Clone, Eq, PartialEq)]
784pub enum Int {
785 U8,
786 U16,
787 U32,
788 U64,
789}
790
791#[derive(Debug, Clone, PartialEq, Hash, Eq)]
792#[cfg_attr(feature = "serde", derive(Serialize))]
793pub struct Record {
794 pub fields: Vec<Field>,
795}
796
797#[derive(Debug, Clone, PartialEq, Hash, Eq)]
798#[cfg_attr(feature = "serde", derive(Serialize))]
799pub struct Field {
800 pub name: String,
801 #[cfg_attr(feature = "serde", serde(rename = "type"))]
802 pub ty: Type,
803 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
804 pub docs: Docs,
805 #[cfg_attr(feature = "serde", serde(skip))]
807 pub span: Span,
808}
809
810#[derive(Debug, Clone, PartialEq, Hash, Eq)]
811#[cfg_attr(feature = "serde", derive(Serialize))]
812pub struct Flags {
813 pub flags: Vec<Flag>,
814}
815
816#[derive(Debug, Clone, PartialEq, Hash, Eq)]
817#[cfg_attr(feature = "serde", derive(Serialize))]
818pub struct Flag {
819 pub name: String,
820 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
821 pub docs: Docs,
822 #[cfg_attr(feature = "serde", serde(skip))]
824 pub span: Span,
825}
826
827#[derive(Debug, Clone, PartialEq)]
828pub enum FlagsRepr {
829 U8,
830 U16,
831 U32(usize),
832}
833
834impl Flags {
835 pub fn repr(&self) -> FlagsRepr {
836 match self.flags.len() {
837 0 => FlagsRepr::U32(0),
838 n if n <= 8 => FlagsRepr::U8,
839 n if n <= 16 => FlagsRepr::U16,
840 n => FlagsRepr::U32(sizealign::align_to(n, 32) / 32),
841 }
842 }
843}
844
845impl FlagsRepr {
846 pub fn count(&self) -> usize {
847 match self {
848 FlagsRepr::U8 => 1,
849 FlagsRepr::U16 => 1,
850 FlagsRepr::U32(n) => *n,
851 }
852 }
853}
854
855#[derive(Debug, Clone, PartialEq, Hash, Eq)]
856#[cfg_attr(feature = "serde", derive(Serialize))]
857pub struct Tuple {
858 pub types: Vec<Type>,
859}
860
861#[derive(Debug, Clone, PartialEq, Hash, Eq)]
862#[cfg_attr(feature = "serde", derive(Serialize))]
863pub struct Variant {
864 pub cases: Vec<Case>,
865}
866
867#[derive(Debug, Clone, PartialEq, Hash, Eq)]
868#[cfg_attr(feature = "serde", derive(Serialize))]
869pub struct Case {
870 pub name: String,
871 #[cfg_attr(feature = "serde", serde(rename = "type"))]
872 pub ty: Option<Type>,
873 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
874 pub docs: Docs,
875 #[cfg_attr(feature = "serde", serde(skip))]
877 pub span: Span,
878}
879
880impl Variant {
881 pub fn tag(&self) -> Int {
882 discriminant_type(self.cases.len())
883 }
884}
885
886#[derive(Debug, Clone, PartialEq, Hash, Eq)]
887#[cfg_attr(feature = "serde", derive(Serialize))]
888pub struct Enum {
889 pub cases: Vec<EnumCase>,
890}
891
892#[derive(Debug, Clone, PartialEq, Hash, Eq)]
893#[cfg_attr(feature = "serde", derive(Serialize))]
894pub struct EnumCase {
895 pub name: String,
896 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
897 pub docs: Docs,
898 #[cfg_attr(feature = "serde", serde(skip))]
900 pub span: Span,
901}
902
903impl Enum {
904 pub fn tag(&self) -> Int {
905 discriminant_type(self.cases.len())
906 }
907}
908
909fn discriminant_type(num_cases: usize) -> Int {
911 match num_cases.checked_sub(1) {
912 None => Int::U8,
913 Some(n) if n <= u8::max_value() as usize => Int::U8,
914 Some(n) if n <= u16::max_value() as usize => Int::U16,
915 Some(n) if n <= u32::max_value() as usize => Int::U32,
916 _ => panic!("too many cases to fit in a repr"),
917 }
918}
919
920#[derive(Debug, Clone, PartialEq, Hash, Eq)]
921#[cfg_attr(feature = "serde", derive(Serialize))]
922pub struct Result_ {
923 pub ok: Option<Type>,
924 pub err: Option<Type>,
925}
926
927#[derive(Clone, Default, Debug, PartialEq, Eq, Hash)]
928#[cfg_attr(feature = "serde", derive(Serialize))]
929pub struct Docs {
930 pub contents: Option<String>,
931}
932
933impl Docs {
934 pub fn is_empty(&self) -> bool {
935 self.contents.is_none()
936 }
937}
938
939#[derive(Debug, Clone, PartialEq, Eq)]
940#[cfg_attr(feature = "serde", derive(Serialize))]
941pub struct Param {
942 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "String::is_empty"))]
943 pub name: String,
944 #[cfg_attr(feature = "serde", serde(rename = "type"))]
945 pub ty: Type,
946 #[cfg_attr(feature = "serde", serde(skip))]
947 pub span: Span,
948}
949
950#[derive(Debug, Clone, PartialEq, Eq)]
951#[cfg_attr(feature = "serde", derive(Serialize))]
952pub struct Function {
953 pub name: String,
954 pub kind: FunctionKind,
955 pub params: Vec<Param>,
956 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
957 pub result: Option<Type>,
958 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
959 pub docs: Docs,
960 #[cfg_attr(
962 feature = "serde",
963 serde(skip_serializing_if = "Stability::is_unknown")
964 )]
965 pub stability: Stability,
966
967 #[cfg_attr(feature = "serde", serde(skip))]
969 pub span: Span,
970}
971
972#[derive(Debug, Clone, PartialEq, Eq)]
973#[cfg_attr(feature = "serde", derive(Serialize))]
974#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
975pub enum FunctionKind {
976 Freestanding,
984
985 AsyncFreestanding,
993
994 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
1005 Method(TypeId),
1006
1007 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
1018 AsyncMethod(TypeId),
1019
1020 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
1030 Static(TypeId),
1031
1032 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
1042 AsyncStatic(TypeId),
1043
1044 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
1054 Constructor(TypeId),
1055}
1056
1057impl FunctionKind {
1058 pub fn is_async(&self) -> bool {
1060 match self {
1061 FunctionKind::Freestanding
1062 | FunctionKind::Method(_)
1063 | FunctionKind::Static(_)
1064 | FunctionKind::Constructor(_) => false,
1065 FunctionKind::AsyncFreestanding
1066 | FunctionKind::AsyncMethod(_)
1067 | FunctionKind::AsyncStatic(_) => true,
1068 }
1069 }
1070
1071 pub fn resource(&self) -> Option<TypeId> {
1073 match self {
1074 FunctionKind::Freestanding | FunctionKind::AsyncFreestanding => None,
1075 FunctionKind::Method(id)
1076 | FunctionKind::Static(id)
1077 | FunctionKind::Constructor(id)
1078 | FunctionKind::AsyncMethod(id)
1079 | FunctionKind::AsyncStatic(id) => Some(*id),
1080 }
1081 }
1082
1083 pub fn resource_mut(&mut self) -> Option<&mut TypeId> {
1085 match self {
1086 FunctionKind::Freestanding | FunctionKind::AsyncFreestanding => None,
1087 FunctionKind::Method(id)
1088 | FunctionKind::Static(id)
1089 | FunctionKind::Constructor(id)
1090 | FunctionKind::AsyncMethod(id)
1091 | FunctionKind::AsyncStatic(id) => Some(id),
1092 }
1093 }
1094}
1095
1096#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1098pub enum Mangling {
1099 Standard32,
1102
1103 Legacy,
1108}
1109
1110impl core::str::FromStr for Mangling {
1111 type Err = anyhow::Error;
1112
1113 fn from_str(s: &str) -> anyhow::Result<Mangling> {
1114 match s {
1115 "legacy" => Ok(Mangling::Legacy),
1116 "standard32" => Ok(Mangling::Standard32),
1117 _ => {
1118 anyhow::bail!(
1119 "unknown name mangling `{s}`, \
1120 supported values are `legacy` or `standard32`"
1121 )
1122 }
1123 }
1124 }
1125}
1126
1127#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1129pub enum LiftLowerAbi {
1130 Sync,
1132
1133 AsyncCallback,
1136
1137 AsyncStackful,
1140}
1141
1142impl LiftLowerAbi {
1143 fn import_prefix(self) -> &'static str {
1144 match self {
1145 Self::Sync => "",
1146 Self::AsyncCallback | Self::AsyncStackful => "[async-lower]",
1147 }
1148 }
1149
1150 pub fn import_variant(self) -> AbiVariant {
1152 match self {
1153 Self::Sync => AbiVariant::GuestImport,
1154 Self::AsyncCallback | Self::AsyncStackful => AbiVariant::GuestImportAsync,
1155 }
1156 }
1157
1158 fn export_prefix(self) -> &'static str {
1159 match self {
1160 Self::Sync => "",
1161 Self::AsyncCallback => "[async-lift]",
1162 Self::AsyncStackful => "[async-lift-stackful]",
1163 }
1164 }
1165
1166 pub fn export_variant(self) -> AbiVariant {
1168 match self {
1169 Self::Sync => AbiVariant::GuestExport,
1170 Self::AsyncCallback => AbiVariant::GuestExportAsync,
1171 Self::AsyncStackful => AbiVariant::GuestExportAsyncStackful,
1172 }
1173 }
1174}
1175
1176#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1178pub enum ManglingAndAbi {
1179 Standard32,
1184
1185 Legacy(LiftLowerAbi),
1187}
1188
1189impl ManglingAndAbi {
1190 pub fn import_variant(self) -> AbiVariant {
1192 match self {
1193 Self::Standard32 => AbiVariant::GuestImport,
1194 Self::Legacy(abi) => abi.import_variant(),
1195 }
1196 }
1197
1198 pub fn export_variant(self) -> AbiVariant {
1200 match self {
1201 Self::Standard32 => AbiVariant::GuestExport,
1202 Self::Legacy(abi) => abi.export_variant(),
1203 }
1204 }
1205
1206 pub fn sync(self) -> Self {
1208 match self {
1209 Self::Standard32 | Self::Legacy(LiftLowerAbi::Sync) => self,
1210 Self::Legacy(LiftLowerAbi::AsyncCallback)
1211 | Self::Legacy(LiftLowerAbi::AsyncStackful) => Self::Legacy(LiftLowerAbi::Sync),
1212 }
1213 }
1214
1215 pub fn is_async(&self) -> bool {
1217 match self {
1218 Self::Standard32 | Self::Legacy(LiftLowerAbi::Sync) => false,
1219 Self::Legacy(LiftLowerAbi::AsyncCallback)
1220 | Self::Legacy(LiftLowerAbi::AsyncStackful) => true,
1221 }
1222 }
1223
1224 pub fn mangling(&self) -> Mangling {
1225 match self {
1226 Self::Standard32 => Mangling::Standard32,
1227 Self::Legacy(_) => Mangling::Legacy,
1228 }
1229 }
1230
1231 pub fn for_func(&self, func: &Function) -> Self {
1237 match self {
1238 Self::Standard32 => *self,
1239 Self::Legacy(abi) => {
1240 if !func.kind.is_async() {
1241 Self::Legacy(LiftLowerAbi::Sync)
1242 } else {
1243 Self::Legacy(*abi)
1244 }
1245 }
1246 }
1247 }
1248}
1249
1250impl Function {
1251 pub(crate) fn adjust_spans(&mut self, offset: u32) {
1253 self.span.adjust(offset);
1254 for param in &mut self.params {
1255 param.span.adjust(offset);
1256 }
1257 }
1258
1259 pub fn item_name(&self) -> &str {
1260 match &self.kind {
1261 FunctionKind::Freestanding | FunctionKind::AsyncFreestanding => &self.name,
1262 FunctionKind::Method(_)
1263 | FunctionKind::Static(_)
1264 | FunctionKind::AsyncMethod(_)
1265 | FunctionKind::AsyncStatic(_) => &self.name[self.name.find('.').unwrap() + 1..],
1266 FunctionKind::Constructor(_) => "constructor",
1267 }
1268 }
1269
1270 pub fn parameter_and_result_types(&self) -> impl Iterator<Item = Type> + '_ {
1275 self.params.iter().map(|p| p.ty).chain(self.result)
1276 }
1277
1278 pub fn standard32_core_export_name<'a>(&'a self, interface: Option<&str>) -> Cow<'a, str> {
1280 self.core_export_name(interface, Mangling::Standard32)
1281 }
1282
1283 pub fn legacy_core_export_name<'a>(&'a self, interface: Option<&str>) -> Cow<'a, str> {
1284 self.core_export_name(interface, Mangling::Legacy)
1285 }
1286 pub fn core_export_name<'a>(
1288 &'a self,
1289 interface: Option<&str>,
1290 mangling: Mangling,
1291 ) -> Cow<'a, str> {
1292 match interface {
1293 Some(interface) => match mangling {
1294 Mangling::Standard32 => Cow::Owned(format!("cm32p2|{interface}|{}", self.name)),
1295 Mangling::Legacy => Cow::Owned(format!("{interface}#{}", self.name)),
1296 },
1297 None => match mangling {
1298 Mangling::Standard32 => Cow::Owned(format!("cm32p2||{}", self.name)),
1299 Mangling::Legacy => Cow::Borrowed(&self.name),
1300 },
1301 }
1302 }
1303 pub fn find_futures_and_streams(&self, resolve: &Resolve) -> Vec<TypeId> {
1319 let mut results = Vec::new();
1320 for param in self.params.iter() {
1321 find_futures_and_streams(resolve, param.ty, &mut results);
1322 }
1323 if let Some(ty) = self.result {
1324 find_futures_and_streams(resolve, ty, &mut results);
1325 }
1326 results
1327 }
1328
1329 pub fn is_constructor_shorthand(&self, resolve: &Resolve) -> bool {
1332 let FunctionKind::Constructor(containing_resource_id) = self.kind else {
1333 return false;
1334 };
1335
1336 let Some(Type::Id(id)) = &self.result else {
1337 return false;
1338 };
1339
1340 let TypeDefKind::Handle(Handle::Own(returned_resource_id)) = resolve.types[*id].kind else {
1341 return false;
1342 };
1343
1344 return containing_resource_id == returned_resource_id;
1345 }
1346
1347 pub fn task_return_import(
1350 &self,
1351 resolve: &Resolve,
1352 interface: Option<&WorldKey>,
1353 mangling: Mangling,
1354 ) -> (String, String, abi::WasmSignature) {
1355 match mangling {
1356 Mangling::Standard32 => todo!(),
1357 Mangling::Legacy => {}
1358 }
1359 let module = match interface {
1361 Some(key) => format!("[export]{}", resolve.name_world_key(key)),
1362 None => "[export]$root".to_string(),
1363 };
1364 let name = format!("[task-return]{}", self.name);
1365
1366 let mut func_tmp = self.clone();
1367 func_tmp.params = Vec::new();
1368 func_tmp.result = None;
1369 if let Some(ty) = self.result {
1370 func_tmp.params.push(Param {
1371 name: "x".to_string(),
1372 ty,
1373 span: Default::default(),
1374 });
1375 }
1376 let sig = resolve.wasm_signature(AbiVariant::GuestImport, &func_tmp);
1377 (module, name, sig)
1378 }
1379
1380 }
1382
1383fn find_futures_and_streams(resolve: &Resolve, ty: Type, results: &mut Vec<TypeId>) {
1384 let Type::Id(id) = ty else {
1385 return;
1386 };
1387
1388 match &resolve.types[id].kind {
1389 TypeDefKind::Resource
1390 | TypeDefKind::Handle(_)
1391 | TypeDefKind::Flags(_)
1392 | TypeDefKind::Enum(_) => {}
1393 TypeDefKind::Record(r) => {
1394 for Field { ty, .. } in &r.fields {
1395 find_futures_and_streams(resolve, *ty, results);
1396 }
1397 }
1398 TypeDefKind::Tuple(t) => {
1399 for ty in &t.types {
1400 find_futures_and_streams(resolve, *ty, results);
1401 }
1402 }
1403 TypeDefKind::Variant(v) => {
1404 for Case { ty, .. } in &v.cases {
1405 if let Some(ty) = ty {
1406 find_futures_and_streams(resolve, *ty, results);
1407 }
1408 }
1409 }
1410 TypeDefKind::Option(ty)
1411 | TypeDefKind::List(ty)
1412 | TypeDefKind::FixedLengthList(ty, ..)
1413 | TypeDefKind::Type(ty) => {
1414 find_futures_and_streams(resolve, *ty, results);
1415 }
1416 TypeDefKind::Map(k, v) => {
1417 find_futures_and_streams(resolve, *k, results);
1418 find_futures_and_streams(resolve, *v, results);
1419 }
1420 TypeDefKind::Result(r) => {
1421 if let Some(ty) = r.ok {
1422 find_futures_and_streams(resolve, ty, results);
1423 }
1424 if let Some(ty) = r.err {
1425 find_futures_and_streams(resolve, ty, results);
1426 }
1427 }
1428 TypeDefKind::Future(ty) => {
1429 if let Some(ty) = ty {
1430 find_futures_and_streams(resolve, *ty, results);
1431 }
1432 results.push(id);
1433 }
1434 TypeDefKind::Stream(ty) => {
1435 if let Some(ty) = ty {
1436 find_futures_and_streams(resolve, *ty, results);
1437 }
1438 results.push(id);
1439 }
1440 TypeDefKind::Unknown => unreachable!(),
1441 }
1442}
1443
1444#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
1452#[cfg_attr(feature = "serde", derive(serde_derive::Deserialize, Serialize))]
1453#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
1454pub enum Stability {
1455 Unknown,
1457
1458 Unstable {
1463 feature: String,
1464 #[cfg_attr(
1465 feature = "serde",
1466 serde(
1467 skip_serializing_if = "Option::is_none",
1468 default,
1469 serialize_with = "serialize_optional_version",
1470 deserialize_with = "deserialize_optional_version"
1471 )
1472 )]
1473 deprecated: Option<Version>,
1474 },
1475
1476 Stable {
1481 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_version"))]
1482 #[cfg_attr(feature = "serde", serde(deserialize_with = "deserialize_version"))]
1483 since: Version,
1484 #[cfg_attr(
1485 feature = "serde",
1486 serde(
1487 skip_serializing_if = "Option::is_none",
1488 default,
1489 serialize_with = "serialize_optional_version",
1490 deserialize_with = "deserialize_optional_version"
1491 )
1492 )]
1493 deprecated: Option<Version>,
1494 },
1495}
1496
1497impl Stability {
1498 pub fn is_unknown(&self) -> bool {
1500 matches!(self, Stability::Unknown)
1501 }
1502
1503 pub fn is_stable(&self) -> bool {
1504 matches!(self, Stability::Stable { .. })
1505 }
1506}
1507
1508impl Default for Stability {
1509 fn default() -> Stability {
1510 Stability::Unknown
1511 }
1512}
1513
1514#[cfg(test)]
1515mod test {
1516 use super::*;
1517 use alloc::vec;
1518
1519 #[test]
1520 fn test_discriminant_type() {
1521 assert_eq!(discriminant_type(1), Int::U8);
1522 assert_eq!(discriminant_type(0x100), Int::U8);
1523 assert_eq!(discriminant_type(0x101), Int::U16);
1524 assert_eq!(discriminant_type(0x10000), Int::U16);
1525 assert_eq!(discriminant_type(0x10001), Int::U32);
1526 if let Ok(num_cases) = usize::try_from(0x100000000_u64) {
1527 assert_eq!(discriminant_type(num_cases), Int::U32);
1528 }
1529 }
1530
1531 #[test]
1532 fn test_find_futures_and_streams() {
1533 let mut resolve = Resolve::default();
1534 let t0 = resolve.types.alloc(TypeDef {
1535 name: None,
1536 kind: TypeDefKind::Future(Some(Type::U32)),
1537 owner: TypeOwner::None,
1538 docs: Docs::default(),
1539 stability: Stability::Unknown,
1540 span: Default::default(),
1541 });
1542 let t1 = resolve.types.alloc(TypeDef {
1543 name: None,
1544 kind: TypeDefKind::Future(Some(Type::Id(t0))),
1545 owner: TypeOwner::None,
1546 docs: Docs::default(),
1547 stability: Stability::Unknown,
1548 span: Default::default(),
1549 });
1550 let t2 = resolve.types.alloc(TypeDef {
1551 name: None,
1552 kind: TypeDefKind::Stream(Some(Type::U32)),
1553 owner: TypeOwner::None,
1554 docs: Docs::default(),
1555 stability: Stability::Unknown,
1556 span: Default::default(),
1557 });
1558 let found = Function {
1559 name: "foo".into(),
1560 kind: FunctionKind::Freestanding,
1561 params: vec![
1562 Param {
1563 name: "p1".into(),
1564 ty: Type::Id(t1),
1565 span: Default::default(),
1566 },
1567 Param {
1568 name: "p2".into(),
1569 ty: Type::U32,
1570 span: Default::default(),
1571 },
1572 ],
1573 result: Some(Type::Id(t2)),
1574 docs: Docs::default(),
1575 stability: Stability::Unknown,
1576 span: Default::default(),
1577 }
1578 .find_futures_and_streams(&resolve);
1579 assert_eq!(3, found.len());
1580 assert_eq!(t0, found[0]);
1581 assert_eq!(t1, found[1]);
1582 assert_eq!(t2, found[2]);
1583 }
1584}