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