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