pub trait BaseScanner<App: Send + Sync = ()> {
// Required methods
fn scan<'life0, 'life1, 'async_trait>(
&'life0 self,
app: &'life1 App,
) -> Pin<Box<dyn Future<Output = Vec<ScannedModule>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait;
fn source_name(&self) -> &str;
}Expand description
Abstract interface for framework scanners.
Implementors provide scan() for framework-specific endpoint scanning
and source_name() for identification. The App type parameter allows
each framework adapter to accept its own application type.
§Language-specific API shape
The Rust BaseScanner trait intentionally contains only the primitive scan() and
source_name() operations, keeping it object-safe (usable as Box<dyn BaseScanner>).
Helper utilities — filter_modules, deduplicate_ids, infer_annotations_from_method —
are free functions in the scanner module rather than trait default methods.
This differs from Python and TypeScript where these are instance methods on the class.
Usage:
let filtered = scanner::filter_modules(&modules, Some("my.*"), None)?;
let deduplicated = scanner::deduplicate_ids(filtered);§Note: ConventionScanner
ConventionScanner (available in Python as apcore_toolkit.ConventionScanner) is
Python-only. It relies on Python’s importlib module introspection for plain-function
discovery, which has no equivalent in Rust. Rust consumers should use BaseScanner
implementations that work with Rust’s type system directly.
// Example: Axum adapter
struct AxumScanner;
#[async_trait]
impl BaseScanner<axum::Router> for AxumScanner {
async fn scan(&self, app: &axum::Router) -> Vec<ScannedModule> { /* ... */ }
fn source_name(&self) -> &str { "axum" }
}
// Example: Actix adapter
struct ActixScanner;
#[async_trait]
impl BaseScanner<()> for ActixScanner {
async fn scan(&self, _app: &()) -> Vec<ScannedModule> { /* ... */ }
fn source_name(&self) -> &str { "actix-web" }
}Required Methods§
Sourcefn scan<'life0, 'life1, 'async_trait>(
&'life0 self,
app: &'life1 App,
) -> Pin<Box<dyn Future<Output = Vec<ScannedModule>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn scan<'life0, 'life1, 'async_trait>(
&'life0 self,
app: &'life1 App,
) -> Pin<Box<dyn Future<Output = Vec<ScannedModule>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Scan endpoints and return module definitions.
The app parameter receives framework-specific state (e.g., axum::Router,
actix_web::App). Use () if no app context is needed.
Sourcefn source_name(&self) -> &str
fn source_name(&self) -> &str
Return human-readable scanner name (e.g., “axum”, “actix-web”).
Dyn Compatibility§
This trait is dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".