distant_net/common/packet/
header.rs

1use std::collections::HashMap;
2use std::ops::{Deref, DerefMut};
3use std::{fmt, io};
4
5use derive_more::IntoIterator;
6use serde::de::DeserializeOwned;
7use serde::{Deserialize, Serialize};
8
9use crate::common::{utils, Value};
10
11/// Generates a new [`Header`] of key/value pairs based on literals.
12///
13/// ```
14/// use distant_net::header;
15///
16/// let _header = header!("key" -> "value", "key2" -> 123);
17/// ```
18#[macro_export]
19macro_rules! header {
20    ($($key:literal -> $value:expr),* $(,)?) => {{
21        let mut _header = $crate::common::Header::default();
22
23        $(
24            _header.insert($key, $value);
25        )*
26
27        _header
28    }};
29}
30
31/// Represents a packet header comprised of arbitrary data tied to string keys.
32#[derive(Clone, Debug, Default, PartialEq, Eq, IntoIterator, Serialize, Deserialize)]
33#[serde(transparent)]
34pub struct Header(HashMap<String, Value>);
35
36impl Header {
37    /// Creates an empty [`Header`] newtype wrapper.
38    pub fn new() -> Self {
39        Self::default()
40    }
41
42    /// Exists purely to support serde serialization checks.
43    #[inline]
44    pub(crate) fn is_empty(&self) -> bool {
45        self.0.is_empty()
46    }
47
48    /// Inserts a key-value pair into the map.
49    ///
50    /// If the map did not have this key present, [`None`] is returned.
51    ///
52    /// If the map did have this key present, the value is updated, and the old value is returned.
53    /// The key is not updated, though; this matters for types that can be `==` without being
54    /// identical. See the [module-level documentation](std::collections#insert-and-complex-keys)
55    /// for more.
56    pub fn insert(&mut self, key: impl Into<String>, value: impl Into<Value>) -> Option<Value> {
57        self.0.insert(key.into(), value.into())
58    }
59
60    /// Retrieves a value from the header, attempting to convert it to the specified type `T`
61    /// by cloning the value and then converting it.
62    pub fn get_as<T>(&self, key: impl AsRef<str>) -> Option<io::Result<T>>
63    where
64        T: DeserializeOwned,
65    {
66        self.0
67            .get(key.as_ref())
68            .map(|value| value.clone().cast_as())
69    }
70
71    /// Serializes the header into bytes.
72    pub fn to_vec(&self) -> io::Result<Vec<u8>> {
73        utils::serialize_to_vec(self)
74    }
75
76    /// Deserializes the header from bytes.
77    pub fn from_slice(slice: &[u8]) -> io::Result<Self> {
78        utils::deserialize_from_slice(slice)
79    }
80}
81
82impl Deref for Header {
83    type Target = HashMap<String, Value>;
84
85    fn deref(&self) -> &Self::Target {
86        &self.0
87    }
88}
89
90impl DerefMut for Header {
91    fn deref_mut(&mut self) -> &mut Self::Target {
92        &mut self.0
93    }
94}
95
96impl fmt::Display for Header {
97    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
98        write!(f, "{{")?;
99
100        for (key, value) in self.0.iter() {
101            let value = serde_json::to_string(value).unwrap_or_else(|_| String::from("--"));
102            write!(f, "\"{key}\" = {value}")?;
103        }
104
105        write!(f, "}}")?;
106
107        Ok(())
108    }
109}