dolphin 0.2.1

A lightweight and safe Rust FFI library for dynamically loading and invoking functions from shared libraries (.dll, .so, .dylib)
Documentation
# ๐Ÿฌ Dolphin

A lightweight and safe Rust FFI library for dynamically loading and invoking functions from shared libraries (`.dll`, `.so`, `.dylib`). Dolphin provides a simple interface to call native C functions from any compiled library at runtime.

## Features

- ๐Ÿš€ **Dynamic Loading** - Load functions from any shared library at runtime
- ๐Ÿ”’ **Safe API** - Wraps unsafe FFI calls in a safe, ergonomic interface
- โšก **Performance** - Pre-load function addresses for zero-overhead repeated calls
- ๐ŸŽฏ **Flexible** - Pass any data type including primitives, strings, and complex structs
- ๐ŸŒ **Cross-Platform** - Works on Windows (`.dll`), Linux (`.so`), and macOS (`.dylib`)

## Installation

Add Dolphin to your `Cargo.toml`:

```toml
[dependencies]
dolphin = "0.2.1"
```

## Quick Start

### Simple Usage

```rust
use dolphin::load_and_invoke;

fn main() {
    // Call a C function with a string
    let message = "Hello from Rust!";
    load_and_invoke("./mylib.dylib", "print_message", message.as_bytes())
        .expect("Failed to call function");
    
    // Call with integer array
    let numbers = vec![10, 20, 30, 40, 50];
    load_and_invoke("./mylib.dylib", "calculate_sum", &numbers)
        .expect("Failed to call function");
}
```

### High-Performance Pattern (Pre-loading)

For repeated calls, pre-load the function once and reuse the address:

```rust
use dolphin::{load, invoke};

fn main() {
    // Load once
    let print_addr = load("./mylib.dylib", "print_message")
        .expect("Failed to load function");
    
    // Invoke many times with zero loading overhead
    for i in 0..1000 {
        let msg = format!("Message {}", i);
        invoke(print_addr, msg.as_bytes()).ok();
    }
}
```

### Working with Structs

```rust
use dolphin::load_and_invoke;

#[repr(C)]
struct User {
    id: i32,
    name: [u8; 64],
    age: i32,
    balance: f64,
}

fn main() {
    let user = User {
        id: 1,
        name: [0; 64], // Initialize with your data
        age: 30,
        balance: 1000.0,
    };
    
    let user_bytes = unsafe {
        std::slice::from_raw_parts(
            &user as *const User as *const u8,
            std::mem::size_of::<User>()
        )
    };
    
    load_and_invoke("./mylib.dylib", "process_user", user_bytes)
        .expect("Failed to process user");
}
```

## API Overview

### Core Functions

- **`load(library_path, function_name)`** - Load a function and return its address
  - Returns: `Option<usize>` - The function address if found
  
- **`invoke(address, arguments)`** - Call a pre-loaded function
  - Returns: `Result<(), String>` - Success or error message
  
- **`load_and_invoke(library_path, function_name, arguments)`** - Load and call in one step
  - Returns: `Result<(), String>` - Success or error message

## C Function Requirements

C functions must follow this signature:

```c
void your_function(const uint8_t* data, size_t len) {
    // Your implementation
}
```

The `data` pointer contains the serialized arguments, and `len` is the byte count.

### Example C Library

```c
#include <stdio.h>
#include <stdint.h>

void print_message(const uint8_t* data, size_t len) {
    printf("Message: %.*s\n", (int)len, (char*)data);
}

void calculate_sum(const uint8_t* data, size_t len) {
    int count = len / sizeof(int);
    const int* numbers = (const int*)data;
    int sum = 0;
    for (int i = 0; i < count; i++) {
        sum += numbers[i];
    }
    printf("Sum: %d\n", sum);
}
```

Compile it:
```bash
# macOS
gcc -shared -fPIC mylib.c -o libmylib.dylib

# Linux
gcc -shared -fPIC mylib.c -o libmylib.so

# Windows
gcc -shared mylib.c -o mylib.dll
```

## Examples

The repository includes comprehensive examples:

```bash
# Clone the repository
git clone https://github.com/Logan-Garrett/dolphin.git
cd dolphin/dolphin

# Build C examples
cd examples && make && cd ..

# Run examples
cargo run --example usage_example    # Basic usage patterns
cargo run --example preload_example  # Pre-loading pattern
```

## Use Cases

- **Plugin Systems** - Dynamically load and execute plugins at runtime
- **C Library Integration** - Call C libraries without compile-time linking
- **Hot Reloading** - Reload functions without restarting your application
- **Language Interop** - Bridge Rust with C, C++, or any C-compatible library
- **Legacy Code** - Interface with existing native libraries

## Performance

Dolphin is designed for performance:

- **Zero overhead** for pre-loaded functions
- **No runtime dependencies** beyond `libloading`
- **Minimal allocations** - Direct memory operations
- **Efficient** - Function addresses are simple integers

Benchmark comparison:
- `load_and_invoke`: ~1-2ยตs per call (includes library loading)
- `load` + `invoke`: ~50-100ns per call (pre-loaded)

## Safety

While FFI is inherently unsafe, Dolphin provides guardrails:

- โœ… Validates function addresses before calling
- โœ… Returns `Result` types for error handling
- โœ… Safe wrapper API around unsafe operations
- โš ๏ธ User must ensure correct function signatures
- โš ๏ธ User must ensure data layout matches C expectations

## Platform Support

| Platform | Library Format | Tested |
|----------|---------------|---------|
| macOS    | `.dylib`      | โœ…      |
| Linux    | `.so`         | โœ…      |
| Windows  | `.dll`        | โœ…      |

## Contributing

Contributions are welcome! Please feel free to submit issues or pull requests.

## License

This project is licensed under the MIT License - see the [LICENSE](../LICENSE) file for details.

## Acknowledgments

Built with:
- [`libloading`]https://crates.io/crates/libloading - Cross-platform dynamic library loading

## Links

- **Repository**: https://github.com/Logan-Garrett/dolphin
- **Documentation**: https://docs.rs/dolphin
- **Crates.io**: https://crates.io/crates/dolphin

---

Made with ๐Ÿฌ by Logan Garrett 


cargo test                    # Run basic tests
cargo test -- --ignored       # Run integration tests (requires gcc)
cargo test -- --include-ignored  # Run all tests