box_raw_ptr/lib.rs
1/*
2* ____ ____ ____ __
3* / __ )____ _ __/ __ \____ __ __/ __ \/ /______
4* / __ / __ \| |/_/ /_/ / __ `/ | /| / / /_/ / __/ ___/
5* / /_/ / /_/ /> </ _, _/ /_/ /| |/ |/ / ____/ /_/ /
6* /_____/\____/_/|_/_/ |_|\__,_/ |__/|__/_/ \__/_/
7*
8*
9* Copyright (c) 2024 Rocco Zinedine Samuel Jenson
10*
11* Licensed under the MIT License (the "License");
12* you may not use this file except in compliance with the License.
13* You may obtain a copy of the License at
14*
15* https://opensource.org/licenses/MIT
16*
17* Unless required by applicable law or agreed to in writing, software
18* distributed under the License is distributed on an "AS IS" BASIS,
19* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20* See the License for the specific language governing permissions and
21* limitations under the License.
22*/
23
24//! # box_raw_ptr
25//!
26//! box_raw_ptr is a Rust library providing safe abstractions for working with raw pointers (`*const T` and `*mut T`). It ensures proper alignment, bounds checking, and safe memory operations, inspired by Rust's safety principles while allowing interoperability with C-style memory management. NOTE: It is still the user's responcibilty to correctly handle input of length and offset.
27//!
28//! ## Features
29//!
30//! - **Type Safety**: Wrappers (`ConstRawPtr` and `MutRawPtr`) ensure safe usage of raw pointers (`*const T` and `*mut T`).
31//!
32//! - **Bounds Checking**: Methods to check and adjust offsets within allocated memory.
33//!
34//! - **Alignment Guarantees**: Ensures pointers are aligned according to `T`.
35//!
36//! - **Memory Management**: Includes methods for deallocating memory and safely handling null pointers.
37//!
38//! - **Interoperability**: Facilitates safe interaction with memory allocated by C functions or Rust's allocator.
39//!
40//! ## Components
41//!
42//! - **ConstRawPtr**: Provides safe operations on `*const T` pointers, including bounds checking and memory release.
43//!
44//! - **MutRawPtr**: Offers safe operations on `*mut T` pointers, supporting mutable access and memory management.
45//!
46//! ## Usage
47//!
48//! ```rust
49//! use box_raw_ptr::mut_raw_ptr::MutRawPtr; // Import MutRawPtr from box_raw_ptr
50//!
51//! #[link(name = "example", kind = "static")] // Link to a static library "example"
52//! extern "C" { // Declare C functions
53//! fn c_ptr() -> *mut Data; // Declare C function returning a pointer to Data
54//! fn c_ptr2() -> *mut std::ffi::c_int; // Declare C function returning a pointer to std::ffi::c_int
55//! }
56//!
57//! #[repr(C)] // Make Data a C-compatible struct
58//! #[derive(Clone, Copy)] // Derive Copy and Clone traits for Data
59//! struct Data { // Define a struct to represent data
60//! a: i32, // Field of type i32
61//! b: f64, // Field of type f64
62//! }
63//!
64//! fn main() { // Main function starts here
65//! // Example: Import C pointer and write to the allocated data
66//! let mut safeptr: MutRawPtr<Data> = MutRawPtr::new(unsafe { c_ptr() }, /*# of Data Blocks*/ 1, /*offset*/ 0); // Create MutRawPtr with the C pointer
67//!
68//! assert_eq!(16, safeptr.size_of()); // Assert the size of Data is 16 bytes
69//!
70//! safeptr.write_ptr(Data {a: 100, b: 12.0}); // Write to the memory pointed by safeptr
71//!
72//! assert_eq!(100, (safeptr.access().unwrap()).a); // Assert the written value
73//!
74//! // Example: Iteratively Rewrite Values in a Block Of Data (Assuming 5 Blocks of i32)
75//! let mut safeptr: MutRawPtr<_> = MutRawPtr::new( unsafe { c_ptr2() }, 5, 0); // Create MutRawPtr with another C pointer
76//!
77//! for i in 0..=4 { // Iterate 5 times
78//! /* change_offset() is byte indexed */
79//! safeptr.change_offset(i * std::mem::size_of::<i32>()).unwrap();
80//! safeptr.write_ptr(100 as i32).unwrap(); // Write a value (100) to the current memory location
81//! println!("{}", safeptr.access().unwrap()); // Print the value at the current offset
82//! }
83//! }
84//!
85//! ```
86//!
87//! ## Safety Considerations
88//!
89//! - **Unsafe Contexts**: Use of raw pointers inherently involves unsafe operations.
90//!
91//! - **Memory Safety**: Ensure proper initialization and alignment of pointers.
92//!
93//! - **Dropping Pointers**: Manually dropping pointers can lead to undefined behavior if used afterward.
94//!
95//! ## Installation
96//!
97//! Add the following to your `Cargo.toml`:
98//!
99//! ```toml
100//! [dependencies]
101//! box_raw_ptr = "2.2.0"
102//! ```
103//!
104//! ## Documentation
105//!
106//! For detailed API documentation, refer to [docs.rs](https://docs.rs/box_raw_ptr/latest/box_raw_ptr/).
107//!
108//! ## License
109//!
110//! MIT License
111//!
112//! Copyright (c) 2024 Rocco Zinedine Samuel Jenson
113//!
114//! Permission is hereby granted, free of charge, to any person obtaining a copy
115//! of this software and associated documentation files (the "Software"), to deal
116//! in the Software without restriction, including without limitation the rights
117//! to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
118//! copies of the Software, and to permit persons to whom the Software is
119//! furnished to do so, subject to the following conditions:
120//!
121//! The above copyright notice and this permission notice shall be included in all
122//! copies or substantial portions of the Software.
123//!
124//! THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
125//! IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
126//! FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
127//! AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
128//! LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
129//! OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
130//! SOFTWARE.
131
132/*
133Imports C_Global_Allocator to library
134See allocator.rs and allocator.c for implementation
135Note: ALL LIBRARY HEAP ALLOCATIONS MANAGED BY MALLOC AND FREE
136*/
137mod allocator;
138
139pub mod const_raw_ptr {
140 use std::marker::{Copy, Send, Sync};
141
142 /// A wrapper for `*const T` providing methods for safely working with constant raw pointers.
143 ///
144 /// `ConstRawPtr` ensures that the raw pointer is properly aligned and provides utility methods
145 /// for checking bounds, changing offsets, and other common pointer operations.
146 ///
147 /// Fields:
148 /// - `ptr: *const T`: A raw constant pointer to the data.
149 /// - `memory_length: usize`: The length of the memory block in elements of T that `ptr` points to.
150 /// - `offset: usize`: The current position within the memory block.
151 ///
152 /// Notes:
153 /// - `memory_length` is not zero-based indexed.
154 /// - `offset` is zero-based indexed.
155 ///
156 /// # Safety
157 ///
158 /// Working with raw pointers is inherently unsafe. Ensure that the memory pointed to by `ptr` is valid
159 /// and properly aligned before using this struct.
160 pub struct ConstRawPtr<T>
161 where T: Sized + Copy + Send + Sync
162 {
163 ptr: *const T,
164 memory_length: usize,
165 offset: usize,
166 }
167
168 impl<T: Sized + Copy + Send + Sync> ConstRawPtr<T> {
169 /// Allocates memory for an array of `memory_length` elements of type `T` and returns a const raw pointer to the allocated memory.
170 ///
171 /// # Parameters
172 ///
173 /// - `memory_length`: The number of elements of type `T` to allocate memory for. Must be greater than 0.
174 /// - `offset`: The initial offset within the allocated memory, typically starting at 0.
175 /// - `data`: A vector of values of type `T` that will be written to the newly allocated memory. The number of elements in `data` must not exceed `memory_length`, and the vector cannot be empty.
176 ///
177 /// # Returns
178 ///
179 /// - `Some(ConstRawPtr<T>)`: A const raw pointer to the allocated memory if the allocation is successful and the data is written correctly.
180 /// - `None`: If `memory_length` is 0 or less, or if the data vector is not within the bounds of the allocated memory (either because it is empty or has more elements than `memory_length`).
181 ///
182 /// # Panics
183 ///
184 /// This function may panic if the alignment or size parameters are invalid. Specifically, the following conditions may cause a panic:
185 /// - Alignment being zero or not a power of two.
186 /// - The size, when rounded up to the nearest multiple of alignment, overflows `isize` (i.e., the rounded value must be less than or equal to `isize::MAX`).
187 ///
188 /// # Safety
189 ///
190 /// This function is marked `unsafe` because it performs raw memory allocation. The caller is responsible for ensuring that:
191 /// - The memory is properly initialized and used correctly.
192 /// - Proper alignment and size are provided, as invalid values may cause undefined behavior.
193 /// - The `data` vector contains values that will be written to the allocated memory safely, as raw pointer operations do not include bounds checking.
194 ///
195 /// # Example
196 ///
197 /// ```rust
198 /// let alloc: *const i32 = unsafe {
199 /// ConstRawPtr::c_malloc(vec![1, 2, 3], 5, 1).unwrap();
200 /// };
201 /// ```
202 pub unsafe fn c_malloc(data: Vec<T>, memory_length: usize, offset: usize) -> Option<ConstRawPtr<T>> {
203 if memory_length == 0 || offset >= memory_length || data.len() == 0 || data.len() > memory_length {
204 return None;
205 }
206
207 let size: usize = std::mem::size_of::<T>() * memory_length;
208 let align: usize = std::mem::align_of::<T>();
209 let layout: std::alloc::Layout = std::alloc::Layout::from_size_align(size, align).expect("Invalid alignment or size parameters.");
210
211 unsafe {
212 let alloc: *mut T = std::alloc::alloc(layout) as *mut T;
213
214 if alloc.is_null() {
215 return None;
216 }
217
218 for (idx, value) in data.into_iter().enumerate() {
219 std::ptr::write(alloc.add(idx), value);
220 }
221
222 Some(ConstRawPtr::new(alloc as *const T, memory_length, offset))
223 }
224 }
225
226 /// Creates a new `ConstRawPtr` with the given pointer, memory length, and offset. Make sure the length and offset are correct from C or std::alloc
227 ///
228 /// This method ensures that the pointer is properly aligned and that the offset is within the bounds
229 /// of the allocated memory length.
230 ///
231 /// # Panics
232 ///
233 /// Panics if the pointer is not aligned to `T` or if the offset is not within the bounds of the memory length.
234 ///
235 /// # Examples
236 ///
237 /// ```rust
238 /// let alloc_ptr: *const i32 = ...; // Assume this is a properly allocated and aligned pointer either from C or using Rust's std::alloc::alloc and std::alloc::Layout otherwise it will panic.
239 /// let ptr = ConstRawPtr::new(alloc_ptr, 1, 1);
240 /// ```
241 #[inline]
242 pub fn new(ptr: *const T, memory_length: usize, offset: usize) -> Self {
243 assert!((ptr as usize) % std::mem::align_of::<T>() == 0, "box_raw_ptr Err: Memory Not Aligned");
244 assert!(offset < memory_length, "box_raw_ptr Err: Offset Is Not Within Bounds");
245 Self { ptr, memory_length, offset, }
246 }
247
248 /// Creates a new `ConstRawPtr` with a null pointer and zero memory length and offset.
249 ///
250 /// This is useful for creating a placeholder `ConstRawPtr` that can later be assigned a valid pointer.
251 ///
252 /// # Examples
253 ///
254 /// ```rust
255 /// let null_ptr = ConstRawPtr::<i32>::nullptr();
256 /// ```
257 #[inline]
258 pub fn nullptr() -> Self {
259 Self { ptr: std::ptr::null(), memory_length: 0, offset: 0 }
260 }
261
262 /// Manually drops the `ConstRawPtr` instance.
263 ///
264 /// # Safety
265 ///
266 /// This function is unsafe because it drops the instance manually, which can lead to undefined behavior
267 /// if the instance is used after being dropped.
268 ///
269 /// # Examples
270 ///
271 /// ```rust
272 /// unsafe {
273 /// ptr.manual_drop();
274 /// }
275 /// ```
276 #[inline]
277 pub unsafe fn manual_drop(self) -> () {
278 drop(self);
279 }
280
281 /// Checks if the current offset is within the bounds of the memory length.
282 ///
283 /// This method ensures that the pointer is pointing to a valid position within the allocated memory block.
284 ///
285 /// # Examples
286 ///
287 /// ```rust
288 /// assert!(ptr.check_bounds());
289 /// ```
290 #[inline]
291 pub fn check_bounds(&self) -> bool {
292 (0..=self.memory_length).contains(&self.offset)
293 }
294
295 /// Checks if the pointer is not null and properly aligned.
296 ///
297 /// This method ensures that the pointer is valid and meets the alignment requirements of `T`.
298 ///
299 /// # Examples
300 ///
301 /// ```rust
302 /// assert!(ptr.check_ptr());
303 /// ```
304 pub fn check_ptr(&self) -> bool {
305 if self.ptr.is_null() {
306 return false;
307 }
308 let align: usize = std::mem::align_of::<T>();
309 (self.ptr as usize) % align == 0
310 }
311
312 /// Returns the current offset.
313 ///
314 /// This method provides the current offset within the memory block.
315 ///
316 /// # Examples
317 ///
318 /// ```rust
319 /// let offset = ptr.check_offset();
320 /// ```
321 pub fn check_offset(&self) -> usize {
322 self.offset
323 }
324
325 /// Returns the current memory length.
326 ///
327 /// This method provides the total length of the memory block that the pointer points to.
328 ///
329 /// # Examples
330 ///
331 /// ```rust
332 /// let length = ptr.check_memory_length();
333 /// ```
334 pub fn check_memory_length(&self) -> usize {
335 self.memory_length
336 }
337
338 /// Changes the offset by a given byte index, if the resulting offset is within bounds.
339 ///
340 /// This method allows you to move the pointer by a specified index within the memory block,
341 /// ensuring that the new offset is within bounds.
342 ///
343 /// # Examples
344 ///
345 /// ```rust
346 /// assert!(ptr.change_offset(2).is_some());
347 /// ```
348 pub fn change_offset(&mut self, offset: isize) -> Option<()> {
349 if !self.check_ptr() {
350 return None;
351 }
352
353 let new_offset: isize = self.offset as isize + offset;
354
355 if new_offset >= 0 && new_offset < self.memory_length as isize {
356 let new_ptr: *const T = unsafe { self.ptr.byte_offset(offset) };
357
358 self.offset = new_offset as usize;
359
360 self.ptr = new_ptr;
361 Some(())
362 } else {
363 None
364 }
365 }
366
367 /// Changes the memory length, if the new length is valid.
368 ///
369 /// # Safety
370 ///
371 /// This function is unsafe because it directly modifies the memory length. Ensure that the new length is
372 /// valid and that the memory block can accommodate the new length.
373 ///
374 /// # Examples
375 ///
376 /// ```rust
377 /// unsafe {
378 /// assert!(ptr.change_memory_length(10).is_some());
379 /// }
380 /// ```
381 pub unsafe fn change_memory_length(&mut self, memory_length: usize) -> Option<()> {
382 if memory_length <= 0 || self.offset >= memory_length {
383 return None;
384 }
385
386 self.memory_length = memory_length;
387 Some(())
388 }
389
390 /// Releases the pointer and returns the value it points to, if valid.
391 ///
392 /// This method takes ownership of the pointer and returns the value it points to, ensuring that
393 /// the pointer is valid and properly aligned.
394 ///
395 /// # Examples
396 ///
397 /// ```rust
398 /// let value = ptr.release_ptr().unwrap();
399 /// ```
400 pub fn release_ptr(self) -> Option<T> {
401 if self.check_ptr() {
402 unsafe {
403 let ptr: T = *self.ptr;
404 drop(self);
405 Some(ptr)
406 }
407 } else {
408 None
409 }
410 }
411
412 /// Sets the pointer to null and resets the memory length and offset.
413 ///
414 /// This method is useful for invalidating a pointer and ensuring that it no longer points to any memory.
415 ///
416 /// # Examples
417 ///
418 /// ```rust
419 /// ptr.set_null();
420 /// ```
421 #[inline]
422 pub fn set_null(&mut self) -> () {
423 if self.check_ptr() {
424 self.memory_length = 0;
425 self.offset = 0;
426 self.ptr = std::ptr::null();
427 }
428 }
429
430 /// Returns the memory address of the pointer as a hexadecimal string.
431 ///
432 /// This method is useful for debugging and logging purposes to inspect the raw memory address.
433 ///
434 /// # Examples
435 ///
436 /// ```rust
437 /// let address = ptr.memory_address();
438 /// ```
439 #[inline]
440 pub fn memory_address(&self) -> usize {
441 self.ptr as usize
442 }
443
444 /// Converts the `ConstRawPtr` to a mutable pointer.
445 ///
446 /// This method creates a mutable version of the `ConstRawPtr`, which allows for modification of the
447 /// underlying data.
448 ///
449 /// # Examples
450 ///
451 /// ```rust
452 /// let mut_ptr = ptr.as_mut();
453 /// ```
454 #[inline]
455 pub fn as_mut(&self) -> super::mut_raw_ptr::MutRawPtr<T> {
456 super::mut_raw_ptr::MutRawPtr::new(self.ptr as *mut T, self.memory_length, self.offset)
457 }
458
459 /// Unwraps the pointer and returns the value it points to, if valid.
460 ///
461 /// This method returns the value that the pointer points to, ensuring that the pointer is valid and
462 /// properly aligned.
463 ///
464 /// # Examples
465 ///
466 /// ```rust
467 /// let value = ptr.access().unwrap();
468 /// ```
469 pub fn access(&self) -> Option<T> {
470 if self.check_ptr() {
471 Some( unsafe { *self.ptr } )
472 } else {
473 None
474 }
475 }
476
477 /// Returns a reference to the value the pointer points to, if valid.
478 ///
479 /// This method provides a reference to the value that the pointer points to, ensuring that the pointer
480 /// is valid and properly aligned.
481 ///
482 /// # Examples
483 ///
484 /// ```rust
485 /// let reference = ptr.ref_const().unwrap();
486 /// ```
487 pub fn ref_const(&self) -> Option<&T> {
488 if self.check_ptr() {
489 Some( unsafe { & *self.ptr } )
490 } else {
491 None
492 }
493 }
494
495 /// Checks if the pointer is null.
496 ///
497 /// This method determines if the pointer is null, which is useful for validation and error checking.
498 ///
499 /// # Examples
500 ///
501 /// ```rust
502 /// assert!(ptr.is_null());
503 /// ```
504 #[inline]
505 pub fn is_null(&self) -> bool {
506 self.ptr.is_null()
507 }
508
509 /// Returns the size of the type `T`.
510 ///
511 /// This method provides the size of the type `T` in bytes, which is useful for memory allocation and
512 /// pointer arithmetic.
513 ///
514 /// # Examples
515 ///
516 /// ```rust
517 /// let size = ConstRawPtr::<i32>::size_of();
518 /// ```
519 #[inline]
520 pub fn size_of() -> usize {
521 std::mem::size_of::<T>()
522 }
523
524 /// Casts the pointer to a `ConstRawPtr` of another type `U`.
525 ///
526 /// This method allows you to reinterpret the pointer as a different type, ensuring that the new type
527 /// is compatible and properly aligned.
528 ///
529 /// # Examples
530 ///
531 /// ```rust
532 /// let new_ptr = ptr.cast_ptr::<f64>().unwrap();
533 /// ```
534 pub fn cast_ptr<U: Sized + Copy + Send + Sync>(&self) -> Option<ConstRawPtr<U>> {
535 if !self.ptr.is_null() {
536 Some(ConstRawPtr {
537 ptr: self.ptr as *const U, memory_length: self.memory_length, offset: self.offset
538 })
539 } else {
540 None
541 }
542 }
543 }
544
545 impl<T: Sized + Copy + Send + Sync> Clone for ConstRawPtr<T> {
546 fn clone(&self) -> Self {
547 Self { ptr: self.ptr.clone(), memory_length: self.memory_length, offset: self.offset }
548 }
549 }
550
551 impl<T: Sized + Copy + Send + Sync> Drop for ConstRawPtr<T> {
552 fn drop(&mut self) {
553 if self.check_ptr() {
554 unsafe {
555 let layout: std::alloc::Layout = std::alloc::Layout::new::<T>();
556 std::alloc::dealloc(self.ptr as *mut u8, layout);
557 }
558 }
559 }
560 }
561}
562
563pub mod mut_raw_ptr {
564 use std::marker::{Copy, Send, Sync};
565
566 /// A wrapper for `*mut T` providing methods for safely working with constant raw pointers.
567 ///
568 /// `MutRawPtr` ensures that the raw pointer is properly aligned and provides utility methods
569 /// for checking bounds, changing offsets, and other common pointer operations.
570 ///
571 /// Fields:
572 /// - `ptr: *mut T`: A raw constant pointer to the data.
573 /// - `memory_length: usize`: The length of the memory block in elements of T that `ptr` points to.
574 /// - `offset: usize`: The current position within the memory block.
575 ///
576 /// Notes:
577 /// - `memory_length` is not zero-based indexed.
578 /// - `offset` is zero-based indexed.
579 ///
580 /// # Safety
581 ///
582 /// Working with raw pointers is inherently unsafe. Ensure that the memory pointed to by `ptr` is valid
583 /// and properly aligned before using this struct.
584 pub struct MutRawPtr<T>
585 where T: Sized + Copy + Clone + Send + Sync
586 {
587 ptr: *mut T,
588 memory_length: usize,
589 offset: usize,
590 }
591
592 impl<T: Sized + Copy + Clone + Send + Sync> MutRawPtr<T> {
593 /// Allocates memory for an array of `memory_length` elements of type `T` and returns a mutable raw pointer to the allocated memory.
594 ///
595 /// # Parameters
596 ///
597 /// - `memory_length`: The number of elements of type `T` to allocate memory for. Must be greater than 0.
598 /// - `offset`: The initial offset within the allocated memory, typically starting at 0.
599 /// - `data`: A vector of values of type `T` that will be written to the newly allocated memory. The number of elements in `data` must not exceed `memory_length`, and the vector cannot be empty.
600 ///
601 /// # Returns
602 ///
603 /// - `Some(MutRawPtr<T>)`: A mutable raw pointer to the allocated memory if the allocation is successful and the data is written correctly.
604 /// - `None`: If `memory_length` is 0 or less, or if the data vector is not within the bounds of the allocated memory (either because it is empty or has more elements than `memory_length`).
605 ///
606 /// # Panics
607 ///
608 /// This function may panic if the alignment or size parameters are invalid. Specifically, the following conditions may cause a panic:
609 /// - Alignment being zero or not a power of two.
610 /// - The size, when rounded up to the nearest multiple of alignment, overflows `isize` (i.e., the rounded value must be less than or equal to `isize::MAX`).
611 ///
612 /// # Safety
613 ///
614 /// This function is marked `unsafe` because it performs raw memory allocation. The caller is responsible for ensuring that:
615 /// - The memory is properly initialized and used correctly.
616 /// - Proper alignment and size are provided, as invalid values may cause undefined behavior.
617 /// - The `data` vector contains values that will be written to the allocated memory safely, as raw pointer operations do not include bounds checking.
618 ///
619 /// # Example
620 ///
621 /// ```rust
622 /// let alloc: *const i32 = unsafe {
623 /// MutRawPtr::c_malloc(vec![1, 2, 3], 5, 1).unwrap();
624 /// };
625 /// ```
626 pub unsafe fn c_malloc(data: Vec<T>, memory_length: usize, offset: usize) -> Option<MutRawPtr<T>> {
627 if memory_length == 0 || offset >= memory_length || data.len() == 0 || data.len() > memory_length {
628 return None;
629 }
630
631 let size: usize = std::mem::size_of::<T>() * memory_length;
632 let align: usize = std::mem::align_of::<T>();
633 let layout: std::alloc::Layout = std::alloc::Layout::from_size_align(size, align).expect("Invalid alignment or size parameters.");
634
635 unsafe {
636 let alloc: *mut T = std::alloc::alloc(layout) as *mut T;
637
638 if alloc.is_null() {
639 return None;
640 }
641
642 for (idx, value) in data.into_iter().enumerate() {
643 std::ptr::write(alloc.add(idx), value);
644 }
645
646 Some(MutRawPtr::new(alloc, memory_length, offset))
647 }
648 }
649
650 /// Creates a new `MutRawPtr` with the given pointer, memory length, and offset. Make sure the length and offset are correct from C or std::alloc
651 ///
652 /// This method ensures that the pointer is properly aligned and that the offset is within the bounds
653 /// of the allocated memory length.
654 ///
655 /// # Panics
656 ///
657 /// Panics if the pointer is not aligned to `T` or if the offset is not within the bounds of the memory length.
658 ///
659 /// # Examples
660 ///
661 /// ```rust
662 /// let alloc_ptr: *mut i32 = ...; // Assume this is a properly allocated and aligned pointer either from C or using Rust's std::alloc::alloc and std::alloc::Layout otherwise it will panic.
663 /// let ptr = MutRawPtr::new(alloc_ptr, 1, 1);
664 /// ```
665 #[inline]
666 pub fn new(ptr: *mut T, memory_length: usize, offset: usize) -> Self {
667 assert!((ptr as usize) % std::mem::align_of::<T>() == 0, "box_raw_ptr Err: Memory Not Aligned");
668 assert!(offset < memory_length, "box_raw_ptr Err: Offset Is Not Within Bounds");
669 Self { ptr, memory_length, offset, }
670 }
671
672 /// Creates a new `MutRawPtr` with a null mutable pointer and zero memory length and offset.
673 ///
674 /// This is useful for creating a placeholder `MutRawPtr` that can later be assigned a valid mutable pointer.
675 ///
676 /// # Examples
677 ///
678 /// ```rust
679 /// let null_ptr = MutRawPtr::<i32>::nullptr();
680 /// ```
681 #[inline]
682 pub fn nullptr() -> Self {
683 Self { ptr: std::ptr::null_mut(), memory_length: 0, offset: 0 }
684 }
685
686 /// Manually drops the `MutRawPtr` instance.
687 ///
688 /// # Safety
689 ///
690 /// This function is unsafe because it drops the instance manually, which can lead to undefined behavior
691 /// if the instance is used after being dropped.
692 ///
693 /// # Examples
694 ///
695 /// ```rust
696 /// unsafe {
697 /// mut_ptr.manual_drop();
698 /// }
699 /// ```
700 #[inline]
701 pub unsafe fn manual_drop(self) -> () {
702 drop(self);
703 }
704
705 /// Checks if the current offset is within the bounds of the memory length.
706 ///
707 /// This method ensures that the mutable pointer is pointing to a valid position within the allocated memory block.
708 ///
709 /// # Examples
710 ///
711 /// ```rust
712 /// assert!(mut_ptr.check_bounds());
713 /// ```
714 #[inline]
715 pub fn check_bounds(&self) -> bool {
716 (0..=self.memory_length).contains(&self.offset)
717 }
718
719 /// Checks if the mutable pointer is not null and properly aligned.
720 ///
721 /// This method ensures that the mutable pointer is valid and meets the alignment requirements of `T`.
722 ///
723 /// # Examples
724 ///
725 /// ```rust
726 /// assert!(mut_ptr.check_ptr());
727 /// ```
728 pub fn check_ptr(&self) -> bool {
729 if self.ptr.is_null() {
730 return false;
731 }
732 let align: usize = std::mem::align_of::<T>();
733 (self.ptr as usize) % align == 0
734 }
735
736 /// Returns the current offset.
737 ///
738 /// This method provides the current offset within the memory block.
739 ///
740 /// # Examples
741 ///
742 /// ```rust
743 /// let offset = mut_ptr.check_offset();
744 /// ```
745 pub fn check_offset(&self) -> usize {
746 self.offset
747 }
748
749 /// Returns the current memory length.
750 ///
751 /// This method provides the total length of the memory block that the mutable pointer points to.
752 ///
753 /// # Examples
754 ///
755 /// ```rust
756 /// let length = mut_ptr.check_memory_length();
757 /// ```
758 pub fn check_memory_length(&self) -> usize {
759 self.memory_length
760 }
761
762 /// Changes the offset by a given byte index, if the resulting offset is within bounds.
763 ///
764 /// This method allows you to move the mutable pointer by a specified index within the memory block,
765 /// ensuring that the new offset is within bounds.
766 ///
767 /// # Examples
768 ///
769 /// ```rust
770 /// assert!(mut_ptr.change_offset(2).is_some());
771 /// ```
772 pub fn change_offset(&mut self, offset: isize) -> Option<()> {
773 if !self.check_ptr() {
774 return None;
775 }
776
777 let new_offset: isize = self.offset as isize + offset;
778
779 if new_offset >= 0 && new_offset < self.memory_length as isize {
780 let new_ptr: *mut T = unsafe { self.ptr.byte_offset(offset) };
781
782 self.offset = new_offset as usize;
783
784 self.ptr = new_ptr;
785 Some(())
786 } else {
787 None
788 }
789 }
790
791 /// Changes the memory length, if the new length is valid.
792 ///
793 /// # Examples
794 ///
795 /// ```rust
796 /// assert!(mut_ptr.change_memory_length(10).is_some());
797 /// ```
798 pub fn change_memory_length(&mut self, memory_length: usize) -> Option<()> {
799 if memory_length <= 0 || self.offset > memory_length {
800 return None;
801 }
802
803 self.memory_length = memory_length;
804 Some(())
805 }
806
807 /// Releases the mutable pointer and returns the value it points to, if valid.
808 ///
809 /// This method takes ownership of the mutable pointer and returns the value it points to, ensuring that
810 /// the pointer is valid and properly aligned.
811 ///
812 /// # Examples
813 ///
814 /// ```rust
815 /// let value = mut_ptr.release_ptr().unwrap();
816 /// ```
817 pub fn release_ptr(self) -> Option<T> {
818 if self.check_ptr() {
819 unsafe {
820 let ptr: T = *self.ptr;
821 drop(self);
822 Some(ptr)
823 }
824 } else {
825 None
826 }
827 }
828
829 /// Sets the mutable pointer to null and resets the memory length and offset.
830 ///
831 /// This method is useful for invalidating a mutable pointer and ensuring that it no longer points to any memory.
832 ///
833 /// # Examples
834 ///
835 /// ```rust
836 /// mut_ptr.set_null();
837 /// ```
838 #[inline]
839 pub fn set_null(&mut self) -> () {
840 if self.check_ptr() {
841 self.memory_length = 0;
842 self.offset = 0;
843 self.ptr = std::ptr::null_mut();
844 }
845 }
846
847 /// Returns the memory address of the mutable pointer as a hexadecimal string.
848 ///
849 /// This method is useful for debugging and logging purposes to inspect the raw memory address.
850 ///
851 /// # Examples
852 ///
853 /// ```rust
854 /// let address = mut_ptr.memory_address();
855 /// ```
856 #[inline]
857 pub fn memory_address(&self) -> usize {
858 self.ptr as usize
859 }
860
861 /// Converts the `MutRawPtr` to a constant pointer (`ConstRawPtr`).
862 ///
863 /// This method creates a constant version of the `MutRawPtr`, which allows for read-only access to the
864 /// underlying data.
865 ///
866 /// # Examples
867 ///
868 /// ```rust
869 /// let const_ptr = mut_ptr.as_const();
870 /// ```
871 pub fn as_const(&self) -> super::const_raw_ptr::ConstRawPtr<T> {
872 super::const_raw_ptr::ConstRawPtr::new(self.ptr as *const T, self.memory_length, self.offset)
873 }
874
875 /// Unwraps the mutable pointer and returns the value it points to, if valid.
876 ///
877 /// This method returns the value that the mutable pointer points to, ensuring that the pointer is valid and
878 /// properly aligned.
879 ///
880 /// # Examples
881 ///
882 /// ```rust
883 /// let value = mut_ptr.access().unwrap();
884 /// ```
885 pub fn access(&self) -> Option<T> {
886 if self.check_ptr() {
887 Some( unsafe { *self.ptr } )
888 } else {
889 None
890 }
891 }
892
893 /// Returns a reference to the value the mutable pointer points to, if valid.
894 ///
895 /// This method provides a reference to the value that the mutable pointer points to, ensuring that the pointer
896 /// is valid and properly aligned.
897 ///
898 /// # Examples
899 ///
900 /// ```rust
901 /// let reference = mut_ptr.ref_const().unwrap();
902 /// ```
903 pub fn ref_const(&self) -> Option<&T> {
904 if self.check_ptr() {
905 Some( unsafe { & *self.ptr } )
906 } else {
907 None
908 }
909 }
910
911 /// Returns a mutable reference to the value the mutable pointer points to, if valid.
912 ///
913 /// This method provides a mutable reference to the value that the mutable pointer points to, ensuring that
914 /// the pointer is valid and properly aligned.
915 ///
916 /// # Examples
917 ///
918 /// ```rust
919 /// let mut reference = mut_ptr.ref_mut().unwrap();
920 /// *reference = 42;
921 /// ```
922 pub fn ref_mut(&self) -> Option<&mut T> {
923 if self.check_ptr() {
924 unsafe { Some(&mut *self.ptr) }
925 } else {
926 None
927 }
928 }
929
930 /// Checks if the mutable pointer is null.
931 ///
932 /// This method determines if the mutable pointer is null, which is useful for validation and error checking.
933 ///
934 /// # Examples
935 ///
936 /// ```rust
937 /// assert!(mut_ptr.is_null());
938 /// ```
939 #[inline]
940 pub fn is_null(&self) -> bool {
941 self.ptr.is_null()
942 }
943
944 /// Returns the size of the type `T`.
945 ///
946 /// This method provides the size of the type `T` in bytes, which is useful for memory allocation and
947 /// pointer arithmetic.
948 ///
949 /// # Examples
950 ///
951 /// ```rust
952 /// let size = mut_ptr.size_of();
953 /// ```
954 #[inline]
955 pub fn size_of(&self) -> usize {
956 std::mem::size_of::<T>()
957 }
958
959 /// Casts the mutable pointer to a `MutRawPtr` of another type `U`.
960 ///
961 /// This method allows you to reinterpret the mutable pointer as a different type, ensuring that the new type
962 /// is compatible and properly aligned.
963 ///
964 /// # Examples
965 ///
966 /// ```rust
967 /// let new_ptr = mut_ptr.cast_ptr::<f64>().unwrap();
968 /// ```
969 pub fn cast_ptr<U: Sized + Copy + Send + Sync>(&self) -> Option<MutRawPtr<U>> {
970 if !self.ptr.is_null() {
971 Some(MutRawPtr {
972 ptr: self.ptr as *mut U,
973 memory_length: self.memory_length,
974 offset: self.offset,
975 })
976 } else {
977 None
978 }
979 }
980
981 /// Writes a value into the memory location pointed to by the mutable pointer, and drops original value.
982 ///
983 /// This method writes a value into the memory location pointed to by the mutable pointer, ensuring that
984 /// the pointer is valid and properly aligned.
985 ///
986 /// # Examples
987 ///
988 /// ```rust
989 /// mut_ptr.write_ptr(42);
990 /// ```
991 pub fn write_ptr(&mut self, src: T) -> Option<()> {
992 if !self.check_ptr() {
993 return None;
994 }
995 unsafe {
996 std::ptr::write(self.ptr, src);
997 }
998 Some(())
999 }
1000 }
1001
1002 impl<T: Sized + Copy + Send + Sync> Clone for MutRawPtr<T> {
1003 fn clone(&self) -> Self {
1004 Self { ptr: self.ptr.clone(), memory_length: self.memory_length, offset: self.offset }
1005 }
1006 }
1007
1008 impl<T: Sized + Copy + Send + Sync> Drop for MutRawPtr<T> {
1009 fn drop(&mut self) {
1010 if self.check_ptr() {
1011 unsafe {
1012 let layout: std::alloc::Layout = std::alloc::Layout::new::<T>();
1013 std::alloc::dealloc(self.ptr as *mut u8, layout);
1014 }
1015 }
1016 }
1017 }
1018}
1019
1020#[cfg(test)]
1021mod box_raw_ptr_tests {
1022 use super::mut_raw_ptr::MutRawPtr;
1023
1024 #[test]
1025 fn c_allocator_test() -> () {
1026 /* Tests If Allocator Works */
1027 let alloc: *mut _ = unsafe { std::alloc::alloc(std::alloc::Layout::new::<i32>()) as *mut i32 };
1028 let _ = MutRawPtr::new(alloc, 1, 0);
1029 }
1030}