Skip to main content

diesel/
util.rs

1/// Treats tuples as a list which can be appended to. e.g.
2/// `(a,).tuple_append(b) == (a, b)`
3pub trait TupleAppend<T> {
4    type Output;
5
6    fn tuple_append(self, right: T) -> Self::Output;
7}
8
9pub trait TupleSize {
10    const SIZE: usize;
11}
12
13#[cfg(not(feature = "std"))]
14pub(crate) mod std_compat {
15    #[cfg(feature = "hashbrown")]
16    pub(crate) type Entry<'a, K, V> =
17        hashbrown::hash_map::Entry<'a, K, V, hashbrown::DefaultHashBuilder>;
18    #[cfg(feature = "hashbrown")]
19    pub(crate) use hashbrown::HashMap;
20
21    // a dummy map impl that provides
22    // the absulut minimum of api that is required to
23    // compile diesel without any features compiled
24    //
25    // This won't be actually used by anyone as any practical
26    // usage will rely on the `std` or `sqlite-nostd` (which pulls in hashbrown)
27    // feature instead
28    //
29    // The only way you actually get this with the public API
30    // is via the StatementCache implementation
31    // for the case that you only enabled `i-implement-a-third-party-backend-and-opt-into-breaking-changes`
32    // so it might be fine to require those users to either choose `std` or `hashbrown` as feature
33    #[cfg(not(feature = "hashbrown"))]
34    mod dummy_map {
35        use core::borrow::Borrow;
36
37        pub(crate) struct VecMap<K, V>(alloc::vec::Vec<(K, V)>);
38
39        impl<K, V> Default for VecMap<K, V> {
40            fn default() -> Self {
41                Self(alloc::vec::Vec::new())
42            }
43        }
44
45        impl<K, V> FromIterator<(K, V)> for VecMap<K, V> {
46            fn from_iter<T: IntoIterator<Item = (K, V)>>(iter: T) -> Self {
47                Self(iter.into_iter().collect())
48            }
49        }
50
51        impl<K, V> VecMap<K, V> {
52            pub(crate) fn get<Q>(&self, key: &Q) -> Option<&V>
53            where
54                K: Borrow<Q>,
55                Q: PartialEq,
56            {
57                self.0
58                    .iter()
59                    .find_map(|(k, v)| (k.borrow() == key).then_some(v))
60            }
61
62            pub(crate) fn entry(&mut self, key: K) -> Entry<'_, K, V>
63            where
64                K: PartialEq,
65            {
66                // We need to use the index based lookup here to workaround borrowck
67                // limitations
68                // FIXME: polonius
69                if let Some(pos) = self.0.iter().position(|(k, _)| *k == key) {
70                    Entry::Occupied(OccupiedEntry {
71                        entry: &mut self.0[pos],
72                    })
73                } else {
74                    Entry::Vacant(VacantEntry {
75                        vec: &mut self.0,
76                        key,
77                    })
78                }
79            }
80        }
81
82        #[derive(Debug)]
83        pub struct OccupiedEntry<'a, K, V> {
84            entry: &'a mut (K, V),
85        }
86
87        impl<'a, K, V> OccupiedEntry<'a, K, V> {
88            pub(crate) fn into_mut(self) -> &'a mut V {
89                &mut self.entry.1
90            }
91        }
92
93        #[derive(Debug)]
94        pub struct VacantEntry<'a, K, V> {
95            vec: &'a mut alloc::vec::Vec<(K, V)>,
96            key: K,
97        }
98
99        impl<'a, K, V> VacantEntry<'a, K, V> {
100            pub(crate) fn key(&self) -> &K {
101                &self.key
102            }
103
104            pub(crate) fn insert(self, value: V) -> &'a mut V {
105                let Self { vec, key } = self;
106                vec.push((key, value));
107                &mut vec.last_mut().expect("We literally pushed it above").1
108            }
109        }
110
111        #[derive(Debug)]
112        pub enum Entry<'a, K, V> {
113            Occupied(OccupiedEntry<'a, K, V>),
114            Vacant(VacantEntry<'a, K, V>),
115        }
116    }
117
118    #[cfg(not(feature = "hashbrown"))]
119    pub(crate) use self::dummy_map::VecMap as HashMap;
120    #[cfg(not(feature = "hashbrown"))]
121    pub(crate) type Entry<'a, K, V> = self::dummy_map::Entry<'a, K, V>;
122
123    #[cfg(feature = "__sqlite-shared")]
124    pub(crate) fn catch_unwind<R>(f: impl FnOnce() -> R) -> Result<R, ()> {
125        Ok(f())
126    }
127
128    #[cfg(feature = "__sqlite-shared")]
129    pub(crate) fn panicking() -> bool {
130        false
131    }
132
133    #[cfg(feature = "__sqlite-shared")]
134    pub(crate) fn abort() -> ! {
135        struct DropBomb;
136
137        impl Drop for DropBomb {
138            fn drop(&mut self) {
139                panic!("Abort");
140            }
141        }
142
143        let _guard = DropBomb;
144
145        panic!("Abort");
146    }
147}
148
149#[cfg(feature = "std")]
150pub(crate) mod std_compat {
151    pub(crate) use std::collections::HashMap;
152    // Used only by the statement cache, which needs a connection, not a bare backend.
153    #[cfg(any(
154        feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes",
155        feature = "__sqlite-shared",
156        feature = "mysql",
157        feature = "mariadb",
158        feature = "postgres"
159    ))]
160    pub(crate) use std::collections::hash_map::Entry;
161    #[cfg(feature = "__sqlite-shared")]
162    pub(crate) use std::panic::catch_unwind;
163    #[cfg(feature = "__sqlite-shared")]
164    pub(crate) use std::process::abort;
165    #[cfg(feature = "__sqlite-shared")]
166    pub(crate) use std::thread::panicking;
167}