arc-handle 1.2.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(())
}
```

### Default Method Implementations

Trait methods with default bodies are supported. The handle delegates to the
trait object, so implementors may override the default and the handle will
dispatch to their override:

```rust
use arc_handle::arc_handle;

#[arc_handle]
pub trait Worker {
    fn name(&self) -> &str;

    fn greet(&self) -> String {
        format!("Hello from {}", self.name())
    }
}

struct Robot;

impl WorkerImpl for Robot {
    fn name(&self) -> &str {
        "Rob"
    }
}

fn main() {
    let worker = Worker::new(Robot);
    // Uses the default body, which calls `name()` on the implementor.
    assert_eq!(worker.greet(), "Hello from Rob");
}
```

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