Unsafe and raw memory
Beans-এর বেশিরভাগ কোডই safe: কোনো null নেই, indexing check করা, আর ownership
compiler নিজে প্রমাণ করে। যখন raw memory লাগে — কোনো device, কোনো
database page, বা C interop-এর জন্য — তখন একটা unsafe { } block-এ
ঢুকতে হয়। তার ভেতরে কিছু নিচু-স্তরের operation খুলে যায়, আর সেগুলোর safety
নিশ্চিত করার দায় তখন আপনার।
unsafe { let counters: RawPtr<Counter> = RawPtr.alloc(4) // element type's alignment let page: RawPtr<Counter> = RawPtr.alloc_aligned(2, 4096) counters.write(new_value) counters.free()}unsafe operation-টাকে আটকায়, function-কে না। কোনো unsafe fn নেই, তাই
block-টা সবসময় ঠিক সেই call site-এই বসে যেখানে raw operation-টা ঘটছে।
RawPtr
“RawPtr” সেকশনRawPtr<T> হলো primitive integer, float, bool, raw-pointer, fixed-array বা
extern "C" struct/union memory-র দিকে একটা raw typed pointer (এই গড়নগুলো
একটার ভেতর আরেকটা nest হতে পারে)।
বানানো (সবই unsafe):
RawPtr.alloc(count)element type-এর নিজের alignment-এ শূন্য-করা unmanaged storage দেয়।RawPtr.alloc_aligned(count, align)কড়া একটা alignment চায়।alignদুইয়ের ঘাত হতে হবে আর element-এর নিজেরটার চেয়ে দুর্বল না; দুটোই run time-এ check হয়।RawPtr.null()আরRawPtr.from_address(addr)কিছু allocate না করেই pointer value বানায়।
Method (সবই unsafe): read(), write(v), read_volatile(),
write_volatile(v), offset(n), address(), is_null(), element_size(),
element_align(), copy_from(src, n) (overlap হলেও নিরাপদ), fill_zero(n),
free()। integer আর bool pointer sequentially-consistent atomic_load,
atomic_store, atomic_compare_exchange-ও দেয়; integer pointer সাথে যোগ
করে atomic_fetch_add (পুরনো value ফেরত দেয়)।
lifetime, bound, alignment, address-এর বৈধতা, আর প্রতিটা alloc-কে একটা
free-এর সাথে মেলানো — সব দায় আপনার। null-এর উপর কোনো memory operation
করলে panic; বাকি সব আপনার দায়িত্ব। raw pointer copy করা যায়, তাই একটা alias
free করলে বাকিগুলো ঝুলে থাকে।
RawPtr.with_local(inout value, fn(pointer: RawPtr<T>) { ... }) closure-টা
চলার সময়টুকুর জন্য একটা stack value-র দিকে একটা pointer ধার দেয়।
Slice
“Slice” সেকশনSlice<T> হলো raw-compatible memory-র উপর একটা মালিকানা-হীন {pointer, length} view। Slice.from_raw(ptr, len), get, set, indexing,
subslice, as_ptr আর iteration — সবের জন্য unsafe লাগে; read আর write
bound-check করা। কোনো non-empty slice একটা null pointer নাকচ করে। পেছনের
allocation-টা জীবিত রাখতে হবে, আর free-এর পরে view-টা ব্যবহার করা যাবে না।
Fixed array
“Fixed array” সেকশন[T; N] হলো একটা fixed-size inline array (1 <= N <= 4096), যার element
হয় inline scalar, RawPtr, nested-array বা struct। raw pointer-এর উল্টো,
fixed array safe: index check করা, var local-এ element assign করা,
len(), equality আর for iteration — সবই কোনো unsafe ছাড়া। list-আকৃতির
কোনো literal তার ঘোষিত জায়গা থেকেই fixed-array হিসেবে ধরা হয়:
var lanes: [f32; 4] = [1, 2, 3, 4]lanes[0] = 9.0SIMD
“SIMD” সেকশনSIMD vector পরিবার (Simd4f32, Simd4i32, Simd16u8, …) unsafe-এর
ভেতরে পাওয়া যায়। একটা vector-এর নামই তার গড়ন। পুরো operation set-এর জন্য
দেখুন SIMD, array, slice।
Intrinsic আর inline assembly
“Intrinsic আর inline assembly” সেকশনstd.intrinsicহলো নাম-দেওয়া machine operation-এর একটা বন্ধ allowlist (popcount,bswap32,sqrt,fma, …), প্রতিটার জন্যunsafeলাগে। দেখুন std.cpu আর std.intrinsic।std.asmunsafe-এর ভেতরে প্রতি-architecture-এর একটা ছোট assembly template allowlist দেয়। দেখুন std.asm।
একটা পুরো program
“একটা পুরো program” সেকশনallocate করা হয়, লেখা হয়, আবার পড়া হয়, তারপর free করা হয়। প্রতিটা raw ধাপ unsafe
block-এর ভেতরে, আর সেই একটা alloc-কে একটা free মিলিয়ে দেয়:
import std.io
fn main() { unsafe { let cells: RawPtr<i32> = RawPtr.alloc(3) cells.write(10) cells.offset(1).write(20) cells.offset(2).write(30)
let sum: i32 = cells.read() + cells.offset(1).read() + cells.offset(2).read() io.println("sum {sum}")
cells.free() }}যখন সম্ভব, একটা fixed array বা একটা safe collection বেছে নিন: এরা কোনো
unsafe ছাড়াই index check আর নিজে নিজে cleanup দেয়। RawPtr আর Slice
ব্যবহার করুন শুধু device memory, নিজে হাতে সাজানো কোনো file format, বা
C interop-এর জন্য — যেখানে raw layout-টাই আসল কথা।