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::error::*;
50pub use ast::lex::Span;
51pub use ast::{ParsedUsePath, parse_use_path};
52mod sizealign;
53pub use sizealign::*;
54mod resolve;
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) -> Result<()> {
68 ast::validate_id(0, s)?;
69 Ok(())
70}
71
72pub type WorldId = Id<World>;
73pub type InterfaceId = Id<Interface>;
74pub type TypeId = Id<TypeDef>;
75
76#[derive(Clone, PartialEq, Eq)]
102pub struct UnresolvedPackage {
103 pub name: PackageName,
105
106 pub worlds: Arena<World>,
110
111 pub interfaces: Arena<Interface>,
118
119 pub types: Arena<TypeDef>,
126
127 pub foreign_deps: IndexMap<PackageName, IndexMap<String, (AstItem, Vec<Stability>)>>,
136
137 pub docs: Docs,
139
140 #[cfg_attr(not(feature = "std"), allow(dead_code))]
141 package_name_span: Span,
142 unknown_type_spans: Vec<Span>,
143 foreign_dep_spans: Vec<Span>,
144 required_resource_types: Vec<(TypeId, Span)>,
145}
146
147impl UnresolvedPackage {
148 pub(crate) fn adjust_spans(&mut self, offset: u32) {
153 self.package_name_span.adjust(offset);
155 for span in &mut self.unknown_type_spans {
156 span.adjust(offset);
157 }
158 for span in &mut self.foreign_dep_spans {
159 span.adjust(offset);
160 }
161 for (_, span) in &mut self.required_resource_types {
162 span.adjust(offset);
163 }
164
165 for (_, world) in self.worlds.iter_mut() {
167 world.adjust_spans(offset);
168 }
169 for (_, iface) in self.interfaces.iter_mut() {
170 iface.adjust_spans(offset);
171 }
172 for (_, ty) in self.types.iter_mut() {
173 ty.adjust_spans(offset);
174 }
175 }
176}
177
178#[derive(Clone, PartialEq, Eq)]
180pub struct UnresolvedPackageGroup {
181 pub main: UnresolvedPackage,
186
187 pub nested: Vec<UnresolvedPackage>,
189
190 pub source_map: SourceMap,
192}
193
194#[derive(Debug, Copy, Clone, PartialEq, Eq)]
195#[cfg_attr(feature = "serde", derive(Serialize))]
196#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
197pub enum AstItem {
198 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
199 Interface(InterfaceId),
200 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
201 World(WorldId),
202}
203
204#[derive(Debug, Clone, Hash, Eq, PartialEq, Ord, PartialOrd)]
210#[cfg_attr(feature = "serde", derive(Serialize))]
211#[cfg_attr(feature = "serde", serde(into = "String"))]
212pub struct PackageName {
213 pub namespace: String,
215 pub name: String,
217 pub version: Option<Version>,
219}
220
221impl From<PackageName> for String {
222 fn from(name: PackageName) -> String {
223 name.to_string()
224 }
225}
226
227impl PackageName {
228 pub fn interface_id(&self, interface: &str) -> String {
231 let mut s = String::new();
232 s.push_str(&format!("{}:{}/{interface}", self.namespace, self.name));
233 if let Some(version) = &self.version {
234 s.push_str(&format!("@{version}"));
235 }
236 s
237 }
238
239 pub fn version_compat_track(version: &Version) -> Version {
252 let mut version = version.clone();
253 version.build = semver::BuildMetadata::EMPTY;
254 if !version.pre.is_empty() {
255 return version;
256 }
257 if version.major != 0 {
258 version.minor = 0;
259 version.patch = 0;
260 return version;
261 }
262 if version.minor != 0 {
263 version.patch = 0;
264 return version;
265 }
266 version
267 }
268
269 pub fn version_compat_track_string(version: &Version) -> String {
273 let version = Self::version_compat_track(version);
274 if !version.pre.is_empty() {
275 return version.to_string();
276 }
277 if version.major != 0 {
278 return format!("{}", version.major);
279 }
280 if version.minor != 0 {
281 return format!("{}.{}", version.major, version.minor);
282 }
283 version.to_string()
284 }
285}
286
287impl fmt::Display for PackageName {
288 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
289 write!(f, "{}:{}", self.namespace, self.name)?;
290 if let Some(version) = &self.version {
291 write!(f, "@{version}")?;
292 }
293 Ok(())
294 }
295}
296
297#[derive(Debug)]
298struct Error {
299 span: Span,
300 msg: String,
301 highlighted: Option<String>,
302}
303
304impl Error {
305 fn new(span: Span, msg: impl Into<String>) -> Error {
306 Error {
307 span,
308 msg: msg.into(),
309 highlighted: None,
310 }
311 }
312
313 fn highlight(&mut self, source_map: &ast::SourceMap) {
315 if self.highlighted.is_none() {
316 self.highlighted = source_map.highlight_span(self.span, &self.msg);
317 }
318 }
319}
320
321impl fmt::Display for Error {
322 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
323 self.highlighted.as_ref().unwrap_or(&self.msg).fmt(f)
324 }
325}
326
327impl core::error::Error for Error {}
328
329#[derive(Debug)]
330struct PackageNotFoundError {
331 span: Span,
332 requested: PackageName,
333 known: Vec<PackageName>,
334 highlighted: Option<String>,
335}
336
337impl PackageNotFoundError {
338 pub fn new(span: Span, requested: PackageName, known: Vec<PackageName>) -> Self {
339 Self {
340 span,
341 requested,
342 known,
343 highlighted: None,
344 }
345 }
346
347 fn highlight(&mut self, source_map: &ast::SourceMap) {
349 if self.highlighted.is_none() {
350 self.highlighted = source_map.highlight_span(self.span, &format!("{self}"));
351 }
352 }
353}
354
355impl fmt::Display for PackageNotFoundError {
356 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
357 if let Some(highlighted) = &self.highlighted {
358 return highlighted.fmt(f);
359 }
360 if self.known.is_empty() {
361 write!(
362 f,
363 "package '{}' not found. no known packages.",
364 self.requested
365 )?;
366 } else {
367 write!(
368 f,
369 "package '{}' not found. known packages:\n",
370 self.requested
371 )?;
372 for known in self.known.iter() {
373 write!(f, " {known}\n")?;
374 }
375 }
376 Ok(())
377 }
378}
379
380impl core::error::Error for PackageNotFoundError {}
381
382impl UnresolvedPackageGroup {
383 #[cfg(feature = "std")]
389 pub fn parse(path: impl AsRef<Path>, contents: &str) -> Result<UnresolvedPackageGroup> {
390 let path = path
391 .as_ref()
392 .to_str()
393 .ok_or_else(|| anyhow::anyhow!("path is not valid utf-8: {:?}", path.as_ref()))?;
394 let mut map = SourceMap::default();
395 map.push_str(path, contents);
396 map.parse()
397 .map_err(|(map, e)| anyhow::anyhow!("{}", e.highlight(&map)))
398 }
399
400 #[cfg(feature = "std")]
407 pub fn parse_dir(path: impl AsRef<Path>) -> Result<UnresolvedPackageGroup> {
408 let path = path.as_ref();
409 let mut map = SourceMap::default();
410 let cx = || format!("failed to read directory {path:?}");
411 for entry in path.read_dir().with_context(&cx)? {
412 let entry = entry.with_context(&cx)?;
413 let path = entry.path();
414 let ty = entry.file_type().with_context(&cx)?;
415 if ty.is_dir() {
416 continue;
417 }
418 if ty.is_symlink() {
419 if path.is_dir() {
420 continue;
421 }
422 }
423 let filename = match path.file_name().and_then(|s| s.to_str()) {
424 Some(name) => name,
425 None => continue,
426 };
427 if !filename.ends_with(".wit") {
428 continue;
429 }
430 map.push_file(&path)?;
431 }
432 map.parse()
433 .map_err(|(map, e)| anyhow::anyhow!("{}", e.highlight(&map)))
434 }
435}
436
437#[derive(Debug, Clone, PartialEq, Eq)]
438#[cfg_attr(feature = "serde", derive(Serialize))]
439pub struct World {
440 pub name: String,
442
443 pub imports: IndexMap<WorldKey, WorldItem>,
445
446 pub exports: IndexMap<WorldKey, WorldItem>,
448
449 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_optional_id"))]
451 pub package: Option<PackageId>,
452
453 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
455 pub docs: Docs,
456
457 #[cfg_attr(
459 feature = "serde",
460 serde(skip_serializing_if = "Stability::is_unknown")
461 )]
462 pub stability: Stability,
463
464 #[cfg_attr(feature = "serde", serde(skip))]
466 pub includes: Vec<WorldInclude>,
467
468 #[cfg_attr(feature = "serde", serde(skip))]
470 pub span: Span,
471}
472
473impl World {
474 pub(crate) fn adjust_spans(&mut self, offset: u32) {
476 self.span.adjust(offset);
477 for item in self.imports.values_mut().chain(self.exports.values_mut()) {
478 item.adjust_spans(offset);
479 }
480 for include in &mut self.includes {
481 include.span.adjust(offset);
482 }
483 }
484}
485
486#[derive(Debug, Clone, PartialEq, Eq)]
487pub struct IncludeName {
488 pub name: String,
490
491 pub as_: String,
493}
494
495#[derive(Debug, Clone, PartialEq, Eq)]
498pub struct WorldInclude {
499 pub stability: Stability,
501
502 pub id: WorldId,
504
505 pub names: Vec<IncludeName>,
507
508 pub span: Span,
510}
511
512#[derive(Debug, Clone, Eq)]
515#[cfg_attr(feature = "serde", derive(Serialize))]
516#[cfg_attr(feature = "serde", serde(into = "String"))]
517pub enum WorldKey {
518 Name(String),
520 Interface(InterfaceId),
522}
523
524impl Hash for WorldKey {
525 fn hash<H: Hasher>(&self, hasher: &mut H) {
526 match self {
527 WorldKey::Name(s) => {
528 0u8.hash(hasher);
529 s.as_str().hash(hasher);
530 }
531 WorldKey::Interface(i) => {
532 1u8.hash(hasher);
533 i.hash(hasher);
534 }
535 }
536 }
537}
538
539impl PartialEq for WorldKey {
540 fn eq(&self, other: &WorldKey) -> bool {
541 match (self, other) {
542 (WorldKey::Name(a), WorldKey::Name(b)) => a.as_str() == b.as_str(),
543 (WorldKey::Name(_), _) => false,
544 (WorldKey::Interface(a), WorldKey::Interface(b)) => a == b,
545 (WorldKey::Interface(_), _) => false,
546 }
547 }
548}
549
550impl From<WorldKey> for String {
551 fn from(key: WorldKey) -> String {
552 match key {
553 WorldKey::Name(name) => name,
554 WorldKey::Interface(id) => format!("interface-{}", id.index()),
555 }
556 }
557}
558
559impl WorldKey {
560 #[track_caller]
562 pub fn unwrap_name(self) -> String {
563 match self {
564 WorldKey::Name(name) => name,
565 WorldKey::Interface(_) => panic!("expected a name, found interface"),
566 }
567 }
568}
569
570#[derive(Debug, Clone, PartialEq, Eq)]
571#[cfg_attr(feature = "serde", derive(Serialize))]
572#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
573pub enum WorldItem {
574 Interface {
577 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
578 id: InterfaceId,
579 #[cfg_attr(
580 feature = "serde",
581 serde(skip_serializing_if = "Stability::is_unknown")
582 )]
583 stability: Stability,
584 #[cfg_attr(feature = "serde", serde(skip))]
585 span: Span,
586 },
587
588 Function(Function),
590
591 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id_ignore_span"))]
595 Type { id: TypeId, span: Span },
596}
597
598impl WorldItem {
599 pub fn stability<'a>(&'a self, resolve: &'a Resolve) -> &'a Stability {
600 match self {
601 WorldItem::Interface { stability, .. } => stability,
602 WorldItem::Function(f) => &f.stability,
603 WorldItem::Type { id, .. } => &resolve.types[*id].stability,
604 }
605 }
606
607 pub fn span(&self) -> Span {
608 match self {
609 WorldItem::Interface { span, .. } => *span,
610 WorldItem::Function(f) => f.span,
611 WorldItem::Type { span, .. } => *span,
612 }
613 }
614
615 pub(crate) fn adjust_spans(&mut self, offset: u32) {
616 match self {
617 WorldItem::Function(f) => f.adjust_spans(offset),
618 WorldItem::Interface { span, .. } => span.adjust(offset),
619 WorldItem::Type { span, .. } => span.adjust(offset),
620 }
621 }
622}
623
624#[derive(Debug, Clone, PartialEq, Eq)]
625#[cfg_attr(feature = "serde", derive(Serialize))]
626pub struct Interface {
627 pub name: Option<String>,
631
632 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id_map"))]
637 pub types: IndexMap<String, TypeId>,
638
639 pub functions: IndexMap<String, Function>,
641
642 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
644 pub docs: Docs,
645
646 #[cfg_attr(
648 feature = "serde",
649 serde(skip_serializing_if = "Stability::is_unknown")
650 )]
651 pub stability: Stability,
652
653 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_optional_id"))]
655 pub package: Option<PackageId>,
656
657 #[cfg_attr(feature = "serde", serde(skip))]
659 pub span: Span,
660
661 #[cfg_attr(
665 feature = "serde",
666 serde(
667 skip_serializing_if = "Option::is_none",
668 serialize_with = "serialize_optional_id",
669 )
670 )]
671 pub clone_of: Option<InterfaceId>,
672}
673
674impl Interface {
675 pub(crate) fn adjust_spans(&mut self, offset: u32) {
677 self.span.adjust(offset);
678 for func in self.functions.values_mut() {
679 func.adjust_spans(offset);
680 }
681 }
682}
683
684#[derive(Debug, Clone, PartialEq, Eq)]
685#[cfg_attr(feature = "serde", derive(Serialize))]
686pub struct TypeDef {
687 pub name: Option<String>,
688 pub kind: TypeDefKind,
689 pub owner: TypeOwner,
690 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
691 pub docs: Docs,
692 #[cfg_attr(
694 feature = "serde",
695 serde(skip_serializing_if = "Stability::is_unknown")
696 )]
697 pub stability: Stability,
698 #[cfg_attr(feature = "serde", serde(skip))]
700 pub span: Span,
701}
702
703impl TypeDef {
704 pub(crate) fn adjust_spans(&mut self, offset: u32) {
709 self.span.adjust(offset);
710 match &mut self.kind {
711 TypeDefKind::Record(r) => {
712 for field in &mut r.fields {
713 field.span.adjust(offset);
714 }
715 }
716 TypeDefKind::Variant(v) => {
717 for case in &mut v.cases {
718 case.span.adjust(offset);
719 }
720 }
721 TypeDefKind::Enum(e) => {
722 for case in &mut e.cases {
723 case.span.adjust(offset);
724 }
725 }
726 TypeDefKind::Flags(f) => {
727 for flag in &mut f.flags {
728 flag.span.adjust(offset);
729 }
730 }
731 _ => {}
732 }
733 }
734}
735
736#[derive(Debug, Clone, PartialEq, Hash, Eq)]
737#[cfg_attr(feature = "serde", derive(Serialize))]
738#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
739pub enum TypeDefKind {
740 Record(Record),
741 Resource,
742 Handle(Handle),
743 Flags(Flags),
744 Tuple(Tuple),
745 Variant(Variant),
746 Enum(Enum),
747 Option(Type),
748 Result(Result_),
749 List(Type),
750 Map(Type, Type),
751 FixedLengthList(Type, u32),
752 Future(Option<Type>),
753 Stream(Option<Type>),
754 Type(Type),
755
756 Unknown,
762}
763
764impl TypeDefKind {
765 pub fn as_str(&self) -> &'static str {
766 match self {
767 TypeDefKind::Record(_) => "record",
768 TypeDefKind::Resource => "resource",
769 TypeDefKind::Handle(handle) => match handle {
770 Handle::Own(_) => "own",
771 Handle::Borrow(_) => "borrow",
772 },
773 TypeDefKind::Flags(_) => "flags",
774 TypeDefKind::Tuple(_) => "tuple",
775 TypeDefKind::Variant(_) => "variant",
776 TypeDefKind::Enum(_) => "enum",
777 TypeDefKind::Option(_) => "option",
778 TypeDefKind::Result(_) => "result",
779 TypeDefKind::List(_) => "list",
780 TypeDefKind::Map(_, _) => "map",
781 TypeDefKind::FixedLengthList(..) => "fixed-length list",
782 TypeDefKind::Future(_) => "future",
783 TypeDefKind::Stream(_) => "stream",
784 TypeDefKind::Type(_) => "type",
785 TypeDefKind::Unknown => "unknown",
786 }
787 }
788}
789
790#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
791#[cfg_attr(feature = "serde", derive(Serialize))]
792#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
793pub enum TypeOwner {
794 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
796 World(WorldId),
797 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
799 Interface(InterfaceId),
800 #[cfg_attr(feature = "serde", serde(untagged, serialize_with = "serialize_none"))]
803 None,
804}
805
806#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone)]
807#[cfg_attr(feature = "serde", derive(Serialize))]
808#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
809pub enum Handle {
810 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
811 Own(TypeId),
812 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
813 Borrow(TypeId),
814}
815
816#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, Clone)]
817pub enum Type {
818 Bool,
819 U8,
820 U16,
821 U32,
822 U64,
823 S8,
824 S16,
825 S32,
826 S64,
827 F32,
828 F64,
829 Char,
830 String,
831 ErrorContext,
832 Id(TypeId),
833}
834
835#[derive(Debug, Copy, Clone, Eq, PartialEq)]
836pub enum Int {
837 U8,
838 U16,
839 U32,
840 U64,
841}
842
843#[derive(Debug, Clone, PartialEq, Hash, Eq)]
844#[cfg_attr(feature = "serde", derive(Serialize))]
845pub struct Record {
846 pub fields: Vec<Field>,
847}
848
849#[derive(Debug, Clone, PartialEq, Hash, Eq)]
850#[cfg_attr(feature = "serde", derive(Serialize))]
851pub struct Field {
852 pub name: String,
853 #[cfg_attr(feature = "serde", serde(rename = "type"))]
854 pub ty: Type,
855 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
856 pub docs: Docs,
857 #[cfg_attr(feature = "serde", serde(skip))]
859 pub span: Span,
860}
861
862#[derive(Debug, Clone, PartialEq, Hash, Eq)]
863#[cfg_attr(feature = "serde", derive(Serialize))]
864pub struct Flags {
865 pub flags: Vec<Flag>,
866}
867
868#[derive(Debug, Clone, PartialEq, Hash, Eq)]
869#[cfg_attr(feature = "serde", derive(Serialize))]
870pub struct Flag {
871 pub name: String,
872 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
873 pub docs: Docs,
874 #[cfg_attr(feature = "serde", serde(skip))]
876 pub span: Span,
877}
878
879#[derive(Debug, Clone, PartialEq)]
880pub enum FlagsRepr {
881 U8,
882 U16,
883 U32(usize),
884}
885
886impl Flags {
887 pub fn repr(&self) -> FlagsRepr {
888 match self.flags.len() {
889 0 => FlagsRepr::U32(0),
890 n if n <= 8 => FlagsRepr::U8,
891 n if n <= 16 => FlagsRepr::U16,
892 n => FlagsRepr::U32(sizealign::align_to(n, 32) / 32),
893 }
894 }
895}
896
897impl FlagsRepr {
898 pub fn count(&self) -> usize {
899 match self {
900 FlagsRepr::U8 => 1,
901 FlagsRepr::U16 => 1,
902 FlagsRepr::U32(n) => *n,
903 }
904 }
905}
906
907#[derive(Debug, Clone, PartialEq, Hash, Eq)]
908#[cfg_attr(feature = "serde", derive(Serialize))]
909pub struct Tuple {
910 pub types: Vec<Type>,
911}
912
913#[derive(Debug, Clone, PartialEq, Hash, Eq)]
914#[cfg_attr(feature = "serde", derive(Serialize))]
915pub struct Variant {
916 pub cases: Vec<Case>,
917}
918
919#[derive(Debug, Clone, PartialEq, Hash, Eq)]
920#[cfg_attr(feature = "serde", derive(Serialize))]
921pub struct Case {
922 pub name: String,
923 #[cfg_attr(feature = "serde", serde(rename = "type"))]
924 pub ty: Option<Type>,
925 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
926 pub docs: Docs,
927 #[cfg_attr(feature = "serde", serde(skip))]
929 pub span: Span,
930}
931
932impl Variant {
933 pub fn tag(&self) -> Int {
934 discriminant_type(self.cases.len())
935 }
936}
937
938#[derive(Debug, Clone, PartialEq, Hash, Eq)]
939#[cfg_attr(feature = "serde", derive(Serialize))]
940pub struct Enum {
941 pub cases: Vec<EnumCase>,
942}
943
944#[derive(Debug, Clone, PartialEq, Hash, Eq)]
945#[cfg_attr(feature = "serde", derive(Serialize))]
946pub struct EnumCase {
947 pub name: String,
948 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
949 pub docs: Docs,
950 #[cfg_attr(feature = "serde", serde(skip))]
952 pub span: Span,
953}
954
955impl Enum {
956 pub fn tag(&self) -> Int {
957 discriminant_type(self.cases.len())
958 }
959}
960
961fn discriminant_type(num_cases: usize) -> Int {
963 match num_cases.checked_sub(1) {
964 None => Int::U8,
965 Some(n) if n <= u8::max_value() as usize => Int::U8,
966 Some(n) if n <= u16::max_value() as usize => Int::U16,
967 Some(n) if n <= u32::max_value() as usize => Int::U32,
968 _ => panic!("too many cases to fit in a repr"),
969 }
970}
971
972#[derive(Debug, Clone, PartialEq, Hash, Eq)]
973#[cfg_attr(feature = "serde", derive(Serialize))]
974pub struct Result_ {
975 pub ok: Option<Type>,
976 pub err: Option<Type>,
977}
978
979#[derive(Clone, Default, Debug, PartialEq, Eq, Hash)]
980#[cfg_attr(feature = "serde", derive(Serialize))]
981pub struct Docs {
982 pub contents: Option<String>,
983}
984
985impl Docs {
986 pub fn is_empty(&self) -> bool {
987 self.contents.is_none()
988 }
989}
990
991#[derive(Debug, Clone, PartialEq, Eq)]
992#[cfg_attr(feature = "serde", derive(Serialize))]
993pub struct Param {
994 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "String::is_empty"))]
995 pub name: String,
996 #[cfg_attr(feature = "serde", serde(rename = "type"))]
997 pub ty: Type,
998 #[cfg_attr(feature = "serde", serde(skip))]
999 pub span: Span,
1000}
1001
1002#[derive(Debug, Clone, PartialEq, Eq)]
1003#[cfg_attr(feature = "serde", derive(Serialize))]
1004pub struct Function {
1005 pub name: String,
1006 pub kind: FunctionKind,
1007 pub params: Vec<Param>,
1008 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
1009 pub result: Option<Type>,
1010 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
1011 pub docs: Docs,
1012 #[cfg_attr(
1014 feature = "serde",
1015 serde(skip_serializing_if = "Stability::is_unknown")
1016 )]
1017 pub stability: Stability,
1018
1019 #[cfg_attr(feature = "serde", serde(skip))]
1021 pub span: Span,
1022}
1023
1024#[derive(Debug, Clone, PartialEq, Eq)]
1025#[cfg_attr(feature = "serde", derive(Serialize))]
1026#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
1027pub enum FunctionKind {
1028 Freestanding,
1036
1037 AsyncFreestanding,
1045
1046 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
1057 Method(TypeId),
1058
1059 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
1070 AsyncMethod(TypeId),
1071
1072 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
1082 Static(TypeId),
1083
1084 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
1094 AsyncStatic(TypeId),
1095
1096 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
1106 Constructor(TypeId),
1107}
1108
1109impl FunctionKind {
1110 pub fn is_async(&self) -> bool {
1112 match self {
1113 FunctionKind::Freestanding
1114 | FunctionKind::Method(_)
1115 | FunctionKind::Static(_)
1116 | FunctionKind::Constructor(_) => false,
1117 FunctionKind::AsyncFreestanding
1118 | FunctionKind::AsyncMethod(_)
1119 | FunctionKind::AsyncStatic(_) => true,
1120 }
1121 }
1122
1123 pub fn resource(&self) -> Option<TypeId> {
1125 match self {
1126 FunctionKind::Freestanding | FunctionKind::AsyncFreestanding => None,
1127 FunctionKind::Method(id)
1128 | FunctionKind::Static(id)
1129 | FunctionKind::Constructor(id)
1130 | FunctionKind::AsyncMethod(id)
1131 | FunctionKind::AsyncStatic(id) => Some(*id),
1132 }
1133 }
1134
1135 pub fn resource_mut(&mut self) -> Option<&mut TypeId> {
1137 match self {
1138 FunctionKind::Freestanding | FunctionKind::AsyncFreestanding => None,
1139 FunctionKind::Method(id)
1140 | FunctionKind::Static(id)
1141 | FunctionKind::Constructor(id)
1142 | FunctionKind::AsyncMethod(id)
1143 | FunctionKind::AsyncStatic(id) => Some(id),
1144 }
1145 }
1146}
1147
1148#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1150pub enum Mangling {
1151 Standard32,
1154
1155 Legacy,
1160}
1161
1162impl core::str::FromStr for Mangling {
1163 type Err = anyhow::Error;
1164
1165 fn from_str(s: &str) -> Result<Mangling> {
1166 match s {
1167 "legacy" => Ok(Mangling::Legacy),
1168 "standard32" => Ok(Mangling::Standard32),
1169 _ => {
1170 bail!(
1171 "unknown name mangling `{s}`, \
1172 supported values are `legacy` or `standard32`"
1173 )
1174 }
1175 }
1176 }
1177}
1178
1179#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1181pub enum LiftLowerAbi {
1182 Sync,
1184
1185 AsyncCallback,
1188
1189 AsyncStackful,
1192}
1193
1194impl LiftLowerAbi {
1195 fn import_prefix(self) -> &'static str {
1196 match self {
1197 Self::Sync => "",
1198 Self::AsyncCallback | Self::AsyncStackful => "[async-lower]",
1199 }
1200 }
1201
1202 pub fn import_variant(self) -> AbiVariant {
1204 match self {
1205 Self::Sync => AbiVariant::GuestImport,
1206 Self::AsyncCallback | Self::AsyncStackful => AbiVariant::GuestImportAsync,
1207 }
1208 }
1209
1210 fn export_prefix(self) -> &'static str {
1211 match self {
1212 Self::Sync => "",
1213 Self::AsyncCallback => "[async-lift]",
1214 Self::AsyncStackful => "[async-lift-stackful]",
1215 }
1216 }
1217
1218 pub fn export_variant(self) -> AbiVariant {
1220 match self {
1221 Self::Sync => AbiVariant::GuestExport,
1222 Self::AsyncCallback => AbiVariant::GuestExportAsync,
1223 Self::AsyncStackful => AbiVariant::GuestExportAsyncStackful,
1224 }
1225 }
1226}
1227
1228#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1230pub enum ManglingAndAbi {
1231 Standard32,
1236
1237 Legacy(LiftLowerAbi),
1239}
1240
1241impl ManglingAndAbi {
1242 pub fn import_variant(self) -> AbiVariant {
1244 match self {
1245 Self::Standard32 => AbiVariant::GuestImport,
1246 Self::Legacy(abi) => abi.import_variant(),
1247 }
1248 }
1249
1250 pub fn export_variant(self) -> AbiVariant {
1252 match self {
1253 Self::Standard32 => AbiVariant::GuestExport,
1254 Self::Legacy(abi) => abi.export_variant(),
1255 }
1256 }
1257
1258 pub fn sync(self) -> Self {
1260 match self {
1261 Self::Standard32 | Self::Legacy(LiftLowerAbi::Sync) => self,
1262 Self::Legacy(LiftLowerAbi::AsyncCallback)
1263 | Self::Legacy(LiftLowerAbi::AsyncStackful) => Self::Legacy(LiftLowerAbi::Sync),
1264 }
1265 }
1266
1267 pub fn is_async(&self) -> bool {
1269 match self {
1270 Self::Standard32 | Self::Legacy(LiftLowerAbi::Sync) => false,
1271 Self::Legacy(LiftLowerAbi::AsyncCallback)
1272 | Self::Legacy(LiftLowerAbi::AsyncStackful) => true,
1273 }
1274 }
1275
1276 pub fn mangling(&self) -> Mangling {
1277 match self {
1278 Self::Standard32 => Mangling::Standard32,
1279 Self::Legacy(_) => Mangling::Legacy,
1280 }
1281 }
1282}
1283
1284impl Function {
1285 pub(crate) fn adjust_spans(&mut self, offset: u32) {
1287 self.span.adjust(offset);
1288 for param in &mut self.params {
1289 param.span.adjust(offset);
1290 }
1291 }
1292
1293 pub fn item_name(&self) -> &str {
1294 match &self.kind {
1295 FunctionKind::Freestanding | FunctionKind::AsyncFreestanding => &self.name,
1296 FunctionKind::Method(_)
1297 | FunctionKind::Static(_)
1298 | FunctionKind::AsyncMethod(_)
1299 | FunctionKind::AsyncStatic(_) => &self.name[self.name.find('.').unwrap() + 1..],
1300 FunctionKind::Constructor(_) => "constructor",
1301 }
1302 }
1303
1304 pub fn parameter_and_result_types(&self) -> impl Iterator<Item = Type> + '_ {
1309 self.params.iter().map(|p| p.ty).chain(self.result)
1310 }
1311
1312 pub fn standard32_core_export_name<'a>(&'a self, interface: Option<&str>) -> Cow<'a, str> {
1314 self.core_export_name(interface, Mangling::Standard32)
1315 }
1316
1317 pub fn legacy_core_export_name<'a>(&'a self, interface: Option<&str>) -> Cow<'a, str> {
1318 self.core_export_name(interface, Mangling::Legacy)
1319 }
1320 pub fn core_export_name<'a>(
1322 &'a self,
1323 interface: Option<&str>,
1324 mangling: Mangling,
1325 ) -> Cow<'a, str> {
1326 match interface {
1327 Some(interface) => match mangling {
1328 Mangling::Standard32 => Cow::Owned(format!("cm32p2|{interface}|{}", self.name)),
1329 Mangling::Legacy => Cow::Owned(format!("{interface}#{}", self.name)),
1330 },
1331 None => match mangling {
1332 Mangling::Standard32 => Cow::Owned(format!("cm32p2||{}", self.name)),
1333 Mangling::Legacy => Cow::Borrowed(&self.name),
1334 },
1335 }
1336 }
1337 pub fn find_futures_and_streams(&self, resolve: &Resolve) -> Vec<TypeId> {
1353 let mut results = Vec::new();
1354 for param in self.params.iter() {
1355 find_futures_and_streams(resolve, param.ty, &mut results);
1356 }
1357 if let Some(ty) = self.result {
1358 find_futures_and_streams(resolve, ty, &mut results);
1359 }
1360 results
1361 }
1362
1363 pub fn is_constructor_shorthand(&self, resolve: &Resolve) -> bool {
1366 let FunctionKind::Constructor(containing_resource_id) = self.kind else {
1367 return false;
1368 };
1369
1370 let Some(Type::Id(id)) = &self.result else {
1371 return false;
1372 };
1373
1374 let TypeDefKind::Handle(Handle::Own(returned_resource_id)) = resolve.types[*id].kind else {
1375 return false;
1376 };
1377
1378 return containing_resource_id == returned_resource_id;
1379 }
1380
1381 pub fn task_return_import(
1384 &self,
1385 resolve: &Resolve,
1386 interface: Option<&WorldKey>,
1387 mangling: Mangling,
1388 ) -> (String, String, abi::WasmSignature) {
1389 match mangling {
1390 Mangling::Standard32 => todo!(),
1391 Mangling::Legacy => {}
1392 }
1393 let module = match interface {
1395 Some(key) => format!("[export]{}", resolve.name_world_key(key)),
1396 None => "[export]$root".to_string(),
1397 };
1398 let name = format!("[task-return]{}", self.name);
1399
1400 let mut func_tmp = self.clone();
1401 func_tmp.params = Vec::new();
1402 func_tmp.result = None;
1403 if let Some(ty) = self.result {
1404 func_tmp.params.push(Param {
1405 name: "x".to_string(),
1406 ty,
1407 span: Default::default(),
1408 });
1409 }
1410 let sig = resolve.wasm_signature(AbiVariant::GuestImport, &func_tmp);
1411 (module, name, sig)
1412 }
1413
1414 }
1416
1417fn find_futures_and_streams(resolve: &Resolve, ty: Type, results: &mut Vec<TypeId>) {
1418 let Type::Id(id) = ty else {
1419 return;
1420 };
1421
1422 match &resolve.types[id].kind {
1423 TypeDefKind::Resource
1424 | TypeDefKind::Handle(_)
1425 | TypeDefKind::Flags(_)
1426 | TypeDefKind::Enum(_) => {}
1427 TypeDefKind::Record(r) => {
1428 for Field { ty, .. } in &r.fields {
1429 find_futures_and_streams(resolve, *ty, results);
1430 }
1431 }
1432 TypeDefKind::Tuple(t) => {
1433 for ty in &t.types {
1434 find_futures_and_streams(resolve, *ty, results);
1435 }
1436 }
1437 TypeDefKind::Variant(v) => {
1438 for Case { ty, .. } in &v.cases {
1439 if let Some(ty) = ty {
1440 find_futures_and_streams(resolve, *ty, results);
1441 }
1442 }
1443 }
1444 TypeDefKind::Option(ty)
1445 | TypeDefKind::List(ty)
1446 | TypeDefKind::FixedLengthList(ty, ..)
1447 | TypeDefKind::Type(ty) => {
1448 find_futures_and_streams(resolve, *ty, results);
1449 }
1450 TypeDefKind::Map(k, v) => {
1451 find_futures_and_streams(resolve, *k, results);
1452 find_futures_and_streams(resolve, *v, results);
1453 }
1454 TypeDefKind::Result(r) => {
1455 if let Some(ty) = r.ok {
1456 find_futures_and_streams(resolve, ty, results);
1457 }
1458 if let Some(ty) = r.err {
1459 find_futures_and_streams(resolve, ty, results);
1460 }
1461 }
1462 TypeDefKind::Future(ty) => {
1463 if let Some(ty) = ty {
1464 find_futures_and_streams(resolve, *ty, results);
1465 }
1466 results.push(id);
1467 }
1468 TypeDefKind::Stream(ty) => {
1469 if let Some(ty) = ty {
1470 find_futures_and_streams(resolve, *ty, results);
1471 }
1472 results.push(id);
1473 }
1474 TypeDefKind::Unknown => unreachable!(),
1475 }
1476}
1477
1478#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
1486#[cfg_attr(feature = "serde", derive(serde_derive::Deserialize, Serialize))]
1487#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
1488pub enum Stability {
1489 Unknown,
1491
1492 Unstable {
1497 feature: String,
1498 #[cfg_attr(
1499 feature = "serde",
1500 serde(
1501 skip_serializing_if = "Option::is_none",
1502 default,
1503 serialize_with = "serialize_optional_version",
1504 deserialize_with = "deserialize_optional_version"
1505 )
1506 )]
1507 deprecated: Option<Version>,
1508 },
1509
1510 Stable {
1515 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_version"))]
1516 #[cfg_attr(feature = "serde", serde(deserialize_with = "deserialize_version"))]
1517 since: Version,
1518 #[cfg_attr(
1519 feature = "serde",
1520 serde(
1521 skip_serializing_if = "Option::is_none",
1522 default,
1523 serialize_with = "serialize_optional_version",
1524 deserialize_with = "deserialize_optional_version"
1525 )
1526 )]
1527 deprecated: Option<Version>,
1528 },
1529}
1530
1531impl Stability {
1532 pub fn is_unknown(&self) -> bool {
1534 matches!(self, Stability::Unknown)
1535 }
1536
1537 pub fn is_stable(&self) -> bool {
1538 matches!(self, Stability::Stable { .. })
1539 }
1540}
1541
1542impl Default for Stability {
1543 fn default() -> Stability {
1544 Stability::Unknown
1545 }
1546}
1547
1548#[cfg(test)]
1549mod test {
1550 use super::*;
1551 use alloc::vec;
1552
1553 #[test]
1554 fn test_discriminant_type() {
1555 assert_eq!(discriminant_type(1), Int::U8);
1556 assert_eq!(discriminant_type(0x100), Int::U8);
1557 assert_eq!(discriminant_type(0x101), Int::U16);
1558 assert_eq!(discriminant_type(0x10000), Int::U16);
1559 assert_eq!(discriminant_type(0x10001), Int::U32);
1560 if let Ok(num_cases) = usize::try_from(0x100000000_u64) {
1561 assert_eq!(discriminant_type(num_cases), Int::U32);
1562 }
1563 }
1564
1565 #[test]
1566 fn test_find_futures_and_streams() {
1567 let mut resolve = Resolve::default();
1568 let t0 = resolve.types.alloc(TypeDef {
1569 name: None,
1570 kind: TypeDefKind::Future(Some(Type::U32)),
1571 owner: TypeOwner::None,
1572 docs: Docs::default(),
1573 stability: Stability::Unknown,
1574 span: Default::default(),
1575 });
1576 let t1 = resolve.types.alloc(TypeDef {
1577 name: None,
1578 kind: TypeDefKind::Future(Some(Type::Id(t0))),
1579 owner: TypeOwner::None,
1580 docs: Docs::default(),
1581 stability: Stability::Unknown,
1582 span: Default::default(),
1583 });
1584 let t2 = resolve.types.alloc(TypeDef {
1585 name: None,
1586 kind: TypeDefKind::Stream(Some(Type::U32)),
1587 owner: TypeOwner::None,
1588 docs: Docs::default(),
1589 stability: Stability::Unknown,
1590 span: Default::default(),
1591 });
1592 let found = Function {
1593 name: "foo".into(),
1594 kind: FunctionKind::Freestanding,
1595 params: vec![
1596 Param {
1597 name: "p1".into(),
1598 ty: Type::Id(t1),
1599 span: Default::default(),
1600 },
1601 Param {
1602 name: "p2".into(),
1603 ty: Type::U32,
1604 span: Default::default(),
1605 },
1606 ],
1607 result: Some(Type::Id(t2)),
1608 docs: Docs::default(),
1609 stability: Stability::Unknown,
1610 span: Default::default(),
1611 }
1612 .find_futures_and_streams(&resolve);
1613 assert_eq!(3, found.len());
1614 assert_eq!(t0, found[0]);
1615 assert_eq!(t1, found[1]);
1616 assert_eq!(t2, found[2]);
1617 }
1618}