use std::fmt::Display;
use super::raw::IdentRaw;
#[derive(Clone, Debug, PartialEq, Serialize, Hash, Eq, Default)]
pub struct NodeId {
pub(crate) id: String,
pub(crate) module: Vec<String>,
}
impl<T: ToString> From<&T> for NodeId {
fn from(id: &T) -> Self {
Self {
id: id.to_string(),
module: vec![],
}
}
}
impl<'script> From<IdentRaw<'script>> for NodeId {
fn from(id: IdentRaw<'script>) -> Self {
Self {
id: id.id.to_string(),
module: vec![],
}
}
}
impl NodeId {
#[must_use]
pub fn new<T: ToString>(id: &T, module: &[String]) -> Self {
Self {
id: id.to_string(),
module: module.to_vec(),
}
}
#[must_use]
pub fn id(&self) -> &str {
self.id.as_str()
}
#[must_use]
pub fn module(&self) -> &[String] {
&self.module
}
pub fn module_mut(&mut self) -> &mut Vec<String> {
&mut self.module
}
#[must_use]
pub fn fqn(&self) -> String {
self.to_string()
}
#[must_use]
pub fn target_fqn(&self, target: &str) -> String {
if self.module.is_empty() {
target.to_string()
} else {
format!("{}::{}", self.module.join("::"), target)
}
}
}
impl Display for NodeId {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if self.module.is_empty() {
write!(f, "{}", self.id)
} else {
write!(f, "{}::{}", self.module.join("::"), self.id)
}
}
}
pub trait BaseRef {
fn fqn(&self) -> String;
}
#[doc(hidden)]
#[macro_export]
macro_rules! impl_fqn {
($struct:ident) => {
impl crate::ast::node_id::BaseRef for $struct<'_> {
fn fqn(&self) -> String {
self.node_id.fqn()
}
}
};
}
#[cfg(test)]
mod test {
use super::NodeId;
#[test]
fn fqn() {
let no_module = NodeId::new(&"foo", &[]);
assert_eq!(no_module.fqn(), "foo");
assert!(no_module.module().is_empty());
let with_module = NodeId::new(&"foo", &["bar".to_string(), "baz".to_string()]);
assert_eq!(with_module.fqn(), "bar::baz::foo");
assert_eq!(with_module.module(), &["bar", "baz"]);
let target = "quux";
assert_eq!(no_module.target_fqn(target), target);
assert_eq!(with_module.target_fqn(target), "bar::baz::quux");
}
}