Skip to main content

greentic_interfaces/
lib.rs

1#![deny(unsafe_code)]
2#![warn(missing_docs, clippy::unwrap_used, clippy::expect_used)]
3#![doc = include_str!("../README.md")]
4
5//! ABI-oriented bindings for Greentic WIT packages.
6
7/// Returns the canonical WIT root shipped with this crate.
8#[must_use]
9pub fn wit_root() -> std::path::PathBuf {
10    let manifest_dir = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"));
11    for candidate in [
12        manifest_dir.join("../../wit"),
13        manifest_dir.join("wit"),
14        manifest_dir.join("../greentic-interfaces/wit"),
15    ] {
16        if has_wit_files(&candidate) {
17            return candidate;
18        }
19    }
20    manifest_dir.join("wit")
21}
22
23fn has_wit_files(root: &std::path::Path) -> bool {
24    let mut stack = vec![root.to_path_buf()];
25    while let Some(dir) = stack.pop() {
26        let Ok(entries) = std::fs::read_dir(dir) else {
27            continue;
28        };
29        for entry in entries.flatten() {
30            let path = entry.path();
31            if path.is_dir() {
32                stack.push(path);
33            } else if path.extension().and_then(|s| s.to_str()) == Some("wit") {
34                return true;
35            }
36        }
37    }
38    false
39}
40
41#[cfg(test)]
42mod tests {
43    use super::*;
44
45    use std::fs;
46    use std::path::PathBuf;
47    use std::time::{SystemTime, UNIX_EPOCH};
48
49    struct TempTree {
50        root: PathBuf,
51    }
52
53    impl TempTree {
54        fn new(name: &str) -> Self {
55            let nanos = match SystemTime::now().duration_since(UNIX_EPOCH) {
56                Ok(duration) => duration.as_nanos(),
57                Err(err) => panic!("system time before epoch: {err}"),
58            };
59            let root = std::env::temp_dir().join(format!("{name}-{}-{nanos}", std::process::id()));
60            if let Err(err) = fs::create_dir_all(&root) {
61                panic!("create temp tree: {err}");
62            }
63            Self { root }
64        }
65    }
66
67    impl Drop for TempTree {
68        fn drop(&mut self) {
69            let _ = fs::remove_dir_all(&self.root);
70        }
71    }
72
73    #[test]
74    fn has_wit_files_finds_nested_wit_package() {
75        let temp = TempTree::new("greentic-wit-root");
76        let nested = temp.root.join("greentic/example");
77        if let Err(err) = fs::create_dir_all(&nested) {
78            panic!("create nested WIT dir: {err}");
79        }
80        if let Err(err) = fs::write(nested.join("package.wit"), "package greentic:example;") {
81            panic!("write WIT file: {err}");
82        }
83
84        assert!(has_wit_files(&temp.root));
85    }
86
87    #[test]
88    fn has_wit_files_ignores_missing_or_non_wit_trees() {
89        let temp = TempTree::new("greentic-empty-wit-root");
90        if let Err(err) = fs::write(temp.root.join("README.md"), "not WIT") {
91            panic!("write marker: {err}");
92        }
93
94        assert!(!has_wit_files(&temp.root));
95        assert!(!has_wit_files(&temp.root.join("missing")));
96    }
97
98    #[test]
99    fn wit_root_points_at_a_tree_with_wit_files() {
100        let root = wit_root();
101        assert!(
102            has_wit_files(&root),
103            "wit_root selected a path without WIT files: {}",
104            root.display()
105        );
106    }
107}
108
109/// Stable ABI facade modules (`canonical`, `v0_6_0`) over generated bindings.
110#[cfg(all(feature = "bindings-rust", not(target_arch = "wasm32")))]
111pub mod abi;
112#[cfg(not(target_arch = "wasm32"))]
113pub mod bindings;
114#[cfg(not(target_arch = "wasm32"))]
115pub mod wit_all;
116#[cfg(all(
117    feature = "bindings-rust",
118    feature = "wit-v0_6_0",
119    not(target_arch = "wasm32")
120))]
121pub use abi::canonical;
122#[cfg(all(
123    feature = "bindings-rust",
124    feature = "wit-v0_6_0",
125    not(target_arch = "wasm32")
126))]
127pub use abi::v0_6_0;
128#[cfg(all(
129    feature = "bindings-rust",
130    feature = "provider-common",
131    not(target_arch = "wasm32")
132))]
133pub use bindings::provider_common_0_0_2_common;
134#[cfg(not(target_arch = "wasm32"))]
135#[allow(unused_imports)]
136pub use wit_all::*;
137#[cfg(all(
138    feature = "bindings-rust",
139    feature = "wit-v0_6_0",
140    not(target_arch = "wasm32")
141))]
142pub mod mappers;
143#[cfg(all(
144    feature = "bindings-rust",
145    feature = "wit-v0_6_0",
146    not(target_arch = "wasm32")
147))]
148pub mod validate;