1use crate::{Context, Key, KeyValue, StringValue};
22use std::collections::hash_map::Entry;
23use std::collections::{hash_map, HashMap};
24use std::fmt;
25use std::sync::OnceLock;
26
27static DEFAULT_BAGGAGE: OnceLock<Baggage> = OnceLock::new();
28
29const MAX_KEY_VALUE_PAIRS: usize = 64;
30const MAX_LEN_OF_ALL_PAIRS: usize = 8192;
31
32const INVALID_ASCII_KEY_CHARS: [u8; 17] = *b"(),/:;<=>?@[\\]{}\"";
34
35#[inline]
37fn get_default_baggage() -> &'static Baggage {
38 DEFAULT_BAGGAGE.get_or_init(Baggage::default)
39}
40
41#[derive(Debug, Default)]
64pub struct Baggage {
65 inner: HashMap<Key, (StringValue, BaggageMetadata)>,
66 kv_content_len: usize, }
68
69impl Baggage {
70 pub fn new() -> Self {
72 Baggage {
73 inner: HashMap::default(),
74 kv_content_len: 0,
75 }
76 }
77
78 pub fn get<K: AsRef<str>>(&self, key: K) -> Option<&StringValue> {
91 self.inner.get(key.as_ref()).map(|(value, _metadata)| value)
92 }
93
94 pub fn get_with_metadata<K: AsRef<str>>(
107 &self,
108 key: K,
109 ) -> Option<&(StringValue, BaggageMetadata)> {
110 self.inner.get(key.as_ref())
111 }
112
113 pub fn insert<K, V>(&mut self, key: K, value: V) -> Option<StringValue>
129 where
130 K: Into<Key>,
131 V: Into<StringValue>,
132 {
133 self.insert_with_metadata(key, value, BaggageMetadata::default())
134 .map(|pair| pair.0)
135 }
136
137 pub fn insert_with_metadata<K, V, S>(
155 &mut self,
156 key: K,
157 value: V,
158 metadata: S,
159 ) -> Option<(StringValue, BaggageMetadata)>
160 where
161 K: Into<Key>,
162 V: Into<StringValue>,
163 S: Into<BaggageMetadata>,
164 {
165 let (key, value, metadata) = (key.into(), value.into(), metadata.into());
166 let entries_count = self.inner.len();
167 match self.inner.entry(key) {
168 Entry::Occupied(mut occupied_entry) => {
169 let key_str = occupied_entry.key().as_str();
170 let entry_content_len =
171 key_value_metadata_bytes_size(key_str, value.as_str(), metadata.as_str());
172 let prev_content_len = key_value_metadata_bytes_size(
173 key_str,
174 occupied_entry.get().0.as_str(),
175 occupied_entry.get().1.as_str(),
176 );
177 let new_content_len = self.kv_content_len + entry_content_len - prev_content_len;
178 if new_content_len > MAX_LEN_OF_ALL_PAIRS {
179 return None;
180 }
181 self.kv_content_len = new_content_len;
182 Some(occupied_entry.insert((value, metadata)))
183 }
184 Entry::Vacant(vacant_entry) => {
185 let key_str = vacant_entry.key().as_str();
186 if !Self::is_key_valid(key_str.as_bytes()) {
187 return None;
188 }
189 if entries_count == MAX_KEY_VALUE_PAIRS {
190 return None;
191 }
192 let entry_content_len =
193 key_value_metadata_bytes_size(key_str, value.as_str(), metadata.as_str());
194 let new_content_len = self.kv_content_len + entry_content_len;
195 if new_content_len > MAX_LEN_OF_ALL_PAIRS {
196 return None;
197 }
198 self.kv_content_len = new_content_len;
199 vacant_entry.insert((value, metadata));
200 None
201 }
202 }
203 }
204
205 pub fn remove<K: AsRef<str>>(&mut self, key: K) -> Option<(StringValue, BaggageMetadata)> {
208 self.inner.remove(key.as_ref())
209 }
210
211 pub fn len(&self) -> usize {
213 self.inner.len()
214 }
215
216 pub fn is_empty(&self) -> bool {
218 self.inner.is_empty()
219 }
220
221 pub fn iter(&self) -> Iter<'_> {
223 self.into_iter()
224 }
225
226 fn is_key_valid(key: &[u8]) -> bool {
227 !key.is_empty()
228 && key
229 .iter()
230 .all(|b| b.is_ascii_graphic() && !INVALID_ASCII_KEY_CHARS.contains(b))
231 }
232}
233
234fn key_value_metadata_bytes_size(key: &str, value: &str, metadata: &str) -> usize {
236 key.len() + value.len() + metadata.len()
237}
238
239#[derive(Debug)]
241pub struct Iter<'a>(hash_map::Iter<'a, Key, (StringValue, BaggageMetadata)>);
242
243impl<'a> Iterator for Iter<'a> {
244 type Item = (&'a Key, &'a (StringValue, BaggageMetadata));
245
246 fn next(&mut self) -> Option<Self::Item> {
247 self.0.next()
248 }
249}
250
251impl<'a> IntoIterator for &'a Baggage {
252 type Item = (&'a Key, &'a (StringValue, BaggageMetadata));
253 type IntoIter = Iter<'a>;
254
255 fn into_iter(self) -> Self::IntoIter {
256 Iter(self.inner.iter())
257 }
258}
259
260impl FromIterator<(Key, (StringValue, BaggageMetadata))> for Baggage {
261 fn from_iter<I: IntoIterator<Item = (Key, (StringValue, BaggageMetadata))>>(iter: I) -> Self {
262 let mut baggage = Baggage::default();
263 for (key, (value, metadata)) in iter.into_iter() {
264 baggage.insert_with_metadata(key, value, metadata);
265 }
266 baggage
267 }
268}
269
270impl FromIterator<KeyValue> for Baggage {
271 fn from_iter<I: IntoIterator<Item = KeyValue>>(iter: I) -> Self {
272 let mut baggage = Baggage::default();
273 for kv in iter.into_iter() {
274 baggage.insert(kv.key, kv.value);
275 }
276 baggage
277 }
278}
279
280impl FromIterator<KeyValueMetadata> for Baggage {
281 fn from_iter<I: IntoIterator<Item = KeyValueMetadata>>(iter: I) -> Self {
282 let mut baggage = Baggage::default();
283 for kvm in iter.into_iter() {
284 baggage.insert_with_metadata(kvm.key, kvm.value, kvm.metadata);
285 }
286 baggage
287 }
288}
289
290impl<I> From<I> for Baggage
291where
292 I: IntoIterator,
293 I::Item: Into<KeyValueMetadata>,
294{
295 fn from(value: I) -> Self {
296 value.into_iter().map(Into::into).collect()
297 }
298}
299
300fn encode(s: &str) -> String {
301 let mut encoded_string = String::with_capacity(s.len());
302
303 for byte in s.as_bytes() {
304 match *byte {
305 b'a'..=b'z' | b'A'..=b'Z' | b'0'..=b'9' | b'.' | b'-' | b'_' | b'~' => {
306 encoded_string.push(*byte as char)
307 }
308 b' ' => encoded_string.push_str("%20"),
309 _ => encoded_string.push_str(&format!("%{byte:02X}")),
310 }
311 }
312 encoded_string
313}
314
315impl fmt::Display for Baggage {
316 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
317 for (i, (k, v)) in self.into_iter().enumerate() {
318 write!(f, "{}={}", k, encode(v.0.as_str()))?;
319 if !v.1.as_str().is_empty() {
320 write!(f, ";{}", v.1)?;
321 }
322
323 if i < self.len() - 1 {
324 write!(f, ",")?;
325 }
326 }
327
328 Ok(())
329 }
330}
331
332pub trait BaggageExt {
334 fn with_baggage<T: Into<Baggage>>(&self, baggage: T) -> Self;
360
361 fn current_with_baggage<T: Into<Baggage>>(baggage: T) -> Self;
379
380 fn with_cleared_baggage(&self) -> Self;
392
393 fn baggage(&self) -> &Baggage;
396}
397
398#[derive(Debug)]
400struct BaggageContextValue(Baggage);
401
402impl BaggageExt for Context {
403 fn with_baggage<T: Into<Baggage>>(&self, baggage: T) -> Self {
404 self.with_value(BaggageContextValue(baggage.into()))
405 }
406
407 fn current_with_baggage<T: Into<Baggage>>(baggage: T) -> Self {
408 Context::map_current(|cx| cx.with_baggage(baggage))
409 }
410
411 fn with_cleared_baggage(&self) -> Self {
412 self.with_baggage(Baggage::new())
413 }
414
415 fn baggage(&self) -> &Baggage {
416 self.get::<BaggageContextValue>()
417 .map_or(get_default_baggage(), |b| &b.0)
418 }
419}
420
421#[derive(Clone, Debug, PartialOrd, PartialEq, Eq, Default)]
427pub struct BaggageMetadata(String);
428
429impl BaggageMetadata {
430 pub fn as_str(&self) -> &str {
432 self.0.as_str()
433 }
434}
435
436impl From<String> for BaggageMetadata {
437 fn from(s: String) -> BaggageMetadata {
438 BaggageMetadata(s.trim().to_string())
439 }
440}
441
442impl From<&str> for BaggageMetadata {
443 fn from(s: &str) -> Self {
444 BaggageMetadata(s.trim().to_string())
445 }
446}
447
448impl fmt::Display for BaggageMetadata {
449 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
450 Ok(write!(f, "{}", self.as_str())?)
451 }
452}
453
454#[derive(Clone, Debug, PartialEq)]
456pub struct KeyValueMetadata {
457 pub(crate) key: Key,
459 pub(crate) value: StringValue,
461 pub(crate) metadata: BaggageMetadata,
463}
464
465impl KeyValueMetadata {
466 pub fn new<K, V, S>(key: K, value: V, metadata: S) -> Self
468 where
469 K: Into<Key>,
470 V: Into<StringValue>,
471 S: Into<BaggageMetadata>,
472 {
473 KeyValueMetadata {
474 key: key.into(),
475 value: value.into(),
476 metadata: metadata.into(),
477 }
478 }
479}
480
481impl From<KeyValue> for KeyValueMetadata {
482 fn from(kv: KeyValue) -> Self {
483 KeyValueMetadata {
484 key: kv.key,
485 value: kv.value.into(),
486 metadata: BaggageMetadata::default(),
487 }
488 }
489}
490
491#[cfg(test)]
492mod tests {
493 use crate::StringValue;
494
495 use super::*;
496
497 #[test]
498 fn insert_non_ascii_key() {
499 let mut baggage = Baggage::new();
500 baggage.insert("🚫", "not ascii key");
501 assert_eq!(baggage.len(), 0, "did not insert invalid key");
502 }
503
504 #[test]
505 fn test_ascii_values() {
506 let string1 = "test_ 123";
507 let string2 = "Hello123";
508 let string3 = "This & That = More";
509 let string4 = "Unicode: 😊";
510 let string5 = "Non-ASCII: áéÃóú";
511 let string6 = "Unsafe: ~!@#$%^&*()_+{}[];:'\\\"<>?,./";
512 let string7: &str = "🚀Unicode:";
513 let string8 = "ΑΒΓ";
514
515 assert_eq!(encode(string1), "test_%20123");
516 assert_eq!(encode(string2), "Hello123");
517 assert_eq!(encode(string3), "This%20%26%20That%20%3D%20More");
518 assert_eq!(encode(string4), "Unicode%3A%20%F0%9F%98%8A");
519 assert_eq!(
520 encode(string5),
521 "Non-ASCII%3A%20%C3%A1%C3%A9%C3%AD%C3%B3%C3%BA"
522 );
523 assert_eq!(encode(string6), "Unsafe%3A%20~%21%40%23%24%25%5E%26%2A%28%29_%2B%7B%7D%5B%5D%3B%3A%27%5C%22%3C%3E%3F%2C.%2F");
524 assert_eq!(encode(string7), "%F0%9F%9A%80Unicode%3A");
525 assert_eq!(encode(string8), "%CE%91%CE%92%CE%93");
526 }
527
528 #[test]
529 fn insert_too_much_baggage() {
530 let over_limit = MAX_KEY_VALUE_PAIRS + 1;
532 let mut data = Vec::with_capacity(over_limit);
533 for i in 0..over_limit {
534 data.push(KeyValue::new(format!("key{i}"), format!("key{i}")))
535 }
536 let baggage = data.into_iter().collect::<Baggage>();
537 assert_eq!(baggage.len(), MAX_KEY_VALUE_PAIRS)
538 }
539
540 #[test]
541 fn insert_pairs_length_exceed() {
542 let mut data = vec![];
543 for letter in vec!['a', 'b', 'c', 'd'].into_iter() {
544 data.push(KeyValue::new(
545 (0..MAX_LEN_OF_ALL_PAIRS / 3)
546 .map(|_| letter)
547 .collect::<String>(),
548 "",
549 ));
550 }
551 let baggage = data.into_iter().collect::<Baggage>();
552 assert_eq!(baggage.len(), 3)
553 }
554
555 #[test]
556 fn serialize_baggage_as_string() {
557 let b = Baggage::default();
559 assert_eq!("", b.to_string());
560
561 let mut b = Baggage::default();
563 b.insert("foo", StringValue::from(""));
564 assert_eq!("foo=", b.to_string());
565
566 let mut b = Baggage::default();
568 b.insert("foo", StringValue::from("1"));
569 assert_eq!("foo=1", b.to_string());
570
571 let mut b = Baggage::default();
573 b.insert("foo", StringValue::from("1=1"));
574 assert_eq!("foo=1%3D1", b.to_string());
575
576 let mut b = Baggage::default();
578 b.insert_with_metadata(
579 "foo",
580 StringValue::from(""),
581 BaggageMetadata::from("red;state=on"),
582 );
583 assert_eq!("foo=;red;state=on", b.to_string());
584
585 let mut b = Baggage::default();
587 b.insert_with_metadata("foo", StringValue::from("1"), "red;state=on;z=z=z");
588 assert_eq!("foo=1;red;state=on;z=z=z", b.to_string());
589
590 let mut b = Baggage::default();
592 b.insert_with_metadata("foo", StringValue::from("1"), "red;state=on");
593 b.insert_with_metadata("bar", StringValue::from("2"), "yellow");
594 assert!(b.to_string().contains("bar=2;yellow"));
595 assert!(b.to_string().contains("foo=1;red;state=on"));
596 }
597
598 #[test]
599 fn replace_existing_key() {
600 let half_minus2: StringValue = (0..MAX_LEN_OF_ALL_PAIRS / 2 - 2)
601 .map(|_| 'x')
602 .collect::<String>()
603 .into();
604
605 let mut b = Baggage::default();
606 b.insert("a", half_minus2.clone()); b.insert("b", half_minus2); b.insert("c", StringValue::from(".")); assert!(b.get("a").is_some());
610 assert!(b.get("b").is_some());
611 assert!(b.get("c").is_some());
612 assert!(b.insert("c", StringValue::from("..")).is_none()); assert_eq!(b.insert("c", StringValue::from("!")).unwrap(), ".".into()); }
615
616 #[test]
617 fn test_crud_operations() {
618 let mut baggage = Baggage::default();
619 assert!(baggage.is_empty());
620
621 baggage.insert("foo", "1");
623 assert_eq!(baggage.len(), 1);
624
625 assert_eq!(baggage.get("foo"), Some(&StringValue::from("1")));
627
628 baggage.insert("foo", "2");
630 assert_eq!(baggage.get("foo"), Some(&StringValue::from("2")));
631
632 baggage.remove("foo");
634 assert!(baggage.is_empty());
635 }
636
637 #[test]
638 fn test_insert_invalid_key() {
639 let mut baggage = Baggage::default();
640
641 baggage.insert("", "1");
643 assert!(baggage.is_empty());
644
645 baggage.insert("Grüße", "1");
647 assert!(baggage.is_empty());
648
649 baggage.insert("(example)", "1");
651 assert!(baggage.is_empty());
652 }
653
654 #[test]
655 fn test_context_clear_baggage() {
656 let ctx = Context::new();
657 let ctx = ctx.with_baggage([KeyValue::new("foo", 1)]);
658 let _guard = ctx.attach();
659
660 {
661 let ctx = Context::current();
662 let baggage = ctx.baggage();
663 assert_eq!(baggage.len(), 1);
665
666 let ctx = ctx.with_cleared_baggage();
668 let _guard = ctx.attach();
669 {
670 let ctx = Context::current();
671 let baggage = ctx.baggage();
672 assert_eq!(baggage.len(), 0);
674 }
675 }
676 }
677}