use std::fmt;
use std::hash::Hash;
use std::ops::{Deref, Index};
use std::sync::Arc;
use indexmap::{Equivalent, IndexMap, IndexSet};
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct OrderedSet<T>
where
T: Eq + Hash,
{
items: IndexSet<T>,
}
impl<T> Default for OrderedSet<T>
where
T: Eq + Hash,
{
fn default() -> Self {
Self {
items: IndexSet::new(),
}
}
}
impl<T> OrderedSet<T>
where
T: Eq + Hash,
{
pub fn new() -> Self {
Self::default()
}
pub fn len(&self) -> usize {
self.items.len()
}
pub fn is_empty(&self) -> bool {
self.items.is_empty()
}
pub fn add(&mut self, value: T) -> bool {
self.items.insert(value)
}
pub fn contains<Q>(&self, value: &Q) -> bool
where
Q: Hash + Equivalent<T> + ?Sized,
{
self.items.contains(value)
}
pub fn remove<Q>(&mut self, value: &Q) -> bool
where
Q: Hash + Equivalent<T> + ?Sized,
{
self.items.shift_remove(value)
}
pub fn discard<Q>(&mut self, value: &Q) -> bool
where
Q: Hash + Equivalent<T> + ?Sized,
{
self.remove(value)
}
pub fn iter(&self) -> impl Iterator<Item = &T> {
self.items.iter()
}
pub fn iter_rev(&self) -> impl Iterator<Item = &T> {
self.items.iter().rev()
}
}
impl<T> FromIterator<T> for OrderedSet<T>
where
T: Eq + Hash,
{
fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
Self {
items: iter.into_iter().collect(),
}
}
}
impl<T> IntoIterator for OrderedSet<T>
where
T: Eq + Hash,
{
type Item = T;
type IntoIter = indexmap::set::IntoIter<T>;
fn into_iter(self) -> Self::IntoIter {
self.items.into_iter()
}
}
impl<'a, T> IntoIterator for &'a OrderedSet<T>
where
T: Eq + Hash,
{
type Item = &'a T;
type IntoIter = indexmap::set::Iter<'a, T>;
fn into_iter(self) -> Self::IntoIter {
self.items.iter()
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct MultiValueDict<K, V>
where
K: Eq + Hash,
{
entries: IndexMap<K, Vec<V>>,
}
impl<K, V> Default for MultiValueDict<K, V>
where
K: Eq + Hash,
{
fn default() -> Self {
Self {
entries: IndexMap::new(),
}
}
}
impl<K, V> MultiValueDict<K, V>
where
K: Eq + Hash,
{
pub fn new() -> Self {
Self::default()
}
pub fn len(&self) -> usize {
self.entries.len()
}
pub fn is_empty(&self) -> bool {
self.entries.is_empty()
}
pub fn contains_key<Q>(&self, key: &Q) -> bool
where
Q: Hash + Equivalent<K> + ?Sized,
{
self.entries.contains_key(key)
}
pub fn get<Q>(&self, key: &Q) -> Option<&V>
where
Q: Hash + Equivalent<K> + ?Sized,
{
self.entries.get(key).and_then(|values| values.last())
}
pub fn get_list<Q>(&self, key: &Q) -> &[V]
where
Q: Hash + Equivalent<K> + ?Sized,
{
self.entries.get(key).map(Vec::as_slice).unwrap_or(&[])
}
pub fn set(&mut self, key: K, value: V) {
self.entries.insert(key, vec![value]);
}
pub fn set_list(&mut self, key: K, values: Vec<V>) {
self.entries.insert(key, values);
}
pub fn append(&mut self, key: K, value: V) {
self.entries.entry(key).or_default().push(value);
}
pub fn update<I>(&mut self, iter: I)
where
I: IntoIterator<Item = (K, Vec<V>)>,
{
for (key, values) in iter {
self.entries.entry(key).or_default().extend(values);
}
}
pub fn items(&self) -> impl Iterator<Item = (&K, Option<&V>)> {
self.entries
.iter()
.map(|(key, values)| (key, values.last()))
}
pub fn lists(&self) -> impl Iterator<Item = (&K, &[V])> {
self.entries
.iter()
.map(|(key, values)| (key, values.as_slice()))
}
pub fn values(&self) -> impl Iterator<Item = Option<&V>> {
self.entries.values().map(|values| values.last())
}
}
impl<K, V, const N: usize> From<[(K, Vec<V>); N]> for MultiValueDict<K, V>
where
K: Eq + Hash,
{
fn from(value: [(K, Vec<V>); N]) -> Self {
Self::from_iter(value)
}
}
impl<K, V> FromIterator<(K, Vec<V>)> for MultiValueDict<K, V>
where
K: Eq + Hash,
{
fn from_iter<I: IntoIterator<Item = (K, Vec<V>)>>(iter: I) -> Self {
Self {
entries: iter.into_iter().collect(),
}
}
}
impl<K, V> IntoIterator for MultiValueDict<K, V>
where
K: Eq + Hash,
{
type Item = (K, Vec<V>);
type IntoIter = indexmap::map::IntoIter<K, Vec<V>>;
fn into_iter(self) -> Self::IntoIter {
self.entries.into_iter()
}
}
#[derive(Clone, PartialEq, Eq, Hash)]
pub struct ImmutableList<T> {
items: Arc<[T]>,
}
impl<T> ImmutableList<T> {
pub fn new<I>(items: I) -> Self
where
I: Into<Arc<[T]>>,
{
Self {
items: items.into(),
}
}
#[track_caller]
fn immutable_panic() -> ! {
panic!("ImmutableList object is immutable.")
}
pub fn len(&self) -> usize {
self.items.len()
}
pub fn is_empty(&self) -> bool {
self.items.is_empty()
}
pub fn as_slice(&self) -> &[T] {
&self.items
}
pub fn iter(&self) -> impl Iterator<Item = &T> {
self.items.iter()
}
pub fn push(&mut self, _value: T) {
Self::immutable_panic();
}
pub fn pop(&mut self) -> Option<T> {
Self::immutable_panic();
}
pub fn insert(&mut self, _index: usize, _value: T) {
Self::immutable_panic();
}
}
impl<T> Deref for ImmutableList<T> {
type Target = [T];
fn deref(&self) -> &Self::Target {
&self.items
}
}
impl<T> Index<usize> for ImmutableList<T> {
type Output = T;
fn index(&self, index: usize) -> &Self::Output {
&self.items[index]
}
}
impl<T> fmt::Debug for ImmutableList<T>
where
T: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.items[..].fmt(f)
}
}
impl<T> From<Vec<T>> for ImmutableList<T> {
fn from(value: Vec<T>) -> Self {
Self::new(Arc::<[T]>::from(value))
}
}
impl<T, const N: usize> From<[T; N]> for ImmutableList<T> {
fn from(value: [T; N]) -> Self {
Self::from(Vec::from(value))
}
}
impl<T> FromIterator<T> for ImmutableList<T> {
fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
Self::from(iter.into_iter().collect::<Vec<_>>())
}
}
#[derive(Clone)]
struct CaseInsensitiveEntry<V> {
original_key: String,
value: V,
}
#[derive(Clone)]
pub struct CaseInsensitiveMapping<V> {
entries: IndexMap<String, CaseInsensitiveEntry<V>>,
}
impl<V> Default for CaseInsensitiveMapping<V> {
fn default() -> Self {
Self {
entries: IndexMap::new(),
}
}
}
impl<V> CaseInsensitiveMapping<V> {
pub fn new() -> Self {
Self::default()
}
pub fn len(&self) -> usize {
self.entries.len()
}
pub fn is_empty(&self) -> bool {
self.entries.is_empty()
}
pub fn insert<K>(&mut self, key: K, value: V) -> Option<V>
where
K: Into<String>,
{
let original_key = key.into();
let folded_key = original_key.to_lowercase();
self.entries
.insert(
folded_key,
CaseInsensitiveEntry {
original_key,
value,
},
)
.map(|entry| entry.value)
}
pub fn get(&self, key: &str) -> Option<&V> {
self.entries
.get(&key.to_lowercase())
.map(|entry| &entry.value)
}
pub fn contains_key(&self, key: &str) -> bool {
self.entries.contains_key(&key.to_lowercase())
}
pub fn keys(&self) -> impl Iterator<Item = &str> {
self.entries
.values()
.map(|entry| entry.original_key.as_str())
}
pub fn iter(&self) -> impl Iterator<Item = (&str, &V)> {
self.entries
.values()
.map(|entry| (entry.original_key.as_str(), &entry.value))
}
}
impl<V> fmt::Debug for CaseInsensitiveMapping<V>
where
V: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_map().entries(self.iter()).finish()
}
}
impl<V> PartialEq for CaseInsensitiveMapping<V>
where
V: PartialEq,
{
fn eq(&self, other: &Self) -> bool {
self.len() == other.len()
&& self.entries.iter().all(|(folded, entry)| {
other
.entries
.get(folded)
.is_some_and(|other_entry| other_entry.value == entry.value)
})
}
}
impl<V> Eq for CaseInsensitiveMapping<V> where V: Eq {}
impl<V, K, const N: usize> From<[(K, V); N]> for CaseInsensitiveMapping<V>
where
K: Into<String>,
{
fn from(value: [(K, V); N]) -> Self {
Self::from_iter(value)
}
}
impl<V, K> FromIterator<(K, V)> for CaseInsensitiveMapping<V>
where
K: Into<String>,
{
fn from_iter<I: IntoIterator<Item = (K, V)>>(iter: I) -> Self {
let mut mapping = Self::new();
for (key, value) in iter {
mapping.insert(key, value);
}
mapping
}
}
#[cfg(test)]
mod tests {
use super::*;
mod ordered_set_tests {
use super::*;
#[test]
fn test_init_with_iterable() {
let set = OrderedSet::from_iter([1, 2, 3]);
assert_eq!(set.iter().copied().collect::<Vec<_>>(), vec![1, 2, 3]);
}
#[test]
fn test_remove() {
let mut set = OrderedSet::new();
assert_eq!(set.len(), 0);
assert!(set.add(1));
assert!(set.add(2));
assert!(set.remove(&2));
assert_eq!(set.len(), 1);
assert!(!set.contains(&2));
}
#[test]
fn test_discard() {
let mut set = OrderedSet::new();
assert_eq!(set.len(), 0);
assert!(set.add(1));
assert!(!set.discard(&2));
assert_eq!(set.len(), 1);
}
#[test]
fn test_reversed() {
let set = OrderedSet::from_iter([1, 2, 3]);
assert_eq!(set.iter_rev().copied().collect::<Vec<_>>(), vec![3, 2, 1]);
}
#[test]
fn test_contains() {
let mut set = OrderedSet::new();
assert_eq!(set.len(), 0);
assert!(set.add(1));
assert!(set.contains(&1));
}
#[test]
fn test_bool() {
let mut set = OrderedSet::new();
assert!(set.is_empty());
assert!(set.add(1));
assert!(!set.is_empty());
}
#[test]
fn test_len() {
let mut set = OrderedSet::new();
assert_eq!(set.len(), 0);
assert!(set.add(1));
assert!(set.add(2));
assert!(!set.add(2));
assert_eq!(set.len(), 2);
}
#[test]
fn test_duplicate_insertion_keeps_order() {
let mut set = OrderedSet::new();
assert!(set.add(2));
assert!(set.add(3));
assert!(!set.add(2));
assert!(set.add(1));
assert_eq!(set.iter().copied().collect::<Vec<_>>(), vec![2, 3, 1]);
}
#[test]
fn test_into_iter_preserves_first_insertion_order() {
let mut set = OrderedSet::new();
assert!(set.add(3));
assert!(set.add(1));
assert!(!set.add(3));
assert!(set.add(2));
assert_eq!(set.len(), 3);
assert!(set.contains(&1));
assert_eq!(set.into_iter().collect::<Vec<_>>(), vec![3, 1, 2]);
}
}
mod multi_value_dict_tests {
use super::*;
fn sample_dict() -> MultiValueDict<&'static str, &'static str> {
MultiValueDict::from([
("name", vec!["Adrian", "Simon"]),
("position", vec!["Developer"]),
("empty", Vec::new()),
])
}
#[test]
fn test_multivaluedict() {
let dict = sample_dict();
assert_eq!(dict.get(&"name"), Some(&"Simon"));
assert_eq!(dict.get_list(&"name"), ["Adrian", "Simon"]);
assert_eq!(
dict.items().collect::<Vec<_>>(),
vec![
(&"name", Some(&"Simon")),
(&"position", Some(&"Developer")),
(&"empty", None),
]
);
assert_eq!(
dict.lists().collect::<Vec<_>>(),
vec![
(&"name", ["Adrian", "Simon"].as_slice()),
(&"position", ["Developer"].as_slice()),
(&"empty", <&[&str]>::default()),
]
);
assert_eq!(dict.get(&"empty"), None);
assert_eq!(dict.get(&"lastname"), None);
assert_eq!(dict.get_list(&"lastname"), <&[&str]>::default());
}
#[test]
fn test_appendlist() {
let mut dict = MultiValueDict::new();
dict.append("name", "Adrian");
dict.append("name", "Simon");
assert_eq!(dict.get_list(&"name"), ["Adrian", "Simon"]);
}
#[test]
fn test_copy_is_shallow() {
use std::cell::RefCell;
use std::rc::Rc;
let shared = Rc::new(RefCell::new(vec!["value"]));
let original = MultiValueDict::from([("key", vec![Rc::clone(&shared)])]);
let copied = original.clone();
copied
.get_list(&"key")
.first()
.expect("missing copied inner list")
.borrow_mut()
.push("Penguin");
assert_eq!(
&*original.get_list(&"key")[0].borrow(),
&["value", "Penguin"]
);
assert_eq!(&*copied.get_list(&"key")[0].borrow(), &["value", "Penguin"]);
}
#[test]
fn test_getlist_doesnt_mutate() {
let dict = MultiValueDict::from([("a", vec!["1", "2"]), ("b", vec!["3"])]);
let mut values = dict.get_list(&"a").to_vec();
values.extend(dict.get_list(&"b"));
assert_eq!(dict.get_list(&"a"), ["1", "2"]);
assert_eq!(values, vec!["1", "2", "3"]);
}
#[test]
fn test_getlist_none_empty_values() {
let dict = MultiValueDict::from([("a", vec![None]), ("b", Vec::<Option<i32>>::new())]);
assert_eq!(dict.get_list(&"a"), [None]);
assert_eq!(dict.get(&"a"), Some(&None));
assert_eq!(dict.get(&"b"), None);
assert_eq!(dict.get_list(&"b"), <&[Option<i32>]>::default());
}
#[test]
fn test_setitem() {
let mut dict = MultiValueDict::from([("a", vec![1, 2])]);
dict.set("a", 3);
assert_eq!(
dict.lists().collect::<Vec<_>>(),
vec![(&"a", [3].as_slice())]
);
}
#[test]
fn test_setlist() {
let mut dict = MultiValueDict::from([("lastname", vec!["Doe"])]);
dict.set_list("lastname", vec!["Holovaty", "Willison"]);
assert_eq!(dict.get_list(&"lastname"), ["Holovaty", "Willison"]);
}
#[test]
fn test_items() {
let dict = sample_dict();
assert_eq!(
dict.items().collect::<Vec<_>>(),
vec![
(&"name", Some(&"Simon")),
(&"position", Some(&"Developer")),
(&"empty", None),
]
);
}
#[test]
fn test_lists() {
let dict = sample_dict();
assert_eq!(
dict.lists()
.map(|(k, v)| (*k, v.to_vec()))
.collect::<Vec<_>>(),
vec![
("name", vec!["Adrian", "Simon"]),
("position", vec!["Developer"]),
("empty", Vec::new()),
]
);
}
#[test]
fn test_values() {
let dict = sample_dict();
assert_eq!(
dict.values().collect::<Vec<_>>(),
vec![Some(&"Simon"), Some(&"Developer"), None]
);
}
#[test]
fn test_get_missing_returns_none() {
let dict = MultiValueDict::from([("a", vec![1])]);
assert_eq!(dict.get(&"b"), None);
}
#[test]
fn test_get_list_missing_returns_empty_slice() {
let dict = MultiValueDict::from([("a", vec![1])]);
assert_eq!(dict.get_list(&"b"), <&[i32]>::default());
}
#[test]
fn test_set_replaces_entire_list() {
let mut dict = MultiValueDict::from([("a", vec![1, 2])]);
dict.set("a", 3);
assert_eq!(dict.get_list(&"a"), [3]);
}
#[test]
fn test_append_creates_new_key() {
let mut dict = MultiValueDict::new();
dict.append("a", 1);
assert_eq!(dict.get_list(&"a"), [1]);
}
#[test]
fn test_append_preserves_existing_key_order() {
let mut dict = MultiValueDict::from([("a", vec![1]), ("b", vec![2])]);
dict.append("a", 3);
dict.append("b", 4);
assert_eq!(
dict.lists()
.map(|(k, v)| (*k, v.to_vec()))
.collect::<Vec<_>>(),
vec![("a", vec![1, 3]), ("b", vec![2, 4])]
);
}
#[test]
fn test_update_appends_values_from_pairs() {
let mut dict = MultiValueDict::from([("a", vec![1]), ("b", vec![2]), ("c", vec![3])]);
dict.update([("a", vec![4]), ("b", vec![5])]);
assert_eq!(
dict.lists()
.map(|(k, v)| (*k, v.to_vec()))
.collect::<Vec<_>>(),
vec![("a", vec![1, 4]), ("b", vec![2, 5]), ("c", vec![3])]
);
}
#[test]
fn test_update_appends_values_from_multivaluedict() {
let mut dict = MultiValueDict::from([("a", vec![1]), ("b", vec![2]), ("c", vec![3])]);
dict.update(MultiValueDict::from([("a", vec![4]), ("b", vec![5])]));
assert_eq!(
dict.lists()
.map(|(k, v)| (*k, v.to_vec()))
.collect::<Vec<_>>(),
vec![("a", vec![1, 4]), ("b", vec![2, 5]), ("c", vec![3])]
);
}
#[test]
fn test_iteration_order() {
let dict =
MultiValueDict::from([("first", vec![1]), ("second", vec![2]), ("third", vec![3])]);
assert_eq!(
dict.lists().map(|(k, _)| *k).collect::<Vec<_>>(),
vec!["first", "second", "third"]
);
}
#[test]
fn test_len_counts_keys() {
let dict = sample_dict();
assert_eq!(dict.len(), 3);
}
#[test]
fn test_contains_key() {
let dict = sample_dict();
assert!(dict.contains_key(&"name"));
assert!(!dict.contains_key(&"lastname"));
}
}
mod immutable_list_tests {
use super::*;
#[test]
fn test_from_iter_and_indexing() {
let list = ImmutableList::from_iter(0..10);
assert_eq!(list[1], 1);
assert_eq!(list.len(), 10);
}
#[test]
fn test_as_slice() {
let list = ImmutableList::from([1, 2, 3]);
assert_eq!(list.as_slice(), [1, 2, 3]);
}
#[test]
fn test_iter() {
let list = ImmutableList::from([1, 2, 3]);
assert_eq!(list.iter().copied().collect::<Vec<_>>(), vec![1, 2, 3]);
}
#[test]
fn test_debug() {
let list = ImmutableList::from_iter(0..4);
assert_eq!(format!("{list:?}"), "[0, 1, 2, 3]");
}
#[test]
fn test_is_empty() {
let list = ImmutableList::<i32>::from(Vec::new());
assert!(list.is_empty());
}
#[test]
#[should_panic(expected = "ImmutableList object is immutable.")]
fn test_push_panics() {
let mut list = ImmutableList::from([1, 2, 3]);
list.push(4);
}
#[test]
#[should_panic(expected = "ImmutableList object is immutable.")]
fn test_pop_panics() {
let mut list = ImmutableList::from([1, 2, 3]);
let _ = list.pop();
}
#[test]
#[should_panic(expected = "ImmutableList object is immutable.")]
fn test_insert_panics() {
let mut list = ImmutableList::from([1, 2, 3]);
list.insert(1, 99);
}
}
mod case_insensitive_mapping_tests {
use super::*;
fn sample_mapping() -> CaseInsensitiveMapping<&'static str> {
CaseInsensitiveMapping::from([
("Accept", "application/json"),
("content-type", "text/html"),
])
}
#[test]
fn test_list() {
let mapping = sample_mapping();
assert_eq!(
mapping.keys().collect::<Vec<_>>(),
vec!["Accept", "content-type"]
);
}
#[test]
fn test_dict() {
let mapping = sample_mapping();
assert_eq!(
mapping.iter().collect::<Vec<_>>(),
vec![
("Accept", &"application/json"),
("content-type", &"text/html"),
]
);
}
#[test]
fn test_repr() {
let dict1 = CaseInsensitiveMapping::from([("Accept", "application/json")]);
let dict2 = CaseInsensitiveMapping::from([("content-type", "text/html")]);
assert_eq!(format!("{dict1:?}"), r#"{"Accept": "application/json"}"#);
assert_eq!(format!("{dict2:?}"), r#"{"content-type": "text/html"}"#);
}
#[test]
fn test_equal() {
let left = sample_mapping();
let right = CaseInsensitiveMapping::from([
("accept", "application/json"),
("Content-Type", "text/html"),
]);
assert_eq!(left, right);
}
#[test]
fn test_not_equal_when_value_differs() {
let left = sample_mapping();
let right = CaseInsensitiveMapping::from([
("accept", "application/jso"),
("Content-Type", "text/html"),
]);
assert_ne!(left, right);
}
#[test]
fn test_getitem() {
let mapping = sample_mapping();
assert_eq!(mapping.get("Accept"), Some(&"application/json"));
assert_eq!(mapping.get("accept"), Some(&"application/json"));
assert_eq!(mapping.get("aCCept"), Some(&"application/json"));
assert_eq!(mapping.get("content-type"), Some(&"text/html"));
assert_eq!(mapping.get("Content-Type"), Some(&"text/html"));
assert_eq!(mapping.get("Content-type"), Some(&"text/html"));
}
#[test]
fn test_in() {
let mapping = sample_mapping();
assert!(mapping.contains_key("Accept"));
assert!(mapping.contains_key("accept"));
assert!(mapping.contains_key("aCCept"));
assert!(mapping.contains_key("content-type"));
assert!(mapping.contains_key("Content-Type"));
}
#[test]
fn test_lookups_preserve_original_case() {
let mapping = sample_mapping();
assert_eq!(mapping.get("ACCEPT"), Some(&"application/json"));
assert_eq!(mapping.get("CONTENT-TYPE"), Some(&"text/html"));
assert_eq!(
mapping.keys().collect::<Vec<_>>(),
vec!["Accept", "content-type"]
);
}
#[test]
fn test_insert_overwrites_case_insensitively() {
let mut mapping = sample_mapping();
mapping.insert("ACCEPT", "application/xml");
assert_eq!(mapping.len(), 2);
assert_eq!(mapping.get("accept"), Some(&"application/xml"));
assert_eq!(
mapping.keys().collect::<Vec<_>>(),
vec!["ACCEPT", "content-type"]
);
}
#[test]
fn test_insert_preserves_insertion_order() {
let mut mapping = sample_mapping();
mapping.insert("X-Test", "1");
assert_eq!(
mapping.keys().collect::<Vec<_>>(),
vec!["Accept", "content-type", "X-Test"]
);
}
#[test]
fn test_missing_key() {
let mapping = sample_mapping();
assert_eq!(mapping.get("missing"), None);
assert!(!mapping.contains_key("missing"));
}
#[test]
fn test_is_empty() {
let mapping = CaseInsensitiveMapping::<&str>::new();
assert!(mapping.is_empty());
}
}
}