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