file_io/
file_io.rs

1//! Example demonstrating the `Byteable` derive macro with file I/O operations.
2//!
3//! This example shows how to:
4//! - Define a struct with the Byteable derive macro
5//! - Write byteable structs to a file
6//! - Read byteable structs from a file
7//! - Handle endianness with BigEndian and LittleEndian wrappers
8
9use byteable::{BigEndian, Byteable, LittleEndian, ReadByteable, WriteByteable};
10use std::fs::File;
11use std::io::{self, Seek, SeekFrom};
12
13/// A simple network packet structure demonstrating the Byteable derive macro.
14///
15/// Requirements for deriving Byteable:
16/// - Must be `#[repr(C, packed)]` or `#[repr(C)]` for predictable memory layout
17/// - Must implement `Copy`
18/// - All fields must be Byteable (primitives, or types wrapped in BigEndian/LittleEndian)
19#[derive(Byteable, Clone, Copy, PartialEq, Debug)]
20#[repr(C, packed)]
21struct NetworkPacket {
22    /// Packet sequence number (native endianness)
23    sequence: u8,
24    /// Packet type identifier (little-endian)
25    packet_type: LittleEndian<u16>,
26    /// Payload length (big-endian)
27    payload_length: BigEndian<u32>,
28    /// Timestamp (little-endian)
29    timestamp: LittleEndian<u64>,
30}
31
32/// A configuration structure demonstrating mixed endianness.
33#[derive(Byteable, Clone, Copy, PartialEq, Debug)]
34#[repr(C, packed)]
35struct DeviceConfig {
36    /// Device ID (little-endian, common for x86 devices)
37    device_id: LittleEndian<u32>,
38    /// Protocol version (native endianness for single-byte values)
39    version: u8,
40    /// Flags bitfield
41    flags: u8,
42    /// Network port (big-endian, standard for network byte order)
43    port: BigEndian<u16>,
44    /// Calibration factor (little-endian float)
45    calibration: LittleEndian<f32>,
46}
47
48fn main() -> io::Result<()> {
49    println!("=== Byteable Derive Macro Example ===\n");
50
51    // Example 1: Creating and inspecting a byteable struct
52    println!("1. Creating a NetworkPacket:");
53    let packet = NetworkPacket {
54        sequence: 42,
55        packet_type: LittleEndian::new(0x1234),
56        payload_length: BigEndian::new(1024),
57        timestamp: LittleEndian::new(1638360000),
58    };
59
60    println!("   Packet: {:?}", packet);
61    println!("   Sequence: {}", packet.sequence);
62    println!("   Packet Type: 0x{:04X}", packet.packet_type.get());
63    println!("   Payload Length: {} bytes", packet.payload_length.get());
64    println!("   Timestamp: {}", packet.timestamp.get());
65
66    // Convert to byte array
67    let bytes = packet.as_bytearray();
68    println!("   As bytes: {:?}", bytes);
69    println!("   Size: {} bytes\n", bytes.len());
70
71    // Example 2: Writing to a file
72    println!("2. Writing structs to a file:");
73    let mut file = File::create("example_data.bin")?;
74
75    // Write multiple packets
76    file.write_one(packet)?;
77
78    let packet2 = NetworkPacket {
79        sequence: 43,
80        packet_type: LittleEndian::new(0x5678),
81        payload_length: BigEndian::new(2048),
82        timestamp: LittleEndian::new(1638360001),
83    };
84    file.write_one(packet2)?;
85
86    // Write a device config
87    let config = DeviceConfig {
88        device_id: LittleEndian::new(0xABCDEF01),
89        version: 1,
90        flags: 0b10101010,
91        port: BigEndian::new(8080),
92        calibration: LittleEndian::new(3.14159),
93    };
94    file.write_one(config)?;
95
96    println!("   Written 2 NetworkPackets and 1 DeviceConfig to 'example_data.bin'");
97    println!(
98        "   File size: {} bytes\n",
99        std::mem::size_of::<NetworkPacket>() * 2 + std::mem::size_of::<DeviceConfig>()
100    );
101
102    // Example 3: Reading from a file
103    println!("3. Reading structs from the file:");
104    let mut file = File::open("example_data.bin")?;
105
106    // Read the packets back
107    let read_packet1: NetworkPacket = file.read_one()?;
108    let read_packet2: NetworkPacket = file.read_one()?;
109    let read_config: DeviceConfig = file.read_one()?;
110
111    println!("   First packet: {:?}", read_packet1);
112    println!("   Matches original: {}", read_packet1 == packet);
113    println!();
114
115    println!("   Second packet: {:?}", read_packet2);
116    println!("   Sequence: {}", read_packet2.sequence);
117    println!();
118
119    println!("   Device config: {:?}", read_config);
120    println!("   Device ID: 0x{:08X}", read_config.device_id.get());
121    println!("   Version: {}", read_config.version);
122    println!("   Flags: 0b{:08b}", read_config.flags);
123    println!("   Port: {}", read_config.port.get());
124    println!("   Calibration: {:.5}", read_config.calibration.get());
125    println!();
126
127    // Example 4: Random access with seek
128    println!("4. Random access with seek:");
129    file.seek(SeekFrom::Start(0))?;
130    let first: NetworkPacket = file.read_one()?;
131    println!("   Read first packet again: sequence = {}", first.sequence);
132
133    // Seek to the second packet
134    file.seek(SeekFrom::Start(std::mem::size_of::<NetworkPacket>() as u64))?;
135    let second: NetworkPacket = file.read_one()?;
136    println!("   Seeked to second packet: sequence = {}", second.sequence);
137    println!();
138
139    // Example 5: Demonstrating byte array conversion
140    println!("5. Manual byte array conversion:");
141    let test_packet = NetworkPacket {
142        sequence: 100,
143        packet_type: LittleEndian::new(0xFF00),
144        payload_length: BigEndian::new(512),
145        timestamp: LittleEndian::new(999999),
146    };
147
148    // Convert to bytes
149    let byte_array = test_packet.as_bytearray();
150    println!("   Original packet: {:?}", test_packet);
151    println!("   Byte array: {:?}", byte_array);
152
153    // Convert back from bytes
154    let reconstructed = NetworkPacket::from_bytearray(byte_array);
155    println!("   Reconstructed: {:?}", reconstructed);
156    println!("   Round-trip successful: {}", test_packet == reconstructed);
157
158    // Cleanup
159    println!("\n=== Example completed successfully! ===");
160    println!("Note: The file 'example_data.bin' has been created in the current directory.");
161
162    Ok(())
163}