greentic_interfaces/
lib.rs1#![deny(unsafe_code)]
2#![warn(missing_docs, clippy::unwrap_used, clippy::expect_used)]
3#![doc = include_str!("../README.md")]
4
5#[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#[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;