use super::{BidError, BidResult, BidHandle, BidTag, BID_VERSION}; use std::mem; /// BID-1 TLV Header #[repr(C)] #[derive(Debug, Clone, Copy)] pub struct BidTlvHeader { pub version: u16, // BID version (1) pub argc: u16, // Argument count } /// TLV Entry structure #[repr(C)] #[derive(Debug, Clone, Copy)] pub struct TlvEntry { pub tag: u8, // Type tag pub reserved: u8, // Reserved for future use (0) pub size: u16, // Payload size // Payload follows immediately after } /// TLV encoder for BID-1 format pub struct TlvEncoder { buffer: Vec, entry_count: u16, } impl TlvEncoder { /// Create a new TLV encoder pub fn new() -> Self { let mut encoder = Self { buffer: Vec::with_capacity(256), entry_count: 0, }; // Reserve space for header encoder.buffer.extend_from_slice(&[0; mem::size_of::()]); encoder } /// Encode a boolean value pub fn encode_bool(&mut self, value: bool) -> BidResult<()> { self.encode_entry(BidTag::Bool, &[if value { 1 } else { 0 }]) } /// Encode a 32-bit integer pub fn encode_i32(&mut self, value: i32) -> BidResult<()> { self.encode_entry(BidTag::I32, &value.to_le_bytes()) } /// Encode a 64-bit integer pub fn encode_i64(&mut self, value: i64) -> BidResult<()> { self.encode_entry(BidTag::I64, &value.to_le_bytes()) } /// Encode a 32-bit float pub fn encode_f32(&mut self, value: f32) -> BidResult<()> { self.encode_entry(BidTag::F32, &value.to_le_bytes()) } /// Encode a 64-bit float pub fn encode_f64(&mut self, value: f64) -> BidResult<()> { self.encode_entry(BidTag::F64, &value.to_le_bytes()) } /// Encode a string pub fn encode_string(&mut self, value: &str) -> BidResult<()> { let bytes = value.as_bytes(); if bytes.len() > u16::MAX as usize { return Err(BidError::InvalidArgs); } self.encode_entry(BidTag::String, bytes) } /// Encode binary data pub fn encode_bytes(&mut self, value: &[u8]) -> BidResult<()> { if value.len() > u16::MAX as usize { return Err(BidError::InvalidArgs); } self.encode_entry(BidTag::Bytes, value) } /// Encode a handle pub fn encode_handle(&mut self, handle: BidHandle) -> BidResult<()> { self.encode_entry(BidTag::Handle, &handle.to_u64().to_le_bytes()) } /// Encode void (no payload) pub fn encode_void(&mut self) -> BidResult<()> { self.encode_entry(BidTag::Void, &[]) } /// Internal: encode a TLV entry fn encode_entry(&mut self, tag: BidTag, payload: &[u8]) -> BidResult<()> { let entry = TlvEntry { tag: tag as u8, reserved: 0, size: payload.len() as u16, }; // Write entry header self.buffer.push(entry.tag); self.buffer.push(entry.reserved); self.buffer.extend_from_slice(&entry.size.to_le_bytes()); // Write payload self.buffer.extend_from_slice(payload); self.entry_count += 1; Ok(()) } /// Finalize the encoding and return the buffer pub fn finish(mut self) -> Vec { // Update header let header = BidTlvHeader { version: BID_VERSION, argc: self.entry_count, }; // Write header at the beginning self.buffer[0..2].copy_from_slice(&header.version.to_le_bytes()); self.buffer[2..4].copy_from_slice(&header.argc.to_le_bytes()); self.buffer } } /// TLV decoder for BID-1 format pub struct TlvDecoder<'a> { data: &'a [u8], position: usize, header: BidTlvHeader, } impl<'a> TlvDecoder<'a> { /// Create a new TLV decoder pub fn new(data: &'a [u8]) -> BidResult { if data.len() < mem::size_of::() { return Err(BidError::InvalidArgs); } // Read header safely let version = u16::from_le_bytes([data[0], data[1]]); let argc = u16::from_le_bytes([data[2], data[3]]); let header = BidTlvHeader { version, argc }; if header.version != BID_VERSION { return Err(BidError::VersionMismatch); } Ok(Self { data, position: mem::size_of::(), header, }) } /// Get the argument count pub fn arg_count(&self) -> u16 { self.header.argc } /// Decode the next entry pub fn decode_next(&mut self) -> BidResult> { if self.position >= self.data.len() { return Ok(None); } // Read entry header if self.position + mem::size_of::() > self.data.len() { return Err(BidError::InvalidArgs); } // Read entry safely let tag = self.data[self.position]; let reserved = self.data[self.position + 1]; let size = u16::from_le_bytes([ self.data[self.position + 2], self.data[self.position + 3], ]); let entry = TlvEntry { tag, reserved, size }; self.position += mem::size_of::(); // Read payload let payload_end = self.position + entry.size as usize; if payload_end > self.data.len() { return Err(BidError::InvalidArgs); } let payload = &self.data[self.position..payload_end]; self.position = payload_end; // Convert tag let tag = match entry.tag { 1 => BidTag::Bool, 2 => BidTag::I32, 3 => BidTag::I64, 4 => BidTag::F32, 5 => BidTag::F64, 6 => BidTag::String, 7 => BidTag::Bytes, 8 => BidTag::Handle, 9 => BidTag::Void, 20 => BidTag::Result, 21 => BidTag::Option, 22 => BidTag::Array, _ => return Err(BidError::InvalidType), }; Ok(Some((tag, payload))) } /// Decode a boolean from payload pub fn decode_bool(payload: &[u8]) -> BidResult { if payload.len() != 1 { return Err(BidError::InvalidArgs); } Ok(payload[0] != 0) } /// Decode an i32 from payload pub fn decode_i32(payload: &[u8]) -> BidResult { if payload.len() != 4 { return Err(BidError::InvalidArgs); } Ok(i32::from_le_bytes([payload[0], payload[1], payload[2], payload[3]])) } /// Decode an i64 from payload pub fn decode_i64(payload: &[u8]) -> BidResult { if payload.len() != 8 { return Err(BidError::InvalidArgs); } let mut bytes = [0u8; 8]; bytes.copy_from_slice(payload); Ok(i64::from_le_bytes(bytes)) } /// Decode a handle from payload pub fn decode_handle(payload: &[u8]) -> BidResult { if payload.len() != 8 { return Err(BidError::InvalidArgs); } let mut bytes = [0u8; 8]; bytes.copy_from_slice(payload); Ok(BidHandle::from_u64(u64::from_le_bytes(bytes))) } /// Decode an f32 from payload pub fn decode_f32(payload: &[u8]) -> BidResult { if payload.len() != 4 { return Err(BidError::InvalidArgs); } Ok(f32::from_le_bytes([payload[0], payload[1], payload[2], payload[3]])) } /// Decode an f64 from payload pub fn decode_f64(payload: &[u8]) -> BidResult { if payload.len() != 8 { return Err(BidError::InvalidArgs); } let mut bytes = [0u8; 8]; bytes.copy_from_slice(payload); Ok(f64::from_le_bytes(bytes)) } /// Decode a string from payload pub fn decode_string(payload: &[u8]) -> BidResult<&str> { std::str::from_utf8(payload).map_err(|_| BidError::InvalidUtf8) } } #[cfg(test)] mod tests { use super::*; #[test] fn test_encode_decode_primitives() { let mut encoder = TlvEncoder::new(); encoder.encode_bool(true).unwrap(); encoder.encode_i32(42).unwrap(); encoder.encode_i64(9876543210).unwrap(); encoder.encode_string("Hello Nyash!").unwrap(); let data = encoder.finish(); let mut decoder = TlvDecoder::new(&data).unwrap(); assert_eq!(decoder.arg_count(), 4); // Decode bool let (tag, payload) = decoder.decode_next().unwrap().unwrap(); assert_eq!(tag, BidTag::Bool); assert_eq!(TlvDecoder::decode_bool(payload).unwrap(), true); // Decode i32 let (tag, payload) = decoder.decode_next().unwrap().unwrap(); assert_eq!(tag, BidTag::I32); assert_eq!(TlvDecoder::decode_i32(payload).unwrap(), 42); // Decode i64 let (tag, payload) = decoder.decode_next().unwrap().unwrap(); assert_eq!(tag, BidTag::I64); assert_eq!(TlvDecoder::decode_i64(payload).unwrap(), 9876543210); // Decode string let (tag, payload) = decoder.decode_next().unwrap().unwrap(); assert_eq!(tag, BidTag::String); assert_eq!(TlvDecoder::decode_string(payload).unwrap(), "Hello Nyash!"); } #[test] fn test_encode_decode_handle() { let mut encoder = TlvEncoder::new(); let handle = BidHandle::new(6, 12345); encoder.encode_handle(handle).unwrap(); let data = encoder.finish(); let mut decoder = TlvDecoder::new(&data).unwrap(); let (tag, payload) = decoder.decode_next().unwrap().unwrap(); assert_eq!(tag, BidTag::Handle); assert_eq!(TlvDecoder::decode_handle(payload).unwrap(), handle); } }