use conduit_core::{
Decode, Encode, FRAME_HEADER_SIZE, FrameHeader, MsgType, PROTOCOL_VERSION, RingBuffer, Router,
frame_pack, frame_unpack,
};
fn main() {
println!("=== conduit-core basic usage ===\n");
println!("--- Step 1: Router ---\n");
let table = Router::new();
table.register("echo", |payload: Vec<u8>| payload);
table.register("greet", |payload: Vec<u8>| match String::decode(&payload) {
Some((name, _consumed)) => {
let greeting = format!("Hello, {name}! Welcome to conduit.");
let mut out = Vec::new();
greeting.encode(&mut out);
out
}
None => b"decode error".to_vec(),
});
table.register_simple("version", || {
let mut out = Vec::new();
String::from("conduit-core 1.0.0").encode(&mut out);
out
});
println!(" Registered commands: echo, greet, version");
println!(" has(\"echo\") = {}", table.has("echo"));
println!(" has(\"greet\") = {}", table.has("greet"));
println!(" has(\"version\") = {}", table.has("version"));
println!(" has(\"nope\") = {}", table.has("nope"));
println!("\n--- Step 2: Build a request frame ---\n");
let mut payload = Vec::new();
String::from("Alice").encode(&mut payload);
println!(
" Payload (wire-encoded \"Alice\"): {} bytes",
payload.len()
);
println!(" Raw bytes: {:02X?}", payload);
let request_header = FrameHeader {
version: PROTOCOL_VERSION,
reserved: 0,
msg_type: MsgType::Request,
sequence: 1,
payload_len: payload.len() as u32,
};
println!(" Frame header: {:?}", request_header);
let request_frame = frame_pack(&request_header, &payload);
println!(
" Complete frame: {} bytes (header {FRAME_HEADER_SIZE} + payload {})",
request_frame.len(),
payload.len()
);
println!("\n--- Step 3: Dispatch the command ---\n");
let (parsed_header, parsed_payload) =
frame_unpack(&request_frame).expect("frame_unpack failed");
println!(" Parsed header: {:?}", parsed_header);
println!(" Parsed payload length: {} bytes", parsed_payload.len());
let response_bytes = table
.call("greet", parsed_payload.to_vec())
.expect("dispatch failed");
let (greeting, _) = String::decode(&response_bytes).unwrap();
println!(" Response: \"{greeting}\"");
let err = table.call("nonexistent", vec![]).unwrap_err();
println!(" Unknown command error: {err}");
println!("\n--- Step 4: Wrap the response in a frame ---\n");
let response_header = FrameHeader {
version: PROTOCOL_VERSION,
reserved: 0,
msg_type: MsgType::Response,
sequence: 1, payload_len: response_bytes.len() as u32,
};
let response_frame = frame_pack(&response_header, &response_bytes);
println!(" Response frame: {} bytes total", response_frame.len());
let (resp_hdr, resp_payload) = frame_unpack(&response_frame).unwrap();
assert_eq!(resp_hdr.msg_type, MsgType::Response);
assert_eq!(resp_hdr.sequence, 1);
let (decoded_greeting, _) = String::decode(resp_payload).unwrap();
println!(" Verified roundtrip: \"{decoded_greeting}\"");
println!("\n--- Step 5: Ring buffer push/drain ---\n");
let ring = RingBuffer::new(1024);
println!(" Created ring buffer: capacity={} bytes", ring.capacity());
for i in 0u32..5 {
let mut tick_payload = Vec::new();
i.encode(&mut tick_payload);
(100.0 + i as f64).encode(&mut tick_payload);
let tick_header = FrameHeader {
version: PROTOCOL_VERSION,
reserved: 0,
msg_type: MsgType::Push,
sequence: i,
payload_len: tick_payload.len() as u32,
};
let tick_frame = frame_pack(&tick_header, &tick_payload);
let outcome = ring.push(&tick_frame);
println!(
" Pushed tick {i}: {} bytes, outcome={outcome:?}",
tick_frame.len()
);
}
println!(
" Buffer state: {} frames, {} bytes used",
ring.frame_count(),
ring.bytes_used()
);
let blob = ring.drain_all();
println!(" Drained blob: {} bytes", blob.len());
println!(
" Buffer after drain: {} frames, {} bytes used",
ring.frame_count(),
ring.bytes_used()
);
println!("\n--- Step 6: Parse drain wire format ---\n");
let frame_count = u32::from_le_bytes(blob[0..4].try_into().unwrap());
println!(" Frame count: {frame_count}");
let mut offset = 4usize;
for i in 0..frame_count {
let frame_len = u32::from_le_bytes(blob[offset..offset + 4].try_into().unwrap()) as usize;
offset += 4;
let frame_bytes = &blob[offset..offset + frame_len];
offset += frame_len;
let (hdr, payload) = frame_unpack(frame_bytes).expect("bad frame in drain blob");
let (index, consumed) = u32::decode(payload).unwrap();
let (price, _) = f64::decode(&payload[consumed..]).unwrap();
println!(
" Frame {i}: seq={}, type={:?}, index={index}, price={price:.1}",
hdr.sequence, hdr.msg_type,
);
}
assert_eq!(offset, blob.len(), "all bytes consumed");
println!("\n=== Done! ===");
}