1use dolphin::{load_and_invoke, load, invoke};
2
3#[repr(C)]
5struct User {
6 id: i32,
7 name: [u8; 64],
8 age: i32,
9 balance: f64,
10}
11
12impl User {
13 fn new(id: i32, name: &str, age: i32, balance: f64) -> Self {
14 let mut name_buf = [0u8; 64];
15 let name_bytes = name.as_bytes();
16 let len = name_bytes.len().min(63); name_buf[..len].copy_from_slice(&name_bytes[..len]);
18
19 User {
20 id,
21 name: name_buf,
22 age,
23 balance,
24 }
25 }
26}
27
28#[repr(C)]
29struct Product {
30 product_id: i32,
31 name: [u8; 100],
32 price: f64,
33 quantity: i32,
34}
35
36impl Product {
37 fn new(product_id: i32, name: &str, price: f64, quantity: i32) -> Self {
38 let mut name_buf = [0u8; 100];
39 let name_bytes = name.as_bytes();
40 let len = name_bytes.len().min(99);
41 name_buf[..len].copy_from_slice(&name_bytes[..len]);
42
43 Product {
44 product_id,
45 name: name_buf,
46 price,
47 quantity,
48 }
49 }
50}
51
52fn main() {
53 println!("=== Dolphin FFI Examples ===\n");
54
55 println!("=== PART 1: Using load_and_invoke ===\n");
59
60 println!("--- Example 1: Calculate Sum ---");
62 let numbers = vec![10, 20, 30, 40, 50];
63 match load_and_invoke("./examples/libexample.dylib", "calculate_sum", &numbers) {
64 Ok(_) => println!("✓ Successfully invoked calculate_sum\n"),
65 Err(e) => eprintln!("✗ Error: {}\n", e),
66 }
67
68 println!("--- Example 2: Print Message ---");
70 let message = "Hello from Rust!";
71 match load_and_invoke("./examples/libexample.dylib", "print_message", message.as_bytes()) {
72 Ok(_) => println!("✓ Successfully invoked print_message\n"),
73 Err(e) => eprintln!("✗ Error: {}\n", e),
74 }
75
76 println!("--- Example 3: Print User Model ---");
78 let user = User::new(1, "Alice Johnson", 28, 1500.50);
79 let user_bytes = unsafe {
80 std::slice::from_raw_parts(
81 &user as *const User as *const u8,
82 std::mem::size_of::<User>()
83 )
84 };
85 match load_and_invoke("./examples/libexample.dylib", "print_user", user_bytes) {
86 Ok(_) => println!("✓ Successfully invoked print_user\n"),
87 Err(e) => eprintln!("✗ Error: {}\n", e),
88 }
89
90 println!("\n=== PART 2: Using load() + invoke() separately ===\n");
94 println!("This approach is better when you need to call the same function multiple times.\n");
95
96 println!("--- Example 4: Load 'reverse_string' once, use multiple times ---");
98 match load("./examples/libexample.dylib", "reverse_string") {
99 Some(reverse_addr) => {
100 println!("✓ Loaded 'reverse_string' at address: 0x{:x}\n", reverse_addr);
101
102 let strings = vec!["Dolphin", "FFI", "Library", "Rust"];
104 for (i, text) in strings.iter().enumerate() {
105 println!(" Call {}: Reversing '{}'", i + 1, text);
106 match invoke(reverse_addr, text.as_bytes()) {
107 Ok(_) => println!(" ✓ Success\n"),
108 Err(e) => eprintln!(" ✗ Error: {}\n", e),
109 }
110 }
111 }
112 None => eprintln!("✗ Failed to load 'reverse_string'\n"),
113 }
114
115 println!("--- Example 5: Pre-load multiple functions ---");
117 let calc_sum_addr = load("./examples/libexample.dylib", "calculate_sum");
118 let print_msg_addr = load("./examples/libexample.dylib", "print_message");
119 let count_chars_addr = load("./examples/libexample.dylib", "count_characters");
120
121 if calc_sum_addr.is_some() && print_msg_addr.is_some() && count_chars_addr.is_some() {
122 println!("✓ All functions loaded successfully:");
123 println!(" - calculate_sum: 0x{:x}", calc_sum_addr.unwrap());
124 println!(" - print_message: 0x{:x}", print_msg_addr.unwrap());
125 println!(" - count_characters: 0x{:x}\n", count_chars_addr.unwrap());
126
127 println!("Using calculate_sum:");
129 let nums1 = vec![5, 10, 15];
130 let bytes1 = unsafe {
131 std::slice::from_raw_parts(
132 nums1.as_ptr() as *const u8,
133 nums1.len() * std::mem::size_of::<i32>()
134 )
135 };
136 invoke(calc_sum_addr.unwrap(), bytes1).ok();
137
138 println!("\nUsing print_message:");
140 let msg = "Pre-loaded function!";
141 invoke(print_msg_addr.unwrap(), msg.as_bytes()).ok();
142
143 println!("\nUsing count_characters:");
145 let sample = "Rust FFI 2024";
146 invoke(count_chars_addr.unwrap(), sample.as_bytes()).ok();
147
148 println!("\n✓ All pre-loaded functions executed\n");
149 } else {
150 eprintln!("✗ Failed to load one or more functions\n");
151 }
152
153 println!("--- Example 6: User operations with load + invoke ---");
155 if let Some(print_user_addr) = load("./examples/libexample.dylib", "print_user") {
156 println!("✓ Loaded 'print_user' at 0x{:x}\n", print_user_addr);
157
158 let users_to_print = vec![
160 User::new(10, "John", 30, 1000.00),
161 User::new(20, "Jane", 25, 2500.50),
162 User::new(30, "Jake", 40, 5000.75),
163 ];
164
165 for (i, user) in users_to_print.iter().enumerate() {
166 println!("Printing user {}:", i + 1);
167 let bytes = unsafe {
168 std::slice::from_raw_parts(
169 user as *const User as *const u8,
170 std::mem::size_of::<User>()
171 )
172 };
173 match invoke(print_user_addr, bytes) {
174 Ok(_) => println!("✓ User printed\n"),
175 Err(e) => eprintln!("✗ Error: {}\n", e),
176 }
177 }
178 } else {
179 eprintln!("✗ Failed to load 'print_user'\n");
180 }
181
182 println!("--- Example 7: Product processing with load + invoke ---");
184 if let Some(process_order_addr) = load("./examples/libexample.dylib", "process_order") {
185 println!("✓ Loaded 'process_order' at 0x{:x}\n", process_order_addr);
186
187 let orders = vec![
189 (Product::new(1, "Mouse", 29.99, 100), 5),
190 (Product::new(2, "Keyboard", 79.99, 50), 3),
191 (Product::new(3, "Monitor", 299.99, 20), 2),
192 ];
193
194 for (i, (product, qty)) in orders.iter().enumerate() {
195 println!("Processing order {}:", i + 1);
196 let mut order_data = Vec::new();
197 order_data.extend_from_slice(unsafe {
198 std::slice::from_raw_parts(
199 product as *const Product as *const u8,
200 std::mem::size_of::<Product>()
201 )
202 });
203 order_data.extend_from_slice(unsafe {
204 std::slice::from_raw_parts(
205 qty as *const i32 as *const u8,
206 std::mem::size_of::<i32>()
207 )
208 });
209
210 match invoke(process_order_addr, &order_data) {
211 Ok(_) => println!("✓ Order processed\n"),
212 Err(e) => eprintln!("✗ Error: {}\n", e),
213 }
214 }
215 } else {
216 eprintln!("✗ Failed to load 'process_order'\n");
217 }
218
219 println!("\n=== PART 3: Performance Demonstration ===\n");
223 println!("--- Calling same function 5 times ---\n");
224
225 println!("Method 1: Using load_and_invoke (loads each time)");
227 for i in 1..=5 {
228 let msg = format!("Message {}", i);
229 load_and_invoke("./examples/libexample.dylib", "print_message", msg.as_bytes()).ok();
230 }
231
232 println!("\nMethod 2: Using load once + invoke many times (faster)");
233 if let Some(addr) = load("./examples/libexample.dylib", "print_message") {
234 for i in 1..=5 {
235 let msg = format!("Fast call {}", i);
236 invoke(addr, msg.as_bytes()).ok();
237 }
238 }
239
240 println!("\n✓ Notice: Method 2 is more efficient for repeated calls!\n");
241
242 println!("=== All examples completed ===");
243}