Skip to main content

canlink_hal/
backend.rs

1//! Backend trait definitions and factory pattern.
2//!
3//! This module defines the core `CanBackend` trait that all hardware backends must implement,
4//! as well as the `BackendFactory` trait for creating backend instances.
5
6use crate::{BackendConfig, BackendVersion, CanError, CanMessage, CanResult, HardwareCapability};
7use std::time::Duration;
8
9/// CAN hardware backend interface.
10///
11/// This trait defines the unified interface that all hardware backends must implement.
12/// It provides methods for lifecycle management, message transmission/reception,
13/// channel management, and capability querying.
14///
15/// # Thread Safety
16///
17/// This trait's methods require external synchronization. If you need to access the same
18/// backend instance from multiple threads, the caller must provide synchronization using
19/// `Mutex` or `RwLock`.
20///
21/// **Rationale**: External synchronization allows high-performance single-threaded usage
22/// without lock overhead, while still supporting multi-threaded scenarios when needed.
23///
24/// ## Single-Threaded Usage (No Synchronization Needed)
25///
26/// ```rust,ignore
27/// use canlink_hal::{CanBackend, BackendConfig};
28///
29/// fn main() -> Result<(), Box<dyn std::error::Error>> {
30///     let mut backend = create_backend();
31///     backend.initialize(&config)?;
32///     backend.open_channel(0)?;
33///
34///     // Direct access - no locks needed
35///     backend.send_message(&message)?;
36///     if let Some(msg) = backend.receive_message()? {
37///         println!("Received: {:?}", msg);
38///     }
39///
40///     backend.close()?;
41///     Ok(())
42/// }
43/// ```
44///
45/// ## Multi-Threaded Usage with Mutex
46///
47/// Use `Arc<Mutex<>>` when multiple threads need mutable access:
48///
49/// ```rust,ignore
50/// use std::sync::{Arc, Mutex};
51/// use std::thread;
52/// use canlink_hal::{CanBackend, CanMessage};
53///
54/// fn main() -> Result<(), Box<dyn std::error::Error>> {
55///     let backend = Arc::new(Mutex::new(create_backend()));
56///
57///     // Initialize in main thread
58///     backend.lock().unwrap().initialize(&config)?;
59///     backend.lock().unwrap().open_channel(0)?;
60///
61///     // Sender thread
62///     let backend_tx = Arc::clone(&backend);
63///     let tx_handle = thread::spawn(move || {
64///         for i in 0..100 {
65///             let msg = CanMessage::new_standard(0x100 + i, &[i as u8]).unwrap();
66///             backend_tx.lock().unwrap().send_message(&msg).unwrap();
67///         }
68///     });
69///
70///     // Receiver thread
71///     let backend_rx = Arc::clone(&backend);
72///     let rx_handle = thread::spawn(move || {
73///         let mut count = 0;
74///         while count < 100 {
75///             if let Some(msg) = backend_rx.lock().unwrap().receive_message().unwrap() {
76///                 println!("Received: {:?}", msg);
77///                 count += 1;
78///             }
79///         }
80///     });
81///
82///     tx_handle.join().unwrap();
83///     rx_handle.join().unwrap();
84///
85///     backend.lock().unwrap().close()?;
86///     Ok(())
87/// }
88/// ```
89///
90/// ## Multi-Threaded Usage with `RwLock`
91///
92/// Use `Arc<RwLock<>>` when you have many readers and few writers:
93///
94/// ```rust,ignore
95/// use std::sync::{Arc, RwLock};
96/// use std::thread;
97/// use canlink_hal::CanBackend;
98///
99/// fn main() -> Result<(), Box<dyn std::error::Error>> {
100///     let backend = Arc::new(RwLock::new(create_backend()));
101///
102///     // Initialize
103///     backend.write().unwrap().initialize(&config)?;
104///     backend.write().unwrap().open_channel(0)?;
105///
106///     // Multiple reader threads querying capabilities
107///     let mut handles = vec![];
108///     for i in 0..10 {
109///         let backend_clone = Arc::clone(&backend);
110///         let handle = thread::spawn(move || {
111///             // Read lock allows concurrent access
112///             let capability = backend_clone.read().unwrap().get_capability().unwrap();
113///             println!("Thread {}: {} channels", i, capability.channel_count);
114///         });
115///         handles.push(handle);
116///     }
117///
118///     // Writer thread sending messages
119///     let backend_writer = Arc::clone(&backend);
120///     let writer_handle = thread::spawn(move || {
121///         for i in 0..10 {
122///             let msg = CanMessage::new_standard(0x200, &[i]).unwrap();
123///             // Write lock for exclusive access
124///             backend_writer.write().unwrap().send_message(&msg).unwrap();
125///         }
126///     });
127///
128///     for handle in handles {
129///         handle.join().unwrap();
130///     }
131///     writer_handle.join().unwrap();
132///
133///     backend.write().unwrap().close()?;
134///     Ok(())
135/// }
136/// ```
137///
138/// ## Channel-Based Message Passing Pattern
139///
140/// For better performance, consider using channels to decouple threads:
141///
142/// ```rust,ignore
143/// use std::sync::mpsc;
144/// use std::thread;
145/// use canlink_hal::{CanBackend, CanMessage};
146///
147/// fn main() -> Result<(), Box<dyn std::error::Error>> {
148///     let mut backend = create_backend();
149///     backend.initialize(&config)?;
150///     backend.open_channel(0)?;
151///
152///     let (tx, rx) = mpsc::channel();
153///
154///     // Worker threads send messages via channel
155///     for i in 0..4 {
156///         let tx_clone = tx.clone();
157///         thread::spawn(move || {
158///             for j in 0..25 {
159///                 let msg = CanMessage::new_standard(
160///                     0x100 + (i * 25 + j),
161///                     &[i as u8, j as u8]
162///                 ).unwrap();
163///                 tx_clone.send(msg).unwrap();
164///             }
165///         });
166///     }
167///     drop(tx); // Close sender
168///
169///     // Main thread owns backend and sends messages
170///     for msg in rx {
171///         backend.send_message(&msg)?;
172///     }
173///
174///     backend.close()?;
175///     Ok(())
176/// }
177/// ```
178///
179/// ## Performance Considerations
180///
181/// - **Single-threaded**: Zero synchronization overhead
182/// - **Mutex**: Simple but serializes all access
183/// - **`RwLock`**: Better for read-heavy workloads (e.g., capability queries)
184/// - **Channel-based**: Best performance, avoids lock contention
185///
186/// ## Thread Safety Guarantees
187///
188/// - `CanBackend` is `Send`, so it can be moved between threads
189/// - Methods require `&mut self`, enforcing exclusive access
190/// - Backends do not use internal locks (external synchronization model)
191/// - All backend state is protected by the caller's synchronization primitive
192///
193/// # Lifecycle
194///
195/// Backend instances follow this lifecycle:
196/// 1. **Create** (via `BackendFactory::create()`)
197/// 2. **Initialize** (`initialize()`)
198/// 3. **Run** (call `send_message()`, `receive_message()`, etc.)
199/// 4. **Close** (`close()`)
200///
201/// # Examples
202///
203/// ```rust,ignore
204/// use canlink_hal::{CanBackend, BackendConfig};
205///
206/// // Create and initialize backend
207/// let mut backend = create_backend();
208/// backend.initialize(&config)?;
209///
210/// // Use backend
211/// backend.open_channel(0)?;
212/// backend.send_message(&message)?;
213///
214/// // Clean up
215/// backend.close()?;
216/// ```
217pub trait CanBackend: Send {
218    // ========== Lifecycle Management ==========
219
220    /// Initialize the backend.
221    ///
222    /// # Arguments
223    ///
224    /// * `config` - Backend configuration parameters
225    ///
226    /// # Errors
227    ///
228    /// * `CanError::InitializationFailed` - Hardware initialization failed
229    /// * `CanError::ConfigError` - Configuration parameters are invalid
230    ///
231    /// # Preconditions
232    ///
233    /// * Backend is in `Uninitialized` state
234    ///
235    /// # Postconditions
236    ///
237    /// * Success: Backend is in `Ready` state
238    /// * Failure: Backend remains in `Uninitialized` state
239    ///
240    /// # Examples
241    ///
242    /// ```rust,ignore
243    /// let mut backend = create_backend();
244    /// backend.initialize(&config)?;
245    /// ```
246    fn initialize(&mut self, config: &BackendConfig) -> CanResult<()>;
247
248    /// Close the backend and release resources.
249    ///
250    /// This method releases all resources held by the backend, including hardware handles,
251    /// memory buffers, and network connections. It should be called when the backend is
252    /// no longer needed.
253    ///
254    /// # Errors
255    ///
256    /// Returns an error if closing fails, but resources will still be released on a
257    /// best-effort basis.
258    ///
259    /// # Preconditions
260    ///
261    /// * Backend is in `Ready` state
262    ///
263    /// # Postconditions
264    ///
265    /// * Backend is in `Closed` state
266    /// * All resources are released
267    ///
268    /// # Examples
269    ///
270    /// ```rust,ignore
271    /// backend.close()?;
272    /// ```
273    fn close(&mut self) -> CanResult<()>;
274
275    // ========== Hardware Capability Query ==========
276
277    /// Query hardware capabilities.
278    ///
279    /// Returns information about the hardware's capabilities, including supported
280    /// channel count, CAN-FD support, maximum bitrate, and timestamp precision.
281    ///
282    /// Applications should query capabilities at startup to adapt their behavior
283    /// to the available hardware features. This enables writing portable code that
284    /// works across different CAN hardware backends.
285    ///
286    /// # Performance Requirements
287    ///
288    /// * Response time < 1ms (SC-004)
289    /// * Should be cached by the backend for fast repeated queries
290    ///
291    /// # Use Cases
292    ///
293    /// * **Feature Detection**: Check if CAN-FD is supported before sending FD frames
294    /// * **Channel Validation**: Verify channel numbers before opening
295    /// * **Bitrate Selection**: Choose from supported bitrates
296    /// * **Filter Planning**: Determine available hardware filters
297    /// * **Timestamp Handling**: Adapt to available timestamp precision
298    ///
299    /// # Examples
300    ///
301    /// Basic capability query:
302    ///
303    /// ```rust,ignore
304    /// let capability = backend.get_capability()?;
305    /// println!("Hardware: {} channels, CAN-FD: {}",
306    ///          capability.channel_count,
307    ///          capability.supports_canfd);
308    /// ```
309    ///
310    /// Adaptive message sending:
311    ///
312    /// ```rust,ignore
313    /// let capability = backend.get_capability()?;
314    ///
315    /// // Use CAN-FD if available, otherwise fall back to CAN 2.0
316    /// let message = if capability.supports_canfd {
317    ///     CanMessage::new_canfd(0x123, &data, false)?
318    /// } else {
319    ///     CanMessage::new_standard(0x123, &data[..8])?
320    /// };
321    /// backend.send_message(&message)?;
322    /// ```
323    ///
324    /// Bitrate validation:
325    ///
326    /// ```rust,ignore
327    /// let capability = backend.get_capability()?;
328    /// let desired_bitrate = 500_000;
329    ///
330    /// if !capability.supports_bitrate(desired_bitrate) {
331    ///     eprintln!("Bitrate {} not supported", desired_bitrate);
332    ///     eprintln!("Supported bitrates: {:?}", capability.supported_bitrates);
333    ///     return Err(CanError::UnsupportedFeature("bitrate".into()));
334    /// }
335    /// ```
336    ///
337    /// Channel validation:
338    ///
339    /// ```rust,ignore
340    /// let capability = backend.get_capability()?;
341    /// let channel = 2;
342    ///
343    /// if !capability.has_channel(channel) {
344    ///     return Err(CanError::InvalidChannel(channel));
345    /// }
346    /// backend.open_channel(channel)?;
347    /// ```
348    ///
349    /// # Errors
350    ///
351    /// Returns an error if the capability query fails (rare, typically only on
352    /// uninitialized or closed backends).
353    fn get_capability(&self) -> CanResult<HardwareCapability>;
354
355    // ========== Message Transmission/Reception ==========
356
357    /// Send a CAN message.
358    ///
359    /// Transmits a CAN message on the bus. The message must be valid and the hardware
360    /// must support the message type (e.g., CAN-FD messages require CAN-FD support).
361    ///
362    /// # Arguments
363    ///
364    /// * `message` - The message to send
365    ///
366    /// # Errors
367    ///
368    /// * `CanError::SendFailed` - Send failed (e.g., bus Bus-Off)
369    /// * `CanError::UnsupportedFeature` - Hardware doesn't support this message type
370    /// * `CanError::InvalidDataLength` - Data length exceeds limits
371    /// * `CanError::InvalidState` - Backend not in Ready state
372    ///
373    /// # Preconditions
374    ///
375    /// * Backend is in `Ready` state
376    /// * Message format is valid
377    /// * At least one channel is open
378    ///
379    /// # Postconditions
380    ///
381    /// * Success: Message is sent to the bus
382    /// * Failure: Message is not sent, backend state unchanged
383    ///
384    /// # Performance Requirements
385    ///
386    /// * Support 1000 messages/second throughput
387    /// * Abstraction layer overhead < 5% (SC-005)
388    ///
389    /// # Examples
390    ///
391    /// ```rust,ignore
392    /// let msg = CanMessage::new_standard(0x123, &[0x01, 0x02, 0x03])?;
393    /// backend.send_message(&msg)?;
394    /// ```
395    fn send_message(&mut self, message: &CanMessage) -> CanResult<()>;
396
397    /// Receive a CAN message (non-blocking).
398    ///
399    /// Attempts to receive a message from the receive queue. Returns immediately
400    /// with `None` if no messages are available.
401    ///
402    /// # Returns
403    ///
404    /// * `Ok(Some(message))` - A message was received
405    /// * `Ok(None)` - No messages currently available
406    /// * `Err(CanError)` - Reception failed
407    ///
408    /// # Errors
409    ///
410    /// * `CanError::ReceiveFailed` - Reception failed
411    /// * `CanError::InvalidState` - Backend not in Ready state
412    ///
413    /// # Preconditions
414    ///
415    /// * Backend is in `Ready` state
416    ///
417    /// # Postconditions
418    ///
419    /// * Success: Returned message is removed from receive queue
420    /// * Failure: Receive queue state unchanged
421    ///
422    /// # Examples
423    ///
424    /// ```rust,ignore
425    /// if let Some(msg) = backend.receive_message()? {
426    ///     println!("Received: {:?}", msg);
427    /// }
428    /// ```
429    fn receive_message(&mut self) -> CanResult<Option<CanMessage>>;
430
431    // ========== Channel Management ==========
432
433    /// Open a CAN channel.
434    ///
435    /// Opens the specified CAN channel for communication. The channel index must be
436    /// valid (less than the channel count reported by `get_capability()`).
437    ///
438    /// # Arguments
439    ///
440    /// * `channel` - Channel index (0-based)
441    ///
442    /// # Errors
443    ///
444    /// * `CanError::ChannelNotFound` - Channel doesn't exist
445    /// * `CanError::ChannelAlreadyOpen` - Channel is already open
446    ///
447    /// # Preconditions
448    ///
449    /// * Backend is in `Ready` state
450    /// * Channel index is valid (< `capability.channel_count`)
451    ///
452    /// # Examples
453    ///
454    /// ```rust,ignore
455    /// backend.open_channel(0)?;
456    /// ```
457    fn open_channel(&mut self, channel: u8) -> CanResult<()>;
458
459    /// Close a CAN channel.
460    ///
461    /// Closes the specified CAN channel and stops communication on that channel.
462    ///
463    /// # Arguments
464    ///
465    /// * `channel` - Channel index
466    ///
467    /// # Errors
468    ///
469    /// * `CanError::ChannelNotFound` - Channel doesn't exist
470    /// * `CanError::ChannelNotOpen` - Channel is not open
471    ///
472    /// # Examples
473    ///
474    /// ```rust,ignore
475    /// backend.close_channel(0)?;
476    /// ```
477    fn close_channel(&mut self, channel: u8) -> CanResult<()>;
478
479    // ========== Version Information ==========
480
481    /// Get the backend version.
482    ///
483    /// Returns the semantic version number of the backend implementation.
484    ///
485    /// # Examples
486    ///
487    /// ```rust,ignore
488    /// let version = backend.version();
489    /// println!("Backend version: {}", version);
490    /// ```
491    fn version(&self) -> BackendVersion;
492
493    /// Get the backend name.
494    ///
495    /// Returns the unique identifier name of the backend (e.g., "`TSMaster`", "mock").
496    ///
497    /// # Examples
498    ///
499    /// ```rust,ignore
500    /// let name = backend.name();
501    /// println!("Using backend: {}", name);
502    /// ```
503    fn name(&self) -> &str;
504}
505
506/// Backend factory trait.
507///
508/// This trait defines the factory pattern for creating backend instances.
509/// Each backend implementation should provide a factory that implements this trait.
510///
511/// # Examples
512///
513/// ```rust,ignore
514/// use canlink_hal::{BackendFactory, BackendConfig};
515///
516/// struct MockBackendFactory;
517///
518/// impl BackendFactory for MockBackendFactory {
519///     fn create(&self, config: &BackendConfig) -> CanResult<Box<dyn CanBackend>> {
520///         Ok(Box::new(MockBackend::new()))
521///     }
522///
523///     fn name(&self) -> &str {
524///         "mock"
525///     }
526///
527///     fn version(&self) -> BackendVersion {
528///         BackendVersion::new(0, 1, 0)
529///     }
530/// }
531/// ```
532pub trait BackendFactory: Send + Sync {
533    /// Create a new backend instance.
534    ///
535    /// # Arguments
536    ///
537    /// * `config` - Backend configuration
538    ///
539    /// # Returns
540    ///
541    /// A boxed backend instance ready for initialization.
542    ///
543    /// # Errors
544    ///
545    /// * `CanError::ConfigError` - Invalid configuration
546    /// * `CanError::Other` - Factory-specific errors
547    fn create(&self, config: &BackendConfig) -> CanResult<Box<dyn CanBackend>>;
548
549    /// Get the factory name.
550    ///
551    /// Returns the unique identifier for this backend type.
552    fn name(&self) -> &str;
553
554    /// Get the factory version.
555    ///
556    /// Returns the version of the backend implementation.
557    fn version(&self) -> BackendVersion;
558}
559
560/// Helper function to retry backend initialization.
561///
562/// This function implements the retry logic specified in FR-009. It attempts to
563/// initialize a backend multiple times with a fixed interval between attempts.
564///
565/// # Arguments
566///
567/// * `backend` - The backend to initialize
568/// * `config` - Backend configuration
569/// * `retry_count` - Number of retry attempts (default: 3)
570/// * `retry_interval` - Interval between retries in milliseconds (default: 1000)
571///
572/// # Returns
573///
574/// * `Ok(())` - Initialization succeeded
575/// * `Err(CanError::InitializationFailed)` - All retry attempts failed
576///
577/// # Errors
578///
579/// Returns `CanError::InitializationFailed` if all retry attempts fail.
580///
581/// # Examples
582///
583/// ```rust,ignore
584/// let mut backend = create_backend();
585/// retry_initialize(&mut backend, &config, 3, 1000)?;
586/// ```
587pub fn retry_initialize(
588    backend: &mut dyn CanBackend,
589    config: &BackendConfig,
590    retry_count: u32,
591    retry_interval_ms: u64,
592) -> CanResult<()> {
593    let mut errors = Vec::new();
594    let start_time = std::time::Instant::now();
595
596    for attempt in 0..=retry_count {
597        match backend.initialize(config) {
598            Ok(()) => return Ok(()),
599            Err(e) => {
600                errors.push(format!("Attempt {}: {}", attempt + 1, e));
601                if attempt < retry_count {
602                    std::thread::sleep(Duration::from_millis(retry_interval_ms));
603                }
604            }
605        }
606    }
607
608    let total_time = start_time.elapsed();
609    Err(CanError::InitializationFailed {
610        reason: format!(
611            "Failed after {} attempts in {:?}. Errors: {}",
612            retry_count + 1,
613            total_time,
614            errors.join("; ")
615        ),
616    })
617}
618
619/// Switch from one backend to another (FR-015).
620///
621/// This function performs a clean switch between backends:
622/// 1. Closes the old backend (discarding any unprocessed messages)
623/// 2. Initializes the new backend
624///
625/// **Important**: Any messages in the old backend's queue are discarded.
626/// Users should process all pending messages before calling this function
627/// if message preservation is required.
628///
629/// # Arguments
630///
631/// * `old_backend` - The currently active backend to close
632/// * `new_backend` - The new backend to initialize
633/// * `config` - Configuration for the new backend
634///
635/// # Errors
636///
637/// Returns an error if:
638/// - The old backend fails to close (warning only, continues)
639/// - The new backend fails to initialize
640///
641/// # Examples
642///
643/// ```rust,ignore
644/// use canlink_hal::{switch_backend, BackendConfig};
645///
646/// // Process any remaining messages first
647/// while let Some(msg) = old_backend.receive_message()? {
648///     process_message(msg);
649/// }
650///
651/// // Then switch backends
652/// switch_backend(&mut old_backend, &mut new_backend, &new_config)?;
653/// ```
654pub fn switch_backend(
655    old_backend: &mut dyn CanBackend,
656    new_backend: &mut dyn CanBackend,
657    config: &BackendConfig,
658) -> CanResult<()> {
659    // Get names upfront to avoid borrow issues (used for logging)
660    #[allow(unused_variables)]
661    let old_name = old_backend.name().to_string();
662    #[allow(unused_variables)]
663    let new_name = new_backend.name().to_string();
664
665    // Log the switch (if tracing is enabled)
666    #[cfg(feature = "tracing")]
667    tracing::info!("Switching backend from '{}' to '{}'", old_name, new_name);
668
669    // Close the old backend - ignore errors but log them
670    #[allow(unused_variables)]
671    if let Err(e) = old_backend.close() {
672        #[cfg(feature = "tracing")]
673        tracing::warn!("Error closing old backend '{}': {}", old_name, e);
674        // Continue anyway - we want to switch even if close fails
675    }
676
677    // Initialize the new backend
678    #[cfg(feature = "tracing")]
679    {
680        new_backend.initialize(config).map_err(|e| {
681            tracing::error!("Failed to initialize new backend '{}': {}", new_name, e);
682            e
683        })?;
684    }
685    #[cfg(not(feature = "tracing"))]
686    {
687        new_backend.initialize(config)?;
688    }
689
690    #[cfg(feature = "tracing")]
691    tracing::info!("Successfully switched to backend '{}'", new_name);
692
693    Ok(())
694}
695
696// ============================================================================
697// Async Backend Trait (feature-gated)
698// ============================================================================
699
700/// Async CAN hardware backend interface.
701///
702/// This trait provides asynchronous versions of the core message operations.
703/// It is only available when the `async` feature is enabled.
704///
705/// # Feature Flags
706///
707/// - `async` - Enable async trait (requires runtime selection)
708/// - `async-tokio` - Use tokio runtime
709/// - `async-async-std` - Use async-std runtime
710///
711/// # Thread Safety
712///
713/// Like [`CanBackend`], this trait requires external synchronization.
714/// Use `Arc<Mutex<>>` or `Arc<RwLock<>>` for shared access across tasks.
715///
716/// # Examples
717///
718/// ```rust,ignore
719/// use canlink_hal::{CanBackendAsync, CanMessage};
720///
721/// async fn send_messages(backend: &mut impl CanBackendAsync) -> Result<(), Box<dyn std::error::Error>> {
722///     let msg = CanMessage::new_standard(0x123, &[1, 2, 3, 4])?;
723///     backend.send_message_async(&msg).await?;
724///
725///     if let Some(received) = backend.receive_message_async(Some(Duration::from_secs(1))).await? {
726///         println!("Received: {:?}", received);
727///     }
728///     Ok(())
729/// }
730/// ```
731#[cfg(feature = "async")]
732#[allow(async_fn_in_trait)]
733pub trait CanBackendAsync: CanBackend {
734    /// Send a CAN message asynchronously.
735    ///
736    /// This is the async version of [`CanBackend::send_message`].
737    ///
738    /// # Arguments
739    ///
740    /// * `message` - The CAN message to send
741    ///
742    /// # Returns
743    ///
744    /// * `Ok(())` - Message sent successfully
745    /// * `Err(CanError)` - Send failed
746    ///
747    /// # Examples
748    ///
749    /// ```rust,ignore
750    /// let msg = CanMessage::new_standard(0x123, &[0x01, 0x02])?;
751    /// backend.send_message_async(&msg).await?;
752    /// ```
753    async fn send_message_async(&mut self, message: &CanMessage) -> CanResult<()>;
754
755    /// Receive a CAN message asynchronously with optional timeout.
756    ///
757    /// This is the async version of [`CanBackend::receive_message`].
758    /// Unlike the sync version, this method can wait for a message with a timeout.
759    ///
760    /// # Arguments
761    ///
762    /// * `timeout` - Optional timeout duration. If `None`, returns immediately
763    ///   like the sync version. If `Some(duration)`, waits up to that duration
764    ///   for a message.
765    ///
766    /// # Returns
767    ///
768    /// * `Ok(Some(message))` - A message was received
769    /// * `Ok(None)` - No message available (timeout expired or no timeout and queue empty)
770    /// * `Err(CanError)` - Reception failed
771    ///
772    /// # Examples
773    ///
774    /// ```rust,ignore
775    /// // Non-blocking receive
776    /// if let Some(msg) = backend.receive_message_async(None).await? {
777    ///     println!("Received: {:?}", msg);
778    /// }
779    ///
780    /// // Receive with 1 second timeout
781    /// match backend.receive_message_async(Some(Duration::from_secs(1))).await? {
782    ///     Some(msg) => println!("Received: {:?}", msg),
783    ///     None => println!("Timeout - no message received"),
784    /// }
785    /// ```
786    async fn receive_message_async(
787        &mut self,
788        timeout: Option<Duration>,
789    ) -> CanResult<Option<CanMessage>>;
790}
791
792#[cfg(test)]
793mod tests {
794    use super::*;
795
796    // Mock backend for testing
797    struct TestBackend {
798        initialized: bool,
799        fail_count: u32,
800    }
801
802    impl TestBackend {
803        fn new(fail_count: u32) -> Self {
804            Self {
805                initialized: false,
806                fail_count,
807            }
808        }
809    }
810
811    impl CanBackend for TestBackend {
812        fn initialize(&mut self, _config: &BackendConfig) -> CanResult<()> {
813            if self.fail_count > 0 {
814                self.fail_count -= 1;
815                Err(CanError::InitializationFailed {
816                    reason: "Test failure".to_string(),
817                })
818            } else {
819                self.initialized = true;
820                Ok(())
821            }
822        }
823
824        fn close(&mut self) -> CanResult<()> {
825            Ok(())
826        }
827
828        fn get_capability(&self) -> CanResult<HardwareCapability> {
829            unimplemented!()
830        }
831
832        fn send_message(&mut self, _message: &CanMessage) -> CanResult<()> {
833            unimplemented!()
834        }
835
836        fn receive_message(&mut self) -> CanResult<Option<CanMessage>> {
837            unimplemented!()
838        }
839
840        fn open_channel(&mut self, _channel: u8) -> CanResult<()> {
841            unimplemented!()
842        }
843
844        fn close_channel(&mut self, _channel: u8) -> CanResult<()> {
845            unimplemented!()
846        }
847
848        fn version(&self) -> BackendVersion {
849            BackendVersion::new(0, 1, 0)
850        }
851
852        fn name(&self) -> &'static str {
853            "test"
854        }
855    }
856
857    #[test]
858    fn test_retry_initialize_success_first_attempt() {
859        let mut backend = TestBackend::new(0);
860        let config = BackendConfig::new("test");
861
862        let result = retry_initialize(&mut backend, &config, 3, 10);
863        assert!(result.is_ok());
864        assert!(backend.initialized);
865    }
866
867    #[test]
868    fn test_retry_initialize_success_after_retries() {
869        let mut backend = TestBackend::new(2); // Fail 2 times, succeed on 3rd
870        let config = BackendConfig::new("test");
871
872        let result = retry_initialize(&mut backend, &config, 3, 10);
873        assert!(result.is_ok());
874        assert!(backend.initialized);
875    }
876
877    #[test]
878    fn test_retry_initialize_failure_all_attempts() {
879        let mut backend = TestBackend::new(10); // Fail all attempts
880        let config = BackendConfig::new("test");
881
882        let result = retry_initialize(&mut backend, &config, 3, 10);
883        assert!(result.is_err());
884        assert!(!backend.initialized);
885
886        if let Err(CanError::InitializationFailed { reason }) = result {
887            assert!(reason.contains("Failed after 4 attempts"));
888        } else {
889            panic!("Expected InitializationFailed error");
890        }
891    }
892}
893
894// ============================================================================
895// High-Frequency Message Rate Monitor (FR-016)
896// ============================================================================
897
898/// Message rate monitor for detecting high-frequency message scenarios.
899///
900/// This utility helps backends detect when message rates exceed a threshold
901/// and log warnings as specified in FR-016. It does not perform any automatic
902/// throttling or backpressure - it only logs warnings for user awareness.
903///
904/// # Usage
905///
906/// Backends can use this to monitor receive rates:
907///
908/// ```rust,ignore
909/// use canlink_hal::backend::MessageRateMonitor;
910///
911/// let mut monitor = MessageRateMonitor::new(1000); // Warn above 1000 msg/s
912///
913/// // In receive loop:
914/// if let Some(msg) = backend.receive_message()? {
915///     monitor.record_message();
916///     process(msg);
917/// }
918/// ```
919///
920/// # Thread Safety
921///
922/// This struct is not thread-safe. Each thread should have its own monitor
923/// or use external synchronization.
924#[derive(Debug)]
925pub struct MessageRateMonitor {
926    /// Threshold in messages per second
927    threshold_per_second: u32,
928    /// Message count in current window
929    message_count: u32,
930    /// Start of current measurement window
931    window_start: std::time::Instant,
932    /// Whether we've already warned in this window
933    warned_this_window: bool,
934}
935
936impl MessageRateMonitor {
937    /// Create a new message rate monitor.
938    ///
939    /// # Arguments
940    ///
941    /// * `threshold_per_second` - Message rate threshold that triggers warnings
942    ///
943    /// # Examples
944    ///
945    /// ```
946    /// use canlink_hal::backend::MessageRateMonitor;
947    ///
948    /// // Warn when rate exceeds 1000 messages/second
949    /// let monitor = MessageRateMonitor::new(1000);
950    /// ```
951    #[must_use]
952    pub fn new(threshold_per_second: u32) -> Self {
953        Self {
954            threshold_per_second,
955            message_count: 0,
956            window_start: std::time::Instant::now(),
957            warned_this_window: false,
958        }
959    }
960
961    /// Record a message and check if rate exceeds threshold.
962    ///
963    /// Returns `true` if the rate exceeds the threshold (warning should be logged).
964    /// Only returns `true` once per measurement window to avoid log spam.
965    ///
966    /// # Examples
967    ///
968    /// ```
969    /// use canlink_hal::backend::MessageRateMonitor;
970    ///
971    /// let mut monitor = MessageRateMonitor::new(1000);
972    ///
973    /// // Record messages
974    /// if monitor.record_message() {
975    ///     // Rate exceeded threshold - handle warning
976    ///     eprintln!("Warning: High message rate detected");
977    /// }
978    /// ```
979    pub fn record_message(&mut self) -> bool {
980        self.message_count += 1;
981
982        let elapsed = self.window_start.elapsed();
983
984        // Check every second
985        if elapsed >= Duration::from_secs(1) {
986            let exceeded = self.message_count > self.threshold_per_second;
987
988            // Log warning if exceeded and haven't warned yet
989            if exceeded && !self.warned_this_window {
990                #[cfg(feature = "tracing")]
991                tracing::warn!(
992                    "High message rate detected: {} messages/second (threshold: {})",
993                    self.message_count,
994                    self.threshold_per_second
995                );
996                self.warned_this_window = true;
997            }
998
999            // Reset for next window
1000            self.message_count = 0;
1001            self.window_start = std::time::Instant::now();
1002            self.warned_this_window = false;
1003
1004            exceeded
1005        } else {
1006            false
1007        }
1008    }
1009
1010    /// Get the current message count in this window.
1011    #[must_use]
1012    pub fn current_count(&self) -> u32 {
1013        self.message_count
1014    }
1015
1016    /// Get the configured threshold.
1017    #[must_use]
1018    pub fn threshold(&self) -> u32 {
1019        self.threshold_per_second
1020    }
1021
1022    /// Reset the monitor state.
1023    pub fn reset(&mut self) {
1024        self.message_count = 0;
1025        self.window_start = std::time::Instant::now();
1026        self.warned_this_window = false;
1027    }
1028}
1029
1030impl Default for MessageRateMonitor {
1031    /// Create a monitor with default threshold of 10000 messages/second.
1032    fn default() -> Self {
1033        Self::new(10000)
1034    }
1035}