use std::borrow::Cow;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(transparent)]
pub struct Symbol(Cow<'static, str>);
impl Symbol {
pub const fn from_static(s: &'static str) -> Self {
Symbol(Cow::Borrowed(s))
}
pub fn as_str(&self) -> &str {
&self.0
}
pub fn is_spot(&self) -> bool {
self.0.starts_with('@')
}
pub fn is_perp(&self) -> bool {
!self.is_spot()
}
}
impl std::fmt::Display for Symbol {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
impl AsRef<str> for Symbol {
fn as_ref(&self) -> &str {
self.as_str()
}
}
impl From<&'static str> for Symbol {
fn from(s: &'static str) -> Self {
Symbol(Cow::Borrowed(s))
}
}
impl From<String> for Symbol {
fn from(s: String) -> Self {
Symbol(Cow::Owned(s))
}
}
impl From<&String> for Symbol {
fn from(s: &String) -> Self {
Symbol(Cow::Owned(s.clone()))
}
}
impl From<&Symbol> for Symbol {
fn from(s: &Symbol) -> Self {
s.clone()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_symbol_creation() {
let static_sym = Symbol::from_static("BTC");
assert_eq!(static_sym.as_str(), "BTC");
assert!(static_sym.is_perp());
assert!(!static_sym.is_spot());
let owned_sym = Symbol::from("ETH".to_string());
assert_eq!(owned_sym.as_str(), "ETH");
let spot_sym = Symbol::from_static("@107");
assert!(spot_sym.is_spot());
assert!(!spot_sym.is_perp());
}
#[test]
fn test_symbol_conversions() {
let sym: Symbol = "BTC".into();
assert_eq!(sym.as_str(), "BTC");
let sym: Symbol = String::from("ETH").into();
assert_eq!(sym.as_str(), "ETH");
let s = String::from("SOL");
let sym: Symbol = (&s).into();
assert_eq!(sym.as_str(), "SOL");
}
#[test]
fn test_symbol_equality() {
let sym1 = Symbol::from_static("BTC");
let sym2 = Symbol::from("BTC".to_string());
assert_eq!(sym1, sym2);
}
}