1use crate::abi::AbiVariant;
2use anyhow::{bail, Context, Result};
3use id_arena::{Arena, Id};
4use indexmap::IndexMap;
5use semver::Version;
6use std::borrow::Cow;
7use std::fmt;
8use std::path::Path;
9
10#[cfg(feature = "decoding")]
11pub mod decoding;
12#[cfg(feature = "decoding")]
13mod metadata;
14#[cfg(feature = "decoding")]
15pub use metadata::PackageMetadata;
16
17pub mod abi;
18mod ast;
19use ast::lex::Span;
20pub use ast::SourceMap;
21pub use ast::{parse_use_path, ParsedUsePath};
22mod sizealign;
23pub use sizealign::*;
24mod resolve;
25pub use resolve::*;
26mod live;
27pub use live::{LiveTypes, TypeIdVisitor};
28
29#[cfg(feature = "serde")]
30use serde_derive::Serialize;
31#[cfg(feature = "serde")]
32mod serde_;
33#[cfg(feature = "serde")]
34use serde_::*;
35
36pub fn validate_id(s: &str) -> Result<()> {
38 ast::validate_id(0, s)?;
39 Ok(())
40}
41
42pub type WorldId = Id<World>;
43pub type InterfaceId = Id<Interface>;
44pub type TypeId = Id<TypeDef>;
45
46#[derive(Clone)]
72pub struct UnresolvedPackage {
73 pub name: PackageName,
75
76 pub worlds: Arena<World>,
80
81 pub interfaces: Arena<Interface>,
88
89 pub types: Arena<TypeDef>,
96
97 pub foreign_deps: IndexMap<PackageName, IndexMap<String, AstItem>>,
106
107 pub docs: Docs,
109
110 package_name_span: Span,
111 unknown_type_spans: Vec<Span>,
112 interface_spans: Vec<InterfaceSpan>,
113 world_spans: Vec<WorldSpan>,
114 type_spans: Vec<Span>,
115 foreign_dep_spans: Vec<Span>,
116 required_resource_types: Vec<(TypeId, Span)>,
117}
118
119#[derive(Clone)]
121pub struct UnresolvedPackageGroup {
122 pub main: UnresolvedPackage,
127
128 pub nested: Vec<UnresolvedPackage>,
130
131 pub source_map: SourceMap,
133}
134
135#[derive(Clone)]
136struct WorldSpan {
137 span: Span,
138 imports: Vec<Span>,
139 exports: Vec<Span>,
140 includes: Vec<Span>,
141}
142
143#[derive(Clone)]
144struct InterfaceSpan {
145 span: Span,
146 funcs: Vec<Span>,
147}
148
149#[derive(Debug, Copy, Clone)]
150#[cfg_attr(feature = "serde", derive(Serialize))]
151#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
152pub enum AstItem {
153 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
154 Interface(InterfaceId),
155 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
156 World(WorldId),
157}
158
159#[derive(Debug, Clone, Hash, Eq, PartialEq, Ord, PartialOrd)]
165#[cfg_attr(feature = "serde", derive(Serialize))]
166#[cfg_attr(feature = "serde", serde(into = "String"))]
167pub struct PackageName {
168 pub namespace: String,
170 pub name: String,
172 pub version: Option<Version>,
174}
175
176impl From<PackageName> for String {
177 fn from(name: PackageName) -> String {
178 name.to_string()
179 }
180}
181
182impl PackageName {
183 pub fn interface_id(&self, interface: &str) -> String {
186 let mut s = String::new();
187 s.push_str(&format!("{}:{}/{interface}", self.namespace, self.name));
188 if let Some(version) = &self.version {
189 s.push_str(&format!("@{version}"));
190 }
191 s
192 }
193
194 pub fn version_compat_track(version: &Version) -> Version {
207 let mut version = version.clone();
208 version.build = semver::BuildMetadata::EMPTY;
209 if !version.pre.is_empty() {
210 return version;
211 }
212 if version.major != 0 {
213 version.minor = 0;
214 version.patch = 0;
215 return version;
216 }
217 if version.minor != 0 {
218 version.patch = 0;
219 return version;
220 }
221 version
222 }
223
224 pub fn version_compat_track_string(version: &Version) -> String {
228 let version = Self::version_compat_track(version);
229 if !version.pre.is_empty() {
230 return version.to_string();
231 }
232 if version.major != 0 {
233 return format!("{}", version.major);
234 }
235 if version.minor != 0 {
236 return format!("{}.{}", version.major, version.minor);
237 }
238 version.to_string()
239 }
240}
241
242impl fmt::Display for PackageName {
243 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
244 write!(f, "{}:{}", self.namespace, self.name)?;
245 if let Some(version) = &self.version {
246 write!(f, "@{version}")?;
247 }
248 Ok(())
249 }
250}
251
252#[derive(Debug)]
253struct Error {
254 span: Span,
255 msg: String,
256 highlighted: Option<String>,
257}
258
259impl Error {
260 fn new(span: Span, msg: impl Into<String>) -> Error {
261 Error {
262 span,
263 msg: msg.into(),
264 highlighted: None,
265 }
266 }
267}
268
269impl fmt::Display for Error {
270 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
271 self.highlighted.as_ref().unwrap_or(&self.msg).fmt(f)
272 }
273}
274
275impl std::error::Error for Error {}
276
277#[derive(Debug)]
278struct PackageNotFoundError {
279 span: Span,
280 requested: PackageName,
281 known: Vec<PackageName>,
282 highlighted: Option<String>,
283}
284
285impl PackageNotFoundError {
286 pub fn new(span: Span, requested: PackageName, known: Vec<PackageName>) -> Self {
287 Self {
288 span,
289 requested,
290 known,
291 highlighted: None,
292 }
293 }
294}
295
296impl fmt::Display for PackageNotFoundError {
297 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
298 if let Some(highlighted) = &self.highlighted {
299 return highlighted.fmt(f);
300 }
301 if self.known.is_empty() {
302 write!(
303 f,
304 "package '{}' not found. no known packages.",
305 self.requested
306 )?;
307 } else {
308 write!(
309 f,
310 "package '{}' not found. known packages:\n",
311 self.requested
312 )?;
313 for known in self.known.iter() {
314 write!(f, " {known}\n")?;
315 }
316 }
317 Ok(())
318 }
319}
320
321impl std::error::Error for PackageNotFoundError {}
322
323impl UnresolvedPackageGroup {
324 pub fn parse(path: impl AsRef<Path>, contents: &str) -> Result<UnresolvedPackageGroup> {
330 let mut map = SourceMap::default();
331 map.push(path.as_ref(), contents);
332 map.parse()
333 }
334
335 pub fn parse_path(path: impl AsRef<Path>) -> Result<UnresolvedPackageGroup> {
341 let path = path.as_ref();
342 if path.is_dir() {
343 UnresolvedPackageGroup::parse_dir(path)
344 } else {
345 UnresolvedPackageGroup::parse_file(path)
346 }
347 }
348
349 pub fn parse_file(path: impl AsRef<Path>) -> Result<UnresolvedPackageGroup> {
354 let path = path.as_ref();
355 let contents = std::fs::read_to_string(path)
356 .with_context(|| format!("failed to read file {path:?}"))?;
357 Self::parse(path, &contents)
358 }
359
360 pub fn parse_dir(path: impl AsRef<Path>) -> Result<UnresolvedPackageGroup> {
367 let path = path.as_ref();
368 let mut map = SourceMap::default();
369 let cx = || format!("failed to read directory {path:?}");
370 for entry in path.read_dir().with_context(&cx)? {
371 let entry = entry.with_context(&cx)?;
372 let path = entry.path();
373 let ty = entry.file_type().with_context(&cx)?;
374 if ty.is_dir() {
375 continue;
376 }
377 if ty.is_symlink() {
378 if path.is_dir() {
379 continue;
380 }
381 }
382 let filename = match path.file_name().and_then(|s| s.to_str()) {
383 Some(name) => name,
384 None => continue,
385 };
386 if !filename.ends_with(".wit") {
387 continue;
388 }
389 map.push_file(&path)?;
390 }
391 map.parse()
392 }
393}
394
395#[derive(Debug, Clone)]
396#[cfg_attr(feature = "serde", derive(Serialize))]
397pub struct World {
398 pub name: String,
400
401 pub imports: IndexMap<WorldKey, WorldItem>,
403
404 pub exports: IndexMap<WorldKey, WorldItem>,
406
407 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_optional_id"))]
409 pub package: Option<PackageId>,
410
411 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
413 pub docs: Docs,
414
415 #[cfg_attr(
417 feature = "serde",
418 serde(skip_serializing_if = "Stability::is_unknown")
419 )]
420 pub stability: Stability,
421
422 #[cfg_attr(feature = "serde", serde(skip))]
424 pub includes: Vec<(Stability, WorldId)>,
425
426 #[cfg_attr(feature = "serde", serde(skip))]
428 pub include_names: Vec<Vec<IncludeName>>,
429}
430
431#[derive(Debug, Clone)]
432pub struct IncludeName {
433 pub name: String,
435
436 pub as_: String,
438}
439
440#[derive(Debug, Clone, PartialEq, Eq, Hash)]
443#[cfg_attr(feature = "serde", derive(Serialize))]
444#[cfg_attr(feature = "serde", serde(into = "String"))]
445pub enum WorldKey {
446 Name(String),
448 Interface(InterfaceId),
450}
451
452impl From<WorldKey> for String {
453 fn from(key: WorldKey) -> String {
454 match key {
455 WorldKey::Name(name) => name,
456 WorldKey::Interface(id) => format!("interface-{}", id.index()),
457 }
458 }
459}
460
461impl WorldKey {
462 #[track_caller]
464 pub fn unwrap_name(self) -> String {
465 match self {
466 WorldKey::Name(name) => name,
467 WorldKey::Interface(_) => panic!("expected a name, found interface"),
468 }
469 }
470}
471
472#[derive(Debug, Clone, PartialEq)]
473#[cfg_attr(feature = "serde", derive(Serialize))]
474#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
475pub enum WorldItem {
476 Interface {
479 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
480 id: InterfaceId,
481 #[cfg_attr(
482 feature = "serde",
483 serde(skip_serializing_if = "Stability::is_unknown")
484 )]
485 stability: Stability,
486 },
487
488 Function(Function),
490
491 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
495 Type(TypeId),
496}
497
498impl WorldItem {
499 pub fn stability<'a>(&'a self, resolve: &'a Resolve) -> &'a Stability {
500 match self {
501 WorldItem::Interface { stability, .. } => stability,
502 WorldItem::Function(f) => &f.stability,
503 WorldItem::Type(id) => &resolve.types[*id].stability,
504 }
505 }
506}
507
508#[derive(Debug, Clone)]
509#[cfg_attr(feature = "serde", derive(Serialize))]
510pub struct Interface {
511 pub name: Option<String>,
515
516 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id_map"))]
521 pub types: IndexMap<String, TypeId>,
522
523 pub functions: IndexMap<String, Function>,
525
526 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
528 pub docs: Docs,
529
530 #[cfg_attr(
532 feature = "serde",
533 serde(skip_serializing_if = "Stability::is_unknown")
534 )]
535 pub stability: Stability,
536
537 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_optional_id"))]
539 pub package: Option<PackageId>,
540}
541
542#[derive(Debug, Clone, PartialEq)]
543#[cfg_attr(feature = "serde", derive(Serialize))]
544pub struct TypeDef {
545 pub name: Option<String>,
546 pub kind: TypeDefKind,
547 pub owner: TypeOwner,
548 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
549 pub docs: Docs,
550 #[cfg_attr(
552 feature = "serde",
553 serde(skip_serializing_if = "Stability::is_unknown")
554 )]
555 pub stability: Stability,
556}
557
558#[derive(Debug, Clone, PartialEq)]
559#[cfg_attr(feature = "serde", derive(Serialize))]
560#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
561pub enum TypeDefKind {
562 Record(Record),
563 Resource,
564 Handle(Handle),
565 Flags(Flags),
566 Tuple(Tuple),
567 Variant(Variant),
568 Enum(Enum),
569 Option(Type),
570 Result(Result_),
571 List(Type),
572 Future(Option<Type>),
573 Stream(Option<Type>),
574 ErrorContext,
575 Type(Type),
576
577 Unknown,
583}
584
585impl TypeDefKind {
586 pub fn as_str(&self) -> &'static str {
587 match self {
588 TypeDefKind::Record(_) => "record",
589 TypeDefKind::Resource => "resource",
590 TypeDefKind::Handle(handle) => match handle {
591 Handle::Own(_) => "own",
592 Handle::Borrow(_) => "borrow",
593 },
594 TypeDefKind::Flags(_) => "flags",
595 TypeDefKind::Tuple(_) => "tuple",
596 TypeDefKind::Variant(_) => "variant",
597 TypeDefKind::Enum(_) => "enum",
598 TypeDefKind::Option(_) => "option",
599 TypeDefKind::Result(_) => "result",
600 TypeDefKind::List(_) => "list",
601 TypeDefKind::Future(_) => "future",
602 TypeDefKind::Stream(_) => "stream",
603 TypeDefKind::ErrorContext => "error-context",
604 TypeDefKind::Type(_) => "type",
605 TypeDefKind::Unknown => "unknown",
606 }
607 }
608}
609
610#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
611#[cfg_attr(feature = "serde", derive(Serialize))]
612#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
613pub enum TypeOwner {
614 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
616 World(WorldId),
617 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
619 Interface(InterfaceId),
620 #[cfg_attr(feature = "serde", serde(untagged, serialize_with = "serialize_none"))]
623 None,
624}
625
626#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone)]
627#[cfg_attr(feature = "serde", derive(Serialize))]
628#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
629pub enum Handle {
630 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
631 Own(TypeId),
632 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
633 Borrow(TypeId),
634}
635
636#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone)]
637pub enum Type {
638 Bool,
639 U8,
640 U16,
641 U32,
642 U64,
643 S8,
644 S16,
645 S32,
646 S64,
647 F32,
648 F64,
649 Char,
650 String,
651 Id(TypeId),
652}
653
654#[derive(Debug, Copy, Clone, Eq, PartialEq)]
655pub enum Int {
656 U8,
657 U16,
658 U32,
659 U64,
660}
661
662#[derive(Debug, Clone, PartialEq)]
663#[cfg_attr(feature = "serde", derive(Serialize))]
664pub struct Record {
665 pub fields: Vec<Field>,
666}
667
668#[derive(Debug, Clone, PartialEq)]
669#[cfg_attr(feature = "serde", derive(Serialize))]
670pub struct Field {
671 pub name: String,
672 #[cfg_attr(feature = "serde", serde(rename = "type"))]
673 pub ty: Type,
674 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
675 pub docs: Docs,
676}
677
678#[derive(Debug, Clone, PartialEq)]
679#[cfg_attr(feature = "serde", derive(Serialize))]
680pub struct Flags {
681 pub flags: Vec<Flag>,
682}
683
684#[derive(Debug, Clone, PartialEq)]
685#[cfg_attr(feature = "serde", derive(Serialize))]
686pub struct Flag {
687 pub name: String,
688 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
689 pub docs: Docs,
690}
691
692#[derive(Debug, Clone, PartialEq)]
693pub enum FlagsRepr {
694 U8,
695 U16,
696 U32(usize),
697}
698
699impl Flags {
700 pub fn repr(&self) -> FlagsRepr {
701 match self.flags.len() {
702 0 => FlagsRepr::U32(0),
703 n if n <= 8 => FlagsRepr::U8,
704 n if n <= 16 => FlagsRepr::U16,
705 n => FlagsRepr::U32(sizealign::align_to(n, 32) / 32),
706 }
707 }
708}
709
710impl FlagsRepr {
711 pub fn count(&self) -> usize {
712 match self {
713 FlagsRepr::U8 => 1,
714 FlagsRepr::U16 => 1,
715 FlagsRepr::U32(n) => *n,
716 }
717 }
718}
719
720#[derive(Debug, Clone, PartialEq)]
721#[cfg_attr(feature = "serde", derive(Serialize))]
722pub struct Tuple {
723 pub types: Vec<Type>,
724}
725
726#[derive(Debug, Clone, PartialEq)]
727#[cfg_attr(feature = "serde", derive(Serialize))]
728pub struct Variant {
729 pub cases: Vec<Case>,
730}
731
732#[derive(Debug, Clone, PartialEq)]
733#[cfg_attr(feature = "serde", derive(Serialize))]
734pub struct Case {
735 pub name: String,
736 #[cfg_attr(feature = "serde", serde(rename = "type"))]
737 pub ty: Option<Type>,
738 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
739 pub docs: Docs,
740}
741
742impl Variant {
743 pub fn tag(&self) -> Int {
744 discriminant_type(self.cases.len())
745 }
746}
747
748#[derive(Debug, Clone, PartialEq)]
749#[cfg_attr(feature = "serde", derive(Serialize))]
750pub struct Enum {
751 pub cases: Vec<EnumCase>,
752}
753
754#[derive(Debug, Clone, PartialEq)]
755#[cfg_attr(feature = "serde", derive(Serialize))]
756pub struct EnumCase {
757 pub name: String,
758 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
759 pub docs: Docs,
760}
761
762impl Enum {
763 pub fn tag(&self) -> Int {
764 discriminant_type(self.cases.len())
765 }
766}
767
768fn discriminant_type(num_cases: usize) -> Int {
770 match num_cases.checked_sub(1) {
771 None => Int::U8,
772 Some(n) if n <= u8::max_value() as usize => Int::U8,
773 Some(n) if n <= u16::max_value() as usize => Int::U16,
774 Some(n) if n <= u32::max_value() as usize => Int::U32,
775 _ => panic!("too many cases to fit in a repr"),
776 }
777}
778
779#[derive(Debug, Clone, PartialEq)]
780#[cfg_attr(feature = "serde", derive(Serialize))]
781pub struct Result_ {
782 pub ok: Option<Type>,
783 pub err: Option<Type>,
784}
785
786#[derive(Clone, Default, Debug, PartialEq, Eq)]
787#[cfg_attr(feature = "serde", derive(Serialize))]
788pub struct Docs {
789 pub contents: Option<String>,
790}
791
792impl Docs {
793 pub fn is_empty(&self) -> bool {
794 self.contents.is_none()
795 }
796}
797
798#[derive(Debug, Clone, PartialEq, Eq)]
799#[cfg_attr(feature = "serde", derive(Serialize))]
800pub struct Function {
801 pub name: String,
802 pub kind: FunctionKind,
803 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_params"))]
804 pub params: Vec<(String, Type)>,
805 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
806 pub result: Option<Type>,
807 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
808 pub docs: Docs,
809 #[cfg_attr(
811 feature = "serde",
812 serde(skip_serializing_if = "Stability::is_unknown")
813 )]
814 pub stability: Stability,
815}
816
817#[derive(Debug, Clone, PartialEq, Eq)]
818#[cfg_attr(feature = "serde", derive(Serialize))]
819#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
820pub enum FunctionKind {
821 Freestanding,
822 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
823 Method(TypeId),
824 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
825 Static(TypeId),
826 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
827 Constructor(TypeId),
828}
829
830impl FunctionKind {
831 pub fn resource(&self) -> Option<TypeId> {
833 match self {
834 FunctionKind::Freestanding => None,
835 FunctionKind::Method(id) | FunctionKind::Static(id) | FunctionKind::Constructor(id) => {
836 Some(*id)
837 }
838 }
839 }
840}
841
842#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
844pub enum Mangling {
845 Standard32,
848
849 Legacy,
854}
855
856impl std::str::FromStr for Mangling {
857 type Err = anyhow::Error;
858
859 fn from_str(s: &str) -> Result<Mangling> {
860 match s {
861 "legacy" => Ok(Mangling::Legacy),
862 "standard32" => Ok(Mangling::Standard32),
863 _ => {
864 bail!(
865 "unknown name mangling `{s}`, \
866 supported values are `legacy` or `standard32`"
867 )
868 }
869 }
870 }
871}
872
873#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
875pub enum LiftLowerAbi {
876 Sync,
878
879 AsyncCallback,
882
883 AsyncStackful,
886}
887
888impl LiftLowerAbi {
889 fn import_prefix(self) -> &'static str {
890 match self {
891 Self::Sync => "",
892 Self::AsyncCallback | Self::AsyncStackful => "[async]",
893 }
894 }
895
896 pub fn import_variant(self) -> AbiVariant {
898 match self {
899 Self::Sync => AbiVariant::GuestImport,
900 Self::AsyncCallback | Self::AsyncStackful => AbiVariant::GuestImportAsync,
901 }
902 }
903
904 fn export_prefix(self) -> &'static str {
905 match self {
906 Self::Sync => "",
907 Self::AsyncCallback => "[async]",
908 Self::AsyncStackful => "[async-stackful]",
909 }
910 }
911
912 pub fn export_variant(self) -> AbiVariant {
914 match self {
915 Self::Sync => AbiVariant::GuestExport,
916 Self::AsyncCallback => AbiVariant::GuestExportAsync,
917 Self::AsyncStackful => AbiVariant::GuestExportAsyncStackful,
918 }
919 }
920}
921
922#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
924pub enum ManglingAndAbi {
925 Standard32,
930
931 Legacy(LiftLowerAbi),
933}
934
935impl ManglingAndAbi {
936 pub fn import_variant(self) -> AbiVariant {
938 match self {
939 Self::Standard32 => AbiVariant::GuestImport,
940 Self::Legacy(abi) => abi.import_variant(),
941 }
942 }
943
944 pub fn export_variant(self) -> AbiVariant {
946 match self {
947 Self::Standard32 => AbiVariant::GuestExport,
948 Self::Legacy(abi) => abi.export_variant(),
949 }
950 }
951}
952
953impl Function {
954 pub fn item_name(&self) -> &str {
955 match &self.kind {
956 FunctionKind::Freestanding => &self.name,
957 FunctionKind::Method(_) | FunctionKind::Static(_) => {
958 &self.name[self.name.find('.').unwrap() + 1..]
959 }
960 FunctionKind::Constructor(_) => "constructor",
961 }
962 }
963
964 pub fn parameter_and_result_types(&self) -> impl Iterator<Item = Type> + '_ {
969 self.params.iter().map(|(_, t)| *t).chain(self.result)
970 }
971
972 pub fn standard32_core_export_name<'a>(&'a self, interface: Option<&str>) -> Cow<'a, str> {
974 self.core_export_name(interface, Mangling::Standard32)
975 }
976
977 pub fn legacy_core_export_name<'a>(&'a self, interface: Option<&str>) -> Cow<'a, str> {
978 self.core_export_name(interface, Mangling::Legacy)
979 }
980 pub fn core_export_name<'a>(
982 &'a self,
983 interface: Option<&str>,
984 mangling: Mangling,
985 ) -> Cow<'a, str> {
986 match interface {
987 Some(interface) => match mangling {
988 Mangling::Standard32 => Cow::Owned(format!("cm32p2|{interface}|{}", self.name)),
989 Mangling::Legacy => Cow::Owned(format!("{interface}#{}", self.name)),
990 },
991 None => match mangling {
992 Mangling::Standard32 => Cow::Owned(format!("cm32p2||{}", self.name)),
993 Mangling::Legacy => Cow::Borrowed(&self.name),
994 },
995 }
996 }
997 pub fn find_futures_and_streams(&self, resolve: &Resolve) -> Vec<TypeId> {
1013 let mut results = Vec::new();
1014 for (_, ty) in self.params.iter() {
1015 find_futures_and_streams(resolve, *ty, &mut results);
1016 }
1017 if let Some(ty) = self.result {
1018 find_futures_and_streams(resolve, ty, &mut results);
1019 }
1020 results
1021 }
1022}
1023
1024fn find_futures_and_streams(resolve: &Resolve, ty: Type, results: &mut Vec<TypeId>) {
1025 let Type::Id(id) = ty else {
1026 return;
1027 };
1028
1029 match &resolve.types[id].kind {
1030 TypeDefKind::Resource
1031 | TypeDefKind::Handle(_)
1032 | TypeDefKind::Flags(_)
1033 | TypeDefKind::Enum(_)
1034 | TypeDefKind::ErrorContext => {}
1035 TypeDefKind::Record(r) => {
1036 for Field { ty, .. } in &r.fields {
1037 find_futures_and_streams(resolve, *ty, results);
1038 }
1039 }
1040 TypeDefKind::Tuple(t) => {
1041 for ty in &t.types {
1042 find_futures_and_streams(resolve, *ty, results);
1043 }
1044 }
1045 TypeDefKind::Variant(v) => {
1046 for Case { ty, .. } in &v.cases {
1047 if let Some(ty) = ty {
1048 find_futures_and_streams(resolve, *ty, results);
1049 }
1050 }
1051 }
1052 TypeDefKind::Option(ty) | TypeDefKind::List(ty) | TypeDefKind::Type(ty) => {
1053 find_futures_and_streams(resolve, *ty, results);
1054 }
1055 TypeDefKind::Result(r) => {
1056 if let Some(ty) = r.ok {
1057 find_futures_and_streams(resolve, ty, results);
1058 }
1059 if let Some(ty) = r.err {
1060 find_futures_and_streams(resolve, ty, results);
1061 }
1062 }
1063 TypeDefKind::Future(ty) => {
1064 if let Some(ty) = ty {
1065 find_futures_and_streams(resolve, *ty, results);
1066 }
1067 results.push(id);
1068 }
1069 TypeDefKind::Stream(ty) => {
1070 if let Some(ty) = ty {
1071 find_futures_and_streams(resolve, *ty, results);
1072 }
1073 results.push(id);
1074 }
1075 TypeDefKind::Unknown => unreachable!(),
1076 }
1077}
1078
1079#[derive(Debug, Clone, PartialEq, Eq)]
1085#[cfg_attr(feature = "serde", derive(serde_derive::Deserialize, Serialize))]
1086#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
1087pub enum Stability {
1088 Stable {
1093 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_version"))]
1094 #[cfg_attr(feature = "serde", serde(deserialize_with = "deserialize_version"))]
1095 since: Version,
1096 #[cfg_attr(
1097 feature = "serde",
1098 serde(
1099 skip_serializing_if = "Option::is_none",
1100 default,
1101 serialize_with = "serialize_optional_version",
1102 deserialize_with = "deserialize_optional_version"
1103 )
1104 )]
1105 deprecated: Option<Version>,
1106 },
1107
1108 Unstable {
1113 feature: String,
1114 #[cfg_attr(
1115 feature = "serde",
1116 serde(
1117 skip_serializing_if = "Option::is_none",
1118 default,
1119 serialize_with = "serialize_optional_version",
1120 deserialize_with = "deserialize_optional_version"
1121 )
1122 )]
1123 deprecated: Option<Version>,
1124 },
1125
1126 Unknown,
1128}
1129
1130impl Stability {
1131 pub fn is_unknown(&self) -> bool {
1133 matches!(self, Stability::Unknown)
1134 }
1135}
1136
1137impl Default for Stability {
1138 fn default() -> Stability {
1139 Stability::Unknown
1140 }
1141}
1142
1143#[cfg(test)]
1144mod test {
1145 use super::*;
1146
1147 #[test]
1148 fn test_discriminant_type() {
1149 assert_eq!(discriminant_type(1), Int::U8);
1150 assert_eq!(discriminant_type(0x100), Int::U8);
1151 assert_eq!(discriminant_type(0x101), Int::U16);
1152 assert_eq!(discriminant_type(0x10000), Int::U16);
1153 assert_eq!(discriminant_type(0x10001), Int::U32);
1154 if let Ok(num_cases) = usize::try_from(0x100000000_u64) {
1155 assert_eq!(discriminant_type(num_cases), Int::U32);
1156 }
1157 }
1158
1159 #[test]
1160 fn test_find_futures_and_streams() {
1161 let mut resolve = Resolve::default();
1162 let t0 = resolve.types.alloc(TypeDef {
1163 name: None,
1164 kind: TypeDefKind::Future(Some(Type::U32)),
1165 owner: TypeOwner::None,
1166 docs: Docs::default(),
1167 stability: Stability::Unknown,
1168 });
1169 let t1 = resolve.types.alloc(TypeDef {
1170 name: None,
1171 kind: TypeDefKind::Future(Some(Type::Id(t0))),
1172 owner: TypeOwner::None,
1173 docs: Docs::default(),
1174 stability: Stability::Unknown,
1175 });
1176 let t2 = resolve.types.alloc(TypeDef {
1177 name: None,
1178 kind: TypeDefKind::Stream(Some(Type::U32)),
1179 owner: TypeOwner::None,
1180 docs: Docs::default(),
1181 stability: Stability::Unknown,
1182 });
1183 let found = Function {
1184 name: "foo".into(),
1185 kind: FunctionKind::Freestanding,
1186 params: vec![("p1".into(), Type::Id(t1)), ("p2".into(), Type::U32)],
1187 result: Some(Type::Id(t2)),
1188 docs: Docs::default(),
1189 stability: Stability::Unknown,
1190 }
1191 .find_futures_and_streams(&resolve);
1192 assert_eq!(3, found.len());
1193 assert_eq!(t0, found[0]);
1194 assert_eq!(t1, found[1]);
1195 assert_eq!(t2, found[2]);
1196 }
1197}