1use serde::{Deserialize, Serialize};
2
3#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Hash)]
4#[serde(rename_all = "lowercase")]
5pub enum Language {
6 Python,
7 Node,
8 Ruby,
9 Php,
10 Elixir,
11 Wasm,
12 Ffi,
13 Go,
14 Java,
15 Csharp,
16 R,
17 Rust,
18 Kotlin,
19 #[serde(rename = "kotlin_android", alias = "kotlin-android")]
20 KotlinAndroid,
21 Swift,
22 Dart,
23 Gleam,
24 Zig,
25 C,
27 #[serde(rename = "jni")]
30 Jni,
31}
32
33impl std::fmt::Display for Language {
34 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
35 match self {
36 Self::Python => write!(f, "python"),
37 Self::Node => write!(f, "node"),
38 Self::Ruby => write!(f, "ruby"),
39 Self::Php => write!(f, "php"),
40 Self::Elixir => write!(f, "elixir"),
41 Self::Wasm => write!(f, "wasm"),
42 Self::Ffi => write!(f, "ffi"),
43 Self::Go => write!(f, "go"),
44 Self::Java => write!(f, "java"),
45 Self::Csharp => write!(f, "csharp"),
46 Self::R => write!(f, "r"),
47 Self::Rust => write!(f, "rust"),
48 Self::Kotlin => write!(f, "kotlin"),
49 Self::KotlinAndroid => write!(f, "kotlin_android"),
50 Self::Swift => write!(f, "swift"),
51 Self::Dart => write!(f, "dart"),
52 Self::Gleam => write!(f, "gleam"),
53 Self::Zig => write!(f, "zig"),
54 Self::C => write!(f, "c"),
55 Self::Jni => write!(f, "jni"),
56 }
57 }
58}
59
60#[derive(Debug, Clone, Serialize, Deserialize)]
62pub struct AdapterParam {
63 pub name: String,
64 #[serde(rename = "type")]
65 pub ty: String,
66 #[serde(default)]
67 pub optional: bool,
68}
69
70#[derive(Debug, Clone, Serialize, Deserialize)]
72#[serde(rename_all = "snake_case")]
73pub enum AdapterPattern {
74 SyncFunction,
75 AsyncMethod,
76 CallbackBridge,
77 Streaming,
78 ServerLifecycle,
79}
80
81#[derive(Debug, Clone, Serialize, Deserialize)]
83pub struct AdapterConfig {
84 pub name: String,
85 pub pattern: AdapterPattern,
86 pub core_path: String,
88 #[serde(default)]
90 pub params: Vec<AdapterParam>,
91 pub returns: Option<String>,
93 pub error_type: Option<String>,
95 pub owner_type: Option<String>,
97 pub item_type: Option<String>,
99 #[serde(default)]
101 pub gil_release: bool,
102 #[serde(default)]
104 pub trait_name: Option<String>,
105 #[serde(default)]
107 pub trait_method: Option<String>,
108 #[serde(default)]
110 pub detect_async: bool,
111 #[serde(default)]
116 pub request_type: Option<String>,
117 #[serde(default)]
134 pub skip_languages: Vec<String>,
135}
136
137pub fn is_known_language(lang_str: &str) -> bool {
139 matches!(
140 lang_str,
141 "python"
142 | "node"
143 | "ruby"
144 | "php"
145 | "elixir"
146 | "wasm"
147 | "ffi"
148 | "go"
149 | "java"
150 | "csharp"
151 | "r"
152 | "rust"
153 | "kotlin"
154 | "kotlin_android"
155 | "swift"
156 | "dart"
157 | "gleam"
158 | "zig"
159 | "c"
160 | "jni"
161 )
162}
163
164#[cfg(test)]
165mod tests {
166 use super::*;
167
168 #[test]
169 fn adapter_config_skip_languages_deserializes() {
170 let toml_str = r#"
171 name = "crawl_stream"
172 pattern = "streaming"
173 core_path = "kreuzcrawl_core::crawl_stream"
174 owner_type = "CrawlEngine"
175 item_type = "CrawlResult"
176 skip_languages = ["wasm", "kotlin"]
177 "#;
178 let config: AdapterConfig = toml::from_str(toml_str).expect("deserialization failed");
179 assert_eq!(config.skip_languages, vec!["wasm", "kotlin"]);
180 assert_eq!(config.name, "crawl_stream");
181 }
182
183 #[test]
184 fn adapter_config_skip_languages_defaults_to_empty() {
185 let toml_str = r#"
186 name = "crawl_stream"
187 pattern = "streaming"
188 core_path = "kreuzcrawl_core::crawl_stream"
189 "#;
190 let config: AdapterConfig = toml::from_str(toml_str).expect("deserialization failed");
191 assert!(config.skip_languages.is_empty());
192 }
193
194 #[test]
195 fn is_known_language_accepts_all_canonical_names() {
196 for name in &[
197 "python", "node", "ruby", "php", "elixir", "wasm", "ffi", "go", "java", "csharp",
198 "r", "rust", "kotlin", "kotlin_android", "swift", "dart", "gleam", "zig", "c", "jni",
199 ] {
200 assert!(is_known_language(name), "{name} should be recognised");
201 }
202 }
203
204 #[test]
205 fn is_known_language_rejects_unknown() {
206 assert!(!is_known_language("wasm32"));
207 assert!(!is_known_language("kotlin-android"));
208 assert!(!is_known_language(""));
209 }
210}