1. Unsafe Rust
// 5 unsafe superpowers:
// 1. Dereference raw pointer
// 2. Call unsafe function
// 3. Access/modify mutable static
// 4. Implement unsafe trait
// 5. Access fields of union
fn main() {
// Raw pointers
let mut num = 5;
let r1 = &num as *const i32; // immutable raw pointer
let r2 = &mut num as *mut i32; // mutable raw pointer
unsafe {
println!("r1: {}", *r1);
*r2 = 10;
println!("r2: {}", *r2);
}
// unsafe function
unsafe fn dangerous() {
// ...
}
unsafe { dangerous(); }
// Safe abstraction over unsafe code
fn split_at_mut(values: &mut [i32], mid: usize) -> (&mut [i32], &mut [i32]) {
let len = values.len();
let ptr = values.as_mut_ptr();
assert!(mid <= len);
unsafe {
(
std::slice::from_raw_parts_mut(ptr, mid),
std::slice::from_raw_parts_mut(ptr.add(mid), len - mid),
)
}
}
}
2. FFI — Call C from Rust
// Gọi C standard library
extern "C" {
fn abs(input: i32) -> i32;
fn strlen(s: *const std::ffi::c_char) -> usize;
}
fn main() {
unsafe {
println!("abs(-5) = {}", abs(-5));
}
}
// Expose Rust function cho C
#[no_mangle]
pub extern "C" fn rust_add(a: i32, b: i32) -> i32 {
a + b
}
// Dùng bindgen cho C libraries
// build.rs
fn main() {
println!("cargo:rustc-link-lib=z"); // Link libz
let bindings = bindgen::Builder::default()
.header("wrapper.h")
.generate()
.expect("Unable to generate bindings");
bindings.write_to_file("src/bindings.rs").unwrap();
}
3. PyO3 — Python Bindings
use pyo3::prelude::*;
#[pyfunction]
fn sum_as_string(a: usize, b: usize) -> String {
(a + b).to_string()
}
#[pyclass]
struct Calculator {
value: f64,
}
#[pymethods]
impl Calculator {
#[new]
fn new(value: f64) -> Self {
Calculator { value }
}
fn add(&mut self, x: f64) {
self.value += x;
}
fn result(&self) -> f64 {
self.value
}
}
#[pymodule]
fn my_rust_lib(m: &Bound<'_, PyModule>) -> PyResult<()> {
m.add_function(wrap_pyfunction!(sum_as_string, m)?)?;
m.add_class::<Calculator>()?;
Ok(())
}
# Python
import my_rust_lib
print(my_rust_lib.sum_as_string(5, 3)) # "8"
calc = my_rust_lib.Calculator(0.0)
calc.add(3.14)
print(calc.result()) # 3.14
4. Safety Invariants
// ✅ Safe wrapper pattern
pub struct SafeBuffer {
ptr: *mut u8,
len: usize,
capacity: usize,
}
impl SafeBuffer {
pub fn new(capacity: usize) -> Self {
let layout = std::alloc::Layout::array::<u8>(capacity).unwrap();
let ptr = unsafe { std::alloc::alloc(layout) };
Self { ptr, len: 0, capacity }
}
pub fn push(&mut self, byte: u8) {
assert!(self.len < self.capacity, "Buffer full");
unsafe { *self.ptr.add(self.len) = byte; }
self.len += 1;
}
}
impl Drop for SafeBuffer {
fn drop(&mut self) {
let layout = std::alloc::Layout::array::<u8>(self.capacity).unwrap();
unsafe { std::alloc::dealloc(self.ptr, layout); }
}
}
Next article: Testing & Benchmarking.