Skip to main content

ferroui_base/platform/
platform_handle.rs

1use super::IPlatformHandle;
2use std::any::Any;
3use std::fmt;
4
5/// Represents a platform-specific handle.
6#[derive(Clone, Debug, PartialEq, Eq, Hash)]
7pub struct PlatformHandle {
8    handle: isize,
9    handle_descriptor: Option<String>,
10}
11
12impl PlatformHandle {
13    /// Creates a handle.
14    ///
15    /// `descriptor` is an optional string that describes what `handle`
16    /// represents.
17    pub fn new(handle: isize, descriptor: Option<&str>) -> Self {
18        Self { handle, handle_descriptor: descriptor.map(str::to_owned) }
19    }
20}
21
22impl IPlatformHandle for PlatformHandle {
23    fn handle(&self) -> isize {
24        self.handle
25    }
26
27    fn handle_descriptor(&self) -> Option<&str> {
28        self.handle_descriptor.as_deref()
29    }
30
31    fn as_any(&self) -> &dyn Any {
32        self
33    }
34
35    fn equals(&self, other: &dyn IPlatformHandle) -> bool {
36        other.as_any().downcast_ref::<PlatformHandle>().is_some_and(|other| self == other)
37    }
38}
39
40impl fmt::Display for PlatformHandle {
41    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
42        write!(f, "PlatformHandle {{ {} = {} }}", self.handle_descriptor.as_deref().unwrap_or(""), self.handle)
43    }
44}
45
46#[cfg(test)]
47mod tests {
48    use super::*;
49    use std::collections::hash_map::DefaultHasher;
50    use std::hash::{Hash, Hasher};
51
52    struct IdentityHandle(u8);
53
54    impl IPlatformHandle for IdentityHandle {
55        fn handle(&self) -> isize {
56            1
57        }
58
59        fn handle_descriptor(&self) -> Option<&str> {
60            Some("HWND")
61        }
62
63        fn as_any(&self) -> &dyn Any {
64            self
65        }
66    }
67
68    fn hash_of(value: &PlatformHandle) -> u64 {
69        let mut hasher = DefaultHasher::new();
70        value.hash(&mut hasher);
71        hasher.finish()
72    }
73
74    #[test]
75    fn display_writes_descriptor_and_handle() {
76        assert_eq!(PlatformHandle::new(42, Some("HWND")).to_string(), "PlatformHandle { HWND = 42 }");
77        assert_eq!(PlatformHandle::new(7, None).to_string(), "PlatformHandle {  = 7 }");
78    }
79
80    #[test]
81    fn handles_compare_by_handle_and_descriptor() {
82        let a = PlatformHandle::new(1, Some("HWND"));
83        assert_eq!(a, PlatformHandle::new(1, Some("HWND")));
84        assert_eq!(hash_of(&a), hash_of(&PlatformHandle::new(1, Some("HWND"))));
85        assert_ne!(a, PlatformHandle::new(2, Some("HWND")));
86        assert_ne!(a, PlatformHandle::new(1, Some("NSView")));
87        assert_ne!(a, PlatformHandle::new(1, None));
88
89        assert!(a.equals(&PlatformHandle::new(1, Some("HWND"))));
90        assert!(!a.equals(&PlatformHandle::new(2, Some("HWND"))));
91    }
92
93    #[test]
94    fn handles_of_other_types_are_not_equal() {
95        let a = PlatformHandle::new(1, Some("HWND"));
96        let b = IdentityHandle(0);
97        assert!(!a.equals(&b));
98        assert!(!b.equals(&a));
99        // The default equality is identity.
100        assert!(b.equals(&b));
101        assert!(!b.equals(&IdentityHandle(b.0)));
102    }
103}