use super::bits::{BitReader, BitWriter};
use super::traits::FieldAccess;
use crate::core::{FieldDescriptor, FieldKind, PgnBytes, PgnDescriptor, PgnValue, MAX_PGN_BYTES};
use crate::error::{CodecError, DeserializationError, SerializationError};
pub fn deserialize_into<T: FieldAccess>(
instance: &mut T,
payload: &[u8],
descriptor: &'static PgnDescriptor,
) -> Result<(), DeserializationError> {
let mut reader = BitReader::new(payload);
let is_repetitive_field = |field_idx: usize| -> bool {
for rfs in descriptor.repeating_field_sets {
if field_idx >= rfs.start_field_index && field_idx < (rfs.start_field_index + rfs.size)
{
return true;
}
}
false
};
for (field_idx, field_desc) in descriptor.fields.iter().enumerate() {
if is_repetitive_field(field_idx) {
continue;
}
if let Some(value) = read_field_value(&mut reader, field_desc)? {
instance.field_mut(field_desc.id, value).ok_or(
DeserializationError::FieldAssignmentFailed {
desc: field_desc.id,
},
)?
}
}
for rfs in descriptor.repeating_field_sets {
let count = if let Some(counter_idx) = rfs.count_field_index {
let counter_field = descriptor
.fields
.get(counter_idx)
.ok_or(DeserializationError::InvalidDataLength)?;
let raw = match instance.field(counter_field.id) {
Some(PgnValue::U8(v)) => v as usize,
Some(PgnValue::U16(v)) => v as usize,
Some(PgnValue::U32(v)) => v as usize,
_ => return Err(DeserializationError::InvalidDataLength),
};
let counter_bits = counter_field.bits_length.unwrap_or(8).min(64);
let unavailable = (u64::MAX >> (64 - counter_bits)) as usize;
if raw == unavailable {
0
} else {
raw
}
} else {
return Err(DeserializationError::UnsupportedFieldKind {
field_kind: crate::core::FieldKind::Unimplemented,
});
};
let group_bits: usize = descriptor
.fields
.iter()
.skip(rfs.start_field_index)
.take(rfs.size)
.map(|f| f.bits_length.unwrap_or(0) as usize)
.sum();
let fits = reader.bits_remaining().checked_div(group_bits).unwrap_or(0);
let count = count.min(rfs.max_repetitions).min(fits);
instance
.set_repetitive_count(rfs.array_id, count)
.ok_or(DeserializationError::FieldAssignmentFailed { desc: rfs.array_id })?;
for elem_idx in 0..count {
for field_offset in 0..rfs.size {
let field_idx = rfs.start_field_index + field_offset;
let field_desc = descriptor
.fields
.get(field_idx)
.ok_or(DeserializationError::InvalidDataLength)?;
if let Some(value) = read_field_value(&mut reader, field_desc)? {
instance
.repetitive_field_mut(rfs.array_id, elem_idx, field_desc.id, value)
.ok_or(DeserializationError::FieldAssignmentFailed {
desc: field_desc.id,
})?;
}
}
}
}
Ok(())
}
pub fn serialize<T: FieldAccess>(
pgn_instance: &T,
buffer: &mut [u8],
descriptor: &'static PgnDescriptor,
) -> Result<usize, SerializationError> {
buffer.fill(0xFF);
let mut writer = BitWriter::new(buffer);
let is_repetitive_field = |field_idx: usize| -> bool {
for rfs in descriptor.repeating_field_sets {
if field_idx >= rfs.start_field_index && field_idx < (rfs.start_field_index + rfs.size)
{
return true;
}
}
false
};
for (field_idx, field_desc) in descriptor.fields.iter().enumerate() {
if is_repetitive_field(field_idx) {
continue;
}
let value = pgn_instance
.field(field_desc.id)
.ok_or(SerializationError::FieldNotFound {
field_id: field_desc.id,
})?;
write_field(&mut writer, field_desc, &value)?;
}
for rfs in descriptor.repeating_field_sets {
let count = pgn_instance.repetitive_count(rfs.array_id).ok_or(
SerializationError::FieldNotFound {
field_id: rfs.array_id,
},
)?;
let count = count.min(rfs.max_repetitions);
for elem_idx in 0..count {
for field_offset in 0..rfs.size {
let field_idx = rfs.start_field_index + field_offset;
let field_desc = descriptor
.fields
.get(field_idx)
.ok_or(SerializationError::InvalidData)?;
let value = pgn_instance
.repetitive_field(rfs.array_id, elem_idx, field_desc.id)
.ok_or(SerializationError::FieldNotFound {
field_id: field_desc.id,
})?;
write_field(&mut writer, field_desc, &value)?;
}
}
}
let bits_written = writer.bit_cursor();
Ok(bits_written.div_ceil(8))
}
fn read_field_value(
reader: &mut BitReader,
field_desc: &'static FieldDescriptor,
) -> Result<Option<PgnValue>, DeserializationError> {
match field_desc.kind {
FieldKind::BitLookup => {
let raw_val = if let Some(bits) = field_desc.bits_length {
match reader.read_u64(bits as u8) {
Ok(val) => val,
Err(_) => return Err(DeserializationError::InvalidDataLength),
}
} else {
return Err(DeserializationError::InvalidDataLength);
};
let value = match field_desc.bits_length {
Some(1..=8) => PgnValue::U8(raw_val as u8),
Some(9..=16) => PgnValue::U16(raw_val as u16),
Some(17..=32) => PgnValue::U32(raw_val as u32),
_ => PgnValue::U64(raw_val),
};
Ok(Some(value))
}
FieldKind::Number
| FieldKind::Lookup
| FieldKind::IndirectLookup
| FieldKind::Pgn
| FieldKind::IsoName => {
let raw_val = if let Some(bits) = field_desc.bits_length {
match reader.read_u64(bits as u8) {
Ok(val) => val,
Err(_) => return Err(DeserializationError::InvalidDataLength),
}
} else {
return Err(DeserializationError::InvalidDataLength);
};
let value = if field_desc.is_signed.is_some_and(|s| s) {
let signed_val = sign_extend(raw_val, field_desc.bits_length.unwrap_or(0) as u8);
if let Some(res) = field_desc.resolution {
match field_desc
.bits_length
.ok_or(DeserializationError::InvalidDataLength)?
{
1..=24 => PgnValue::F32(signed_val as f32 * res),
_ => PgnValue::F64(signed_val as f64 * res as f64),
}
} else {
match field_desc.bits_length {
Some(1..=8) => PgnValue::I8(signed_val as i8),
Some(9..=16) => PgnValue::I16(signed_val as i16),
Some(17..=32) => PgnValue::I32(signed_val as i32),
_ => PgnValue::I64(signed_val),
}
}
} else if let Some(res) = field_desc.resolution {
match field_desc
.bits_length
.ok_or(DeserializationError::InvalidDataLength)?
{
1..=24 => PgnValue::F32(raw_val as f32 * res),
_ => PgnValue::F64(raw_val as f64 * res as f64),
}
} else {
match field_desc.bits_length {
Some(1..=8) => PgnValue::U8(raw_val as u8),
Some(9..=16) => PgnValue::U16(raw_val as u16),
Some(17..=32) => PgnValue::U32(raw_val as u32),
_ => PgnValue::U64(raw_val),
}
};
Ok(Some(value))
}
FieldKind::Float => {
let raw_val = reader
.read_u64(32)
.map_err(|e| DeserializationError::BitReaderError { err: e })?;
Ok(Some(PgnValue::F32(f32::from_bits(raw_val as u32))))
}
FieldKind::Reserved | FieldKind::Spare => {
if let Some(val) = field_desc.bits_length {
reader
.advance(val as u8)
.map_err(|e| DeserializationError::BitReaderError { err: e })?;
}
Ok(None)
}
FieldKind::StringFix => {
let num_bits = field_desc
.bits_length
.ok_or(DeserializationError::InvalidDataLength)?;
let num_bytes = ((num_bits / 8) as usize).min(reader.bits_remaining() / 8);
let slice = reader
.read_slice(num_bytes)
.map_err(|e| DeserializationError::BitReaderError { err: e })?;
let mut pgn_bytes = PgnBytes {
len: num_bytes,
..Default::default()
};
pgn_bytes.data[..num_bytes].copy_from_slice(slice);
Ok(Some(PgnValue::Bytes(pgn_bytes)))
}
FieldKind::StringLz => {
let strlen = reader
.read_u8(8)
.map_err(|e| DeserializationError::BitReaderError { err: e })?
as usize;
if strlen > MAX_PGN_BYTES {
return Err(DeserializationError::InvalidDataLength);
}
let mut pgn_bytes = PgnBytes::default();
if strlen > 0 {
let slice = reader
.read_slice(strlen)
.map_err(|e| DeserializationError::BitReaderError { err: e })?;
pgn_bytes.copy_from_slice(slice);
}
pgn_bytes.len = strlen;
Ok(Some(PgnValue::Bytes(pgn_bytes)))
}
FieldKind::StringLau => {
let total_len = reader
.read_u8(8)
.map_err(|e| DeserializationError::BitReaderError { err: e })?
as usize;
if total_len > MAX_PGN_BYTES {
return Err(DeserializationError::InvalidDataLength);
}
let mut pgn_bytes = PgnBytes::default();
if total_len >= 2 {
let encoding = reader
.read_u8(8)
.map_err(|e| DeserializationError::BitReaderError { err: e })?;
pgn_bytes.data[0] = encoding;
let payload_len = total_len.saturating_sub(2);
if payload_len > 0 {
let slice = reader
.read_slice(payload_len)
.map_err(|e| DeserializationError::BitReaderError { err: e })?;
pgn_bytes.data[1..1 + payload_len].copy_from_slice(slice);
}
pgn_bytes.len = 1 + payload_len;
}
Ok(Some(PgnValue::Bytes(pgn_bytes)))
}
FieldKind::Binary => {
let num_bits =
field_desc
.bits_length
.ok_or(DeserializationError::InvalidFieldBits {
field_name: field_desc.id,
})?;
if num_bits % 8 != 0 {
let raw_val = reader
.read_u64(num_bits as u8)
.map_err(|e| DeserializationError::BitReaderError { err: e })?;
return Ok(Some(match num_bits {
1..=8 => PgnValue::U8(raw_val as u8),
9..=16 => PgnValue::U16(raw_val as u16),
17..=32 => PgnValue::U32(raw_val as u32),
_ => PgnValue::U64(raw_val),
}));
}
let num_bytes = (num_bits / 8) as usize;
let slice = reader
.read_slice(num_bytes)
.map_err(|e| DeserializationError::BitReaderError { err: e })?;
let mut pgn_bytes = PgnBytes {
len: num_bytes,
..Default::default()
};
pgn_bytes.data[..num_bytes].copy_from_slice(slice);
Ok(Some(PgnValue::Bytes(pgn_bytes)))
}
FieldKind::Date | FieldKind::Mmsi => {
let raw_val = if let Some(value) = field_desc.bits_length {
reader
.read_u64(value as u8)
.map_err(|e| DeserializationError::BitReaderError { err: e })?
} else {
return Err(DeserializationError::InvalidFieldBits {
field_name: field_desc.id,
});
};
let value = if let Some(res) = field_desc.resolution {
let scaled = raw_val as f64 * res as f64;
match field_desc.bits_length.unwrap() {
1..=24 => PgnValue::F32(scaled as f32),
_ => PgnValue::F64(scaled),
}
} else {
match field_desc.bits_length.unwrap() {
16 => PgnValue::U16(raw_val as u16),
32 => PgnValue::U32(raw_val as u32),
_ => {
return Err(DeserializationError::InvalidFieldBits {
field_name: field_desc.id,
})
}
}
};
Ok(Some(value))
}
FieldKind::Duration => {
let raw_val = if let Some(value) = field_desc.bits_length {
reader
.read_u64(value as u8)
.map_err(|e| DeserializationError::BitReaderError { err: e })?
} else {
return Err(DeserializationError::InvalidFieldBits {
field_name: field_desc.id,
});
};
let value = if let Some(res) = field_desc.resolution {
let scaled = raw_val as f64 * res as f64;
match field_desc.bits_length.unwrap() {
1..=24 => PgnValue::F32(scaled as f32),
_ => PgnValue::F64(scaled),
}
} else {
match field_desc.bits_length.unwrap() {
1..=16 => PgnValue::U16(raw_val as u16),
17..=32 => PgnValue::U32(raw_val as u32),
_ => PgnValue::U64(raw_val),
}
};
Ok(Some(value))
}
FieldKind::Time => {
let raw_val = if let Some(value) = field_desc.bits_length {
reader
.read_u64(value as u8)
.map_err(|e| DeserializationError::BitReaderError { err: e })?
} else {
return Err(DeserializationError::InvalidFieldBits {
field_name: field_desc.id,
});
};
let value = if let Some(res) = field_desc.resolution {
let scaled = raw_val as f64 * res as f64;
PgnValue::F64(scaled)
} else {
PgnValue::U64(raw_val)
};
Ok(Some(value))
}
_ => Err(DeserializationError::UnsupportedFieldKind {
field_kind: field_desc.kind,
}),
}
}
fn write_field(
writer: &mut BitWriter,
field_desc: &'static FieldDescriptor,
value: &PgnValue,
) -> Result<(), SerializationError> {
match field_desc.kind {
FieldKind::Number | FieldKind::Pgn | FieldKind::IsoName => {
let bits_to_write = if field_desc.is_signed.is_some_and(|s| s) {
let prepared_val = if let Some(res) = field_desc.resolution {
let float_val = pgn_value_to_f64(value)
.map_err(|e| SerializationError::CodecError { source: e })?;
scale_to_i64(float_val, res)
} else {
pgn_value_to_i64(value)
.map_err(|e| SerializationError::CodecError { source: e })?
};
i64_to_u64_bitwise(prepared_val)
} else if let Some(res) = field_desc.resolution {
let float_val = pgn_value_to_f64(value)
.map_err(|e| SerializationError::CodecError { source: e })?;
i64_to_u64_bitwise(scale_to_i64(float_val, res))
} else {
pgn_value_to_u64(value).map_err(|e| SerializationError::CodecError { source: e })?
};
if let Some(bit_length) = field_desc.bits_length {
writer
.write_u64(bits_to_write, bit_length as u8)
.map_err(|e| SerializationError::BitWriteError { err: e })?;
} else {
return Err(SerializationError::InvalidData);
};
}
FieldKind::Date | FieldKind::Time | FieldKind::Mmsi => {
let bits_to_write =
field_desc
.bits_length
.ok_or(SerializationError::InvalidFieldBits {
field_name: field_desc.id,
})?;
let int_val = if field_desc.resolution.is_some_and(|res| res as u8 != 1) {
let float_val = pgn_value_to_f64(value)
.map_err(|e| SerializationError::CodecError { source: e })?;
scale_to_i64(float_val, field_desc.resolution.unwrap()) as u64 } else {
pgn_value_to_u64(value).map_err(|e| SerializationError::CodecError { source: e })?
};
writer
.write_u64(int_val, bits_to_write as u8)
.map_err(|e| SerializationError::BitWriteError { err: e })?;
}
FieldKind::Duration => {
let bits_to_write =
field_desc
.bits_length
.ok_or(SerializationError::InvalidFieldBits {
field_name: field_desc.id,
})?;
let prepared_val = if let Some(res) = field_desc.resolution {
let float_val = pgn_value_to_f64(value)
.map_err(|e| SerializationError::CodecError { source: e })?;
scale_to_i64(float_val, res) as u64
} else {
pgn_value_to_u64(value).map_err(|e| SerializationError::CodecError { source: e })?
};
writer
.write_u64(prepared_val, bits_to_write as u8)
.map_err(|e| SerializationError::BitWriteError { err: e })?;
}
FieldKind::Lookup => {
let int_val = pgn_value_to_u64(value)
.map_err(|e| SerializationError::CodecError { source: e })?;
if let Some(bit_len) = field_desc.bits_length {
writer
.write_u64(int_val, bit_len as u8)
.map_err(|e| SerializationError::BitWriteError { err: e })?;
};
}
FieldKind::BitLookup => {
let int_val = pgn_value_to_u64(value)
.map_err(|e| SerializationError::CodecError { source: e })?;
let bit_len = field_desc
.bits_length
.ok_or(SerializationError::InvalidFieldBits {
field_name: field_desc.id,
})?;
writer
.write_u64(int_val, bit_len as u8)
.map_err(|e| SerializationError::BitWriteError { err: e })?;
}
FieldKind::IndirectLookup => {
let combined_value = pgn_value_to_u64(value)
.map_err(|e| SerializationError::CodecError { source: e })?
as u16;
let value_to_write = (combined_value & 0x00FF) as u64;
if let Some(bit_len) = field_desc.bits_length {
writer
.write_u64(value_to_write, bit_len as u8)
.map_err(|e| SerializationError::BitWriteError { err: e })?;
};
}
FieldKind::Spare => {
if let Some(bit_len) = field_desc.bits_length {
writer
.write_u64(0, bit_len as u8)
.map_err(|e| SerializationError::BitWriteError { err: e })?;
}
}
FieldKind::Float => {
let val = pgn_value_to_f64(value)
.map_err(|e| SerializationError::CodecError { source: e })?;
writer
.write_u64((val as f32).to_bits() as u64, 32)
.map_err(|e| SerializationError::BitWriteError { err: e })?;
}
FieldKind::Reserved => {
if let Some(bit_len) = field_desc.bits_length {
writer
.advance(bit_len as u8)
.map_err(|e| SerializationError::BitWriteError { err: e })?
}
}
FieldKind::StringFix => {
if let PgnValue::Bytes(val) = value {
writer
.write_slice(&val.data[..val.len])
.map_err(|e| SerializationError::BitWriteError { err: e })?;
} else {
return Err(SerializationError::CodecError {
source: CodecError::DataTypeMismatch {
value_kind: value.kind(),
func: "write_field // StringFix",
},
});
}
}
FieldKind::StringLz => {
if let PgnValue::Bytes(val) = value {
if val.len > u8::MAX as usize {
return Err(SerializationError::InvalidData);
}
writer
.write_u64(val.len as u64, 8)
.map_err(|e| SerializationError::BitWriteError { err: e })?;
if val.len > 0 {
writer
.write_slice(&val.data[..val.len])
.map_err(|e| SerializationError::BitWriteError { err: e })?;
}
} else {
return Err(SerializationError::CodecError {
source: CodecError::DataTypeMismatch {
value_kind: value.kind(),
func: "write_field // StringLz",
},
});
}
}
FieldKind::StringLau => {
if let PgnValue::Bytes(val) = value {
let declared = if val.len == 0 { 0 } else { val.len + 1 };
if declared > u8::MAX as usize {
return Err(SerializationError::InvalidData);
}
writer
.write_u64(declared as u64, 8)
.map_err(|e| SerializationError::BitWriteError { err: e })?;
if val.len > 0 {
writer
.write_u64(val.data[0] as u64, 8)
.map_err(|e| SerializationError::BitWriteError { err: e })?;
if val.len > 1 {
writer
.write_slice(&val.data[1..val.len])
.map_err(|e| SerializationError::BitWriteError { err: e })?;
}
}
} else {
return Err(SerializationError::CodecError {
source: CodecError::DataTypeMismatch {
value_kind: value.kind(),
func: "write_field // StringLau",
},
});
}
}
FieldKind::Binary => {
let expected_bits =
field_desc
.bits_length
.ok_or(SerializationError::InvalidFieldBits {
field_name: field_desc.id,
})?;
if expected_bits % 8 != 0 {
let raw_val = pgn_value_to_u64(value)
.map_err(|e| SerializationError::CodecError { source: e })?;
return writer
.write_u64(raw_val, expected_bits as u8)
.map_err(|e| SerializationError::BitWriteError { err: e });
}
if let PgnValue::Bytes(val) = value {
let expected_len = (expected_bits / 8) as usize;
if val.len != expected_len {
return Err(SerializationError::InvalidData);
}
writer
.write_slice(&val.data[..expected_len])
.map_err(|e| SerializationError::BitWriteError { err: e })?;
} else {
return Err(SerializationError::CodecError {
source: CodecError::DataTypeMismatch {
value_kind: value.kind(),
func: "write_field // Binary",
},
});
}
}
_ => return Err(SerializationError::UnsupportedFieldKind),
}
Ok(())
}
fn scale_to_i64(value: f64, resolution: f32) -> i64 {
let scaled = value / resolution as f64;
if scaled >= 0.0 {
(scaled + 0.5) as i64
} else {
(scaled - 0.5) as i64
}
}
fn pgn_value_to_f64(value: &PgnValue) -> Result<f64, CodecError> {
match value {
PgnValue::F64(v) => Ok(*v),
PgnValue::F32(v) => Ok(*v as f64),
PgnValue::I64(v) => Ok(*v as f64),
PgnValue::I32(v) => Ok(*v as f64),
PgnValue::I16(v) => Ok(*v as f64),
PgnValue::I8(v) => Ok(*v as f64),
_ => Err(CodecError::DataTypeMismatch {
value_kind: value.kind(),
func: "pgn_value_to_f64",
}),
}
}
fn pgn_value_to_i64(value: &PgnValue) -> Result<i64, CodecError> {
match value {
PgnValue::I64(v) => Ok(*v),
PgnValue::I32(v) => Ok(*v as i64),
PgnValue::I16(v) => Ok(*v as i64),
PgnValue::I8(v) => Ok(*v as i64),
_ => Err(CodecError::DataTypeMismatch {
value_kind: value.kind(),
func: "pgn_value_to_i64",
}),
}
}
fn pgn_value_to_u64(value: &PgnValue) -> Result<u64, CodecError> {
match value {
PgnValue::U64(v) => Ok(*v),
PgnValue::U32(v) => Ok(*v as u64),
PgnValue::U16(v) => Ok(*v as u64),
PgnValue::U8(v) => Ok(*v as u64),
_ => Err(CodecError::DataTypeMismatch {
value_kind: value.kind(),
func: "pgn_value_to_u64",
}),
}
}
fn sign_extend(value: u64, bits: u8) -> i64 {
if bits >= 64 {
return value as i64;
}
let sign_bit_mask = 1u64 << (bits - 1);
if (value & sign_bit_mask) != 0 {
let extension_mask = u64::MAX << bits;
(value | extension_mask) as i64
} else {
value as i64
}
}
#[inline] fn i64_to_u64_bitwise(value: i64) -> u64 {
value as u64
}
#[cfg(test)]
#[path = "tests.rs"]
mod tests;