use std::{fmt, str::FromStr};
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct Symbol(String);
#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
#[error("{0:?} is not a Binance symbol: 1 to 32 letters, digits or underscores")]
pub struct InvalidSymbol(pub String);
impl polyoxide_venue::Classify for InvalidSymbol {
fn class(&self) -> polyoxide_venue::Class {
polyoxide_venue::Class::InvalidRequest
}
}
impl Symbol {
pub const MAX_LEN: usize = 32;
pub fn new(symbol: impl Into<String>) -> Result<Self, InvalidSymbol> {
let symbol = symbol.into();
let chars = symbol.chars().count();
let valid = (1..=Self::MAX_LEN).contains(&chars)
&& symbol.chars().all(|c| c.is_alphanumeric() || c == '_');
if valid {
Ok(Self(symbol.to_ascii_uppercase()))
} else {
Err(InvalidSymbol(symbol))
}
}
pub fn as_str(&self) -> &str {
&self.0
}
}
impl fmt::Display for Symbol {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(&self.0)
}
}
impl FromStr for Symbol {
type Err = InvalidSymbol;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Self::new(s)
}
}
impl AsRef<str> for Symbol {
fn as_ref(&self) -> &str {
&self.0
}
}