Skip to main content

reinhardt_core/
lib.rs

1#![warn(missing_docs)]
2//! # Reinhardt Core
3//!
4//! Core components for the Reinhardt framework, providing fundamental types,
5//! exception handling, signals, macros, security, and validation utilities.
6//!
7//! ## Available Validators
8//!
9//! The validators crate provides comprehensive validation utilities:
10//! - **IPAddressValidator**: IPv4/IPv6 address validation
11//! - **PhoneNumberValidator**: International phone number validation (E.164)
12//! - **CreditCardValidator**: Credit card validation with Luhn algorithm
13//! - **IBANValidator**: International bank account number validation
14//! - **ColorValidator**: Hex, RGB, HSL color validation
15//! - **FileTypeValidator**: MIME type and extension validation
16//! - **CustomRegexValidator**: User-defined regex pattern validation
17//!
18//! ## Related Backend Crates
19//!
20//! Backend integrations live in focused crates rather than in `reinhardt-core`.
21//! See `reinhardt-db`, `reinhardt-auth`, `reinhardt-mail`,
22//! `reinhardt-tasks`, and `reinhardt-utils` for database, auth, mail,
23//! queue, cache, and storage integrations.
24//!
25//! ## Quick Start
26//!
27//! ```rust
28//! use reinhardt_core::exception::{Error, ErrorKind};
29//!
30//! // Create a typed application error
31//! let err = Error::NotFound("Resource not found".to_string());
32//! assert_eq!(err.kind(), ErrorKind::NotFound);
33//! ```
34//!
35//! ## Architecture
36//!
37//! Key modules in this crate:
38//!
39//! - [`exception`]: Typed error hierarchy for HTTP and application-level errors
40//! - [`types`]: Fundamental types (URL, money, phone number, color, coordinates)
41//! - [`signals`]: Django-style signal/slot system for decoupled event handling
42//! - [`security`]: CSRF, XSS prevention, security headers, HSTS, IP filtering, redirect validation, and resource limits
43//! - [`validators`]: Comprehensive input validation (IP, IBAN, phone, credit card)
44//! - [`serializers`]: Data serialization and deserialization framework
45//! - `pagination`: Cursor, page number, and limit-offset pagination strategies
46//! - [`parsers`]: Request body parsing (JSON, form, multipart)
47//! - `negotiation`: HTTP content negotiation utilities
48//!
49//! ## Feature Flags
50//!
51//! | Feature | Default | Description |
52//! |---------|---------|-------------|
53//! | `types` | enabled | Core type definitions |
54//! | `exception` | enabled | Error hierarchy and HTTP status mapping |
55//! | `signals` | enabled | Async signal/slot system |
56//! | `macros` | enabled | Procedural macros re-export |
57//! | `security` | enabled | CSRF, XSS prevention, headers, HSTS, IP filtering, redirects, and resource limits |
58//! | `validators` | enabled | Comprehensive input validation |
59//! | `serializers` | enabled | Data serialization framework |
60//! | `parsers` | disabled | Request body parsers |
61//! | `pagination` | disabled | Pagination strategies |
62//! | `negotiation` | disabled | HTTP content negotiation |
63//! | `messages` | disabled | Flash message storage |
64//! | `page` | disabled | Server-side page rendering types |
65//! | `reactive` | disabled | Reactive state management |
66//! | `serde` | disabled | Serde serialization support |
67//! | `json` | disabled | JSON serialization support |
68//! | `xml` | disabled | XML serialization support |
69//! | `yaml` | disabled | YAML serialization support |
70//! | `parallel` | disabled | Parallel processing with Rayon |
71//! | `i18n` | disabled | Internationalization with Fluent |
72
73pub mod apply_update;
74pub use apply_update::ApplyUpdate;
75/// HTTP endpoint routing and handler registration.
76#[cfg(native)]
77pub mod endpoint;
78/// Error types and exception handling.
79#[cfg(feature = "exception")]
80pub mod exception;
81/// Flash message storage framework.
82#[cfg(feature = "messages")]
83pub mod messages;
84/// Target-neutral metadata traits emitted by model macros.
85pub mod model_info {
86	use std::marker::PhantomData;
87
88	/// Minimal model identity needed by generated `{Model}Info` companion types.
89	///
90	/// Unlike the ORM `Model` trait, this trait is available on WASM and only
91	/// exposes the primary-key type required for generated foreign-key `*_id`
92	/// fields.
93	pub trait InfoModel {
94		/// Primary-key type used by generated DTO companion fields.
95		type PrimaryKey;
96	}
97
98	/// Lightweight relationship reference used by generated `{Model}Info` fields (Issue #5272).
99	#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
100	#[cfg_attr(
101		feature = "serde",
102		serde(bound(
103			serialize = "T::PrimaryKey: serde::Serialize",
104			deserialize = "T::PrimaryKey: serde::Deserialize<'de>"
105		))
106	)]
107	pub struct RelationInfo<T: InfoModel> {
108		/// Primary key of the related model.
109		pub id: T::PrimaryKey,
110		#[cfg_attr(feature = "serde", serde(skip))]
111		_model: PhantomData<T>,
112	}
113
114	impl<T: InfoModel> RelationInfo<T> {
115		/// Creates a relationship reference from a related model primary key.
116		pub const fn new(id: T::PrimaryKey) -> Self {
117			Self {
118				id,
119				_model: PhantomData,
120			}
121		}
122
123		/// Returns the related model primary key.
124		pub const fn id(&self) -> &T::PrimaryKey {
125			&self.id
126		}
127
128		/// Converts this relationship reference into its primary key.
129		pub fn into_id(self) -> T::PrimaryKey {
130			self.id
131		}
132	}
133
134	impl<T> std::fmt::Debug for RelationInfo<T>
135	where
136		T: InfoModel,
137		T::PrimaryKey: std::fmt::Debug,
138	{
139		fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
140			f.debug_struct("RelationInfo")
141				.field("id", &self.id)
142				.finish()
143		}
144	}
145
146	impl<T> Clone for RelationInfo<T>
147	where
148		T: InfoModel,
149		T::PrimaryKey: Clone,
150	{
151		fn clone(&self) -> Self {
152			Self::new(self.id.clone())
153		}
154	}
155
156	impl<T> PartialEq for RelationInfo<T>
157	where
158		T: InfoModel,
159		T::PrimaryKey: PartialEq,
160	{
161		fn eq(&self, other: &Self) -> bool {
162			self.id == other.id
163		}
164	}
165
166	/// Lightweight many-to-many relationship payload for generated `{Model}Info` (Issue #5272).
167	#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
168	#[cfg_attr(
169		feature = "serde",
170		serde(bound(
171			serialize = "Target::PrimaryKey: serde::Serialize",
172			deserialize = "Target::PrimaryKey: serde::Deserialize<'de>"
173		))
174	)]
175	pub struct ManyToManyInfo<Source, Target: InfoModel> {
176		/// Primary keys of related target models.
177		pub target_ids: Vec<Target::PrimaryKey>,
178		#[cfg_attr(feature = "serde", serde(skip))]
179		_source: PhantomData<Source>,
180	}
181
182	impl<Source, Target> ManyToManyInfo<Source, Target>
183	where
184		Target: InfoModel,
185	{
186		/// Creates a many-to-many payload from target primary keys.
187		pub fn new<I>(target_ids: I) -> Self
188		where
189			I: IntoIterator<Item = Target::PrimaryKey>,
190		{
191			Self {
192				target_ids: target_ids.into_iter().collect(),
193				_source: PhantomData,
194			}
195		}
196
197		/// Creates an empty many-to-many payload.
198		pub const fn empty() -> Self {
199			Self {
200				target_ids: Vec::new(),
201				_source: PhantomData,
202			}
203		}
204
205		/// Returns the target model primary keys.
206		pub fn target_ids(&self) -> &[Target::PrimaryKey] {
207			&self.target_ids
208		}
209
210		/// Converts this payload into the target primary-key list.
211		pub fn into_target_ids(self) -> Vec<Target::PrimaryKey> {
212			self.target_ids
213		}
214	}
215
216	impl<Source, Target> Default for ManyToManyInfo<Source, Target>
217	where
218		Target: InfoModel,
219	{
220		fn default() -> Self {
221			Self::empty()
222		}
223	}
224
225	impl<Source, Target> std::fmt::Debug for ManyToManyInfo<Source, Target>
226	where
227		Target: InfoModel,
228		Target::PrimaryKey: std::fmt::Debug,
229	{
230		fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
231			f.debug_struct("ManyToManyInfo")
232				.field("target_ids", &self.target_ids)
233				.finish()
234		}
235	}
236
237	impl<Source, Target> Clone for ManyToManyInfo<Source, Target>
238	where
239		Target: InfoModel,
240		Target::PrimaryKey: Clone,
241	{
242		fn clone(&self) -> Self {
243			Self::new(self.target_ids.clone())
244		}
245	}
246
247	impl<Source, Target> PartialEq for ManyToManyInfo<Source, Target>
248	where
249		Target: InfoModel,
250		Target::PrimaryKey: PartialEq,
251	{
252		fn eq(&self, other: &Self) -> bool {
253			self.target_ids == other.target_ids
254		}
255	}
256
257	#[cfg(test)]
258	mod tests {
259		use super::{InfoModel, ManyToManyInfo, RelationInfo};
260
261		#[derive(Debug)]
262		struct Post;
263
264		impl InfoModel for Post {
265			type PrimaryKey = i64;
266		}
267
268		#[test]
269		fn relation_info_preserves_primary_key() {
270			let relation = RelationInfo::<Post>::new(7);
271			assert_eq!(*relation.id(), 7);
272			assert_eq!(relation.into_id(), 7);
273		}
274
275		#[test]
276		fn many_to_many_info_preserves_target_ids() {
277			let info = ManyToManyInfo::<(), Post>::new([1, 2, 3]);
278			assert_eq!(info.target_ids(), &[1, 2, 3]);
279		}
280	}
281}
282/// Content negotiation for request/response formats.
283#[cfg(feature = "negotiation")]
284pub mod negotiation;
285/// Pagination strategies (page-based, cursor, limit-offset).
286#[cfg(feature = "pagination")]
287pub mod pagination;
288/// Request body parsers (JSON, form, multipart, etc.).
289#[cfg(feature = "parsers")]
290pub mod parsers;
291/// Rate limiting strategies.
292pub mod rate_limit;
293/// Reactive state management primitives.
294#[cfg(feature = "reactive")]
295pub mod reactive;
296/// Security utilities (CSRF, XSS prevention, headers, HSTS, IP filtering, redirects, and resource limits).
297#[cfg(feature = "security")]
298pub mod security;
299/// Data serialization framework.
300#[cfg(feature = "serializers")]
301pub mod serializers;
302/// Signal/event dispatch system.
303#[cfg(feature = "signals")]
304pub mod signals;
305/// Core type definitions.
306#[cfg(feature = "types")]
307pub mod types;
308/// Field and data validators.
309#[cfg(feature = "validators")]
310pub mod validators;
311/// WebSocket routing primitives shared across reinhardt crates.
312#[cfg(native)]
313pub mod ws;
314
315// Re-export Page types when page feature is enabled
316// This provides Page, PageElement, IntoPage, Head, EventType, etc.
317#[cfg(all(feature = "types", feature = "page"))]
318pub use crate::types::page;
319
320#[cfg(feature = "macros")]
321pub use reinhardt_macros as macros;
322
323// Re-export rate limiting types
324pub use crate::rate_limit::RateLimitStrategy;
325
326// Re-export common external dependencies
327pub use async_trait::async_trait;
328
329// Re-export tokio only on non-WASM targets
330#[cfg(native)]
331pub use tokio;
332
333/// Re-export of serde serialization types and serde_json.
334#[cfg(feature = "serde")]
335pub mod serde {
336	pub use ::serde::{Deserialize, Deserializer, Serialize, Serializer, de, ser};
337	pub use ::serde_json as json;
338}