Skip to main content

osal_rs/
utils.rs

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