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
//! Auto-route registration using linkme distributed slices
//!
//! **Implementation detail**: This module provides the current backend for
//! automatic, zero-boilerplate route collection using the `linkme` crate's
//! distributed slice mechanism.
//!
//! This is an internal implementation detail of `RustApi::auto()`.
//! The public contract is only:
//! - Handlers annotated with the route macros are discovered automatically.
//! - `collect_auto_routes()` and `auto_route_count()` for introspection.
//!
//! We may change the underlying mechanism in the future (while keeping the
//! observable behavior stable).
//!
//! This module enables **zero-config route registration**. Routes decorated with
//! `#[rustapi_rs::get]`, `#[rustapi_rs::post]`, etc. are automatically collected at
//! **link time** using the [`linkme`](https://docs.rs/linkme) crate.
//!
//! `RustApi::auto()` (and `RustApi::config()`) rely on this mechanism.
//!
//! # How It Works
//!
//! The attribute macros emit a small static initializer that appends a factory
//! function into a `linkme::distributed_slice`. At runtime we simply iterate the
//! slice and build the router.
//!
//! After collection we sort routes into a `BTreeMap` so registration order is
//! deterministic regardless of link order.
//!
//! # Public API
//!
//! - [`collect_auto_routes`] – returns all discovered routes as `Vec<Route>`
//! - [`auto_route_count`] – cheap way to check how many handlers were linked in
//!
//! # Example
//!
//! ```rust,ignore
//! use rustapi_rs::prelude::*;
//!
//! #[rustapi_rs::get("/users")]
//! async fn list_users() -> Json<Vec<User>> {
//! Json(vec![])
//! }
//!
//! #[rustapi_rs::post("/users")]
//! async fn create_user(Json(body): Json<CreateUser>) -> Created<User> {
//! // ...
//! }
//!
//! #[rustapi_rs::main]
//! async fn main() -> Result<()> {
//! // No manual .route() calls needed!
//! RustApi::auto()
//! .run("0.0.0.0:8080")
//! .await
//! }
//! ```
//!
//! # Limitations & Known Gotchas
//!
//! Link-time registration is powerful but comes with trade-offs:
//!
//! - **Tests can be flaky** — the test binary sometimes links differently than the
//! main binary. You may see `auto_route_count() == 0` inside `#[test]` even if
//! your annotated functions exist. Use `collect_auto_routes()` + filtering or
//! fall back to manual `.route()` in tests when necessary.
//!
//! - **Non-executable artifacts** (cdylib, rlib, staticlib, wasm32, etc.) often do
//! **not** populate distributed slices reliably because the linker may discard
//! the registration code.
//!
//! - **Multiple separate binaries** in the same workspace each get their own
//! independent slice. Routes defined in one binary are invisible to another.
//!
//! - There is **no runtime unregistration**. Once linked, the routes are there for
//! the lifetime of the process.
//!
//! - If you see zero routes at runtime with `RustApi::auto()`, the most common
//! causes are:
//! 1. No handlers were annotated with the route attributes.
//! 2. The module containing the handler was not linked into this binary.
//! 3. You are inside a test, library, or cdylib target.
//!
//! A clear warning is now emitted automatically when `RustApi::auto()` collects
//! zero routes (see `mount_auto_routes_grouped`).
//!
//! You can always inspect the situation with:
//!
//! ```rust,ignore
//! println!("Auto routes discovered: {}", rustapi_rs::auto_route_count());
//! ```
//!
//! # Manual Registration (always available)
//!
//! If auto-registration causes problems in your environment, you can ignore the
//! attribute macros entirely and use the classic builder:
//!
//! ```rust,ignore
//! RustApi::new()
//! .route("/users", get(list_users).post(create_user))
//! .run("0.0.0.0:8080")
//! .await
//! ```
//!
//! Both styles can be mixed freely.
use crateRoute;
use distributed_slice;
/// Distributed slice containing all auto-registered route factory functions.
///
/// Each element is a function that returns a [`Route`] when called.
/// The macro `#[rustapi::get]`, `#[rustapi::post]`, etc. automatically
/// add entries to this slice at compile/link time.
pub static AUTO_ROUTES: ;
/// Collect all auto-registered routes.
///
/// This function iterates over the distributed slice and calls each
/// route factory function to produce the actual [`Route`] instances.
///
/// # Returns
///
/// A vector containing all routes that were registered using the
/// `#[rustapi::get]`, `#[rustapi::post]`, etc. macros.
///
/// # Example
///
/// ```rust,ignore
/// let routes = collect_auto_routes();
/// println!("Found {} auto-registered routes", routes.len());
/// ```
/// Get the count of auto-registered routes without collecting them.
///
/// This is useful for:
/// - Debugging (e.g. in tests or startup logs)
/// - Asserting that your annotated handlers were actually linked in
///
/// # Example
///
/// ```rust,ignore
/// let count = rustapi_core::auto_route_count();
/// if count == 0 {
/// eprintln!("Warning: No auto-routes were discovered!");
/// }
/// ```