javy_codegen/
wit.rs

1use std::path::{Path, PathBuf};
2
3use anyhow::{bail, Result};
4
5use wit_parser::{Resolve, WorldItem};
6
7/// Options for using WIT in the code generation process.
8#[derive(Default, Clone, Debug, PartialEq)]
9pub struct WitOptions {
10    /// The path of the .wit file to use.
11    pub path: Option<PathBuf>,
12    /// The name of the wit world to use.
13    pub world: Option<String>,
14}
15
16impl WitOptions {
17    /// Generate WitOptions from a Tuple of Options.
18    pub fn from_tuple(opts: (Option<PathBuf>, Option<String>)) -> Result<Self> {
19        match opts {
20            (None, None) => Ok(Self {
21                path: None,
22                world: None,
23            }),
24            (None, Some(_)) => Ok(Self {
25                path: None,
26                world: None,
27            }),
28            (Some(_), None) => bail!("Must provide WIT world when providing WIT file"),
29            (path, world) => Ok(Self { path, world }),
30        }
31    }
32
33    /// Whether WIT options were defined.
34    pub(crate) fn defined(&self) -> bool {
35        self.path.is_some() && self.world.is_some()
36    }
37
38    /// Unwraps a refernce to the .wit file path.
39    pub(crate) fn unwrap_path(&self) -> &PathBuf {
40        self.path.as_ref().unwrap()
41    }
42
43    /// Unwraps a reference to the WIT world name.
44    pub(crate) fn unwrap_world(&self) -> &String {
45        self.world.as_ref().unwrap()
46    }
47}
48
49pub(crate) fn parse_exports(wit: impl AsRef<Path>, world: &str) -> Result<Vec<String>> {
50    let mut resolve = Resolve::default();
51    resolve.push_path(wit.as_ref())?;
52    let (_, package_id) = resolve.package_names.first().unwrap();
53    let world_id = resolve.select_world(&[*package_id], Some(world))?;
54    let world = resolve.worlds.get(world_id).unwrap();
55
56    if !world.imports.is_empty() {
57        bail!("Imports in WIT file are not supported");
58    }
59    let mut exported_functions = vec![];
60    for (_, export) in &world.exports {
61        match export {
62            WorldItem::Interface { .. } => {
63                bail!("Exported interfaces are not supported")
64            }
65            WorldItem::Function(f) => {
66                if !f.params.is_empty() {
67                    bail!("Exported functions with parameters are not supported")
68                } else if f.results.len() != 0 {
69                    bail!("Exported functions with return values are not supported")
70                } else {
71                    exported_functions.push(f.name.clone())
72                }
73            }
74            WorldItem::Type(_) => bail!("Exported types are not supported"),
75        }
76    }
77    Ok(exported_functions)
78}