use serde::{Deserialize, Serialize};
use std::collections::BTreeMap;
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
pub struct AuthorizationDetail {
#[serde(rename = "type")]
pub detail_type: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub locations: Option<Vec<String>>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub actions: Option<Vec<String>>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub datatypes: Option<Vec<String>>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub identifier: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub privileges: Option<Vec<String>>,
#[serde(flatten)]
pub extra: BTreeMap<String, serde_json::Value>,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn serde_roundtrip_with_rfc9396_keyword() {
let detail = AuthorizationDetail {
detail_type: "tool_invocation".into(),
actions: Some(vec!["read".into()]),
identifier: Some("get_compensation".into()),
..Default::default()
};
let json = serde_json::to_string(&detail).unwrap();
assert!(json.contains(r#""type":"tool_invocation""#));
assert!(!json.contains("detail_type"));
let back: AuthorizationDetail = serde_json::from_str(&json).unwrap();
assert_eq!(back, detail);
}
#[test]
fn extra_fields_round_trip() {
let json = r#"{
"type": "payment",
"actions": ["initiate"],
"amount": "100.00",
"currency": "USD"
}"#;
let detail: AuthorizationDetail = serde_json::from_str(json).unwrap();
assert_eq!(detail.detail_type, "payment");
assert_eq!(
detail.extra.get("amount").and_then(|v| v.as_str()),
Some("100.00")
);
assert_eq!(
detail.extra.get("currency").and_then(|v| v.as_str()),
Some("USD")
);
}
}