1use std::collections::HashMap;
2
3use serde::de::DeserializeOwned;
4use serde::{Deserialize, Serialize};
5use serde_json::Value;
6
7use crate::{ComponentReference, Error, InherentData};
8
9#[derive(Debug, Clone, PartialEq, Default, Serialize, Deserialize)]
10pub struct RuntimeConfig(HashMap<String, Value>);
11
12impl RuntimeConfig {
13 pub fn coerce_key<T>(&self, key: &str) -> Result<T, Error>
15 where
16 T: DeserializeOwned,
17 {
18 let value = self.0.get(key).ok_or_else(|| Error::ContextKey(key.to_owned()))?;
19 serde_json::from_value(value.clone()).map_err(|_| Error::ContextKey(key.to_owned()))
20 }
21
22 #[must_use]
24 pub fn has(&self, key: &str) -> bool {
25 self.0.contains_key(key)
26 }
27
28 #[must_use]
30 pub fn get(&self, key: &str) -> Option<&Value> {
31 self.0.get(key)
32 }
33
34 pub fn from_value(value: Value) -> Result<Self, Error> {
36 match value {
37 Value::Object(map) => {
38 let mut hm = HashMap::new();
39 for (k, v) in map {
40 hm.insert(k, v);
41 }
42 Ok(Self(hm))
43 }
44 _ => Err(Error::BadJson(value)),
45 }
46 }
47}
48
49impl IntoIterator for RuntimeConfig {
50 type Item = (String, Value);
51 type IntoIter = std::collections::hash_map::IntoIter<String, Value>;
52
53 fn into_iter(self) -> Self::IntoIter {
54 self.0.into_iter()
55 }
56}
57
58impl From<HashMap<String, Value>> for RuntimeConfig {
59 fn from(value: HashMap<String, Value>) -> Self {
60 Self(value)
61 }
62}
63
64impl From<RuntimeConfig> for HashMap<String, Value> {
65 fn from(value: RuntimeConfig) -> Self {
66 value.0
67 }
68}
69
70impl<K, const N: usize> From<[(K, Value); N]> for RuntimeConfig
71where
72 K: Into<String>,
73{
74 fn from(arr: [(K, Value); N]) -> Self {
88 Self(HashMap::from_iter(arr.into_iter().map(|(k, v)| (k.into(), v))))
89 }
90}
91
92impl TryFrom<Value> for RuntimeConfig {
93 type Error = Error;
94
95 fn try_from(value: Value) -> Result<Self, Self::Error> {
96 match value {
97 Value::Object(map) => {
98 let mut hm = HashMap::new();
99 for (k, v) in map {
100 hm.insert(k, v);
101 }
102 Ok(Self(hm))
103 }
104 _ => Err(Error::BadJson(value)),
105 }
106 }
107}
108
109#[derive(Deserialize, Serialize, Debug)]
110#[non_exhaustive]
111pub struct ContextTransport<T>
112where
113 T: std::fmt::Debug + Serialize,
114{
115 pub config: T,
116 pub inherent: InherentData,
117 pub invocation: Option<InvocationRequest>,
118}
119
120impl<T> ContextTransport<T>
121where
122 T: std::fmt::Debug + Serialize,
123{
124 pub const fn new(config: T, inherent: InherentData) -> Self {
125 Self {
126 config,
127 inherent,
128 invocation: None,
129 }
130 }
131}
132
133#[derive(Debug, Clone, Serialize, Deserialize)]
134#[non_exhaustive]
135#[must_use]
136pub struct InvocationRequest {
137 pub reference: ComponentReference,
138 pub operation: String,
139}