Skip to main content

lash_core/provider/
spec.rs

1use super::support::*;
2
3/// Serialised form of a provider's host-owned configuration. Runtime
4/// persistence stores only provider ids; this type is for app/user config
5/// files that need credentials.
6///
7/// Wire shape is a flat JSON object: a `type` field plus the
8/// provider-specific config keys. This matches the legacy
9/// `~/.lash/config.json` shape so old configs load without migration.
10#[derive(Clone, Debug, PartialEq, Eq)]
11pub struct ProviderSpec {
12    pub kind: String,
13    pub config: serde_json::Value,
14}
15
16impl Serialize for ProviderSpec {
17    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
18        let mut value = match &self.config {
19            serde_json::Value::Object(map) => serde_json::Value::Object(map.clone()),
20            serde_json::Value::Null => serde_json::Value::Object(serde_json::Map::new()),
21            other => {
22                return Err(serde::ser::Error::custom(format!(
23                    "ProviderSpec.config must serialize to a JSON object, got {}",
24                    other
25                )));
26            }
27        };
28        if let serde_json::Value::Object(ref mut map) = value {
29            map.insert(
30                "type".to_string(),
31                serde_json::Value::String(self.kind.clone()),
32            );
33        }
34        value.serialize(serializer)
35    }
36}
37
38impl<'de> Deserialize<'de> for ProviderSpec {
39    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
40        let mut value = serde_json::Value::deserialize(deserializer)?;
41        let kind = if let serde_json::Value::Object(ref mut map) = value {
42            let raw = map
43                .remove("type")
44                .ok_or_else(|| serde::de::Error::missing_field("type"))?;
45            raw.as_str()
46                .ok_or_else(|| serde::de::Error::custom("provider `type` must be a string"))?
47                .to_string()
48        } else {
49            return Err(serde::de::Error::custom(
50                "provider spec must be a JSON object",
51            ));
52        };
53        Ok(Self {
54            kind,
55            config: value,
56        })
57    }
58}