skp_cache_core/traits/
key.rs1use std::fmt::Display;
4
5pub trait CacheKey: Send + Sync {
9 fn cache_key(&self) -> String;
11
12 fn namespace(&self) -> Option<&str> {
14 None
15 }
16
17 fn full_key(&self) -> String {
19 match self.namespace() {
20 Some(ns) => format!("{}:{}", ns, self.cache_key()),
21 None => self.cache_key(),
22 }
23 }
24}
25
26impl CacheKey for String {
29 fn cache_key(&self) -> String {
30 self.clone()
31 }
32}
33
34impl CacheKey for &str {
35 fn cache_key(&self) -> String {
36 self.to_string()
37 }
38}
39
40impl CacheKey for &String {
41 fn cache_key(&self) -> String {
42 (*self).clone()
43 }
44}
45
46impl<T: Display + Send + Sync> CacheKey for (T,) {
49 fn cache_key(&self) -> String {
50 self.0.to_string()
51 }
52}
53
54impl<T1: Display + Send + Sync, T2: Display + Send + Sync> CacheKey for (T1, T2) {
55 fn cache_key(&self) -> String {
56 format!("{}:{}", self.0, self.1)
57 }
58}
59
60impl<T1: Display + Send + Sync, T2: Display + Send + Sync, T3: Display + Send + Sync> CacheKey
61 for (T1, T2, T3)
62{
63 fn cache_key(&self) -> String {
64 format!("{}:{}:{}", self.0, self.1, self.2)
65 }
66}
67
68impl<
69 T1: Display + Send + Sync,
70 T2: Display + Send + Sync,
71 T3: Display + Send + Sync,
72 T4: Display + Send + Sync,
73 > CacheKey for (T1, T2, T3, T4)
74{
75 fn cache_key(&self) -> String {
76 format!("{}:{}:{}:{}", self.0, self.1, self.2, self.3)
77 }
78}
79
80#[derive(Debug, Clone)]
82pub struct CompositeKey {
83 parts: Vec<String>,
84 ns: Option<String>,
85}
86
87impl CompositeKey {
88 pub fn new() -> Self {
90 Self {
91 parts: Vec::new(),
92 ns: None,
93 }
94 }
95
96 pub fn with_namespace(mut self, ns: impl Into<String>) -> Self {
98 self.ns = Some(ns.into());
99 self
100 }
101
102 pub fn part(mut self, part: impl Display) -> Self {
104 self.parts.push(part.to_string());
105 self
106 }
107
108 pub fn parts<I, S>(mut self, parts: I) -> Self
110 where
111 I: IntoIterator<Item = S>,
112 S: Display,
113 {
114 self.parts.extend(parts.into_iter().map(|p| p.to_string()));
115 self
116 }
117
118 pub fn get_namespace(&self) -> Option<&str> {
120 self.ns.as_deref()
121 }
122}
123
124impl Default for CompositeKey {
125 fn default() -> Self {
126 Self::new()
127 }
128}
129
130impl CacheKey for CompositeKey {
131 fn cache_key(&self) -> String {
132 self.parts.join(":")
133 }
134
135 fn namespace(&self) -> Option<&str> {
136 self.ns.as_deref()
137 }
138}
139
140#[cfg(test)]
141mod tests {
142 use super::*;
143
144 #[test]
145 fn test_string_key() {
146 let key = "my_key".to_string();
147 assert_eq!(key.cache_key(), "my_key");
148 assert_eq!(key.full_key(), "my_key");
149 }
150
151 #[test]
152 fn test_str_key() {
153 let key = "my_key";
154 assert_eq!(key.cache_key(), "my_key");
155 }
156
157 #[test]
158 fn test_tuple_key_2() {
159 let key = ("user", 123);
160 assert_eq!(key.cache_key(), "user:123");
161 }
162
163 #[test]
164 fn test_tuple_key_3() {
165 let key = ("org", 1, "user");
166 assert_eq!(key.cache_key(), "org:1:user");
167 }
168
169 #[test]
170 fn test_composite_key() {
171 let key = CompositeKey::new()
172 .with_namespace("myapp")
173 .part("user")
174 .part(123);
175
176 assert_eq!(key.cache_key(), "user:123");
177 assert_eq!(key.get_namespace(), Some("myapp"));
178 assert_eq!(key.full_key(), "myapp:user:123");
179 }
180
181 #[test]
182 fn test_composite_key_no_namespace() {
183 let key = CompositeKey::new().part("session").part("abc123");
184
185 assert_eq!(key.cache_key(), "session:abc123");
186 assert_eq!(key.full_key(), "session:abc123");
187 }
188}