File: id-complex.rs

package info (click to toggle)
rust-iddqd 0.3.17-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 1,088 kB
  • sloc: makefile: 2
file content (140 lines) | stat: -rw-r--r-- 3,885 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
//! An example demonstrating `IdOrdMap` use with complex borrowed keys.

use iddqd::{
    Comparable, Equivalent, IdOrdItem, IdOrdMap, id_ord_map::Entry, id_upcast,
};
use std::path::{Path, PathBuf};

/// These are the items we'll store in the `IdOrdMap`.
#[derive(Clone, Debug, PartialEq, Eq)]
struct MyStruct {
    a: String,
    b: usize,
    c: PathBuf,
    d: Vec<usize>,
}

/// The map will be indexed uniquely by (b, c, d). Note that this is a
/// borrowed key that can be constructed efficiently.
#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
struct MyKey<'a> {
    b: usize,
    c: &'a Path,
    d: &'a [usize],
}

impl IdOrdItem for MyStruct {
    type Key<'a> = MyKey<'a>;

    fn key(&self) -> Self::Key<'_> {
        MyKey { b: self.b, c: &self.c, d: &self.d }
    }

    id_upcast!();
}

fn main() {
    // Make a `TriHashMap` with the keys we defined above.
    let mut map = IdOrdMap::new();

    let item = MyStruct {
        a: "example".to_owned(),
        b: 20,
        c: PathBuf::from("/"),
        d: Vec::new(),
    };

    // Add an item to the map.
    map.insert_unique(item.clone()).unwrap();

    // This item will conflict with the previous one due to b, c and d
    // matching.
    map.insert_unique(MyStruct {
        a: "something-else".to_owned(),
        b: 20,
        c: PathBuf::from("/"),
        d: Vec::new(),
    })
    .unwrap_err();

    // Add another item to the map. Note that this item has the same c and d
    // but a different b.
    let item2 = MyStruct {
        a: "example".to_owned(),
        b: 10,
        c: PathBuf::from("/"),
        d: Vec::new(),
    };
    map.insert_unique(item2.clone()).unwrap();

    // Lookups can happen based on a borrowed key. For example:
    assert_eq!(
        map.get(&MyKey { b: 20, c: Path::new("/"), d: &[] }),
        Some(&item)
    );

    // Values can also be mutated in place, as long as the key type implements
    // `Hash`. For example:
    {
        let mut item =
            map.get_mut(&MyKey { b: 20, c: Path::new("/"), d: &[] }).unwrap();
        item.a = "changed".to_owned();

        // Key changes will be checked when the item is dropped.
    }

    // While iterating over the map, items will be sorted by their key.
    for item in map.iter() {
        println!("{item:?}");
    }

    let item3 = MyStruct {
        a: "example".to_owned(),
        b: 20,
        c: PathBuf::from("/"),
        d: vec![1, 2, 3],
    };

    for item in [item, item2, item3.clone()] {
        let entry = map.entry(item.key());
        match entry {
            Entry::Occupied(entry) => {
                // Get the entry's item.
                let item = entry.get();
                println!("occupied: {item:?}");
            }
            Entry::Vacant(entry) => {
                // Insert a new item.
                let item_ref = entry.insert_ref(item);
                println!("inserted: {item_ref:?}");
            }
        }
    }

    // Lookups can be done with any key type that implements `Comparable`. This
    // is strictly more general than the Borrow you might be used to. For
    // example, lookups against an owned key:
    struct MyKeyOwned {
        b: usize,
        c: PathBuf,
        d: Vec<usize>,
    }

    impl Equivalent<MyKey<'_>> for MyKeyOwned {
        fn equivalent(&self, other: &MyKey<'_>) -> bool {
            self.b == other.b && self.c == other.c && self.d == other.d
        }
    }

    impl Comparable<MyKey<'_>> for MyKeyOwned {
        fn compare(&self, other: &MyKey<'_>) -> std::cmp::Ordering {
            self.b
                .cmp(&other.b)
                .then_with(|| self.c.as_path().cmp(other.c))
                .then_with(|| self.d.as_slice().cmp(other.d))
        }
    }

    let key = MyKeyOwned { b: 20, c: PathBuf::from("/"), d: vec![1, 2, 3] };
    assert_eq!(map.get(&key), Some(&item3));
}