#![allow(clippy::not_unsafe_ptr_arg_deref)]
use crate::{
simics_exception,
sys::{
attr_kind_t, attr_value__bindgen_ty_1, attr_value_t, SIM_alloc_attr_dict,
SIM_alloc_attr_list, SIM_attr_dict_resize, SIM_attr_dict_set_item, SIM_attr_list_resize,
SIM_attr_list_set_item, SIM_free_attribute,
},
ConfObject, Error, Result,
};
use ordered_float::OrderedFloat;
use std::{
any::type_name,
collections::{BTreeMap, BTreeSet, HashMap, HashSet},
ffi::{c_void, CStr, CString},
fmt::Debug,
hash::Hash,
mem::size_of,
path::PathBuf,
ptr::null_mut,
};
pub type AttrKind = attr_kind_t;
#[derive(Copy, Clone)]
#[repr(C)]
pub struct AttrValue(attr_value_t);
unsafe impl Send for AttrValue {}
unsafe impl Sync for AttrValue {}
impl Debug for AttrValue {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut debug = f.debug_tuple("AttrValue");
debug
.field(&self.0.private_kind)
.field(&self.0.private_size);
match self.0.private_kind {
AttrKind::Sim_Val_Integer => {
if self.0.private_size == 0 {
debug.field(&unsafe { self.0.private_u.integer })
} else {
debug.field(&unsafe { self.0.private_u.integer.to_le_bytes() })
}
}
AttrKind::Sim_Val_Boolean => debug.field(&unsafe { self.0.private_u.boolean }),
AttrKind::Sim_Val_String => {
let string = unsafe { CStr::from_ptr(self.0.private_u.string) }
.to_str()
.unwrap_or("Invalid UTF-8");
debug.field(&string)
}
AttrKind::Sim_Val_Floating => debug.field(&unsafe { self.0.private_u.floating }),
AttrKind::Sim_Val_Object => debug.field(&unsafe { self.0.private_u.object }),
AttrKind::Sim_Val_Data => {
let data = unsafe {
std::slice::from_raw_parts(
self.0.private_u.data as *const u8,
self.0.private_size as usize,
)
};
debug.field(&data)
}
AttrKind::Sim_Val_List => debug.field(&"[...]"),
AttrKind::Sim_Val_Dict => debug.field(&"{..., ...}"),
AttrKind::Sim_Val_Nil => debug.field(&"Nil"),
AttrKind::Sim_Val_Invalid => debug.field(&"Invalid"),
AttrKind::Sim_Val_Py_Object => debug.field(&"PyObject"),
AttrKind::Sim_Val_Unresolved_Object => debug.field(&"UnresolvedObject"),
};
debug.finish()
}
}
impl AttrValue {
pub fn nil() -> Self {
Self(attr_value_t {
private_kind: AttrKind::Sim_Val_Nil,
private_size: 0,
private_u: attr_value__bindgen_ty_1 { integer: 0 },
})
}
pub fn invalid() -> Self {
Self(attr_value_t {
private_kind: AttrKind::Sim_Val_Invalid,
private_size: 0,
private_u: attr_value__bindgen_ty_1 { integer: 0 },
})
}
pub fn signed(s: i64) -> Self {
Self(attr_value_t {
private_kind: AttrKind::Sim_Val_Integer,
private_size: 1,
private_u: attr_value__bindgen_ty_1 { integer: s },
})
}
pub fn unsigned(u: u64) -> Self {
Self(attr_value_t {
private_kind: AttrKind::Sim_Val_Integer,
private_size: 0,
private_u: attr_value__bindgen_ty_1 {
integer: i64::from_le_bytes(u.to_le_bytes()),
},
})
}
pub fn boolean(b: bool) -> Self {
Self(attr_value_t {
private_kind: AttrKind::Sim_Val_Boolean,
private_size: 0,
private_u: attr_value__bindgen_ty_1 { boolean: b },
})
}
pub fn string(s: &str) -> Result<Self> {
Ok(Self(attr_value_t {
private_kind: AttrKind::Sim_Val_String,
private_size: 0,
private_u: attr_value__bindgen_ty_1 {
string: CString::new(s).map_err(Error::from)?.into_raw(),
},
}))
}
pub fn string_unchecked(s: &str) -> Self {
Self(attr_value_t {
private_kind: AttrKind::Sim_Val_String,
private_size: 0,
private_u: attr_value__bindgen_ty_1 {
string: CString::new(s)
.expect("Failed to allocate memory for string")
.into_raw(),
},
})
}
pub fn floating(f: f64) -> Self {
Self(attr_value_t {
private_kind: AttrKind::Sim_Val_Floating,
private_size: 0,
private_u: attr_value__bindgen_ty_1 { floating: f },
})
}
pub fn object(o: *mut ConfObject) -> Self {
Self(attr_value_t {
private_kind: AttrKind::Sim_Val_Object,
private_size: 0,
private_u: attr_value__bindgen_ty_1 { object: o },
})
}
pub fn data<T>(d: T) -> Self
where
T: Into<Box<[u8]>>,
{
let data = d.into();
let len = data.len();
Self(attr_value_t {
private_kind: AttrKind::Sim_Val_Data,
private_size: len as u32,
private_u: attr_value__bindgen_ty_1 {
data: Box::into_raw(data) as *mut _,
},
})
}
pub fn list(length: usize) -> Result<Self> {
alloc_attr_list(length.try_into()?)
}
pub fn dict(size: usize) -> Result<Self> {
alloc_attr_dict(size.try_into()?)
}
}
impl AttrValue {
#[doc(hidden)]
pub unsafe fn from_raw(raw: *mut attr_value_t) -> Self {
Self(unsafe { *raw })
}
#[doc(hidden)]
pub fn into_raw(self) -> attr_value_t {
self.0
}
pub fn as_ptr(&self) -> *const attr_value_t {
&self.0 as *const attr_value_t
}
pub fn as_mut_ptr(&mut self) -> *mut attr_value_t {
&mut self.0 as *mut attr_value_t
}
pub fn kind(&self) -> AttrKind {
self.0.private_kind
}
pub fn size(&self) -> u32 {
self.0.private_size
}
pub fn is_invalid(&self) -> bool {
self.kind() == AttrKind::Sim_Val_Invalid
}
pub fn is_nil(&self) -> bool {
self.kind() == AttrKind::Sim_Val_Nil
}
pub fn is_integer(&self) -> bool {
self.kind() == AttrKind::Sim_Val_Integer
}
pub fn is_unsigned(&self) -> bool {
self.is_integer() && self.size() == 0
}
pub fn is_signed(&self) -> bool {
self.is_integer() && self.size() == 1
}
pub fn is_boolean(&self) -> bool {
self.kind() == AttrKind::Sim_Val_Boolean
}
pub fn is_string(&self) -> bool {
self.kind() == AttrKind::Sim_Val_String
}
pub fn is_floating(&self) -> bool {
self.kind() == AttrKind::Sim_Val_Floating
}
pub fn is_object(&self) -> bool {
self.kind() == AttrKind::Sim_Val_Object
}
pub fn is_data(&self) -> bool {
self.kind() == AttrKind::Sim_Val_Data
}
pub fn is_list(&self) -> bool {
self.kind() == AttrKind::Sim_Val_List
}
pub fn is_dict(&self) -> bool {
self.kind() == AttrKind::Sim_Val_Dict
}
pub fn as_integer(&self) -> Option<i64> {
self.is_integer()
.then_some(unsafe { self.0.private_u.integer })
}
pub fn as_unsigned(&self) -> Option<u64> {
self.is_unsigned().then_some(u64::from_le_bytes(unsafe {
self.0.private_u.integer.to_le_bytes()
}))
}
pub fn as_signed(&self) -> Option<i64> {
self.is_signed()
.then_some(unsafe { self.0.private_u.integer })
}
pub fn as_boolean(&self) -> Option<bool> {
self.is_boolean()
.then_some(unsafe { self.0.private_u.boolean })
}
pub fn as_string(&self) -> Option<String> {
self.is_string()
.then(|| {
unsafe { CStr::from_ptr(self.0.private_u.string) }
.to_str()
.ok()
.map(|s| s.to_string())
})
.flatten()
}
pub fn as_floating(&self) -> Option<f64> {
self.is_floating()
.then_some(unsafe { self.0.private_u.floating })
}
pub fn as_object(&self) -> Option<*mut ConfObject> {
self.is_object()
.then_some(unsafe { self.0.private_u.object })
}
pub fn as_data<T>(&self) -> Option<T>
where
T: Clone,
{
if self.is_data() {
let data = Box::leak(unsafe { Box::from_raw(self.0.private_u.data as *mut T) });
Some(data.clone())
} else {
None
}
}
pub fn as_list_checked<T>(&self) -> Result<Option<Vec<T>>>
where
T: TryFrom<AttrValue> + Clone,
Error: From<<T as TryFrom<AttrValue>>::Error>,
{
if self.is_list() {
let size = self.size() as isize;
let items = (0..size)
.map(|i| Box::leak(unsafe { Box::from_raw(self.0.private_u.list.offset(i)) }))
.collect::<Vec<_>>();
if items
.iter()
.all(|i| Some(i.private_kind) == items.first().map(|f| f.private_kind))
{
Ok(Some(
items
.into_iter()
.map(|i| {
let value = AttrValue(*i);
value.try_into().map_err(|e| {
Error::NestedFromAttrValueConversionError {
ty: type_name::<T>().to_string(),
source: Box::new(Error::from(e)),
}
})
})
.collect::<Result<Vec<_>>>()?,
))
} else {
Err(Error::NonHomogeneousList)
}
} else {
Ok(None)
}
}
pub fn as_list<T>(&self) -> Option<Vec<T>>
where
T: TryFrom<AttrValue> + Clone,
Error: From<<T as TryFrom<AttrValue>>::Error>,
{
if self.is_list() {
let size = self.size() as isize;
let items = (0..size)
.map(|i| Box::leak(unsafe { Box::from_raw(self.0.private_u.list.offset(i)) }))
.collect::<Vec<_>>();
if items
.iter()
.all(|i| Some(i.private_kind) == items.first().map(|f| f.private_kind))
{
items
.into_iter()
.map(|i| {
let value = AttrValue(*i);
value.try_into().ok()
})
.collect::<Option<Vec<_>>>()
} else {
None
}
} else {
None
}
}
pub fn as_heterogeneous_list(&self) -> Option<Vec<AttrValueType>> {
if self.is_list() {
let size = self.size() as isize;
let items = (0..size)
.map(|i| Box::leak(unsafe { Box::from_raw(self.0.private_u.list.offset(i)) }))
.collect::<Vec<_>>();
Some(
items
.into_iter()
.map(|i| AttrValue(*i).into())
.collect::<Vec<_>>(),
)
} else {
None
}
}
pub fn as_dict_checked<T, U>(&self) -> Result<Option<BTreeMap<T, U>>>
where
T: TryFrom<AttrValue> + Ord,
U: TryFrom<AttrValue>,
Error: From<<T as TryFrom<AttrValue>>::Error>,
Error: From<<U as TryFrom<AttrValue>>::Error>,
{
if self.is_dict() {
let size = self.size() as isize;
let items = (0..size)
.map(|i| {
(
Box::leak(unsafe { Box::from_raw(self.0.private_u.dict.offset(i)) }).key,
Box::leak(unsafe { Box::from_raw(self.0.private_u.dict.offset(i)) }).value,
)
})
.collect::<Vec<_>>();
if items.iter().all(|(k, v)| {
Some(k.private_kind) == items.first().map(|f| f.0.private_kind)
&& Some(v.private_kind) == items.first().map(|f| f.1.private_kind)
}) {
Ok(Some(
items
.into_iter()
.map(|(k, v)| {
let key = AttrValue(k);
key.try_into()
.map_err(|e| Error::NestedFromAttrValueConversionError {
ty: type_name::<T>().to_string(),
source: Box::new(Error::from(e)),
})
.and_then(|k| {
let value = AttrValue(v);
value
.try_into()
.map_err(|e| Error::NestedFromAttrValueConversionError {
ty: type_name::<U>().to_string(),
source: Box::new(Error::from(e)),
})
.map(|v| (k, v))
})
})
.collect::<Result<Vec<_>>>()?
.into_iter()
.collect::<BTreeMap<_, _>>(),
))
} else {
Err(Error::NonHomogeneousDict)
}
} else {
Ok(None)
}
}
pub fn as_dict<T, U>(&self) -> Option<BTreeMap<T, U>>
where
T: TryFrom<AttrValue> + Ord,
U: TryFrom<AttrValue>,
Error: From<<T as TryFrom<AttrValue>>::Error>,
Error: From<<U as TryFrom<AttrValue>>::Error>,
{
if self.is_dict() {
let size = self.size() as isize;
let items = (0..size)
.map(|i| {
(
Box::leak(unsafe { Box::from_raw(self.0.private_u.dict.offset(i)) }).key,
Box::leak(unsafe { Box::from_raw(self.0.private_u.dict.offset(i)) }).value,
)
})
.collect::<Vec<_>>();
if items.iter().all(|(k, v)| {
Some(k.private_kind) == items.first().map(|f| f.0.private_kind)
&& Some(v.private_kind) == items.first().map(|f| f.1.private_kind)
}) {
Some(
items
.into_iter()
.map(|(k, v)| {
let key = AttrValue(k);
key.try_into().ok().and_then(|k| {
let value = AttrValue(v);
value.try_into().ok().map(|v| (k, v))
})
})
.collect::<Option<Vec<_>>>()?
.into_iter()
.collect::<BTreeMap<_, _>>(),
)
} else {
None
}
} else {
None
}
}
pub fn as_heterogeneous_dict(&self) -> Result<Option<BTreeMap<AttrValueType, AttrValueType>>> {
Ok(if self.is_dict() {
let size = self.size() as isize;
let items = (0..size)
.map(|i| {
(
Box::leak(unsafe { Box::from_raw(self.0.private_u.dict.offset(i)) }).key,
Box::leak(unsafe { Box::from_raw(self.0.private_u.dict.offset(i)) }).value,
)
})
.collect::<Vec<_>>();
Some(
items
.into_iter()
.map(|(k, v)| {
let key = AttrValue(k);
let value = AttrValue(v);
(key.into(), value.into())
})
.collect::<BTreeMap<_, _>>(),
)
} else {
None
})
}
}
impl From<attr_value_t> for AttrValue {
fn from(value: attr_value_t) -> Self {
AttrValue(value)
}
}
impl From<AttrValue> for attr_value_t {
fn from(value: AttrValue) -> Self {
value.0
}
}
impl From<i64> for AttrValue {
fn from(value: i64) -> Self {
AttrValue(attr_value_t {
private_kind: AttrKind::Sim_Val_Integer,
private_size: 1,
private_u: attr_value__bindgen_ty_1 { integer: value },
})
}
}
impl From<u64> for AttrValue {
fn from(value: u64) -> Self {
AttrValue(attr_value_t {
private_kind: AttrKind::Sim_Val_Integer,
private_size: 0,
private_u: attr_value__bindgen_ty_1 {
integer: i64::from_le_bytes(value.to_le_bytes()),
},
})
}
}
impl From<f64> for AttrValue {
fn from(value: f64) -> Self {
AttrValue(attr_value_t {
private_kind: AttrKind::Sim_Val_Floating,
private_size: 0,
private_u: attr_value__bindgen_ty_1 { floating: value },
})
}
}
macro_rules! impl_from_signed {
($t:ty) => {
impl From<$t> for AttrValue {
fn from(value: $t) -> AttrValue {
#[allow(clippy::unnecessary_cast)]
AttrValue::from(value as i64)
}
}
impl From<&$t> for AttrValue {
fn from(value: &$t) -> AttrValue {
#[allow(clippy::unnecessary_cast)]
AttrValue::from(*value as i64)
}
}
};
}
macro_rules! impl_from_unsigned {
($t:ty) => {
impl From<$t> for AttrValue {
fn from(value: $t) -> AttrValue {
#[allow(clippy::unnecessary_cast)]
AttrValue::from(value as u64)
}
}
impl From<&$t> for AttrValue {
fn from(value: &$t) -> AttrValue {
#[allow(clippy::unnecessary_cast)]
AttrValue::from(*value as u64)
}
}
};
}
macro_rules! impl_from_float {
($t:ty) => {
impl From<$t> for AttrValue {
fn from(value: $t) -> AttrValue {
#[allow(clippy::unnecessary_cast)]
AttrValue::from(value as f64)
}
}
impl From<&$t> for AttrValue {
fn from(value: &$t) -> AttrValue {
#[allow(clippy::unnecessary_cast)]
AttrValue::from(*value as f64)
}
}
};
}
impl_from_unsigned! { u8 }
impl_from_unsigned! { u16 }
impl_from_unsigned! { u32 }
impl_from_unsigned! { usize }
impl_from_signed! { i8 }
impl_from_signed! { i16 }
impl_from_signed! { i32 }
impl_from_signed! { isize }
impl_from_float! { f32 }
impl From<OrderedFloat<f32>> for AttrValue {
fn from(value: OrderedFloat<f32>) -> Self {
AttrValue::from(value.0 as f64)
}
}
impl From<&OrderedFloat<f32>> for AttrValue {
fn from(value: &OrderedFloat<f32>) -> Self {
AttrValue::from(value.0 as f64)
}
}
impl From<OrderedFloat<f64>> for AttrValue {
fn from(value: OrderedFloat<f64>) -> Self {
AttrValue::from(value.0)
}
}
impl From<&OrderedFloat<f64>> for AttrValue {
fn from(value: &OrderedFloat<f64>) -> Self {
AttrValue::from(value.0)
}
}
impl From<String> for AttrValue {
fn from(value: String) -> Self {
AttrValue(attr_value_t {
private_kind: AttrKind::Sim_Val_String,
private_size: 0,
private_u: attr_value__bindgen_ty_1 {
string: CString::new(value)
.expect("Failed to allocate memory for string")
.into_raw(),
},
})
}
}
impl From<&str> for AttrValue {
fn from(value: &str) -> Self {
AttrValue(attr_value_t {
private_kind: AttrKind::Sim_Val_String,
private_size: 0,
private_u: attr_value__bindgen_ty_1 {
string: CString::new(value)
.expect("Failed to allocate memory for string")
.into_raw(),
},
})
}
}
impl From<bool> for AttrValue {
fn from(value: bool) -> Self {
AttrValue(attr_value_t {
private_kind: AttrKind::Sim_Val_Boolean,
private_size: 0,
private_u: attr_value__bindgen_ty_1 { boolean: value },
})
}
}
impl From<*mut ConfObject> for AttrValue {
fn from(value: *mut ConfObject) -> Self {
AttrValue(attr_value_t {
private_kind: if value.is_null() {
AttrKind::Sim_Val_Nil
} else {
AttrKind::Sim_Val_Object
},
private_size: 0,
private_u: attr_value__bindgen_ty_1 { object: value },
})
}
}
impl TryFrom<PathBuf> for AttrValue {
type Error = Error;
fn try_from(value: PathBuf) -> Result<Self> {
value
.to_str()
.ok_or_else(|| Error::ToString)
.map(|s| s.to_string().into())
}
}
impl<T> TryFrom<Option<T>> for AttrValue
where
T: TryInto<AttrValue>,
Error: From<<T as TryInto<AttrValue>>::Error>,
{
type Error = Error;
fn try_from(value: Option<T>) -> Result<Self> {
if let Some(value) = value {
value
.try_into()
.map_err(|e| Error::NestedToAttrValueConversionError {
ty: type_name::<T>().to_string(),
source: Box::new(Error::from(e)),
})
} else {
Ok(AttrValue::nil())
}
}
}
impl<T> TryFrom<&[T]> for AttrValue
where
T: TryInto<AttrValue> + Clone,
Error: From<<T as TryInto<AttrValue>>::Error>,
{
type Error = Error;
fn try_from(value: &[T]) -> Result<Self> {
let mut list = AttrValue::list(value.len())?;
value.iter().enumerate().try_for_each(|(i, a)| {
a.clone()
.try_into()
.map_err(|e| Error::NestedToAttrValueConversionError {
ty: type_name::<T>().to_string(),
source: Box::new(Error::from(e)),
})
.and_then(|a| attr_list_set_item(&mut list, i as u32, a))
})?;
Ok(list)
}
}
impl<T> TryFrom<Vec<T>> for AttrValue
where
T: TryInto<AttrValue>,
Error: From<<T as TryInto<AttrValue>>::Error>,
{
type Error = Error;
fn try_from(value: Vec<T>) -> Result<Self> {
let mut list = AttrValue::list(value.len())?;
value.into_iter().enumerate().try_for_each(|(i, a)| {
a.try_into()
.map_err(|e| Error::NestedToAttrValueConversionError {
ty: type_name::<T>().to_string(),
source: Box::new(Error::from(e)),
})
.and_then(|a| attr_list_set_item(&mut list, i as u32, a))
})?;
Ok(list)
}
}
impl<T> TryFrom<HashSet<T>> for AttrValue
where
T: TryInto<AttrValue>,
Error: From<<T as TryInto<AttrValue>>::Error>,
{
type Error = Error;
fn try_from(value: HashSet<T>) -> Result<Self> {
let mut list = AttrValue::list(value.len())?;
value.into_iter().enumerate().try_for_each(|(i, a)| {
a.try_into()
.map_err(|e| Error::NestedToAttrValueConversionError {
ty: type_name::<T>().to_string(),
source: Box::new(Error::from(e)),
})
.and_then(|a| attr_list_set_item(&mut list, i as u32, a))
})?;
Ok(list)
}
}
impl<T> TryFrom<BTreeSet<T>> for AttrValue
where
T: TryInto<AttrValue>,
Error: From<<T as TryInto<AttrValue>>::Error>,
{
type Error = Error;
fn try_from(value: BTreeSet<T>) -> Result<Self> {
let mut list = AttrValue::list(value.len())?;
value.into_iter().enumerate().try_for_each(|(i, a)| {
a.try_into()
.map_err(|e| Error::NestedToAttrValueConversionError {
ty: type_name::<T>().to_string(),
source: Box::new(Error::from(e)),
})
.and_then(|a| attr_list_set_item(&mut list, i as u32, a))
})?;
Ok(list)
}
}
impl<T, U> TryFrom<HashMap<T, U>> for AttrValue
where
T: TryInto<AttrValue>,
U: TryInto<AttrValue>,
Error: From<<T as TryInto<AttrValue>>::Error>,
Error: From<<U as TryInto<AttrValue>>::Error>,
{
type Error = Error;
fn try_from(value: HashMap<T, U>) -> Result<Self> {
let mut dict = AttrValue::dict(value.len())?;
value.into_iter().enumerate().try_for_each(|(i, (k, v))| {
k.try_into()
.map_err(|e| Error::NestedToAttrValueConversionError {
ty: type_name::<T>().to_string(),
source: Box::new(Error::from(e)),
})
.and_then(|k| {
v.try_into()
.map_err(|e| Error::NestedToAttrValueConversionError {
ty: type_name::<U>().to_string(),
source: Box::new(Error::from(e)),
})
.map(|v| (k, v))
})
.and_then(|(k, v)| attr_dict_set_item(&mut dict, i as u32, k, v))
})?;
Ok(dict)
}
}
impl<T, U> TryFrom<BTreeMap<T, U>> for AttrValue
where
T: TryInto<AttrValue>,
U: TryInto<AttrValue>,
Error: From<<T as TryInto<AttrValue>>::Error>,
Error: From<<U as TryInto<AttrValue>>::Error>,
{
type Error = Error;
fn try_from(value: BTreeMap<T, U>) -> Result<Self> {
let mut dict = AttrValue::dict(value.len())?;
value.into_iter().enumerate().try_for_each(|(i, (k, v))| {
k.try_into()
.map_err(|e| Error::NestedToAttrValueConversionError {
ty: type_name::<T>().to_string(),
source: Box::new(Error::from(e)),
})
.and_then(|k| {
v.try_into()
.map_err(|e| Error::NestedToAttrValueConversionError {
ty: type_name::<U>().to_string(),
source: Box::new(Error::from(e)),
})
.map(|v| (k, v))
})
.and_then(|(k, v)| attr_dict_set_item(&mut dict, i as u32, k, v))
})?;
Ok(dict)
}
}
impl<T, U> TryFrom<&[(T, U)]> for AttrValue
where
T: TryInto<AttrValue> + Clone,
U: TryInto<AttrValue> + Clone,
Error: From<<T as TryInto<AttrValue>>::Error>,
Error: From<<U as TryInto<AttrValue>>::Error>,
{
type Error = Error;
fn try_from(value: &[(T, U)]) -> Result<Self> {
let mut dict = AttrValue::dict(value.len())?;
value.iter().enumerate().try_for_each(|(i, (k, v))| {
k.clone()
.try_into()
.map_err(|e| Error::NestedToAttrValueConversionError {
ty: type_name::<T>().to_string(),
source: Box::new(Error::from(e)),
})
.and_then(|k| {
v.clone()
.try_into()
.map_err(|e| Error::NestedToAttrValueConversionError {
ty: type_name::<U>().to_string(),
source: Box::new(Error::from(e)),
})
.map(|v| (k, v))
})
.and_then(|(k, v)| attr_dict_set_item(&mut dict, i as u32, k, v))
})?;
Ok(dict)
}
}
impl<T, U> TryFrom<Vec<(T, U)>> for AttrValue
where
T: TryInto<AttrValue>,
U: TryInto<AttrValue>,
Error: From<<T as TryInto<AttrValue>>::Error>,
Error: From<<U as TryInto<AttrValue>>::Error>,
{
type Error = Error;
fn try_from(value: Vec<(T, U)>) -> Result<Self> {
let mut dict = AttrValue::dict(value.len())?;
value.into_iter().enumerate().try_for_each(|(i, (k, v))| {
k.try_into()
.map_err(|e| Error::NestedToAttrValueConversionError {
ty: type_name::<T>().to_string(),
source: Box::new(Error::from(e)),
})
.and_then(|k| {
v.try_into()
.map_err(|e| Error::NestedToAttrValueConversionError {
ty: type_name::<U>().to_string(),
source: Box::new(Error::from(e)),
})
.map(|v| (k, v))
})
.and_then(|(k, v)| attr_dict_set_item(&mut dict, i as u32, k, v))
})?;
Ok(dict)
}
}
impl<T, U> TryFrom<HashSet<(T, U)>> for AttrValue
where
T: TryInto<AttrValue>,
U: TryInto<AttrValue>,
Error: From<<T as TryInto<AttrValue>>::Error>,
Error: From<<U as TryInto<AttrValue>>::Error>,
{
type Error = Error;
fn try_from(value: HashSet<(T, U)>) -> Result<Self> {
let mut dict = AttrValue::dict(value.len())?;
value.into_iter().enumerate().try_for_each(|(i, (k, v))| {
k.try_into()
.map_err(|e| Error::NestedToAttrValueConversionError {
ty: type_name::<T>().to_string(),
source: Box::new(Error::from(e)),
})
.and_then(|k| {
v.try_into()
.map_err(|e| Error::NestedToAttrValueConversionError {
ty: type_name::<U>().to_string(),
source: Box::new(Error::from(e)),
})
.map(|v| (k, v))
})
.and_then(|(k, v)| attr_dict_set_item(&mut dict, i as u32, k, v))
})?;
Ok(dict)
}
}
impl<T, U> TryFrom<BTreeSet<(T, U)>> for AttrValue
where
T: TryInto<AttrValue>,
U: TryInto<AttrValue>,
Error: From<<T as TryInto<AttrValue>>::Error>,
Error: From<<U as TryInto<AttrValue>>::Error>,
{
type Error = Error;
fn try_from(value: BTreeSet<(T, U)>) -> Result<Self> {
let mut dict = AttrValue::dict(value.len())?;
value.into_iter().enumerate().try_for_each(|(i, (k, v))| {
k.try_into()
.map_err(|e| Error::NestedToAttrValueConversionError {
ty: type_name::<T>().to_string(),
source: Box::new(Error::from(e)),
})
.and_then(|k| {
v.try_into()
.map_err(|e| Error::NestedToAttrValueConversionError {
ty: type_name::<U>().to_string(),
source: Box::new(Error::from(e)),
})
.map(|v| (k, v))
})
.and_then(|(k, v)| attr_dict_set_item(&mut dict, i as u32, k, v))
})?;
Ok(dict)
}
}
macro_rules! impl_try_into_unsigned {
($t:ty) => {
impl TryFrom<AttrValue> for $t {
type Error = Error;
fn try_from(value: AttrValue) -> Result<Self> {
if let Some(unsigned) = value.as_unsigned() {
unsigned
.try_into()
.map_err(|_| Error::FromAttrValueConversionError {
ty: type_name::<$t>().to_string(),
})
} else if let Some(signed) = value.as_signed() {
if signed >= 0 {
signed
.try_into()
.map_err(|_| Error::FromAttrValueConversionError {
ty: type_name::<$t>().to_string(),
})
} else {
Err(Error::AttrValueType {
actual: value.kind(),
expected: AttrKind::Sim_Val_Integer,
reason: "negative value cannot be converted to unsigned".to_string(),
})
}
} else {
Err(Error::AttrValueType {
actual: value.kind(),
expected: AttrKind::Sim_Val_Integer,
reason: "value is not an integer".to_string(),
})
}
}
}
};
}
macro_rules! impl_try_into_signed {
($t:ty) => {
impl TryFrom<AttrValue> for $t {
type Error = Error;
fn try_from(value: AttrValue) -> Result<Self> {
if let Some(signed) = value.as_signed() {
signed
.try_into()
.map_err(|_| Error::FromAttrValueConversionError {
ty: type_name::<$t>().to_string(),
})
} else if let Some(unsigned) = value.as_unsigned() {
unsigned.try_into().map_err(Error::from)
} else {
Err(Error::AttrValueType {
actual: value.kind(),
expected: AttrKind::Sim_Val_Integer,
reason: "The value is not an integer".to_string(),
})
}
}
}
};
}
macro_rules! impl_try_into_float {
($t:ty) => {
impl TryFrom<AttrValue> for $t {
type Error = Error;
fn try_from(value: AttrValue) -> Result<Self> {
value
.as_floating()
.ok_or_else(|| Error::AttrValueType {
actual: value.kind(),
expected: AttrKind::Sim_Val_Floating,
reason: "The value is not a floating point number".to_string(),
})
.and_then(|f| {
f.try_into()
.map_err(|_| Error::FromAttrValueConversionError {
ty: type_name::<$t>().to_string(),
})
})
}
}
};
}
impl_try_into_unsigned! { u8 }
impl_try_into_unsigned! { u16 }
impl_try_into_unsigned! { u32 }
impl_try_into_unsigned! { u64 }
impl_try_into_unsigned! { usize }
impl_try_into_signed! { i8 }
impl_try_into_signed! { i16 }
impl_try_into_signed! { i32 }
impl_try_into_signed! { i64 }
impl_try_into_signed! { isize }
impl_try_into_float! { f64 }
impl TryFrom<AttrValue> for f32 {
type Error = Error;
fn try_from(value: AttrValue) -> Result<Self> {
Ok(value.as_floating().ok_or_else(|| Error::AttrValueType {
actual: value.kind(),
expected: AttrKind::Sim_Val_Floating,
reason: "The value is not a floating point number".to_string(),
})? as f32)
}
}
impl TryFrom<AttrValue> for bool {
type Error = Error;
fn try_from(value: AttrValue) -> Result<Self> {
value.as_boolean().ok_or_else(|| Error::AttrValueType {
actual: value.kind(),
expected: AttrKind::Sim_Val_Boolean,
reason: "The value is not a boolean".to_string(),
})
}
}
impl TryFrom<AttrValue> for String {
type Error = Error;
fn try_from(value: AttrValue) -> Result<Self> {
value.as_string().ok_or_else(|| Error::AttrValueType {
actual: value.kind(),
expected: AttrKind::Sim_Val_String,
reason: "The value is not a string".to_string(),
})
}
}
impl TryFrom<AttrValue> for PathBuf {
type Error = Error;
fn try_from(value: AttrValue) -> Result<Self> {
value
.as_string()
.ok_or_else(|| Error::AttrValueType {
actual: value.kind(),
expected: AttrKind::Sim_Val_String,
reason: "The value is not a string".to_string(),
})
.map(PathBuf::from)
}
}
impl<T> TryFrom<AttrValue> for Vec<T>
where
T: TryFrom<AttrValue> + Clone,
Error: From<<T as TryFrom<AttrValue>>::Error>,
{
type Error = Error;
fn try_from(value: AttrValue) -> Result<Self> {
value.as_list().ok_or_else(|| Error::AttrValueType {
actual: value.kind(),
expected: AttrKind::Sim_Val_List,
reason: "The value is not a homogeneous list".to_string(),
})
}
}
impl<T> TryFrom<AttrValue> for HashSet<T>
where
T: TryFrom<AttrValue> + Eq + Hash + Clone,
Error: From<<T as TryFrom<AttrValue>>::Error>,
{
type Error = Error;
fn try_from(value: AttrValue) -> Result<Self> {
value
.as_list()
.ok_or_else(|| Error::AttrValueType {
actual: value.kind(),
expected: AttrKind::Sim_Val_List,
reason: "The value is not a homogeneous list".to_string(),
})
.map(|s| s.into_iter().collect::<HashSet<_>>())
}
}
impl<T> TryFrom<AttrValue> for BTreeSet<T>
where
T: TryFrom<AttrValue> + Ord + Clone,
Error: From<<T as TryFrom<AttrValue>>::Error>,
{
type Error = Error;
fn try_from(value: AttrValue) -> Result<Self> {
value
.as_list()
.ok_or_else(|| Error::AttrValueType {
actual: value.kind(),
expected: AttrKind::Sim_Val_List,
reason: "The value is not a homogeneous list".to_string(),
})
.map(|s| s.into_iter().collect::<BTreeSet<_>>())
}
}
impl<T, U> TryFrom<AttrValue> for HashMap<T, U>
where
T: TryFrom<AttrValue> + Eq + Hash + Ord,
U: TryFrom<AttrValue>,
Error: From<<T as TryFrom<AttrValue>>::Error>,
Error: From<<U as TryFrom<AttrValue>>::Error>,
{
type Error = Error;
fn try_from(value: AttrValue) -> Result<Self> {
value
.as_dict()
.ok_or_else(|| Error::AttrValueType {
actual: value.kind(),
expected: AttrKind::Sim_Val_Dict,
reason: "The value is not a homogeneous dict".to_string(),
})
.map(|d| d.into_iter().collect::<HashMap<_, _>>())
}
}
impl<T, U> TryFrom<AttrValue> for BTreeMap<T, U>
where
T: TryFrom<AttrValue> + Ord,
U: TryFrom<AttrValue>,
Error: From<<T as TryFrom<AttrValue>>::Error>,
Error: From<<U as TryFrom<AttrValue>>::Error>,
{
type Error = Error;
fn try_from(value: AttrValue) -> Result<Self> {
value.as_dict().ok_or_else(|| Error::AttrValueType {
actual: value.kind(),
expected: AttrKind::Sim_Val_Dict,
reason: "The value is not a homogeneous dict".to_string(),
})
}
}
impl TryFrom<AttrValue> for Option<u8> {
type Error = Error;
fn try_from(value: AttrValue) -> Result<Self> {
if value.is_nil() {
Ok(None)
} else {
value.try_into().map(Some)
}
}
}
impl TryFrom<AttrValue> for Option<u16> {
type Error = Error;
fn try_from(value: AttrValue) -> Result<Self> {
if value.is_nil() {
Ok(None)
} else {
value.try_into().map(Some)
}
}
}
impl TryFrom<AttrValue> for Option<u32> {
type Error = Error;
fn try_from(value: AttrValue) -> Result<Self> {
if value.is_nil() {
Ok(None)
} else {
value.try_into().map(Some)
}
}
}
impl TryFrom<AttrValue> for Option<u64> {
type Error = Error;
fn try_from(value: AttrValue) -> Result<Self> {
if value.is_nil() {
Ok(None)
} else {
value.try_into().map(Some)
}
}
}
impl TryFrom<AttrValue> for Option<usize> {
type Error = Error;
fn try_from(value: AttrValue) -> Result<Self> {
if value.is_nil() {
Ok(None)
} else {
value.try_into().map(Some)
}
}
}
impl TryFrom<AttrValue> for Option<i8> {
type Error = Error;
fn try_from(value: AttrValue) -> Result<Self> {
if value.is_nil() {
Ok(None)
} else {
value.try_into().map(Some)
}
}
}
impl TryFrom<AttrValue> for Option<i16> {
type Error = Error;
fn try_from(value: AttrValue) -> Result<Self> {
if value.is_nil() {
Ok(None)
} else {
value.try_into().map(Some)
}
}
}
impl TryFrom<AttrValue> for Option<i32> {
type Error = Error;
fn try_from(value: AttrValue) -> Result<Self> {
if value.is_nil() {
Ok(None)
} else {
value.try_into().map(Some)
}
}
}
impl TryFrom<AttrValue> for Option<i64> {
type Error = Error;
fn try_from(value: AttrValue) -> Result<Self> {
if value.is_nil() {
Ok(None)
} else {
value.try_into().map(Some)
}
}
}
impl TryFrom<AttrValue> for Option<isize> {
type Error = Error;
fn try_from(value: AttrValue) -> Result<Self> {
if value.is_nil() {
Ok(None)
} else {
value.try_into().map(Some)
}
}
}
impl TryFrom<AttrValue> for Option<f32> {
type Error = Error;
fn try_from(value: AttrValue) -> Result<Self> {
if value.is_nil() {
Ok(None)
} else {
value.try_into().map(Some)
}
}
}
impl TryFrom<AttrValue> for Option<f64> {
type Error = Error;
fn try_from(value: AttrValue) -> Result<Self> {
if value.is_nil() {
Ok(None)
} else {
value.try_into().map(Some)
}
}
}
impl TryFrom<AttrValue> for Option<bool> {
type Error = Error;
fn try_from(value: AttrValue) -> Result<Self> {
if value.is_nil() {
Ok(None)
} else {
value.try_into().map(Some)
}
}
}
impl TryFrom<AttrValue> for Option<String> {
type Error = Error;
fn try_from(value: AttrValue) -> Result<Self> {
if value.is_nil() {
Ok(None)
} else {
value.try_into().map(Some)
}
}
}
impl<T> TryFrom<AttrValue> for Option<Vec<T>>
where
T: TryFrom<AttrValue> + Clone,
Error: From<<T as TryFrom<AttrValue>>::Error>,
{
type Error = Error;
fn try_from(value: AttrValue) -> Result<Self> {
if value.is_nil() {
Ok(None)
} else {
value.try_into().map(Some)
}
}
}
impl<T> TryFrom<AttrValue> for Option<HashSet<T>>
where
T: TryFrom<AttrValue> + Eq + Hash + Clone,
Error: From<<T as TryFrom<AttrValue>>::Error>,
{
type Error = Error;
fn try_from(value: AttrValue) -> Result<Self> {
if value.is_nil() {
Ok(None)
} else {
value.try_into().map(Some)
}
}
}
impl<T> TryFrom<AttrValue> for Option<BTreeSet<T>>
where
T: TryFrom<AttrValue> + Ord + Clone,
Error: From<<T as TryFrom<AttrValue>>::Error>,
{
type Error = Error;
fn try_from(value: AttrValue) -> Result<Self> {
if value.is_nil() {
Ok(None)
} else {
value.try_into().map(Some)
}
}
}
impl<T, U> TryFrom<AttrValue> for Option<HashMap<T, U>>
where
T: TryFrom<AttrValue> + Eq + Hash + Ord,
U: TryFrom<AttrValue>,
Error: From<<T as TryFrom<AttrValue>>::Error>,
Error: From<<U as TryFrom<AttrValue>>::Error>,
{
type Error = Error;
fn try_from(value: AttrValue) -> Result<Self> {
if value.is_nil() {
Ok(None)
} else {
value.try_into().map(Some)
}
}
}
impl<T, U> TryFrom<AttrValue> for Option<BTreeMap<T, U>>
where
T: TryFrom<AttrValue> + Ord,
U: TryFrom<AttrValue>,
Error: From<<T as TryFrom<AttrValue>>::Error>,
Error: From<<U as TryFrom<AttrValue>>::Error>,
{
type Error = Error;
fn try_from(value: AttrValue) -> Result<Self> {
if value.is_nil() {
Ok(None)
} else {
value.try_into().map(Some)
}
}
}
#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
pub enum AttrValueType {
Invalid,
Nil,
Unsigned(u64),
Signed(i64),
Bool(bool),
String(String),
Float(OrderedFloat<f64>),
Object(*mut ConfObject),
Data(Box<[u8]>),
List(Vec<Self>),
Dict(BTreeMap<Self, Self>),
}
impl AttrValueType {
pub fn is_invalid(&self) -> bool {
matches!(self, Self::Invalid)
}
pub fn is_nil(&self) -> bool {
matches!(self, Self::Nil)
}
pub fn is_integer(&self) -> bool {
matches!(self, Self::Signed(_) | Self::Unsigned(_))
}
pub fn is_signed(&self) -> bool {
matches!(self, Self::Signed(_))
}
pub fn is_unsigned(&self) -> bool {
matches!(self, Self::Unsigned(_))
}
pub fn is_boolean(&self) -> bool {
matches!(self, Self::Bool(_))
}
pub fn is_string(&self) -> bool {
matches!(self, Self::String(_))
}
pub fn is_floating(&self) -> bool {
matches!(self, Self::Float(_))
}
pub fn is_object(&self) -> bool {
matches!(self, Self::Object(_))
}
pub fn is_data(&self) -> bool {
matches!(self, Self::Data(_))
}
pub fn is_list(&self) -> bool {
matches!(self, Self::List(_))
}
pub fn is_dict(&self) -> bool {
matches!(self, Self::Dict(_))
}
pub fn kind(&self) -> AttrKind {
match self {
Self::Invalid => AttrKind::Sim_Val_Invalid,
Self::Nil => AttrKind::Sim_Val_Nil,
Self::Unsigned(_) => AttrKind::Sim_Val_Integer,
Self::Signed(_) => AttrKind::Sim_Val_Integer,
Self::Bool(_) => AttrKind::Sim_Val_Boolean,
Self::String(_) => AttrKind::Sim_Val_String,
Self::Float(_) => AttrKind::Sim_Val_Floating,
Self::Object(_) => AttrKind::Sim_Val_Object,
Self::Data(_) => AttrKind::Sim_Val_Data,
Self::List(_) => AttrKind::Sim_Val_List,
Self::Dict(_) => AttrKind::Sim_Val_Dict,
}
}
pub fn as_invalid(&self) -> Option<()> {
self.is_invalid().then_some(())
}
pub fn as_nil(&self) -> Option<()> {
self.is_nil().then_some(())
}
pub fn as_unsigned(&self) -> Option<u64> {
match self {
Self::Unsigned(u) => Some(*u),
_ => None,
}
}
pub fn as_signed(&self) -> Option<i64> {
match self {
Self::Signed(i) => Some(*i),
_ => None,
}
}
pub fn as_boolean(&self) -> Option<bool> {
match self {
Self::Bool(b) => Some(*b),
_ => None,
}
}
pub fn as_string(&self) -> Option<String> {
match self {
Self::String(s) => Some(s.clone()),
_ => None,
}
}
pub fn as_float(&self) -> Option<f64> {
match self {
Self::Float(f) => Some(f.0),
_ => None,
}
}
pub fn as_object(&self) -> Option<*mut ConfObject> {
match self {
Self::Object(o) => Some(*o),
_ => None,
}
}
pub fn as_data(&self) -> Option<*mut c_void> {
match self {
Self::Data(d) => Some(d.as_ptr() as *mut c_void),
_ => None,
}
}
pub fn as_list(&self) -> Option<Vec<AttrValueType>> {
match self {
Self::List(l) => Some(l.clone()),
_ => None,
}
}
pub fn as_dict(&self) -> Option<BTreeMap<AttrValueType, AttrValueType>> {
match self {
Self::Dict(d) => Some(d.clone()),
_ => None,
}
}
}
macro_rules! impl_attr_value_type_from {
($t:ty, $($variant:tt)+) => {
impl From<$t> for AttrValueType {
fn from(value: $t) -> Self {
$($variant)+(value.into())
}
}
};
}
impl_attr_value_type_from! { u8, Self::Unsigned }
impl_attr_value_type_from! { u16, Self::Unsigned }
impl_attr_value_type_from! { u32, Self::Unsigned }
impl_attr_value_type_from! { u64, Self::Unsigned }
impl_attr_value_type_from! { i8, Self::Signed }
impl_attr_value_type_from! { i16, Self::Signed }
impl_attr_value_type_from! { i32, Self::Signed }
impl_attr_value_type_from! { i64, Self::Signed }
impl_attr_value_type_from! { f64, Self::Float }
impl_attr_value_type_from! { bool, Self::Bool}
impl_attr_value_type_from! { String, Self::String }
impl From<usize> for AttrValueType {
fn from(value: usize) -> Self {
Self::Unsigned(value as u64)
}
}
impl From<isize> for AttrValueType {
fn from(value: isize) -> Self {
Self::Signed(value as i64)
}
}
impl From<&str> for AttrValueType {
fn from(value: &str) -> Self {
Self::String(value.to_string())
}
}
impl From<PathBuf> for AttrValueType {
fn from(value: PathBuf) -> Self {
value
.to_str()
.ok_or_else(|| Error::ToString)
.map(|s| s.to_string().into())
.expect("Failed to convert pathbuf to string")
}
}
impl<T> From<Vec<T>> for AttrValueType
where
T: Into<AttrValueType>,
{
fn from(value: Vec<T>) -> Self {
Self::List(value.into_iter().map(|i| i.into()).collect::<Vec<_>>())
}
}
impl<T> From<BTreeSet<T>> for AttrValueType
where
T: Into<AttrValueType>,
{
fn from(value: BTreeSet<T>) -> Self {
Self::List(value.into_iter().map(|i| i.into()).collect::<Vec<_>>())
}
}
impl<T> From<HashSet<T>> for AttrValueType
where
T: Into<AttrValueType>,
{
fn from(value: HashSet<T>) -> Self {
Self::List(value.into_iter().map(|i| i.into()).collect::<Vec<_>>())
}
}
impl<T, U> From<BTreeMap<T, U>> for AttrValueType
where
T: Into<AttrValueType>,
U: Into<AttrValueType>,
{
fn from(value: BTreeMap<T, U>) -> Self {
Self::Dict(
value
.into_iter()
.map(|(k, v)| (k.into(), v.into()))
.collect::<BTreeMap<_, _>>(),
)
}
}
impl<T, U> From<HashMap<T, U>> for AttrValueType
where
T: Into<AttrValueType>,
U: Into<AttrValueType>,
{
fn from(value: HashMap<T, U>) -> Self {
Self::Dict(
value
.into_iter()
.map(|(k, v)| (k.into(), v.into()))
.collect::<BTreeMap<_, _>>(),
)
}
}
impl<T> From<Option<T>> for AttrValueType
where
T: Into<AttrValueType>,
{
fn from(value: Option<T>) -> Self {
if let Some(value) = value {
value.into()
} else {
Self::Nil
}
}
}
impl From<AttrValue> for AttrValueType {
fn from(value: AttrValue) -> Self {
if value.is_nil() {
Self::Nil
} else if let Some(i) = value.as_signed() {
Self::Signed(i)
} else if let Some(i) = value.as_unsigned() {
Self::Unsigned(i)
} else if let Some(b) = value.as_boolean() {
Self::Bool(b)
} else if let Some(s) = value.as_string() {
Self::String(s)
} else if let Some(f) = value.as_floating() {
Self::Float(OrderedFloat(f))
} else if let Some(o) = value.as_object() {
Self::Object(o)
} else if let Some(d) = value.as_data() {
Self::Data(d)
} else if let Some(l) = value.as_list() {
Self::List(l)
} else if let Some(d) = value.as_dict() {
Self::Dict(d)
} else {
Self::Invalid
}
}
}
impl From<AttrValueType> for AttrValue {
fn from(value: AttrValueType) -> Self {
match value {
AttrValueType::Invalid => AttrValue::invalid(),
AttrValueType::Nil => AttrValue::nil(),
AttrValueType::Unsigned(u) => AttrValue::unsigned(u),
AttrValueType::Signed(s) => AttrValue::signed(s),
AttrValueType::Bool(b) => AttrValue::boolean(b),
AttrValueType::String(s) => AttrValue::string_unchecked(&s),
AttrValueType::Float(f) => AttrValue::floating(f.0),
AttrValueType::Object(o) => AttrValue::object(o),
AttrValueType::Data(d) => AttrValue::data(d),
AttrValueType::List(l) => l
.try_into()
.map_err(|_| unreachable!("Conversion from Vec<AttrValueType> is infallible"))
.expect("Conversion from Vec<AttrValueType> is infallible"),
AttrValueType::Dict(d) => d
.try_into()
.map_err(|_| {
unreachable!(
"Conversion from BTreeMap<AttrValueType, AttrValueType> is infallible"
)
})
.expect("Conversion from BTreeMap<AttrValueType, AttrValueType> is infallible"),
}
}
}
impl TryFrom<AttrValueType> for u8 {
type Error = Error;
fn try_from(value: AttrValueType) -> Result<Self> {
if let Some(unsigned) = value.as_unsigned() {
unsigned.try_into().map_err(Error::from)
} else if let Some(signed) = value.as_signed() {
if signed >= 0 {
signed.try_into().map_err(Error::from)
} else {
Err(Error::FromAttrValueTypeConversionError {
ty: type_name::<u8>().to_string(),
reason: "Negative value cannot be converted to unsigned".to_string(),
})
}
} else {
Err(Error::FromAttrValueTypeConversionError {
ty: type_name::<u8>().to_string(),
reason: "Value is not an integer".to_string(),
})
}
}
}
impl TryFrom<AttrValueType> for u16 {
type Error = Error;
fn try_from(value: AttrValueType) -> Result<Self> {
if let Some(unsigned) = value.as_unsigned() {
unsigned.try_into().map_err(Error::from)
} else if let Some(signed) = value.as_signed() {
if signed >= 0 {
signed.try_into().map_err(Error::from)
} else {
Err(Error::FromAttrValueTypeConversionError {
ty: type_name::<u16>().to_string(),
reason: "Negative value cannot be converted to unsigned".to_string(),
})
}
} else {
Err(Error::FromAttrValueTypeConversionError {
ty: type_name::<u16>().to_string(),
reason: "Value is not an integer".to_string(),
})
}
}
}
impl TryFrom<AttrValueType> for u32 {
type Error = Error;
fn try_from(value: AttrValueType) -> Result<Self> {
if let Some(unsigned) = value.as_unsigned() {
unsigned.try_into().map_err(Error::from)
} else if let Some(signed) = value.as_signed() {
if signed >= 0 {
signed.try_into().map_err(Error::from)
} else {
Err(Error::FromAttrValueTypeConversionError {
ty: type_name::<u32>().to_string(),
reason: "Negative value cannot be converted to unsigned".to_string(),
})
}
} else {
Err(Error::FromAttrValueTypeConversionError {
ty: type_name::<u32>().to_string(),
reason: "Value is not an integer".to_string(),
})
}
}
}
impl TryFrom<AttrValueType> for u64 {
type Error = Error;
fn try_from(value: AttrValueType) -> Result<Self> {
if let Some(unsigned) = value.as_unsigned() {
Ok(unsigned)
} else if let Some(signed) = value.as_signed() {
if signed >= 0 {
signed.try_into().map_err(Error::from)
} else {
Err(Error::FromAttrValueTypeConversionError {
ty: type_name::<u64>().to_string(),
reason: "Negative value cannot be converted to unsigned".to_string(),
})
}
} else {
Err(Error::FromAttrValueTypeConversionError {
ty: type_name::<u64>().to_string(),
reason: "Value is not an integer".to_string(),
})
}
}
}
impl TryFrom<AttrValueType> for usize {
type Error = Error;
fn try_from(value: AttrValueType) -> Result<Self> {
if let Some(unsigned) = value.as_unsigned() {
unsigned.try_into().map_err(Error::from)
} else if let Some(signed) = value.as_signed() {
if signed >= 0 {
signed.try_into().map_err(Error::from)
} else {
Err(Error::FromAttrValueTypeConversionError {
ty: type_name::<usize>().to_string(),
reason: "Negative value cannot be converted to unsigned".to_string(),
})
}
} else {
Err(Error::FromAttrValueTypeConversionError {
ty: type_name::<usize>().to_string(),
reason: "Value is not an integer".to_string(),
})
}
}
}
impl TryFrom<AttrValueType> for i8 {
type Error = Error;
fn try_from(value: AttrValueType) -> Result<Self> {
if let Some(signed) = value.as_signed() {
signed.try_into().map_err(Error::from)
} else if let Some(unsigned) = value.as_unsigned() {
if unsigned <= i8::MAX as u64 {
unsigned.try_into().map_err(Error::from)
} else {
Err(Error::FromAttrValueTypeConversionError {
ty: type_name::<i8>().to_string(),
reason: "Value is too large to be converted to signed".to_string(),
})
}
} else {
Err(Error::FromAttrValueTypeConversionError {
ty: type_name::<i8>().to_string(),
reason: "Value is not an integer".to_string(),
})
}
}
}
impl TryFrom<AttrValueType> for i16 {
type Error = Error;
fn try_from(value: AttrValueType) -> Result<Self> {
if let Some(signed) = value.as_signed() {
signed.try_into().map_err(Error::from)
} else if let Some(unsigned) = value.as_unsigned() {
if unsigned <= i16::MAX as u64 {
unsigned.try_into().map_err(Error::from)
} else {
Err(Error::FromAttrValueTypeConversionError {
ty: type_name::<i16>().to_string(),
reason: "Value is too large to be converted to signed".to_string(),
})
}
} else {
Err(Error::FromAttrValueTypeConversionError {
ty: type_name::<i16>().to_string(),
reason: "Value is not an integer".to_string(),
})
}
}
}
impl TryFrom<AttrValueType> for i32 {
type Error = Error;
fn try_from(value: AttrValueType) -> Result<Self> {
if let Some(signed) = value.as_signed() {
signed.try_into().map_err(Error::from)
} else if let Some(unsigned) = value.as_unsigned() {
if unsigned <= i32::MAX as u64 {
unsigned.try_into().map_err(Error::from)
} else {
Err(Error::FromAttrValueTypeConversionError {
ty: type_name::<i32>().to_string(),
reason: "Value is too large to be converted to signed".to_string(),
})
}
} else {
Err(Error::FromAttrValueTypeConversionError {
ty: type_name::<i32>().to_string(),
reason: "Value is not an integer".to_string(),
})
}
}
}
impl TryFrom<AttrValueType> for i64 {
type Error = Error;
fn try_from(value: AttrValueType) -> Result<Self> {
if let Some(signed) = value.as_signed() {
Ok(signed)
} else if let Some(unsigned) = value.as_unsigned() {
if unsigned <= i64::MAX as u64 {
unsigned.try_into().map_err(Error::from)
} else {
Err(Error::FromAttrValueTypeConversionError {
ty: type_name::<i64>().to_string(),
reason: "Value is too large to be converted to signed".to_string(),
})
}
} else {
Err(Error::FromAttrValueTypeConversionError {
ty: type_name::<i64>().to_string(),
reason: "Value is not an integer".to_string(),
})
}
}
}
impl TryFrom<AttrValueType> for isize {
type Error = Error;
fn try_from(value: AttrValueType) -> Result<Self> {
if let Some(signed) = value.as_signed() {
signed.try_into().map_err(Error::from)
} else if let Some(unsigned) = value.as_unsigned() {
if unsigned <= isize::MAX as u64 {
unsigned.try_into().map_err(Error::from)
} else {
Err(Error::FromAttrValueTypeConversionError {
ty: type_name::<isize>().to_string(),
reason: "Value is too large to be converted to signed".to_string(),
})
}
} else {
Err(Error::FromAttrValueTypeConversionError {
ty: type_name::<isize>().to_string(),
reason: "Value is not an integer".to_string(),
})
}
}
}
impl TryFrom<AttrValueType> for f32 {
type Error = Error;
fn try_from(value: AttrValueType) -> Result<Self> {
if let Some(f) = value.as_float() {
Ok(f as f32)
} else {
Err(Error::FromAttrValueTypeConversionError {
ty: type_name::<f32>().to_string(),
reason: "Value is not a floating-point number".to_string(),
})
}
}
}
impl TryFrom<AttrValueType> for f64 {
type Error = Error;
fn try_from(value: AttrValueType) -> Result<Self> {
if let Some(f) = value.as_float() {
Ok(f)
} else {
Err(Error::FromAttrValueTypeConversionError {
ty: type_name::<f64>().to_string(),
reason: "Value is not a floating-point number".to_string(),
})
}
}
}
impl TryFrom<AttrValueType> for bool {
type Error = Error;
fn try_from(value: AttrValueType) -> Result<Self> {
if let Some(b) = value.as_boolean() {
Ok(b)
} else {
Err(Error::FromAttrValueTypeConversionError {
ty: type_name::<bool>().to_string(),
reason: "Value is not a boolean".to_string(),
})
}
}
}
impl TryFrom<AttrValueType> for String {
type Error = Error;
fn try_from(value: AttrValueType) -> Result<Self> {
if let Some(s) = value.as_string() {
Ok(s)
} else {
Err(Error::FromAttrValueTypeConversionError {
ty: type_name::<String>().to_string(),
reason: "Value is not a string".to_string(),
})
}
}
}
impl<T> TryFrom<AttrValueType> for Vec<T>
where
T: TryFrom<AttrValueType>,
Error: From<<T as TryFrom<AttrValueType>>::Error>,
{
type Error = Error;
fn try_from(value: AttrValueType) -> Result<Self> {
value
.as_list()
.ok_or_else(|| Error::FromAttrValueTypeConversionError {
ty: type_name::<Vec<AttrValueType>>().to_string(),
reason: "Value is not a list".to_string(),
})?
.into_iter()
.map(|a| {
a.try_into()
.map_err(|e| Error::NestedFromAttrValueTypeConversionError {
ty: type_name::<T>().to_string(),
source: Box::new(Error::from(e)),
})
})
.collect::<Result<Vec<_>>>()
}
}
impl<T> TryFrom<AttrValueType> for HashSet<T>
where
T: TryFrom<AttrValueType> + Eq + Hash,
Error: From<<T as TryFrom<AttrValueType>>::Error>,
{
type Error = Error;
fn try_from(value: AttrValueType) -> Result<Self> {
Ok(value
.as_list()
.ok_or_else(|| Error::FromAttrValueTypeConversionError {
ty: type_name::<Vec<AttrValueType>>().to_string(),
reason: "Value is not a list".to_string(),
})?
.into_iter()
.map(|e| {
e.try_into()
.map_err(|e| Error::NestedFromAttrValueTypeConversionError {
ty: type_name::<T>().to_string(),
source: Box::new(Error::from(e)),
})
})
.collect::<Result<Vec<_>>>()?
.into_iter()
.collect::<HashSet<_>>())
}
}
impl<T> TryFrom<AttrValueType> for BTreeSet<T>
where
T: TryFrom<AttrValueType> + Ord,
Error: From<<T as TryFrom<AttrValueType>>::Error>,
{
type Error = Error;
fn try_from(value: AttrValueType) -> Result<Self> {
Ok(value
.as_list()
.ok_or_else(|| Error::FromAttrValueTypeConversionError {
ty: type_name::<Vec<AttrValueType>>().to_string(),
reason: "Value is not a list".to_string(),
})?
.into_iter()
.map(|e| {
e.try_into()
.map_err(|e| Error::NestedFromAttrValueTypeConversionError {
ty: type_name::<T>().to_string(),
source: Box::new(Error::from(e)),
})
})
.collect::<Result<Vec<_>>>()?
.into_iter()
.collect::<BTreeSet<_>>())
}
}
impl<T, U> TryFrom<AttrValueType> for HashMap<T, U>
where
T: TryFrom<AttrValueType> + Eq + Hash,
U: TryFrom<AttrValueType>,
Error: From<<T as TryFrom<AttrValueType>>::Error>,
Error: From<<U as TryFrom<AttrValueType>>::Error>,
{
type Error = Error;
fn try_from(value: AttrValueType) -> Result<Self> {
Ok(value
.as_dict()
.ok_or_else(|| Error::FromAttrValueTypeConversionError {
ty: type_name::<Vec<AttrValueType>>().to_string(),
reason: "Value is not a dict".to_string(),
})?
.into_iter()
.map(|(k, v)| {
k.try_into()
.map_err(|e| Error::NestedFromAttrValueTypeConversionError {
ty: type_name::<T>().to_string(),
source: Box::new(Error::from(e)),
})
.and_then(|k| {
v.try_into()
.map_err(|e| Error::NestedFromAttrValueTypeConversionError {
ty: type_name::<U>().to_string(),
source: Box::new(Error::from(e)),
})
.map(|v| (k, v))
})
})
.collect::<Result<Vec<(_, _)>>>()?
.into_iter()
.collect::<HashMap<_, _>>())
}
}
impl<T, U> TryFrom<AttrValueType> for BTreeMap<T, U>
where
T: TryFrom<AttrValueType> + Ord,
U: TryFrom<AttrValueType>,
Error: From<<T as TryFrom<AttrValueType>>::Error>,
Error: From<<U as TryFrom<AttrValueType>>::Error>,
{
type Error = Error;
fn try_from(value: AttrValueType) -> Result<Self> {
Ok(value
.as_dict()
.ok_or_else(|| Error::FromAttrValueTypeConversionError {
ty: type_name::<Vec<AttrValueType>>().to_string(),
reason: "Value is not a dict".to_string(),
})?
.into_iter()
.map(|(k, v)| {
k.try_into()
.map_err(|e| Error::NestedFromAttrValueTypeConversionError {
ty: type_name::<T>().to_string(),
source: Box::new(Error::from(e)),
})
.and_then(|k| {
v.try_into()
.map_err(|e| Error::NestedFromAttrValueTypeConversionError {
ty: type_name::<U>().to_string(),
source: Box::new(Error::from(e)),
})
.map(|v| (k, v))
})
})
.collect::<Result<Vec<(_, _)>>>()?
.into_iter()
.collect::<BTreeMap<_, _>>())
}
}
impl TryFrom<AttrValueType> for Option<u8> {
type Error = Error;
fn try_from(value: AttrValueType) -> Result<Self> {
if value.is_nil() {
Ok(None)
} else {
value.try_into().map(Some)
}
}
}
impl TryFrom<AttrValueType> for Option<u16> {
type Error = Error;
fn try_from(value: AttrValueType) -> Result<Self> {
if value.is_nil() {
Ok(None)
} else {
value.try_into().map(Some)
}
}
}
impl TryFrom<AttrValueType> for Option<u32> {
type Error = Error;
fn try_from(value: AttrValueType) -> Result<Self> {
if value.is_nil() {
Ok(None)
} else {
value.try_into().map(Some)
}
}
}
impl TryFrom<AttrValueType> for Option<u64> {
type Error = Error;
fn try_from(value: AttrValueType) -> Result<Self> {
if value.is_nil() {
Ok(None)
} else {
value.try_into().map(Some)
}
}
}
impl TryFrom<AttrValueType> for Option<usize> {
type Error = Error;
fn try_from(value: AttrValueType) -> Result<Self> {
if value.is_nil() {
Ok(None)
} else {
value.try_into().map(Some)
}
}
}
impl TryFrom<AttrValueType> for Option<i8> {
type Error = Error;
fn try_from(value: AttrValueType) -> Result<Self> {
if value.is_nil() {
Ok(None)
} else {
value.try_into().map(Some)
}
}
}
impl TryFrom<AttrValueType> for Option<i16> {
type Error = Error;
fn try_from(value: AttrValueType) -> Result<Self> {
if value.is_nil() {
Ok(None)
} else {
value.try_into().map(Some)
}
}
}
impl TryFrom<AttrValueType> for Option<i32> {
type Error = Error;
fn try_from(value: AttrValueType) -> Result<Self> {
if value.is_nil() {
Ok(None)
} else {
value.try_into().map(Some)
}
}
}
impl TryFrom<AttrValueType> for Option<i64> {
type Error = Error;
fn try_from(value: AttrValueType) -> Result<Self> {
if value.is_nil() {
Ok(None)
} else {
value.try_into().map(Some)
}
}
}
impl TryFrom<AttrValueType> for Option<isize> {
type Error = Error;
fn try_from(value: AttrValueType) -> Result<Self> {
if value.is_nil() {
Ok(None)
} else {
value.try_into().map(Some)
}
}
}
impl TryFrom<AttrValueType> for Option<f32> {
type Error = Error;
fn try_from(value: AttrValueType) -> Result<Self> {
if value.is_nil() {
Ok(None)
} else {
value.try_into().map(Some)
}
}
}
impl TryFrom<AttrValueType> for Option<f64> {
type Error = Error;
fn try_from(value: AttrValueType) -> Result<Self> {
if value.is_nil() {
Ok(None)
} else {
value.try_into().map(Some)
}
}
}
impl TryFrom<AttrValueType> for Option<bool> {
type Error = Error;
fn try_from(value: AttrValueType) -> Result<Self> {
if value.is_nil() {
Ok(None)
} else {
value.try_into().map(Some)
}
}
}
impl TryFrom<AttrValueType> for Option<String> {
type Error = Error;
fn try_from(value: AttrValueType) -> Result<Self> {
if value.is_nil() {
Ok(None)
} else {
value.try_into().map(Some)
}
}
}
impl<T> TryFrom<AttrValueType> for Option<Vec<T>>
where
T: TryFrom<AttrValueType> + Clone,
Error: From<<T as TryFrom<AttrValueType>>::Error>,
{
type Error = Error;
fn try_from(value: AttrValueType) -> Result<Self> {
if value.is_nil() {
Ok(None)
} else {
value.try_into().map(Some)
}
}
}
impl<T> TryFrom<AttrValueType> for Option<HashSet<T>>
where
T: TryFrom<AttrValueType> + Eq + Hash + Clone,
Error: From<<T as TryFrom<AttrValueType>>::Error>,
{
type Error = Error;
fn try_from(value: AttrValueType) -> Result<Self> {
if value.is_nil() {
Ok(None)
} else {
value.try_into().map(Some)
}
}
}
impl<T> TryFrom<AttrValueType> for Option<BTreeSet<T>>
where
T: TryFrom<AttrValueType> + Ord + Clone,
Error: From<<T as TryFrom<AttrValueType>>::Error>,
{
type Error = Error;
fn try_from(value: AttrValueType) -> Result<Self> {
if value.is_nil() {
Ok(None)
} else {
value.try_into().map(Some)
}
}
}
impl<T, U> TryFrom<AttrValueType> for Option<HashMap<T, U>>
where
T: TryFrom<AttrValueType> + Eq + Hash + Ord,
U: TryFrom<AttrValueType>,
Error: From<<T as TryFrom<AttrValueType>>::Error>,
Error: From<<U as TryFrom<AttrValueType>>::Error>,
{
type Error = Error;
fn try_from(value: AttrValueType) -> Result<Self> {
if value.is_nil() {
Ok(None)
} else {
value.try_into().map(Some)
}
}
}
impl<T, U> TryFrom<AttrValueType> for Option<BTreeMap<T, U>>
where
T: TryFrom<AttrValueType> + Ord,
U: TryFrom<AttrValueType>,
Error: From<<T as TryFrom<AttrValueType>>::Error>,
Error: From<<U as TryFrom<AttrValueType>>::Error>,
{
type Error = Error;
fn try_from(value: AttrValueType) -> Result<Self> {
if value.is_nil() {
Ok(None)
} else {
value.try_into().map(Some)
}
}
}
pub fn make_attr_invalid() -> AttrValue {
AttrValue::invalid()
}
pub fn make_attr_nil() -> AttrValue {
AttrValue::nil()
}
pub fn make_attr_uint64(u: u64) -> AttrValue {
u.into()
}
pub fn make_attr_int64(i: i64) -> AttrValue {
i.into()
}
pub fn make_attr_boolean(b: bool) -> AttrValue {
b.into()
}
pub fn make_attr_string<S>(s: S) -> AttrValue
where
S: AsRef<str>,
{
s.as_ref().into()
}
pub fn make_attr_floating(d: f64) -> AttrValue {
d.into()
}
pub fn make_attr_object(obj: *mut ConfObject) -> AttrValue {
obj.into()
}
pub fn make_attr_data<T>(data: &T) -> Result<AttrValue>
where
T: Clone,
{
let data = Box::new(data.clone());
let data_raw = Box::into_raw(data);
debug_assert!(
std::mem::size_of_val(&data_raw) == std::mem::size_of::<*mut std::ffi::c_void>(),
"Pointer is not convertible to *mut c_void"
);
let data_size = u32::try_from(size_of::<*mut T>())?;
if !data_raw.is_null() || data_size == 0 {
Err(Error::InvalidNullDataSize)
} else {
Ok(AttrValue(attr_value_t {
private_kind: AttrKind::Sim_Val_Data,
private_size: data_size,
private_u: attr_value__bindgen_ty_1 {
data: data_raw as *mut u8,
},
}))
}
}
pub fn make_attr_data_adopt<T>(data: T) -> Result<AttrValue> {
let data = Box::new(data);
let data_raw = Box::into_raw(data);
debug_assert!(
std::mem::size_of_val(&data_raw) == std::mem::size_of::<*mut std::ffi::c_void>(),
"Pointer is not convertible to *mut c_void"
);
let data_size = u32::try_from(size_of::<*mut T>())?;
if !data_raw.is_null() || data_size == 0 {
Err(Error::InvalidNullDataSize)
} else {
Ok(AttrValue(attr_value_t {
private_kind: AttrKind::Sim_Val_Data,
private_size: data_size,
private_u: attr_value__bindgen_ty_1 {
data: data_raw as *mut u8,
},
}))
}
}
pub fn make_attr_list<T>(attrs: Vec<T>) -> Result<AttrValue>
where
T: TryInto<AttrValue>,
Error: From<<T as TryInto<AttrValue>>::Error>,
{
attrs.try_into()
}
#[simics_exception]
pub fn alloc_attr_list(length: u32) -> AttrValue {
AttrValue(unsafe { SIM_alloc_attr_list(length) })
}
pub fn make_attr_dict(attrs: Vec<(AttrValue, AttrValue)>) -> Result<AttrValue> {
attrs.try_into()
}
#[simics_exception]
pub fn alloc_attr_dict(length: u32) -> AttrValue {
AttrValue(unsafe { SIM_alloc_attr_dict(length) })
}
#[simics_exception]
pub fn attr_list_set_item<E>(attr: &mut AttrValue, index: u32, elem: E)
where
E: Into<AttrValue>,
{
unsafe { SIM_attr_list_set_item(attr.as_mut_ptr(), index, elem.into().into()) }
}
#[simics_exception]
pub fn attr_list_resize(attr: &mut AttrValue, newsize: u32) {
unsafe { SIM_attr_list_resize(attr.as_mut_ptr(), newsize) };
}
#[simics_exception]
pub fn attr_dict_set_item<E>(attr: &mut AttrValue, index: u32, key: E, value: E)
where
E: Into<AttrValue>,
{
unsafe {
SIM_attr_dict_set_item(
attr.as_mut_ptr(),
index,
key.into().into(),
value.into().into(),
)
};
}
#[simics_exception]
pub fn attr_dict_resize(attr: &mut AttrValue, newsize: u32) {
unsafe { SIM_attr_dict_resize(attr.as_mut_ptr(), newsize) };
}
pub fn attr_is_nil(attr: &AttrValue) -> bool {
attr.kind() == AttrKind::Sim_Val_Nil
}
pub fn attr_is_int64(attr: &AttrValue) -> bool {
attr.is_integer() && (attr.size() == 0 || attr.as_integer().is_some_and(|i| i < 0))
}
pub fn attr_is_uint64(attr: &AttrValue) -> bool {
attr.is_integer() && (attr.size() != 0 || attr.as_integer().is_some_and(|i| i >= 0))
}
pub fn attr_is_integer(attr: &AttrValue) -> bool {
attr.is_integer()
}
pub fn attr_is_boolean(attr: &AttrValue) -> bool {
attr.is_boolean()
}
pub fn attr_is_string(attr: &AttrValue) -> bool {
attr.is_string()
}
pub fn attr_is_object(attr: &AttrValue) -> bool {
attr.is_object()
}
pub fn attr_is_invalid(attr: &AttrValue) -> bool {
attr.is_invalid()
}
pub fn attr_is_data(attr: &AttrValue) -> bool {
attr.is_data()
}
pub fn attr_is_floating(attr: &AttrValue) -> bool {
attr.is_floating()
}
pub fn attr_is_dict(attr: &AttrValue) -> bool {
attr.is_dict()
}
pub fn attr_is_list(attr: &AttrValue) -> bool {
attr.is_list()
}
pub fn attr_integer(attr: &AttrValue) -> Result<i64> {
attr.as_integer().ok_or_else(|| Error::AttrValueType {
actual: attr.kind(),
expected: AttrKind::Sim_Val_Integer,
reason: "The value is not an integer".to_string(),
})
}
pub fn attr_boolean(attr: &AttrValue) -> Result<bool> {
attr.as_boolean().ok_or_else(|| Error::AttrValueType {
actual: attr.kind(),
expected: AttrKind::Sim_Val_Boolean,
reason: "The value is not a boolean".to_string(),
})
}
pub fn attr_string(attr: &AttrValue) -> Result<String> {
attr.as_string().ok_or_else(|| Error::AttrValueType {
actual: attr.kind(),
expected: AttrKind::Sim_Val_String,
reason: "The value is not a string".to_string(),
})
}
pub fn attr_floating(attr: &AttrValue) -> Result<f64> {
attr.as_floating().ok_or_else(|| Error::AttrValueType {
actual: attr.kind(),
expected: AttrKind::Sim_Val_Floating,
reason: "The value is not a floating point number".to_string(),
})
}
pub fn attr_object(attr: &AttrValue) -> Result<*mut ConfObject> {
attr.as_object().ok_or_else(|| Error::AttrValueType {
actual: attr.kind(),
expected: AttrKind::Sim_Val_Object,
reason: "The value is not a ConfObject pointer".to_string(),
})
}
pub fn attr_object_or_nil(attr: &AttrValue) -> *mut ConfObject {
attr.as_object().unwrap_or(null_mut())
}
pub fn attr_data_size(attr: &AttrValue) -> Result<u32> {
attr.is_data()
.then(|| attr.size())
.ok_or_else(|| Error::AttrValueType {
actual: attr.kind(),
expected: AttrKind::Sim_Val_Data,
reason: "The value is not data".to_string(),
})
}
pub fn attr_data<T>(attr: &AttrValue) -> Result<T>
where
T: Clone,
{
attr.as_data().ok_or_else(|| Error::AttrValueType {
actual: attr.kind(),
expected: AttrKind::Sim_Val_Data,
reason: "The value is not data".to_string(),
})
}
pub fn attr_list_size(attr: &AttrValue) -> Result<u32> {
attr.is_list()
.then(|| attr.size())
.ok_or_else(|| Error::AttrValueType {
actual: attr.kind(),
expected: AttrKind::Sim_Val_List,
reason: "The value is not a list".to_string(),
})
}
pub fn attr_list_item(attr: &AttrValue, index: usize) -> Result<AttrValue> {
let list: Vec<AttrValue> = attr.as_list().ok_or_else(|| Error::AttrValueType {
actual: attr.kind(),
expected: AttrKind::Sim_Val_List,
reason: "The value is not a list".to_string(),
})?;
list.get(index)
.cloned()
.ok_or(Error::AttrValueListIndexOutOfBounds {
index,
length: list.len(),
})
}
pub fn attr_dict_size(attr: &AttrValue) -> Result<u32> {
attr.is_dict()
.then(|| attr.size())
.ok_or(Error::AttrValueType {
actual: attr.kind(),
expected: AttrKind::Sim_Val_Data,
reason: "The value is not a dict".to_string(),
})
}
pub fn attr_dict_key(attr: &AttrValue, index: u32) -> Result<AttrValue> {
if index < attr.size() {
attr.is_dict()
.then(|| {
AttrValue(
Box::leak(unsafe {
Box::from_raw(attr.0.private_u.dict.offset(index as isize))
})
.key,
)
})
.ok_or_else(|| Error::AttrValueType {
actual: attr.kind(),
expected: AttrKind::Sim_Val_Dict,
reason: "The value is not a dict".to_string(),
})
} else {
Err(Error::AttrValueDictIndexOutOfBounds {
index: index as usize,
size: attr.size() as usize,
})
}
}
pub fn attr_dict_value(attr: &AttrValue, index: u32) -> Result<AttrValue> {
if index < attr.size() {
attr.is_dict()
.then(|| {
AttrValue(
Box::leak(unsafe {
Box::from_raw(attr.0.private_u.dict.offset(index as isize))
})
.value,
)
})
.ok_or_else(|| Error::AttrValueType {
actual: attr.kind(),
expected: AttrKind::Sim_Val_Dict,
reason: "The value is not a dict".to_string(),
})
} else {
Err(Error::AttrValueDictIndexOutOfBounds {
index: index as usize,
size: attr.size() as usize,
})
}
}
#[simics_exception]
pub fn free_attribute(attr: AttrValue) {
unsafe { SIM_free_attribute(attr.0) }
}