From d77312309f53966ff8c90d9a460354db51e915ce Mon Sep 17 00:00:00 2001
From: Quaternions <krakow20@gmail.com>
Date: Thu, 10 Apr 2025 15:26:02 -0700
Subject: [PATCH] rbx_asset: helpers for integers within a string

---
 rbx_asset/src/cloud.rs | 14 ++++++++++----
 rbx_asset/src/lib.rs   |  1 +
 rbx_asset/src/util.rs  | 21 +++++++++++++++++++++
 src/main.rs            | 10 +++++-----
 4 files changed, 37 insertions(+), 9 deletions(-)
 create mode 100644 rbx_asset/src/util.rs

diff --git a/rbx_asset/src/cloud.rs b/rbx_asset/src/cloud.rs
index fae4f61..bdc5fd1 100644
--- a/rbx_asset/src/cloud.rs
+++ b/rbx_asset/src/cloud.rs
@@ -1,3 +1,4 @@
+use crate::util::{serialize_u64,deserialize_u64};
 use crate::{ResponseError,maybe_gzip_decode};
 
 #[derive(Debug,serde::Deserialize,serde::Serialize)]
@@ -65,8 +66,8 @@ pub struct UpdateAssetRequest{
 #[derive(Clone,Debug,serde::Deserialize,serde::Serialize)]
 #[allow(nonstandard_style,dead_code)]
 pub enum Creator{
-	userId(String),//u64 string
-	groupId(String),//u64 string
+	userId(#[serde(deserialize_with="deserialize_u64",serialize_with="serialize_u64")]u64),
+	groupId(#[serde(deserialize_with="deserialize_u64",serialize_with="serialize_u64")]u64),
 }
 #[derive(Debug,serde::Deserialize,serde::Serialize)]
 #[allow(nonstandard_style,dead_code)]
@@ -146,14 +147,19 @@ pub struct GetAssetLatestRequest{
 #[derive(Debug,serde::Deserialize,serde::Serialize)]
 #[allow(nonstandard_style,dead_code)]
 pub struct AssetResponse{
-	pub assetId:String,//u64 wrapped in quotes wohoo!!
+	//u64 wrapped in quotes wohoo!!
+	#[serde(deserialize_with="deserialize_u64")]
+	#[serde(serialize_with="serialize_u64")]
+	pub assetId:u64,
 	pub assetType:AssetType,
 	pub creationContext:CreationContext,
 	pub description:Option<String>,
 	pub displayName:String,
 	pub path:String,
 	pub revisionCreateTime:chrono::DateTime<chrono::Utc>,
-	pub revisionId:String,//u64
+	#[serde(deserialize_with="deserialize_u64")]
+	#[serde(serialize_with="serialize_u64")]
+	pub revisionId:u64,
 	pub moderationResult:ModerationResult,
 	pub icon:Option<String>,
 	#[serde(default)]
diff --git a/rbx_asset/src/lib.rs b/rbx_asset/src/lib.rs
index 0c6f8fb..7a5274a 100644
--- a/rbx_asset/src/lib.rs
+++ b/rbx_asset/src/lib.rs
@@ -1,5 +1,6 @@
 pub mod cloud;
 pub mod cookie;
+mod util;
 
 #[allow(dead_code)]
 #[derive(Debug)]
diff --git a/rbx_asset/src/util.rs b/rbx_asset/src/util.rs
new file mode 100644
index 0000000..24ae3d5
--- /dev/null
+++ b/rbx_asset/src/util.rs
@@ -0,0 +1,21 @@
+use serde::de::{Error,Unexpected};
+use serde::{Deserializer,Serializer};
+
+struct U64StringVisitor;
+impl serde::de::Visitor<'_> for U64StringVisitor{
+	type Value=u64;
+	fn expecting(&self,formatter:&mut std::fmt::Formatter)->std::fmt::Result{
+		write!(formatter,"string value with int")
+	}
+	fn visit_str<E:Error>(self,v:&str)->Result<Self::Value,E>{
+		v.parse().map_err(|_|E::invalid_value(Unexpected::Str(v),&"u64"))
+	}
+}
+
+pub(crate) fn deserialize_u64<'de,D:Deserializer<'de>>(deserializer:D)->Result<u64,D::Error>{
+	deserializer.deserialize_any(U64StringVisitor)
+}
+
+pub(crate) fn serialize_u64<S:Serializer>(v:&u64,serializer:S)->Result<S::Ok,S::Error>{
+	serializer.serialize_str(v.to_string().as_str())
+}
diff --git a/src/main.rs b/src/main.rs
index ba89009..b30aa28 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -563,8 +563,8 @@ async fn main()->AResult<()>{
 				subcommand.api_key_file,
 			).await?,
 			creator:match (subcommand.creator_user_id,subcommand.creator_group_id){
-				(Some(user_id),None)=>rbx_asset::cloud::Creator::userId(user_id.to_string()),
-				(None,Some(group_id))=>rbx_asset::cloud::Creator::groupId(group_id.to_string()),
+				(Some(user_id),None)=>rbx_asset::cloud::Creator::userId(user_id),
+				(None,Some(group_id))=>rbx_asset::cloud::Creator::groupId(group_id),
 				other=>Err(anyhow!("Invalid creator {other:?}"))?,
 			},
 			input_file:subcommand.input_file,
@@ -585,8 +585,8 @@ async fn main()->AResult<()>{
 				subcommand.cookie_file,
 			).await?,
 			creator:match (subcommand.creator_user_id,subcommand.creator_group_id){
-				(Some(user_id),None)=>rbx_asset::cloud::Creator::userId(user_id.to_string()),
-				(None,Some(group_id))=>rbx_asset::cloud::Creator::groupId(group_id.to_string()),
+				(Some(user_id),None)=>rbx_asset::cloud::Creator::userId(user_id),
+				(None,Some(group_id))=>rbx_asset::cloud::Creator::groupId(group_id),
 				other=>Err(anyhow!("Invalid creator {other:?}"))?,
 			},
 			description:subcommand.description.unwrap_or_else(||String::with_capacity(0)),
@@ -904,7 +904,7 @@ async fn create_asset_medias(config:CreateAssetMediasConfig)->AResult<()>{
 		async move{
 			let asset_response=asset_response_result.map_err(DownloadDecalError::PollOperation)?;
 			let file=cookie_context.get_asset(rbx_asset::cookie::GetAssetRequest{
-				asset_id:asset_response.assetId.parse().map_err(DownloadDecalError::ParseInt)?,
+				asset_id:asset_response.assetId,
 				version:None,
 			}).await.map_err(DownloadDecalError::Get)?;
 			let dom=load_dom(std::io::Cursor::new(file)).map_err(DownloadDecalError::LoadDom)?;