actioncable/
identifier.rs1use std::collections::BTreeMap;
2use std::fmt;
3
4use serde_json::Value;
5
6#[derive(Debug, Clone, PartialEq, Eq)]
22pub struct Identifier {
23 channel: String,
24 params: BTreeMap<String, Value>,
25}
26
27impl Identifier {
28 pub fn new(channel: impl Into<String>) -> Identifier {
30 Identifier {
31 channel: channel.into(),
32 params: BTreeMap::new(),
33 }
34 }
35
36 pub fn param(mut self, name: impl Into<String>, value: impl Into<Value>) -> Identifier {
38 self.params.insert(name.into(), value.into());
39 self
40 }
41
42 pub fn channel(&self) -> &str {
44 &self.channel
45 }
46
47 pub fn params(&self) -> &BTreeMap<String, Value> {
49 &self.params
50 }
51
52 #[allow(
58 clippy::expect_used,
59 reason = "serializing a map of Values has no failure mode to report"
60 )]
61 pub fn key(&self) -> String {
62 let mut fields = self.params.clone();
63 fields.insert("channel".to_string(), Value::String(self.channel.clone()));
64 serde_json::to_string(&fields).expect("a map of JSON values always encodes")
65 }
66}
67
68impl fmt::Display for Identifier {
69 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
70 f.write_str(&self.key())
71 }
72}
73
74#[cfg(test)]
75mod tests {
76 use super::*;
77
78 #[test]
79 fn the_key_is_the_sorted_json_encoding() {
80 let identifiers = [
81 (
82 Identifier::new("RoomChannel"),
83 r#"{"channel":"RoomChannel"}"#,
84 ),
85 (
86 Identifier::new("RoomChannel").param("id", 42),
87 r#"{"channel":"RoomChannel","id":42}"#,
88 ),
89 (
90 Identifier::new("RoomChannel")
91 .param("since", "yesterday")
92 .param("id", 42),
93 r#"{"channel":"RoomChannel","id":42,"since":"yesterday"}"#,
94 ),
95 (
96 Identifier::new("RoomChannel").param("channel", "impostor"),
97 r#"{"channel":"RoomChannel"}"#,
98 ),
99 ];
100
101 for (identifier, key) in identifiers {
102 assert_eq!(key, identifier.key());
103 assert_eq!(key, identifier.to_string());
104 }
105 }
106
107 #[test]
110 fn an_identifier_always_encodes() {
111 let identifier = Identifier::new("RoomChannel").param("id", f64::NAN);
112
113 assert_eq!(r#"{"channel":"RoomChannel","id":null}"#, identifier.key());
114 }
115}