1#![allow(dead_code)]
7
8use crate::binding_generator::{FunctionSignature, TargetLanguage};
9use crate::error::FfiResult;
10use std::collections::HashMap;
11use std::fmt::Write;
12
13#[derive(Debug, Clone, PartialEq, Eq)]
15pub enum DocFormat {
16 Markdown,
17 Html,
18 RestructuredText,
19 ApiDoc,
20 Javadoc,
21 Sphinx,
22 GoDoc,
23 SwiftDoc,
24 RDoc,
25 JuliaDoc,
26}
27
28impl DocFormat {
29 pub fn file_extension(&self) -> &'static str {
30 match self {
31 DocFormat::Markdown => "md",
32 DocFormat::Html => "html",
33 DocFormat::RestructuredText => "rst",
34 DocFormat::ApiDoc => "txt",
35 DocFormat::Javadoc => "html",
36 DocFormat::Sphinx => "rst",
37 DocFormat::GoDoc => "md",
38 DocFormat::SwiftDoc => "md",
39 DocFormat::RDoc => "Rd",
40 DocFormat::JuliaDoc => "md",
41 }
42 }
43
44 pub fn for_language(lang: &TargetLanguage) -> Self {
45 match lang {
46 TargetLanguage::Java => DocFormat::Javadoc,
47 TargetLanguage::Python => DocFormat::Sphinx,
48 TargetLanguage::Go => DocFormat::GoDoc,
49 TargetLanguage::Swift => DocFormat::SwiftDoc,
50 TargetLanguage::R => DocFormat::RDoc,
51 TargetLanguage::Julia => DocFormat::JuliaDoc,
52 _ => DocFormat::Markdown,
53 }
54 }
55}
56
57#[derive(Debug, Clone, PartialEq, Eq, Hash)]
59pub enum FunctionCategory {
60 TensorCreation,
61 TensorOperations,
62 TensorManipulation,
63 NeuralNetworks,
64 Optimization,
65 Utilities,
66 MemoryManagement,
67 ErrorHandling,
68 Performance,
69}
70
71impl FunctionCategory {
72 pub fn description(&self) -> &'static str {
73 match self {
74 FunctionCategory::TensorCreation => "Functions for creating new tensors",
75 FunctionCategory::TensorOperations => "Mathematical operations on tensors",
76 FunctionCategory::TensorManipulation => {
77 "Functions for reshaping, indexing, and manipulating tensors"
78 }
79 FunctionCategory::NeuralNetworks => "Neural network layers and modules",
80 FunctionCategory::Optimization => "Optimizers and training utilities",
81 FunctionCategory::Utilities => "Utility and helper functions",
82 FunctionCategory::MemoryManagement => "Memory allocation and cleanup functions",
83 FunctionCategory::ErrorHandling => "Error management and diagnostics",
84 FunctionCategory::Performance => "Performance optimization and profiling",
85 }
86 }
87
88 pub fn from_function_name(name: &str) -> Self {
89 if name.contains("tensor_zeros")
90 || name.contains("tensor_ones")
91 || name.contains("tensor_rand")
92 || name.contains("tensor_new")
93 {
94 FunctionCategory::TensorCreation
95 } else if name.contains("tensor_add")
96 || name.contains("tensor_mul")
97 || name.contains("tensor_matmul")
98 || name.contains("tensor_sub")
99 {
100 FunctionCategory::TensorOperations
101 } else if name.contains("tensor_reshape")
102 || name.contains("tensor_transpose")
103 || name.contains("tensor_view")
104 {
105 FunctionCategory::TensorManipulation
106 } else if name.contains("linear")
107 || name.contains("conv")
108 || name.contains("relu")
109 || name.contains("module")
110 {
111 FunctionCategory::NeuralNetworks
112 } else if name.contains("sgd") || name.contains("adam") || name.contains("optimizer") {
113 FunctionCategory::Optimization
114 } else if name.contains("free") || name.contains("cleanup") {
115 FunctionCategory::MemoryManagement
116 } else if name.contains("error") || name.contains("clear") {
117 FunctionCategory::ErrorHandling
118 } else if name.contains("batch") || name.contains("performance") || name.contains("stats") {
119 FunctionCategory::Performance
120 } else {
121 FunctionCategory::Utilities
122 }
123 }
124}
125
126#[derive(Debug, Clone)]
128pub struct ApiDocEntry {
129 pub function: FunctionSignature,
130 pub category: FunctionCategory,
131 pub examples: Vec<String>,
132 pub notes: Vec<String>,
133 pub see_also: Vec<String>,
134 pub since_version: Option<String>,
135}
136
137impl ApiDocEntry {
138 pub fn new(function: FunctionSignature) -> Self {
139 let category = FunctionCategory::from_function_name(&function.name);
140 Self {
141 function,
142 category,
143 examples: Vec::new(),
144 notes: Vec::new(),
145 see_also: Vec::new(),
146 since_version: None,
147 }
148 }
149
150 pub fn with_example(mut self, example: String) -> Self {
151 self.examples.push(example);
152 self
153 }
154
155 pub fn with_note(mut self, note: String) -> Self {
156 self.notes.push(note);
157 self
158 }
159
160 pub fn with_see_also(mut self, reference: String) -> Self {
161 self.see_also.push(reference);
162 self
163 }
164
165 pub fn with_version(mut self, version: String) -> Self {
166 self.since_version = Some(version);
167 self
168 }
169}
170
171pub struct ApiDocGenerator {
173 target_language: TargetLanguage,
174 format: DocFormat,
175 entries: Vec<ApiDocEntry>,
176 metadata: HashMap<String, String>,
177}
178
179impl ApiDocGenerator {
180 pub fn new(target_language: TargetLanguage) -> Self {
181 let format = DocFormat::for_language(&target_language);
182 Self {
183 target_language,
184 format,
185 entries: Vec::new(),
186 metadata: HashMap::new(),
187 }
188 }
189
190 pub fn with_format(mut self, format: DocFormat) -> Self {
191 self.format = format;
192 self
193 }
194
195 pub fn add_entry(&mut self, entry: ApiDocEntry) {
196 self.entries.push(entry);
197 }
198
199 pub fn add_metadata(&mut self, key: String, value: String) {
200 self.metadata.insert(key, value);
201 }
202
203 pub fn load_standard_functions(&mut self) {
204 let tensor_zeros = FunctionSignature {
206 name: "torsh_tensor_zeros".to_string(),
207 return_type: "*mut TorshTensor".to_string(),
208 parameters: vec![
209 ("shape".to_string(), "*const c_int".to_string()),
210 ("shape_len".to_string(), "c_int".to_string()),
211 ],
212 description: "Create a tensor filled with zeros".to_string(),
213 is_unsafe: true,
214 };
215
216 let entry = ApiDocEntry::new(tensor_zeros)
217 .with_example(self.generate_example_for_function("torsh_tensor_zeros"))
218 .with_note("The shape array must contain positive integers".to_string())
219 .with_see_also("torsh_tensor_ones".to_string())
220 .with_version("0.1.0".to_string());
221 self.add_entry(entry);
222
223 let tensor_add = FunctionSignature {
224 name: "torsh_tensor_add".to_string(),
225 return_type: "*mut TorshTensor".to_string(),
226 parameters: vec![
227 ("a".to_string(), "*mut TorshTensor".to_string()),
228 ("b".to_string(), "*mut TorshTensor".to_string()),
229 ],
230 description: "Add two tensors element-wise".to_string(),
231 is_unsafe: true,
232 };
233
234 let entry = ApiDocEntry::new(tensor_add)
235 .with_example(self.generate_example_for_function("torsh_tensor_add"))
236 .with_note("Both tensors must have compatible shapes for broadcasting".to_string())
237 .with_see_also("torsh_tensor_sub".to_string())
238 .with_see_also("torsh_tensor_mul".to_string())
239 .with_version("0.1.0".to_string());
240 self.add_entry(entry);
241
242 let linear_create = FunctionSignature {
243 name: "torsh_linear_create".to_string(),
244 return_type: "*mut TorshModule".to_string(),
245 parameters: vec![
246 ("in_features".to_string(), "c_int".to_string()),
247 ("out_features".to_string(), "c_int".to_string()),
248 ("bias".to_string(), "bool".to_string()),
249 ],
250 description: "Create a linear (fully connected) layer".to_string(),
251 is_unsafe: true,
252 };
253
254 let entry = ApiDocEntry::new(linear_create)
255 .with_example(self.generate_example_for_function("torsh_linear_create"))
256 .with_note("The layer weights are initialized randomly".to_string())
257 .with_see_also("torsh_linear_forward".to_string())
258 .with_version("0.1.0".to_string());
259 self.add_entry(entry);
260
261 self.add_optimizer_functions();
263 self.add_utility_functions();
264 }
265
266 fn add_optimizer_functions(&mut self) {
267 let sgd_create = FunctionSignature {
268 name: "torsh_sgd_create".to_string(),
269 return_type: "*mut TorshOptimizer".to_string(),
270 parameters: vec![("learning_rate".to_string(), "c_float".to_string())],
271 description: "Create a Stochastic Gradient Descent optimizer".to_string(),
272 is_unsafe: true,
273 };
274
275 let entry = ApiDocEntry::new(sgd_create)
276 .with_example(self.generate_example_for_function("torsh_sgd_create"))
277 .with_note(
278 "Learning rate should be positive and typically between 0.001 and 0.1".to_string(),
279 )
280 .with_see_also("torsh_adam_create".to_string())
281 .with_version("0.1.0".to_string());
282 self.add_entry(entry);
283 }
284
285 fn add_utility_functions(&mut self) {
286 let get_error = FunctionSignature {
287 name: "torsh_get_last_error".to_string(),
288 return_type: "c_int".to_string(),
289 parameters: vec![
290 ("buffer".to_string(), "*mut c_char".to_string()),
291 ("buffer_size".to_string(), "c_int".to_string()),
292 ],
293 description: "Get the last error message".to_string(),
294 is_unsafe: true,
295 };
296
297 let entry = ApiDocEntry::new(get_error)
298 .with_example(self.generate_example_for_function("torsh_get_last_error"))
299 .with_note("Buffer should be large enough to hold the error message".to_string())
300 .with_see_also("torsh_clear_last_error".to_string())
301 .with_version("0.1.0".to_string());
302 self.add_entry(entry);
303 }
304
305 fn generate_example_for_function(&self, function_name: &str) -> String {
306 match self.target_language {
307 TargetLanguage::Python => self.generate_python_example(function_name),
308 TargetLanguage::Java => self.generate_java_example(function_name),
309 TargetLanguage::Go => self.generate_go_example(function_name),
310 TargetLanguage::CSharp => self.generate_csharp_example(function_name),
311 TargetLanguage::Swift => self.generate_swift_example(function_name),
312 TargetLanguage::R => self.generate_r_example(function_name),
313 TargetLanguage::Julia => self.generate_julia_example(function_name),
314 _ => self.generate_c_example(function_name),
315 }
316 }
317
318 fn generate_python_example(&self, function_name: &str) -> String {
319 match function_name {
320 "torsh_tensor_zeros" => r#"```python
321import torsh_ffi as torsh
322
323# Create a 2x3 tensor filled with zeros
324shape = [2, 3]
325tensor = torsh.tensor_zeros(shape)
326print(f"Created tensor with shape: {tensor.shape()}")
327```"#
328 .to_string(),
329 "torsh_tensor_add" => r#"```python
330import torsh_ffi as torsh
331
332# Create two tensors and add them
333a = torsh.tensor_ones([2, 3])
334b = torsh.tensor_ones([2, 3])
335result = torsh.tensor_add(a, b)
336print("Added two tensors successfully")
337```"#
338 .to_string(),
339 "torsh_linear_create" => r#"```python
340import torsh_ffi as torsh
341
342# Create a linear layer with 10 input features and 5 output features
343layer = torsh.linear_create(in_features=10, out_features=5, bias=True)
344print("Created linear layer")
345```"#
346 .to_string(),
347 _ => "```python\n# Example not available\n```".to_string(),
348 }
349 }
350
351 fn generate_java_example(&self, function_name: &str) -> String {
352 match function_name {
353 "torsh_tensor_zeros" => r#"```java
354import com.torsh.ffi.TorshBindings;
355
356// Create a 2x3 tensor filled with zeros
357int[] shape = {2, 3};
358TensorHandle tensor = TorshBindings.tensorZeros(shape);
359System.out.println("Created tensor with zeros");
360```"#
361 .to_string(),
362 "torsh_tensor_add" => r#"```java
363import com.torsh.ffi.TorshBindings;
364
365// Create two tensors and add them
366int[] shape = {2, 3};
367TensorHandle a = TorshBindings.tensorOnes(shape);
368TensorHandle b = TorshBindings.tensorOnes(shape);
369TensorHandle result = TorshBindings.tensorAdd(a, b);
370System.out.println("Added two tensors successfully");
371```"#
372 .to_string(),
373 _ => "```java\n// Example not available\n```".to_string(),
374 }
375 }
376
377 fn generate_go_example(&self, function_name: &str) -> String {
378 match function_name {
379 "torsh_tensor_zeros" => r#"```go
380package main
381
382import (
383 "fmt"
384 "github.com/torsh/go-bindings/torsh"
385)
386
387func main() {
388 // Create a 2x3 tensor filled with zeros
389 shape := []int32{2, 3}
390 tensor := torsh.TensorZeros(shape)
391 fmt.Println("Created tensor with zeros")
392}
393```"#
394 .to_string(),
395 _ => "```go\n// Example not available\n```".to_string(),
396 }
397 }
398
399 fn generate_csharp_example(&self, function_name: &str) -> String {
400 match function_name {
401 "torsh_tensor_zeros" => r#"```csharp
402using TorshBindings;
403
404// Create a 2x3 tensor filled with zeros
405int[] shape = {2, 3};
406IntPtr tensor = TorshAPI.TensorZeros(shape, shape.Length);
407Console.WriteLine("Created tensor with zeros");
408```"#
409 .to_string(),
410 _ => "```csharp\n// Example not available\n```".to_string(),
411 }
412 }
413
414 fn generate_swift_example(&self, function_name: &str) -> String {
415 match function_name {
416 "torsh_tensor_zeros" => r#"```swift
417import TorshBindings
418
419// Create a 2x3 tensor filled with zeros
420let shape: [Int32] = [2, 3]
421let tensor = tensorZeros(shape: shape)
422print("Created tensor with zeros")
423```"#
424 .to_string(),
425 _ => "```swift\n// Example not available\n```".to_string(),
426 }
427 }
428
429 fn generate_r_example(&self, function_name: &str) -> String {
430 match function_name {
431 "torsh_tensor_zeros" => r#"```r
432library(torsh)
433
434# Create a 2x3 tensor filled with zeros
435shape <- c(2L, 3L)
436tensor <- r_tensor_zeros(shape)
437cat("Created tensor with zeros\n")
438```"#
439 .to_string(),
440 _ => "```r\n# Example not available\n```".to_string(),
441 }
442 }
443
444 fn generate_julia_example(&self, function_name: &str) -> String {
445 match function_name {
446 "torsh_tensor_zeros" => r#"```julia
447using TorshBindings
448
449# Create a 2x3 tensor filled with zeros
450shape = Int32[2, 3]
451tensor = jl_tensor_zeros(shape)
452println("Created tensor with zeros")
453```"#
454 .to_string(),
455 _ => "```julia\n# Example not available\n```".to_string(),
456 }
457 }
458
459 fn generate_c_example(&self, function_name: &str) -> String {
460 match function_name {
461 "torsh_tensor_zeros" => r#"```c
462#include "torsh_ffi.h"
463
464// Create a 2x3 tensor filled with zeros
465int shape[] = {2, 3};
466TorshTensor* tensor = torsh_tensor_zeros(shape, 2);
467printf("Created tensor with zeros\n");
468```"#
469 .to_string(),
470 _ => "```c\n// Example not available\n```".to_string(),
471 }
472 }
473
474 pub fn generate_documentation(&self) -> FfiResult<String> {
475 match self.format {
476 DocFormat::Markdown => self.generate_markdown(),
477 DocFormat::Html => self.generate_html(),
478 DocFormat::RestructuredText => self.generate_rst(),
479 DocFormat::Sphinx => self.generate_sphinx(),
480 DocFormat::Javadoc => self.generate_javadoc(),
481 _ => self.generate_markdown(), }
483 }
484
485 fn generate_markdown(&self) -> FfiResult<String> {
486 let mut output = String::new();
487
488 writeln!(
490 output,
491 "# ToRSh {} API Documentation",
492 format!("{:?}", self.target_language)
493 )?;
494 writeln!(output)?;
495
496 if let Some(version) = self.metadata.get("version") {
498 writeln!(output, "**Version:** {}", version)?;
499 }
500 if let Some(generated) = self.metadata.get("generated_at") {
501 writeln!(output, "**Generated:** {}", generated)?;
502 }
503 writeln!(output)?;
504
505 writeln!(output, "## Table of Contents")?;
507 writeln!(output)?;
508
509 let mut categories: HashMap<FunctionCategory, Vec<&ApiDocEntry>> = HashMap::new();
510 for entry in &self.entries {
511 categories
512 .entry(entry.category.clone())
513 .or_default()
514 .push(entry);
515 }
516
517 for (category, _) in &categories {
518 writeln!(
519 output,
520 "- [{}](#{:?})",
521 category.description(),
522 format!("{:?}", category).to_lowercase().replace(' ', "-")
523 )?;
524 }
525 writeln!(output)?;
526
527 for (category, entries) in categories {
529 writeln!(output, "## {}", category.description())?;
530 writeln!(output)?;
531
532 for entry in entries {
533 self.write_function_markdown(&mut output, entry)?;
534 }
535 }
536
537 Ok(output)
538 }
539
540 fn write_function_markdown(&self, output: &mut String, entry: &ApiDocEntry) -> FfiResult<()> {
541 let func = &entry.function;
542
543 writeln!(output, "### `{}`", func.name)?;
545 writeln!(output)?;
546 writeln!(output, "{}", func.description)?;
547 writeln!(output)?;
548
549 if !func.parameters.is_empty() {
551 writeln!(output, "**Parameters:**")?;
552 writeln!(output)?;
553 for (name, param_type) in &func.parameters {
554 writeln!(
555 output,
556 "- `{}`: {} - Parameter description",
557 name, param_type
558 )?;
559 }
560 writeln!(output)?;
561 }
562
563 writeln!(output, "**Returns:** `{}`", func.return_type)?;
565 writeln!(output)?;
566
567 if !entry.examples.is_empty() {
569 writeln!(output, "**Example:**")?;
570 writeln!(output)?;
571 for example in &entry.examples {
572 writeln!(output, "{}", example)?;
573 writeln!(output)?;
574 }
575 }
576
577 if !entry.notes.is_empty() {
579 writeln!(output, "**Notes:**")?;
580 writeln!(output)?;
581 for note in &entry.notes {
582 writeln!(output, "- {}", note)?;
583 }
584 writeln!(output)?;
585 }
586
587 if !entry.see_also.is_empty() {
589 writeln!(output, "**See also:** {}", entry.see_also.join(", "))?;
590 writeln!(output)?;
591 }
592
593 if let Some(version) = &entry.since_version {
595 writeln!(output, "**Since version:** {}", version)?;
596 writeln!(output)?;
597 }
598
599 writeln!(output, "---")?;
600 writeln!(output)?;
601
602 Ok(())
603 }
604
605 fn generate_html(&self) -> FfiResult<String> {
606 let mut output = String::new();
607
608 writeln!(output, "<!DOCTYPE html>")?;
609 writeln!(output, "<html>")?;
610 writeln!(output, "<head>")?;
611 writeln!(
612 output,
613 " <title>ToRSh {} API Documentation</title>",
614 format!("{:?}", self.target_language)
615 )?;
616 writeln!(output, " <style>")?;
617 writeln!(
618 output,
619 " body {{ font-family: Arial, sans-serif; margin: 40px; }}"
620 )?;
621 writeln!(
622 output,
623 " .function {{ margin: 20px 0; padding: 15px; border: 1px solid #ddd; }}"
624 )?;
625 writeln!(
626 output,
627 " .signature {{ font-family: monospace; background: #f5f5f5; padding: 10px; }}"
628 )?;
629 writeln!(
630 output,
631 " .example {{ background: #f9f9f9; padding: 10px; margin: 10px 0; }}"
632 )?;
633 writeln!(output, " </style>")?;
634 writeln!(output, "</head>")?;
635 writeln!(output, "<body>")?;
636
637 writeln!(
638 output,
639 "<h1>ToRSh {} API Documentation</h1>",
640 format!("{:?}", self.target_language)
641 )?;
642
643 let mut categories: HashMap<FunctionCategory, Vec<&ApiDocEntry>> = HashMap::new();
645 for entry in &self.entries {
646 categories
647 .entry(entry.category.clone())
648 .or_default()
649 .push(entry);
650 }
651
652 for (category, entries) in categories {
653 writeln!(output, "<h2>{}</h2>", category.description())?;
654
655 for entry in entries {
656 writeln!(output, "<div class=\"function\">")?;
657 writeln!(output, "<h3>{}</h3>", entry.function.name)?;
658 writeln!(output, "<p>{}</p>", entry.function.description)?;
659
660 if !entry.examples.is_empty() {
661 writeln!(output, "<div class=\"example\">")?;
662 writeln!(output, "<h4>Example:</h4>")?;
663 for example in &entry.examples {
664 writeln!(output, "<pre>{}</pre>", example)?;
665 }
666 writeln!(output, "</div>")?;
667 }
668
669 writeln!(output, "</div>")?;
670 }
671 }
672
673 writeln!(output, "</body>")?;
674 writeln!(output, "</html>")?;
675
676 Ok(output)
677 }
678
679 fn generate_rst(&self) -> FfiResult<String> {
680 let mut output = String::new();
681
682 writeln!(
683 output,
684 "ToRSh {} API Documentation",
685 format!("{:?}", self.target_language)
686 )?;
687 writeln!(output, "{}", "=".repeat(50))?;
688 writeln!(output)?;
689
690 let mut categories: HashMap<FunctionCategory, Vec<&ApiDocEntry>> = HashMap::new();
692 for entry in &self.entries {
693 categories
694 .entry(entry.category.clone())
695 .or_default()
696 .push(entry);
697 }
698
699 for (category, entries) in categories {
700 writeln!(output, "{}", category.description())?;
701 writeln!(output, "{}", "-".repeat(category.description().len()))?;
702 writeln!(output)?;
703
704 for entry in entries {
705 writeln!(output, "{}", entry.function.name)?;
706 writeln!(output, "{}", "~".repeat(entry.function.name.len()))?;
707 writeln!(output)?;
708 writeln!(output, "{}", entry.function.description)?;
709 writeln!(output)?;
710
711 if !entry.examples.is_empty() {
712 writeln!(output, ".. code-block::")?;
713 writeln!(output)?;
714 for example in &entry.examples {
715 for line in example.lines() {
716 writeln!(output, " {}", line)?;
717 }
718 }
719 writeln!(output)?;
720 }
721 }
722 }
723
724 Ok(output)
725 }
726
727 fn generate_sphinx(&self) -> FfiResult<String> {
728 self.generate_rst()
730 }
731
732 fn generate_javadoc(&self) -> FfiResult<String> {
733 let mut output = String::new();
734
735 writeln!(output, "/**")?;
736 writeln!(output, " * ToRSh Java API Documentation")?;
737 writeln!(
738 output,
739 " * Auto-generated documentation for ToRSh Java bindings"
740 )?;
741 writeln!(output, " */")?;
742
743 for entry in &self.entries {
745 writeln!(output, "/**")?;
746 writeln!(output, " * {}", entry.function.description)?;
747 writeln!(output, " *")?;
748
749 for (name, _) in &entry.function.parameters {
750 writeln!(output, " * @param {} parameter description", name)?;
751 }
752
753 writeln!(output, " * @return {}", entry.function.return_type)?;
754
755 if let Some(version) = &entry.since_version {
756 writeln!(output, " * @since {}", version)?;
757 }
758
759 writeln!(output, " */")?;
760 writeln!(output)?;
761 }
762
763 Ok(output)
764 }
765}
766
767pub fn generate_api_docs(target_language: TargetLanguage, format: DocFormat) -> FfiResult<String> {
769 let mut generator = ApiDocGenerator::new(target_language).with_format(format);
770
771 generator.add_metadata("version".to_string(), "0.1.0-alpha.2".to_string());
773 generator.add_metadata("generated_at".to_string(), chrono::Utc::now().to_rfc3339());
774
775 generator.load_standard_functions();
777
778 generator.generate_documentation()
779}
780
781pub fn generate_all_api_docs() -> FfiResult<HashMap<TargetLanguage, String>> {
783 let languages = vec![
784 TargetLanguage::Python,
785 TargetLanguage::Java,
786 TargetLanguage::Go,
787 TargetLanguage::CSharp,
788 TargetLanguage::Swift,
789 TargetLanguage::R,
790 TargetLanguage::Julia,
791 ];
792
793 let mut results = HashMap::new();
794
795 for lang in languages {
796 let docs = generate_api_docs(lang.clone(), DocFormat::for_language(&lang))?;
797 results.insert(lang, docs);
798 }
799
800 Ok(results)
801}
802
803#[cfg(test)]
804mod tests {
805 use super::*;
806
807 #[test]
808 fn test_doc_format_for_language() {
809 assert_eq!(
810 DocFormat::for_language(&TargetLanguage::Java),
811 DocFormat::Javadoc
812 );
813 assert_eq!(
814 DocFormat::for_language(&TargetLanguage::Python),
815 DocFormat::Sphinx
816 );
817 assert_eq!(
818 DocFormat::for_language(&TargetLanguage::Go),
819 DocFormat::GoDoc
820 );
821 }
822
823 #[test]
824 fn test_function_category_from_name() {
825 assert_eq!(
826 FunctionCategory::from_function_name("torsh_tensor_zeros"),
827 FunctionCategory::TensorCreation
828 );
829 assert_eq!(
830 FunctionCategory::from_function_name("torsh_tensor_add"),
831 FunctionCategory::TensorOperations
832 );
833 assert_eq!(
834 FunctionCategory::from_function_name("torsh_linear_create"),
835 FunctionCategory::NeuralNetworks
836 );
837 assert_eq!(
838 FunctionCategory::from_function_name("torsh_sgd_create"),
839 FunctionCategory::Optimization
840 );
841 }
842
843 #[test]
844 fn test_api_doc_entry_creation() {
845 let func = FunctionSignature {
846 name: "test_function".to_string(),
847 return_type: "void".to_string(),
848 parameters: vec![],
849 description: "Test function".to_string(),
850 is_unsafe: false,
851 };
852
853 let entry = ApiDocEntry::new(func)
854 .with_example("Example code".to_string())
855 .with_note("Important note".to_string())
856 .with_version("1.0.0".to_string());
857
858 assert_eq!(entry.examples.len(), 1);
859 assert_eq!(entry.notes.len(), 1);
860 assert_eq!(entry.since_version, Some("1.0.0".to_string()));
861 }
862
863 #[test]
864 fn test_doc_generator_creation() {
865 let generator = ApiDocGenerator::new(TargetLanguage::Python);
866 assert_eq!(generator.target_language, TargetLanguage::Python);
867 assert_eq!(generator.format, DocFormat::Sphinx);
868 }
869
870 #[test]
871 fn test_markdown_generation() {
872 let mut generator =
873 ApiDocGenerator::new(TargetLanguage::Python).with_format(DocFormat::Markdown);
874 generator.load_standard_functions();
875
876 let docs = generator.generate_documentation();
877 assert!(docs.is_ok());
878
879 let content = docs.unwrap();
880 assert!(content.contains("# ToRSh Python API Documentation"));
881 assert!(content.contains("## Table of Contents"));
882 }
883}