arc-handle 1.1.0

Proc macro for generating Arc-based handle wrappers for traits
Documentation
# arc-handle

A Rust procedural macro crate for generating Arc-based handle wrappers for traits, enabling easy trait object sharing across threads.

## Overview

The `#[arc_handle]` attribute macro transforms a trait definition into a thread-safe handle struct that wraps trait implementations in `Arc<dyn Trait + Send + Sync>`. This pattern is useful when you need to share trait objects across multiple threads or async tasks.

## Features

- **Thread-safe sharing**: Generated handles implement `Clone`, `Send`, and `Sync`
- **Async/await support**: Properly handles both sync and async trait methods
- **Zero-cost abstraction**: Minimal overhead over direct Arc usage
- **Easy integration**: Simple attribute macro application

## Installation

Add this to your `Cargo.toml`:

```toml
[dependencies]
arc-handle = "1.0.0"
```

## Usage

### Basic Example

```rust
use arc_handle::arc_handle;

#[arc_handle]
pub trait Calculator {
    fn add(&self, a: i32, b: i32) -> i32;
    fn multiply(&self, a: i32, b: i32) -> i32;
}

// Implementation
struct BasicCalculator;

impl CalculatorImpl for BasicCalculator {
    fn add(&self, a: i32, b: i32) -> i32 {
        a + b
    }
    
    fn multiply(&self, a: i32, b: i32) -> i32 {
        a * b
    }
}

// Usage
fn main() {
    let calc = Calculator::new(BasicCalculator);
    
    // Can be cloned and shared across threads
    let calc_clone = calc.clone();
    
    println!("2 + 3 = {}", calc.add(2, 3));
    println!("2 * 3 = {}", calc_clone.multiply(2, 3));
}
```

### Async Example

```rust
use arc_handle::arc_handle;
use async_trait::async_trait;

#[arc_handle]
#[async_trait]
pub trait DataProcessor {
    async fn process_data(&self, data: Vec<u8>) -> Result<String, Box<dyn std::error::Error>>;
    fn get_name(&self) -> &str;
}

struct JsonProcessor {
    name: String,
}

#[async_trait]
impl DataProcessorImpl for JsonProcessor {
    async fn process_data(&self, data: Vec<u8>) -> Result<String, Box<dyn std::error::Error>> {
        // Process data asynchronously
        tokio::time::sleep(std::time::Duration::from_millis(10)).await;
        Ok(String::from_utf8(data)?)
    }
    
    fn get_name(&self) -> &str {
        &self.name
    }
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let processor = DataProcessor::new(JsonProcessor {
        name: "JSON Processor".to_string(),
    });
    
    let data = b"Hello, World!".to_vec();
    let result = processor.process_data(data).await?;
    
    println!("Processed: {}", result);
    println!("Processor: {}", processor.get_name());
    
    Ok(())
}
```

## How It Works

When you apply `#[arc_handle]` to a trait:

1. **Trait Transformation**: The original trait is renamed to `TraitImpl`
2. **Handle Generation**: A new struct with the original trait name is created
3. **Method Delegation**: All trait methods are implemented on the handle, delegating to the inner `Arc<dyn TraitImpl + Send + Sync>`
4. **Constructor Methods**: `new()` and `from_boxed()` methods are generated for easy instantiation

### Generated Code Structure

For a trait named `MyTrait`, the macro generates:

```rust
// Original trait renamed
pub trait MyTraitImpl {
    // ... original methods
}

// Generated handle struct
#[derive(Clone)]
pub struct MyTrait {
    inner: std::sync::Arc<dyn MyTraitImpl + Send + Sync>,
}

impl MyTrait {
    pub fn new(inner: impl MyTraitImpl + Send + Sync + 'static) -> Self { /* ... */ }
    pub fn from_boxed(inner: Box<dyn MyTraitImpl + Send + Sync>) -> Self { /* ... */ }
    
    // Delegating methods for each trait method
    // ...
}
```

## Requirements

- Rust 2024 edition or later
- For async traits, use with `#[async_trait]` from the `async-trait` crate

## 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.

## Contributing

Contributions are welcome! Please feel free to submit a Pull Request.