datafusion_expr/
ptr_eq.rs

1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements.  See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership.  The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License.  You may obtain a copy of the License at
8//
9//   http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied.  See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18use std::fmt::Debug;
19use std::hash::{Hash, Hasher};
20use std::ops::Deref;
21use std::sync::Arc;
22
23/// Compares two `Arc` pointers for equality based on their underlying pointers values.
24/// This is not equivalent to [`Arc::ptr_eq`] for fat pointers, see that method
25/// for more information.
26pub fn arc_ptr_eq<T: ?Sized>(a: &Arc<T>, b: &Arc<T>) -> bool {
27    std::ptr::eq(Arc::as_ptr(a), Arc::as_ptr(b))
28}
29
30/// Hashes an `Arc` pointer based on its underlying pointer value.
31/// The general contract for this function is that if [`arc_ptr_eq`] returns `true`
32/// for two `Arc`s, then this function should return the same hash value for both.
33pub fn arc_ptr_hash<T: ?Sized>(a: &Arc<T>, hasher: &mut impl Hasher) {
34    std::ptr::hash(Arc::as_ptr(a), hasher)
35}
36
37/// A wrapper around a pointer that implements `Eq` and `Hash` comparing
38/// the underlying pointer address.
39///
40/// If you have pointers to a `dyn UDF impl` consider using [`super::udf_eq::UdfEq`].
41#[derive(Clone)]
42#[allow(private_bounds)] // This is so that PtrEq can only be used with allowed pointer types (e.g. Arc), without allowing misuse.
43pub struct PtrEq<Ptr: PointerType>(Ptr);
44
45impl<T> PartialEq for PtrEq<Arc<T>>
46where
47    T: ?Sized,
48{
49    fn eq(&self, other: &Self) -> bool {
50        arc_ptr_eq(&self.0, &other.0)
51    }
52}
53impl<T> Eq for PtrEq<Arc<T>> where T: ?Sized {}
54
55impl<T> Hash for PtrEq<Arc<T>>
56where
57    T: ?Sized,
58{
59    fn hash<H: Hasher>(&self, state: &mut H) {
60        arc_ptr_hash(&self.0, state);
61    }
62}
63
64impl<Ptr> From<Ptr> for PtrEq<Ptr>
65where
66    Ptr: PointerType,
67{
68    fn from(ptr: Ptr) -> Self {
69        PtrEq(ptr)
70    }
71}
72
73impl<T> From<PtrEq<Arc<T>>> for Arc<T>
74where
75    T: ?Sized,
76{
77    fn from(wrapper: PtrEq<Arc<T>>) -> Self {
78        wrapper.0
79    }
80}
81
82impl<Ptr> Debug for PtrEq<Ptr>
83where
84    Ptr: PointerType + Debug,
85{
86    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
87        self.0.fmt(f)
88    }
89}
90
91impl<Ptr> Deref for PtrEq<Ptr>
92where
93    Ptr: PointerType,
94{
95    type Target = Ptr;
96
97    fn deref(&self) -> &Self::Target {
98        &self.0
99    }
100}
101
102trait PointerType {}
103impl<T> PointerType for Arc<T> where T: ?Sized {}
104
105#[cfg(test)]
106mod tests {
107    use super::*;
108    use std::hash::DefaultHasher;
109
110    #[test]
111    pub fn test_ptr_eq_wrapper() {
112        let a = Arc::new("Hello".to_string());
113        let b = Arc::new(a.deref().clone());
114        let c = Arc::new("world".to_string());
115
116        let wrapper = PtrEq(Arc::clone(&a));
117        assert_eq!(wrapper, wrapper);
118
119        // same address (equal)
120        assert_eq!(PtrEq(Arc::clone(&a)), PtrEq(Arc::clone(&a)));
121        assert_eq!(hash(PtrEq(Arc::clone(&a))), hash(PtrEq(Arc::clone(&a))));
122
123        // different address, same content (not equal)
124        assert_ne!(PtrEq(Arc::clone(&a)), PtrEq(Arc::clone(&b)));
125
126        // different address, different content (not equal)
127        assert_ne!(PtrEq(Arc::clone(&a)), PtrEq(Arc::clone(&c)));
128    }
129
130    fn hash<T: Hash>(value: T) -> u64 {
131        let hasher = &mut DefaultHasher::new();
132        value.hash(hasher);
133        hasher.finish()
134    }
135}