Skip to main content

osal_rs/
utils.rs

1/***************************************************************************
2 *
3 * osal-rs
4 * Copyright (C) 2023/2026 Antonio Salsi <passy.linux@zresa.it>
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 *
18 ***************************************************************************/
19
20//! Utility types and functions for OSAL-RS.
21//!
22//! This module contains common types, error definitions, and helper functions
23//! used throughout the library.
24
25use core::cell::UnsafeCell;
26use core::ffi::{CStr, c_char, c_void};
27use core::str::{from_utf8_mut, FromStr};
28use core::fmt::{Debug, Display}; 
29use core::ops::{Deref, DerefMut};
30use core::time::Duration;
31
32use alloc::ffi::CString;
33use alloc::format;
34use alloc::string::{String, ToString};
35use alloc::sync::Arc;
36use alloc::vec::Vec;
37
38#[cfg(not(feature = "serde"))]
39use crate::os::{Deserialize, Serialize};
40
41#[cfg(feature = "serde")]
42use osal_rs_serde::{Deserialize, Serialize};
43
44use crate::os::{AsSyncStr, Mutex};
45
46/// Error types for OSAL-RS operations.
47///
48/// Represents all possible error conditions that can occur when using
49/// the OSAL-RS library.
50///
51/// # Examples
52///
53/// ```ignore
54/// use osal_rs::os::{Queue, QueueFn};
55/// use osal_rs::utils::Error;
56/// 
57/// match Queue::new(10, 32) {
58///     Ok(queue) => { /* use queue */ },
59///     Err(Error::OutOfMemory) => println!("Failed to allocate queue"),
60///     Err(e) => println!("Other error: {:?}", e),
61/// }
62/// ```
63#[derive(Debug, Clone, PartialEq, Eq, Hash)]
64pub enum Error {
65    /// Insufficient memory to complete operation
66    OutOfMemory,
67    /// Queue send operation timed out
68    QueueSendTimeout,
69    /// Queue receive operation timed out
70    QueueReceiveTimeout,
71    /// Mutex operation timed out
72    MutexTimeout,
73    /// Failed to acquire mutex lock
74    MutexLockFailed,
75    /// Generic timeout error
76    Timeout,
77    /// Queue is full and cannot accept more items
78    QueueFull,
79    /// String conversion failed
80    StringConversionError,
81    /// Thread/task not found
82    TaskNotFound,
83    /// Invalid queue size specified
84    InvalidQueueSize,
85    /// Null pointer encountered
86    NullPtr,
87    /// Requested item not found
88    NotFound,
89    /// Index out of bounds
90    OutOfIndex,
91    /// Invalid type for operation
92    InvalidType,
93    /// No data available
94    Empty,
95    /// Write error occurred
96    WriteError(&'static str),
97    /// Read error occurred
98    ReadError(&'static str),
99    /// Return error with code
100    ReturnWithCode(i32),
101    /// Unhandled error with description
102    Unhandled(&'static str),
103    /// Unhandled error with description owned
104    UnhandledOwned(String)
105}
106
107impl Display for Error {
108    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
109        use Error::*;
110
111        match self {
112            OutOfMemory => write!(f, "Out of memory"),
113            QueueSendTimeout => write!(f, "Queue send timeout"),
114            QueueReceiveTimeout => write!(f, "Queue receive timeout"),
115            MutexTimeout => write!(f, "Mutex timeout"),
116            MutexLockFailed => write!(f, "Mutex lock failed"),
117            Timeout => write!(f, "Operation timeout"),
118            QueueFull => write!(f, "Queue full"),
119            StringConversionError => write!(f, "String conversion error"),
120            TaskNotFound => write!(f, "Task not found"),
121            InvalidQueueSize => write!(f, "Invalid queue size"),
122            NullPtr => write!(f, "Null pointer encountered"),
123            NotFound => write!(f, "Item not found"),
124            OutOfIndex => write!(f, "Index out of bounds"),
125            InvalidType => write!(f, "Invalid type for operation"),
126            Empty => write!(f, "No data available"),
127            WriteError(desc) => write!(f, "Write error occurred: {}", desc),
128            ReadError(desc) => write!(f, "Read error occurred: {}", desc),
129            ReturnWithCode(code) => write!(f, "Return with code: {}", code),
130            Unhandled(desc) => write!(f, "Unhandled error: {}", desc),
131            UnhandledOwned(desc) => write!(f, "Unhandled error owned: {}", desc),
132        }
133    }
134}
135
136
137/// CPU register size enumeration.
138///
139/// Identifies whether the target CPU uses 32-bit or 64-bit registers.
140/// This is used for platform-specific tick count overflow handling.
141#[derive(PartialEq, Eq, Clone, Copy, Debug)]
142pub enum CpuRegisterSize {
143    /// 64-bit CPU registers
144    Bit64,
145    /// 32-bit CPU registers
146    Bit32
147}
148
149/// Boolean type compatible with RTOS return values.
150///
151/// Many RTOS functions return 0 for success and non-zero for failure.
152/// This type provides a Rust-idiomatic way to work with such values.
153///
154/// # Examples
155///
156/// ```ignore
157/// use osal_rs::os::{Semaphore, SemaphoreFn};
158/// use osal_rs::utils::OsalRsBool;
159/// use core::time::Duration;
160/// 
161/// let sem = Semaphore::new(1, 1).unwrap();
162/// 
163/// match sem.wait(Duration::from_millis(100)) {
164///     OsalRsBool::True => println!("Acquired semaphore"),
165///     OsalRsBool::False => println!("Failed to acquire"),
166/// }
167/// 
168/// // Can also convert to bool
169/// if sem.signal().into() {
170///     println!("Semaphore signaled");
171/// }
172/// ```
173#[derive(PartialEq, Eq, Clone, Copy, Debug)]
174#[repr(u8)]
175pub enum OsalRsBool {
176    /// Operation failed or condition is false
177    False = 1,
178    /// Operation succeeded or condition is true
179    True = 0
180}
181
182/// Maximum delay constant for blocking operations.
183///
184/// When used as a timeout parameter, indicates the operation should
185/// block indefinitely until it succeeds.
186///
187/// # Examples
188///
189/// ```ignore
190/// use osal_rs::os::{Mutex, MutexFn};
191/// use osal_rs::utils::MAX_DELAY;
192/// 
193/// let mutex = Mutex::new(0);
194/// let guard = mutex.lock();  // Blocks forever if needed
195/// ```
196pub const MAX_DELAY: Duration = Duration::from_millis(usize::MAX as u64);
197
198/// Standard Result type for OSAL-RS operations.
199///
200/// Uses [`Error`] as the default error type.
201pub type Result<T, E = Error> = core::result::Result<T, E>;
202
203/// Pointer to pointer type for C FFI.
204pub type DoublePtr = *mut *mut c_void;
205
206/// Mutable pointer type for C FFI.
207pub type Ptr = *mut c_void;
208
209/// Const pointer type for C FFI.
210pub type ConstPtr = *const c_void;
211
212/// Shortcut for Arc<Mutex<T>>
213pub type ArcMux<T> = Arc<Mutex<T>>;
214
215/// Determines the CPU register size at compile time.
216///
217/// This constant function checks the size of `usize` to determine whether
218/// the target architecture uses 32-bit or 64-bit registers. This information
219/// is used for platform-specific optimizations and overflow handling.
220///
221/// # Returns
222///
223/// * [`CpuRegisterSize::Bit64`] - For 64-bit architectures
224/// * [`CpuRegisterSize::Bit32`] - For 32-bit architectures
225///
226/// # Examples
227///
228/// ```ignore
229/// use osal_rs::utils::{register_bit_size, CpuRegisterSize};
230/// 
231/// match register_bit_size() {
232///     CpuRegisterSize::Bit64 => println!("Running on 64-bit platform"),
233///     CpuRegisterSize::Bit32 => println!("Running on 32-bit platform"),
234/// }
235/// ```
236pub const fn register_bit_size() -> CpuRegisterSize {
237    if size_of::<usize>() == 8 {
238        CpuRegisterSize::Bit64
239    } else {
240        CpuRegisterSize::Bit32
241    }
242}
243
244/// Converts a C string pointer to a Rust String.
245///
246/// This macro safely converts a raw C string pointer (`*const c_char`) into
247/// a Rust `String`. It handles UTF-8 conversion gracefully using lossy conversion.
248///
249/// # Safety
250///
251/// The pointer must be valid and point to a null-terminated C string.
252///
253/// # Examples
254///
255/// ```ignore
256/// use osal_rs::from_c_str;
257/// use core::ffi::c_char;
258/// 
259/// extern "C" {
260///     fn get_system_name() -> *const c_char;
261/// }
262/// 
263/// let name = from_c_str!(get_system_name());
264/// println!("System: {}", name);
265/// ```
266#[macro_export]
267macro_rules! from_c_str {
268    ($str:expr) => {
269        unsafe {
270            let c_str = core::ffi::CStr::from_ptr($str);
271            alloc::string::String::from_utf8_lossy(c_str.to_bytes()).to_string()
272        }
273    };
274}
275
276/// Converts a Rust string to a CString with error handling.
277///
278/// This macro creates a `CString` from a Rust string reference, returning
279/// a `Result` that can be used with the `?` operator. If the conversion fails
280/// (e.g., due to interior null bytes), it returns an appropriate error.
281///
282/// # Returns
283///
284/// * `Ok(CString)` - On successful conversion
285/// * `Err(Error::Unhandled)` - If the string contains interior null bytes
286///
287/// # Examples
288///
289/// ```ignore
290/// use osal_rs::to_cstring;
291/// use osal_rs::utils::Result;
292/// 
293/// fn pass_to_c_api(name: &str) -> Result<()> {
294///     let c_name = to_cstring!(name)?;
295///     // Use c_name.as_ptr() with C FFI
296///     Ok(())
297/// }
298/// ```
299#[macro_export]
300macro_rules! to_cstring {
301    ($s:expr) => {
302        alloc::ffi::CString::new($s.as_str())
303            .map_err(|_| $crate::utils::Error::Unhandled("Failed to convert string to CString"))
304    };
305}
306
307/// Converts a Rust string to a C string pointer.
308///
309/// This macro creates a `CString` from a Rust string and returns its raw pointer.
310/// **Warning**: This macro panics if the conversion fails. Consider using
311/// [`to_cstring!`] for safer error handling.
312///
313/// # Panics
314///
315/// Panics if the string contains interior null bytes.
316///
317/// # Examples
318///
319/// ```ignore
320/// use osal_rs::to_c_str;
321/// 
322/// extern "C" {
323///     fn set_name(name: *const core::ffi::c_char);
324/// }
325/// 
326/// let name = "FreeRTOS Task";
327/// unsafe {
328///     set_name(to_c_str!(name));
329/// }
330/// ```
331#[macro_export]
332macro_rules! to_c_str {
333    ($s:expr) => {
334        alloc::ffi::CString::new($s.as_ref() as &str).unwrap().as_ptr()
335    };
336}
337
338/// Converts a string to a fixed-size byte array.
339///
340/// This macro creates a byte array of the specified size and fills it with
341/// the bytes from the input string. If the string is shorter than the buffer,
342/// the remaining bytes are filled with spaces. If the string is longer, it
343/// is truncated to fit.
344///
345/// # Parameters
346///
347/// * `$str` - The source string to convert
348/// * `$buff_name` - The identifier name for the created buffer variable
349/// * `$buff_size` - The size of the byte array to create
350///
351/// # Examples
352///
353/// ```ignore
354/// use osal_rs::from_str_to_array;
355/// 
356/// let task_name = "MainTask";
357/// from_str_to_array!(task_name, name_buffer, 16);
358/// // name_buffer is now [u8; 16] containing "MainTask        "
359/// 
360/// // Use with C FFI
361/// extern "C" {
362///     fn create_task(name: *const u8, len: usize);
363/// }
364/// 
365/// unsafe {
366///     create_task(name_buffer.as_ptr(), name_buffer.len());
367/// }
368/// ```
369#[macro_export]
370macro_rules! from_str_to_array {
371    ($str:expr, $buff_name:ident, $buff_size:expr) => {
372        let mut $buff_name = [b' '; $buff_size];
373        let _bytes = $str.as_bytes();
374        let _len = core::cmp::min(_bytes.len(), $buff_size);
375        $buff_name[.._len].copy_from_slice(&_bytes[.._len]);
376    };
377}
378
379/// Extracts a typed parameter from an optional boxed Any reference.
380///
381/// This macro is used in thread/task entry points to safely extract and
382/// downcast parameters passed to the thread. It handles both the Option
383/// unwrapping and the type downcast, returning appropriate errors if either
384/// operation fails.
385///
386/// # Parameters
387///
388/// * `$param` - An `Option<Box<dyn Any>>` containing the parameter
389/// * `$t` - The type to downcast the parameter to
390///
391/// # Returns
392///
393/// * A reference to the downcasted value of type `$t`
394/// * `Err(Error::NullPtr)` - If the parameter is None
395/// * `Err(Error::InvalidType)` - If the downcast fails
396///
397/// # Examples
398///
399/// ```ignore
400/// use osal_rs::thread_extract_param;
401/// use osal_rs::utils::Result;
402/// use core::any::Any;
403/// 
404/// struct TaskConfig {
405///     priority: u8,
406///     stack_size: usize,
407/// }
408/// 
409/// fn task_entry(param: Option<Box<dyn Any>>) -> Result<()> {
410///     let config = thread_extract_param!(param, TaskConfig);
411///     
412///     println!("Priority: {}", config.priority);
413///     println!("Stack: {}", config.stack_size);
414///     
415///     Ok(())
416/// }
417/// ```
418#[macro_export]
419macro_rules! thread_extract_param {
420    ($param:expr, $t:ty) => {
421        match $param.as_ref() {
422            Some(p) => {
423                match p.downcast_ref::<$t>() {
424                    Some(value) => value,
425                    None => return Err($crate::utils::Error::InvalidType),
426                }
427            }
428            None => return Err($crate::utils::Error::NullPtr),
429        }
430    };
431}
432
433/// Creates an Arc<Mutex<T>> from a value.
434///
435/// This is a convenience macro to reduce boilerplate when creating
436/// thread-safe shared data structures.
437///
438/// # Examples
439///
440/// ```ignore
441/// use osal_rs::arcmux;
442/// 
443/// let shared_counter = arcmux!(0);
444/// // Equivalent to: Arc::new(Mutex::new(0))
445/// ```
446#[macro_export]
447macro_rules! arcmux {
448    ($value:expr) => {
449        alloc::sync::Arc::new($crate::os::Mutex::new($value))
450    };
451}
452
453
454
455/// Fixed-size byte array wrapper with string conversion utilities.
456///
457/// `Bytes` is a generic wrapper around a fixed-size byte array that provides
458/// convenient methods for converting between strings and byte arrays. It's
459/// particularly useful for interfacing with C APIs that expect fixed-size
460/// character buffers, or for storing strings in embedded systems with
461/// constrained memory.
462///
463/// # Type Parameters
464///
465/// * `SIZE` - The size of the internal byte array (default: 0)
466///
467/// # Examples
468///
469/// ```ignore
470/// use osal_rs::utils::Bytes;
471/// 
472/// // Create an empty 32-byte buffer
473/// let mut buffer = Bytes::<32>::new();
474/// 
475/// // Create a buffer from a string
476/// let name = Bytes::<16>::new_by_str("TaskName");
477/// println!("{}", name); // Prints "TaskName"
478/// 
479/// // Create from any type that implements ToString
480/// let number = 42;
481/// let num_bytes = Bytes::<8>::new_by_string(&number);
482/// ```
483
484#[cfg(feature = "serde")]
485#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
486pub struct Bytes<const SIZE: usize> (pub [u8; SIZE]);
487
488#[cfg(not(feature = "serde"))]
489#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
490pub struct Bytes<const SIZE: usize> (pub [u8; SIZE]);
491
492impl<const SIZE: usize> Deref for Bytes<SIZE> {
493    type Target = [u8; SIZE];
494
495    /// Dereferences to the underlying byte array.
496    ///
497    /// This allows `Bytes` to be used anywhere a `[u8; SIZE]` reference is expected.
498    ///
499    /// # Examples
500    ///
501    /// ```ignore
502    /// use osal_rs::utils::Bytes;
503    /// 
504    /// let bytes = Bytes::<8>::new_by_str("test");
505    /// assert_eq!(bytes[0], b't');
506    /// ```
507    fn deref(&self) -> &Self::Target {
508        &self.0
509    }
510}
511
512impl<const SIZE: usize> DerefMut for Bytes<SIZE> {
513    /// Provides mutable access to the underlying byte array.
514    ///
515    /// This allows `Bytes` to be mutably dereferenced, enabling direct modification
516    /// of the internal byte array through the `DerefMut` trait.
517    ///
518    /// # Examples
519    ///
520    /// ```ignore
521    /// use osal_rs::utils::Bytes;
522    /// 
523    /// let mut bytes = Bytes::<8>::new();
524    /// bytes[0] = b'H';
525    /// bytes[1] = b'i';
526    /// assert_eq!(bytes[0], b'H');
527    /// ```
528    fn deref_mut(&mut self) -> &mut Self::Target {
529        &mut self.0
530    }
531}
532
533impl<const SIZE: usize> Display for Bytes<SIZE> {
534    /// Formats the byte array as a C-style null-terminated string.
535    ///
536    /// This implementation treats the byte array as a C string and converts it
537    /// to a Rust string for display. If the conversion fails, it displays
538    /// "Conversion error".
539    ///
540    /// # Safety
541    ///
542    /// This method assumes the byte array contains valid UTF-8 data and is
543    /// null-terminated. Invalid data may result in the error message being displayed.
544    ///
545    /// # Examples
546    ///
547    /// ```ignore
548    /// use osal_rs::utils::Bytes;
549    /// 
550    /// let bytes = Bytes::<16>::new_by_str("Hello");
551    /// println!("{}", bytes); // Prints "Hello"
552    /// ```
553    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
554        let str = unsafe {
555            CStr::from_ptr(self.0.as_ptr() as *const c_char)
556            .to_str()
557            .unwrap_or("Conversion error")
558        };
559        
560        write!(f, "{}", str.to_string())
561    }
562}
563
564impl<const SIZE: usize> FromStr for Bytes<{SIZE}> {
565    type Err = Error;
566
567    #[inline]
568    fn from_str(s: &str) -> core::result::Result<Self, Self::Err> {
569        Ok(Self::new_by_str(s))
570    }
571}
572
573impl<const SIZE: usize> AsSyncStr for Bytes<SIZE> {
574    /// Returns a string slice reference.
575    ///
576    /// This method provides access to the underlying string data in a way
577    /// that is safe to use across thread boundaries.
578    ///
579    /// # Returns
580    ///
581    /// A reference to a string slice with lifetime tied to `self`.
582    fn as_str(&self) -> &str {
583        unsafe {
584            CStr::from_ptr(self.0.as_ptr() as *const c_char)
585            .to_str()
586            .unwrap_or("Conversion error")
587        }
588    }
589}
590
591/// Serialization implementation for `Bytes<SIZE>` when the `serde` feature is enabled.
592///
593/// This implementation provides serialization by directly serializing each byte
594/// in the array using the osal-rs-serde serialization framework.
595#[cfg(feature = "serde")]
596impl<const SIZE: usize> Serialize for Bytes<SIZE> {
597    /// Serializes the `Bytes` instance using the given serializer.
598    ///
599    /// # Parameters
600    ///
601    /// * `serializer` - The serializer to use
602    ///
603    /// # Returns
604    ///
605    /// * `Ok(())` - On successful serialization
606    /// * `Err(S::Error)` - If serialization fails
607    fn serialize<S: osal_rs_serde::Serializer>(&self, name: &str, serializer: &mut S) -> core::result::Result<(), S::Error> {
608        // Find the actual length (up to first null byte or SIZE)
609        let len = self.0.iter().position(|&b| b == 0).unwrap_or(SIZE);
610        
611        // Try to serialize as UTF-8 string if valid, otherwise as hex
612        if let Ok(s) = core::str::from_utf8(&self.0[..len]) {
613            serializer.serialize_str(name, s)
614        } else {
615            // For binary data, serialize as bytes (hex encoded)
616            serializer.serialize_bytes(name, &self.0[..len])
617        }
618    }
619}
620
621/// Deserialization implementation for `Bytes<SIZE>` when the `serde` feature is enabled.
622///
623/// This implementation provides deserialization by reading bytes from the deserializer
624/// into a fixed-size array using the osal-rs-serde deserialization framework.
625#[cfg(feature = "serde")]
626impl<const SIZE: usize> Deserialize for Bytes<SIZE> {
627    /// Deserializes a `Bytes` instance using the given deserializer.
628    ///
629    /// # Parameters
630    ///
631    /// * `deserializer` - The deserializer to use
632    ///
633    /// # Returns
634    ///
635    /// * `Ok(Bytes<SIZE>)` - A new `Bytes` instance with deserialized data
636    /// * `Err(D::Error)` - If deserialization fails
637    fn deserialize<D: osal_rs_serde::Deserializer>(deserializer: &mut D, name: &str) -> core::result::Result<Self, D::Error> {
638        let mut array = [0u8; SIZE];
639        let _ = deserializer.deserialize_bytes(name, &mut array)?;
640        Ok(Self(array))
641    }
642}
643
644/// Serialization implementation for `Bytes<SIZE>` when the `serde` feature is disabled.
645///
646/// This implementation provides basic serialization by directly returning a reference
647/// to the underlying byte array. It's used when the library is compiled without the
648/// `serde` feature, providing a lightweight alternative serialization mechanism.
649#[cfg(not(feature = "serde"))]
650impl<const SIZE: usize> Serialize for Bytes<SIZE> {
651    /// Converts the `Bytes` instance to a byte slice.
652    ///
653    /// # Returns
654    ///
655    /// A reference to the internal byte array.
656    fn to_bytes(&self) -> &[u8] {
657        &self.0
658    }
659}
660
661/// Deserialization implementation for `Bytes<SIZE>` when the `serde` feature is disabled.
662///
663/// This implementation provides basic deserialization by copying bytes from a slice
664/// into a fixed-size array. If the source slice is shorter than `SIZE`, the remaining
665/// bytes are zero-filled. If longer, it's truncated to fit.
666#[cfg(not(feature = "serde"))]
667impl<const SIZE: usize> Deserialize for Bytes<SIZE> {
668    /// Creates a `Bytes` instance from a byte slice.
669    ///
670    /// # Parameters
671    ///
672    /// * `bytes` - The source byte slice to deserialize from
673    ///
674    /// # Returns
675    ///
676    /// * `Ok(Bytes<SIZE>)` - A new `Bytes` instance with data copied from the slice
677    ///
678    /// # Examples
679    ///
680    /// ```ignore
681    /// use osal_rs::utils::Bytes;
682    /// use osal_rs::os::Deserialize;
683    /// 
684    /// let data = b"Hello";
685    /// let bytes = Bytes::<16>::from_bytes(data).unwrap();
686    /// // Result: [b'H', b'e', b'l', b'l', b'o', 0, 0, 0, ...]
687    /// ```
688    fn from_bytes(bytes: &[u8]) -> Result<Self> {
689        let mut array = [0u8; SIZE];
690        let len = core::cmp::min(bytes.len(), SIZE);
691        array[..len].copy_from_slice(&bytes[..len]);
692        Ok(Self( array ))
693    }
694}
695
696impl<const SIZE: usize> Bytes<SIZE> {
697    /// Creates a new `Bytes` instance filled with zeros.
698    ///
699    /// This is a const function, allowing it to be used in const contexts
700    /// and static variable declarations.
701    ///
702    /// # Returns
703    ///
704    /// A `Bytes` instance with all bytes set to 0.
705    ///
706    /// # Examples
707    ///
708    /// ```ignore
709    /// use osal_rs::utils::Bytes;
710    /// 
711    /// const BUFFER: Bytes<64> = Bytes::new();
712    /// 
713    /// let runtime_buffer = Bytes::<32>::new();
714    /// assert_eq!(runtime_buffer[0], 0);
715    /// ```
716    pub const fn new() -> Self {
717        Self( [0u8; SIZE] )
718    }
719
720    /// Creates a new `Bytes` instance from a string slice.
721    ///
722    /// Copies the bytes from the input string into the fixed-size array.
723    /// If the string is shorter than `SIZE`, the remaining bytes are zero-filled.
724    /// If the string is longer, it is truncated to fit.
725    ///
726    /// # Parameters
727    ///
728    /// * `str` - The source string to convert
729    ///
730    /// # Returns
731    ///
732    /// A `Bytes` instance containing the string data.
733    ///
734    /// # Examples
735    ///
736    /// ```ignore
737    /// use osal_rs::utils::Bytes;
738    ///
739    /// let short = Bytes::<16>::new_by_str("Hi");
740    /// // Internal array: [b'H', b'i', 0, 0, 0, ...]
741    ///
742    /// let exact = Bytes::<5>::new_by_str("Hello");
743    /// // Internal array: [b'H', b'e', b'l', b'l', b'o']
744    ///
745    /// let long = Bytes::<3>::new_by_str("Hello");
746    /// // Internal array: [b'H', b'e', b'l'] (truncated)
747    /// ```
748    pub fn new_by_str(str: &str) -> Self {
749
750        let mut array = [0u8; SIZE];
751
752        let mut i = 0usize ;
753        for byte in str.as_bytes() {
754            if i > SIZE - 1{
755                break;
756            }
757            array[i] = *byte;
758            i += 1;
759        }
760
761        Self( array )
762    }
763
764    /// Creates a new `Bytes` instance from a C string pointer.
765    ///
766    /// Safely converts a null-terminated C string pointer into a `Bytes` instance.
767    /// If the pointer is null, returns a zero-initialized `Bytes`. The function
768    /// copies bytes from the C string into the fixed-size array, truncating if
769    /// the source is longer than `SIZE`.
770    ///
771    /// # Parameters
772    ///
773    /// * `str` - A pointer to a null-terminated C string (`*const c_char`)
774    ///
775    /// # Safety
776    ///
777    /// While this function is not marked unsafe, it internally uses `unsafe` code
778    /// to dereference the pointer. The caller must ensure that:
779    /// - If not null, the pointer points to a valid null-terminated C string
780    /// - The memory the pointer references remains valid for the duration of the call
781    ///
782    /// # Returns
783    ///
784    /// A `Bytes` instance containing the C string data, or zero-initialized if the pointer is null.
785    ///
786    /// # Examples
787    ///
788    /// ```ignore
789    /// use osal_rs::utils::Bytes;
790    /// use core::ffi::c_char;
791    /// use alloc::ffi::CString;
792    ///
793    /// // From a CString
794    /// let c_string = CString::new("Hello").unwrap();
795    /// let bytes = Bytes::<16>::new_by_ptr(c_string.as_ptr());
796    ///
797    /// // From a null pointer
798    /// let null_bytes = Bytes::<16>::new_by_ptr(core::ptr::null());
799    /// // Returns zero-initialized Bytes
800    ///
801    /// // Truncation example
802    /// let long_string = CString::new("This is a very long string").unwrap();
803    /// let short_bytes = Bytes::<8>::new_by_ptr(long_string.as_ptr());
804    /// // Only first 8 bytes are copied
805    /// ```
806    pub fn new_by_ptr(str: *const c_char) -> Self {
807        if str.is_null() {
808            return Self::new();
809        }
810
811        let mut array = [0u8; SIZE];
812
813        let mut i = 0usize ;
814        for byte in unsafe { CStr::from_ptr(str) }.to_bytes() {
815            if i > SIZE - 1{
816                break;
817            }
818            array[i] = *byte;
819            i += 1;
820        }
821
822        Self( array )
823    }
824
825    /// Creates a new `Bytes` instance from any type implementing `ToString`.
826    ///
827    /// This is a convenience wrapper around [`new_by_str`](Self::new_by_str)
828    /// that first converts the input to a string.
829    ///
830    /// # Parameters
831    ///
832    /// * `str` - Any value that implements `ToString`
833    ///
834    /// # Returns
835    ///
836    /// A `Bytes` instance containing the string representation of the input.
837    ///
838    /// # Examples
839    ///
840    /// ```ignore
841    /// use osal_rs::utils::Bytes;
842    ///
843    /// // From integer
844    /// let num_bytes = Bytes::<8>::new_by_string(&42);
845    ///
846    /// // From String
847    /// let string = String::from("Task");
848    /// let str_bytes = Bytes::<16>::new_by_string(&string);
849    ///
850    /// // From custom type with ToString
851    /// #[derive(Debug)]
852    /// struct TaskId(u32);
853    /// impl ToString for TaskId {
854    ///     fn to_string(&self) -> String {
855    ///         format!("Task-{}", self.0)
856    ///     }
857    /// }
858    /// let task_bytes = Bytes::<16>::new_by_string(&TaskId(5));
859    /// ```
860    pub fn new_by_as_sync_str(str: &impl ToString) -> Self {
861        Self::new_by_str(&str.to_string())
862    }
863
864    pub fn new_by_bytes(bytes: &[u8]) -> Self {
865        let mut array = [0u8; SIZE];
866        let len = core::cmp::min(bytes.len(), SIZE);
867        array[..len].copy_from_slice(&bytes[..len]);
868        Self( array )
869    }
870
871    /// Fills a mutable string slice with the contents of the byte array.
872    ///
873    /// Attempts to convert the internal byte array to a UTF-8 string and
874    /// copies it into the destination string slice. Only copies up to the
875    /// minimum of the source and destination lengths.
876    ///
877    /// # Parameters
878    ///
879    /// * `dest` - The destination string slice to fill
880    ///
881    /// # Returns
882    ///
883    /// `Ok(())` if the operation succeeds, or `Err(Error::StringConversionError)` if the byte array cannot be converted to a valid UTF-8 string.
884    ///
885    /// # Examples
886    ///
887    /// ```ignore
888    /// use osal_rs::utils::Bytes;
889    /// 
890    /// let bytes = Bytes::<16>::new_by_str("Hello World");
891    /// 
892    /// let mut output = String::from("                "); // 16 spaces
893    /// bytes.fill_str(unsafe { output.as_mut_str() });
894    /// 
895    /// assert_eq!(&output[..11], "Hello World");
896    /// ```
897    pub fn fill_str(&mut self, dest: &mut str) -> Result<()>{
898        match from_utf8_mut(&mut self.0) {
899            Ok(str) => {
900                let len = core::cmp::min(str.len(), dest.len());
901                unsafe {
902                    dest.as_bytes_mut()[..len].copy_from_slice(&str.as_bytes()[..len]);
903                }
904                Ok(())
905            }
906            Err(_) => Err(Error::StringConversionError),
907        }
908    }
909
910    /// Converts the byte array to a C string reference.
911    ///
912    /// Creates a `CStr` reference from the internal byte array, treating it as
913    /// a null-terminated C string. This is useful for passing strings to C FFI
914    /// functions that expect `*const c_char` or `&CStr`.
915    ///
916    /// # Safety
917    ///
918    /// This method is unsafe because it assumes:
919    /// - The byte array contains valid UTF-8 data
920    /// - The byte array is null-terminated
921    /// - There are no interior null bytes before the terminating null
922    ///
923    /// Violating these assumptions may lead to undefined behavior.
924    ///
925    /// # Returns
926    ///
927    /// A reference to a `CStr` with lifetime tied to `self`.
928    ///
929    /// # Examples
930    ///
931    /// ```ignore
932    /// use osal_rs::utils::Bytes;
933    /// 
934    /// let bytes = Bytes::<16>::new_by_str("Hello");
935    /// let c_str = bytes.as_c_str();
936    /// 
937    /// extern "C" {
938    ///     fn print_string(s: *const core::ffi::c_char);
939    /// }
940    /// 
941    /// unsafe {
942    ///     print_string(c_str.as_ptr());
943    /// }
944    /// ```
945    pub fn as_c_str(&self) -> &CStr {
946        unsafe {
947            CStr::from_ptr(self.0.as_ptr() as *const c_char)
948        }
949    }
950
951    /// Converts the byte array to an owned C string.
952    ///
953    /// Creates a new `CString` by copying the contents of the internal byte array.
954    /// Unlike [`as_c_str`](Self::as_c_str), this method allocates heap memory and
955    /// returns an owned string that can outlive the original `Bytes` instance.
956    ///
957    /// # Safety
958    ///
959    /// This method uses `from_vec_unchecked` which assumes the byte array
960    /// does not contain any interior null bytes. If this assumption is violated,
961    /// the resulting `CString` will be invalid.
962    ///
963    /// # Returns
964    ///
965    /// An owned `CString` containing a copy of the byte array data.
966    ///
967    /// # Memory Allocation
968    ///
969    /// This method allocates on the heap. In memory-constrained embedded systems,
970    /// prefer [`as_c_str`](Self::as_c_str) when possible.
971    ///
972    /// # Examples
973    ///
974    /// ```ignore
975    /// use osal_rs::utils::Bytes;
976    /// 
977    /// fn process_name(bytes: &Bytes<16>) -> alloc::ffi::CString {
978    ///     // Create an owned copy that can be returned
979    ///     bytes.as_cstring()
980    /// }
981    /// 
982    /// let name = Bytes::<16>::new_by_str("Task");
983    /// let owned = process_name(&name);
984    /// // 'name' can be dropped, 'owned' still valid
985    /// ```
986    pub fn as_cstring(&self) -> CString {
987        unsafe {
988            CString::from_vec_unchecked(self.0.to_vec())
989        }
990    }
991
992    /// Appends a string slice to the existing content in the `Bytes` buffer.
993    ///
994    /// This method finds the current end of the content (first null byte) and appends
995    /// the provided string starting from that position. If the buffer is already full
996    /// or if the appended content would exceed the buffer size, the content is truncated
997    /// to fit within the `SIZE` limit.
998    ///
999    /// # Parameters
1000    ///
1001    /// * `str` - The string slice to append
1002    ///
1003    /// # Examples
1004    ///
1005    /// ```
1006    /// use osal_rs::utils::Bytes;
1007    ///
1008    /// let mut bytes = Bytes::<16>::new_by_str("Hello");
1009    /// bytes.append_str(" World");
1010    /// assert_eq!(bytes.as_str(), "Hello World");
1011    ///
1012    /// // Truncation when exceeding buffer size
1013    /// let mut small_bytes = Bytes::<8>::new_by_str("Hi");
1014    /// small_bytes.append_str(" there friend");
1015    /// assert_eq!(small_bytes.as_str(), "Hi ther");
1016    /// ```
1017    pub fn append_str(&mut self, str: &str) {
1018        let current_len = self.0.iter().position(|&b| b == 0).unwrap_or(SIZE);
1019        let mut i = current_len;
1020        for byte in str.as_bytes() {
1021            if i > SIZE - 1{
1022                break;
1023            }
1024            self.0[i] = *byte;
1025            i += 1;
1026        }
1027    }
1028
1029    /// Appends content from any type implementing `AsSyncStr` to the buffer.
1030    ///
1031    /// This method accepts any type that implements the `AsSyncStr` trait, converts
1032    /// it to a string slice, and appends it to the existing content. If the buffer
1033    /// is already full or if the appended content would exceed the buffer size,
1034    /// the content is truncated to fit within the `SIZE` limit.
1035    ///
1036    /// # Parameters
1037    ///
1038    /// * `c_str` - A reference to any type implementing `AsSyncStr`
1039    ///
1040    /// # Examples
1041    ///
1042    /// ```ignore
1043    /// use osal_rs::utils::Bytes;
1044    ///
1045    /// let mut bytes = Bytes::<16>::new_by_str("Hello");
1046    /// let other_bytes = Bytes::<8>::new_by_str(" World");
1047    /// bytes.append_as_sync_str(&other_bytes);
1048    /// assert_eq!(bytes.as_str(), "Hello World");
1049    /// ```
1050    pub fn append_as_sync_str(&mut self, c_str: & impl AsSyncStr) {
1051        let current_len = self.0.iter().position(|&b| b == 0).unwrap_or(SIZE);
1052        let mut i = current_len;
1053        for byte in c_str.as_str().as_bytes() {
1054            if i > SIZE - 1{
1055                break;
1056            }
1057            self.0[i] = *byte;
1058            i += 1;
1059        }
1060    }
1061
1062    /// Appends raw bytes to the existing content in the `Bytes` buffer.
1063    ///
1064    /// This method finds the current end of the content (first null byte) and appends
1065    /// the provided byte slice starting from that position. If the buffer is already
1066    /// full or if the appended content would exceed the buffer size, the content is
1067    /// truncated to fit within the `SIZE` limit.
1068    ///
1069    /// # Parameters
1070    ///
1071    /// * `bytes` - The byte slice to append
1072    ///
1073    /// # Examples
1074    ///
1075    /// ```
1076    /// use osal_rs::utils::Bytes;
1077    ///
1078    /// let mut bytes = Bytes::<16>::new_by_str("Hello");
1079    /// bytes.append_bytes(b" World");
1080    /// assert_eq!(bytes.as_str(), "Hello World");
1081    ///
1082    /// // Appending arbitrary bytes
1083    /// let mut data = Bytes::<16>::new_by_str("Data: ");
1084    /// data.append_bytes(&[0x41, 0x42, 0x43]);
1085    /// assert_eq!(data.as_str(), "Data: ABC");
1086    /// ```
1087    pub fn append_bytes(&mut self, bytes: &[u8]) {
1088        let current_len = self.0.iter().position(|&b| b == 0).unwrap_or(SIZE);
1089        let mut i = current_len;
1090        for byte in bytes {
1091            if i > SIZE - 1{
1092                break;
1093            }
1094            self.0[i] = *byte;
1095            i += 1;
1096        }
1097    }
1098
1099    /// Appends the content of another `Bytes` instance to this buffer.
1100    ///
1101    /// This method allows appending content from a `Bytes` instance of a different
1102    /// size (specified by the generic parameter `OHTER_SIZE`). The method finds the
1103    /// current end of the content (first null byte) and appends the content from the
1104    /// other `Bytes` instance. If the buffer is already full or if the appended content
1105    /// would exceed the buffer size, the content is truncated to fit within the `SIZE` limit.
1106    ///
1107    /// # Type Parameters
1108    ///
1109    /// * `OHTER_SIZE` - The size of the source `Bytes` buffer (can be different from `SIZE`)
1110    ///
1111    /// # Parameters
1112    ///
1113    /// * `other` - A reference to the `Bytes` instance to append
1114    ///
1115    /// # Examples
1116    ///
1117    /// ```
1118    /// use osal_rs::utils::Bytes;
1119    ///
1120    /// let mut bytes = Bytes::<16>::new_by_str("Hello");
1121    /// let other = Bytes::<8>::new_by_str(" World");
1122    /// bytes.append(&other);
1123    /// assert_eq!(bytes.as_str(), "Hello World");
1124    ///
1125    /// // Appending from a larger buffer
1126    /// let mut small = Bytes::<8>::new_by_str("Hi");
1127    /// let large = Bytes::<32>::new_by_str(" there friend");
1128    /// small.append(&large);
1129    /// assert_eq!(small.as_str(), "Hi ther");
1130    /// ```
1131    pub fn append<const OHTER_SIZE: usize>(&mut self, other: &Bytes<OHTER_SIZE>) {
1132        let current_len = self.0.iter().position(|&b| b == 0).unwrap_or(SIZE);
1133        let mut i = current_len;
1134        for &byte in other.0.iter() {
1135            if i > SIZE - 1{
1136                break;
1137            }
1138            self.0[i] = byte;
1139            i += 1;
1140        }
1141    }
1142}
1143
1144/// Converts a byte slice to a hexadecimal string representation.
1145///
1146/// Each byte is converted to its two-character hexadecimal representation
1147/// in lowercase. This function allocates a new `String` on the heap.
1148///
1149/// # Parameters
1150///
1151/// * `bytes` - The byte slice to convert
1152///
1153/// # Returns
1154///
1155/// A `String` containing the hexadecimal representation of the bytes.
1156/// Each byte is represented by exactly 2 hex characters (lowercase).
1157///
1158/// # Memory Allocation
1159///
1160/// This function allocates heap memory. In memory-constrained environments,
1161/// consider using [`bytes_to_hex_into_slice`] instead.
1162///
1163/// # Examples
1164///
1165/// ```ignore
1166/// use osal_rs::utils::bytes_to_hex;
1167/// 
1168/// let data = &[0x01, 0x23, 0xAB, 0xFF];
1169/// let hex = bytes_to_hex(data);
1170/// assert_eq!(hex, "0123abff");
1171/// 
1172/// let empty = bytes_to_hex(&[]);
1173/// assert_eq!(empty, "");
1174/// ```
1175pub fn bytes_to_hex(bytes: &[u8]) -> String {
1176    bytes.iter()
1177         .map(|b| format!("{:02x}", b))
1178         .collect()
1179}
1180
1181/// Converts a byte slice to hexadecimal representation into a pre-allocated buffer.
1182///
1183/// This is a zero-allocation version of [`bytes_to_hex`] that writes the
1184/// hexadecimal representation directly into a provided output buffer.
1185/// Suitable for embedded systems and real-time applications.
1186///
1187/// # Parameters
1188///
1189/// * `bytes` - The source byte slice to convert
1190/// * `output` - The destination buffer to write hex characters into
1191///
1192/// # Returns
1193///
1194/// The number of bytes written to the output buffer (always `bytes.len() * 2`).
1195///
1196/// # Panics
1197///
1198/// Panics if `output.len() < bytes.len() * 2`. The output buffer must be
1199/// at least twice the size of the input to hold the hex representation.
1200///
1201/// # Examples
1202///
1203/// ```ignore
1204/// use osal_rs::utils::bytes_to_hex_into_slice;
1205/// 
1206/// let data = &[0x01, 0xAB, 0xFF];
1207/// let mut buffer = [0u8; 6];
1208/// 
1209/// let written = bytes_to_hex_into_slice(data, &mut buffer);
1210/// assert_eq!(written, 6);
1211/// assert_eq!(&buffer, b"01abff");
1212/// 
1213/// // Will panic - buffer too small
1214/// // let mut small = [0u8; 4];
1215/// // bytes_to_hex_into_slice(data, &mut small);
1216/// ```
1217pub fn bytes_to_hex_into_slice(bytes: &[u8], output: &mut [u8]) -> usize {
1218    assert!(output.len() >= bytes.len() * 2, "Buffer too small for hex conversion");
1219    let mut i = 0;
1220    for &b in bytes {
1221        let hex = format!("{:02x}", b);
1222        output[i..i+2].copy_from_slice(hex.as_bytes());
1223        i += 2;
1224    }
1225    i 
1226}
1227
1228/// Converts a hexadecimal string to a vector of bytes.
1229///
1230/// Parses a string of hexadecimal digits (case-insensitive) and converts
1231/// them to their binary representation. Each pair of hex digits becomes
1232/// one byte in the output.
1233///
1234/// # Parameters
1235///
1236/// * `hex` - A string slice containing hexadecimal digits (0-9, a-f, A-F)
1237///
1238/// # Returns
1239///
1240/// * `Ok(Vec<u8>)` - A vector containing the decoded bytes
1241/// * `Err(Error::StringConversionError)` - If the string has odd length or contains invalid hex digits
1242///
1243/// # Memory Allocation
1244///
1245/// This function allocates a `Vec` on the heap. For no-alloc environments,
1246/// use [`hex_to_bytes_into_slice`] instead.
1247///
1248/// # Examples
1249///
1250/// ```ignore
1251/// use osal_rs::utils::hex_to_bytes;
1252/// 
1253/// // Lowercase hex
1254/// let bytes = hex_to_bytes("0123abff").unwrap();
1255/// assert_eq!(bytes, vec![0x01, 0x23, 0xAB, 0xFF]);
1256/// 
1257/// // Uppercase hex
1258/// let bytes2 = hex_to_bytes("ABCD").unwrap();
1259/// assert_eq!(bytes2, vec![0xAB, 0xCD]);
1260/// 
1261/// // Odd length - error
1262/// assert!(hex_to_bytes("ABC").is_err());
1263/// 
1264/// // Invalid character - error
1265/// assert!(hex_to_bytes("0G").is_err());
1266/// ```
1267pub fn hex_to_bytes(hex: &str) -> Result<Vec<u8>> {
1268    if hex.len() % 2 != 0 {
1269        return Err(Error::StringConversionError);
1270    }
1271
1272    let bytes_result: Result<Vec<u8>> = (0..hex.len())
1273        .step_by(2)
1274        .map(|i| {
1275            u8::from_str_radix(&hex[i..i + 2], 16)
1276                .map_err(|_| Error::StringConversionError)
1277        })
1278        .collect();
1279
1280    bytes_result
1281}
1282
1283/// Converts a hexadecimal string to bytes into a pre-allocated buffer.
1284///
1285/// This is a zero-allocation version of [`hex_to_bytes`] that writes decoded
1286/// bytes directly into a provided output buffer. Suitable for embedded systems
1287/// and real-time applications where heap allocation is not desired.
1288///
1289/// # Parameters
1290///
1291/// * `hex` - A string slice containing hexadecimal digits (0-9, a-f, A-F)
1292/// * `output` - The destination buffer to write decoded bytes into
1293///
1294/// # Returns
1295///
1296/// * `Ok(usize)` - The number of bytes written to the output buffer (`hex.len() / 2`)
1297/// * `Err(Error::StringConversionError)` - If:
1298///   - The hex string has odd length
1299///   - The output buffer is too small (`output.len() < hex.len() / 2`)
1300///   - The hex string contains invalid characters
1301///
1302/// # Examples
1303///
1304/// ```ignore
1305/// use osal_rs::utils::hex_to_bytes_into_slice;
1306/// 
1307/// let mut buffer = [0u8; 4];
1308/// let written = hex_to_bytes_into_slice("0123abff", &mut buffer).unwrap();
1309/// assert_eq!(written, 4);
1310/// assert_eq!(buffer, [0x01, 0x23, 0xAB, 0xFF]);
1311/// 
1312/// // Buffer too small
1313/// let mut small = [0u8; 2];
1314/// assert!(hex_to_bytes_into_slice("0123abff", &mut small).is_err());
1315/// 
1316/// // Odd length string
1317/// assert!(hex_to_bytes_into_slice("ABC", &mut buffer).is_err());
1318/// ```
1319pub fn hex_to_bytes_into_slice(hex: &str, output: &mut [u8]) -> Result<usize> {
1320    if hex.len() % 2 != 0 || output.len() < hex.len() / 2 {
1321        return Err(Error::StringConversionError);
1322    }
1323
1324    for i in 0..(hex.len() / 2) {
1325        output[i] = u8::from_str_radix(&hex[2 * i..2 * i + 2], 16)
1326            .map_err(|_| Error::StringConversionError)?;
1327    }
1328
1329    Ok(hex.len() / 2)
1330}
1331
1332/// Thread-safe wrapper for `UnsafeCell` usable in `static` contexts.
1333///
1334/// `SyncUnsafeCell<T>` is a thin wrapper around `UnsafeCell<T>` that manually
1335/// implements the `Sync` and `Send` traits, allowing its use in `static` variables.
1336/// This is necessary in Rust 2024+ where `static mut` is no longer allowed.
1337///
1338/// # Safety
1339///
1340/// The manual implementation of `Sync` and `Send` is **unsafe** because the compiler
1341/// cannot verify that concurrent access is safe. It is the programmer's responsibility
1342/// to ensure that:
1343///
1344/// 1. In **single-threaded** environments (e.g., embedded bare-metal), there are no
1345///    synchronization issues since only one thread of execution exists.
1346///
1347/// 2. In **multi-threaded** environments, access to `SyncUnsafeCell` must be
1348///    externally protected via mutexes, critical sections, or other synchronization
1349///    primitives.
1350///
1351/// 3. No **data race** conditions occur during data access.
1352///
1353/// # Typical Usage
1354///
1355/// This structure is designed to replace `static mut` in embedded scenarios
1356/// where global mutability is necessary (e.g., hardware registers, shared buffers).
1357///
1358/// # Examples
1359///
1360/// ```ignore
1361/// use osal_rs::utils::SyncUnsafeCell;
1362///
1363/// // Global mutable variable in Rust 2024+
1364/// static COUNTER: SyncUnsafeCell<u32> = SyncUnsafeCell::new(0);
1365///
1366/// fn increment_counter() {
1367///     unsafe {
1368///         let counter = &mut *COUNTER.get();
1369///         *counter += 1;
1370///     }
1371/// }
1372/// ```
1373///
1374/// # Alternatives
1375///
1376/// For non-embedded code or when real synchronization is needed:
1377/// - Use `Mutex<T>` or `RwLock<T>` for thread-safe protection
1378/// - Use `AtomicUsize`, `AtomicBool`, etc. for simple atomic types
1379pub struct SyncUnsafeCell<T>(UnsafeCell<T>);
1380
1381/// Manual implementation of `Sync` for `SyncUnsafeCell<T>`.
1382///
1383/// # Safety
1384///
1385/// This is **unsafe** because it asserts that `SyncUnsafeCell<T>` can be shared
1386/// between threads without causing data races. The caller must ensure synchronization.
1387unsafe impl<T> Sync for SyncUnsafeCell<T> {}
1388
1389/// Manual implementation of `Send` for `SyncUnsafeCell<T>`.
1390///
1391/// # Safety
1392///
1393/// This is **unsafe** because it asserts that `SyncUnsafeCell<T>` can be transferred
1394/// between threads. The inner type `T` may not be `Send`, so the caller must handle
1395/// memory safety.
1396unsafe impl<T> Send for SyncUnsafeCell<T> {}
1397
1398impl<T> SyncUnsafeCell<T> {
1399    /// Creates a new instance of `SyncUnsafeCell<T>`.
1400    ///
1401    /// This is a `const` function, allowing initialization in static and
1402    /// constant contexts.
1403    ///
1404    /// # Parameters
1405    ///
1406    /// * `value` - The initial value to wrap
1407    ///
1408    /// # Examples
1409    ///
1410    /// ```ignore
1411    /// use osal_rs::utils::SyncUnsafeCell;
1412    ///
1413    /// static CONFIG: SyncUnsafeCell<u32> = SyncUnsafeCell::new(42);
1414    /// ```
1415    pub const fn new(value: T) -> Self {
1416        Self(UnsafeCell::new(value))
1417    }
1418    
1419    /// Gets a raw mutable pointer to the contained value.
1420    ///
1421    /// # Safety
1422    ///
1423    /// This function is **unsafe** because:
1424    /// - It returns a raw pointer that bypasses the borrow checker
1425    /// - The caller must ensure there are no mutable aliases
1426    /// - Dereferencing the pointer without synchronization can cause data races
1427    ///
1428    /// # Returns
1429    ///
1430    /// A raw mutable pointer `*mut T` to the inner value.
1431    ///
1432    /// # Examples
1433    ///
1434    /// ```ignore
1435    /// use osal_rs::utils::SyncUnsafeCell;
1436    ///
1437    /// static VALUE: SyncUnsafeCell<i32> = SyncUnsafeCell::new(0);
1438    ///
1439    /// unsafe {
1440    ///     let ptr = VALUE.get();
1441    ///     *ptr = 42;
1442    /// }
1443    /// ```
1444    pub unsafe fn get(&self) -> *mut T {
1445        self.0.get()
1446    }
1447}