#[derive(Hash,Eq,PartialEq)] pub struct RobloxAssetId(pub u64); #[derive(Debug)] #[allow(dead_code)] pub struct StringWithError{ string:String, error:RobloxAssetIdParseErr, } impl std::fmt::Display for StringWithError{ fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{ write!(f,"{self:?}") } } impl std::error::Error for StringWithError{} impl StringWithError{ const fn new( string:String, error:RobloxAssetIdParseErr, )->Self{ Self{string,error} } } #[derive(Debug)] pub enum RobloxAssetIdParseErr{ Url(url::ParseError), UnknownScheme, ParseInt(std::num::ParseIntError), MissingAssetId, } impl std::str::FromStr for RobloxAssetId{ type Err=StringWithError; fn from_str(s:&str)->Result{ let url=url::Url::parse(s).map_err(|e|StringWithError::new(s.to_owned(),RobloxAssetIdParseErr::Url(e)))?; let parsed_asset_id=match url.scheme(){ "rbxassetid"=>url.domain().ok_or_else(||StringWithError::new(s.to_owned(),RobloxAssetIdParseErr::MissingAssetId))?.parse(), "http"|"https"=>{ let (_,asset_id)=url.query_pairs() .find(|(id,_)|match id.as_ref(){ "ID"|"id"|"Id"|"iD"=>true, _=>false, }).ok_or_else(||StringWithError::new(s.to_owned(),RobloxAssetIdParseErr::MissingAssetId))?; asset_id.parse() }, _=>Err(StringWithError::new(s.to_owned(),RobloxAssetIdParseErr::UnknownScheme))?, }; Ok(Self(parsed_asset_id.map_err(|e|StringWithError::new(s.to_owned(),RobloxAssetIdParseErr::ParseInt(e)))?)) } }