use crate::*;
#[cfg(feature = "bevy")]
use bevy::{
asset::{AssetPath, ParseAssetPathError},
prelude::{Component, Reflect, ReflectComponent},
};
use pathdiff::diff_paths;
use serde::{Deserialize, Serialize};
use std::path::{Path, PathBuf};
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[cfg_attr(feature = "bevy", derive(Component, Reflect))]
#[cfg_attr(feature = "bevy", reflect(Component))]
pub enum AssetSource {
Local(String),
Remote(String),
Search(String),
Package(String),
Memory(String),
}
impl AssetSource {
pub fn label(&self) -> &str {
match self {
Self::Local(_) => "Local",
Self::Remote(_) => "Remote",
Self::Search(_) => "Search",
Self::Package(_) => "Package",
Self::Memory(_) => "Memory",
}
}
pub fn is_local_relative(&self) -> bool {
if let Self::Local(asset_path) = self {
return Path::new(asset_path).is_relative();
}
return false;
}
pub fn migrate_relative_path(
&mut self,
old_reference_path: &PathBuf,
new_reference_path: &PathBuf,
) -> Result<(), ()> {
if let Self::Local(asset_path) = self {
if Path::new(asset_path).is_relative() {
println!("Changing path for [{asset_path:?}]");
let new_path = diff_paths(
old_reference_path.with_file_name(asset_path.clone()),
new_reference_path.parent().ok_or(())?,
)
.ok_or(())?;
*asset_path = new_path.to_str().ok_or(())?.to_owned();
}
}
Ok(())
}
pub unsafe fn as_unvalidated_asset_path(&self) -> String {
match self {
AssetSource::Remote(uri) => String::from("rmf-server://") + uri,
AssetSource::Local(filename) => String::from("file://") + filename,
AssetSource::Search(name) => String::from("search://") + name,
AssetSource::Package(path) => String::from("package://") + path,
AssetSource::Memory(path) => String::from("memory://") + path,
}
}
pub fn model_name(&self) -> String {
let asset_path = unsafe { self.as_unvalidated_asset_path() };
asset_path.split("/").last().unwrap().into()
}
pub fn with_base_path(self, base_path: Option<&PathBuf>) -> Self {
let Some(base_folder) = base_path else {
return self;
};
match self {
AssetSource::Local(filename) => {
let path = PathBuf::from(filename);
if path.is_relative() {
Self::Local(
base_folder
.with_file_name(path)
.to_string_lossy()
.into_owned(),
)
} else {
Self::Local(path.to_string_lossy().into_owned())
}
}
source => source,
}
}
}
impl Default for AssetSource {
fn default() -> Self {
AssetSource::Local(String::new()).into()
}
}
#[cfg(feature = "bevy")]
impl TryFrom<&AssetSource> for String {
type Error = ParseAssetPathError;
fn try_from(asset_source: &AssetSource) -> Result<String, ParseAssetPathError> {
let result = unsafe { asset_source.as_unvalidated_asset_path() };
AssetPath::try_parse(&result)
.map(|_| ()) .map(|_| result)
}
}
impl TryFrom<&str> for AssetSource {
type Error = String;
fn try_from(s: &str) -> Result<Self, Self::Error> {
if let Some(uri) = s.strip_prefix("rmf-server://") {
Ok(AssetSource::Remote(uri.to_owned()))
} else if let Some(uri) = s.strip_prefix("file://") {
Ok(AssetSource::Local(uri.to_owned()))
} else if let Some(uri) = s.strip_prefix("search://") {
Ok(AssetSource::Search(uri.to_owned()))
} else if let Some(uri) = s.strip_prefix("package://") {
Ok(AssetSource::Package(uri.to_owned()))
} else if let Some(uri) = s.strip_prefix("memory://") {
Ok(AssetSource::Memory(uri.to_owned()))
} else {
Err(format!("Unsupported asset type: {}", s))
}
}
}
#[derive(Clone, Debug, Default, PartialEq)]
#[cfg_attr(feature = "bevy", derive(Component))]
pub struct RecallAssetSource {
pub filename: Option<String>,
pub remote_uri: Option<String>,
pub search_name: Option<String>,
pub bundled_name: Option<String>,
pub package_path: Option<String>,
pub ros_resource: Option<String>,
pub map: Option<(i32, f32, f32)>,
}
impl Eq for RecallAssetSource {}
impl Recall for RecallAssetSource {
type Source = AssetSource;
fn remember(&mut self, source: &AssetSource) {
match source {
AssetSource::Local(name) => {
self.filename = Some(name.clone());
}
AssetSource::Remote(uri) => {
self.remote_uri = Some(uri.clone());
}
AssetSource::Search(name) => {
self.search_name = Some(name.clone());
}
AssetSource::Package(path) => {
self.package_path = Some(path.clone());
}
AssetSource::Memory(path) => {
self.ros_resource = Some(path.clone());
}
}
}
}