| Crates.io | infiltrait |
| lib.rs | infiltrait |
| version | 0.1.0 |
| created_at | 2025-08-23 14:00:05.749802+00 |
| updated_at | 2025-08-23 14:00:05.749802+00 |
| description | A procedural macro that automatically generates trait definitions from implementation blocks |
| homepage | https://github.com/aldenmoreton/infiltrait |
| repository | https://github.com/aldenmoreton/infiltrait |
| max_upload_size | |
| id | 1807540 |
| size | 29,666 |
A Rust procedural macro that automatically generates trait definitions from implementation blocks.
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.
Add this to your Cargo.toml:
[dependencies]
infiltrait = "0.1.0"
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)
}
pub, pub(crate), and other visibility modifiersunsafe markers where appropriateuse 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);
}
}
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
}
}
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 { ... }
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;
}
}
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;
}
}
When exploring API designs, infiltrait lets you focus on the implementation without getting bogged down in trait definitions:
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...
}
}
Create clean APIs where the trait and implementation are defined together:
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())
}
}
Generate traits that can be easily mocked for testing:
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(())
}
}
#[infiltrait] attribute generates exactly one traitThe macro provides clear error messages for common mistakes:
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) {}
}
The infiltrait macro:
Contributions are welcome! Please feel free to submit a Pull Request.
Licensed under either of
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.