1use crate::{Context, Key, KeyValue, Value};
18use std::collections::{hash_map, HashMap};
19use std::fmt;
20use std::sync::OnceLock;
21
22static DEFAULT_BAGGAGE: OnceLock<Baggage> = OnceLock::new();
23
24const MAX_KEY_VALUE_PAIRS: usize = 180;
25const MAX_BYTES_FOR_ONE_PAIR: usize = 4096;
26const MAX_LEN_OF_ALL_PAIRS: usize = 8192;
27
28#[inline]
30fn get_default_baggage() -> &'static Baggage {
31 DEFAULT_BAGGAGE.get_or_init(Baggage::default)
32}
33
34#[derive(Debug, Default)]
58pub struct Baggage {
59 inner: HashMap<Key, (Value, BaggageMetadata)>,
60 kv_content_len: usize, }
62
63impl Baggage {
64 pub fn new() -> Self {
66 Baggage {
67 inner: HashMap::default(),
68 kv_content_len: 0,
69 }
70 }
71
72 pub fn get<K: AsRef<str>>(&self, key: K) -> Option<&Value> {
85 self.inner.get(key.as_ref()).map(|(value, _metadata)| value)
86 }
87
88 pub fn get_with_metadata<K: AsRef<str>>(&self, key: K) -> Option<&(Value, BaggageMetadata)> {
101 self.inner.get(key.as_ref())
102 }
103
104 pub fn insert<K, V>(&mut self, key: K, value: V) -> Option<Value>
120 where
121 K: Into<Key>,
122 V: Into<Value>,
123 {
124 self.insert_with_metadata(key, value, BaggageMetadata::default())
125 .map(|pair| pair.0)
126 }
127
128 pub fn insert_with_metadata<K, V, S>(
144 &mut self,
145 key: K,
146 value: V,
147 metadata: S,
148 ) -> Option<(Value, BaggageMetadata)>
149 where
150 K: Into<Key>,
151 V: Into<Value>,
152 S: Into<BaggageMetadata>,
153 {
154 let (key, value, metadata) = (key.into(), value.into(), metadata.into());
155 if self.insertable(&key, &value, &metadata) {
156 self.inner.insert(key, (value, metadata))
157 } else {
158 None
159 }
160 }
161
162 pub fn remove<K: Into<Key>>(&mut self, key: K) -> Option<(Value, BaggageMetadata)> {
165 self.inner.remove(&key.into())
166 }
167
168 pub fn len(&self) -> usize {
170 self.inner.len()
171 }
172
173 pub fn is_empty(&self) -> bool {
175 self.inner.is_empty()
176 }
177
178 pub fn iter(&self) -> Iter<'_> {
180 self.into_iter()
181 }
182
183 fn insertable(&mut self, key: &Key, value: &Value, metadata: &BaggageMetadata) -> bool {
186 if !key.as_str().is_ascii() {
187 return false;
188 }
189 let value = value.as_str();
190 if key_value_metadata_bytes_size(key.as_str(), value.as_ref(), metadata.as_str())
191 < MAX_BYTES_FOR_ONE_PAIR
192 {
193 match self.inner.get(key) {
194 None => {
195 if self.kv_content_len
197 + metadata.as_str().len()
198 + value.len()
199 + key.as_str().len()
200 > MAX_LEN_OF_ALL_PAIRS
201 {
202 return false;
203 }
204 if self.inner.len() + 1 > MAX_KEY_VALUE_PAIRS {
206 return false;
207 }
208 self.kv_content_len +=
209 metadata.as_str().len() + value.len() + key.as_str().len()
210 }
211 Some((old_value, old_metadata)) => {
212 let old_value = old_value.as_str();
213 if self.kv_content_len - old_metadata.as_str().len() - old_value.len()
214 + metadata.as_str().len()
215 + value.len()
216 > MAX_LEN_OF_ALL_PAIRS
217 {
218 return false;
219 }
220 self.kv_content_len =
221 self.kv_content_len - old_metadata.as_str().len() - old_value.len()
222 + metadata.as_str().len()
223 + value.len()
224 }
225 }
226 true
227 } else {
228 false
229 }
230 }
231}
232
233fn key_value_metadata_bytes_size(key: &str, value: &str, metadata: &str) -> usize {
235 key.bytes().len() + value.bytes().len() + metadata.bytes().len()
236}
237
238#[derive(Debug)]
240pub struct Iter<'a>(hash_map::Iter<'a, Key, (Value, BaggageMetadata)>);
241
242impl<'a> Iterator for Iter<'a> {
243 type Item = (&'a Key, &'a (Value, BaggageMetadata));
244
245 fn next(&mut self) -> Option<Self::Item> {
246 self.0.next()
247 }
248}
249
250impl<'a> IntoIterator for &'a Baggage {
251 type Item = (&'a Key, &'a (Value, BaggageMetadata));
252 type IntoIter = Iter<'a>;
253
254 fn into_iter(self) -> Self::IntoIter {
255 Iter(self.inner.iter())
256 }
257}
258
259impl FromIterator<(Key, (Value, BaggageMetadata))> for Baggage {
260 fn from_iter<I: IntoIterator<Item = (Key, (Value, BaggageMetadata))>>(iter: I) -> Self {
261 let mut baggage = Baggage::default();
262 for (key, (value, metadata)) in iter.into_iter() {
263 baggage.insert_with_metadata(key, value, metadata);
264 }
265 baggage
266 }
267}
268
269impl FromIterator<KeyValue> for Baggage {
270 fn from_iter<I: IntoIterator<Item = KeyValue>>(iter: I) -> Self {
271 let mut baggage = Baggage::default();
272 for kv in iter.into_iter() {
273 baggage.insert(kv.key, kv.value);
274 }
275 baggage
276 }
277}
278
279impl FromIterator<KeyValueMetadata> for Baggage {
280 fn from_iter<I: IntoIterator<Item = KeyValueMetadata>>(iter: I) -> Self {
281 let mut baggage = Baggage::default();
282 for kvm in iter.into_iter() {
283 baggage.insert_with_metadata(kvm.key, kvm.value, kvm.metadata);
284 }
285 baggage
286 }
287}
288
289fn encode(s: &str) -> String {
290 let mut encoded_string = String::with_capacity(s.len());
291
292 for byte in s.as_bytes() {
293 match *byte {
294 b'a'..=b'z' | b'A'..=b'Z' | b'0'..=b'9' | b'.' | b'-' | b'_' | b'~' => {
295 encoded_string.push(*byte as char)
296 }
297 b' ' => encoded_string.push_str("%20"),
298 _ => encoded_string.push_str(&format!("%{:02X}", byte)),
299 }
300 }
301 encoded_string
302}
303
304impl fmt::Display for Baggage {
305 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
306 for (i, (k, v)) in self.into_iter().enumerate() {
307 write!(f, "{}={}", k, encode(v.0.as_str().as_ref()))?;
308 if !v.1.as_str().is_empty() {
309 write!(f, ";{}", v.1)?;
310 }
311
312 if i < self.len() - 1 {
313 write!(f, ",")?;
314 }
315 }
316
317 Ok(())
318 }
319}
320
321pub trait BaggageExt {
323 fn with_baggage<T: IntoIterator<Item = I>, I: Into<KeyValueMetadata>>(
340 &self,
341 baggage: T,
342 ) -> Self;
343
344 fn current_with_baggage<T: IntoIterator<Item = I>, I: Into<KeyValueMetadata>>(
359 baggage: T,
360 ) -> Self;
361
362 fn with_cleared_baggage(&self) -> Self;
374
375 fn baggage(&self) -> &Baggage;
378}
379
380impl BaggageExt for Context {
381 fn with_baggage<T: IntoIterator<Item = I>, I: Into<KeyValueMetadata>>(
382 &self,
383 baggage: T,
384 ) -> Self {
385 let mut merged: Baggage = self
386 .baggage()
387 .iter()
388 .map(|(key, (value, metadata))| {
389 KeyValueMetadata::new(key.clone(), value.clone(), metadata.clone())
390 })
391 .collect();
392 for kvm in baggage.into_iter().map(|kv| kv.into()) {
393 merged.insert_with_metadata(kvm.key, kvm.value, kvm.metadata);
394 }
395
396 self.with_value(merged)
397 }
398
399 fn current_with_baggage<T: IntoIterator<Item = I>, I: Into<KeyValueMetadata>>(kvs: T) -> Self {
400 Context::map_current(|cx| cx.with_baggage(kvs))
401 }
402
403 fn with_cleared_baggage(&self) -> Self {
404 self.with_value(Baggage::new())
405 }
406
407 fn baggage(&self) -> &Baggage {
408 self.get::<Baggage>().unwrap_or(get_default_baggage())
409 }
410}
411
412#[derive(Clone, Debug, PartialOrd, PartialEq, Eq, Default)]
418pub struct BaggageMetadata(String);
419
420impl BaggageMetadata {
421 pub fn as_str(&self) -> &str {
423 self.0.as_str()
424 }
425}
426
427impl From<String> for BaggageMetadata {
428 fn from(s: String) -> BaggageMetadata {
429 BaggageMetadata(s.trim().to_string())
430 }
431}
432
433impl From<&str> for BaggageMetadata {
434 fn from(s: &str) -> Self {
435 BaggageMetadata(s.trim().to_string())
436 }
437}
438
439impl fmt::Display for BaggageMetadata {
440 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
441 Ok(write!(f, "{}", self.as_str())?)
442 }
443}
444
445#[derive(Clone, Debug, PartialEq)]
447pub struct KeyValueMetadata {
448 pub key: Key,
450 pub value: Value,
452 pub metadata: BaggageMetadata,
454}
455
456impl KeyValueMetadata {
457 pub fn new<K, V, S>(key: K, value: V, metadata: S) -> Self
459 where
460 K: Into<Key>,
461 V: Into<Value>,
462 S: Into<BaggageMetadata>,
463 {
464 KeyValueMetadata {
465 key: key.into(),
466 value: value.into(),
467 metadata: metadata.into(),
468 }
469 }
470}
471
472impl From<KeyValue> for KeyValueMetadata {
473 fn from(kv: KeyValue) -> Self {
474 KeyValueMetadata {
475 key: kv.key,
476 value: kv.value,
477 metadata: BaggageMetadata::default(),
478 }
479 }
480}
481
482#[cfg(test)]
483mod tests {
484 use crate::StringValue;
485
486 use super::*;
487
488 #[test]
489 fn insert_non_ascii_key() {
490 let mut baggage = Baggage::new();
491 baggage.insert("🚫", "not ascii key");
492 assert_eq!(baggage.len(), 0, "did not insert invalid key");
493 }
494
495 #[test]
496 fn test_ascii_values() {
497 let string1 = "test_ 123";
498 let string2 = "Hello123";
499 let string3 = "This & That = More";
500 let string4 = "Unicode: 😊";
501 let string5 = "Non-ASCII: áéÃóú";
502 let string6 = "Unsafe: ~!@#$%^&*()_+{}[];:'\\\"<>?,./";
503 let string7: &str = "🚀Unicode:";
504 let string8 = "ΑΒΓ";
505
506 assert_eq!(encode(string1), "test_%20123");
507 assert_eq!(encode(string2), "Hello123");
508 assert_eq!(encode(string3), "This%20%26%20That%20%3D%20More");
509 assert_eq!(encode(string4), "Unicode%3A%20%F0%9F%98%8A");
510 assert_eq!(
511 encode(string5),
512 "Non-ASCII%3A%20%C3%A1%C3%A9%C3%AD%C3%B3%C3%BA"
513 );
514 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");
515 assert_eq!(encode(string7), "%F0%9F%9A%80Unicode%3A");
516 assert_eq!(encode(string8), "%CE%91%CE%92%CE%93");
517 }
518
519 #[test]
520 fn insert_too_much_baggage() {
521 let over_limit = MAX_KEY_VALUE_PAIRS + 1;
523 let mut data = Vec::with_capacity(over_limit);
524 for i in 0..over_limit {
525 data.push(KeyValue::new(format!("key{i}"), format!("key{i}")))
526 }
527 let baggage = data.into_iter().collect::<Baggage>();
528 assert_eq!(baggage.len(), MAX_KEY_VALUE_PAIRS)
529 }
530
531 #[test]
532 fn insert_too_long_pair() {
533 let pair = KeyValue::new(
534 "test",
535 String::from_utf8_lossy(vec![12u8; MAX_BYTES_FOR_ONE_PAIR].as_slice()).to_string(),
536 );
537 let mut baggage = Baggage::default();
538 baggage.insert(pair.key.clone(), pair.value.clone());
539 assert_eq!(
540 baggage.len(),
541 0,
542 "The input pair is too long to insert into baggage"
543 );
544
545 baggage.insert("test", "value");
546 baggage.insert(pair.key.clone(), pair.value);
547 assert_eq!(
548 baggage.get(pair.key),
549 Some(&Value::from("value")),
550 "If the input pair is too long, then don't replace entry with same key"
551 )
552 }
553
554 #[test]
555 fn insert_pairs_length_exceed() {
556 let mut data = vec![];
557 for letter in vec!['a', 'b', 'c', 'd'].into_iter() {
558 data.push(KeyValue::new(
559 (0..MAX_LEN_OF_ALL_PAIRS / 3)
560 .map(|_| letter)
561 .collect::<String>(),
562 "",
563 ));
564 }
565 let baggage = data.into_iter().collect::<Baggage>();
566 assert_eq!(baggage.len(), 3)
567 }
568
569 #[test]
570 fn serialize_baggage_as_string() {
571 let b = Baggage::default();
573 assert_eq!("", b.to_string());
574
575 let mut b = Baggage::default();
577 b.insert("foo", StringValue::from(""));
578 assert_eq!("foo=", b.to_string());
579
580 let mut b = Baggage::default();
582 b.insert("foo", StringValue::from("1"));
583 assert_eq!("foo=1", b.to_string());
584
585 let mut b = Baggage::default();
587 b.insert("foo", StringValue::from("1=1"));
588 assert_eq!("foo=1%3D1", b.to_string());
589
590 let mut b = Baggage::default();
592 b.insert_with_metadata(
593 "foo",
594 StringValue::from(""),
595 BaggageMetadata::from("red;state=on"),
596 );
597 assert_eq!("foo=;red;state=on", b.to_string());
598
599 let mut b = Baggage::default();
601 b.insert_with_metadata("foo", StringValue::from("1"), "red;state=on;z=z=z");
602 assert_eq!("foo=1;red;state=on;z=z=z", b.to_string());
603
604 let mut b = Baggage::default();
606 b.insert_with_metadata("foo", StringValue::from("1"), "red;state=on");
607 b.insert_with_metadata("bar", StringValue::from("2"), "yellow");
608 assert!(b.to_string().contains("bar=2;yellow"));
609 assert!(b.to_string().contains("foo=1;red;state=on"));
610 }
611}