### nb::Error - Non-Blocking Error Handling in Rust Source: https://context7.com/rust-embedded/nb/llms.txt Demonstrates the use of the `nb::Error` enum for non-blocking error handling. It distinguishes between fatal errors (`Error::Other(E)`) and retriable non-blocking operations (`Error::WouldBlock`). Includes examples of error creation and pattern matching. ```rust use nb::Error; // Define custom error types for your API #[derive(Debug)] enum SerialError { Overrun, ParityError, FramingError, } // Create errors let fatal_error: Error = Error::Other(SerialError::Overrun); let would_block: Error = Error::WouldBlock; // Pattern matching on errors match some_operation() { Ok(value) => println!("Success: {:?}", value), Err(Error::Other(e)) => eprintln!("Fatal error: {:?}", e), Err(Error::WouldBlock) => println!("Operation would block, retry later"), } fn some_operation() -> nb::Result { // Simulating a non-blocking read that would block Err(Error::WouldBlock) } ``` -------------------------------- ### Hardware Abstraction Layer (HAL) Pattern with Non-Blocking UART in Rust Source: https://context7.com/rust-embedded/nb/llms.txt Presents a Hardware Abstraction Layer (HAL) pattern using a non-blocking UART implementation in Rust. It showcases how to build a HAL that can be used in both blocking and asynchronous contexts, featuring a `Uart` struct with non-blocking `read` and `write` methods. It also demonstrates a `BlockingUart` wrapper that utilizes the `nb::block!` macro to provide a blocking interface over the non-blocking primitives. ```rust use core::convert::Infallible; use nb::{Error, Result, block}; // Hardware abstraction layer pub struct Uart { tx_ready: bool, rx_ready: bool, rx_buffer: Option, } impl Uart { pub fn new() -> Self { Uart { tx_ready: true, rx_ready: false, rx_buffer: None, } } pub fn read(&mut self) -> Result { match self.rx_buffer.take() { Some(byte) => { self.rx_ready = false; Ok(byte) } None => Err(Error::WouldBlock), } } pub fn write(&mut self, byte: u8) -> Result<(), Infallible> { if self.tx_ready { // Simulate transmission self.tx_ready = false; Ok(()) } else { Err(Error::WouldBlock) } } } // Blocking wrapper using block! macro pub struct BlockingUart { inner: Uart, } impl BlockingUart { pub fn new(uart: Uart) -> Self { BlockingUart { inner: uart } } pub fn read(&mut self) -> Result { block!(self.inner.read()) } pub fn write(&mut self, byte: u8) -> Result<(), Infallible> { block!(self.inner.write(byte)) } } fn main() { let uart = Uart::new(); let mut blocking_uart = BlockingUart::new(uart); // Blocks until write completes blocking_uart.write(0x48).unwrap(); println!("Data transmitted"); } ``` -------------------------------- ### Rust: Cooperative Multitasking with Custom Scheduler and nb Crate Source: https://context7.com/rust-embedded/nb/llms.txt This Rust code demonstrates cooperative multitasking using a custom scheduler. It defines `Task` and `Scheduler` structs, utilizing the `nb::Result` and `Error::WouldBlock` for non-blocking operations, suitable for embedded systems where cooperative multitasking is required. ```rust use nb::{Error, Result}; use core::convert::Infallible; struct Task { id: u8, } impl Task { fn process(&mut self) -> Result<(), Infallible> { static mut TICKS: u32 = 0; unsafe { TICKS += 1; if TICKS % 10 == 0 { Ok(()) } else { Err(Error::WouldBlock) } } } } struct Scheduler { tasks: Vec, } impl Scheduler { fn run(&mut self) { loop { let mut all_blocked = true; for task in &mut self.tasks { match task.process() { Ok(()) => { println!("Task {} completed", task.id); all_blocked = false; } Err(Error::WouldBlock) => { // Try next task continue; } Err(Error::Other(_)) => { // Infallible, unreachable unreachable!(); } } } if all_blocked { // All tasks blocked, could sleep or wait for interrupt break; } } } } fn main() { let mut scheduler = Scheduler { tasks: vec![Task { id: 1 }, Task { id: 2 }], }; scheduler.run(); } ``` -------------------------------- ### nb::block! Macro - Blocking Conversion in Rust Source: https://context7.com/rust-embedded/nb/llms.txt Demonstrates the `block!` macro from the nb crate, which converts a non-blocking expression into a blocking one by repeatedly retrying until successful. It handles both successful completion and fatal errors, suitable for scenarios where busy-waiting is acceptable. ```rust use core::convert::Infallible; use nb::{Error, block}; // Simulated non-blocking serial interface struct Serial { buffer: Option, } impl Serial { fn read(&mut self) -> nb::Result { match self.buffer.take() { Some(byte) => Ok(byte), None => Err(Error::WouldBlock), } } fn write(&mut self, byte: u8) -> nb::Result<(), Infallible> { if self.buffer.is_none() { self.buffer = Some(byte); Ok(()) } else { Err(Error::WouldBlock) } } } fn main() -> Result<(), Infallible> { let mut serial = Serial { buffer: Some(0x42) }; // Block until data is available let byte = block!(serial.read())?; println!("Received: 0x{:02X}", byte); // Block until write completes block!(serial.write(0xFF))?; println!("Sent: 0xFF"); Ok(()) } ``` -------------------------------- ### Non-Blocking Result Type Usage with Custom Errors in Rust Source: https://context7.com/rust-embedded/nb/llms.txt Demonstrates the usage of `nb::Result` for non-blocking APIs. It shows how to define custom error types and handle `Error::Other` and `Error::WouldBlock` variants. This is crucial for managing operations that might fail or temporarily cannot complete in embedded systems. ```rust use core::convert::Infallible; use nb::{Error, Result}; // API with custom error type #[derive(Debug)] enum SpiError { BusError, ChipSelectError, } struct Spi; impl Spi { // Can fail with SpiError or would block fn transfer(&mut self, byte: u8) -> Result { if byte == 0 { Err(Error::Other(SpiError::BusError)) } else if byte == 0xFF { Err(Error::WouldBlock) } else { Ok(byte.wrapping_add(1)) } } } // API with no fatal errors, only blocks struct Timer; impl Timer { fn wait(&self) -> Result<(), Infallible> { // Uses Infallible to indicate no fatal errors static mut COUNTER: u32 = 0; unsafe { COUNTER += 1; if COUNTER >= 100 { COUNTER = 0; Ok(()) } else { Err(Error::WouldBlock) } } } } fn example() { let mut spi = Spi; match spi.transfer(5) { Ok(response) => println!("Got: {}", response), Err(Error::Other(e)) => eprintln!("Fatal: {:?}", e), Err(Error::WouldBlock) => println!("Busy"), } } ``` -------------------------------- ### Automatic Error Conversion with `From` Trait in Rust Source: https://context7.com/rust-embedded/nb/llms.txt Illustrates how the `From` trait implementation simplifies error handling in non-blocking Rust APIs. It enables automatic conversion of application-specific errors into `nb::Error::Other(E)`, allowing the use of the `?` operator for cleaner error propagation. This reduces boilerplate code when dealing with nested or chained non-blocking operations. ```rust use nb::{Error, Result}; #[derive(Debug)] enum I2cError { NoAck, BusTimeout, } // From is implemented automatically impl From for Error { fn from(error: I2cError) -> Error { Error::Other(error) } } struct I2c; impl I2c { fn write_byte(&mut self, addr: u8, byte: u8) -> Result<(), I2cError> { self.check_bus()?; // Automatically converts I2cError to Error if byte == 0xFF { Err(Error::WouldBlock) } else { Ok(()) } } fn check_bus(&self) -> core::result::Result<(), I2cError> { // Returns plain I2cError, automatically converted via ? Err(I2cError::NoAck) } } fn usage_example() { let mut i2c = I2c; match i2c.write_byte(0x50, 0x42) { Ok(()) => println!("Write successful"), Err(Error::Other(I2cError::NoAck)) => eprintln!("Device not responding"), Err(Error::Other(I2cError::BusTimeout)) => eprintln!("Bus timeout"), Err(Error::WouldBlock) => println!("Bus busy"), } } ``` -------------------------------- ### nb::Error::map() - Transforming Non-Blocking Errors in Rust Source: https://context7.com/rust-embedded/nb/llms.txt Illustrates the `map()` method on `nb::Error`, which transforms the inner error type of `Error::Other` while leaving `Error::WouldBlock` untouched. This is useful for error propagation and adaptation between different API layers. ```rust use nb::Error; #[derive(Debug)] enum LowLevelError { HardwareFault, } #[derive(Debug)] enum HighLevelError { DeviceError(String), } fn low_level_read() -> nb::Result { Err(Error::Other(LowLevelError::HardwareFault)) } fn high_level_read() -> nb::Result { // Map low-level errors to high-level errors low_level_read().map_err(|e| e.map(|low_err| { HighLevelError::DeviceError(format!("Hardware failed: {:?}", low_err)) })) } // WouldBlock is preserved through mapping let result: nb::Result = Err(Error::WouldBlock); let mapped: nb::Result = result.map_err(|e| e.map(|_| { HighLevelError::DeviceError("Unreachable".to_string()) })); assert_eq!(mapped, Err(Error::WouldBlock)); ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.