use std::cmp::Ordering;
use std::convert::Infallible;
use std::fmt;
use std::hash::{Hash, Hasher};
use std::ops::Deref;
use std::str::FromStr;
use std::sync::Arc;
#[derive(Clone)]
pub struct Token(Repr);
#[derive(Clone)]
enum Repr {
Static(&'static str),
Shared(Arc<str>), }
impl Token {
pub const fn new(text: &'static str) -> Self {
Token(Repr::Static(text))
}
pub fn as_str(&self) -> &str {
match &self.0 {
Repr::Static(s) => s,
Repr::Shared(s) => s,
}
}
}
impl Default for Token {
fn default() -> Self {
Token(Repr::Static(""))
}
}
impl Deref for Token {
type Target = str;
fn deref(&self) -> &str {
self.as_str()
}
}
impl AsRef<str> for Token {
fn as_ref(&self) -> &str {
self.as_str()
}
}
impl From<&str> for Token {
fn from(text: &str) -> Self {
Token(Repr::Shared(Arc::from(text)))
}
}
impl From<String> for Token {
fn from(text: String) -> Self {
Token(Repr::Shared(Arc::from(text)))
}
}
impl From<&String> for Token {
fn from(text: &String) -> Self {
Token(Repr::Shared(Arc::from(text.as_str())))
}
}
impl From<&Token> for Token {
fn from(token: &Token) -> Self {
token.clone()
}
}
impl From<Token> for String {
fn from(token: Token) -> Self {
token.as_str().to_owned()
}
}
impl FromStr for Token {
type Err = Infallible;
fn from_str(text: &str) -> Result<Self, Self::Err> {
Ok(Token::from(text))
}
}
impl PartialEq for Token {
fn eq(&self, other: &Self) -> bool {
self.as_str() == other.as_str()
}
}
impl Eq for Token {}
impl PartialEq<str> for Token {
fn eq(&self, other: &str) -> bool {
self.as_str() == other
}
}
impl PartialEq<&str> for Token {
fn eq(&self, other: &&str) -> bool {
self.as_str() == *other
}
}
impl PartialEq<Token> for str {
fn eq(&self, other: &Token) -> bool {
self == other.as_str()
}
}
impl PartialEq<Token> for &str {
fn eq(&self, other: &Token) -> bool {
*self == other.as_str()
}
}
impl Hash for Token {
fn hash<H: Hasher>(&self, state: &mut H) {
self.as_str().hash(state);
}
}
impl PartialOrd for Token {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for Token {
fn cmp(&self, other: &Self) -> Ordering {
self.as_str().cmp(other.as_str())
}
}
impl fmt::Display for Token {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.as_str())
}
}
impl fmt::Debug for Token {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:?}", self.as_str())
}
}
#[cfg(feature = "serde")]
impl serde::Serialize for Token {
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
serializer.serialize_str(self.as_str())
}
}
#[cfg(test)]
mod tests {
use super::*;
const KIND: Token = Token::new("Xform");
#[test]
fn const_static_equals_runtime() {
let runtime = Token::from("Xform".to_string());
assert_eq!(KIND, runtime);
assert_eq!(KIND.as_str(), "Xform");
let mut set = std::collections::HashSet::new();
set.insert(runtime);
assert!(set.contains(&KIND));
}
#[test]
fn compares_with_str() {
assert_eq!(KIND, "Xform");
assert_eq!("Xform", KIND);
assert_ne!(KIND, "Mesh");
let name: &str = "Xform";
assert!(KIND == name);
assert!(name == KIND);
}
}