# ๐ฌ 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
| 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