# Infiltrait
A Rust procedural macro that automatically generates trait definitions from implementation blocks.
## Overview
The `#[infiltrait]` attribute macro allows you to define a trait and its implementation simultaneously by writing only the impl block. This eliminates the need to separately define the trait interface, reducing code duplication and keeping related code together.
## Installation
Add this to your `Cargo.toml`:
```toml
[dependencies]
infiltrait = "0.1.0"
```
## Quick Start
```rust
use infiltrait::infiltrait;
struct Calculator;
#[infiltrait]
impl Arithmetic for Calculator {
fn add(&self, a: i32, b: i32) -> i32 {
a + b
}
fn multiply(&self, a: i32, b: i32) -> i32 {
a * b
}
}
// The macro automatically generates:
// trait Arithmetic {
// fn add(&self, a: i32, b: i32) -> i32;
// fn multiply(&self, a: i32, b: i32) -> i32;
// }
// Now you can use the trait normally:
fn calculate<T: Arithmetic>(calc: &T) -> i32 {
let sum = calc.add(2, 3);
calc.multiply(sum, 4)
}
```
## Features
- **Zero Runtime Overhead**: Pure compile-time code generation
- **Full Feature Support**: Methods, associated types, and associated constants
- **Visibility Control**: Respects `pub`, `pub(crate)`, and other visibility modifiers
- **Safety Preservation**: Maintains `unsafe` markers where appropriate
- **Clear Error Messages**: Helpful compile-time diagnostics
## Examples
### Basic Methods
```rust
use infiltrait::infiltrait;
struct Logger;
#[infiltrait]
impl Logging for Logger {
fn info(&self, message: &str) {
println!("[INFO] {}", message);
}
fn error(&self, message: &str) {
eprintln!("[ERROR] {}", message);
}
}
```
### Associated Types and Constants
```rust
use infiltrait::infiltrait;
struct Database;
#[infiltrait]
impl Storage for Database {
type Item = String;
const MAX_CAPACITY: usize = 1000;
fn store(&mut self, item: Self::Item) -> Result<(), &'static str> {
// Implementation details...
Ok(())
}
fn capacity(&self) -> usize {
Self::MAX_CAPACITY
}
}
```
### Public Traits
```rust
use infiltrait::infiltrait;
struct ApiService;
#[infiltrait]
pub impl PublicApi for ApiService {
fn process_request(&self, data: &str) -> String {
format!("Processed: {}", data)
}
}
// The generated trait will also be public:
// pub trait PublicApi { ... }
```
### Generic Implementations
```rust
use infiltrait::infiltrait;
struct Container<T> {
value: T,
}
#[infiltrait]
impl<T: Clone> Wrapper<T> for Container<T> {
fn get(&self) -> T {
self.value.clone()
}
fn set(&mut self, value: T) {
self.value = value;
}
}
```
### Unsafe Traits
```rust
use infiltrait::infiltrait;
struct RawPointer(*mut u8);
#[infiltrait]
unsafe impl UnsafeOperations for RawPointer {
unsafe fn read(&self) -> u8 {
*self.0
}
unsafe fn write(&mut self, value: u8) {
*self.0 = value;
}
}
```
## Use Cases
### Rapid Prototyping
When exploring API designs, `infiltrait` lets you focus on the implementation without getting bogged down in trait definitions:
```rust
use infiltrait::infiltrait;
struct GameEngine;
#[infiltrait]
impl GameLoop for GameEngine {
fn update(&mut self, delta_time: f32) {
// Game logic here...
}
fn render(&self) {
// Rendering code here...
}
}
```
### Library Development
Create clean APIs where the trait and implementation are defined together:
```rust
use infiltrait::infiltrait;
pub struct HttpClient;
#[infiltrait]
pub impl HttpRequests for HttpClient {
async fn get(&self, url: &str) -> Result<String, Box<dyn std::error::Error>> {
// HTTP GET implementation
Ok("response".to_string())
}
async fn post(&self, url: &str, body: &str) -> Result<String, Box<dyn std::error::Error>> {
// HTTP POST implementation
Ok("response".to_string())
}
}
```
### Testing and Mocking
Generate traits that can be easily mocked for testing:
```rust
use infiltrait::infiltrait;
struct FileSystem;
#[infiltrait]
impl FileOperations for FileSystem {
fn read_file(&self, path: &str) -> std::io::Result<String> {
std::fs::read_to_string(path)
}
fn write_file(&self, path: &str, content: &str) -> std::io::Result<()> {
std::fs::write(path, content)
}
}
// Easy to create a mock for testing:
struct MockFileSystem;
impl FileOperations for MockFileSystem {
fn read_file(&self, _path: &str) -> std::io::Result<String> {
Ok("mock content".to_string())
}
fn write_file(&self, _path: &str, _content: &str) -> std::io::Result<()> {
Ok(())
}
}
```
## Limitations
- **Trait Names**: Cannot contain lifetimes or generic parameters in the trait name itself
- **Implementation Only**: Only works with trait implementations, not inherent impls
- **Single Trait**: Each `#[infiltrait]` attribute generates exactly one trait
## Error Handling
The macro provides clear error messages for common mistakes:
```rust
use infiltrait::infiltrait;
struct MyStruct;
// ❌ Error: Please name a trait to implement
#[infiltrait]
impl MyStruct {
fn method(&self) {}
}
// ❌ Error: Trait may not contain lifetimes or generics
#[infiltrait]
impl MyTrait<T> for MyStruct {
fn method(&self) {}
}
```
## How It Works
The `infiltrait` macro:
1. Parses the implementation block and extracts the trait name
2. Converts each implementation item into its corresponding trait item:
- Method implementations → Method signatures
- Associated constants → Associated constant declarations
- Associated types → Associated type declarations
3. Generates both the trait definition and preserves the original implementation
4. Applies the same visibility and safety modifiers to the generated trait
## Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
## License
Licensed under either of
- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
at your option.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this crate by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.