use std::sync::Arc;
use crate::ArcLock;
#[cfg(feature = "urdf")]
use crate::to_rdf::to_urdf::ToURDF;
#[cfg(feature = "xml")]
use quick_xml::{events::attributes::Attribute, name::QName};
#[derive(Debug, PartialEq, Clone)]
pub enum MaterialData {
Color(f32, f32, f32, f32),
Texture(String),
}
#[cfg(feature = "urdf")]
impl ToURDF for MaterialData {
fn to_urdf(
&self,
writer: &mut quick_xml::Writer<std::io::Cursor<Vec<u8>>>,
_urdf_config: &crate::to_rdf::to_urdf::URDFConfig,
) -> Result<(), quick_xml::Error> {
match self {
MaterialData::Color(red, green, blue, alpha) => {
writer
.create_element("color")
.with_attribute(Attribute {
key: QName(b"rgba"),
value: format!("{} {} {} {}", red, green, blue, alpha)
.as_bytes()
.into(),
})
.write_empty()?;
Ok(())
}
MaterialData::Texture(texture_path) => {
writer
.create_element("texture")
.with_attribute(Attribute {
key: QName(b"filename"),
value: texture_path.clone().as_bytes().into(),
})
.write_empty()?;
Ok(())
}
}
}
}
#[derive(Debug)]
pub enum MaterialDataReferenceWrapper<'a> {
Direct(&'a MaterialData),
Global(ArcLock<MaterialData>),
}
impl<'a> MaterialDataReferenceWrapper<'a> {
pub fn same_material_data(&self, other: &MaterialDataReferenceWrapper) -> bool {
#[allow(unreachable_code)] match (self, other) {
(
MaterialDataReferenceWrapper::Direct(left),
MaterialDataReferenceWrapper::Direct(right),
) => left == right,
(
MaterialDataReferenceWrapper::Direct(left),
MaterialDataReferenceWrapper::Global(right),
) => match !right.is_poisoned() {
true => (*left).clone() == right.read().unwrap().clone(), false => {
*right.write().map_err(|err| err.into_inner()).unwrap() = (*left).clone();
todo!("Unpoisoning is still a nightly-only experimental feature. (mutex_unpoison #96469)");
true
}
},
(
MaterialDataReferenceWrapper::Global(left),
MaterialDataReferenceWrapper::Direct(right),
) => {
match !left.is_poisoned() {
true => (*right).clone() == left.read().unwrap().clone(), false => {
*left.write().map_err(|err| err.into_inner()).unwrap() = (*right).clone();
todo!("Unpoisoning is still a nightly-only experimental feature. (mutex_unpoison #96469)");
true
}
}
}
(
MaterialDataReferenceWrapper::Global(left),
MaterialDataReferenceWrapper::Global(right),
) => left.read().unwrap().clone() == right.read().unwrap().clone(), }
}
}
impl<'a> PartialEq for MaterialDataReferenceWrapper<'a> {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Self::Direct(l0), Self::Direct(r0)) => l0 == r0,
(Self::Global(l0), Self::Global(r0)) => Arc::ptr_eq(l0, r0),
_ => false,
}
}
}
impl<'a> From<&'a MaterialData> for MaterialDataReferenceWrapper<'a> {
fn from(value: &'a MaterialData) -> Self {
Self::Direct(value)
}
}
impl<'a> From<ArcLock<MaterialData>> for MaterialDataReferenceWrapper<'a> {
fn from(value: ArcLock<MaterialData>) -> Self {
MaterialDataReferenceWrapper::Global(value)
}
}
impl<'a> TryFrom<MaterialDataReferenceWrapper<'a>> for MaterialData {
type Error = std::sync::PoisonError<ArcLock<MaterialData>>;
fn try_from(value: MaterialDataReferenceWrapper) -> Result<Self, Self::Error> {
match value {
MaterialDataReferenceWrapper::Direct(data) => Ok(data.clone()),
MaterialDataReferenceWrapper::Global(arc_data) => {
let data_ref = arc_data
.read()
.map(|data| data.clone())
.map_err(|_| std::sync::PoisonError::new(Arc::clone(&arc_data)));
data_ref
}
}
}
}