cratestack_core/context/
identity.rs1use std::collections::BTreeMap;
9
10use serde::{Deserialize, Serialize};
11
12use crate::error::CoolError;
13use crate::value::Value;
14
15#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
16pub struct CoolAuthIdentity {
17 pub fields: BTreeMap<String, Value>,
18}
19
20impl CoolAuthIdentity {
21 pub fn from_principal<P: Serialize>(principal: P) -> Result<Self, CoolError> {
22 let value = serde_json::to_value(principal).map_err(|error| {
23 CoolError::Internal(format!("failed to serialize auth principal: {error}"))
24 })?;
25 let serde_json::Value::Object(object) = value else {
26 return Err(CoolError::Internal(
27 "auth principal must serialize to a JSON object".to_owned(),
28 ));
29 };
30
31 let mut fields = BTreeMap::new();
32 for (key, value) in object {
33 fields.insert(key, json_value_to_cool_value(value)?);
34 }
35
36 Ok(Self { fields })
37 }
38}
39
40pub(super) fn json_value_to_cool_value(value: serde_json::Value) -> Result<Value, CoolError> {
43 match value {
44 serde_json::Value::Null => Ok(Value::Null),
45 serde_json::Value::Bool(value) => Ok(Value::Bool(value)),
46 serde_json::Value::Number(number) => {
47 if let Some(value) = number.as_i64() {
48 Ok(Value::Int(value))
49 } else if let Some(value) = number.as_f64() {
50 Ok(Value::Float(value))
51 } else {
52 Err(CoolError::Internal(format!(
53 "unsupported auth principal number '{number}'"
54 )))
55 }
56 }
57 serde_json::Value::String(value) => Ok(Value::String(value)),
58 serde_json::Value::Array(values) => values
59 .into_iter()
60 .map(json_value_to_cool_value)
61 .collect::<Result<Vec<_>, _>>()
62 .map(Value::List),
63 serde_json::Value::Object(object) => object
64 .into_iter()
65 .map(|(key, value)| json_value_to_cool_value(value).map(|value| (key, value)))
66 .collect::<Result<BTreeMap<_, _>, _>>()
67 .map(Value::Map),
68 }
69}