rusty_typesh/lib.rs
1//! Type pattern matching system for Rust.
2//!
3//! This crate provides a flexible type pattern matching system that allows:
4//! - Runtime type checking and matching
5//! - Pattern matching with custom handlers
6//! - Both macro-based and manual matching approaches
7//!
8//! # Examples
9//! ```
10//! use rusty_typesh::type_match;
11//!
12//! let value = 42i32;
13//! let result = type_match!(
14//! value,
15//! i32 => |x: &i32| format!("Got integer: {}", x),
16//! String => |x: &String| format!("Got string: {}", x)
17//! );
18//! assert_eq!(result, Some("Got integer: 42".to_string()));
19//! ```
20
21mod macros;
22
23use std::any::TypeId;
24
25/// A trait for implementing type pattern matching behavior.
26///
27/// This trait is used to define how types should be matched against patterns.
28/// Implementors must provide a `matches()` method that determines if a type
29/// matches the pattern.
30pub trait TypePattern<T: 'static> {
31 /// Returns true if the type matches this pattern
32 fn matches(&self) -> bool;
33}
34
35/// A concrete type matcher implementation.
36///
37/// TypeMatcher provides runtime type checking capabilities by storing
38/// and comparing TypeIds.
39///
40/// # Type Parameters
41/// * `U` - The type to match against
42pub struct TypeMatcher<U: 'static> {
43 /// The TypeId of the type to match
44 type_id: TypeId,
45 /// PhantomData to handle the generic type parameter
46 _phantom: std::marker::PhantomData<U>,
47}
48
49impl<U: 'static> TypeMatcher<U> {
50 /// Creates a new TypeMatcher for the given type.
51 ///
52 /// # Examples
53 /// ```
54 /// use rusty_typesh::TypeMatcher;
55 /// let matcher = TypeMatcher::<i32>::new();
56 /// ```
57 pub fn new() -> Self {
58 Self {
59 type_id: TypeId::of::<U>(),
60 _phantom: std::marker::PhantomData,
61 }
62 }
63}
64
65impl<T: 'static, U: 'static> TypePattern<T> for TypeMatcher<U> {
66 fn matches(&self) -> bool {
67 TypeId::of::<T>() == self.type_id
68 }
69}
70
71/// Matches a value against a series of type patterns and handlers.
72///
73/// # Type Parameters
74/// * `T` - The type of the value to match
75/// * `R` - The return type of the pattern handlers
76///
77/// # Arguments
78/// * `value` - The value to match against patterns
79/// * `patterns` - A slice of tuples containing patterns and their handlers
80///
81/// # Returns
82/// * `Some(R)` if a pattern matches and its handler succeeds
83/// * `None` if no pattern matches
84pub fn match_type<T: 'static, R>(
85 value: &T,
86 patterns: &[(Box<dyn TypePattern<T>>, Box<dyn Fn(&T) -> R>)],
87) -> Option<R> {
88 for (pattern, handler) in patterns {
89 if pattern.matches() {
90 return Some(handler(value));
91 }
92 }
93 None
94}
95
96#[cfg(test)]
97mod tests {
98 use super::*;
99
100 #[test]
101 fn test_basic_type_matching() {
102 let value = 42i32;
103 let patterns = vec![
104 (
105 Box::new(TypeMatcher::<i32>::new()) as Box<dyn TypePattern<i32>>,
106 Box::new(|x: &i32| format!("Integer: {}", x)) as Box<dyn Fn(&i32) -> String>,
107 ),
108 (
109 Box::new(TypeMatcher::<i32>::new()) as Box<dyn TypePattern<i32>>,
110 Box::new(|x: &i32| format!("String length: {}", x.to_string().len())) as Box<dyn Fn(&i32) -> String>,
111 ),
112 ];
113
114 let result = match_type(&value, &patterns);
115 assert_eq!(result, Some("Integer: 42".to_string()));
116 }
117}