1#![cfg_attr(not(feature = "std"), no_std)]
73
74extern crate alloc;
75
76use alloc::borrow::{Borrow, Cow};
77use alloc::string::{String, ToString};
78use alloc::vec::{IntoIter as VecIntoIter, Vec};
79use core::array::IntoIter as ArrayIntoIter;
80use core::iter::{once, Map, Once};
81use core::ops::{Deref, DerefMut, Index, IndexMut};
82use core::option::IntoIter as OptionIntoIter;
83use core::slice::{Iter as SliceIter, IterMut as SliceIterMut};
84use serde::{Deserialize, Serialize};
85
86#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
105#[serde(bound(deserialize = "'de: 'a"))]
106#[serde(transparent)]
107pub struct KVPairs<'a> {
108 pub content: Vec<KVPair<'a>>,
110}
111
112pub type KVPair<'a> = (&'a str, Cow<'a, str>);
114
115#[doc(hidden)]
116pub mod __private {
117 pub use alloc::borrow::Cow;
118}
119
120impl Default for KVPairs<'_> {
121 fn default() -> Self {
122 Self::new()
123 }
124}
125
126impl<'a> KVPairs<'a> {
127 #[must_use]
129 pub fn new() -> Self {
130 Self {
131 content: Vec::new(),
132 }
133 }
134
135 pub fn push_one<'b: 'a, V: IntoValue<'b>>(&mut self, key: &'a str, value: V) {
137 self.content.push((key, value.into_value()));
138 }
139
140 pub fn push<'b: 'a, V: IntoValues<'b>>(&mut self, key: &'a str, value: V) {
142 for v in value.into_values() {
143 self.content.push((key, v));
144 }
145 }
146
147 pub fn push_str<'b: 'a, V: AsRef<str> + ?Sized>(&mut self, key: &'a str, value: &'b V) {
149 self.content.push((key, Cow::Borrowed(value.as_ref())));
150 }
151
152 pub fn push_owned<V: Into<String>>(&mut self, key: &'a str, value: V) {
154 self.content.push((key, Cow::Owned(value.into())));
155 }
156}
157
158impl<'a> AsRef<[KVPair<'a>]> for KVPairs<'a> {
159 fn as_ref(&self) -> &[KVPair<'a>] {
160 self.content.as_ref()
161 }
162}
163
164impl<'a> AsRef<Vec<KVPair<'a>>> for KVPairs<'a> {
165 fn as_ref(&self) -> &Vec<KVPair<'a>> {
166 &self.content
167 }
168}
169
170impl<'a> AsMut<[KVPair<'a>]> for KVPairs<'a> {
171 fn as_mut(&mut self) -> &mut [KVPair<'a>] {
172 self.content.as_mut()
173 }
174}
175
176impl<'a> AsMut<Vec<KVPair<'a>>> for KVPairs<'a> {
177 fn as_mut(&mut self) -> &mut Vec<KVPair<'a>> {
178 &mut self.content
179 }
180}
181
182impl<'a> Borrow<[KVPair<'a>]> for KVPairs<'a> {
183 fn borrow(&self) -> &[KVPair<'a>] {
184 self.content.as_ref()
185 }
186}
187
188impl<'a> Borrow<Vec<KVPair<'a>>> for KVPairs<'a> {
189 fn borrow(&self) -> &Vec<KVPair<'a>> {
190 &self.content
191 }
192}
193
194impl<'a> Deref for KVPairs<'a> {
195 type Target = Vec<KVPair<'a>>;
196
197 fn deref(&self) -> &Self::Target {
198 &self.content
199 }
200}
201
202impl DerefMut for KVPairs<'_> {
203 fn deref_mut(&mut self) -> &mut Self::Target {
204 &mut self.content
205 }
206}
207
208impl<'a, I> Index<I> for KVPairs<'a>
209where
210 Vec<KVPair<'a>>: Index<I>,
211{
212 type Output = <Vec<KVPair<'a>> as Index<I>>::Output;
213
214 fn index(&self, index: I) -> &Self::Output {
215 &self.content[index]
216 }
217}
218
219impl<'a, I> IndexMut<I> for KVPairs<'a>
220where
221 Vec<KVPair<'a>>: IndexMut<I>,
222{
223 fn index_mut(&mut self, index: I) -> &mut Self::Output {
224 &mut self.content[index]
225 }
226}
227
228impl<'a> FromIterator<KVPair<'a>> for KVPairs<'a> {
229 fn from_iter<T: IntoIterator<Item = KVPair<'a>>>(iter: T) -> Self {
230 Self {
231 content: iter.into_iter().collect(),
232 }
233 }
234}
235
236impl<'a> IntoIterator for KVPairs<'a> {
237 type Item = KVPair<'a>;
238 type IntoIter = <Vec<KVPair<'a>> as IntoIterator>::IntoIter;
239
240 fn into_iter(self) -> Self::IntoIter {
241 self.content.into_iter()
242 }
243}
244
245impl<'a, 'b> IntoIterator for &'b KVPairs<'a> {
246 type Item = &'b KVPair<'a>;
247 type IntoIter = SliceIter<'b, KVPair<'a>>;
248
249 fn into_iter(self) -> Self::IntoIter {
250 self.content.iter()
251 }
252}
253
254impl<'a, 'b> IntoIterator for &'b mut KVPairs<'a> {
255 type Item = &'b mut KVPair<'a>;
256 type IntoIter = SliceIterMut<'b, KVPair<'a>>;
257
258 fn into_iter(self) -> Self::IntoIter {
259 self.content.iter_mut()
260 }
261}
262
263pub trait IntoValue<'a> {
278 fn into_value(self) -> Cow<'a, str>;
280}
281
282pub trait IntoValues<'a> {
306 type Iter: Iterator<Item = Cow<'a, str>>;
308
309 fn into_values(self) -> Self::Iter;
311}
312
313impl<'a> IntoValue<'a> for &'a str {
314 fn into_value(self) -> Cow<'a, str> {
315 Cow::Borrowed(self)
316 }
317}
318
319impl<'a, 'b> IntoValue<'a> for &'b &'a str
320where
321 'a: 'b,
322{
323 fn into_value(self) -> Cow<'a, str> {
324 Cow::Borrowed(*self)
325 }
326}
327
328impl<'a> IntoValue<'a> for String {
329 fn into_value(self) -> Cow<'a, str> {
330 Cow::Owned(self)
331 }
332}
333
334impl<'a> IntoValue<'a> for &'a String {
335 fn into_value(self) -> Cow<'a, str> {
336 Cow::Borrowed(self.as_str())
337 }
338}
339
340impl<'a> IntoValue<'a> for bool {
341 fn into_value(self) -> Cow<'a, str> {
342 Cow::Borrowed(if self { "true" } else { "false" })
343 }
344}
345
346impl<'a, T: IntoValue<'a>> IntoValues<'a> for T {
347 type Iter = Once<Cow<'a, str>>;
348
349 fn into_values(self) -> Self::Iter {
350 once(self.into_value())
351 }
352}
353
354impl<'a, T: IntoValue<'a>> IntoValues<'a> for Option<T> {
355 type Iter = Map<OptionIntoIter<T>, fn(T) -> Cow<'a, str>>;
356
357 fn into_values(self) -> Self::Iter {
358 self.into_iter().map(IntoValue::into_value)
359 }
360}
361
362impl<'a, T> IntoValues<'a> for &'a [T]
363where
364 &'a T: IntoValue<'a>,
365{
366 type Iter = Map<SliceIter<'a, T>, fn(&'a T) -> Cow<'a, str>>;
367
368 fn into_values(self) -> Self::Iter {
369 self.iter().map(IntoValue::into_value)
370 }
371}
372
373impl<'a, T, const N: usize> IntoValues<'a> for &'a [T; N]
374where
375 &'a T: IntoValue<'a>,
376{
377 type Iter = Map<SliceIter<'a, T>, fn(&'a T) -> Cow<'a, str>>;
378
379 fn into_values(self) -> Self::Iter {
380 self.iter().map(IntoValue::into_value)
381 }
382}
383
384impl<'a, T> IntoValues<'a> for &'a Vec<T>
385where
386 &'a T: IntoValue<'a>,
387{
388 type Iter = Map<SliceIter<'a, T>, fn(&'a T) -> Cow<'a, str>>;
389
390 fn into_values(self) -> Self::Iter {
391 self.iter().map(IntoValue::into_value)
392 }
393}
394
395impl<'a, T, const N: usize> IntoValues<'a> for [T; N]
396where
397 T: IntoValue<'a>,
398{
399 type Iter = Map<ArrayIntoIter<T, N>, fn(T) -> Cow<'a, str>>;
400
401 fn into_values(self) -> Self::Iter {
402 self.into_iter().map(IntoValue::into_value)
403 }
404}
405
406impl<'a, T> IntoValues<'a> for Vec<T>
407where
408 T: IntoValue<'a>,
409{
410 type Iter = Map<VecIntoIter<T>, fn(T) -> Cow<'a, str>>;
411
412 fn into_values(self) -> Self::Iter {
413 self.into_iter().map(IntoValue::into_value)
414 }
415}
416
417#[macro_export]
421macro_rules! impl_into_value_by_as_ref_str {
422 ($($type:ty),* $(,)?) => {
423 $(
424 impl<'a> $crate::IntoValue<'a> for &'a $type where $type: AsRef<str> {
425 fn into_value(self) -> $crate::__private::Cow<'a, str> {
426 $crate::__private::Cow::Borrowed(self.as_ref())
427 }
428 }
429 )*
430 };
431}
432
433#[macro_export]
437macro_rules! impl_into_value_by_into_str_ref {
438 ($($type:ty),* $(,)?) => {
439 $(
440 impl<'a> $crate::IntoValue<'a> for $type where $type: Into<&'a str> {
441 fn into_value(self) -> $crate::__private::Cow<'a, str> {
442 $crate::__private::Cow::Borrowed(self.into())
443 }
444 }
445 )*
446 };
447}
448
449#[macro_export]
453macro_rules! impl_into_value_by_to_string {
454 ($($type:ty),* $(,)?) => {
455 $(
456 impl<'a> $crate::IntoValue<'a> for $type where $type: ToString {
457 fn into_value(self) -> $crate::__private::Cow<'a, str> {
458 $crate::__private::Cow::Owned(self.to_string())
459 }
460 }
461 )*
462 };
463}
464
465#[macro_export]
492macro_rules! kv_pairs {
493 () => {
494 $crate::KVPairs::new()
495 };
496 (@inner, $result: expr $(,)?) => {};
497 (@inner, $result: expr, $key:expr => $value:expr $(, $($($rest:tt)+)?)?) => {
498 $result.push($key, $value);
499 $($(kv_pairs!(@inner, $result, $($rest)+);)?)?
500 };
501 ($($input:tt)*) => {
502 {
503 let mut result = $crate::KVPairs::new();
504 kv_pairs!(@inner, result, $($input)*);
505 result
506 }
507 };
508}
509
510impl_into_value_by_to_string! {
511 u64,
512 u32,
513 u16,
514 u8,
515 i64,
516 i32,
517 i16,
518 i8,
519}
520
521#[cfg(test)]
522mod tests {
523 use super::*;
524 use std::ops::DerefMut;
525
526 #[test]
527 fn new_and_default_are_empty() {
528 let p: KVPairs = KVPairs::new();
529 assert!(p.content.is_empty());
530 let q: KVPairs = KVPairs::default();
531 assert!(q.content.is_empty());
532 }
533
534 #[test]
535 fn push_str_borrows() {
536 let mut p = KVPairs::new();
537 let s = String::from("v");
538 p.push_str("k", &s);
539 assert_eq!(p.content.len(), 1);
540 assert_eq!(p.content[0].0, "k");
541 assert_eq!(p.content[0].1.as_ref(), "v");
542 }
543
544 #[test]
545 fn push_owned_allocates() {
546 let mut p = KVPairs::new();
547 p.push_owned("key", "value");
548 assert_eq!(p.content[0].0, "key");
549 assert_eq!(p.content[0].1.as_ref(), "value");
550 }
551
552 #[test]
553 fn push_one_with_into_value() {
554 let mut p = KVPairs::new();
555 p.push_one("a", "b");
556 p.push_one("n", 42_u32);
557 p.push_one("flag", true);
558 assert_eq!(p.content.len(), 3);
559 assert_eq!(p.content[0], ("a", Cow::Borrowed("b")));
560 assert_eq!(p.content[1].1.as_ref(), "42");
561 assert_eq!(p.content[2].1.as_ref(), "true");
562 }
563
564 #[test]
565 fn push_some_adds() {
566 let mut p = KVPairs::new();
567 p.push("opt", Some("v"));
568 assert_eq!(p.content.len(), 1);
569 assert_eq!(p.content[0].1.as_ref(), "v");
570 }
571
572 #[test]
573 fn push_none_skips() {
574 let mut p = KVPairs::new();
575 p.push("opt", None::<&str>);
576 assert!(p.content.is_empty());
577 }
578
579 #[test]
580 fn macro_empty() {
581 let p = kv_pairs![];
582 assert!(p.content.is_empty());
583 }
584
585 #[test]
586 fn macro_single() {
587 let p = kv_pairs![ "k" => "v" ];
588 assert_eq!(p.content.len(), 1);
589 assert_eq!(p.content[0].0, "k");
590 assert_eq!(p.content[0].1.as_ref(), "v");
591 }
592
593 #[test]
594 fn macro_multiple() {
595 let p = kv_pairs![
596 "a" => "1",
597 "b" => 2_u64,
598 "c" => false,
599 ];
600 assert_eq!(p.content.len(), 3);
601 assert_eq!(p.content[0], ("a", Cow::Borrowed("1")));
602 assert_eq!(p.content[1].1.as_ref(), "2");
603 assert_eq!(p.content[2].1.as_ref(), "false");
604 }
605
606 #[test]
607 fn into_values_for_option() {
608 let some_val: Option<&str> = Some("x");
609 let out: Vec<Cow<str>> = some_val.into_values().collect();
610 assert_eq!(out.len(), 1);
611 assert_eq!(out[0].as_ref(), "x");
612
613 let none_val: Option<&str> = None;
614 let out2: Vec<Cow<str>> = none_val.into_values().collect();
615 assert!(out2.is_empty());
616 }
617
618 #[test]
619 fn into_value_str_string_bool() {
620 assert_eq!("hi".into_value().as_ref(), "hi");
621 assert_eq!(String::from("owned").into_value().as_ref(), "owned");
622 let s = String::from("borrowed");
623 assert_eq!((&s).into_value().as_ref(), "borrowed");
624 assert_eq!(true.into_value().as_ref(), "true");
625 assert_eq!(false.into_value().as_ref(), "false");
626 }
627
628 #[test]
629 fn into_value_integers() {
630 assert_eq!(0_u8.into_value().as_ref(), "0");
631 assert_eq!(1_u16.into_value().as_ref(), "1");
632 assert_eq!(42_u32.into_value().as_ref(), "42");
633 assert_eq!(100_u64.into_value().as_ref(), "100");
634 assert_eq!((-1_i8).into_value().as_ref(), "-1");
635 assert_eq!(2_i16.into_value().as_ref(), "2");
636 assert_eq!((-99_i32).into_value().as_ref(), "-99");
637 assert_eq!(1000_i64.into_value().as_ref(), "1000");
638 }
639
640 #[test]
641 fn into_values_slice() {
642 let out: Vec<Cow<str>> = ["a", "b"].as_slice().into_values().collect();
643 assert_eq!(out.len(), 2);
644 assert_eq!(out[0].as_ref(), "a");
645 assert_eq!(out[1].as_ref(), "b");
646 }
647
648 #[test]
649 fn into_values_array() {
650 let out: Vec<Cow<str>> = ["x", "y"].into_values().collect();
651 assert_eq!(out.len(), 2);
652 assert_eq!(out[0].as_ref(), "x");
653 assert_eq!(out[1].as_ref(), "y");
654 }
655
656 #[test]
657 fn into_values_vec() {
658 let out: Vec<Cow<str>> = vec!["p", "q"].into_values().collect();
659 assert_eq!(out.len(), 2);
660 assert_eq!(out[0].as_ref(), "p");
661 assert_eq!(out[1].as_ref(), "q");
662 }
663
664 #[test]
665 fn into_values_vec_ref() {
666 let v = vec!["m", "n"];
667 let out: Vec<Cow<str>> = (&v).into_values().collect();
668 assert_eq!(out.len(), 2);
669 assert_eq!(out[0].as_ref(), "m");
670 assert_eq!(out[1].as_ref(), "n");
671 }
672
673 #[test]
674 fn into_values_option_integers() {
675 let out: Vec<Cow<str>> = Some(10_u32).into_values().collect();
676 assert_eq!(out.len(), 1);
677 assert_eq!(out[0].as_ref(), "10");
678 let out: Vec<Cow<str>> = None::<u32>.into_values().collect();
679 assert!(out.is_empty());
680 }
681
682 #[test]
683 fn macro_with_option_some_none() {
684 let p = kv_pairs![
685 "q" => Some("search"),
686 "filter" => None::<&str>,
687 ];
688 assert_eq!(p.content.len(), 1);
689 assert_eq!(p.content[0].0, "q");
690 assert_eq!(p.content[0].1.as_ref(), "search");
691 }
692
693 #[test]
694 fn macro_with_slice() {
695 let p = kv_pairs!["tag" => ["a", "b"].as_slice()];
696 assert_eq!(p.content.len(), 2);
697 assert_eq!(p.content[0], ("tag", Cow::Borrowed("a")));
698 assert_eq!(p.content[1], ("tag", Cow::Borrowed("b")));
699 }
700
701 #[test]
702 fn macro_with_array() {
703 let p = kv_pairs!["x" => ["one", "two"]];
704 assert_eq!(p.content.len(), 2);
705 assert_eq!(p.content[0].1.as_ref(), "one");
706 assert_eq!(p.content[1].1.as_ref(), "two");
707 }
708
709 #[test]
710 fn macro_with_vec() {
711 let p = kv_pairs!["ids" => vec![1_u32, 2_u32]];
712 assert_eq!(p.content.len(), 2);
713 assert_eq!(p.content[0].1.as_ref(), "1");
714 assert_eq!(p.content[1].1.as_ref(), "2");
715 }
716
717 #[test]
718 fn push_with_slice_multi_value() {
719 let mut p = KVPairs::new();
720 p.push("tag", ["a", "b"].as_slice());
721 assert_eq!(p.content.len(), 2);
722 assert_eq!(p.content[0], ("tag", Cow::Borrowed("a")));
723 assert_eq!(p.content[1], ("tag", Cow::Borrowed("b")));
724 }
725
726 #[test]
727 fn push_with_vec_multi_value() {
728 let mut p = KVPairs::new();
729 p.push("n", vec![10_u32, 20_u32]);
730 assert_eq!(p.content.len(), 2);
731 assert_eq!(p.content[0].1.as_ref(), "10");
732 assert_eq!(p.content[1].1.as_ref(), "20");
733 }
734
735 #[test]
736 fn serialize_roundtrip() {
737 let p = kv_pairs![ "a" => "b", "c" => 1_i32 ];
738 let json = serde_json::to_string(&p.content).unwrap();
739 let back: Vec<(String, String)> = serde_json::from_str(&json).unwrap();
740 assert_eq!(back.len(), 2);
741 assert_eq!((back[0].0.as_str(), back[0].1.as_str()), ("a", "b"));
742 assert_eq!((back[1].0.as_str(), back[1].1.as_str()), ("c", "1"));
743 }
744
745 #[test]
746 fn eq_and_hash() {
747 let a = kv_pairs!["x" => "1", "y" => "2"];
748 let b = kv_pairs!["x" => "1", "y" => "2"];
749 let c = kv_pairs!["x" => "1"];
750 assert_eq!(a, b);
751 assert_ne!(a, c);
752 use std::collections::hash_map::DefaultHasher;
753 use std::hash::{Hash, Hasher};
754 let mut hasher = DefaultHasher::new();
755 a.hash(&mut hasher);
756 let _ = hasher.finish();
757 }
758
759 #[test]
760 fn as_ref_as_mut_borrow() {
761 let p = kv_pairs!["a" => "b"];
762 let slice: &[KVPair] = p.as_ref();
763 assert_eq!(slice.len(), 1);
764 let vec_ref: &Vec<KVPair> = p.as_ref();
765 assert_eq!(vec_ref.len(), 1);
766 let slice_borrow: &[KVPair] = p.borrow();
767 assert_eq!(slice_borrow, slice);
768 let vec_borrow: &Vec<KVPair> = p.borrow();
769 assert_eq!(vec_borrow.len(), 1);
770 let mut q = kv_pairs!["k" => "v"];
771 let slice_mut: &mut [KVPair] = q.as_mut();
772 slice_mut[0].1 = Cow::Borrowed("v2");
773 assert_eq!(q[0].1.as_ref(), "v2");
774 }
775
776 #[test]
777 fn deref_deref_mut() {
778 let p = kv_pairs!["a" => "1", "b" => "2"];
779 assert_eq!(p.len(), 2);
780 assert!(!p.is_empty());
781 let mut q = kv_pairs!["x" => "y"];
782 q.deref_mut().push(("z", Cow::Borrowed("w")));
783 assert_eq!(q.len(), 2);
784 }
785
786 #[test]
787 fn index_index_mut() {
788 let mut p = kv_pairs!["a" => "b", "c" => "d"];
789 assert_eq!(p[0].0, "a");
790 assert_eq!(p[1].1.as_ref(), "d");
791 p[0].1 = Cow::Borrowed("b2");
792 assert_eq!(p[0].1.as_ref(), "b2");
793 }
794
795 #[test]
796 fn from_iterator_into_iterator() {
797 let pairs: Vec<KVPair> = vec![("k1", Cow::Borrowed("v1")), ("k2", Cow::Borrowed("v2"))];
798 let p: KVPairs = pairs.into_iter().collect();
799 assert_eq!(p.len(), 2);
800 let back: Vec<KVPair> = p.into_iter().collect();
801 assert_eq!(back.len(), 2);
802 assert_eq!(back[0].0, "k1");
803 let p2 = kv_pairs!["a" => "b"];
804 let ref_iter: Vec<_> = (&p2).into_iter().collect();
805 assert_eq!(ref_iter.len(), 1);
806 assert_eq!(ref_iter[0].0, "a");
807 }
808}