🦀 Unsafe Rust in TuskLang

Rust Documentation

Unsafe Rust in TuskLang

⚠️ Unsafe Foundation

Unsafe Rust provides the ability to bypass Rust's safety guarantees when necessary, enabling low-level programming, FFI integration, and performance optimizations. This guide covers raw pointers, unsafe blocks, and safe abstractions over unsafe code.

🏗️ Unsafe Architecture

Unsafe Principles

[unsafe_principles]
safety_contracts: true
unsafe_blocks: true
raw_pointers: true
ffi_integration: true

[unsafe_patterns] safe_abstractions: true unsafe_apis: true memory_safety: true undefined_behavior: true

Unsafe Components

[unsafe_components]
raw_pointers: "unsafe"
unsafe_functions: "unsafe_blocks"
ffi: "foreign_functions"
static_mut: "global_state"

🔧 Raw Pointers

Raw Pointer Types

[raw_pointer_types]
const_pointers: true
mut_pointers: true
pointer_arithmetic: true

[raw_pointer_implementation] // Raw pointer basics pub fn raw_pointer_example() { let mut x = 5; let raw_ptr = &mut x as *mut i32; unsafe { println!("Value through raw pointer: {}", *raw_ptr); *raw_ptr = 10; println!("Modified value: {}", *raw_ptr); } }

// Raw pointer arithmetic pub fn pointer_arithmetic_example() { let mut arr = [1, 2, 3, 4, 5]; let ptr = arr.as_mut_ptr(); unsafe { for i in 0..5 { let element_ptr = ptr.add(i); println!("Element {}: {}", i, *element_ptr); } } }

// Null pointers pub fn null_pointer_example() { let null_ptr: *const i32 = std::ptr::null(); unsafe { if null_ptr.is_null() { println!("Pointer is null"); } else { println!("Pointer is not null: {}", *null_ptr); } } }

// Raw pointer to struct #[derive(Debug)] pub struct Point { x: f64, y: f64, }

pub fn struct_pointer_example() { let mut point = Point { x: 1.0, y: 2.0 }; let ptr = &mut point as *mut Point; unsafe { println!("Point: {:?}", *ptr); (*ptr).x = 3.0; (*ptr).y = 4.0; println!("Modified point: {:?}", *ptr); } }

Pointer Safety

[pointer_safety]
dereference_safety: true
aliasing_rules: true
lifetime_management: true

[pointer_safety_implementation] // Safe dereferencing pub fn safe_dereference_example() { let mut data = vec![1, 2, 3, 4, 5]; let ptr = data.as_mut_ptr(); unsafe { // Safe because we know the pointer is valid for i in 0..data.len() { let element_ptr = ptr.add(i); println!("Element {}: {}", i, *element_ptr); } } }

// Aliasing prevention pub fn aliasing_example() { let mut data = vec![1, 2, 3, 4, 5]; let ptr1 = data.as_mut_ptr(); let ptr2 = data.as_mut_ptr(); unsafe { // This is safe because we're not aliasing mutable references *ptr1 = 10; *ptr2 = 20; } }

// Lifetime management with raw pointers pub struct RawBuffer { ptr: *mut u8, len: usize, }

impl RawBuffer { pub fn new(size: usize) -> Self { let layout = std::alloc::Layout::from_size_align(size, 8).unwrap(); let ptr = unsafe { std::alloc::alloc(layout) }; Self { ptr, len: size, } } pub fn as_slice(&self) -> &[u8] { unsafe { std::slice::from_raw_parts(self.ptr, self.len) } } pub fn as_mut_slice(&mut self) -> &mut [u8] { unsafe { std::slice::from_raw_parts_mut(self.ptr, self.len) } } }

impl Drop for RawBuffer { fn drop(&mut self) { let layout = std::alloc::Layout::from_size_align(self.len, 8).unwrap(); unsafe { std::alloc::dealloc(self.ptr, layout); } } }

🔄 Unsafe Functions

Unsafe Function Design

[unsafe_function_design]
safety_contracts: true
documentation: true
invariant_checks: true

