use rust_decimal::Decimal; use serde::{Deserialize, Serialize}; use std::{fmt::Display, str::FromStr}; use thiserror::Error; #[derive(Serialize, Deserialize, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default)] #[serde(transparent)] pub struct StockName(String); impl From for StockName { fn from(s: String) -> Self { Self(s) } } #[derive(Error, Debug)] pub enum StockNameParseError {} impl FromStr for StockName { type Err = StockNameParseError; fn from_str(s: &str) -> Result { Ok(Self(s.to_string())) } } #[derive(Serialize, Deserialize, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default)] #[serde(transparent)] pub struct StockSymbol(String); impl Display for StockSymbol { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "${}", self.0) } } impl From for StockSymbol { fn from(s: String) -> Self { Self(s) } } impl FromStr for StockSymbol { type Err = StockNameParseError; fn from_str(s: &str) -> Result { Ok(Self(s.to_string())) } } impl StockSymbol { pub fn inner(&self) -> &str { &self.0 } } #[derive(Serialize, Deserialize, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default)] #[serde(transparent)] pub struct StockDescription(String); impl From for StockDescription { fn from(s: String) -> Self { Self(s) } } #[derive(Serialize, Deserialize, Copy, Clone, PartialEq, PartialOrd, Debug, Default)] #[serde(transparent)] pub struct StockPrice(Decimal); impl From for StockPrice { fn from(p: Decimal) -> Self { Self(p) } } #[derive(Serialize, Deserialize, Clone, PartialEq, Debug)] pub struct Stock { name: StockName, symbol: StockSymbol, description: StockDescription, price: StockPrice, } impl Stock { pub fn new( name: impl Into, symbol: impl Into, description: impl Into, price: impl Into, ) -> Self { Self { name: name.into(), symbol: symbol.into(), description: description.into(), price: price.into(), } } }