diff options
author | 2024-05-01 01:39:43 +0200 | |
---|---|---|
committer | 2024-05-01 01:39:43 +0200 | |
commit | b52c7bb610f593fffc624d461dca17ac50c81626 (patch) | |
tree | 19e1ac3268350b422154c6fd1cd3a585e250d3ac /core/src/image.rs | |
parent | f5bc336d699d0c6440f6d638a5a437baaabe1e43 (diff) | |
download | iced-b52c7bb610f593fffc624d461dca17ac50c81626.tar.gz iced-b52c7bb610f593fffc624d461dca17ac50c81626.tar.bz2 iced-b52c7bb610f593fffc624d461dca17ac50c81626.zip |
Use an opaque `Id` type for `image::Handle`
Hashing pointers is a terrible idea.
Diffstat (limited to 'core/src/image.rs')
-rw-r--r-- | core/src/image.rs | 68 |
1 files changed, 47 insertions, 21 deletions
diff --git a/core/src/image.rs b/core/src/image.rs index 5b31fbcf..a0e40787 100644 --- a/core/src/image.rs +++ b/core/src/image.rs @@ -5,19 +5,21 @@ use crate::{Rectangle, Size}; use rustc_hash::FxHasher; use std::hash::{Hash, Hasher}; -use std::path::PathBuf; +use std::path::{Path, PathBuf}; /// A handle of some image data. #[derive(Clone, PartialEq, Eq)] pub enum Handle { /// File data - Path(PathBuf), + Path(Id, PathBuf), /// In-memory data - Bytes(Bytes), + Bytes(Id, Bytes), /// Decoded image pixels in RGBA format. Rgba { + /// The id of this handle. + id: Id, /// The width of the image. width: u32, /// The height of the image. @@ -32,7 +34,9 @@ impl Handle { /// /// Makes an educated guess about the image format by examining the data in the file. pub fn from_path<T: Into<PathBuf>>(path: T) -> Handle { - Self::Path(path.into()) + let path = path.into(); + + Self::Path(Id::path(&path), path) } /// Creates an image [`Handle`] containing the image pixels directly. This @@ -46,6 +50,7 @@ impl Handle { pixels: impl Into<Bytes>, ) -> Handle { Self::Rgba { + id: Id::unique(), width, height, pixels: pixels.into(), @@ -59,24 +64,15 @@ impl Handle { /// This is useful if you already have your image loaded in-memory, maybe /// because you downloaded or generated it procedurally. pub fn from_memory(bytes: impl Into<Bytes>) -> Handle { - Self::Bytes(bytes.into()) + Self::Bytes(Id::unique(), bytes.into()) } /// Returns the unique identifier of the [`Handle`]. - pub fn id(&self) -> u64 { - let mut hasher = FxHasher::default(); - self.hash(&mut hasher); - - hasher.finish() - } -} - -impl Hash for Handle { - fn hash<H: Hasher>(&self, state: &mut H) { + pub fn id(&self) -> Id { match self { - Self::Path(path) => path.hash(state), - Self::Bytes(bytes) => bytes.as_ptr().hash(state), - Self::Rgba { pixels, .. } => pixels.as_ptr().hash(state), + Handle::Path(id, _) + | Handle::Bytes(id, _) + | Handle::Rgba { id, .. } => *id, } } } @@ -93,8 +89,8 @@ where impl std::fmt::Debug for Handle { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { - Self::Path(path) => write!(f, "Path({path:?})"), - Self::Bytes(_) => write!(f, "Bytes(...)"), + Self::Path(_, path) => write!(f, "Path({path:?})"), + Self::Bytes(_, _) => write!(f, "Bytes(...)"), Self::Rgba { width, height, .. } => { write!(f, "Pixels({width} * {height})") } @@ -102,6 +98,36 @@ impl std::fmt::Debug for Handle { } } +/// The unique identifier of some [`Handle`] data. +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum Id { + /// A unique identifier. + Unique(u64), + /// A hash identifier. + Hash(u64), +} + +impl Id { + fn unique() -> Self { + use std::sync::atomic::{self, AtomicU64}; + + static NEXT_ID: AtomicU64 = AtomicU64::new(0); + + Self::Unique(NEXT_ID.fetch_add(1, atomic::Ordering::Relaxed)) + } + + fn path(path: impl AsRef<Path>) -> Self { + let hash = { + let mut hasher = FxHasher::default(); + path.as_ref().hash(&mut hasher); + + hasher.finish() + }; + + Self::Hash(hash) + } +} + /// Image filtering strategy. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)] pub enum FilterMethod { @@ -119,7 +145,7 @@ pub trait Renderer: crate::Renderer { /// The image Handle to be displayed. Iced exposes its own default implementation of a [`Handle`] /// /// [`Handle`]: Self::Handle - type Handle: Clone + Hash; + type Handle: Clone; /// Returns the dimensions of an image for the given [`Handle`]. fn measure_image(&self, handle: &Self::Handle) -> Size<u32>; |