Skip to main content

hive_rs/types/
account.rs

1use std::collections::BTreeMap;
2
3use serde::de::Error as _;
4use serde::{Deserialize, Serialize};
5use serde_json::Value;
6
7use crate::types::Operation;
8
9fn deserialize_stringified<'de, D>(deserializer: D) -> std::result::Result<String, D::Error>
10where
11    D: serde::Deserializer<'de>,
12{
13    let value = Value::deserialize(deserializer)?;
14    match value {
15        Value::String(text) => Ok(text),
16        Value::Number(number) => Ok(number.to_string()),
17        other => Err(D::Error::custom(format!(
18            "expected string or number, got {other}"
19        ))),
20    }
21}
22
23fn deserialize_opt_stringified<'de, D>(
24    deserializer: D,
25) -> std::result::Result<Option<String>, D::Error>
26where
27    D: serde::Deserializer<'de>,
28{
29    Option::<Value>::deserialize(deserializer)?
30        .map(|value| match value {
31            Value::String(text) => Ok(text),
32            Value::Number(number) => Ok(number.to_string()),
33            other => Err(D::Error::custom(format!(
34                "expected string or number, got {other}"
35            ))),
36        })
37        .transpose()
38}
39
40#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
41pub struct ExtendedAccount {
42    pub name: String,
43    #[serde(default, deserialize_with = "deserialize_opt_stringified")]
44    pub reputation: Option<String>,
45    #[serde(default)]
46    pub memo_key: Option<String>,
47    #[serde(flatten)]
48    pub extra: BTreeMap<String, Value>,
49}
50
51#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Default)]
52pub struct AccountReputation {
53    pub account: String,
54    #[serde(deserialize_with = "deserialize_stringified")]
55    pub reputation: String,
56}
57
58#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
59pub struct OwnerHistory {
60    #[serde(default)]
61    pub account: Option<String>,
62    #[serde(default)]
63    pub previous_owner_authority: Option<Value>,
64    #[serde(default)]
65    pub last_valid_time: Option<String>,
66    #[serde(flatten)]
67    pub extra: BTreeMap<String, Value>,
68}
69
70#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
71pub struct RecoveryRequest {
72    #[serde(default)]
73    pub account_to_recover: Option<String>,
74    #[serde(default)]
75    pub recovery_account: Option<String>,
76    #[serde(default)]
77    pub new_owner_authority: Option<Value>,
78    #[serde(default)]
79    pub expires: Option<String>,
80    #[serde(flatten)]
81    pub extra: BTreeMap<String, Value>,
82}
83
84#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
85pub struct AccountHistoryEntry {
86    pub index: u64,
87    #[serde(default)]
88    pub timestamp: Option<String>,
89    #[serde(default)]
90    pub op: Option<Operation>,
91    #[serde(flatten)]
92    pub extra: BTreeMap<String, Value>,
93}
94
95#[cfg(test)]
96mod tests {
97    use serde_json::json;
98
99    use crate::types::{AccountReputation, ExtendedAccount};
100
101    #[test]
102    fn extended_account_supports_numeric_reputation() {
103        let account: ExtendedAccount = serde_json::from_value(json!({
104            "name": "beggars",
105            "reputation": 0,
106            "memo_key": "STM1111111111111111111111111111111114T1Anm",
107        }))
108        .expect("account should deserialize");
109
110        assert_eq!(account.name, "beggars");
111        assert_eq!(account.reputation.as_deref(), Some("0"));
112    }
113
114    #[test]
115    fn account_reputation_supports_numeric_reputation() {
116        let reputation: AccountReputation = serde_json::from_value(json!({
117            "account": "alice",
118            "reputation": 12345,
119        }))
120        .expect("reputation should deserialize");
121
122        assert_eq!(reputation.account, "alice");
123        assert_eq!(reputation.reputation, "12345");
124    }
125}