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::ffi::{CStr, c_char};
26use core::{ffi::c_void, str::from_utf8_mut};
27use core::fmt::{Debug, Display}; 
28use core::ops::{Deref, DerefMut};
29use core::time::Duration;
30use alloc::ffi::CString;
31use alloc::string::{String, ToString};
32use alloc::sync::Arc;
33
34use crate::os::Mutex;
35
36/// Error types for OSAL-RS operations.
37///
38/// Represents all possible error conditions that can occur when using
39/// the OSAL-RS library.
40///
41/// # Examples
42///
43/// ```ignore
44/// use osal_rs::os::{Queue, QueueFn};
45/// use osal_rs::utils::Error;
46/// 
47/// match Queue::new(10, 32) {
48///     Ok(queue) => { /* use queue */ },
49///     Err(Error::OutOfMemory) => println!("Failed to allocate queue"),
50///     Err(e) => println!("Other error: {:?}", e),
51/// }
52/// ```
53#[derive(Debug, Clone, PartialEq, Eq, Hash)]
54pub enum Error {
55    /// Insufficient memory to complete operation
56    OutOfMemory,
57    /// Queue send operation timed out
58    QueueSendTimeout,
59    /// Queue receive operation timed out
60    QueueReceiveTimeout,
61    /// Mutex operation timed out
62    MutexTimeout,
63    /// Failed to acquire mutex lock
64    MutexLockFailed,
65    /// Generic timeout error
66    Timeout,
67    /// Queue is full and cannot accept more items
68    QueueFull,
69    /// String conversion failed
70    StringConversionError,
71    /// Thread/task not found
72    TaskNotFound,
73    /// Invalid queue size specified
74    InvalidQueueSize,
75    /// Null pointer encountered
76    NullPtr,
77    /// Requested item not found
78    NotFound,
79    /// Index out of bounds
80    OutOfIndex,
81    /// Invalid type for operation
82    InvalidType,
83    /// No data available
84    Empty,
85    /// Write error occurred
86    WriteError,
87    /// Read error occurred
88    ReadError,
89    /// Return error with code
90    ReturnWithCode(i32),
91    /// Unhandled error with description
92    Unhandled(&'static str)
93}
94
95/// CPU register size enumeration.
96///
97/// Identifies whether the target CPU uses 32-bit or 64-bit registers.
98/// This is used for platform-specific tick count overflow handling.
99#[derive(PartialEq, Eq, Clone, Copy, Debug)]
100pub enum CpuRegisterSize {
101    /// 64-bit CPU registers
102    Bit64,
103    /// 32-bit CPU registers
104    Bit32
105}
106
107/// Boolean type compatible with RTOS return values.
108///
109/// Many RTOS functions return 0 for success and non-zero for failure.
110/// This type provides a Rust-idiomatic way to work with such values.
111///
112/// # Examples
113///
114/// ```ignore
115/// use osal_rs::os::{Semaphore, SemaphoreFn};
116/// use osal_rs::utils::OsalRsBool;
117/// use core::time::Duration;
118/// 
119/// let sem = Semaphore::new(1, 1).unwrap();
120/// 
121/// match sem.wait(Duration::from_millis(100)) {
122///     OsalRsBool::True => println!("Acquired semaphore"),
123///     OsalRsBool::False => println!("Failed to acquire"),
124/// }
125/// 
126/// // Can also convert to bool
127/// if sem.signal().into() {
128///     println!("Semaphore signaled");
129/// }
130/// ```
131#[derive(PartialEq, Eq, Clone, Copy, Debug)]
132#[repr(u8)]
133pub enum OsalRsBool {
134    /// Operation failed or condition is false
135    False = 1,
136    /// Operation succeeded or condition is true
137    True = 0
138}
139
140/// Maximum delay constant for blocking operations.
141///
142/// When used as a timeout parameter, indicates the operation should
143/// block indefinitely until it succeeds.
144///
145/// # Examples
146///
147/// ```ignore
148/// use osal_rs::os::{Mutex, MutexFn};
149/// use osal_rs::utils::MAX_DELAY;
150/// 
151/// let mutex = Mutex::new(0);
152/// let guard = mutex.lock();  // Blocks forever if needed
153/// ```
154pub const MAX_DELAY: Duration = Duration::from_millis(usize::MAX as u64);
155
156/// Standard Result type for OSAL-RS operations.
157///
158/// Uses [`Error`] as the default error type.
159pub type Result<T, E = Error> = core::result::Result<T, E>;
160
161/// Pointer to pointer type for C FFI.
162pub type DoublePtr = *mut *mut c_void;
163
164/// Mutable pointer type for C FFI.
165pub type Ptr = *mut c_void;
166
167/// Const pointer type for C FFI.
168pub type ConstPtr = *const c_void;
169
170/// Shortcut for Arc<Mutex<T>>
171pub type ArcMux<T> = Arc<Mutex<T>>;
172
173/// Determines the CPU register size at compile time.
174///
175/// This constant function checks the size of `usize` to determine whether
176/// the target architecture uses 32-bit or 64-bit registers. This information
177/// is used for platform-specific optimizations and overflow handling.
178///
179/// # Returns
180///
181/// * [`CpuRegisterSize::Bit64`] - For 64-bit architectures
182/// * [`CpuRegisterSize::Bit32`] - For 32-bit architectures
183///
184/// # Examples
185///
186/// ```ignore
187/// use osal_rs::utils::{register_bit_size, CpuRegisterSize};
188/// 
189/// match register_bit_size() {
190///     CpuRegisterSize::Bit64 => println!("Running on 64-bit platform"),
191///     CpuRegisterSize::Bit32 => println!("Running on 32-bit platform"),
192/// }
193/// ```
194pub const fn register_bit_size() -> CpuRegisterSize {
195    if size_of::<usize>() == 8 {
196        CpuRegisterSize::Bit64
197    } else {
198        CpuRegisterSize::Bit32
199    }
200}
201
202/// Converts a C string pointer to a Rust String.
203///
204/// This macro safely converts a raw C string pointer (`*const c_char`) into
205/// a Rust `String`. It handles UTF-8 conversion gracefully using lossy conversion.
206///
207/// # Safety
208///
209/// The pointer must be valid and point to a null-terminated C string.
210///
211/// # Examples
212///
213/// ```ignore
214/// use osal_rs::from_c_str;
215/// use core::ffi::c_char;
216/// 
217/// extern "C" {
218///     fn get_system_name() -> *const c_char;
219/// }
220/// 
221/// let name = from_c_str!(get_system_name());
222/// println!("System: {}", name);
223/// ```
224#[macro_export]
225macro_rules! from_c_str {
226    ($str:expr) => {
227        unsafe {
228            let c_str = core::ffi::CStr::from_ptr($str);
229            alloc::string::String::from_utf8_lossy(c_str.to_bytes()).to_string()
230        }
231    };
232}
233
234/// Converts a Rust string to a CString with error handling.
235///
236/// This macro creates a `CString` from a Rust string reference, returning
237/// a `Result` that can be used with the `?` operator. If the conversion fails
238/// (e.g., due to interior null bytes), it returns an appropriate error.
239///
240/// # Returns
241///
242/// * `Ok(CString)` - On successful conversion
243/// * `Err(Error::Unhandled)` - If the string contains interior null bytes
244///
245/// # Examples
246///
247/// ```ignore
248/// use osal_rs::to_cstring;
249/// use osal_rs::utils::Result;
250/// 
251/// fn pass_to_c_api(name: &str) -> Result<()> {
252///     let c_name = to_cstring!(name)?;
253///     // Use c_name.as_ptr() with C FFI
254///     Ok(())
255/// }
256/// ```
257#[macro_export]
258macro_rules! to_cstring {
259    ($s:expr) => {
260        alloc::ffi::CString::new($s.as_str())
261            .map_err(|_| $crate::utils::Error::Unhandled("Failed to convert string to CString"))
262    };
263}
264
265/// Converts a Rust string to a C string pointer.
266///
267/// This macro creates a `CString` from a Rust string and returns its raw pointer.
268/// **Warning**: This macro panics if the conversion fails. Consider using
269/// [`to_cstring!`] for safer error handling.
270///
271/// # Panics
272///
273/// Panics if the string contains interior null bytes.
274///
275/// # Examples
276///
277/// ```ignore
278/// use osal_rs::to_c_str;
279/// 
280/// extern "C" {
281///     fn set_name(name: *const core::ffi::c_char);
282/// }
283/// 
284/// let name = "FreeRTOS Task";
285/// unsafe {
286///     set_name(to_c_str!(name));
287/// }
288/// ```
289#[macro_export]
290macro_rules! to_c_str {
291    ($s:expr) => {
292        alloc::ffi::CString::new($s.as_ref() as &str).unwrap().as_ptr()
293    };
294}
295
296/// Converts a string to a fixed-size byte array.
297///
298/// This macro creates a byte array of the specified size and fills it with
299/// the bytes from the input string. If the string is shorter than the buffer,
300/// the remaining bytes are filled with spaces. If the string is longer, it
301/// is truncated to fit.
302///
303/// # Parameters
304///
305/// * `$str` - The source string to convert
306/// * `$buff_name` - The identifier name for the created buffer variable
307/// * `$buff_size` - The size of the byte array to create
308///
309/// # Examples
310///
311/// ```ignore
312/// use osal_rs::from_str_to_array;
313/// 
314/// let task_name = "MainTask";
315/// from_str_to_array!(task_name, name_buffer, 16);
316/// // name_buffer is now [u8; 16] containing "MainTask        "
317/// 
318/// // Use with C FFI
319/// extern "C" {
320///     fn create_task(name: *const u8, len: usize);
321/// }
322/// 
323/// unsafe {
324///     create_task(name_buffer.as_ptr(), name_buffer.len());
325/// }
326/// ```
327#[macro_export]
328macro_rules! from_str_to_array {
329    ($str:expr, $buff_name:ident, $buff_size:expr) => {
330        let mut $buff_name = [b' '; $buff_size];
331        let _bytes = $str.as_bytes();
332        let _len = core::cmp::min(_bytes.len(), $buff_size);
333        $buff_name[.._len].copy_from_slice(&_bytes[.._len]);
334    };
335}
336
337/// Extracts a typed parameter from an optional boxed Any reference.
338///
339/// This macro is used in thread/task entry points to safely extract and
340/// downcast parameters passed to the thread. It handles both the Option
341/// unwrapping and the type downcast, returning appropriate errors if either
342/// operation fails.
343///
344/// # Parameters
345///
346/// * `$param` - An `Option<Box<dyn Any>>` containing the parameter
347/// * `$t` - The type to downcast the parameter to
348///
349/// # Returns
350///
351/// * A reference to the downcasted value of type `$t`
352/// * `Err(Error::NullPtr)` - If the parameter is None
353/// * `Err(Error::InvalidType)` - If the downcast fails
354///
355/// # Examples
356///
357/// ```ignore
358/// use osal_rs::thread_extract_param;
359/// use osal_rs::utils::Result;
360/// use core::any::Any;
361/// 
362/// struct TaskConfig {
363///     priority: u8,
364///     stack_size: usize,
365/// }
366/// 
367/// fn task_entry(param: Option<Box<dyn Any>>) -> Result<()> {
368///     let config = thread_extract_param!(param, TaskConfig);
369///     
370///     println!("Priority: {}", config.priority);
371///     println!("Stack: {}", config.stack_size);
372///     
373///     Ok(())
374/// }
375/// ```
376#[macro_export]
377macro_rules! thread_extract_param {
378    ($param:expr, $t:ty) => {
379        match $param.as_ref() {
380            Some(p) => {
381                match p.downcast_ref::<$t>() {
382                    Some(value) => value,
383                    None => return Err($crate::utils::Error::InvalidType),
384                }
385            }
386            None => return Err($crate::utils::Error::NullPtr),
387        }
388    };
389}
390
391/// Creates an Arc<Mutex<T>> from a value.
392///
393/// This is a convenience macro to reduce boilerplate when creating
394/// thread-safe shared data structures.
395///
396/// # Examples
397///
398/// ```ignore
399/// use osal_rs::arcmux;
400/// 
401/// let shared_counter = arcmux!(0);
402/// // Equivalent to: Arc::new(Mutex::new(0))
403/// ```
404#[macro_export]
405macro_rules! arcmux {
406    ($value:expr) => {
407        alloc::sync::Arc::new($crate::os::Mutex::new($value))
408    };
409}
410
411
412
413/// Fixed-size byte array wrapper with string conversion utilities.
414///
415/// `Bytes` is a generic wrapper around a fixed-size byte array that provides
416/// convenient methods for converting between strings and byte arrays. It's
417/// particularly useful for interfacing with C APIs that expect fixed-size
418/// character buffers, or for storing strings in embedded systems with
419/// constrained memory.
420///
421/// # Type Parameters
422///
423/// * `SIZE` - The size of the internal byte array (default: 0)
424///
425/// # Examples
426///
427/// ```ignore
428/// use osal_rs::utils::Bytes;
429/// 
430/// // Create an empty 32-byte buffer
431/// let mut buffer = Bytes::<32>::new();
432/// 
433/// // Create a buffer from a string
434/// let name = Bytes::<16>::new_by_str("TaskName");
435/// println!("{}", name); // Prints "TaskName"
436/// 
437/// // Create from any type that implements ToString
438/// let number = 42;
439/// let num_bytes = Bytes::<8>::new_by_string(&number);
440/// ```
441#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
442pub struct Bytes<const SIZE: usize = 0> (pub [u8; SIZE]);
443
444impl<const SIZE: usize> Deref for Bytes<SIZE> {
445    type Target = [u8; SIZE];
446
447    /// Dereferences to the underlying byte array.
448    ///
449    /// This allows `Bytes` to be used anywhere a `[u8; SIZE]` reference is expected.
450    ///
451    /// # Examples
452    ///
453    /// ```ignore
454    /// use osal_rs::utils::Bytes;
455    /// 
456    /// let bytes = Bytes::<8>::new_by_str("test");
457    /// assert_eq!(bytes[0], b't');
458    /// ```
459    fn deref(&self) -> &Self::Target {
460        &self.0
461    }
462}
463
464impl<const SIZE: usize> DerefMut for Bytes<SIZE> {
465    /// Provides mutable access to the underlying byte array.
466    ///
467    /// This allows `Bytes` to be mutably dereferenced, enabling direct modification
468    /// of the internal byte array through the `DerefMut` trait.
469    ///
470    /// # Examples
471    ///
472    /// ```ignore
473    /// use osal_rs::utils::Bytes;
474    /// 
475    /// let mut bytes = Bytes::<8>::new();
476    /// bytes[0] = b'H';
477    /// bytes[1] = b'i';
478    /// assert_eq!(bytes[0], b'H');
479    /// ```
480    fn deref_mut(&mut self) -> &mut Self::Target {
481        &mut self.0
482    }
483}
484
485impl<const SIZE: usize> Display for Bytes<SIZE> {
486    /// Formats the byte array as a C-style null-terminated string.
487    ///
488    /// This implementation treats the byte array as a C string and converts it
489    /// to a Rust string for display. If the conversion fails, it displays
490    /// "Conversion error".
491    ///
492    /// # Safety
493    ///
494    /// This method assumes the byte array contains valid UTF-8 data and is
495    /// null-terminated. Invalid data may result in the error message being displayed.
496    ///
497    /// # Examples
498    ///
499    /// ```ignore
500    /// use osal_rs::utils::Bytes;
501    /// 
502    /// let bytes = Bytes::<16>::new_by_str("Hello");
503    /// println!("{}", bytes); // Prints "Hello"
504    /// ```
505    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
506        let str = unsafe {
507            CStr::from_ptr(self.0.as_ptr() as *const c_char)
508            .to_str()
509            .unwrap_or("Conversion error")
510        };
511        
512        write!(f, "{}", str.to_string())
513    }
514}
515
516impl AsSyncStr for Bytes<> {
517    /// Returns a string slice reference.
518    ///
519    /// This method provides access to the underlying string data in a way
520    /// that is safe to use across thread boundaries.
521    ///
522    /// # Returns
523    ///
524    /// A reference to a string slice with lifetime tied to `self`.
525    fn as_str(&self) -> &str {
526        unsafe {
527            CStr::from_ptr(self.0.as_ptr() as *const c_char)
528            .to_str()
529            .unwrap_or("Conversion error")
530        }
531    }
532}
533
534impl<const SIZE: usize> Bytes<SIZE> {
535    /// Creates a new `Bytes` instance filled with zeros.
536    ///
537    /// This is a const function, allowing it to be used in const contexts
538    /// and static variable declarations.
539    ///
540    /// # Returns
541    ///
542    /// A `Bytes` instance with all bytes set to 0.
543    ///
544    /// # Examples
545    ///
546    /// ```ignore
547    /// use osal_rs::utils::Bytes;
548    /// 
549    /// const BUFFER: Bytes<64> = Bytes::new();
550    /// 
551    /// let runtime_buffer = Bytes::<32>::new();
552    /// assert_eq!(runtime_buffer[0], 0);
553    /// ```
554    pub const fn new() -> Self {
555        Self( [0u8; SIZE] )
556    }
557
558    /// Creates a new `Bytes` instance from a string slice.
559    ///
560    /// Copies the bytes from the input string into the fixed-size array.
561    /// If the string is shorter than `SIZE`, the remaining bytes are zero-filled.
562    /// If the string is longer, it is truncated to fit.
563    ///
564    /// # Parameters
565    ///
566    /// * `str` - The source string to convert
567    ///
568    /// # Returns
569    ///
570    /// A `Bytes` instance containing the string data.
571    ///
572    /// # Examples
573    ///
574    /// ```ignore
575    /// use osal_rs::utils::Bytes;
576    /// 
577    /// let short = Bytes::<16>::new_by_str("Hi");
578    /// // Internal array: [b'H', b'i', 0, 0, 0, ...]
579    /// 
580    /// let exact = Bytes::<5>::new_by_str("Hello");
581    /// // Internal array: [b'H', b'e', b'l', b'l', b'o']
582    /// 
583    /// let long = Bytes::<3>::new_by_str("Hello");
584    /// // Internal array: [b'H', b'e', b'l'] (truncated)
585    /// ```
586    pub fn new_by_str(str: &str) -> Self {
587
588        let mut array = [0u8; SIZE];
589        
590        let mut i = 0usize ;
591        for byte in str.as_bytes() {
592            if i > SIZE - 1{
593                break;
594            }
595            array[i] = *byte;
596            i += 1;
597        }  
598
599        Self( array )
600    }
601
602    /// Creates a new `Bytes` instance from any type implementing `ToString`.
603    ///
604    /// This is a convenience wrapper around [`new_by_str`](Self::new_by_str)
605    /// that first converts the input to a string.
606    ///
607    /// # Parameters
608    ///
609    /// * `str` - Any value that implements `ToString`
610    ///
611    /// # Returns
612    ///
613    /// A `Bytes` instance containing the string representation of the input.
614    ///
615    /// # Examples
616    ///
617    /// ```ignore
618    /// use osal_rs::utils::Bytes;
619    /// 
620    /// // From integer
621    /// let num_bytes = Bytes::<8>::new_by_string(&42);
622    /// 
623    /// // From String
624    /// let string = String::from("Task");
625    /// let str_bytes = Bytes::<16>::new_by_string(&string);
626    /// 
627    /// // From custom type with ToString
628    /// #[derive(Debug)]
629    /// struct TaskId(u32);
630    /// impl ToString for TaskId {
631    ///     fn to_string(&self) -> String {
632    ///         format!("Task-{}", self.0)
633    ///     }
634    /// }
635    /// let task_bytes = Bytes::<16>::new_by_string(&TaskId(5));
636    /// ```
637    pub fn new_by_string(str: &impl ToString) -> Self {
638        Self::new_by_str(&str.to_string())
639    }
640
641    /// Fills a mutable string slice with the contents of the byte array.
642    ///
643    /// Attempts to convert the internal byte array to a UTF-8 string and
644    /// copies it into the destination string slice. Only copies up to the
645    /// minimum of the source and destination lengths.
646    ///
647    /// # Parameters
648    ///
649    /// * `dest` - The destination string slice to fill
650    ///
651    /// # Panics
652    ///
653    /// Currently panics (todo!) if the byte array contains invalid UTF-8.
654    ///
655    /// # Examples
656    ///
657    /// ```ignore
658    /// use osal_rs::utils::Bytes;
659    /// 
660    /// let bytes = Bytes::<16>::new_by_str("Hello World");
661    /// 
662    /// let mut output = String::from("                "); // 16 spaces
663    /// bytes.fill_str(unsafe { output.as_mut_str() });
664    /// 
665    /// assert_eq!(&output[..11], "Hello World");
666    /// ```
667    pub fn fill_str(&mut self, dest: &mut str) {
668        match from_utf8_mut(&mut self.0) {
669            Ok(str) => {
670                let len = core::cmp::min(str.len(), dest.len());
671                unsafe {
672                    dest.as_bytes_mut()[..len].copy_from_slice(&str.as_bytes()[..len]);
673                }
674            }
675            Err(_) => todo!(),
676        }
677    }
678
679    /// Converts the byte array to a C string reference.
680    ///
681    /// Creates a `CStr` reference from the internal byte array, treating it as
682    /// a null-terminated C string. This is useful for passing strings to C FFI
683    /// functions that expect `*const c_char` or `&CStr`.
684    ///
685    /// # Safety
686    ///
687    /// This method is unsafe because it assumes:
688    /// - The byte array contains valid UTF-8 data
689    /// - The byte array is null-terminated
690    /// - There are no interior null bytes before the terminating null
691    ///
692    /// Violating these assumptions may lead to undefined behavior.
693    ///
694    /// # Returns
695    ///
696    /// A reference to a `CStr` with lifetime tied to `self`.
697    ///
698    /// # Examples
699    ///
700    /// ```ignore
701    /// use osal_rs::utils::Bytes;
702    /// 
703    /// let bytes = Bytes::<16>::new_by_str("Hello");
704    /// let c_str = bytes.as_c_str();
705    /// 
706    /// extern "C" {
707    ///     fn print_string(s: *const core::ffi::c_char);
708    /// }
709    /// 
710    /// unsafe {
711    ///     print_string(c_str.as_ptr());
712    /// }
713    /// ```
714    pub fn as_c_str(&self) -> &CStr {
715        unsafe {
716            CStr::from_ptr(self.0.as_ptr() as *const c_char)
717        }
718    }
719
720    /// Converts the byte array to an owned C string.
721    ///
722    /// Creates a new `CString` by copying the contents of the internal byte array.
723    /// Unlike [`as_c_str`](Self::as_c_str), this method allocates heap memory and
724    /// returns an owned string that can outlive the original `Bytes` instance.
725    ///
726    /// # Safety
727    ///
728    /// This method uses `from_vec_unchecked` which assumes the byte array
729    /// does not contain any interior null bytes. If this assumption is violated,
730    /// the resulting `CString` will be invalid.
731    ///
732    /// # Returns
733    ///
734    /// An owned `CString` containing a copy of the byte array data.
735    ///
736    /// # Memory Allocation
737    ///
738    /// This method allocates on the heap. In memory-constrained embedded systems,
739    /// prefer [`as_c_str`](Self::as_c_str) when possible.
740    ///
741    /// # Examples
742    ///
743    /// ```ignore
744    /// use osal_rs::utils::Bytes;
745    /// 
746    /// fn process_name(bytes: &Bytes<16>) -> alloc::ffi::CString {
747    ///     // Create an owned copy that can be returned
748    ///     bytes.as_cstring()
749    /// }
750    /// 
751    /// let name = Bytes::<16>::new_by_str("Task");
752    /// let owned = process_name(&name);
753    /// // 'name' can be dropped, 'owned' still valid
754    /// ```
755    pub fn as_cstring(&self) -> CString {
756        unsafe {
757            CString::from_vec_unchecked(self.0.to_vec())
758        }
759    }
760}
761
762/// Trait for types that can provide a string reference in a thread-safe manner.
763///
764/// This trait extends the basic string reference functionality with thread-safety
765/// guarantees by requiring both `Sync` and `Send` bounds. It's useful for types
766/// that need to provide string data across thread boundaries in a concurrent
767/// environment.
768///
769/// # Thread Safety
770///
771/// Implementors must be both `Sync` (safe to share references across threads) and
772/// `Send` (safe to transfer ownership across threads).
773///
774/// # Examples
775///
776/// ```ignore
777/// use osal_rs::utils::AsSyncStr;
778/// 
779/// struct ThreadSafeName {
780///     name: &'static str,
781/// }
782/// 
783/// impl AsSyncStr for ThreadSafeName {
784///     fn as_str(&self) -> &str {
785///         self.name
786///     }
787/// }
788/// 
789/// // Can be safely shared across threads
790/// fn use_in_thread(item: &dyn AsSyncStr) {
791///     println!("Name: {}", item.as_str());
792/// }
793/// ```
794pub trait AsSyncStr : Sync + Send { 
795    /// Returns a string slice reference.
796    ///
797    /// This method provides access to the underlying string data in a way
798    /// that is safe to use across thread boundaries.
799    ///
800    /// # Returns
801    ///
802    /// A reference to a string slice with lifetime tied to `self`.
803    fn as_str(&self) -> &str;
804}
805
806impl PartialEq for dyn AsSyncStr {
807    fn eq(&self, other: &Self) -> bool {
808        self.as_str() == other.as_str()
809    }
810}
811
812impl Eq for dyn AsSyncStr {}
813
814impl Debug for dyn AsSyncStr {
815    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
816        write!(f, "{}", self.as_str())
817    }
818}
819
820impl Display for dyn AsSyncStr {
821    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
822        write!(f, "{}", self.as_str())
823    }
824}
825