Skip to main content

sklears_core/
api_reference_generator.rs

1//! Rich API-reference types for the trait graph visualization subsystem.
2//!
3//! [`crate::api_data_structures`] defines a deliberately simple `TraitInfo`
4//! shape (`description`/`path`/`methods: Vec<MethodInfo>` as plain strings)
5//! that backs the modularized API reference generator
6//! (`api_analyzers`/`api_formatters`/`api_generator_config`/...).
7//!
8//! The trait graph visualization system
9//! (`crate::trait_explorer::graph_visualization`) needs a richer shape that
10//! carries structured documentation, visibility, source location, and
11//! feature-flag metadata for each trait, associated type, and method so that
12//! it can render meaningful graphs (node coloring by stability, tooltips with
13//! signatures, filtering by feature flag, etc.). This module provides that
14//! richer shape.
15//!
16//! The two `TraitInfo` shapes are intentionally independent types: this
17//! module does not modify or replace [`crate::api_data_structures::TraitInfo`],
18//! which remains in use by the already-enabled modularized API reference
19//! system.
20
21use crate::api_data_structures::ParameterInfo;
22
23/// Visibility levels for API items.
24///
25/// Re-exported from [`crate::api_data_structures`] so callers that only deal
26/// with the graph-visualization API surface can refer to
27/// `crate::api_reference_generator::Visibility` without an additional
28/// dependency on [`crate::api_data_structures`].
29pub use crate::api_data_structures::Visibility;
30
31/// Rich description of a Rust trait definition.
32///
33/// This is the shape consumed by
34/// [`crate::trait_explorer::graph_visualization::graph_generator::TraitGraphGenerator`]
35/// when building a [`crate::trait_explorer::graph_visualization::TraitGraph`]
36/// from source-level trait information.
37#[derive(Debug, Clone)]
38pub struct TraitInfo {
39    /// Name of the trait (e.g. `"Estimator"`).
40    pub name: String,
41    /// Rustdoc documentation attached to the trait, if any.
42    pub docs: Option<String>,
43    /// Module path the trait is declared in (e.g. `"sklears_core::traits"`).
44    pub module_path: Option<String>,
45    /// Visibility of the trait declaration.
46    pub visibility: Visibility,
47    /// Generic parameters declared on the trait, e.g. `["T: Clone + Send"]`.
48    pub generics: Vec<String>,
49    /// Names of the supertraits this trait requires.
50    pub supertraits: Vec<String>,
51    /// Associated types declared by the trait.
52    pub associated_types: Vec<AssociatedType>,
53    /// Methods declared by the trait (required and provided).
54    pub methods: Vec<MethodInfo>,
55    /// Source file the trait is declared in, if known.
56    pub source_file: Option<String>,
57    /// Line number of the trait declaration within `source_file`, if known.
58    pub source_line: Option<u32>,
59    /// Cargo feature flags that must be enabled for this trait to be
60    /// available (e.g. `["experimental"]`).
61    pub feature_flags: Vec<String>,
62}
63
64/// An associated type declared by a trait.
65#[derive(Debug, Clone)]
66pub struct AssociatedType {
67    /// Name of the associated type (e.g. `"Output"`).
68    pub name: String,
69    /// Trait bounds placed on the associated type (e.g. `["Clone", "Send"]`).
70    pub bounds: Vec<String>,
71    /// Default type, if the associated type declares one.
72    pub default: Option<String>,
73}
74
75/// A method declared by a trait.
76#[derive(Debug, Clone)]
77pub struct MethodInfo {
78    /// Name of the method.
79    pub name: String,
80    /// Full method signature as written in source, e.g.
81    /// `"fn fit(&mut self, x: &Array2<f64>) -> Result<()>"`.
82    pub signature: String,
83    /// Rustdoc documentation attached to the method, if any.
84    pub docs: Option<String>,
85    /// Whether the method has no default implementation (must be implemented
86    /// by every conforming type).
87    pub is_required: bool,
88    /// Whether the method is declared `async`.
89    pub is_async: bool,
90    /// Whether the method is declared `unsafe`.
91    pub is_unsafe: bool,
92    /// Generic parameters declared on the method itself (independent of the
93    /// trait's own generics).
94    pub generics: Vec<String>,
95    /// Return type of the method, if it returns something other than `()`.
96    pub return_type: Option<String>,
97    /// Parameters accepted by the method (excluding `self`).
98    pub arguments: Vec<ParameterInfo>,
99}
100
101#[allow(non_snake_case)]
102#[cfg(test)]
103mod tests {
104    use super::*;
105
106    fn sample_trait_info() -> TraitInfo {
107        TraitInfo {
108            name: "Estimator".to_string(),
109            docs: Some("Base trait for ML estimators.".to_string()),
110            module_path: Some("sklears_core::traits".to_string()),
111            visibility: Visibility::Public,
112            generics: vec!["T: Clone".to_string()],
113            supertraits: vec!["Send".to_string(), "Sync".to_string()],
114            associated_types: vec![AssociatedType {
115                name: "Config".to_string(),
116                bounds: vec!["Default".to_string()],
117                default: None,
118            }],
119            methods: vec![MethodInfo {
120                name: "fit".to_string(),
121                signature: "fn fit(&mut self, x: &Array2<f64>) -> Result<()>".to_string(),
122                docs: Some("Fit the estimator to training data.".to_string()),
123                is_required: true,
124                is_async: false,
125                is_unsafe: false,
126                generics: Vec::new(),
127                return_type: Some("Result<()>".to_string()),
128                arguments: vec![ParameterInfo {
129                    name: "x".to_string(),
130                    param_type: "&Array2<f64>".to_string(),
131                    description: "training features".to_string(),
132                    optional: false,
133                }],
134            }],
135            source_file: Some("src/traits.rs".to_string()),
136            source_line: Some(10),
137            feature_flags: Vec::new(),
138        }
139    }
140
141    #[test]
142    fn test_trait_info_construction() {
143        let trait_info = sample_trait_info();
144        assert_eq!(trait_info.name, "Estimator");
145        assert_eq!(trait_info.supertraits.len(), 2);
146        assert_eq!(trait_info.associated_types.len(), 1);
147        assert_eq!(trait_info.methods.len(), 1);
148        assert!(matches!(trait_info.visibility, Visibility::Public));
149    }
150
151    #[test]
152    fn test_associated_type_construction() {
153        let assoc = AssociatedType {
154            name: "Item".to_string(),
155            bounds: vec!["Clone".to_string(), "Debug".to_string()],
156            default: Some("()".to_string()),
157        };
158        assert_eq!(assoc.name, "Item");
159        assert_eq!(assoc.bounds.len(), 2);
160        assert_eq!(assoc.default.as_deref(), Some("()"));
161    }
162
163    #[test]
164    fn test_method_info_construction() {
165        let trait_info = sample_trait_info();
166        let method = &trait_info.methods[0];
167        assert_eq!(method.name, "fit");
168        assert!(method.is_required);
169        assert!(!method.is_async);
170        assert!(!method.is_unsafe);
171        assert_eq!(method.arguments.len(), 1);
172        assert_eq!(method.arguments[0].name, "x");
173    }
174
175    #[test]
176    fn test_trait_info_clone() {
177        let trait_info = sample_trait_info();
178        let cloned = trait_info.clone();
179        assert_eq!(trait_info.name, cloned.name);
180        assert_eq!(trait_info.methods.len(), cloned.methods.len());
181    }
182
183    #[test]
184    fn test_visibility_reexport_matches_api_data_structures() {
185        // The re-exported `Visibility` must be the exact same type as
186        // `crate::api_data_structures::Visibility`, not a copy.
187        let v: Visibility = crate::api_data_structures::Visibility::Private;
188        assert!(matches!(v, Visibility::Private));
189    }
190}