use std::{borrow::Cow, fmt};
#[allow(missing_docs)]
pub const MINECRAFT_NAMESPACE: &str = "minecraft";
use crate::api::{ModelIdentifier, ResourceKind};
#[derive(Clone, PartialEq, Eq, Hash)]
pub struct ResourceLocation<'a> {
pub(crate) id: Cow<'a, str>,
pub(crate) kind: ResourceKind,
}
impl<'a> ResourceLocation<'a> {
pub fn new(kind: ResourceKind, id: &'a str) -> Self {
Self {
id: Cow::Borrowed(id),
kind,
}
}
pub fn new_owned(kind: ResourceKind, id: String) -> ResourceLocation<'static> {
ResourceLocation {
id: Cow::Owned(id),
kind,
}
}
pub fn blockstates(block_id: &'a str) -> Self {
Self::new(ResourceKind::BlockStates, block_id)
}
pub fn block_model(block_id: &'a str) -> Self {
Self::new(ResourceKind::BlockModel, block_id)
}
pub fn item_model(item_id: &'a str) -> Self {
Self::new(ResourceKind::ItemModel, item_id)
}
pub fn texture(path: &'a str) -> Self {
Self::new(ResourceKind::Texture, path)
}
pub fn as_str(&self) -> &str {
&self.id
}
pub fn has_namespace(&self) -> bool {
self.colon_position().is_some()
}
pub fn namespace(&self) -> &str {
self.colon_position()
.map(|index| &self.id[..index])
.unwrap_or_else(|| MINECRAFT_NAMESPACE)
}
pub fn path(&self) -> &str {
if self.is_model() {
ModelIdentifier::model_name(&self.id)
} else {
&self.id
}
}
pub fn kind(&self) -> ResourceKind {
self.kind
}
pub fn is_builtin(&self) -> bool {
if self.is_model() {
ModelIdentifier::is_builtin(&self.id)
} else {
false
}
}
pub fn to_canonical(&self) -> ResourceLocation<'a> {
if self.has_namespace() {
self.clone()
} else {
let canonical = format!("{}:{}", self.namespace(), self.as_str());
Self {
id: Cow::Owned(canonical),
kind: self.kind,
}
}
}
pub fn to_owned(&self) -> ResourceLocation<'static> {
ResourceLocation {
id: Cow::Owned(self.id.clone().into_owned()),
kind: self.kind,
}
}
pub(crate) fn is_model(&self) -> bool {
matches!(
self.kind,
ResourceKind::BlockModel | ResourceKind::ItemModel
)
}
fn colon_position(&self) -> Option<usize> {
self.id.chars().position(|c| c == ':')
}
}
impl<'a> AsRef<str> for ResourceLocation<'a> {
fn as_ref(&self) -> &str {
&self.id
}
}
impl<'a> fmt::Debug for ResourceLocation<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let kind = format!("{:?}", self.kind);
write!(f, "{}({:?})", kind, &self.id)
}
}
impl<'a> fmt::Display for ResourceLocation<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.to_canonical().as_str())
}
}