1#[macro_export]
45macro_rules! declare_tools {
46 (tools: [ $($tool:expr),* $(,)? ]) => {
47 static TOOLS: ::std::sync::OnceLock<::std::collections::HashMap<::std::string::String, $crate::tool::Tool>>
48 = ::std::sync::OnceLock::new();
49 static TOOLS_LIST_CACHE: ::std::sync::OnceLock<::std::vec::Vec<u8>>
50 = ::std::sync::OnceLock::new();
51
52 fn get_tools() -> &'static ::std::collections::HashMap<::std::string::String, $crate::tool::Tool> {
53 TOOLS.get_or_init(|| {
54 let mut map = ::std::collections::HashMap::new();
55 $(
56 let tool = $tool;
57 map.insert(tool.name.clone(), tool);
58 )*
59 map
60 })
61 }
62
63 fn get_tools_list_cache() -> &'static [u8] {
64 TOOLS_LIST_CACHE.get_or_init(|| {
65 let tools = get_tools();
66 let tools_json: ::std::vec::Vec<$crate::serde_json::Value> = tools
67 .values()
68 .filter(|t| t.active)
69 .map(|t| t.to_json_schema())
70 .collect();
71 let json_array = $crate::serde_json::Value::Array(tools_json);
72 json_array.to_string().into_bytes()
73 })
74 }
75
76 #[no_mangle]
78 pub unsafe extern "C" fn generated_list_tools(
79 result_buf: *mut *mut u8,
80 result_len: *mut usize,
81 ) -> i32 {
82 $crate::utils::return_prebuilt(get_tools_list_cache(), result_buf, result_len)
83 }
84
85 #[no_mangle]
87 pub unsafe extern "C" fn generated_execute_tool(
88 tool_name: *const ::std::os::raw::c_char,
89 args_json: *const u8,
90 args_len: usize,
91 result_buf: *mut *mut u8,
92 result_len: *mut usize,
93 ) -> i32 {
94 use ::std::ffi::CStr;
95
96 let name = match CStr::from_ptr(tool_name).to_str() {
97 Ok(s) => s,
98 Err(_) => return $crate::utils::return_error(
99 "Invalid tool name encoding",
100 result_buf,
101 result_len
102 ),
103 };
104
105 let args_slice = ::std::slice::from_raw_parts(args_json, args_len);
106 let args: $crate::serde_json::Value = match $crate::serde_json::from_slice(args_slice) {
107 Ok(v) => v,
108 Err(e) => return $crate::utils::return_error(
109 &format!("Invalid JSON arguments: {}", e),
110 result_buf,
111 result_len
112 ),
113 };
114
115 let tools = get_tools();
116 match tools.get(name) {
117 Some(tool) => {
118 if tool.active {
119 match (tool.handler)(&args) {
120 Ok(result) => $crate::utils::return_success(
121 result,
122 result_buf,
123 result_len
124 ),
125 Err(e) => $crate::utils::return_error(
126 &e,
127 result_buf,
128 result_len
129 ),
130 }
131 } else {
132 $crate::utils::return_error(
133 &format!("Inactive tool: {}", name),
134 result_buf,
135 result_len)
136 }
137 }
138 None => $crate::utils::return_error(
139 &format!("Unknown tool: {}", name),
140 result_buf,
141 result_len
142 ),
143 }
144 }
145 };
146}
147
148#[macro_export]
188macro_rules! declare_resources {
189 (resources: [ $($resource:expr),* $(,)? ]) => {
190 $crate::declare_resources!(@impl
191 resources: [$($resource),*],
192 templates: [],
193 read_fallback: []
194 );
195 };
196 (
197 resources: [ $($resource:expr),* $(,)? ],
198 templates: [ $($template:expr),* $(,)? ]
199 ) => {
200 $crate::declare_resources!(@impl
201 resources: [$($resource),*],
202 templates: [$($template),*],
203 read_fallback: []
204 );
205 };
206 (
207 resources: [ $($resource:expr),* $(,)? ],
208 templates: [ $($template:expr),* $(,)? ],
209 read_fallback: $fallback:expr
210 ) => {
211 $crate::declare_resources!(@impl
212 resources: [$($resource),*],
213 templates: [$($template),*],
214 read_fallback: [$fallback]
215 );
216 };
217
218 (@impl resources: [$($resource:expr),*], templates: [$($template:expr),*], read_fallback: [$($fallback:tt)*]) => {
219 static RESOURCES: ::std::sync::OnceLock<::std::collections::HashMap<::std::string::String, $crate::resource::Resource>>
220 = ::std::sync::OnceLock::new();
221 static COMPILED_TEMPLATE_MATCHERS: ::std::sync::OnceLock<::std::vec::Vec<$crate::resource::CompiledTemplateMatcher>>
222 = ::std::sync::OnceLock::new();
223 static RESOURCES_LIST_CACHE: ::std::sync::OnceLock<::std::vec::Vec<u8>>
224 = ::std::sync::OnceLock::new();
225 static TEMPLATES_LIST_CACHE: ::std::sync::OnceLock<::std::vec::Vec<u8>>
226 = ::std::sync::OnceLock::new();
227
228 fn get_resources() -> &'static ::std::collections::HashMap<::std::string::String, $crate::resource::Resource> {
229 RESOURCES.get_or_init(|| {
230 let mut map = ::std::collections::HashMap::new();
231 $(
232 let resource = $resource;
233 map.insert(resource.uri.clone(), resource);
234 )*
235 map
236 })
237 }
238
239 fn get_template_matchers() -> &'static ::std::vec::Vec<$crate::resource::CompiledTemplateMatcher> {
240 COMPILED_TEMPLATE_MATCHERS.get_or_init(|| {
241 vec![$($template),*]
242 .into_iter()
243 .map(|t| $crate::resource::CompiledTemplateMatcher::new(t)
244 .expect("invalid URI template in declare_resources!"))
245 .collect()
246 })
247 }
248
249 fn get_resources_list_cache() -> &'static [u8] {
250 RESOURCES_LIST_CACHE.get_or_init(|| {
251 let resources = get_resources();
252 let items: ::std::vec::Vec<$crate::serde_json::Value> = resources
253 .values()
254 .map(|r| r.to_list_item())
255 .collect();
256 $crate::utils::resource_list_response(items, None)
257 .to_string().into_bytes()
258 })
259 }
260
261 fn get_templates_list_cache() -> &'static [u8] {
262 TEMPLATES_LIST_CACHE.get_or_init(|| {
263 let matchers = get_template_matchers();
264 let items: ::std::vec::Vec<$crate::serde_json::Value> = matchers
265 .iter()
266 .map(|m| m.template.to_template_list_item())
267 .collect();
268 $crate::utils::resource_template_list_response(items, None)
269 .to_string().into_bytes()
270 })
271 }
272
273 fn read_fallback_handler() -> ::std::option::Option<$crate::resource::GenericResourceReadHandler> {
274 $crate::__declare_plugin_option!($($fallback)*)
275 }
276
277 $crate::declare_resources!(@generated_functions);
278 };
279
280 (@generated_functions) => {
281 #[no_mangle]
283 pub unsafe extern "C" fn generated_list_resources(
284 result_buf: *mut *mut u8,
285 result_len: *mut usize,
286 ) -> i32 {
287 $crate::utils::return_prebuilt(get_resources_list_cache(), result_buf, result_len)
288 }
289
290 #[no_mangle]
292 pub unsafe extern "C" fn generated_list_resource_templates(
293 result_buf: *mut *mut u8,
294 result_len: *mut usize,
295 ) -> i32 {
296 $crate::utils::return_prebuilt(get_templates_list_cache(), result_buf, result_len)
297 }
298
299 #[no_mangle]
305 pub unsafe extern "C" fn generated_read_resource(
306 uri_ptr: *const u8,
307 uri_len: usize,
308 result_buf: *mut *mut u8,
309 result_len: *mut usize,
310 ) -> i32 {
311 let uri_slice = ::std::slice::from_raw_parts(uri_ptr, uri_len);
312 let uri = match ::std::str::from_utf8(uri_slice) {
313 Ok(s) => s,
314 Err(_) => return $crate::utils::return_error(
315 "Invalid URI encoding",
316 result_buf,
317 result_len
318 ),
319 };
320
321 let resources = get_resources();
322 if let Some(resource) = resources.get(uri) {
323 return match (resource.handler)(uri) {
324 Ok(contents) => {
325 let response = $crate::utils::resource_read_response(&contents);
326 $crate::utils::return_success(response, result_buf, result_len)
327 }
328 Err(e) => $crate::utils::return_error(&e, result_buf, result_len),
329 };
330 }
331
332 for matcher in get_template_matchers() {
333 if let Some(vars) = matcher.match_uri(uri) {
334 return match (matcher.template.handler)(uri, &vars) {
335 Ok(contents) => {
336 let response = $crate::utils::resource_read_response(&contents);
337 $crate::utils::return_success(response, result_buf, result_len)
338 }
339 Err(e) => $crate::utils::return_error(&e, result_buf, result_len),
340 };
341 }
342 }
343
344 if let Some(fallback) = read_fallback_handler() {
345 return match fallback(uri) {
346 Ok(contents) => {
347 let response = $crate::utils::resource_read_response(&contents);
348 $crate::utils::return_success(response, result_buf, result_len)
349 }
350 Err(e) => $crate::utils::return_error(&e, result_buf, result_len),
351 };
352 }
353
354 $crate::utils::return_error(
355 &format!("Unknown resource: {}", uri),
356 result_buf,
357 result_len
358 )
359 }
360 };
361}