use core::fmt;
use core::fmt::Display;
use core::marker::PhantomData;
use core::result::Result;
use core::result::Result::{Err, Ok};
#[cfg(feature = "std")]
use std::error;
use crate::phys::{
BinaryDecodeError, BinaryDecoder, EndianOrder, GetValueFromBinaryDecoder, XdrDecoder,
};
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[repr(u8)]
pub enum NvEndianOrder {
Big = 0,
Little = 1,
}
impl From<NvEndianOrder> for EndianOrder {
fn from(val: NvEndianOrder) -> EndianOrder {
match val {
NvEndianOrder::Big => EndianOrder::Big,
NvEndianOrder::Little => EndianOrder::Little,
}
}
}
impl Display for NvEndianOrder {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
NvEndianOrder::Big => write!(f, "Big"),
NvEndianOrder::Little => write!(f, "Little"),
}
}
}
impl From<NvEndianOrder> for u8 {
fn from(val: NvEndianOrder) -> u8 {
val as u8
}
}
impl TryFrom<u8> for NvEndianOrder {
type Error = NvDecodeError;
fn try_from(order: u8) -> Result<Self, Self::Error> {
match order {
0 => Ok(NvEndianOrder::Big),
1 => Ok(NvEndianOrder::Little),
_ => Err(NvDecodeError::UnknownEndian { order }),
}
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[repr(u8)]
pub enum NvEncoding {
Native = 0,
Xdr = 1,
}
impl Display for NvEncoding {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
NvEncoding::Native => write!(f, "Native"),
NvEncoding::Xdr => write!(f, "Xdr"),
}
}
}
impl From<NvEncoding> for u8 {
fn from(val: NvEncoding) -> u8 {
val as u8
}
}
impl TryFrom<u8> for NvEncoding {
type Error = NvDecodeError;
fn try_from(encoding: u8) -> Result<Self, Self::Error> {
match encoding {
0 => Ok(NvEncoding::Native),
1 => Ok(NvEncoding::Xdr),
_ => Err(NvDecodeError::UnknownEncoding { encoding }),
}
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[repr(u8)]
pub enum NvUnique {
None = 0,
Name = 1,
NameType = 2,
}
impl Display for NvUnique {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
NvUnique::None => write!(f, "None"),
NvUnique::Name => write!(f, "Name"),
NvUnique::NameType => write!(f, "NameType"),
}
}
}
impl From<NvUnique> for u8 {
fn from(val: NvUnique) -> u8 {
val as u8
}
}
impl TryFrom<u8> for NvUnique {
type Error = NvDecodeError;
fn try_from(unique: u8) -> Result<Self, Self::Error> {
match unique {
0 => Ok(NvUnique::None),
1 => Ok(NvUnique::Name),
2 => Ok(NvUnique::NameType),
_ => Err(NvDecodeError::UnknownUnique { unique }),
}
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[repr(u32)]
pub enum NvDataType {
Boolean = 1,
Byte = 2,
Int16 = 3,
Uint16 = 4,
Int32 = 5,
Uint32 = 6,
Int64 = 7,
Uint64 = 8,
String = 9,
ByteArray = 10,
Int16Array = 11,
Uint16Array = 12,
Int32Array = 13,
Uint32Array = 14,
Int64Array = 15,
Uint64Array = 16,
StringArray = 17,
HrTime = 18,
NvList = 19,
NvListArray = 20,
BooleanValue = 21,
Int8 = 22,
Uint8 = 23,
BooleanArray = 24,
Int8Array = 25,
Uint8Array = 26,
Double = 27,
}
impl Display for NvDataType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
NvDataType::Boolean => write!(f, "Boolean"),
NvDataType::Byte => write!(f, "Byte"),
NvDataType::Int16 => write!(f, "Int16"),
NvDataType::Uint16 => write!(f, "Uint16"),
NvDataType::Int32 => write!(f, "Int32"),
NvDataType::Uint32 => write!(f, "Uint32"),
NvDataType::Int64 => write!(f, "Int64"),
NvDataType::Uint64 => write!(f, "Uint64"),
NvDataType::String => write!(f, "String"),
NvDataType::ByteArray => write!(f, "ByteArray"),
NvDataType::Int16Array => write!(f, "Int16Array"),
NvDataType::Uint16Array => write!(f, "Uint16Array"),
NvDataType::Int32Array => write!(f, "Int32Array"),
NvDataType::Uint32Array => write!(f, "Uint32Array"),
NvDataType::Int64Array => write!(f, "Int64Array"),
NvDataType::Uint64Array => write!(f, "Uint64Array"),
NvDataType::StringArray => write!(f, "StringArray"),
NvDataType::HrTime => write!(f, "HrTime"),
NvDataType::NvList => write!(f, "NvList"),
NvDataType::NvListArray => write!(f, "NvListArray"),
NvDataType::BooleanValue => write!(f, "BooleanValue"),
NvDataType::Int8 => write!(f, "Int8"),
NvDataType::Uint8 => write!(f, "Uint8"),
NvDataType::BooleanArray => write!(f, "BooleanArray"),
NvDataType::Int8Array => write!(f, "Int8Array"),
NvDataType::Uint8Array => write!(f, "Uint8Array"),
NvDataType::Double => write!(f, "Double"),
}
}
}
impl From<NvDataType> for u32 {
fn from(val: NvDataType) -> u32 {
val as u32
}
}
impl TryFrom<u32> for NvDataType {
type Error = NvDecodeError;
fn try_from(data_type: u32) -> Result<Self, Self::Error> {
match data_type {
1 => Ok(NvDataType::Boolean),
2 => Ok(NvDataType::Byte),
3 => Ok(NvDataType::Int16),
4 => Ok(NvDataType::Uint16),
5 => Ok(NvDataType::Int32),
6 => Ok(NvDataType::Uint32),
7 => Ok(NvDataType::Int64),
8 => Ok(NvDataType::Uint64),
9 => Ok(NvDataType::String),
10 => Ok(NvDataType::ByteArray),
11 => Ok(NvDataType::Int16Array),
12 => Ok(NvDataType::Uint16Array),
13 => Ok(NvDataType::Int32Array),
14 => Ok(NvDataType::Uint32Array),
15 => Ok(NvDataType::Int64Array),
16 => Ok(NvDataType::Uint64Array),
17 => Ok(NvDataType::StringArray),
18 => Ok(NvDataType::HrTime),
19 => Ok(NvDataType::NvList),
20 => Ok(NvDataType::NvListArray),
21 => Ok(NvDataType::BooleanValue),
22 => Ok(NvDataType::Int8),
23 => Ok(NvDataType::Uint8),
24 => Ok(NvDataType::BooleanArray),
25 => Ok(NvDataType::Int8Array),
26 => Ok(NvDataType::Uint8Array),
27 => Ok(NvDataType::Double),
_ => Err(NvDecodeError::UnknownDataType { data_type }),
}
}
}
fn check_data_type_count_and_get_array_size(
data_type: NvDataType,
count: usize,
) -> Result<usize, NvDecodeError> {
let array_element_size = match data_type {
NvDataType::Boolean => match count {
0 => 0,
_ => return Err(NvDecodeError::InvalidCount { data_type, count }),
},
NvDataType::Byte
| NvDataType::Int16
| NvDataType::Uint16
| NvDataType::Int32
| NvDataType::Uint32
| NvDataType::Int64
| NvDataType::Uint64
| NvDataType::String
| NvDataType::HrTime
| NvDataType::NvList
| NvDataType::BooleanValue
| NvDataType::Int8
| NvDataType::Uint8
| NvDataType::Double => match count {
1 => 0,
_ => return Err(NvDecodeError::InvalidCount { data_type, count }),
},
NvDataType::BooleanArray
| NvDataType::Int16Array
| NvDataType::Uint16Array
| NvDataType::Int32Array
| NvDataType::Uint32Array
| NvDataType::Int8Array
| NvDataType::Uint8Array => 4,
NvDataType::Int64Array | NvDataType::Uint64Array => 8,
NvDataType::ByteArray | NvDataType::StringArray | NvDataType::NvListArray => 0,
};
match count.checked_mul(array_element_size) {
Some(v) => Ok(v),
None => Err(NvDecodeError::InvalidCount { data_type, count }),
}
}
#[derive(Clone, Copy, Debug)]
pub enum NvDataValue<'a> {
Boolean(),
Byte(u8),
Int16(i16),
Uint16(u16),
Int32(i32),
Uint32(u32),
Int64(i64),
Uint64(u64),
String(&'a str),
ByteArray(&'a [u8]),
Int16Array(NvArray<'a, i16>),
Uint16Array(NvArray<'a, u16>),
Int32Array(NvArray<'a, i32>),
Uint32Array(NvArray<'a, u32>),
Int64Array(NvArray<'a, i64>),
Uint64Array(NvArray<'a, u64>),
StringArray(NvArray<'a, &'a str>),
HrTime(i64),
NvList(NvList<'a>),
NvListArray(NvArray<'a, NvList<'a>>),
BooleanValue(bool),
Int8(i8),
Uint8(u8),
BooleanArray(NvArray<'a, bool>),
Int8Array(NvArray<'a, i8>),
Uint8Array(NvArray<'a, u8>),
Double(f64),
}
#[derive(Clone, Copy, Debug)]
pub struct NvList<'a> {
data: &'a [u8],
offset: usize,
length: usize,
encoding: NvEncoding,
order: EndianOrder,
unique: NvUnique,
}
impl<'a> NvList<'a> {
pub fn iter<'b>(&'b self) -> NvListIterator<'a, 'b> {
let (decoder, clamp_err) =
match XdrDecoder::from_bytes_clamped(self.data, self.offset, self.length) {
Ok(decoder) => (decoder, None),
Err(err) => {
(XdrDecoder::from_bytes(self.data), Some(err))
}
};
NvListIterator {
list: self,
decoder,
clamp_err,
}
}
}
#[derive(Debug)]
pub struct NvListIterator<'a, 'b> {
list: &'b NvList<'a>,
decoder: XdrDecoder<'a>,
clamp_err: Option<BinaryDecodeError>,
}
impl<'a> NvListIterator<'a, '_> {
fn next_pair_result(&mut self) -> Result<Option<NvPair<'a, 'a>>, NvDecodeError> {
if self.decoder.is_empty() {
return Ok(None);
}
let starting_offset = self.decoder.offset();
let encoded_size = self.decoder.get_usize_32()?;
let decoded_size = self.decoder.get_usize_32()?;
if encoded_size == 0 && decoded_size == 0 {
return Ok(None);
}
let name = self.decoder.get_str()?;
let data_type = self.decoder.get_u32()?;
let data_type = NvDataType::try_from(data_type)?;
let element_count = self.decoder.get_usize_32()?;
let value_offset = self.decoder.offset();
let bytes_used = value_offset - starting_offset;
let bytes_rem = match encoded_size.checked_sub(bytes_used) {
Some(v) => v,
None => {
return Err(NvDecodeError::InvalidEncodedSize {
encoded_size,
used: bytes_used,
});
}
};
let array_value_size = check_data_type_count_and_get_array_size(data_type, element_count)?;
let value = match data_type {
NvDataType::Boolean => NvDataValue::Boolean(),
NvDataType::Byte => NvDataValue::Byte(self.decoder.get_u8()?),
NvDataType::Int16 => NvDataValue::Int16(self.decoder.get_i16()?),
NvDataType::Uint16 => NvDataValue::Uint16(self.decoder.get_u16()?),
NvDataType::Int32 => NvDataValue::Int32(self.decoder.get_i32()?),
NvDataType::Uint32 => NvDataValue::Uint32(self.decoder.get_u32()?),
NvDataType::Int64 => NvDataValue::Int64(self.decoder.get_i64()?),
NvDataType::Uint64 => NvDataValue::Uint64(self.decoder.get_u64()?),
NvDataType::String => NvDataValue::String(self.decoder.get_str()?),
NvDataType::ByteArray => NvDataValue::ByteArray(self.decoder.get_bytes()?),
NvDataType::Int16Array => NvDataValue::Int16Array({
self.decoder.skip(array_value_size)?;
NvArray {
data: self.list.data,
offset: value_offset,
length: array_value_size,
count: element_count,
order: self.list.order,
encoding: self.list.encoding,
phantom: PhantomData,
}
}),
NvDataType::Uint16Array => NvDataValue::Uint16Array({
self.decoder.skip(array_value_size)?;
NvArray {
data: self.list.data,
offset: value_offset,
length: array_value_size,
count: element_count,
order: self.list.order,
encoding: self.list.encoding,
phantom: PhantomData,
}
}),
NvDataType::Int32Array => NvDataValue::Int32Array({
self.decoder.skip(array_value_size)?;
NvArray {
data: self.list.data,
offset: value_offset,
length: array_value_size,
count: element_count,
order: self.list.order,
encoding: self.list.encoding,
phantom: PhantomData,
}
}),
NvDataType::Uint32Array => NvDataValue::Uint32Array({
self.decoder.skip(array_value_size)?;
NvArray {
data: self.list.data,
offset: value_offset,
length: array_value_size,
count: element_count,
order: self.list.order,
encoding: self.list.encoding,
phantom: PhantomData,
}
}),
NvDataType::Int64Array => NvDataValue::Int64Array({
self.decoder.skip(array_value_size)?;
NvArray {
data: self.list.data,
offset: value_offset,
length: array_value_size,
count: element_count,
order: self.list.order,
encoding: self.list.encoding,
phantom: PhantomData,
}
}),
NvDataType::Uint64Array => NvDataValue::Uint64Array({
self.decoder.skip(array_value_size)?;
NvArray {
data: self.list.data,
offset: value_offset,
length: array_value_size,
count: element_count,
order: self.list.order,
encoding: self.list.encoding,
phantom: PhantomData,
}
}),
NvDataType::StringArray => NvDataValue::StringArray({
self.decoder.skip(bytes_rem)?;
NvArray {
data: self.list.data,
offset: value_offset,
length: bytes_rem,
count: element_count,
order: self.list.order,
encoding: self.list.encoding,
phantom: PhantomData,
}
}),
NvDataType::HrTime => NvDataValue::HrTime(self.decoder.get_i64()?),
NvDataType::NvList => NvDataValue::NvList({
self.decoder.skip(bytes_rem)?;
NvList::from_partial(
self.list.data,
value_offset,
bytes_rem,
self.list.encoding,
self.list.order,
)?
}),
NvDataType::NvListArray => NvDataValue::NvListArray({
self.decoder.skip(bytes_rem)?;
NvArray {
data: self.list.data,
offset: value_offset,
length: bytes_rem,
count: element_count,
order: self.list.order,
encoding: self.list.encoding,
phantom: PhantomData,
}
}),
NvDataType::BooleanValue => NvDataValue::BooleanValue(self.decoder.get_bool()?),
NvDataType::Int8 => NvDataValue::Int8(self.decoder.get_i8()?),
NvDataType::Uint8 => NvDataValue::Uint8(self.decoder.get_u8()?),
NvDataType::BooleanArray => NvDataValue::BooleanArray({
self.decoder.skip(array_value_size)?;
NvArray {
data: self.list.data,
offset: value_offset,
length: array_value_size,
count: element_count,
order: self.list.order,
encoding: self.list.encoding,
phantom: PhantomData,
}
}),
NvDataType::Int8Array => NvDataValue::Int8Array({
self.decoder.skip(array_value_size)?;
NvArray {
data: self.list.data,
offset: value_offset,
length: array_value_size,
count: element_count,
order: self.list.order,
encoding: self.list.encoding,
phantom: PhantomData,
}
}),
NvDataType::Uint8Array => NvDataValue::Uint8Array({
self.decoder.skip(array_value_size)?;
NvArray {
data: self.list.data,
offset: value_offset,
length: array_value_size,
count: element_count,
order: self.list.order,
encoding: self.list.encoding,
phantom: PhantomData,
}
}),
NvDataType::Double => NvDataValue::Double(self.decoder.get_f64()?),
};
let bytes_used = self.decoder.offset() - starting_offset;
let bytes_rem = match encoded_size.checked_sub(bytes_used) {
Some(v) => v,
None => {
return Err(NvDecodeError::InvalidEncodedSize {
encoded_size,
used: bytes_used,
});
}
};
if bytes_rem > 0 {
return Err(NvDecodeError::InvalidEncodedSize {
encoded_size,
used: bytes_used,
});
}
Ok(Some(NvPair { name, value }))
}
}
impl NvListIterator<'_, '_> {
pub fn reset(&mut self) {
self.decoder.reset()
}
}
impl<'a> Iterator for NvListIterator<'a, '_> {
type Item = Result<NvPair<'a, 'a>, NvDecodeError>;
fn next(&mut self) -> Option<<Self as Iterator>::Item> {
if let Some(err) = self.clamp_err {
let _ = self.decoder.skip(self.decoder.len());
return Some(Err(NvDecodeError::BinaryDecoder { err }));
}
match self.next_pair_result() {
Ok(v) => v.map(Ok),
Err(err) => Some(Err(err)),
}
}
}
impl<'a, 'b> IntoIterator for &'b NvList<'a> {
type Item = Result<NvPair<'a, 'a>, NvDecodeError>;
type IntoIter = NvListIterator<'a, 'b>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
#[derive(Clone, Copy, Debug)]
pub struct NvArray<'a, T> {
data: &'a [u8],
offset: usize,
length: usize,
count: usize,
encoding: NvEncoding,
order: EndianOrder,
phantom: PhantomData<T>,
}
impl<'a, T> NvArray<'a, T> {
pub fn iter<'b>(&'b self) -> NvArrayIterator<'a, 'b, T> {
let (decoder, clamp_err) =
match XdrDecoder::from_bytes_clamped(self.data, self.offset, self.length) {
Ok(decoder) => (decoder, None),
Err(err) => {
(XdrDecoder::from_bytes(self.data), Some(err))
}
};
NvArrayIterator::<T> {
array: self,
decoder,
index: 0,
phantom: PhantomData,
clamp_err,
}
}
}
impl<T> NvArray<'_, T> {
pub fn is_empty(&self) -> bool {
self.count == 0
}
pub fn len(&self) -> usize {
self.count
}
}
impl<'a, 'b, T: GetValueFromBinaryDecoder<'a>> IntoIterator for &'b NvArray<'a, T> {
type Item = Result<T, NvDecodeError>;
type IntoIter = NvArrayIterator<'a, 'b, T>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl<'a, 'b> IntoIterator for &'b NvArray<'a, NvList<'a>> {
type Item = Result<NvList<'a>, NvDecodeError>;
type IntoIter = NvArrayIterator<'a, 'b, NvList<'a>>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
#[derive(Debug)]
pub struct NvArrayIterator<'a, 'b, T> {
array: &'b NvArray<'a, T>,
decoder: XdrDecoder<'a>,
index: usize,
phantom: PhantomData<T>,
clamp_err: Option<BinaryDecodeError>,
}
impl<T> NvArrayIterator<'_, '_, T> {
pub fn reset(&mut self) {
self.index = 0;
}
}
impl<'a, T: GetValueFromBinaryDecoder<'a>> Iterator for NvArrayIterator<'a, '_, T> {
type Item = Result<T, NvDecodeError>;
fn next(&mut self) -> Option<<Self as Iterator>::Item> {
if self.index < self.array.count {
if let Some(err) = self.clamp_err {
self.index = self.array.count;
return Some(Err(NvDecodeError::BinaryDecoder { err }));
}
self.index += 1;
match self.decoder.get() {
Ok(v) => Some(Ok(v)),
Err(err) => Some(Err(NvDecodeError::BinaryDecoder { err })),
}
} else {
None
}
}
}
impl<'a> Iterator for NvArrayIterator<'a, '_, NvList<'a>> {
type Item = Result<NvList<'a>, NvDecodeError>;
fn next(&mut self) -> Option<<Self as Iterator>::Item> {
if self.index < self.array.count {
if let Some(err) = self.clamp_err {
self.index = self.array.count;
return Some(Err(NvDecodeError::BinaryDecoder { err }));
}
self.index += 1;
let starting_offset = self.decoder.offset();
let list = match NvList::from_partial(
self.decoder.data(),
self.decoder.offset(),
self.decoder.len(),
self.array.encoding,
self.array.order,
) {
Ok(list) => list,
Err(err) => return Some(Err(err)),
};
let mut iter = list.iter();
for pair_res in iter.by_ref() {
if let Err(err) = pair_res {
return Some(Err(err));
}
}
let bytes_used = iter.decoder.offset() - starting_offset;
if let Err(err) = self.decoder.skip(bytes_used) {
return Some(Err(NvDecodeError::BinaryDecoder { err }));
}
Some(NvList::from_partial(
self.decoder.data(),
starting_offset,
bytes_used,
self.array.encoding,
self.array.order,
))
} else {
None
}
}
}
#[derive(Debug)]
pub struct NvPair<'a, 'b> {
pub name: &'b str,
pub value: NvDataValue<'a>,
}
impl<'a> NvPair<'a, '_> {
pub fn get_bool_array(&self) -> Result<NvArray<'a, bool>, NvDecodeError> {
match self.value {
NvDataValue::BooleanArray(v) => Ok(v),
_ => Err(NvDecodeError::DataTypeMismatch {
expected: NvDataType::BooleanArray,
actual: self.data_type(),
}),
}
}
pub fn get_byte_array(&self) -> Result<&'a [u8], NvDecodeError> {
match self.value {
NvDataValue::ByteArray(v) => Ok(v),
_ => Err(NvDecodeError::DataTypeMismatch {
expected: NvDataType::ByteArray,
actual: self.data_type(),
}),
}
}
pub fn get_i8_array(&self) -> Result<NvArray<'a, i8>, NvDecodeError> {
match self.value {
NvDataValue::Int8Array(v) => Ok(v),
_ => Err(NvDecodeError::DataTypeMismatch {
expected: NvDataType::Int8Array,
actual: self.data_type(),
}),
}
}
pub fn get_i16_array(&self) -> Result<NvArray<'a, i16>, NvDecodeError> {
match self.value {
NvDataValue::Int16Array(v) => Ok(v),
_ => Err(NvDecodeError::DataTypeMismatch {
expected: NvDataType::Int16Array,
actual: self.data_type(),
}),
}
}
pub fn get_i32_array(&self) -> Result<NvArray<'a, i32>, NvDecodeError> {
match self.value {
NvDataValue::Int32Array(v) => Ok(v),
_ => Err(NvDecodeError::DataTypeMismatch {
expected: NvDataType::Int32Array,
actual: self.data_type(),
}),
}
}
pub fn get_i64_array(&self) -> Result<NvArray<'a, i64>, NvDecodeError> {
match self.value {
NvDataValue::Int64Array(v) => Ok(v),
_ => Err(NvDecodeError::DataTypeMismatch {
expected: NvDataType::Int64Array,
actual: self.data_type(),
}),
}
}
pub fn get_nv_list(&self) -> Result<NvList<'a>, NvDecodeError> {
match self.value {
NvDataValue::NvList(v) => Ok(v),
_ => Err(NvDecodeError::DataTypeMismatch {
expected: NvDataType::NvList,
actual: self.data_type(),
}),
}
}
pub fn get_nv_list_array(&self) -> Result<NvArray<'a, NvList<'a>>, NvDecodeError> {
match self.value {
NvDataValue::NvListArray(v) => Ok(v),
_ => Err(NvDecodeError::DataTypeMismatch {
expected: NvDataType::NvListArray,
actual: self.data_type(),
}),
}
}
pub fn get_str(&self) -> Result<&'a str, NvDecodeError> {
match self.value {
NvDataValue::String(v) => Ok(v),
_ => Err(NvDecodeError::DataTypeMismatch {
expected: NvDataType::String,
actual: self.data_type(),
}),
}
}
pub fn get_str_array(&self) -> Result<NvArray<'a, &'a str>, NvDecodeError> {
match self.value {
NvDataValue::StringArray(v) => Ok(v),
_ => Err(NvDecodeError::DataTypeMismatch {
expected: NvDataType::StringArray,
actual: self.data_type(),
}),
}
}
pub fn get_u8_array(&self) -> Result<NvArray<'a, u8>, NvDecodeError> {
match self.value {
NvDataValue::Uint8Array(v) => Ok(v),
_ => Err(NvDecodeError::DataTypeMismatch {
expected: NvDataType::Uint8Array,
actual: self.data_type(),
}),
}
}
pub fn get_u16_array(&self) -> Result<NvArray<'a, u16>, NvDecodeError> {
match self.value {
NvDataValue::Uint16Array(v) => Ok(v),
_ => Err(NvDecodeError::DataTypeMismatch {
expected: NvDataType::Uint16Array,
actual: self.data_type(),
}),
}
}
pub fn get_u32_array(&self) -> Result<NvArray<'a, u32>, NvDecodeError> {
match self.value {
NvDataValue::Uint32Array(v) => Ok(v),
_ => Err(NvDecodeError::DataTypeMismatch {
expected: NvDataType::Uint32Array,
actual: self.data_type(),
}),
}
}
pub fn get_u64_array(&self) -> Result<NvArray<'a, u64>, NvDecodeError> {
match self.value {
NvDataValue::Uint64Array(v) => Ok(v),
_ => Err(NvDecodeError::DataTypeMismatch {
expected: NvDataType::Uint64Array,
actual: self.data_type(),
}),
}
}
}
impl NvPair<'_, '_> {
pub fn data_type(&self) -> NvDataType {
match self.value {
NvDataValue::Boolean() => NvDataType::Boolean,
NvDataValue::Byte(_) => NvDataType::Byte,
NvDataValue::Int16(_) => NvDataType::Int16,
NvDataValue::Uint16(_) => NvDataType::Uint16,
NvDataValue::Int32(_) => NvDataType::Int32,
NvDataValue::Uint32(_) => NvDataType::Uint32,
NvDataValue::Int64(_) => NvDataType::Int64,
NvDataValue::Uint64(_) => NvDataType::Uint64,
NvDataValue::String(_) => NvDataType::String,
NvDataValue::ByteArray(_) => NvDataType::ByteArray,
NvDataValue::Int16Array(_) => NvDataType::Int16Array,
NvDataValue::Uint16Array(_) => NvDataType::Uint16Array,
NvDataValue::Int32Array(_) => NvDataType::Int32Array,
NvDataValue::Uint32Array(_) => NvDataType::Uint32Array,
NvDataValue::Int64Array(_) => NvDataType::Int64Array,
NvDataValue::Uint64Array(_) => NvDataType::Uint64Array,
NvDataValue::StringArray(_) => NvDataType::StringArray,
NvDataValue::HrTime(_) => NvDataType::HrTime,
NvDataValue::NvList(_) => NvDataType::NvList,
NvDataValue::NvListArray(_) => NvDataType::NvListArray,
NvDataValue::BooleanValue(_) => NvDataType::BooleanValue,
NvDataValue::Int8(_) => NvDataType::Int8,
NvDataValue::Uint8(_) => NvDataType::Uint8,
NvDataValue::BooleanArray(_) => NvDataType::BooleanArray,
NvDataValue::Int8Array(_) => NvDataType::Int8Array,
NvDataValue::Uint8Array(_) => NvDataType::Uint8Array,
NvDataValue::Double(_) => NvDataType::Double,
}
}
pub fn get_bool(&self) -> Result<bool, NvDecodeError> {
match self.value {
NvDataValue::BooleanValue(v) => Ok(v),
_ => Err(NvDecodeError::DataTypeMismatch {
expected: NvDataType::BooleanValue,
actual: self.data_type(),
}),
}
}
pub fn get_bool_flag(&self) -> Result<bool, NvDecodeError> {
match self.value {
NvDataValue::Boolean() => Ok(true),
_ => Err(NvDecodeError::DataTypeMismatch {
expected: NvDataType::Boolean,
actual: self.data_type(),
}),
}
}
pub fn get_byte(&self) -> Result<u8, NvDecodeError> {
match self.value {
NvDataValue::Byte(v) => Ok(v),
_ => Err(NvDecodeError::DataTypeMismatch {
expected: NvDataType::Byte,
actual: self.data_type(),
}),
}
}
pub fn get_f64(&self) -> Result<f64, NvDecodeError> {
match self.value {
NvDataValue::Double(v) => Ok(v),
_ => Err(NvDecodeError::DataTypeMismatch {
expected: NvDataType::Double,
actual: self.data_type(),
}),
}
}
pub fn get_hr_time(&self) -> Result<i64, NvDecodeError> {
match self.value {
NvDataValue::HrTime(v) => Ok(v),
_ => Err(NvDecodeError::DataTypeMismatch {
expected: NvDataType::HrTime,
actual: self.data_type(),
}),
}
}
pub fn get_i8(&self) -> Result<i8, NvDecodeError> {
match self.value {
NvDataValue::Int8(v) => Ok(v),
_ => Err(NvDecodeError::DataTypeMismatch {
expected: NvDataType::Int8,
actual: self.data_type(),
}),
}
}
pub fn get_i16(&self) -> Result<i16, NvDecodeError> {
match self.value {
NvDataValue::Int16(v) => Ok(v),
_ => Err(NvDecodeError::DataTypeMismatch {
expected: NvDataType::Int16,
actual: self.data_type(),
}),
}
}
pub fn get_i32(&self) -> Result<i32, NvDecodeError> {
match self.value {
NvDataValue::Int32(v) => Ok(v),
_ => Err(NvDecodeError::DataTypeMismatch {
expected: NvDataType::Int32,
actual: self.data_type(),
}),
}
}
pub fn get_i64(&self) -> Result<i64, NvDecodeError> {
match self.value {
NvDataValue::Int64(v) => Ok(v),
_ => Err(NvDecodeError::DataTypeMismatch {
expected: NvDataType::Int64,
actual: self.data_type(),
}),
}
}
pub fn get_u8(&self) -> Result<u8, NvDecodeError> {
match self.value {
NvDataValue::Uint8(v) => Ok(v),
_ => Err(NvDecodeError::DataTypeMismatch {
expected: NvDataType::Uint8,
actual: self.data_type(),
}),
}
}
pub fn get_u16(&self) -> Result<u16, NvDecodeError> {
match self.value {
NvDataValue::Uint16(v) => Ok(v),
_ => Err(NvDecodeError::DataTypeMismatch {
expected: NvDataType::Uint16,
actual: self.data_type(),
}),
}
}
pub fn get_u32(&self) -> Result<u32, NvDecodeError> {
match self.value {
NvDataValue::Uint32(v) => Ok(v),
_ => Err(NvDecodeError::DataTypeMismatch {
expected: NvDataType::Uint32,
actual: self.data_type(),
}),
}
}
pub fn get_u64(&self) -> Result<u64, NvDecodeError> {
match self.value {
NvDataValue::Uint64(v) => Ok(v),
_ => Err(NvDecodeError::DataTypeMismatch {
expected: NvDataType::Uint64,
actual: self.data_type(),
}),
}
}
}
impl NvList<'_> {
pub fn from_bytes(data: &[u8]) -> Result<NvList<'_>, NvDecodeError> {
if data.len() < NvList::HEADER_SIZE {
return Err(NvDecodeError::EndOfInput {
offset: 0,
capacity: data.len(),
count: NvList::HEADER_SIZE,
detail: "NV List header is truncated",
});
}
let header = &data[0..NvList::HEADER_SIZE];
let encoding = NvEncoding::try_from(header[0])?;
let endian = EndianOrder::from(NvEndianOrder::try_from(header[1])?);
let reserved_0 = header[2];
let reserved_1 = header[3];
if reserved_0 != 0 || reserved_1 != 0 {
return Err(NvDecodeError::InvalidReservedBytes {
reserved: [reserved_0, reserved_1],
});
}
let start = header.len();
let length = data.len() - start;
NvList::from_partial(data, start, length, encoding, endian)
}
fn from_partial(
data: &[u8],
start: usize,
length: usize,
encoding: NvEncoding,
order: EndianOrder,
) -> Result<NvList<'_>, NvDecodeError> {
match encoding {
NvEncoding::Native => todo!("Implement Native decoding"),
NvEncoding::Xdr => (),
}
let mut decoder = XdrDecoder::from_bytes_clamped(data, start, length)?;
let version = decoder.get_u32()?;
if version != 0 {
return Err(NvDecodeError::UnknownVersion { version });
}
let flags = decoder.get_u32()?;
let unique_flags = flags & 0x3;
if unique_flags != flags {
return Err(NvDecodeError::UnknownFlags { flags });
}
let unique = NvUnique::try_from(unique_flags as u8)?;
Ok(NvList {
data,
offset: decoder.offset(),
length: decoder.len(),
encoding,
order,
unique,
})
}
}
impl<'a> NvList<'a> {
pub fn data(&self) -> &'a [u8] {
self.data
}
pub fn find(&self, name: &str) -> Result<Option<NvPair<'a, 'a>>, NvDecodeError> {
for pair_res in self {
let pair = pair_res?;
if pair.name == name {
return Ok(Some(pair));
}
}
Ok(None)
}
pub fn get_bool_array(&self, name: &str) -> Result<Option<NvArray<'a, bool>>, NvDecodeError> {
let nv_pair_opt = self.find(name)?;
match nv_pair_opt {
Some(nv_pair) => match nv_pair.value {
NvDataValue::BooleanArray(v) => Ok(Some(v)),
_ => Err(NvDecodeError::DataTypeMismatch {
expected: NvDataType::BooleanArray,
actual: nv_pair.data_type(),
}),
},
None => Ok(None),
}
}
pub fn get_byte_array(&self, name: &str) -> Result<Option<&'a [u8]>, NvDecodeError> {
let nv_pair_opt = self.find(name)?;
match nv_pair_opt {
Some(nv_pair) => match nv_pair.value {
NvDataValue::ByteArray(v) => Ok(Some(v)),
_ => Err(NvDecodeError::DataTypeMismatch {
expected: NvDataType::ByteArray,
actual: nv_pair.data_type(),
}),
},
None => Ok(None),
}
}
pub fn get_i8_array(&self, name: &str) -> Result<Option<NvArray<'_, i8>>, NvDecodeError> {
let nv_pair_opt = self.find(name)?;
match nv_pair_opt {
Some(nv_pair) => match nv_pair.value {
NvDataValue::Int8Array(v) => Ok(Some(v)),
_ => Err(NvDecodeError::DataTypeMismatch {
expected: NvDataType::Int8Array,
actual: nv_pair.data_type(),
}),
},
None => Ok(None),
}
}
pub fn get_i16_array(&self, name: &str) -> Result<Option<NvArray<'a, i16>>, NvDecodeError> {
let nv_pair_opt = self.find(name)?;
match nv_pair_opt {
Some(nv_pair) => match nv_pair.value {
NvDataValue::Int16Array(v) => Ok(Some(v)),
_ => Err(NvDecodeError::DataTypeMismatch {
expected: NvDataType::Int16Array,
actual: nv_pair.data_type(),
}),
},
None => Ok(None),
}
}
pub fn get_i32_array(&self, name: &str) -> Result<Option<NvArray<'a, i32>>, NvDecodeError> {
let nv_pair_opt = self.find(name)?;
match nv_pair_opt {
Some(nv_pair) => match nv_pair.value {
NvDataValue::Int32Array(v) => Ok(Some(v)),
_ => Err(NvDecodeError::DataTypeMismatch {
expected: NvDataType::Int32Array,
actual: nv_pair.data_type(),
}),
},
None => Ok(None),
}
}
pub fn get_i64_array(&self, name: &str) -> Result<Option<NvArray<'a, i64>>, NvDecodeError> {
let nv_pair_opt = self.find(name)?;
match nv_pair_opt {
Some(nv_pair) => match nv_pair.value {
NvDataValue::Int64Array(v) => Ok(Some(v)),
_ => Err(NvDecodeError::DataTypeMismatch {
expected: NvDataType::Int64Array,
actual: nv_pair.data_type(),
}),
},
None => Ok(None),
}
}
pub fn get_nv_list(&self, name: &str) -> Result<Option<NvList<'a>>, NvDecodeError> {
let nv_pair_opt = self.find(name)?;
match nv_pair_opt {
Some(nv_pair) => match nv_pair.value {
NvDataValue::NvList(v) => Ok(Some(v)),
_ => Err(NvDecodeError::DataTypeMismatch {
expected: NvDataType::NvList,
actual: nv_pair.data_type(),
}),
},
None => Ok(None),
}
}
pub fn get_nv_list_array(
&self,
name: &str,
) -> Result<Option<NvArray<'a, NvList<'a>>>, NvDecodeError> {
let nv_pair_opt = self.find(name)?;
match nv_pair_opt {
Some(nv_pair) => match nv_pair.value {
NvDataValue::NvListArray(v) => Ok(Some(v)),
_ => Err(NvDecodeError::DataTypeMismatch {
expected: NvDataType::NvListArray,
actual: nv_pair.data_type(),
}),
},
None => Ok(None),
}
}
pub fn get_str(&self, name: &str) -> Result<Option<&'a str>, NvDecodeError> {
let nv_pair_opt = self.find(name)?;
match nv_pair_opt {
Some(nv_pair) => match nv_pair.value {
NvDataValue::String(v) => Ok(Some(v)),
_ => Err(NvDecodeError::DataTypeMismatch {
expected: NvDataType::String,
actual: nv_pair.data_type(),
}),
},
None => Ok(None),
}
}
pub fn get_str_array(&self, name: &str) -> Result<Option<NvArray<'a, &'a str>>, NvDecodeError> {
let nv_pair_opt = self.find(name)?;
match nv_pair_opt {
Some(nv_pair) => match nv_pair.value {
NvDataValue::StringArray(v) => Ok(Some(v)),
_ => Err(NvDecodeError::DataTypeMismatch {
expected: NvDataType::StringArray,
actual: nv_pair.data_type(),
}),
},
None => Ok(None),
}
}
pub fn get_u8_array(&self, name: &str) -> Result<Option<NvArray<'a, u8>>, NvDecodeError> {
let nv_pair_opt = self.find(name)?;
match nv_pair_opt {
Some(nv_pair) => match nv_pair.value {
NvDataValue::Uint8Array(v) => Ok(Some(v)),
_ => Err(NvDecodeError::DataTypeMismatch {
expected: NvDataType::Uint8Array,
actual: nv_pair.data_type(),
}),
},
None => Ok(None),
}
}
pub fn get_u16_array(&self, name: &str) -> Result<Option<NvArray<'a, u16>>, NvDecodeError> {
let nv_pair_opt = self.find(name)?;
match nv_pair_opt {
Some(nv_pair) => match nv_pair.value {
NvDataValue::Uint16Array(v) => Ok(Some(v)),
_ => Err(NvDecodeError::DataTypeMismatch {
expected: NvDataType::Uint16Array,
actual: nv_pair.data_type(),
}),
},
None => Ok(None),
}
}
pub fn get_u32_array(&self, name: &str) -> Result<Option<NvArray<'a, u32>>, NvDecodeError> {
let nv_pair_opt = self.find(name)?;
match nv_pair_opt {
Some(nv_pair) => match nv_pair.value {
NvDataValue::Uint32Array(v) => Ok(Some(v)),
_ => Err(NvDecodeError::DataTypeMismatch {
expected: NvDataType::Uint32Array,
actual: nv_pair.data_type(),
}),
},
None => Ok(None),
}
}
pub fn get_u64_array(&self, name: &str) -> Result<Option<NvArray<'_, u64>>, NvDecodeError> {
let nv_pair_opt = self.find(name)?;
match nv_pair_opt {
Some(nv_pair) => match nv_pair.value {
NvDataValue::Uint64Array(v) => Ok(Some(v)),
_ => Err(NvDecodeError::DataTypeMismatch {
expected: NvDataType::Uint64Array,
actual: nv_pair.data_type(),
}),
},
None => Ok(None),
}
}
}
impl NvList<'_> {
const HEADER_SIZE: usize = 4;
pub fn unique(&self) -> NvUnique {
self.unique
}
pub fn get_bool(&self, name: &str) -> Result<Option<bool>, NvDecodeError> {
let nv_pair_opt = self.find(name)?;
match nv_pair_opt {
Some(nv_pair) => Ok(Some(nv_pair.get_bool()?)),
None => Ok(None),
}
}
pub fn get_bool_flag(&self, name: &str) -> Result<Option<bool>, NvDecodeError> {
let nv_pair_opt = self.find(name)?;
match nv_pair_opt {
Some(nv_pair) => Ok(Some(nv_pair.get_bool_flag()?)),
None => Ok(None),
}
}
pub fn get_byte(&self, name: &str) -> Result<Option<u8>, NvDecodeError> {
let nv_pair_opt = self.find(name)?;
match nv_pair_opt {
Some(nv_pair) => Ok(Some(nv_pair.get_byte()?)),
None => Ok(None),
}
}
pub fn get_f64(&self, name: &str) -> Result<Option<f64>, NvDecodeError> {
let nv_pair_opt = self.find(name)?;
match nv_pair_opt {
Some(nv_pair) => Ok(Some(nv_pair.get_f64()?)),
None => Ok(None),
}
}
pub fn get_hr_time(&self, name: &str) -> Result<Option<i64>, NvDecodeError> {
let nv_pair_opt = self.find(name)?;
match nv_pair_opt {
Some(nv_pair) => Ok(Some(nv_pair.get_hr_time()?)),
None => Ok(None),
}
}
pub fn get_i8(&self, name: &str) -> Result<Option<i8>, NvDecodeError> {
let nv_pair_opt = self.find(name)?;
match nv_pair_opt {
Some(nv_pair) => Ok(Some(nv_pair.get_i8()?)),
None => Ok(None),
}
}
pub fn get_i16(&self, name: &str) -> Result<Option<i16>, NvDecodeError> {
let nv_pair_opt = self.find(name)?;
match nv_pair_opt {
Some(nv_pair) => Ok(Some(nv_pair.get_i16()?)),
None => Ok(None),
}
}
pub fn get_i32(&self, name: &str) -> Result<Option<i32>, NvDecodeError> {
let nv_pair_opt = self.find(name)?;
match nv_pair_opt {
Some(nv_pair) => Ok(Some(nv_pair.get_i32()?)),
None => Ok(None),
}
}
pub fn get_i64(&self, name: &str) -> Result<Option<i64>, NvDecodeError> {
let nv_pair_opt = self.find(name)?;
match nv_pair_opt {
Some(nv_pair) => Ok(Some(nv_pair.get_i64()?)),
None => Ok(None),
}
}
pub fn get_u8(&self, name: &str) -> Result<Option<u8>, NvDecodeError> {
let nv_pair_opt = self.find(name)?;
match nv_pair_opt {
Some(nv_pair) => Ok(Some(nv_pair.get_u8()?)),
None => Ok(None),
}
}
pub fn get_u16(&self, name: &str) -> Result<Option<u16>, NvDecodeError> {
let nv_pair_opt = self.find(name)?;
match nv_pair_opt {
Some(nv_pair) => Ok(Some(nv_pair.get_u16()?)),
None => Ok(None),
}
}
pub fn get_u32(&self, name: &str) -> Result<Option<u32>, NvDecodeError> {
let nv_pair_opt = self.find(name)?;
match nv_pair_opt {
Some(nv_pair) => Ok(Some(nv_pair.get_u32()?)),
None => Ok(None),
}
}
pub fn get_u64(&self, name: &str) -> Result<Option<u64>, NvDecodeError> {
let nv_pair_opt = self.find(name)?;
match nv_pair_opt {
Some(nv_pair) => Ok(Some(nv_pair.get_u64()?)),
None => Ok(None),
}
}
}
#[derive(Debug)]
pub enum NvDecodeError {
BinaryDecoder {
err: BinaryDecodeError,
},
DataMismatch {},
DataTypeMismatch {
expected: NvDataType,
actual: NvDataType,
},
EndOfArray {},
EndOfInput {
offset: usize,
capacity: usize,
count: usize,
detail: &'static str,
},
InvalidCount {
data_type: NvDataType,
count: usize,
},
InvalidEncodedSize {
encoded_size: usize,
used: usize,
},
InvalidNestedSize {},
InvalidReservedBytes {
reserved: [u8; 2],
},
NestedDecoderMismatch {},
UnknownDataType {
data_type: u32,
},
UnknownEncoding {
encoding: u8,
},
UnknownEndian {
order: u8,
},
UnknownFlags {
flags: u32,
},
UnknownUnique {
unique: u8,
},
UnknownVersion {
version: u32,
},
}
impl From<BinaryDecodeError> for NvDecodeError {
fn from(err: BinaryDecodeError) -> Self {
NvDecodeError::BinaryDecoder { err }
}
}
impl fmt::Display for NvDecodeError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
NvDecodeError::BinaryDecoder { err } => {
write!(f, "NV decode error | {err}")
}
NvDecodeError::DataMismatch {} => write!(
f,
"NV decode error, provided data slice does not match decoder data slice"
),
NvDecodeError::DataTypeMismatch { expected, actual } => {
write!(
f,
"NV decode error, data type mismatch, expected {expected} actual {actual}"
)
}
NvDecodeError::EndOfArray {} => {
write!(f, "NV decode error, end of array")
}
NvDecodeError::EndOfInput {
offset,
capacity,
count,
detail,
} => {
write!(
f,
"NV decode error, end of input at offset {offset} capacity {capacity} count {count} detail {detail}"
)
}
NvDecodeError::InvalidCount { data_type, count } => {
write!(
f,
"NV decode error, invalid count {count} for data type {data_type}"
)
}
NvDecodeError::InvalidEncodedSize { encoded_size, used } => {
write!(
f,
"NV decode error, invalid encoded size {encoded_size} used {used}"
)
}
NvDecodeError::InvalidNestedSize {} => {
write!(f, "NV decode error, invalid nested size")
}
NvDecodeError::InvalidReservedBytes { reserved } => {
write!(
f,
"NV decode error, invalid reserved bytes {reserved:#02x?}"
)
}
NvDecodeError::NestedDecoderMismatch {} => {
write!(f, "NV decode error, nested decoder mismatch")
}
NvDecodeError::UnknownDataType { data_type } => {
write!(f, "NV decode error, unknown data type {data_type}")
}
NvDecodeError::UnknownEncoding { encoding } => {
write!(f, "NV decode error, unknown encoding {encoding}")
}
NvDecodeError::UnknownEndian { order } => {
write!(f, "NV decode error, unknown endian {order}")
}
NvDecodeError::UnknownFlags { flags } => {
write!(f, "NV decode error, unknown flags {flags:#08x}")
}
NvDecodeError::UnknownUnique { unique } => {
write!(f, "NV decode error, unknown unique {unique}")
}
NvDecodeError::UnknownVersion { version } => {
write!(f, "NV decode error, unknown version {version}")
}
}
}
}
#[cfg(feature = "std")]
impl error::Error for NvDecodeError {
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
match self {
NvDecodeError::BinaryDecoder { err } => Some(err),
_ => None,
}
}
}