[unsafe_function_implementation] // Unsafe function with safety contract /// # Safety /// /// The caller must ensure that: /// - ptr is not null /// - ptr points to valid memory /// - ptr is aligned for T /// - ptr is valid for reads pub unsafe fn read_value<T>(ptr: *const T) -> T { // Safety: caller guarantees ptr is valid ptr.read() }

// Unsafe function with runtime checks pub fn safe_read_value<T>(ptr: *const T) -> Option<T> { if ptr.is_null() { return None; } unsafe { Some(ptr.read()) } }

// Unsafe function with invariant checking pub struct SafeArray<T> { ptr: *mut T, len: usize, }

impl<T> SafeArray<T> { pub fn new(len: usize) -> Self { let layout = std::alloc::Layout::array::<T>(len).unwrap(); let ptr = unsafe { std::alloc::alloc(layout) as *mut T }; Self { ptr, len } } /// # Safety /// /// The caller must ensure that: /// - index < self.len pub unsafe fn get_unchecked(&self, index: usize) -> &T { &*self.ptr.add(index) } /// # Safety /// /// The caller must ensure that: /// - index < self.len pub unsafe fn get_unchecked_mut(&mut self, index: usize) -> &mut T { &mut *self.ptr.add(index) } // Safe wrapper pub fn get(&self, index: usize) -> Option<&T> { if index < self.len { unsafe { Some(self.get_unchecked(index)) } } else { None } } pub fn get_mut(&mut self, index: usize) -> Option<&mut T> { if index < self.len { unsafe { Some(self.get_unchecked_mut(index)) } } else { None } } }

impl<T> Drop for SafeArray<T> { fn drop(&mut self) { let layout = std::alloc::Layout::array::<T>(self.len).unwrap(); unsafe { std::alloc::dealloc(self.ptr as *mut u8, layout); } } }

Unsafe Traits

[unsafe_traits]
send_sync: true
unsafe_trait_impl: true
safety_guarantees: true

[unsafe_trait_implementation] // Unsafe trait pub unsafe trait UnsafeTrait { fn unsafe_method(&self); }

// Safe wrapper trait pub trait SafeTrait { fn safe_method(&self); }

// Implementation of unsafe trait pub struct UnsafeStruct { data: *mut i32, }

unsafe impl UnsafeTrait for UnsafeStruct { fn unsafe_method(&self) { unsafe { if !self.data.is_null() { println!("Unsafe value: {}", *self.data); } } } }

// Safe implementation impl SafeTrait for UnsafeStruct { fn safe_method(&self) { // Safe wrapper around unsafe code if !self.data.is_null() { unsafe { println!("Safe access: {}", *self.data); } } } }

// Send and Sync implementations unsafe impl Send for UnsafeStruct {} unsafe impl Sync for UnsafeStruct {}

🌐 FFI Integration

C FFI

[ffi_integration]
c_functions: true
c_structs: true
callback_functions: true

[ffi_implementation] use std::ffi::{c_char, CStr, CString};

// C function declarations #[link(name = "c")] extern "C" { fn strlen(s: *const c_char) -> usize; fn printf(format: *const c_char, ...) -> i32; }

// Safe wrapper for C functions pub fn safe_strlen(s: &str) -> usize { let c_string = CString::new(s).unwrap(); unsafe { strlen(c_string.as_ptr()) } }

pub fn safe_printf(format: &str) { let c_format = CString::new(format).unwrap(); unsafe { printf(c_format.as_ptr()); } }

// C struct integration #[repr(C)] pub struct CPoint { x: f64, y: f64, }

#[link(name = "math")] extern "C" { fn distance(p1: const CPoint, p2: const CPoint) -> f64; }

pub fn safe_distance(p1: &CPoint, p2: &CPoint) -> f64 { unsafe { distance(p1, p2) } }

// Callback functions pub type CallbackFn = extern "C" fn(i32) -> i32;

#[link(name = "callback")] extern "C" { fn register_callback(callback: CallbackFn); fn call_callback(value: i32) -> i32; }

pub extern "C" fn rust_callback(value: i32) -> i32 { value * 2 }

pub fn register_rust_callback() { unsafe { register_callback(rust_callback); } }

pub fn call_rust_callback(value: i32) -> i32 { unsafe { call_callback(value) } }

System Calls

[system_calls]
syscalls: true
low_level_io: true
memory_mapping: true

[system_calls_implementation] use std::os::unix::io::{AsRawFd, RawFd};

// Low-level file operations pub struct LowLevelFile { fd: RawFd, }

impl LowLevelFile { pub fn open(path: &str, flags: i32, mode: u32) -> Result<Self, i32> { let c_path = CString::new(path).unwrap(); let fd = unsafe { libc::open(c_path.as_ptr(), flags, mode) }; if fd == -1 { Err(std::io::Error::last_os_error().raw_os_error().unwrap()) } else { Ok(Self { fd }) } } pub fn read(&self, buffer: &mut [u8]) -> Result<usize, i32> { let result = unsafe { libc::read( self.fd, buffer.as_mut_ptr() as *mut libc::c_void, buffer.len(), ) }; if result == -1 { Err(std::io::Error::last_os_error().raw_os_error().unwrap()) } else { Ok(result as usize) } } pub fn write(&self, buffer: &[u8]) -> Result<usize, i32> { let result = unsafe { libc::write( self.fd, buffer.as_ptr() as *const libc::c_void, buffer.len(), ) }; if result == -1 { Err(std::io::Error::last_os_error().raw_os_error().unwrap()) } else { Ok(result as usize) } } }

impl Drop for LowLevelFile { fn drop(&mut self) { unsafe { libc::close(self.fd); } } }

// Memory mapping pub struct MemoryMap { ptr: *mut u8, len: usize, }

impl MemoryMap { pub fn new(fd: RawFd, len: usize, offset: i64) -> Result<Self, i32> { let ptr = unsafe { libc::mmap( std::ptr::null_mut(), len, libc::PROT_READ | libc::PROT_WRITE, libc::MAP_SHARED, fd, offset, ) as *mut u8 }; if ptr == std::ptr::null_mut() { Err(std::io::Error::last_os_error().raw_os_error().unwrap()) } else { Ok(Self { ptr, len }) } } pub fn as_slice(&self) -> &[u8] { unsafe { std::slice::from_raw_parts(self.ptr, self.len) } } pub fn as_mut_slice(&mut self) -> &mut [u8] { unsafe { std::slice::from_raw_parts_mut(self.ptr, self.len) } } }

impl Drop for MemoryMap { fn drop(&mut self) { unsafe { libc::munmap(self.ptr as *mut libc::c_void, self.len); } } }

🔒 Static Mutable State

Global State Management

[global_state]
static_mut: true
thread_local: true
atomic_operations: true

[global_state_implementation] use std::sync::atomic::{AtomicUsize, Ordering}; use std::cell::UnsafeCell;

// Static mutable variable static mut GLOBAL_COUNTER: usize = 0;

pub fn increment_global_counter() { unsafe { GLOBAL_COUNTER += 1; } }

pub fn get_global_counter() -> usize { unsafe { GLOBAL_COUNTER } }

// Thread-local storage thread_local! { static THREAD_COUNTER: UnsafeCell<usize> = UnsafeCell::new(0); }

pub fn increment_thread_counter() { THREAD_COUNTER.with(|counter| { unsafe { *counter.get() += 1; } }); }

pub fn get_thread_counter() -> usize { THREAD_COUNTER.with(|counter| { unsafe { *counter.get() } }) }

// Atomic global state static ATOMIC_COUNTER: AtomicUsize = AtomicUsize::new(0);

pub fn increment_atomic_counter() { ATOMIC_COUNTER.fetch_add(1, Ordering::SeqCst); }

pub fn get_atomic_counter() -> usize { ATOMIC_COUNTER.load(Ordering::SeqCst) }

// Singleton pattern with unsafe pub struct Singleton { data: UnsafeCell<String>, }

impl Singleton { pub fn new() -> Self { Self { data: UnsafeCell::new(String::new()), } } pub fn set_data(&self, data: String) { unsafe { *self.data.get() = data; } } pub fn get_data(&self) -> String { unsafe { (*self.data.get()).clone() } } }

unsafe impl Send for Singleton {} unsafe impl Sync for Singleton {}

static mut SINGLETON: Option<Singleton> = None;

pub fn get_singleton() -> &'static Singleton { unsafe { if SINGLETON.is_none() { SINGLETON = Some(Singleton::new()); } SINGLETON.as_ref().unwrap() } }

🔄 Safe Abstractions

Wrapping Unsafe Code

[safe_abstractions]
unsafe_wrappers: true
type_safety: true
error_handling: true

[safe_abstractions_implementation] // Safe wrapper around raw pointer pub struct SafePtr<T> { ptr: *mut T, len: usize, }

impl<T> SafePtr<T> { pub fn new(len: usize) -> Self { let layout = std::alloc::Layout::array::<T>(len).unwrap(); let ptr = unsafe { std::alloc::alloc(layout) as *mut T }; Self { ptr, len } } pub fn len(&self) -> usize { self.len } pub fn is_empty(&self) -> bool { self.len == 0 } pub fn get(&self, index: usize) -> Option<&T> { if index < self.len { unsafe { Some(&*self.ptr.add(index)) } } else { None } } pub fn get_mut(&mut self, index: usize) -> Option<&mut T> { if index < self.len { unsafe { Some(&mut *self.ptr.add(index)) } } else { None } } pub fn iter(&self) -> SafePtrIter<T> { SafePtrIter { ptr: self.ptr, len: self.len, index: 0, } } }

impl<T> Drop for SafePtr<T> { fn drop(&mut self) { let layout = std::alloc::Layout::array::<T>(self.len).unwrap(); unsafe { std::alloc::dealloc(self.ptr as *mut u8, layout); } } }

pub struct SafePtrIter<T> { ptr: *mut T, len: usize, index: usize, }

impl<T> Iterator for SafePtrIter<T> { type Item = &'static T; fn next(&mut self) -> Option<Self::Item> { if self.index < self.len { let item = unsafe { &*self.ptr.add(self.index) }; self.index += 1; Some(item) } else { None } } }

// Safe wrapper for FFI pub struct SafeCString { inner: CString, }

impl SafeCString { pub fn new(s: &str) -> Result<Self, std::ffi::NulError> { Ok(Self { inner: CString::new(s)?, }) } pub fn as_ptr(&self) -> *const c_char { self.inner.as_ptr() } pub fn to_string_lossy(&self) -> std::borrow::Cow<str> { self.inner.to_string_lossy() } }

// Safe wrapper for system calls pub struct SafeFile { inner: LowLevelFile, }

impl SafeFile { pub fn open(path: &str) -> Result<Self, std::io::Error> { let file = LowLevelFile::open(path, libc::O_RDWR | libc::O_CREAT, 0o644) .map_err(|e| std::io::Error::from_raw_os_error(e))?; Ok(Self { inner: file }) } pub fn read(&self, buffer: &mut [u8]) -> Result<usize, std::io::Error> { self.inner.read(buffer) .map_err(|e| std::io::Error::from_raw_os_error(e)) } pub fn write(&self, buffer: &[u8]) -> Result<usize, std::io::Error> { self.inner.write(buffer) .map_err(|e| std::io::Error::from_raw_os_error(e)) } }

🎯 Best Practices

1. Safety Contracts

- Document all safety requirements - Use runtime checks when possible - Provide safe wrappers - Test unsafe code thoroughly

2. Memory Safety

- Validate all pointers - Check bounds before access - Use proper alignment - Avoid undefined behavior

3. FFI Safety

- Validate C function contracts - Handle null pointers - Manage memory properly - Use proper calling conventions

4. Error Handling

- Return Result types - Provide meaningful errors - Handle edge cases - Use proper error propagation

5. Testing

- Test unsafe code extensively - Use Miri for validation - Test edge cases - Verify safety contracts

Unsafe Rust in TuskLang provides the power to write low-level code while maintaining the ability to create safe abstractions that leverage Rust's safety guarantees.