Skip to main content

std_mel/data/string_map/
mod.rs

1use melodium_core::{executive::*, *};
2use melodium_macro::{check, mel_data, mel_function, mel_treatment};
3use std::collections::HashMap;
4use std::sync::Arc;
5
6pub mod block;
7
8#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
9/// A `string`→`string` map; serialisable and equatable.
10///
11/// Commonly used for environment variables and HTTP headers.
12/// Supports `entry`, `get`, `insert`, and `merge` operations.
13/// Later entries with the same key overwrite earlier ones.
14#[mel_data(traits(Serialize Deserialize PartialEquality Equality))]
15pub struct StringMap {
16    pub map: HashMap<String, String>,
17}
18
19impl StringMap {
20    pub fn new() -> Self {
21        Self {
22            map: HashMap::new(),
23        }
24    }
25
26    pub fn new_with(map: HashMap<String, String>) -> Self {
27        Self { map }
28    }
29}
30
31impl Display for StringMap {
32    fn display(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
33        write!(f, "{:#?}", self)
34    }
35}
36
37/// Build a `StringMap` by merging a list of single-entry maps.
38///
39/// Each element in `entries` should be produced by `|entry(key, value)`.
40/// Later entries with the same key overwrite earlier ones.
41#[mel_function]
42pub fn map(entries: Vec<StringMap>) -> StringMap {
43    let mut map = HashMap::new();
44    for submap in entries {
45        map.extend(submap.map);
46    }
47    StringMap { map }
48}
49
50/// Build a single-entry `StringMap` mapping `key` to `value`.
51///
52/// Typically used as an argument to `|map([...])` to construct multi-entry maps.
53#[mel_function]
54pub fn entry(key: string, value: string) -> StringMap {
55    let mut map = HashMap::new();
56    map.insert(key, value);
57    StringMap { map }
58}
59
60/// For every `value` received on the stream, produce a single-entry `StringMap` with `key` → `value` and emit it on `map`.
61#[mel_treatment(
62    input value Stream<string>
63    output map Stream<StringMap>
64)]
65pub async fn entry(key: string) {
66    while let Ok(value) = value
67        .recv_one()
68        .await
69        .map(|val| GetData::<String>::try_data(val).unwrap())
70    {
71        let mut new_map = HashMap::new();
72        new_map.insert(key.clone(), value);
73        let new_map = StringMap { map: new_map };
74        check!(map.send_one(Value::Data(Arc::new(new_map))).await)
75    }
76}
77
78/// Look up `key` in `map` and return its value, or `none` if the key is absent.
79#[mel_function]
80pub fn get(map: StringMap, key: string) -> Option<string> {
81    map.map.get(&key).cloned()
82}
83
84/// For every `map` received on the stream, look up `key` and emit the result as `Option<string>` on `value`.
85#[mel_treatment(
86    input map Stream<StringMap>
87    output value Stream<Option<string>>
88)]
89pub async fn get(key: string) {
90    while let Ok(map) = map.recv_one().await.map(|val| {
91        GetData::<Arc<dyn Data>>::try_data(val)
92            .unwrap()
93            .downcast_arc::<StringMap>()
94            .unwrap()
95    }) {
96        check!(value.send_one(map.map.get(&key).cloned().into()).await)
97    }
98}
99
100/// Return a copy of `map` with `key` set to `value`, overwriting any existing entry for that key.
101#[mel_function]
102pub fn insert(mut map: StringMap, key: string, value: string) -> StringMap {
103    map.map.insert(key, value);
104    map
105}
106
107/// For every (`base`, `value`) pair received from the two streams, insert `key` → `value` into a copy of `base` and emit it on `map`.
108#[mel_treatment(
109    input base Stream<StringMap>
110    input value Stream<string>
111    output map Stream<StringMap>
112)]
113pub async fn insert(key: string) {
114    while let (Ok(base), Ok(value)) = (
115        base.recv_one().await.map(|val| {
116            GetData::<Arc<dyn Data>>::try_data(val)
117                .unwrap()
118                .downcast_arc::<StringMap>()
119                .unwrap()
120        }),
121        value
122            .recv_one()
123            .await
124            .map(|val| GetData::<String>::try_data(val).unwrap()),
125    ) {
126        let mut new_map = Arc::unwrap_or_clone(base);
127        new_map.map.insert(key.clone(), value);
128        check!(map.send_one(Value::Data(Arc::new(new_map))).await)
129    }
130}