Skip to main content

osal_rs/
utils.rs

1/***************************************************************************
2 *
3 * osal-rs
4 * Copyright (C) 2026 Antonio Salsi <passy.linux@zresa.it>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see <https://www.gnu.org/licenses/>.
18 *
19 ***************************************************************************/
20
21//! Utility types and functions for OSAL-RS.
22//!
23//! This module contains common types, error definitions, and helper functions
24//! used throughout the library.
25//!
26//! # Overview
27//!
28//! The utilities module provides essential building blocks for working with
29//! OSAL-RS in embedded environments:
30//!
31//! - **Error handling**: Comprehensive [`Error`] enum for all OSAL operations
32//! - **String utilities**: Fixed-size [`Bytes`] type for embedded string handling
33//! - **Conversion macros**: Safe C string conversion and parameter extraction
34//! - **FFI types**: Type aliases for C interoperability
35//! - **Thread safety**: [`SyncUnsafeCell`] for static mutable state in Rust 2024+
36//!
37//! # Main Types
38//!
39//! ## Error Handling
40//!
41//! - [`Error<'a>`] - All possible error conditions with optional borrowed error messages
42//! - [`Result<T, E>`] - Type alias for `core::result::Result` with default `Error<'static>`
43//! - [`OsalRsBool`] - Boolean type compatible with RTOS return values
44//!
45//! ## String Handling
46//!
47//! - [`Bytes<SIZE>`] - Fixed-size byte buffer with string conversion utilities
48//! - [`AsSyncStr`] - Trait for thread-safe string references
49//!
50//! ## Constants
51//!
52//! - [`MAX_DELAY`] - Maximum timeout for blocking indefinitely
53//! - [`CpuRegisterSize`] - CPU register size detection (32-bit or 64-bit)
54//!
55//! ## FFI Types
56//!
57//! - [`Ptr`], [`ConstPtr`], [`DoublePtr`] - Type aliases for C pointers
58//!
59//! ## Thread Safety
60//!
61//! - [`SyncUnsafeCell<T>`] - Wrapper for static mutable variables (replaces `static mut`)
62//!
63//! # Macros
64//!
65//! ## String Conversion
66//!
67//! - [`from_c_str!`] - Convert C string pointer to Rust String (lossy conversion)
68//! - [`to_cstring!`] - Convert Rust string to CString with error handling
69//! - [`to_c_str!`] - Convert Rust string to C string pointer (panics on error)
70//! - [`from_str_to_array!`] - Convert string to fixed-size byte array
71//!
72//! ## Parameter Handling
73//!
74//! - [`thread_extract_param!`] - Extract typed parameter from thread entry point
75//! - [`access_static_option!`] - Access static Option variable (panics if None)
76//!
77//! # Helper Functions
78//!
79//! ## Hex Conversion
80//!
81//! - [`bytes_to_hex`] - Convert bytes to hex string (allocates)
82//! - [`bytes_to_hex_into_slice`] - Convert bytes to hex into buffer (no allocation)
83//! - [`hex_to_bytes`] - Parse hex string to bytes (allocates)
84//! - [`hex_to_bytes_into_slice`] - Parse hex string into buffer (no allocation)
85//!
86//! # Platform Detection
87//!
88//! - [`register_bit_size`] - Const function to detect CPU register size (32-bit or 64-bit)
89//!
90//! # Best Practices
91//!
92//! 1. **Use `Bytes<SIZE>` for embedded strings**: Avoids heap allocation, fixed size
93//! 2. **Prefer no-alloc variants**: Use `_into_slice` functions when possible
94//! 3. **Handle errors explicitly**: Always check `Result` returns
95//! 4. **Use `to_cstring!` over `to_c_str!`**: Better error handling with `?` operator
96//! 5. **Synchronize `SyncUnsafeCell` access**: Use mutexes or critical sections in multi-threaded environments
97
98use core::cell::UnsafeCell;
99use core::ffi::{CStr, c_char, c_uchar, c_void};
100use core::str::{from_utf8_mut, FromStr};
101use core::fmt::{Debug, Display}; 
102use core::ops::{Deref, DerefMut};
103use core::time::Duration;
104
105use alloc::format;
106use alloc::string::{String, ToString};
107use alloc::vec::Vec;
108
109#[cfg(not(feature = "serde"))]
110use crate::os::{Deserialize, Serialize};
111
112#[cfg(feature = "serde")]
113use osal_rs_serde::{Deserialize, Serialize};
114
115/// Error types for OSAL-RS operations.
116///
117/// Represents all possible error conditions that can occur when using
118/// the OSAL-RS library.
119///
120/// # Lifetime Parameter
121///
122/// The error type is generic over lifetime `'a` to allow flexible error messages.
123/// Most of the time, you can use the default [`Result<T>`] type alias which uses
124/// `Error<'static>`. For custom lifetimes in error messages, use
125/// `core::result::Result<T, Error<'a>>` explicitly.
126///
127/// # Examples
128///
129/// ## Basic usage with static errors
130///
131/// ```ignore
132/// use osal_rs::os::{Queue, QueueFn};
133/// use osal_rs::utils::Error;
134/// 
135/// match Queue::new(10, 32) {
136///     Ok(queue) => { /* use queue */ },
137///     Err(Error::OutOfMemory) => println!("Failed to allocate queue"),
138///     Err(e) => println!("Other error: {:?}", e),
139/// }
140/// ```
141///
142/// ## Using borrowed error messages
143///
144/// ```ignore
145/// use osal_rs::utils::Error;
146/// 
147/// fn validate_input(input: &str) -> core::result::Result<(), Error> {
148///     if input.is_empty() {
149///         // Use static lifetime for compile-time strings
150///         Err(Error::Unhandled("Input cannot be empty"))
151///     } else {
152///         Ok(())
153///     }
154/// }
155/// 
156/// // For dynamic error messages from borrowed data
157/// fn process_data<'a>(data: &'a str) -> core::result::Result<(), Error<'a>> {
158///     if !data.starts_with("valid:") {
159///         // Error message borrows from 'data' lifetime
160///         Err(Error::ReadError(data))
161///     } else {
162///         Ok(())
163///     }
164/// }
165/// ```
166#[derive(Debug, Clone, PartialEq, Eq, Hash)]
167pub enum Error<'a> {
168    /// Insufficient memory to complete operation
169    OutOfMemory,
170    /// Queue send operation timed out
171    QueueSendTimeout,
172    /// Queue receive operation timed out
173    QueueReceiveTimeout,
174    /// Mutex operation timed out
175    MutexTimeout,
176    /// Failed to acquire mutex lock
177    MutexLockFailed,
178    /// Generic timeout error
179    Timeout,
180    /// Queue is full and cannot accept more items
181    QueueFull,
182    /// String conversion failed
183    StringConversionError,
184    /// Thread/task not found
185    TaskNotFound,
186    /// Invalid queue size specified
187    InvalidQueueSize,
188    /// Null pointer encountered
189    NullPtr,
190    /// Requested item not found
191    NotFound,
192    /// Index out of bounds
193    OutOfIndex,
194    /// Invalid type for operation
195    InvalidType,
196    /// No data available
197    Empty,
198    /// Write error occurred
199    WriteError(&'a str),
200    /// Read error occurred
201    ReadError(&'a str),
202    /// Return error with code
203    ReturnWithCode(i32),
204    /// Unhandled error with description
205    Unhandled(&'a str),
206    /// Unhandled error with description owned
207    UnhandledOwned(String)
208}
209
210impl<'a> Display for Error<'a> {
211    /// Formats the error for display.
212    ///
213    /// Provides human-readable error messages suitable for logging or
214    /// presentation to users.
215    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
216        use Error::*;
217
218        match self {
219            OutOfMemory => write!(f, "Out of memory"),
220            QueueSendTimeout => write!(f, "Queue send timeout"),
221            QueueReceiveTimeout => write!(f, "Queue receive timeout"),
222            MutexTimeout => write!(f, "Mutex timeout"),
223            MutexLockFailed => write!(f, "Mutex lock failed"),
224            Timeout => write!(f, "Operation timeout"),
225            QueueFull => write!(f, "Queue full"),
226            StringConversionError => write!(f, "String conversion error"),
227            TaskNotFound => write!(f, "Task not found"),
228            InvalidQueueSize => write!(f, "Invalid queue size"),
229            NullPtr => write!(f, "Null pointer encountered"),
230            NotFound => write!(f, "Item not found"),
231            OutOfIndex => write!(f, "Index out of bounds"),
232            InvalidType => write!(f, "Invalid type for operation"),
233            Empty => write!(f, "No data available"),
234            WriteError(desc) => write!(f, "Write error occurred: {}", desc),
235            ReadError(desc) => write!(f, "Read error occurred: {}", desc),
236            ReturnWithCode(code) => write!(f, "Return with code: {}", code),
237            Unhandled(desc) => write!(f, "Unhandled error: {}", desc),
238            UnhandledOwned(desc) => write!(f, "Unhandled error owned: {}", desc),
239        }
240    }
241}
242
243
244/// CPU register size enumeration.
245///
246/// Identifies whether the target CPU uses 32-bit or 64-bit registers.
247/// This is used for platform-specific tick count overflow handling and
248/// time calculation optimizations.
249///
250/// # Usage
251///
252/// Typically determined at compile time via [`register_bit_size()`] which
253/// checks `size_of::<usize>()`.
254///
255/// # Examples
256///
257/// ```ignore
258/// use osal_rs::utils::{CpuRegisterSize, register_bit_size};
259///
260/// match register_bit_size() {
261///     CpuRegisterSize::Bit64 => {
262///         // Use 64-bit optimized calculations
263///     }
264///     CpuRegisterSize::Bit32 => {
265///         // Use 32-bit overflow-safe calculations
266///     }
267/// }
268/// ```
269#[derive(PartialEq, Eq, Clone, Copy, Debug)]
270pub enum CpuRegisterSize {
271    /// 64-bit CPU registers (e.g., ARM Cortex-A, x86_64).
272    ///
273    /// On these platforms, `usize` is 8 bytes.
274    Bit64,
275    
276    /// 32-bit CPU registers (e.g., ARM Cortex-M, RP2040, ESP32).
277    ///
278    /// On these platforms, `usize` is 4 bytes.
279    Bit32
280}
281
282/// Boolean type compatible with RTOS return values.
283///
284/// Many RTOS functions return 0 for success and non-zero for failure.
285/// This type provides a Rust-idiomatic way to work with such values.
286///
287/// # Examples
288///
289/// ```ignore
290/// use osal_rs::os::{Semaphore, SemaphoreFn};
291/// use osal_rs::utils::OsalRsBool;
292/// use core::time::Duration;
293/// 
294/// let sem = Semaphore::new(1, 1).unwrap();
295/// 
296/// match sem.wait(Duration::from_millis(100)) {
297///     OsalRsBool::True => println!("Acquired semaphore"),
298///     OsalRsBool::False => println!("Failed to acquire"),
299/// }
300/// 
301/// // Can also convert to bool
302/// if sem.signal().into() {
303///     println!("Semaphore signaled");
304/// }
305/// ```
306#[derive(PartialEq, Eq, Clone, Copy, Debug)]
307#[repr(u8)]
308pub enum OsalRsBool {
309    /// Operation failed or condition is false
310    False = 1,
311    /// Operation succeeded or condition is true
312    True = 0
313}
314
315/// Maximum delay constant for blocking operations.
316///
317/// When used as a timeout parameter, indicates the operation should
318/// block indefinitely until it succeeds.
319///
320/// # Examples
321///
322/// ```ignore
323/// use osal_rs::os::{Mutex, MutexFn};
324/// use osal_rs::utils::MAX_DELAY;
325/// 
326/// let mutex = Mutex::new(0);
327/// let guard = mutex.lock();  // Blocks forever if needed
328/// ```
329pub const MAX_DELAY: Duration = Duration::from_millis(usize::MAX as u64);
330
331/// Standard Result type for OSAL-RS operations.
332///
333/// Uses [`Error`] as the default error type with `'static` lifetime.
334/// For custom lifetimes, use `core::result::Result<T, Error<'a>>`.
335///
336/// # Examples
337///
338/// ```ignore
339/// use osal_rs::utils::Result;
340///
341/// fn create_resource() -> Result<ResourceHandle> {
342///     // Returns Result<ResourceHandle, Error<'static>>
343///     Ok(ResourceHandle::new())
344/// }
345/// ```
346pub type Result<T, E = Error<'static>> = core::result::Result<T, E>;
347
348/// Pointer to pointer type for C FFI.
349///
350/// Equivalent to `void**` in C. Used for double indirection in FFI calls.
351pub type DoublePtr = *mut *mut c_void;
352
353/// Mutable pointer type for C FFI.
354///
355/// Equivalent to `void*` in C. Used for generic mutable data pointers.
356pub type Ptr = *mut c_void;
357
358/// Const pointer type for C FFI.
359///
360/// Equivalent to `const void*` in C. Used for generic immutable data pointers.
361pub type ConstPtr = *const c_void;
362
363
364/// Determines the CPU register size at compile time.
365///
366/// This constant function checks the size of `usize` to determine whether
367/// the target architecture uses 32-bit or 64-bit registers. This information
368/// is used for platform-specific optimizations and overflow handling.
369///
370/// # Returns
371///
372/// * [`CpuRegisterSize::Bit64`] - For 64-bit architectures
373/// * [`CpuRegisterSize::Bit32`] - For 32-bit architectures
374///
375/// # Examples
376///
377/// ```ignore
378/// use osal_rs::utils::{register_bit_size, CpuRegisterSize};
379/// 
380/// match register_bit_size() {
381///     CpuRegisterSize::Bit64 => println!("Running on 64-bit platform"),
382///     CpuRegisterSize::Bit32 => println!("Running on 32-bit platform"),
383/// }
384/// ```
385pub const fn register_bit_size() -> CpuRegisterSize {
386    if size_of::<usize>() == 8 {
387        CpuRegisterSize::Bit64
388    } else {
389        CpuRegisterSize::Bit32
390    }
391}
392
393/// Converts a C string pointer to a Rust String.
394///
395/// This macro safely converts a raw C string pointer (`*const c_char`) into
396/// a Rust `String`. It handles UTF-8 conversion gracefully using lossy conversion.
397///
398/// # Safety
399///
400/// The pointer must be valid and point to a null-terminated C string.
401///
402/// # Examples
403///
404/// ```ignore
405/// use osal_rs::from_c_str;
406/// use core::ffi::c_char;
407/// 
408/// extern "C" {
409///     fn get_system_name() -> *const c_char;
410/// }
411/// 
412/// let name = from_c_str!(get_system_name());
413/// println!("System: {}", name);
414/// ```
415#[macro_export]
416macro_rules! from_c_str {
417    ($str:expr) => {
418        unsafe {
419            let c_str = core::ffi::CStr::from_ptr($str);
420            alloc::string::String::from_utf8_lossy(c_str.to_bytes()).to_string()
421        }
422    };
423}
424
425/// Converts a Rust string to a CString with error handling.
426///
427/// This macro creates a `CString` from a Rust string reference, returning
428/// a `Result` that can be used with the `?` operator. If the conversion fails
429/// (e.g., due to interior null bytes), it returns an appropriate error.
430///
431/// # Returns
432///
433/// * `Ok(CString)` - On successful conversion
434/// * `Err(Error::Unhandled)` - If the string contains interior null bytes
435///
436/// # Examples
437///
438/// ```ignore
439/// use osal_rs::to_cstring;
440/// use osal_rs::utils::Result;
441/// 
442/// fn pass_to_c_api(name: &str) -> Result<()> {
443///     let c_name = to_cstring!(name)?;
444///     // Use c_name.as_ptr() with C FFI
445///     Ok(())
446/// }
447/// ```
448#[macro_export]
449macro_rules! to_cstring {
450    ($s:expr) => {
451        alloc::ffi::CString::new($s.as_str())
452            .map_err(|_| $crate::utils::Error::Unhandled("Failed to convert string to CString"))
453    };
454}
455
456/// Converts a Rust string to a C string pointer.
457///
458/// This macro creates a `CString` from a Rust string and returns its raw pointer.
459/// **Warning**: This macro panics if the conversion fails. Consider using
460/// [`to_cstring!`] for safer error handling.
461///
462/// # Panics
463///
464/// Panics if the string contains interior null bytes.
465///
466/// # Examples
467///
468/// ```ignore
469/// use osal_rs::to_c_str;
470/// 
471/// extern "C" {
472///     fn set_name(name: *const core::ffi::c_char);
473/// }
474/// 
475/// let name = "FreeRTOS Task";
476/// unsafe {
477///     set_name(to_c_str!(name));
478/// }
479/// ```
480#[macro_export]
481macro_rules! to_c_str {
482    ($s:expr) => {
483        alloc::ffi::CString::new($s.as_ref() as &str).unwrap().as_ptr()
484    };
485}
486
487/// Converts a string to a fixed-size byte array.
488///
489/// This macro creates a byte array of the specified size and fills it with
490/// the bytes from the input string. If the string is shorter than the buffer,
491/// the remaining bytes are filled with spaces. If the string is longer, it
492/// is truncated to fit.
493///
494/// # Parameters
495///
496/// * `$str` - The source string to convert
497/// * `$buff_name` - The identifier name for the created buffer variable
498/// * `$buff_size` - The size of the byte array to create
499///
500/// # Examples
501///
502/// ```ignore
503/// use osal_rs::from_str_to_array;
504/// 
505/// let task_name = "MainTask";
506/// from_str_to_array!(task_name, name_buffer, 16);
507/// // name_buffer is now [u8; 16] containing "MainTask        "
508/// 
509/// // Use with C FFI
510/// extern "C" {
511///     fn create_task(name: *const u8, len: usize);
512/// }
513/// 
514/// unsafe {
515///     create_task(name_buffer.as_ptr(), name_buffer.len());
516/// }
517/// ```
518#[macro_export]
519macro_rules! from_str_to_array {
520    ($str:expr, $buff_name:ident, $buff_size:expr) => {
521        let mut $buff_name = [b' '; $buff_size];
522        let _bytes = $str.as_bytes();
523        let _len = core::cmp::min(_bytes.len(), $buff_size);
524        $buff_name[.._len].copy_from_slice(&_bytes[.._len]);
525    };
526}
527
528/// Extracts a typed parameter from an optional boxed Any reference.
529///
530/// This macro is used in thread/task entry points to safely extract and
531/// downcast parameters passed to the thread. It handles both the Option
532/// unwrapping and the type downcast, returning appropriate errors if either
533/// operation fails.
534///
535/// # Parameters
536///
537/// * `$param` - An `Option<Box<dyn Any>>` containing the parameter
538/// * `$t` - The type to downcast the parameter to
539///
540/// # Returns
541///
542/// * A reference to the downcasted value of type `$t`
543/// * `Err(Error::NullPtr)` - If the parameter is None
544/// * `Err(Error::InvalidType)` - If the downcast fails
545///
546/// # Examples
547///
548/// ```ignore
549/// use osal_rs::thread_extract_param;
550/// use osal_rs::utils::Result;
551/// use core::any::Any;
552/// 
553/// struct TaskConfig {
554///     priority: u8,
555///     stack_size: usize,
556/// }
557/// 
558/// fn task_entry(param: Option<Box<dyn Any>>) -> Result<()> {
559///     let config = thread_extract_param!(param, TaskConfig);
560///     
561///     println!("Priority: {}", config.priority);
562///     println!("Stack: {}", config.stack_size);
563///     
564///     Ok(())
565/// }
566/// ```
567#[macro_export]
568macro_rules! thread_extract_param {
569    ($param:expr, $t:ty) => {
570        match $param.as_ref() {
571            Some(p) => {
572                match p.downcast_ref::<$t>() {
573                    Some(value) => value,
574                    None => return Err($crate::utils::Error::InvalidType),
575                }
576            }
577            None => return Err($crate::utils::Error::NullPtr),
578        }
579    };
580}
581
582/// Accesses a static Option variable, returning the contained value or panicking if None.
583/// 
584/// This macro is used to safely access static variables that are initialized at runtime.
585/// It checks if the static variable is `Some` and returns the contained value. If the variable
586/// is `None`, it panics with a message indicating that the variable is not initialized.
587/// 
588/// # Parameters
589/// * `$static_var` - The identifier of the static variable to access
590/// # Returns
591/// * The value contained in the static variable if it is `Some`
592/// * Panics if the static variable is `None`, with a message indicating it is not initialized
593/// # Examples
594/// ```ignore
595/// use osal_rs::access_static_option;
596/// static mut CONFIG: Option<Config> = None;
597/// fn get_config() -> &'static Config {
598///     access_static_option!(CONFIG)
599/// }
600/// ```
601/// 
602/// Note: This macro assumes that the static variable is of type `Option<T>` and that it is initialized at runtime before being accessed. It is intended for use with static variables that are set up during initialization phases of the program, such as in embedded systems where certain resources are not available at compile time.
603/// 
604/// # Safety
605/// This macro uses unsafe code to access the static variable. It is the caller's responsibility to ensure that the static variable is properly initialized before it is accessed, and that it is not accessed concurrently from multiple threads without proper synchronization.
606/// # Warning
607/// This macro will panic if the static variable is not initialized (i.e., if it is `None`). It should be used in contexts where it is guaranteed that the variable will be initialized before
608/// accessing it, such as after an initialization function has been called.
609/// # Alternative
610/// For safer access to static variables, consider using a function that returns a `Result` instead of panicking, allowing the caller to handle the error condition gracefully.
611/// ```ignore
612/// fn get_config() -> Result<&'static Config, Error> {
613///    unsafe {
614///       match &*&raw const CONFIG {
615///         Some(config) => Ok(config),
616///        None => Err(Error::Unhandled("CONFIG is not initialized")),
617///     }
618///  }
619/// }
620/// ```
621/// This alternative approach allows for error handling without panicking, which can be more appropriate in many contexts, especially in production code or libraries where robustness is important.
622/// # Note
623/// This macro is intended for use in embedded systems or low-level code where static variables are commonly used for global state or resources that are initialized at runtime. It provides a convenient way to access such
624/// variables while ensuring that they are initialized, albeit with the risk of panicking if they are not. Use with caution and ensure proper initialization to avoid runtime panics.
625#[macro_export]
626macro_rules! access_static_option {
627    ($static_var:ident) => {
628        unsafe {
629            match &*&raw const $static_var {
630                Some(value) => value,
631                None => panic!(concat!(stringify!($static_var), " is not initialized")),
632            }
633        }
634    };
635}
636
637/// Trait for types that can provide a string reference in a thread-safe manner.
638///
639/// This trait extends the basic string reference functionality with thread-safety
640/// guarantees by requiring both `Sync` and `Send` bounds. It's useful for types
641/// that need to provide string data across thread boundaries in a concurrent
642/// environment.
643///
644/// # Thread Safety
645///
646/// Implementors must be both `Sync` (safe to share references across threads) and
647/// `Send` (safe to transfer ownership across threads).
648///
649/// # Examples
650///
651/// ```ignore
652/// use osal_rs::utils::AsSyncStr;
653/// 
654/// struct ThreadSafeName {
655///     name: &'static str,
656/// }
657/// 
658/// impl AsSyncStr for ThreadSafeName {
659///     fn as_str(&self) -> &str {
660///         self.name
661///     }
662/// }
663/// 
664/// // Can be safely shared across threads
665/// fn use_in_thread(item: &dyn AsSyncStr) {
666///     println!("Name: {}", item.as_str());
667/// }
668/// ```
669pub trait AsSyncStr : Sync + Send { 
670    /// Returns a string slice reference.
671    ///
672    /// This method provides access to the underlying string data in a way
673    /// that is safe to use across thread boundaries.
674    ///
675    /// # Returns
676    ///
677    /// A reference to a string slice with lifetime tied to `self`.
678    fn as_str(&self) -> &str;
679}
680
681impl PartialEq for dyn AsSyncStr + '_ {
682    fn eq(&self, other: &(dyn AsSyncStr + '_)) -> bool {
683        self.as_str() == other.as_str()
684    }
685}
686
687impl Eq for dyn AsSyncStr + '_ {}
688
689impl Debug for dyn AsSyncStr + '_ {
690    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
691        write!(f, "{}", self.as_str())
692    }
693}
694
695impl Display for dyn AsSyncStr + '_ {
696    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
697        write!(f, "{}", self.as_str())
698    }
699}
700
701
702/// Fixed-size byte array wrapper with string conversion utilities.
703///
704/// `Bytes` is a generic wrapper around a fixed-size byte array that provides
705/// convenient methods for converting between strings and byte arrays. It's
706/// particularly useful for interfacing with C APIs that expect fixed-size
707/// character buffers, or for storing strings in embedded systems with
708/// constrained memory.
709///
710/// # Type Parameters
711///
712/// * `SIZE` - The size of the internal byte array (default: 0)
713///
714/// # Examples
715///
716/// ```ignore
717/// use osal_rs::utils::Bytes;
718/// 
719/// // Create an empty 32-byte buffer
720/// let mut buffer = Bytes::<32>::new();
721/// 
722/// // Create a buffer from a string
723/// let name = Bytes::<16>::new_by_str("TaskName");
724/// println!("{}", name); // Prints "TaskName"
725/// 
726/// // Create from any type that implements ToString
727/// let number = 42;
728/// let num_bytes = Bytes::<8>::new_by_string(&number);
729/// ```
730#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
731pub struct Bytes<const SIZE: usize> (pub [u8; SIZE]);
732
733impl<const SIZE: usize> Deref for Bytes<SIZE> {
734    type Target = [u8; SIZE];
735
736    /// Dereferences to the underlying byte array.
737    ///
738    /// This allows `Bytes` to be used anywhere a `[u8; SIZE]` reference is expected.
739    ///
740    /// # Examples
741    ///
742    /// ```ignore
743    /// use osal_rs::utils::Bytes;
744    /// 
745    /// let bytes = Bytes::<8>::new_by_str("test");
746    /// assert_eq!(bytes[0], b't');
747    /// ```
748    fn deref(&self) -> &Self::Target {
749        &self.0
750    }
751}
752
753impl<const SIZE: usize> DerefMut for Bytes<SIZE> {
754    /// Provides mutable access to the underlying byte array.
755    ///
756    /// This allows `Bytes` to be mutably dereferenced, enabling direct modification
757    /// of the internal byte array through the `DerefMut` trait.
758    ///
759    /// # Examples
760    ///
761    /// ```ignore
762    /// use osal_rs::utils::Bytes;
763    /// 
764    /// let mut bytes = Bytes::<8>::new();
765    /// bytes[0] = b'H';
766    /// bytes[1] = b'i';
767    /// assert_eq!(bytes[0], b'H');
768    /// ```
769    fn deref_mut(&mut self) -> &mut Self::Target {
770        &mut self.0
771    }
772}
773
774impl<const SIZE: usize> Display for Bytes<SIZE> {
775    /// Formats the byte array as a C-style null-terminated string.
776    ///
777    /// This implementation treats the byte array as a C string and converts it
778    /// to a Rust string for display. If the conversion fails, it displays
779    /// "Conversion error".
780    ///
781    /// # Safety
782    ///
783    /// This method assumes the byte array contains valid UTF-8 data and is
784    /// null-terminated. Invalid data may result in the error message being displayed.
785    ///
786    /// # Examples
787    ///
788    /// ```ignore
789    /// use osal_rs::utils::Bytes;
790    /// 
791    /// let bytes = Bytes::<16>::new_by_str("Hello");
792    /// println!("{}", bytes); // Prints "Hello"
793    /// ```
794    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
795        let str = unsafe {
796            CStr::from_ptr(self.0.as_ptr() as *const c_char)
797            .to_str()
798            .unwrap_or("Conversion error")
799        };
800        
801        write!(f, "{}", str.to_string())
802    }
803}
804
805impl<const SIZE: usize> FromStr for Bytes<SIZE> {
806    type Err = Error<'static>;
807
808    /// Creates a `Bytes` instance from a string slice.
809    ///
810    /// This implementation allows for easy conversion from string literals or
811    /// string slices to the `Bytes` type, filling the internal byte array
812    /// with the string data and padding with spaces if necessary.
813    ///
814    /// # Examples
815    //// ```ignore
816    /// use osal_rs::utils::Bytes;
817    /// 
818    /// let bytes: Bytes<16> = "Hello".parse().unwrap();
819    /// println!("{}", bytes); // Prints "Hello"
820    /// ```
821    #[inline]
822    fn from_str(s: &str) -> core::result::Result<Self, Self::Err> {
823        Ok(Self::from_str(s))
824    }
825}
826
827impl<const SIZE: usize> From<&str> for Bytes<SIZE> {
828    /// Creates a `Bytes` instance from a string slice.
829    ///
830    /// This implementation allows for easy conversion from string literals or
831    /// string slices to the `Bytes` type, filling the internal byte array
832    /// with the string data and padding with spaces if necessary.
833    ///
834    /// # Examples
835    ///
836    /// ```ignore
837    /// use osal_rs::utils::Bytes;
838    /// 
839    /// let bytes: Bytes<16> = "Hello".into();
840    /// println!("{}", bytes); // Prints "Hello"
841    /// ```
842    #[inline]
843    fn from(s: &str) -> Self {
844        Self::from_str(s)
845    }
846}
847
848impl<const SIZE: usize> AsSyncStr for Bytes<SIZE> {
849    /// Returns a string slice reference.
850    ///
851    /// This method provides access to the underlying string data in a way
852    /// that is safe to use across thread boundaries.
853    ///
854    /// # Returns
855    ///
856    /// A reference to a string slice with lifetime tied to `self`.
857    fn as_str(&self) -> &str {
858        unsafe {
859            CStr::from_ptr(self.0.as_ptr() as *const c_char)
860            .to_str()
861            .unwrap_or("Conversion error")
862        }
863    }
864}
865
866/// Serialization implementation for `Bytes<SIZE>` when the `serde` feature is enabled.
867///
868/// This implementation provides serialization by directly serializing each byte
869/// in the array using the osal-rs-serde serialization framework.
870#[cfg(feature = "serde")]
871impl<const SIZE: usize> Serialize for Bytes<SIZE> {
872    /// Serializes the `Bytes` instance using the given serializer.
873    ///
874    /// # Parameters
875    ///
876    /// * `serializer` - The serializer to use
877    ///
878    /// # Returns
879    ///
880    /// * `Ok(())` - On successful serialization
881    /// * `Err(S::Error)` - If serialization fails
882    fn serialize<S: osal_rs_serde::Serializer>(&self, name: &str, serializer: &mut S) -> core::result::Result<(), S::Error> {
883        // Find the actual length (up to first null byte or SIZE)
884        let len = self.0.iter().position(|&b| b == 0).unwrap_or(SIZE);
885        
886        // Try to serialize as UTF-8 string if valid, otherwise as hex
887        if let Ok(s) = core::str::from_utf8(&self.0[..len]) {
888            serializer.serialize_str(name, s)
889        } else {
890            // For binary data, serialize as bytes (hex encoded)
891            serializer.serialize_bytes(name, &self.0[..len])
892        }
893    }
894}
895
896/// Deserialization implementation for `Bytes<SIZE>` when the `serde` feature is enabled.
897///
898/// This implementation provides deserialization by reading bytes from the deserializer
899/// into a fixed-size array using the osal-rs-serde deserialization framework.
900#[cfg(feature = "serde")]
901impl<const SIZE: usize> Deserialize for Bytes<SIZE> {
902    /// Deserializes a `Bytes` instance using the given deserializer.
903    ///
904    /// # Parameters
905    ///
906    /// * `deserializer` - The deserializer to use
907    ///
908    /// # Returns
909    ///
910    /// * `Ok(Bytes<SIZE>)` - A new `Bytes` instance with deserialized data
911    /// * `Err(D::Error)` - If deserialization fails
912    fn deserialize<D: osal_rs_serde::Deserializer>(deserializer: &mut D, name: &str) -> core::result::Result<Self, D::Error> {
913        let mut array = [0u8; SIZE];
914        let _ = deserializer.deserialize_bytes(name, &mut array)?;
915        Ok(Self(array))
916    }
917}
918
919/// Serialization implementation for `Bytes<SIZE>` when the `serde` feature is disabled.
920///
921/// This implementation provides basic serialization by directly returning a reference
922/// to the underlying byte array. It's used when the library is compiled without the
923/// `serde` feature, providing a lightweight alternative serialization mechanism.
924#[cfg(not(feature = "serde"))]
925impl<const SIZE: usize> Serialize for Bytes<SIZE> {
926    /// Converts the `Bytes` instance to a byte slice.
927    ///
928    /// # Returns
929    ///
930    /// A reference to the internal byte array.
931    fn to_bytes(&self) -> &[u8] {
932        &self.0
933    }
934}
935
936/// Deserialization implementation for `Bytes<SIZE>` when the `serde` feature is disabled.
937///
938/// This implementation provides basic deserialization by copying bytes from a slice
939/// into a fixed-size array. If the source slice is shorter than `SIZE`, the remaining
940/// bytes are zero-filled. If longer, it's truncated to fit.
941#[cfg(not(feature = "serde"))]
942impl<const SIZE: usize> Deserialize for Bytes<SIZE> {
943    /// Creates a `Bytes` instance from a byte slice.
944    ///
945    /// # Parameters
946    ///
947    /// * `bytes` - The source byte slice to deserialize from
948    ///
949    /// # Returns
950    ///
951    /// * `Ok(Bytes<SIZE>)` - A new `Bytes` instance with data copied from the slice
952    ///
953    /// # Examples
954    ///
955    /// ```ignore
956    /// use osal_rs::utils::Bytes;
957    /// use osal_rs::os::Deserialize;
958    /// 
959    /// let data = b"Hello";
960    /// let bytes = Bytes::<16>::from_bytes(data).unwrap();
961    /// // Result: [b'H', b'e', b'l', b'l', b'o', 0, 0, 0, ...]
962    /// ```
963    fn from_bytes(bytes: &[u8]) -> Result<Self> {
964        let mut array = [0u8; SIZE];
965        let len = core::cmp::min(bytes.len(), SIZE);
966        array[..len].copy_from_slice(&bytes[..len]);
967        Ok(Self( array ))
968    }
969}
970
971
972/// Default implementation for `Bytes<SIZE>`.
973/// This provides a default value for `Bytes<SIZE>`, which is a zero-initialized byte array. This allows `Bytes` to be used in contexts that require a default value, such as when using the `Default` trait or when initializing variables without explicit values.
974/// # Examples
975/// ```ignore
976/// use osal_rs::utils::Bytes;
977/// 
978/// let default_bytes: Bytes<16> = Default::default();
979/// assert_eq!(default_bytes[0], 0);
980/// ```
981/// The default implementation initializes the internal byte array to all zeros, which is a common default state for byte buffers in embedded systems and C APIs. This ensures that any uninitialized `Bytes` instance will contain predictable data (zeros) rather than random memory content.
982/// This is particularly useful when `Bytes` is used as a buffer for C string operations, as it ensures that the buffer starts in a known state. Additionally, it allows for easy creation of empty buffers that can be filled later without needing to manually initialize the array each time.
983/// Overall, this default implementation enhances the usability of the `Bytes` type by providing a sensible default state that is commonly needed in embedded and systems programming contexts.
984/// 
985impl<const SIZE: usize> Default for Bytes<SIZE> {
986    /// Provides a default value for `Bytes<SIZE>`, which is a zero-initialized byte array.
987    ///
988    /// This implementation allows `Bytes` to be used in contexts that require a default value,
989    /// such as when using the `Default` trait or when initializing variables without explicit values.
990    ///
991    /// # Examples
992    ///
993    /// ```ignore
994    /// use osal_rs::utils::Bytes;
995    /// 
996    /// let default_bytes: Bytes<16> = Default::default();
997    /// assert_eq!(default_bytes[0], 0);
998    /// ```
999    fn default() -> Self {
1000        Self( [0u8; SIZE] )
1001    }
1002}
1003
1004impl<const SIZE: usize> Bytes<SIZE> {
1005    /// Creates a new `Bytes` instance filled with zeros.
1006    ///
1007    /// This is a const function, allowing it to be used in const contexts
1008    /// and static variable declarations.
1009    ///
1010    /// # Returns
1011    ///
1012    /// A `Bytes` instance with all bytes set to 0.
1013    ///
1014    /// # Examples
1015    ///
1016    /// ```ignore
1017    /// use osal_rs::utils::Bytes;
1018    /// 
1019    /// const BUFFER: Bytes<64> = Bytes::new();
1020    /// 
1021    /// let runtime_buffer = Bytes::<32>::new();
1022    /// assert_eq!(runtime_buffer[0], 0);
1023    /// ```
1024    #[inline]
1025    pub const fn new() -> Self {
1026        Self( [0u8; SIZE] )
1027    }
1028
1029    /// Creates a new `Bytes` instance from a string slice.
1030    ///
1031    /// Copies the bytes from the input string into the fixed-size array.
1032    /// If the string is shorter than `SIZE`, the remaining bytes are zero-filled.
1033    /// If the string is longer, it is truncated to fit.
1034    ///
1035    /// # Parameters
1036    ///
1037    /// * `str` - The source string to convert
1038    ///
1039    /// # Returns
1040    ///
1041    /// A `Bytes` instance containing the string data.
1042    ///
1043    /// # Examples
1044    ///
1045    /// ```ignore
1046    /// use osal_rs::utils::Bytes;
1047    ///
1048    /// let short = Bytes::<16>::new_by_str("Hi");
1049    /// // Internal array: [b'H', b'i', 0, 0, 0, ...]
1050    ///
1051    /// let exact = Bytes::<5>::new_by_str("Hello");
1052    /// // Internal array: [b'H', b'e', b'l', b'l', b'o']
1053    ///
1054    /// let long = Bytes::<3>::new_by_str("Hello");
1055    /// // Internal array: [b'H', b'e', b'l'] (truncated)
1056    /// ```
1057    pub fn from_str(str: &str) -> Self {
1058
1059        let mut array = [0u8; SIZE];
1060
1061        let mut i = 0usize ;
1062        for byte in str.as_bytes() {
1063            if i > SIZE - 1{
1064                break;
1065            }
1066            array[i] = *byte;
1067            i += 1;
1068        }
1069
1070        Self( array )
1071    }
1072
1073    /// Creates a new `Bytes` instance from a C string pointer.
1074    ///
1075    /// Safely converts a null-terminated C string pointer into a `Bytes` instance.
1076    /// If the pointer is null, returns a zero-initialized `Bytes`. The function
1077    /// copies bytes from the C string into the fixed-size array, truncating if
1078    /// the source is longer than `SIZE`.
1079    ///
1080    /// # Parameters
1081    ///
1082    /// * `ptr` - A pointer to a null-terminated C string (`*const c_char`)
1083    ///
1084    /// # Safety
1085    ///
1086    /// While this function is not marked unsafe, it internally uses `unsafe` code
1087    /// to dereference the pointer. The caller must ensure that:
1088    /// - If not null, the pointer points to a valid null-terminated C string
1089    /// - The memory the pointer references remains valid for the duration of the call
1090    ///
1091    /// # Returns
1092    ///
1093    /// A `Bytes` instance containing the C string data, or zero-initialized if the pointer is null.
1094    ///
1095    /// # Examples
1096    ///
1097    /// ```ignore
1098    /// use osal_rs::utils::Bytes;
1099    /// use core::ffi::c_char;
1100    /// use alloc::ffi::CString;
1101    ///
1102    /// // From a CString
1103    /// let c_string = CString::new("Hello").unwrap();
1104    /// let bytes = Bytes::<16>::new_by_ptr(c_string.as_ptr());
1105    ///
1106    /// // From a null pointer
1107    /// let null_bytes = Bytes::<16>::new_by_ptr(core::ptr::null());
1108    /// // Returns zero-initialized Bytes
1109    ///
1110    /// // Truncation example
1111    /// let long_string = CString::new("This is a very long string").unwrap();
1112    /// let short_bytes = Bytes::<8>::new_by_ptr(long_string.as_ptr());
1113    /// // Only first 8 bytes are copied
1114    /// ```
1115    pub fn from_char_ptr(ptr: *const c_char) -> Self {
1116        if ptr.is_null() {
1117            return Self::new();
1118        }
1119
1120        let mut array = [0u8; SIZE];
1121
1122        let mut i = 0usize ;
1123        for byte in unsafe { CStr::from_ptr(ptr) }.to_bytes() {
1124            if i > SIZE - 1{
1125                break;
1126            }
1127            array[i] = *byte;
1128            i += 1;
1129        }
1130
1131        Self( array )
1132    }
1133
1134
1135    /// Creates a new `Bytes` instance from a C unsigned char pointer.
1136    /// 
1137    /// Safely converts a pointer to an array of unsigned chars into a `Bytes` instance. If the pointer is null, returns a zero-initialized `Bytes`. The function copies bytes from the source pointer into the fixed-size array, truncating if the source is longer than `SIZE`.
1138    /// 
1139    /// # Parameters
1140    /// * `ptr` - A pointer to an array of unsigned chars (`*const c_uchar`)
1141    /// 
1142    /// # Safety
1143    /// While this function is not marked unsafe, it internally uses `unsafe` code to dereference the pointer. The caller must ensure that:
1144    /// - If not null, the pointer points to a valid array of unsigned chars with at least `SIZE` bytes
1145    /// - The memory the pointer references remains valid for the duration of the call
1146    /// 
1147    /// # Returns
1148    /// A `Bytes` instance containing the data from the source pointer, or zero-initialized if the pointer is null.
1149    /// 
1150    /// # Examples
1151    /// ```ignore
1152    /// use osal_rs::utils::Bytes;
1153    /// use core::ffi::c_uchar;
1154    /// use alloc::ffi::CString;
1155    /// 
1156    /// // From a C unsigned char pointer
1157    /// let data = [b'H', b'e', b'l', b'l', b'o', 0];
1158    /// let bytes = Bytes::<16>::from_uchar_ptr(data.as_ptr());
1159    /// 
1160    /// // From a null pointer
1161    /// let null_bytes = Bytes::<16>::from_uchar_ptr(core::ptr::null());  
1162    /// // Returns zero-initialized Bytes
1163    /// 
1164    /// // Truncation example
1165    /// let long_data = [b'T', b'h', b'i', b's', b' ', b'i', b's', b' ', b'v', b'e', b'r', b'y', b' ', b'l', b'o', b'n', b'g', 0];
1166    /// let short_bytes = Bytes::<8>::from_uchar_ptr(long_data.as_ptr());
1167    /// // Only first 8 bytes are copied
1168    /// ```
1169    pub fn from_uchar_ptr(ptr: *const c_uchar) -> Self {
1170        if ptr.is_null() {
1171            return Self::new();
1172        }
1173
1174        let mut array = [0u8; SIZE];
1175
1176        let mut i = 0usize ;
1177        for byte in unsafe { core::slice::from_raw_parts(ptr, SIZE) } {
1178            if i > SIZE - 1{
1179                break;
1180            }
1181            array[i] = *byte;
1182            i += 1;
1183        }
1184
1185        Self( array )
1186    }
1187
1188    /// Creates a new `Bytes` instance from any type implementing `ToString`.
1189    ///
1190    /// This is a convenience wrapper around [`new_by_str`](Self::new_by_str)
1191    /// that first converts the input to a string.
1192    ///
1193    /// # Parameters
1194    ///
1195    /// * `str` - Any value that implements `ToString`
1196    ///
1197    /// # Returns
1198    ///
1199    /// A `Bytes` instance containing the string representation of the input.
1200    ///
1201    /// # Examples
1202    ///
1203    /// ```ignore
1204    /// use osal_rs::utils::Bytes;
1205    ///
1206    /// // From integer
1207    /// let num_bytes = Bytes::<8>::new_by_string(&42);
1208    ///
1209    /// // From String
1210    /// let string = String::from("Task");
1211    /// let str_bytes = Bytes::<16>::new_by_string(&string);
1212    ///
1213    /// // From custom type with ToString
1214    /// #[derive(Debug)]
1215    /// struct TaskId(u32);
1216    /// impl ToString for TaskId {
1217    ///     fn to_string(&self) -> String {
1218    ///         format!("Task-{}", self.0)
1219    ///     }
1220    /// }
1221    /// let task_bytes = Bytes::<16>::new_by_string(&TaskId(5));
1222    /// ```
1223    #[inline]
1224    pub fn from_as_sync_str(str: &impl ToString) -> Self {
1225        Self::from_str(&str.to_string())
1226    }
1227
1228    /// Creates a new `Bytes` instance from a byte slice.
1229    /// 
1230    /// This function copies bytes from the input slice into the fixed-size array. If the slice is shorter than `SIZE`, the remaining bytes are zero-filled. If the slice is longer, it is truncated to fit.
1231    /// 
1232    /// # Parameters
1233    /// * `bytes` - The source byte slice to convert
1234    /// 
1235    /// # Returns
1236    /// A `Bytes` instance containing the data from the byte slice.
1237    /// 
1238    /// # Examples
1239    /// ```ignore
1240    /// use osal_rs::utils::Bytes;
1241    /// 
1242    /// let data = b"Hello";
1243    /// let bytes = Bytes::<16>::from_bytes(data);
1244    /// // Result: [b'H', b'e', b'l', b'l', b'o', 0, 0, 0, ...]
1245    /// ```
1246    pub fn from_bytes(bytes: &[u8]) -> Self {
1247        let mut array = [0u8; SIZE];
1248        let len = core::cmp::min(bytes.len(), SIZE);
1249        array[..len].copy_from_slice(&bytes[..len]);
1250        Self( array )
1251    }
1252
1253    /// Fills a mutable string slice with the contents of the byte array.
1254    ///
1255    /// Attempts to convert the internal byte array to a UTF-8 string and
1256    /// copies it into the destination string slice. Only copies up to the
1257    /// minimum of the source and destination lengths.
1258    ///
1259    /// # Parameters
1260    ///
1261    /// * `dest` - The destination string slice to fill
1262    ///
1263    /// # Returns
1264    ///
1265    /// `Ok(())` if the operation succeeds, or `Err(Error::StringConversionError)` if the byte array cannot be converted to a valid UTF-8 string.
1266    ///
1267    /// # Examples
1268    ///
1269    /// ```ignore
1270    /// use osal_rs::utils::Bytes;
1271    /// 
1272    /// let bytes = Bytes::<16>::new_by_str("Hello World");
1273    /// 
1274    /// let mut output = String::from("                "); // 16 spaces
1275    /// bytes.fill_str(unsafe { output.as_mut_str() });
1276    /// 
1277    /// assert_eq!(&output[..11], "Hello World");
1278    /// ```
1279    pub fn fill_str(&mut self, dest: &mut str) -> Result<()>{
1280        match from_utf8_mut(&mut self.0) {
1281            Ok(str) => {
1282                let len = core::cmp::min(str.len(), dest.len());
1283                unsafe {
1284                    dest.as_bytes_mut()[..len].copy_from_slice(&str.as_bytes()[..len]);
1285                }
1286                Ok(())
1287            }
1288            Err(_) => Err(Error::StringConversionError),
1289        }
1290    }
1291
1292    /// Creates a new `Bytes` instance from a C string pointer.
1293    ///
1294    /// This is a convenience wrapper around [`new_by_ptr`](Self::new_by_ptr) that directly converts a C string pointer to a `Bytes` instance.
1295    /// If the pointer is null, it returns a zero-initialized `Bytes`. The function copies bytes from the C string into the fixed-size array, truncating if the source is longer than `SIZE`.
1296    ///
1297    /// # Parameters
1298    ///
1299    /// * `str` - A pointer to a null-terminated C string (`*const c_char`)
1300    ///
1301    /// # Safety
1302    ///
1303    /// This method uses `unsafe` code to dereference the pointer. The caller must ensure that:
1304    /// - If not null, the pointer points to a valid null-terminated C string
1305    /// - The memory the pointer references remains valid for the duration of the call
1306    ///
1307    /// - The byte array can be safely interpreted as UTF-8 if the conversion is expected to succeed. If the byte array contains invalid UTF-8, the resulting `Bytes` instance will contain the raw bytes, and the `Display` implementation will show "Conversion error" when attempting to display it as a string.
1308    ///
1309    /// # Returns
1310    ///
1311    /// A `Bytes` instance containing the C string data, or zero-initialized if the pointer is null.
1312    ///
1313    /// # Examples
1314    ///
1315    /// ```ignore
1316    /// use osal_rs::utils::Bytes;
1317    /// use core::ffi::c_char;
1318    /// use alloc::ffi::CString;
1319    /// 
1320    /// // From a CString
1321    /// let c_string = CString::new("Hello").unwrap();
1322    /// let bytes = Bytes::<16>::from_cstr(c_string.as_ptr());
1323    /// 
1324    /// // From a null pointer
1325    /// let null_bytes = Bytes::<16>::from_cstr(core::ptr::null());
1326    /// // Returns zero-initialized Bytes
1327    /// 
1328    /// // Truncation example
1329    /// let long_string = CString::new("This is a very long string").unwrap();
1330    /// let short_bytes = Bytes::<8>::from_cstr(long_string.as_ptr());
1331    /// // Only first 8 bytes are copied
1332    /// ```
1333    #[inline]
1334    pub fn from_cstr(str: *const c_char) -> Self {
1335        Self::from_bytes(unsafe { CStr::from_ptr(str) }.to_bytes())
1336    }
1337
1338    /// Converts the byte array to a C string reference.
1339    ///
1340    /// Creates a `CStr` reference from the internal byte array, treating it as
1341    /// a null-terminated C string. This is useful for passing strings to C FFI
1342    /// functions that expect `*const c_char` or `&CStr`.
1343    ///
1344    /// # Safety
1345    ///
1346    /// This method assumes the byte array is already null-terminated. All
1347    /// constructors (`new()`, `from_str()`, `from_char_ptr()`, etc.) guarantee
1348    /// this property by initializing with `[0u8; SIZE]`.
1349    ///
1350    /// However, if you've manually modified the array via `DerefMut`,
1351    /// you must ensure the last byte remains 0.
1352    ///
1353    /// # Returns
1354    ///
1355    /// A reference to a `CStr` with lifetime tied to `self`.
1356    ///
1357    /// # Examples
1358    ///
1359    /// ```ignore
1360    /// use osal_rs::utils::Bytes;
1361    /// 
1362    /// let bytes = Bytes::<16>::new_by_str("Hello");
1363    /// let c_str = bytes.as_cstr();
1364    /// 
1365    /// extern "C" {
1366    ///     fn print_string(s: *const core::ffi::c_char);
1367    /// }
1368    /// 
1369    /// unsafe {
1370    ///     print_string(c_str.as_ptr());
1371    /// }
1372    /// ```
1373    #[inline]
1374    pub fn as_cstr(&self) -> &CStr {
1375        unsafe {
1376            CStr::from_ptr(self.0.as_ptr() as *const c_char)
1377        }
1378    }
1379
1380    /// Converts the byte array to a C string reference, ensuring null-termination.
1381    ///
1382    /// This is a safer version of `as_cstr()` that explicitly guarantees
1383    /// null-termination by modifying the last byte. Use this if you've
1384    /// manually modified the array and want to ensure it's null-terminated.
1385    ///
1386    /// # Returns
1387    ///
1388    /// A reference to a `CStr` with lifetime tied to `self`.
1389    ///
1390    /// # Examples
1391    ///
1392    /// ```ignore
1393    /// use osal_rs::utils::Bytes;
1394    /// 
1395    /// let mut bytes = Bytes::<16>::new();
1396    /// bytes[0] = b'H';
1397    /// bytes[1] = b'i';
1398    /// // After manual modification, ensure null-termination
1399    /// let c_str = bytes.as_cstr_mut();
1400    /// ```
1401    #[inline]
1402    pub fn as_cstr_mut(&mut self) -> &CStr {
1403        unsafe {
1404            self.0[SIZE - 1] = 0; // Ensure null-termination
1405            CStr::from_ptr(self.0.as_ptr() as *const c_char)
1406        }
1407    }
1408
1409    /// Appends a string slice to the existing content in the `Bytes` buffer.
1410    ///
1411    /// This method finds the current end of the content (first null byte) and appends
1412    /// the provided string starting from that position. If the buffer is already full
1413    /// or if the appended content would exceed the buffer size, the content is truncated
1414    /// to fit within the `SIZE` limit.
1415    ///
1416    /// # Parameters
1417    ///
1418    /// * `str` - The string slice to append
1419    ///
1420    /// # Examples
1421    ///
1422    /// ```
1423    /// use osal_rs::utils::Bytes;
1424    ///
1425    /// let mut bytes = Bytes::<16>::new_by_str("Hello");
1426    /// bytes.append_str(" World");
1427    /// assert_eq!(bytes.as_str(), "Hello World");
1428    ///
1429    /// // Truncation when exceeding buffer size
1430    /// let mut small_bytes = Bytes::<8>::new_by_str("Hi");
1431    /// small_bytes.append_str(" there friend");
1432    /// assert_eq!(small_bytes.as_str(), "Hi ther");
1433    /// ```
1434    pub fn append_str(&mut self, str: &str) {
1435        let current_len = self.0.iter().position(|&b| b == 0).unwrap_or(SIZE);
1436        let mut i = current_len;
1437        for byte in str.as_bytes() {
1438            if i > SIZE - 1{
1439                break;
1440            }
1441            self.0[i] = *byte;
1442            i += 1;
1443        }
1444    }
1445
1446    /// Appends content from any type implementing `AsSyncStr` to the buffer.
1447    ///
1448    /// This method accepts any type that implements the `AsSyncStr` trait, converts
1449    /// it to a string slice, and appends it to the existing content. If the buffer
1450    /// is already full or if the appended content would exceed the buffer size,
1451    /// the content is truncated to fit within the `SIZE` limit.
1452    ///
1453    /// # Parameters
1454    ///
1455    /// * `c_str` - A reference to any type implementing `AsSyncStr`
1456    ///
1457    /// # Examples
1458    ///
1459    /// ```ignore
1460    /// use osal_rs::utils::Bytes;
1461    ///
1462    /// let mut bytes = Bytes::<16>::new_by_str("Hello");
1463    /// let other_bytes = Bytes::<8>::new_by_str(" World");
1464    /// bytes.append_as_sync_str(&other_bytes);
1465    /// assert_eq!(bytes.as_str(), "Hello World");
1466    /// ```
1467    pub fn append_as_sync_str(&mut self, c_str: & impl AsSyncStr) {
1468        let current_len = self.0.iter().position(|&b| b == 0).unwrap_or(SIZE);
1469        let mut i = current_len;
1470        for byte in c_str.as_str().as_bytes() {
1471            if i > SIZE - 1{
1472                break;
1473            }
1474            self.0[i] = *byte;
1475            i += 1;
1476        }
1477    }
1478
1479    /// Appends raw bytes to the existing content in the `Bytes` buffer.
1480    ///
1481    /// This method finds the current end of the content (first null byte) and appends
1482    /// the provided byte slice starting from that position. If the buffer is already
1483    /// full or if the appended content would exceed the buffer size, the content is
1484    /// truncated to fit within the `SIZE` limit.
1485    ///
1486    /// # Parameters
1487    ///
1488    /// * `bytes` - The byte slice to append
1489    ///
1490    /// # Examples
1491    ///
1492    /// ```
1493    /// use osal_rs::utils::Bytes;
1494    ///
1495    /// let mut bytes = Bytes::<16>::new_by_str("Hello");
1496    /// bytes.append_bytes(b" World");
1497    /// assert_eq!(bytes.as_str(), "Hello World");
1498    ///
1499    /// // Appending arbitrary bytes
1500    /// let mut data = Bytes::<16>::new_by_str("Data: ");
1501    /// data.append_bytes(&[0x41, 0x42, 0x43]);
1502    /// assert_eq!(data.as_str(), "Data: ABC");
1503    /// ```
1504    pub fn append_bytes(&mut self, bytes: &[u8]) {
1505        let current_len = self.0.iter().position(|&b| b == 0).unwrap_or(SIZE);
1506        let mut i = current_len;
1507        for byte in bytes {
1508            if i > SIZE - 1{
1509                break;
1510            }
1511            self.0[i] = *byte;
1512            i += 1;
1513        }
1514    }
1515
1516    /// Appends the content of another `Bytes` instance to this buffer.
1517    ///
1518    /// This method allows appending content from a `Bytes` instance of a different
1519    /// size (specified by the generic parameter `OHTER_SIZE`). The method finds the
1520    /// current end of the content (first null byte) and appends the content from the
1521    /// other `Bytes` instance. If the buffer is already full or if the appended content
1522    /// would exceed the buffer size, the content is truncated to fit within the `SIZE` limit.
1523    ///
1524    /// # Type Parameters
1525    ///
1526    /// * `OTHER_SIZE` - The size of the source `Bytes` buffer (can be different from `SIZE`)
1527    ///
1528    /// # Parameters
1529    ///
1530    /// * `other` - A reference to the `Bytes` instance to append
1531    ///
1532    /// # Examples
1533    ///
1534    /// ```
1535    /// use osal_rs::utils::Bytes;
1536    ///
1537    /// let mut bytes = Bytes::<16>::new_by_str("Hello");
1538    /// let other = Bytes::<8>::new_by_str(" World");
1539    /// bytes.append(&other);
1540    /// assert_eq!(bytes.as_str(), "Hello World");
1541    ///
1542    /// // Appending from a larger buffer
1543    /// let mut small = Bytes::<8>::new_by_str("Hi");
1544    /// let large = Bytes::<32>::new_by_str(" there friend");
1545    /// small.append(&large);
1546    /// assert_eq!(small.as_str(), "Hi ther");
1547    /// ```
1548    pub fn append<const OTHER_SIZE: usize>(&mut self, other: &Bytes<OTHER_SIZE>) {
1549        let current_len = self.0.iter().position(|&b| b == 0).unwrap_or(SIZE);
1550        let mut i = current_len;
1551        for &byte in other.0.iter() {
1552            if i > SIZE - 1{
1553                break;
1554            }
1555            self.0[i] = byte;
1556            i += 1;
1557        }
1558    }
1559
1560    /// Clears all content from the buffer, filling it with zeros.
1561    ///
1562    /// This method resets the entire internal byte array to zeros, effectively
1563    /// clearing any stored data. After calling this method, the buffer will be
1564    /// empty and ready for new content.
1565    ///
1566    /// # Examples
1567    ///
1568    /// ```ignore
1569    /// use osal_rs::utils::Bytes;
1570    ///
1571    /// let mut bytes = Bytes::<16>::new_by_str("Hello");
1572    /// assert!(!bytes.is_empty());
1573    ///
1574    /// bytes.clear();
1575    /// assert!(bytes.is_empty());
1576    /// assert_eq!(bytes.len(), 0);
1577    /// ```
1578    pub fn clear(&mut self) {
1579        for byte in self.0.iter_mut() {
1580            *byte = 0;
1581        }
1582    }
1583
1584    /// Returns the length of the content in the buffer.
1585    ///
1586    /// The length is determined by finding the position of the first null byte (0).
1587    /// If no null byte is found, returns `SIZE`, indicating the buffer is completely
1588    /// filled with non-zero data.
1589    ///
1590    /// # Returns
1591    ///
1592    /// The number of bytes before the first null terminator, or `SIZE` if the
1593    /// buffer is completely filled.
1594    ///
1595    /// # Examples
1596    ///
1597    /// ```ignore
1598    /// use osal_rs::utils::Bytes;
1599    ///
1600    /// let bytes = Bytes::<16>::new_by_str("Hello");
1601    /// assert_eq!(bytes.len(), 5);
1602    ///
1603    /// let empty = Bytes::<16>::new();
1604    /// assert_eq!(empty.len(), 0);
1605    ///
1606    /// // Buffer completely filled (no null terminator)
1607    /// let mut full = Bytes::<4>::new();
1608    /// full[0] = b'A';
1609    /// full[1] = b'B';
1610    /// full[2] = b'C';
1611    /// full[3] = b'D';
1612    /// assert_eq!(full.len(), 4);
1613    /// ```
1614    #[inline]
1615    pub fn len(&self) -> usize {
1616        self.0.iter().position(|&b| b == 0).unwrap_or(SIZE)
1617    }
1618
1619    /// Returns a byte slice of the content in the buffer.
1620    /// 
1621    /// This method returns a slice of the internal byte array up to the first null byte (0). If no null byte is found, it returns a slice of the entire array. This allows you to access the valid content stored in the buffer without including any trailing zeros.
1622    /// 
1623    /// # Returns
1624    /// A byte slice containing the content of the buffer up to the first null terminator.
1625    /// 
1626    /// # Examples
1627    /// ```ignore
1628    /// use osal_rs::utils::Bytes;
1629    /// 
1630    /// let bytes = Bytes::<16>::new_by_str("Hello");
1631    /// assert_eq!(bytes.as_raw_bytes(), b"Hello");
1632    /// 
1633    /// let empty = Bytes::<16>::new();
1634    /// assert_eq!(empty.as_raw_bytes(), b"");
1635    /// 
1636    /// let full = Bytes::<4>::new_by_str("ABCD");
1637    /// assert_eq!(full.as_raw_bytes(), b"ABCD");
1638    /// ``` 
1639    #[inline]
1640    pub fn as_raw_bytes(&self) -> &[u8] {
1641        &self.0[..self.len()]
1642    }
1643
1644    /// Returns the fixed size of the buffer.
1645    /// 
1646    /// This method returns the compile-time constant `SIZE`, which represents the total capacity of the internal byte array. The size is determined by the generic parameter `SIZE` specified when creating the `Bytes` instance. This value is fixed and does not change during the lifetime of the instance.
1647    /// # Returns
1648    /// The fixed size of the buffer in bytes (`SIZE`).
1649    /// # Examples
1650    /// ```ignore
1651    /// use osal_rs::utils::Bytes;
1652    /// 
1653    /// let bytes = Bytes::<32>::new();
1654    /// assert_eq!(bytes.size(), 32);
1655    /// 
1656    /// let other = Bytes::<128>::new_by_str("Hello");
1657    /// assert_eq!(other.size(), 128);
1658    /// ```
1659    #[inline]
1660    pub const fn size(&self) -> usize {
1661        SIZE
1662    }
1663
1664    /// Checks if the buffer is empty.
1665    ///
1666    /// A buffer is considered empty if all bytes are zero. This method searches
1667    /// for the first non-zero byte to determine emptiness.
1668    ///
1669    /// # Returns
1670    ///
1671    /// `true` if all bytes are zero, `false` otherwise.
1672    ///
1673    /// # Examples
1674    ///
1675    /// ```ignore
1676    /// use osal_rs::utils::Bytes;
1677    ///
1678    /// let empty = Bytes::<16>::new();
1679    /// assert!(empty.is_empty());
1680    ///
1681    /// let bytes = Bytes::<16>::new_by_str("Hello");
1682    /// assert!(!bytes.is_empty());
1683    ///
1684    /// let mut cleared = Bytes::<16>::new_by_str("Test");
1685    /// cleared.clear();
1686    /// assert!(cleared.is_empty());
1687    /// ```
1688    #[inline]
1689    pub fn is_empty(&self) -> bool {
1690        self.0.iter().position(|&b| b != 0).is_none()
1691    }
1692
1693    /// Returns the total capacity of the buffer.
1694    ///
1695    /// This is the fixed size of the internal byte array, determined at compile
1696    /// time by the generic `SIZE` parameter. The capacity never changes during
1697    /// the lifetime of the `Bytes` instance.
1698    ///
1699    /// # Returns
1700    ///
1701    /// The total capacity in bytes (`SIZE`).
1702    ///
1703    /// # Examples
1704    ///
1705    /// ```ignore
1706    /// use osal_rs::utils::Bytes;
1707    ///
1708    /// let bytes = Bytes::<32>::new();
1709    /// assert_eq!(bytes.capacity(), 32);
1710    ///
1711    /// let other = Bytes::<128>::new_by_str("Hello");
1712    /// assert_eq!(other.capacity(), 128);
1713    /// ```
1714    #[inline]
1715    pub fn capacity(&self) -> usize {
1716        SIZE
1717    }
1718
1719    /// Replaces all occurrences of a byte pattern with another pattern.
1720    ///
1721    /// This method searches for all occurrences of the `find` byte sequence within
1722    /// the buffer and replaces them with the `replace` byte sequence. The replacement
1723    /// is performed in a single pass, and the method handles cases where the replacement
1724    /// is larger, smaller, or equal in size to the pattern being searched for.
1725    ///
1726    /// # Parameters
1727    ///
1728    /// * `find` - The byte pattern to search for
1729    /// * `replace` - The byte pattern to replace with
1730    ///
1731    /// # Returns
1732    ///
1733    /// * `Ok(())` - If all replacements were successful
1734    /// * `Err(Error::StringConversionError)` - If the replacement would exceed the buffer capacity
1735    ///
1736    /// # Behavior
1737    ///
1738    /// - Empty `find` patterns are ignored (returns `Ok(())` immediately)
1739    /// - Multiple occurrences are replaced in a single pass
1740    /// - Content is properly shifted when replacement size differs from find size
1741    /// - Null terminators and trailing bytes are correctly maintained
1742    /// - Overlapping patterns are not re-matched (avoids infinite loops)
1743    ///
1744    /// # Examples
1745    ///
1746    /// ```ignore
1747    /// use osal_rs::utils::Bytes;
1748    ///
1749    /// // Same length replacement
1750    /// let mut bytes = Bytes::<16>::new_by_str("Hello World");
1751    /// bytes.replace(b"World", b"Rust!").unwrap();
1752    /// assert_eq!(bytes.as_str(), "Hello Rust!");
1753    ///
1754    /// // Shorter replacement
1755    /// let mut bytes2 = Bytes::<16>::new_by_str("aabbcc");
1756    /// bytes2.replace(b"bb", b"X").unwrap();
1757    /// assert_eq!(bytes2.as_str(), "aaXcc");
1758    ///
1759    /// // Longer replacement
1760    /// let mut bytes3 = Bytes::<16>::new_by_str("Hi");
1761    /// bytes3.replace(b"Hi", b"Hello").unwrap();
1762    /// assert_eq!(bytes3.as_str(), "Hello");
1763    ///
1764    /// // Multiple occurrences
1765    /// let mut bytes4 = Bytes::<32>::new_by_str("foo bar foo");
1766    /// bytes4.replace(b"foo", b"baz").unwrap();
1767    /// assert_eq!(bytes4.as_str(), "baz bar baz");
1768    ///
1769    /// // Buffer overflow error
1770    /// let mut small = Bytes::<8>::new_by_str("Hello");
1771    /// assert!(small.replace(b"Hello", b"Hello World").is_err());
1772    /// ```
1773    pub fn replace(&mut self, find: &[u8], replace: &[u8]) -> Result<()> {
1774        if find.is_empty() {
1775            return Ok(());
1776        }
1777        
1778        let mut i = 0;
1779        loop {
1780            let current_len = self.len();
1781            
1782            // Exit if we've reached the end
1783            if i >= current_len {
1784                break;
1785            }
1786            
1787            // Check if pattern starts at position i
1788            if i + find.len() <= current_len && self.0[i..i + find.len()] == *find {
1789                let remaining_len = current_len - (i + find.len());
1790                let new_len = i + replace.len() + remaining_len;
1791                
1792                // Check if replacement fits in buffer
1793                if new_len > SIZE {
1794                    return Err(Error::StringConversionError);
1795                }
1796                
1797                // Shift remaining content if sizes differ
1798                if replace.len() != find.len() {
1799                    self.0.copy_within(
1800                        i + find.len()..i + find.len() + remaining_len,
1801                        i + replace.len()
1802                    );
1803                }
1804                
1805                // Insert replacement bytes
1806                self.0[i..i + replace.len()].copy_from_slice(replace);
1807                
1808                // Update null terminator position
1809                if new_len < SIZE {
1810                    self.0[new_len] = 0;
1811                }
1812                
1813                // Clear trailing bytes if content shrunk
1814                if new_len < current_len {
1815                    for j in (new_len + 1)..=current_len {
1816                        if j < SIZE {
1817                            self.0[j] = 0;
1818                        }
1819                    }
1820                }
1821                
1822                // Move past the replacement to avoid infinite loops
1823                i += replace.len();
1824            } else {
1825                i += 1;
1826            }
1827        }
1828        
1829        Ok(())
1830    }
1831
1832    /// Converts the `Bytes` instance to a byte slice.
1833    ///
1834    /// This method provides a convenient way to access the internal byte array
1835    /// as a slice, which can be useful for C FFI or other operations that
1836    /// require byte slices.
1837    ///
1838    /// # Examples
1839    ///
1840    /// ```ignore
1841    /// use osal_rs::utils::{Bytes, ToBytes};
1842    /// 
1843    /// let bytes = Bytes::<8>::new_by_str("example");
1844    /// let byte_slice = bytes.to_bytes();
1845    /// assert_eq!(byte_slice, b"example\0\0");
1846    /// ```
1847    #[inline]
1848    pub fn to_bytes(&self) -> &[u8] {
1849        &self.0
1850    }
1851
1852    /// Pops the last byte from the buffer and returns it.
1853    ///
1854    /// This method removes the last byte of content (before the first null terminator)
1855    /// and returns it. If the buffer is empty, it returns `None`. After popping, the last byte is set to zero to maintain the null-terminated property.
1856    ///
1857    /// # Returns
1858    ///
1859    /// * `Some(u8)` - The last byte of content if the buffer is not empty
1860    /// * `None` - If the buffer is empty
1861    ///
1862    /// # Examples
1863    //// ```ignore
1864    /// use osal_rs::utils::Bytes;
1865    /// 
1866    /// let mut bytes = Bytes::<16>::new_by_str("Hello");
1867    /// assert_eq!(bytes.pop(), Some(b'o'));
1868    /// assert_eq!(bytes.as_str(), "Hell");
1869    /// 
1870    /// // Pop until empty
1871    /// assert_eq!(bytes.pop(), Some(b'l'));
1872    /// assert_eq!(bytes.pop(), Some(b'l'));
1873    /// assert_eq!(bytes.pop(), Some(b'e'));
1874    /// assert_eq!(bytes.pop(), Some(b'H'));
1875    /// assert_eq!(bytes.pop(), None);
1876    /// ``` 
1877    pub fn pop(&mut self) -> Option<u8> {
1878        let len = self.len();
1879        if len == 0 {
1880            None
1881        } else {
1882            let byte = self.0[len - 1];
1883            self.0[len - 1] = 0; // Clear the popped byte
1884            Some(byte)
1885        }
1886    }
1887
1888    /// Pushes a byte to the end of the content in the buffer.
1889    ///
1890    /// # Parameters
1891    ///
1892    /// * `byte` - The byte to push into the buffer
1893    ///
1894    /// # Returns
1895    ///
1896    /// * `Ok(())` - If the byte was successfully pushed
1897    /// * `Err(Error::StringConversionError)` - If the buffer is full
1898    ///
1899    /// # Examples
1900    ///
1901    /// ```ignore
1902    /// use osal_rs::utils::Bytes;
1903    ///
1904    /// let mut bytes = Bytes::<16>::new_by_str("Hello");
1905    /// assert_eq!(bytes.push(b'!'), Ok(()));
1906    /// assert_eq!(bytes.as_str(), "Hello!");
1907    /// ```
1908    pub fn push(&mut self, byte: u8) -> Result<()> {
1909        let len = self.len();
1910        if len >= SIZE {
1911            Err(Error::StringConversionError) // Buffer is full
1912        } else {
1913            self.0[len] = byte;
1914            Ok(())
1915        }
1916    }
1917
1918    /// Pops the last byte from the buffer and returns it as a character.
1919    ///
1920    /// This method removes the last byte of content (before the first null terminator)
1921    /// and attempts to convert it to a `char`. If the buffer is empty or if the byte cannot be converted to a valid `char`, it returns `None`. After popping, the last byte is set to zero to maintain the null-terminated property.
1922    ///
1923    /// # Returns
1924    ///
1925    /// * `Some(char)` - The last byte of content as a character if the buffer is not empty and the byte is a valid character
1926    /// * `None` - If the buffer is empty or if the byte cannot be converted to a valid character
1927    ///
1928    /// # Examples
1929    //// ```ignore
1930    /// use osal_rs::utils::Bytes;
1931    /// 
1932    /// let mut bytes = Bytes::<16>::new_by_str("Hello");
1933    /// assert_eq!(bytes.pop_char(), Some('o'));
1934    /// assert_eq!(bytes.as_str(), "Hell");
1935    /// 
1936    /// // Pop until empty
1937    /// assert_eq!(bytes.pop_char(), Some('l'));
1938    /// assert_eq!(bytes.pop_char(), Some('l'));
1939    /// assert_eq!(bytes.pop_char(), Some('e'));
1940    /// assert_eq!(bytes.pop_char(), Some('H'));
1941    /// assert_eq!(bytes.pop_char(), None);
1942    /// ```
1943    #[inline]
1944    pub fn pop_char(&mut self) -> Option<char> {
1945        self.pop().and_then(|byte| char::from_u32(byte as u32))
1946    }
1947
1948    /// Pushes a character to the end of the content in the buffer.
1949    ///
1950    /// This method attempts to convert the provided `char` to a byte and push it into the buffer. If the character is not a valid ASCII character (i.e., its code point is greater than 127), it returns an error since it cannot be represented as a single byte. If the buffer is full, it also returns an error.
1951    ///
1952    /// # Parameters
1953    ///
1954    /// * `ch` - The character to push into the buffer
1955    ///
1956    /// # Returns
1957    ///
1958    /// * `Ok(())` - If the character was successfully pushed
1959    /// * `Err(Error::StringConversionError)` - If the character is not a valid ASCII character or if the buffer is full
1960    ///
1961    /// # Examples
1962    //// ```ignore
1963    /// use osal_rs::utils::Bytes;
1964    /// 
1965    /// let mut bytes = Bytes::<16>::new_by_str("Hello");
1966    /// assert_eq!(bytes.push_char('!'), Ok(()));
1967    /// assert_eq!(bytes.as_str(), "Hello!");
1968    /// 
1969    /// // Attempt to push a non-ASCII character
1970    /// assert!(bytes.push_char('é').is_err());
1971    /// ```
1972    pub fn push_char(&mut self, ch: char) -> Result<()> {
1973        if ch.is_ascii() {
1974            self.push(ch as u8)
1975        } else {
1976            Err(Error::StringConversionError) // Non-ASCII characters not supported
1977        }
1978    }
1979
1980    /// Checks if the content of the buffer can be interpreted as a valid UTF-8 string.
1981    ///
1982    /// This method attempts to convert the internal byte array to a UTF-8 string. If the conversion is successful, it returns `true`, indicating that the content can be treated as a valid string. If the conversion fails due to invalid UTF-8 sequences, it returns `false`.
1983    ///
1984    /// # Returns
1985    ///
1986    /// * `true` - If the content can be interpreted as a valid UTF-8 string
1987    /// * `false` - If the content contains invalid UTF-8 sequences
1988    ///
1989    /// # Examples
1990    //// ```ignore
1991    /// use osal_rs::utils::Bytes;
1992    /// 
1993    /// let valid_bytes = Bytes::<16>::new_by_str("Hello");
1994    /// assert!(valid_bytes.is_string());
1995    /// 
1996    /// let mut invalid_bytes = Bytes::<16>::new();
1997    /// invalid_bytes[0] = 0xFF; // Invalid UTF-8 byte
1998    /// assert!(!invalid_bytes.is_string());
1999    /// ```
2000    #[inline]
2001    pub fn is_string(&self) -> bool {
2002        String::from_utf8(self.0.to_vec()).is_ok()
2003    }
2004        
2005}
2006
2007/// Converts a byte slice to a hexadecimal string representation.
2008///
2009/// Each byte is converted to its two-character hexadecimal representation
2010/// in lowercase. This function allocates a new `String` on the heap.
2011///
2012/// # Parameters
2013///
2014/// * `bytes` - The byte slice to convert
2015///
2016/// # Returns
2017///
2018/// A `String` containing the hexadecimal representation of the bytes.
2019/// Each byte is represented by exactly 2 hex characters (lowercase).
2020///
2021/// # Memory Allocation
2022///
2023/// This function allocates heap memory. In memory-constrained environments,
2024/// consider using [`bytes_to_hex_into_slice`] instead.
2025///
2026/// # Examples
2027///
2028/// ```ignore
2029/// use osal_rs::utils::bytes_to_hex;
2030/// 
2031/// let data = &[0x01, 0x23, 0xAB, 0xFF];
2032/// let hex = bytes_to_hex(data);
2033/// assert_eq!(hex, "0123abff");
2034/// 
2035/// let empty = bytes_to_hex(&[]);
2036/// assert_eq!(empty, "");
2037/// ```
2038#[inline]
2039pub fn bytes_to_hex(bytes: &[u8]) -> String {
2040    bytes.iter()
2041         .map(|b| format!("{:02x}", b))
2042         .collect()
2043}
2044
2045/// Converts a byte slice to hexadecimal representation into a pre-allocated buffer.
2046///
2047/// This is a zero-allocation version of [`bytes_to_hex`] that writes the
2048/// hexadecimal representation directly into a provided output buffer.
2049/// Suitable for embedded systems and real-time applications.
2050///
2051/// # Parameters
2052///
2053/// * `bytes` - The source byte slice to convert
2054/// * `output` - The destination buffer to write hex characters into
2055///
2056/// # Returns
2057///
2058/// The number of bytes written to the output buffer (always `bytes.len() * 2`).
2059///
2060/// # Panics
2061///
2062/// Panics if `output.len() < bytes.len() * 2`. The output buffer must be
2063/// at least twice the size of the input to hold the hex representation.
2064///
2065/// # Examples
2066///
2067/// ```ignore
2068/// use osal_rs::utils::bytes_to_hex_into_slice;
2069/// 
2070/// let data = &[0x01, 0xAB, 0xFF];
2071/// let mut buffer = [0u8; 6];
2072/// 
2073/// let written = bytes_to_hex_into_slice(data, &mut buffer);
2074/// assert_eq!(written, 6);
2075/// assert_eq!(&buffer, b"01abff");
2076/// 
2077/// // Will panic - buffer too small
2078/// // let mut small = [0u8; 4];
2079/// // bytes_to_hex_into_slice(data, &mut small);
2080/// ```
2081pub fn bytes_to_hex_into_slice(bytes: &[u8], output: &mut [u8]) -> usize {
2082    assert!(output.len() >= bytes.len() * 2, "Buffer too small for hex conversion");
2083    let mut i = 0;
2084    for &b in bytes {
2085        let hex = format!("{:02x}", b);
2086        output[i..i+2].copy_from_slice(hex.as_bytes());
2087        i += 2;
2088    }
2089    i 
2090}
2091
2092/// Converts a hexadecimal string to a vector of bytes.
2093///
2094/// Parses a string of hexadecimal digits (case-insensitive) and converts
2095/// them to their binary representation. Each pair of hex digits becomes
2096/// one byte in the output.
2097///
2098/// # Parameters
2099///
2100/// * `hex` - A string slice containing hexadecimal digits (0-9, a-f, A-F)
2101///
2102/// # Returns
2103///
2104/// * `Ok(Vec<u8>)` - A vector containing the decoded bytes
2105/// * `Err(Error::StringConversionError)` - If the string has odd length or contains invalid hex digits
2106///
2107/// # Memory Allocation
2108///
2109/// This function allocates a `Vec` on the heap. For no-alloc environments,
2110/// use [`hex_to_bytes_into_slice`] instead.
2111///
2112/// # Examples
2113///
2114/// ```ignore
2115/// use osal_rs::utils::hex_to_bytes;
2116/// 
2117/// // Lowercase hex
2118/// let bytes = hex_to_bytes("0123abff").unwrap();
2119/// assert_eq!(bytes, vec![0x01, 0x23, 0xAB, 0xFF]);
2120/// 
2121/// // Uppercase hex
2122/// let bytes2 = hex_to_bytes("ABCD").unwrap();
2123/// assert_eq!(bytes2, vec![0xAB, 0xCD]);
2124/// 
2125/// // Odd length - error
2126/// assert!(hex_to_bytes("ABC").is_err());
2127/// 
2128/// // Invalid character - error
2129/// assert!(hex_to_bytes("0G").is_err());
2130/// ```
2131pub fn hex_to_bytes(hex: &str) -> Result<Vec<u8>> {
2132    if hex.len() % 2 != 0 {
2133        return Err(Error::StringConversionError);
2134    }
2135
2136    let bytes_result: Result<Vec<u8>> = (0..hex.len())
2137        .step_by(2)
2138        .map(|i| {
2139            u8::from_str_radix(&hex[i..i + 2], 16)
2140                .map_err(|_| Error::StringConversionError)
2141        })
2142        .collect();
2143
2144    bytes_result
2145}
2146
2147/// Converts a hexadecimal string to bytes into a pre-allocated buffer.
2148///
2149/// This is a zero-allocation version of [`hex_to_bytes`] that writes decoded
2150/// bytes directly into a provided output buffer. Suitable for embedded systems
2151/// and real-time applications where heap allocation is not desired.
2152///
2153/// # Parameters
2154///
2155/// * `hex` - A string slice containing hexadecimal digits (0-9, a-f, A-F)
2156/// * `output` - The destination buffer to write decoded bytes into
2157///
2158/// # Returns
2159///
2160/// * `Ok(usize)` - The number of bytes written to the output buffer (`hex.len() / 2`)
2161/// * `Err(Error::StringConversionError)` - If:
2162///   - The hex string has odd length
2163///   - The output buffer is too small (`output.len() < hex.len() / 2`)
2164///   - The hex string contains invalid characters
2165///
2166/// # Examples
2167///
2168/// ```ignore
2169/// use osal_rs::utils::hex_to_bytes_into_slice;
2170/// 
2171/// let mut buffer = [0u8; 4];
2172/// let written = hex_to_bytes_into_slice("0123abff", &mut buffer).unwrap();
2173/// assert_eq!(written, 4);
2174/// assert_eq!(buffer, [0x01, 0x23, 0xAB, 0xFF]);
2175/// 
2176/// // Buffer too small
2177/// let mut small = [0u8; 2];
2178/// assert!(hex_to_bytes_into_slice("0123abff", &mut small).is_err());
2179/// 
2180/// // Odd length string
2181/// assert!(hex_to_bytes_into_slice("ABC", &mut buffer).is_err());
2182/// ```
2183pub fn hex_to_bytes_into_slice(hex: &str, output: &mut [u8]) -> Result<usize> {
2184    if hex.len() % 2 != 0 || output.len() < hex.len() / 2 {
2185        return Err(Error::StringConversionError);
2186    }
2187
2188    for i in 0..(hex.len() / 2) {
2189        output[i] = u8::from_str_radix(&hex[2 * i..2 * i + 2], 16)
2190            .map_err(|_| Error::StringConversionError)?;
2191    }
2192
2193    Ok(hex.len() / 2)
2194}
2195
2196/// Thread-safe wrapper for `UnsafeCell` usable in `static` contexts.
2197///
2198/// `SyncUnsafeCell<T>` is a thin wrapper around `UnsafeCell<T>` that manually
2199/// implements the `Sync` and `Send` traits, allowing its use in `static` variables.
2200/// This is necessary in Rust 2024+ where `static mut` is no longer allowed.
2201///
2202/// # Safety
2203///
2204/// The manual implementation of `Sync` and `Send` is **unsafe** because the compiler
2205/// cannot verify that concurrent access is safe. It is the programmer's responsibility
2206/// to ensure that:
2207///
2208/// 1. In **single-threaded** environments (e.g., embedded bare-metal), there are no
2209///    synchronization issues since only one thread of execution exists.
2210///
2211/// 2. In **multi-threaded** environments, access to `SyncUnsafeCell` must be
2212///    externally protected via mutexes, critical sections, or other synchronization
2213///    primitives.
2214///
2215/// 3. No **data race** conditions occur during data access.
2216///
2217/// # Typical Usage
2218///
2219/// This structure is designed to replace `static mut` in embedded scenarios
2220/// where global mutability is necessary (e.g., hardware registers, shared buffers).
2221///
2222/// # Examples
2223///
2224/// ```ignore
2225/// use osal_rs::utils::SyncUnsafeCell;
2226///
2227/// // Global mutable variable in Rust 2024+
2228/// static COUNTER: SyncUnsafeCell<u32> = SyncUnsafeCell::new(0);
2229///
2230/// fn increment_counter() {
2231///     unsafe {
2232///         let counter = &mut *COUNTER.get();
2233///         *counter += 1;
2234///     }
2235/// }
2236/// ```
2237///
2238/// # Alternatives
2239///
2240/// For non-embedded code or when real synchronization is needed:
2241/// - Use `Mutex<T>` or `RwLock<T>` for thread-safe protection
2242/// - Use `AtomicUsize`, `AtomicBool`, etc. for simple atomic types
2243pub struct SyncUnsafeCell<T>(UnsafeCell<T>);
2244
2245/// Manual implementation of `Sync` for `SyncUnsafeCell<T>`.
2246///
2247/// # Safety
2248///
2249/// This is **unsafe** because it asserts that `SyncUnsafeCell<T>` can be shared
2250/// between threads without causing data races. The caller must ensure synchronization.
2251unsafe impl<T> Sync for SyncUnsafeCell<T> {}
2252
2253/// Manual implementation of `Send` for `SyncUnsafeCell<T>`.
2254///
2255/// # Safety
2256///
2257/// This is **unsafe** because it asserts that `SyncUnsafeCell<T>` can be transferred
2258/// between threads. The inner type `T` may not be `Send`, so the caller must handle
2259/// memory safety.
2260unsafe impl<T> Send for SyncUnsafeCell<T> {}
2261
2262impl<T> SyncUnsafeCell<T> {
2263    /// Creates a new instance of `SyncUnsafeCell<T>`.
2264    ///
2265    /// This is a `const` function, allowing initialization in static and
2266    /// constant contexts.
2267    ///
2268    /// # Parameters
2269    ///
2270    /// * `value` - The initial value to wrap
2271    ///
2272    /// # Examples
2273    ///
2274    /// ```ignore
2275    /// use osal_rs::utils::SyncUnsafeCell;
2276    ///
2277    /// static CONFIG: SyncUnsafeCell<u32> = SyncUnsafeCell::new(42);
2278    /// ```
2279    #[inline]
2280    pub const fn new(value: T) -> Self {
2281        Self(UnsafeCell::new(value))
2282    }
2283    
2284    /// Gets a raw mutable pointer to the contained value.
2285    ///
2286    /// # Safety
2287    ///
2288    /// This function is **unsafe** because:
2289    /// - It returns a raw pointer that bypasses the borrow checker
2290    /// - The caller must ensure there are no mutable aliases
2291    /// - Dereferencing the pointer without synchronization can cause data races
2292    ///
2293    /// # Returns
2294    ///
2295    /// A raw mutable pointer `*mut T` to the inner value.
2296    ///
2297    /// # Examples
2298    ///
2299    /// ```ignore
2300    /// use osal_rs::utils::SyncUnsafeCell;
2301    ///
2302    /// static VALUE: SyncUnsafeCell<i32> = SyncUnsafeCell::new(0);
2303    ///
2304    /// unsafe {
2305    ///     let ptr = VALUE.get();
2306    ///     *ptr = 42;
2307    /// }
2308    /// ```
2309    #[inline]
2310    pub unsafe fn get(&self) -> *mut T {
2311        self.0.get()
2312    }
2313}