Basic Type Implementations

Relevant source files

This section documents the concrete implementations of I/O traits for basic Rust types provided by the axio crate. These implementations enable fundamental data types to participate in the I/O trait ecosystem without requiring additional wrapper types.

The primary focus is on implementations for byte slices (&[u8]), which provide efficient read operations directly from memory. For buffered I/O implementations like BufReader, see Buffered I/O. For error handling across all implementations, see Error Handling.

Byte Slice Read Implementation

The axio crate provides a comprehensive Read trait implementation for byte slices (&[u8]), enabling direct reading from memory buffers. This implementation is found in src/impls.rs(L4 - L54)  and provides all core Read trait methods with performance optimizations.

Implementation Overview

The &[u8] implementation supports three key methods from the Read trait:

MethodPurposeFeature Gate
read()Pull bytes into a bufferAlways available
read_exact()Read exact number of bytesAlways available
read_to_end()Read all remaining bytesallocfeature

Sources: src/impls.rs(L4 - L54) 

Core Read Method

The fundamental read() method implementation uses an optimized approach for copying data from the byte slice to the destination buffer:

flowchart TD
A["read(buf: &mut [u8])"]
B["Calculate amt = min(buf.len(), self.len())"]
C["amt == 1?"]
D["Single byte copy: buf[0] = a[0]"]
E["Slice copy: buf[..amt].copy_from_slice(a)"]
F["Update slice: *self = &self[amt..]"]
G["Return Ok(amt)"]

A --> B
B --> C
C --> D
C --> E
D --> F
E --> F
F --> G

Byte Slice Read Operation Flow

The implementation includes a performance optimization that avoids the overhead of copy_from_slice for single-byte reads, directly assigning buf[0] = a[0] instead.

Sources: src/impls.rs(L6 - L22) 

Exact Read Implementation

The read_exact() method provides guaranteed completion semantics, either reading the exact requested amount or returning an error:

flowchart TD
A["read_exact(buf: &mut [u8])"]
B["buf.len() > self.len()?"]
C["Return UnexpectedEof error"]
D["Calculate amt = buf.len()"]
E["amt == 1?"]
F["Single byte: buf[0] = a[0]"]
G["Slice copy: buf[..amt].copy_from_slice(a)"]
H["Update slice: *self = &self[amt..]"]
I["Return Ok(())"]

A --> B
B --> C
B --> D
D --> E
E --> F
E --> G
F --> H
G --> H
H --> I

Exact Read Operation Flow

This method differs from read() by guaranteeing that either all requested bytes are read or an UnexpectedEof error is returned.

Sources: src/impls.rs(L25 - L44) 

Allocation-Dependent Methods

When the alloc feature is enabled, the byte slice implementation provides read_to_end(), which efficiently transfers all remaining data:

flowchart TD
A["read_to_end(buf: &mut Vec)"]
B["buf.extend_from_slice(self)"]
C["let len = self.len()"]
D["*self = &self[len..]"]
E["Return Ok(len)"]

A --> B
B --> C
C --> D
D --> E

Read to End Operation Flow

This implementation leverages Vec::extend_from_slice() for optimal performance when copying all remaining data from the byte slice.

Sources: src/impls.rs(L47 - L53) 

Trait Method Mapping

The following diagram shows how the generic Read trait methods map to specific implementations for byte slices:

classDiagram
note for Read "Optimized for memory efficiencySingle-byte copy optimizationDirect slice manipulation"
note for ByteSliceImpl "Optimized for memory efficiencySingle-byte copy optimizationDirect slice manipulation"
note for Read "Unsupported markdown: list"
class Read {
    <<trait>>
    
    +read(buf: &mut [u8]) Result~usize~
    +read_exact(buf: &mut [u8]) Result~() ~
    +read_to_end(buf: &mut Vec~u8~) Result~usize~
}

class ByteSliceImpl {
    
    +read(buf: &mut [u8]) Result~usize~
    +read_exact(buf: &mut [u8]) Result~() ~
    +read_to_end(buf: &mut Vec~u8~) Result~usize~
}

class &[u8] {
    -data: bytes
    -position: usize
    
}

Read  ..|>  ByteSliceImpl : implements
ByteSliceImpl  -->  ByteSliceImpl : operates on

Trait Implementation Relationship

Sources: src/lib.rs(L152 - L188)  src/impls.rs(L4 - L54) 

Performance Characteristics

The byte slice implementation includes several performance optimizations:

Memory Copy Optimization

The implementation uses conditional logic to optimize memory operations based on the amount of data being copied:

ScenarioImplementationRationale
Single byte (amt == 1)Direct assignment:buf[0] = a[0]Avoidsmemcpyoverhead
Multiple bytes (amt > 1)Slice copy:copy_from_slice(a)Leverages optimizedmemcpy

Slice Management

All methods update the source slice pointer (*self = b) to reflect consumed data, maintaining zero-copy semantics where the slice reference advances through the underlying data without additional allocations.

Sources: src/impls.rs(L14 - L18)  src/impls.rs(L36 - L40) 

Error Handling Integration

The byte slice implementations integrate with the axio error system through the axerrno crate:

flowchart TD
A["&[u8] methods"]
B["Validation check"]
C["Successful operation"]
D["axerrno::ax_err!"]
E["Error::UnexpectedEof"]
F["Result::Ok"]
G["Result::Err"]

A --> B
B --> C
B --> D
C --> F
D --> E
E --> G

Error Flow in Byte Slice Operations

The primary error condition for byte slice operations is UnexpectedEof, which occurs when read_exact() is called with a buffer larger than the remaining slice data.

Sources: src/impls.rs(L27)  src/error.rs