mod builtin;
mod io;
use alloc::string::String;
use alloc::vec::Vec;
pub(crate) use builtin::{builtin_type_from_value, decode_builtin_value};
pub use io::{UaReader, UaWriter};
use crate::error::{DecodeError, EncodeError};
pub trait UaEncode {
fn encode(&self, w: &mut UaWriter) -> Result<(), EncodeError>;
}
pub trait UaDecode: Sized {
fn decode(r: &mut UaReader<'_>) -> Result<Self, DecodeError>;
}
pub(crate) fn len_i32(what: &'static str, len: usize) -> Result<i32, EncodeError> {
i32::try_from(len).map_err(|_| EncodeError::LengthOverflow { what, len })
}
pub(crate) fn len_u16(what: &'static str, len: usize) -> Result<u16, EncodeError> {
u16::try_from(len).map_err(|_| EncodeError::LengthOverflow { what, len })
}
pub(crate) fn write_string(w: &mut UaWriter, s: &str) -> Result<(), EncodeError> {
w.write_i32(len_i32("String", s.len())?);
w.write_bytes(s.as_bytes());
Ok(())
}
pub(crate) fn write_byte_string(w: &mut UaWriter, b: &[u8]) -> Result<(), EncodeError> {
w.write_i32(len_i32("ByteString", b.len())?);
w.write_bytes(b);
Ok(())
}
pub(crate) fn read_string(r: &mut UaReader<'_>) -> Result<String, DecodeError> {
Ok(read_opt_string(r)?.unwrap_or_default())
}
pub(crate) fn read_opt_string(r: &mut UaReader<'_>) -> Result<Option<String>, DecodeError> {
let len = r.read_i32()?;
if len < 0 {
return Ok(None);
}
let bytes = r.read_bytes(len as usize)?;
let s = core::str::from_utf8(bytes).map_err(|_| DecodeError::InvalidUtf8)?;
Ok(Some(String::from(s)))
}
pub(crate) fn read_byte_string(r: &mut UaReader<'_>) -> Result<Vec<u8>, DecodeError> {
let len = r.read_i32()?;
if len < 0 {
return Ok(Vec::new());
}
Ok(r.read_bytes(len as usize)?.to_vec())
}
pub(crate) fn write_array<T: UaEncode>(
w: &mut UaWriter,
items: &[T],
what: &'static str,
) -> Result<(), EncodeError> {
w.write_i32(len_i32(what, items.len())?);
for it in items {
it.encode(w)?;
}
Ok(())
}
pub(crate) fn read_array<T: UaDecode>(r: &mut UaReader<'_>) -> Result<Vec<T>, DecodeError> {
let len = r.read_i32()?;
if len < 0 {
return Ok(Vec::new());
}
let mut out = Vec::with_capacity(len as usize);
for _ in 0..len {
out.push(T::decode(r)?);
}
Ok(out)
}
pub(crate) fn write_u16_array(w: &mut UaWriter, items: &[u16]) -> Result<(), EncodeError> {
w.write_i32(len_i32("UInt16 array", items.len())?);
for x in items {
w.write_u16(*x);
}
Ok(())
}
pub(crate) fn read_u16_array(r: &mut UaReader<'_>) -> Result<Vec<u16>, DecodeError> {
let len = r.read_i32()?;
if len < 0 {
return Ok(Vec::new());
}
let mut out = Vec::with_capacity(len as usize);
for _ in 0..len {
out.push(r.read_u16()?);
}
Ok(out)
}
pub(crate) fn write_u32_array(w: &mut UaWriter, items: &[u32]) -> Result<(), EncodeError> {
w.write_i32(len_i32("UInt32 array", items.len())?);
for x in items {
w.write_u32(*x);
}
Ok(())
}
pub(crate) fn read_u32_array(r: &mut UaReader<'_>) -> Result<Vec<u32>, DecodeError> {
let len = r.read_i32()?;
if len < 0 {
return Ok(Vec::new());
}
let mut out = Vec::with_capacity(len as usize);
for _ in 0..len {
out.push(r.read_u32()?);
}
Ok(out)
}
pub(crate) fn write_string_array(w: &mut UaWriter, items: &[String]) -> Result<(), EncodeError> {
w.write_i32(len_i32("String array", items.len())?);
for s in items {
write_string(w, s)?;
}
Ok(())
}
pub(crate) fn read_string_array(r: &mut UaReader<'_>) -> Result<Vec<String>, DecodeError> {
let len = r.read_i32()?;
if len < 0 {
return Ok(Vec::new());
}
let mut out = Vec::with_capacity(len as usize);
for _ in 0..len {
out.push(read_string(r)?);
}
Ok(out)
}
pub fn to_binary<T: UaEncode>(value: &T) -> Result<Vec<u8>, EncodeError> {
let mut w = UaWriter::new();
value.encode(&mut w)?;
Ok(w.into_vec())
}
pub fn from_binary<T: UaDecode>(bytes: &[u8]) -> Result<T, DecodeError> {
let mut r = UaReader::new(bytes);
T::decode(&mut r)
}