diff --git a/crates/ecolor/src/color32.rs b/crates/ecolor/src/color32.rs index 72d0496e..55e3f232 100644 --- a/crates/ecolor/src/color32.rs +++ b/crates/ecolor/src/color32.rs @@ -102,9 +102,6 @@ impl Color32 { /// i.e. often taken to mean "no color". pub const PLACEHOLDER: Self = Self::from_rgba_premultiplied(64, 254, 0, 128); - #[deprecated = "Renamed to PLACEHOLDER"] - pub const TEMPORARY_COLOR: Self = Self::PLACEHOLDER; - /// From RGB with alpha of 255 (opaque). #[inline] pub const fn from_rgb(r: u8, g: u8, b: u8) -> Self { diff --git a/crates/egui/src/containers/scroll_area.rs b/crates/egui/src/containers/scroll_area.rs index 0c4cc7ef..9e4d60d3 100644 --- a/crates/egui/src/containers/scroll_area.rs +++ b/crates/egui/src/containers/scroll_area.rs @@ -513,14 +513,6 @@ impl ScrollArea { self } - /// Turn on/off scrolling on the horizontal/vertical axes. - #[deprecated = "Renamed to `scroll`"] - #[inline] - pub fn scroll2(mut self, direction_enabled: impl Into) -> Self { - self.direction_enabled = direction_enabled.into(); - self - } - /// Control the scrolling behavior. /// /// * If `true` (default), the scroll area will respond to user scrolling. diff --git a/crates/egui/src/containers/window.rs b/crates/egui/src/containers/window.rs index fa3d0d1f..b34332ea 100644 --- a/crates/egui/src/containers/window.rs +++ b/crates/egui/src/containers/window.rs @@ -376,14 +376,6 @@ impl<'open> Window<'open> { self } - /// Enable/disable horizontal/vertical scrolling. `false` by default. - #[deprecated = "Renamed to `scroll`"] - #[inline] - pub fn scroll2(mut self, scroll: impl Into) -> Self { - self.scroll = self.scroll.scroll(scroll); - self - } - /// Enable/disable horizontal scrolling. `false` by default. #[inline] pub fn hscroll(mut self, hscroll: bool) -> Self { diff --git a/crates/egui/src/context.rs b/crates/egui/src/context.rs index 03a58f70..b567493a 100644 --- a/crates/egui/src/context.rs +++ b/crates/egui/src/context.rs @@ -2,14 +2,13 @@ use std::{borrow::Cow, cell::RefCell, panic::Location, sync::Arc, time::Duration}; -use emath::GuiRounding as _; +use emath::{GuiRounding as _, OrderedFloat}; use epaint::{ emath::{self, TSTransform}, mutex::RwLock, stats::PaintStats, tessellator, text::{FontInsert, FontPriority, Fonts}, - util::OrderedFloat, vec2, ClippedPrimitive, ClippedShape, Color32, ImageData, ImageDelta, Pos2, Rect, StrokeKind, TessellationOptions, TextureAtlas, TextureId, Vec2, }; @@ -1231,13 +1230,6 @@ impl Context { .map(|widget_rect| self.get_response(widget_rect)) } - /// Returns `true` if the widget with the given `Id` contains the pointer. - #[deprecated = "Use Response.contains_pointer or Context::read_response instead"] - pub fn widget_contains_pointer(&self, id: Id) -> bool { - self.read_response(id) - .is_some_and(|response| response.contains_pointer()) - } - /// Do all interaction for an existing widget, without (re-)registering it. pub(crate) fn get_response(&self, widget_rect: WidgetRect) -> Response { use response::Flags; @@ -2740,21 +2732,6 @@ impl Context { .map(|t| t.inverse()) } - /// Move all the graphics at the given layer. - /// - /// Is used to implement drag-and-drop preview. - /// - /// This only applied to the existing graphics at the layer, not to new graphics added later. - /// - /// For a persistent transform, use [`Self::set_transform_layer`] instead. - #[deprecated = "Use `transform_layer_shapes` instead"] - pub fn translate_layer(&self, layer_id: LayerId, delta: Vec2) { - if delta != Vec2::ZERO { - let transform = emath::TSTransform::from_translation(delta); - self.transform_layer_shapes(layer_id, transform); - } - } - /// Transform all the graphics at the given layer. /// /// Is used to implement drag-and-drop preview. diff --git a/crates/egui/src/data/input.rs b/crates/egui/src/data/input.rs index 9f15f1c4..f84bc78c 100644 --- a/crates/egui/src/data/input.rs +++ b/crates/egui/src/data/input.rs @@ -592,7 +592,7 @@ pub const NUM_POINTER_BUTTONS: usize = 5; /// State of the modifier keys. These must be fed to egui. /// -/// The best way to compare [`Modifiers`] is by using [`Modifiers::matches`]. +/// The best way to compare [`Modifiers`] is by using [`Modifiers::matches_logically`] or [`Modifiers::matches_exact`]. /// /// NOTE: For cross-platform uses, ALT+SHIFT is a bad combination of modifiers /// as on mac that is how you type special characters, @@ -775,8 +775,8 @@ impl Modifiers { /// ``` /// # use egui::Modifiers; /// # let pressed_modifiers = Modifiers::default(); - /// if pressed_modifiers.matches(Modifiers::ALT | Modifiers::SHIFT) { - /// // Alt and Shift are pressed, and nothing else + /// if pressed_modifiers.matches_logically(Modifiers::ALT | Modifiers::SHIFT) { + /// // Alt and Shift are pressed, but not ctrl/command /// } /// ``` /// @@ -817,7 +817,7 @@ impl Modifiers { /// ``` /// # use egui::Modifiers; /// # let pressed_modifiers = Modifiers::default(); - /// if pressed_modifiers.matches(Modifiers::ALT | Modifiers::SHIFT) { + /// if pressed_modifiers.matches_exact(Modifiers::ALT | Modifiers::SHIFT) { /// // Alt and Shift are pressed, and nothing else /// } /// ``` @@ -825,13 +825,13 @@ impl Modifiers { /// ## Behavior: /// ``` /// # use egui::Modifiers; - /// assert!(Modifiers::CTRL.matches(Modifiers::CTRL)); - /// assert!(!Modifiers::CTRL.matches(Modifiers::CTRL | Modifiers::SHIFT)); - /// assert!(!(Modifiers::CTRL | Modifiers::SHIFT).matches(Modifiers::CTRL)); - /// assert!((Modifiers::CTRL | Modifiers::COMMAND).matches(Modifiers::CTRL)); - /// assert!((Modifiers::CTRL | Modifiers::COMMAND).matches(Modifiers::COMMAND)); - /// assert!((Modifiers::MAC_CMD | Modifiers::COMMAND).matches(Modifiers::COMMAND)); - /// assert!(!Modifiers::COMMAND.matches(Modifiers::MAC_CMD)); + /// assert!(Modifiers::CTRL.matches_exact(Modifiers::CTRL)); + /// assert!(!Modifiers::CTRL.matches_exact(Modifiers::CTRL | Modifiers::SHIFT)); + /// assert!(!(Modifiers::CTRL | Modifiers::SHIFT).matches_exact(Modifiers::CTRL)); + /// assert!((Modifiers::CTRL | Modifiers::COMMAND).matches_exact(Modifiers::CTRL)); + /// assert!((Modifiers::CTRL | Modifiers::COMMAND).matches_exact(Modifiers::COMMAND)); + /// assert!((Modifiers::MAC_CMD | Modifiers::COMMAND).matches_exact(Modifiers::COMMAND)); + /// assert!(!Modifiers::COMMAND.matches_exact(Modifiers::MAC_CMD)); /// ``` pub fn matches_exact(&self, pattern: Self) -> bool { // alt and shift must always match the pattern: @@ -842,11 +842,6 @@ impl Modifiers { self.cmd_ctrl_matches(pattern) } - #[deprecated = "Renamed `matches_exact`, but maybe you want to use `matches_logically` instead"] - pub fn matches(&self, pattern: Self) -> bool { - self.matches_exact(pattern) - } - /// Checks only cmd/ctrl, not alt/shift. /// /// `self` here are the currently pressed modifiers, diff --git a/crates/egui/src/memory/mod.rs b/crates/egui/src/memory/mod.rs index b8cd782c..5bf1a1d8 100644 --- a/crates/egui/src/memory/mod.rs +++ b/crates/egui/src/memory/mod.rs @@ -993,59 +993,6 @@ impl Memory { self.focus_mut().focused_widget = None; } - /// Is any widget being dragged? - #[deprecated = "Use `Context::dragged_id` instead"] - #[inline(always)] - pub fn is_anything_being_dragged(&self) -> bool { - self.interaction().potential_drag_id.is_some() - } - - /// Is this specific widget being dragged? - /// - /// A widget that sense both clicks and drags is only marked as "dragged" - /// when the mouse has moved a bit, but `is_being_dragged` will return true immediately. - #[deprecated = "Use `Context::is_being_dragged` instead"] - #[inline(always)] - pub fn is_being_dragged(&self, id: Id) -> bool { - self.interaction().potential_drag_id == Some(id) - } - - /// Get the id of the widget being dragged, if any. - /// - /// Note that this is set as soon as the mouse is pressed, - /// so the widget may not yet be marked as "dragged", - /// as that can only happen after the mouse has moved a bit - /// (at least if the widget is interesated in both clicks and drags). - #[deprecated = "Use `Context::dragged_id` instead"] - #[inline(always)] - pub fn dragged_id(&self) -> Option { - self.interaction().potential_drag_id - } - - /// Set which widget is being dragged. - #[inline(always)] - #[deprecated = "Use `Context::set_dragged_id` instead"] - pub fn set_dragged_id(&mut self, id: Id) { - self.interaction_mut().potential_drag_id = Some(id); - } - - /// Stop dragging any widget. - #[inline(always)] - #[deprecated = "Use `Context::stop_dragging` instead"] - pub fn stop_dragging(&mut self) { - self.interaction_mut().potential_drag_id = None; - } - - /// Is something else being dragged? - /// - /// Returns true if we are dragging something, but not the given widget. - #[inline(always)] - #[deprecated = "Use `Context::dragging_something_else` instead"] - pub fn dragging_something_else(&self, not_this: Id) -> bool { - let drag_id = self.interaction().potential_drag_id; - drag_id.is_some() && drag_id != Some(not_this) - } - /// Forget window positions, sizes etc. /// Can be used to auto-layout windows. pub fn reset_areas(&mut self) { diff --git a/crates/egui/src/painter.rs b/crates/egui/src/painter.rs index 732d78ee..c17fbb27 100644 --- a/crates/egui/src/painter.rs +++ b/crates/egui/src/painter.rs @@ -582,16 +582,6 @@ impl Painter { )); } } - - #[deprecated = "Use `Painter::galley` or `Painter::galley_with_override_text_color` instead"] - #[inline] - pub fn galley_with_color(&self, pos: Pos2, galley: Arc, text_color: Color32) { - if !galley.is_empty() { - self.add(Shape::galley_with_override_text_color( - pos, galley, text_color, - )); - } - } } fn tint_shape_towards(shape: &mut Shape, target: Color32) { diff --git a/crates/egui/src/response.rs b/crates/egui/src/response.rs index 0fdadfcc..b54cb10e 100644 --- a/crates/egui/src/response.rs +++ b/crates/egui/src/response.rs @@ -395,19 +395,6 @@ impl Response { self.drag_stopped() && self.ctx.input(|i| i.pointer.button_released(button)) } - /// The widget was being dragged, but now it has been released. - #[inline] - #[deprecated = "Renamed 'drag_stopped'"] - pub fn drag_released(&self) -> bool { - self.drag_stopped() - } - - /// The widget was being dragged by the button, but now it has been released. - #[deprecated = "Renamed 'drag_stopped_by'"] - pub fn drag_released_by(&self, button: PointerButton) -> bool { - self.drag_stopped_by(button) - } - /// If dragged, how many points were we dragged and in what direction? #[inline] pub fn drag_delta(&self) -> Vec2 { diff --git a/crates/egui/src/widgets/text_edit/output.rs b/crates/egui/src/widgets/text_edit/output.rs index 2aa6711e..8149bbe5 100644 --- a/crates/egui/src/widgets/text_edit/output.rs +++ b/crates/egui/src/widgets/text_edit/output.rs @@ -23,11 +23,4 @@ pub struct TextEditOutput { pub cursor_range: Option, } -impl TextEditOutput { - #[deprecated = "Renamed `self.galley_pos`"] - pub fn text_draw_pos(&self) -> crate::Pos2 { - self.galley_pos - } -} - // TODO(emilk): add `output.paint` and `output.store` and split out that code from `TextEdit::show`. diff --git a/crates/egui_extras/src/image.rs b/crates/egui_extras/src/image.rs index b181a6bc..b5ed70fa 100644 --- a/crates/egui_extras/src/image.rs +++ b/crates/egui_extras/src/image.rs @@ -1,222 +1,6 @@ -#![allow(deprecated)] - -use egui::{load::SizedTexture, mutex::Mutex, ColorImage, TextureOptions, Vec2}; - #[cfg(feature = "svg")] use egui::SizeHint; -/// An image to be shown in egui. -/// -/// Load once, and save somewhere in your app state. -/// -/// Use the `svg` and `image` features to enable more constructors. -/// -/// ⚠ This type is deprecated: Consider using [`egui::Image`] instead. -#[deprecated = "consider using `egui::Image` instead"] -pub struct RetainedImage { - debug_name: String, - - /// Texel size. - /// - /// Same as [`Self.image`]`.size` - texel_size: [usize; 2], - - /// Original SVG size (if this is an SVG), or same as [`Self::texel_size`]. - source_size: Vec2, - - /// Cleared once [`Self::texture`] has been loaded. - image: Mutex, - - /// Lazily loaded when we have an egui context. - texture: Mutex>, - - options: TextureOptions, -} - -impl RetainedImage { - pub fn from_color_image(debug_name: impl Into, image: ColorImage) -> Self { - Self { - debug_name: debug_name.into(), - texel_size: image.size, - source_size: image.source_size, - image: Mutex::new(image), - texture: Default::default(), - options: Default::default(), - } - } - - /// Load a (non-svg) image. - /// - /// `image_bytes` should be the raw contents of an image file (`.png`, `.jpg`, …). - /// - /// Requires the "image" feature. You must also opt-in to the image formats you need - /// with e.g. `image = { version = "0.25", features = ["jpeg", "png"] }`. - /// - /// # Errors - /// On invalid image or unsupported image format. - #[cfg(feature = "image")] - pub fn from_image_bytes( - debug_name: impl Into, - image_bytes: &[u8], - ) -> Result { - Ok(Self::from_color_image( - debug_name, - load_image_bytes(image_bytes).map_err(|err| err.to_string())?, - )) - } - - /// Pass in the bytes of an SVG that you've loaded. - /// - /// # Errors - /// On invalid image - #[cfg(feature = "svg")] - pub fn from_svg_bytes( - debug_name: impl Into, - svg_bytes: &[u8], - options: &resvg::usvg::Options<'_>, - ) -> Result { - Self::from_svg_bytes_with_size(debug_name, svg_bytes, Default::default(), options) - } - - /// Pass in the str of an SVG that you've loaded. - /// - /// # Errors - /// On invalid image - #[cfg(feature = "svg")] - pub fn from_svg_str( - debug_name: impl Into, - svg_str: &str, - options: &resvg::usvg::Options<'_>, - ) -> Result { - Self::from_svg_bytes_with_size(debug_name, svg_str.as_bytes(), Default::default(), options) - } - - /// Pass in the bytes of an SVG that you've loaded - /// and the scaling option to resize the SVG with. - /// - /// # Errors - /// On invalid image - #[cfg(feature = "svg")] - pub fn from_svg_bytes_with_size( - debug_name: impl Into, - svg_bytes: &[u8], - size_hint: SizeHint, - options: &resvg::usvg::Options<'_>, - ) -> Result { - Ok(Self::from_color_image( - debug_name, - load_svg_bytes_with_size(svg_bytes, size_hint, options)?, - )) - } - - /// Set the texture filters to use for the image. - /// - /// **Note:** If the texture has already been uploaded to the GPU, this will require - /// re-uploading the texture with the updated filter. - /// - /// # Example - /// ```rust - /// # use egui_extras::RetainedImage; - /// # use egui::{Color32, epaint::{ColorImage, textures::TextureOptions}}; - /// # let pixels = vec![Color32::BLACK]; - /// # let color_image = ColorImage::new([1, 1], pixels); - /// # - /// // Upload a pixel art image without it getting blurry when resized - /// let image = RetainedImage::from_color_image("my_image", color_image) - /// .with_options(TextureOptions::NEAREST); - /// ``` - #[inline] - pub fn with_options(mut self, options: TextureOptions) -> Self { - self.options = options; - - // If the texture has already been uploaded, this will force it to be re-uploaded with the - // updated filter. - *self.texture.lock() = None; - - self - } - - /// The size of the image data (number of pixels wide/high). - pub fn texel_size(&self) -> [usize; 2] { - self.texel_size - } - - /// The size of the original SVG image (if any). - /// - /// Note that this can differ from [`Self::texel_size`] if the SVG was rasterized at a different - /// resolution than the size of the original SVG. - pub fn source_size(&self) -> Vec2 { - self.source_size - } - - #[deprecated = "use `texel_size` or `source_size` instead"] - pub fn size(&self) -> [usize; 2] { - self.texel_size - } - - /// The width of the image. - #[deprecated = "use `texel_size` or `source_size` instead"] - pub fn width(&self) -> usize { - self.texel_size[0] - } - - /// The height of the image. - #[deprecated = "use `texel_size` or `source_size` instead"] - pub fn height(&self) -> usize { - self.texel_size[1] - } - - /// The size of the image data (number of pixels wide/high). - #[deprecated = "use `texel_size` or `source_size` instead"] - pub fn size_vec2(&self) -> egui::Vec2 { - let [w, h] = self.texel_size; - egui::vec2(w as f32, h as f32) - } - - /// The debug name of the image, e.g. the file name. - pub fn debug_name(&self) -> &str { - &self.debug_name - } - - /// The texture id for this image. - pub fn texture_id(&self, ctx: &egui::Context) -> egui::TextureId { - self.texture - .lock() - .get_or_insert_with(|| { - let image: &mut ColorImage = &mut self.image.lock(); - let image = std::mem::take(image); - ctx.load_texture(&self.debug_name, image, self.options) - }) - .id() - } - - /// Show the image with the given maximum size. - pub fn show_max_size(&self, ui: &mut egui::Ui, max_size: egui::Vec2) -> egui::Response { - let mut desired_size = self.source_size(); - desired_size *= (max_size.x / desired_size.x).min(1.0); - desired_size *= (max_size.y / desired_size.y).min(1.0); - self.show_size(ui, desired_size) - } - - /// Show the image with the original size (one image pixel = one gui point). - pub fn show(&self, ui: &mut egui::Ui) -> egui::Response { - self.show_size(ui, self.source_size()) - } - - /// Show the image with the given scale factor (1.0 = original size). - pub fn show_scaled(&self, ui: &mut egui::Ui, scale: f32) -> egui::Response { - self.show_size(ui, self.source_size() * scale) - } - - /// Show the image with the given size. - pub fn show_size(&self, ui: &mut egui::Ui, desired_size: egui::Vec2) -> egui::Response { - // We need to convert the SVG to a texture to display it: - // Future improvement: tell backend to do mip-mapping of the image to - // make it look smoother when downsized. - ui.image(SizedTexture::new(self.texture_id(ui.ctx()), desired_size)) - } -} - // ---------------------------------------------------------------------------- /// Load a (non-svg) image. @@ -227,7 +11,7 @@ impl RetainedImage { /// # Errors /// On invalid image or unsupported image format. #[cfg(feature = "image")] -pub fn load_image_bytes(image_bytes: &[u8]) -> Result { +pub fn load_image_bytes(image_bytes: &[u8]) -> Result { profiling::function_scope!(); let image = image::load_from_memory(image_bytes).map_err(|err| match err { image::ImageError::Unsupported(err) => match err.kind() { @@ -247,7 +31,10 @@ pub fn load_image_bytes(image_bytes: &[u8]) -> Result Result, -) -> Result { +) -> Result { load_svg_bytes_with_size(svg_bytes, Default::default(), options) } @@ -275,7 +62,7 @@ pub fn load_svg_bytes_with_size( svg_bytes: &[u8], size_hint: SizeHint, options: &resvg::usvg::Options<'_>, -) -> Result { +) -> Result { use egui::Vec2; use resvg::{ tiny_skia::Pixmap, @@ -323,7 +110,7 @@ pub fn load_svg_bytes_with_size( &mut pixmap.as_mut(), ); - let image = ColorImage::from_rgba_premultiplied([w as _, h as _], pixmap.data()) + let image = egui::ColorImage::from_rgba_premultiplied([w as _, h as _], pixmap.data()) .with_source_size(source_size); Ok(image) diff --git a/crates/egui_extras/src/lib.rs b/crates/egui_extras/src/lib.rs index 1a58402f..f70ff9ff 100644 --- a/crates/egui_extras/src/lib.rs +++ b/crates/egui_extras/src/lib.rs @@ -25,9 +25,6 @@ mod table; #[cfg(feature = "chrono")] pub use crate::datepicker::DatePickerButton; -#[doc(hidden)] -#[expect(deprecated)] -pub use crate::image::RetainedImage; pub(crate) use crate::layout::StripLayout; pub use crate::sizing::Size; pub use crate::strip::*; diff --git a/crates/epaint/src/lib.rs b/crates/epaint/src/lib.rs index a1972769..633aa668 100644 --- a/crates/epaint/src/lib.rs +++ b/crates/epaint/src/lib.rs @@ -2,7 +2,7 @@ //! //! Made for [`egui`](https://github.com/emilk/egui/). //! -//! Create some [`Shape`]:s and pass them to [`tessellate_shapes`] to generate [`Mesh`]:es +//! Create some [`Shape`]:s and pass them to [`Tessellator::tessellate_shapes`] to generate [`Mesh`]:es //! that you can then paint using some graphics API of your choice (e.g. OpenGL). //! //! ## Coordinate system @@ -72,9 +72,6 @@ pub use self::{ #[deprecated = "Renamed to CornerRadius"] pub type Rounding = CornerRadius; -#[expect(deprecated)] -pub use tessellator::tessellate_shapes; - pub use ecolor::{Color32, Hsva, HsvaGamma, Rgba}; pub use emath::{pos2, vec2, Pos2, Rect, Vec2}; diff --git a/crates/epaint/src/margin.rs b/crates/epaint/src/margin.rs index 2e87b7b3..417cc556 100644 --- a/crates/epaint/src/margin.rs +++ b/crates/epaint/src/margin.rs @@ -96,18 +96,6 @@ impl Margin { pub const fn is_same(self) -> bool { self.left == self.right && self.left == self.top && self.left == self.bottom } - - #[deprecated = "Use `rect + margin` instead"] - #[inline] - pub fn expand_rect(self, rect: Rect) -> Rect { - Rect::from_min_max(rect.min - self.left_top(), rect.max + self.right_bottom()) - } - - #[deprecated = "Use `rect - margin` instead"] - #[inline] - pub fn shrink_rect(self, rect: Rect) -> Rect { - Rect::from_min_max(rect.min + self.left_top(), rect.max - self.right_bottom()) - } } impl From for Margin { diff --git a/crates/epaint/src/tessellator.rs b/crates/epaint/src/tessellator.rs index 32f715b1..b083ea45 100644 --- a/crates/epaint/src/tessellator.rs +++ b/crates/epaint/src/tessellator.rs @@ -1300,8 +1300,6 @@ fn mul_color(color: Color32, factor: f32) -> Color32 { /// Converts [`Shape`]s into triangles ([`Mesh`]). /// /// For performance reasons it is smart to reuse the same [`Tessellator`]. -/// -/// See also [`tessellate_shapes`], a convenient wrapper around [`Tessellator`]. #[derive(Clone)] pub struct Tessellator { pixels_per_point: f32, @@ -2194,18 +2192,6 @@ impl Tessellator { } } -#[deprecated = "Use `Tessellator::new(…).tessellate_shapes(…)` instead"] -pub fn tessellate_shapes( - pixels_per_point: f32, - options: TessellationOptions, - font_tex_size: [usize; 2], - prepared_discs: Vec, - shapes: Vec, -) -> Vec { - Tessellator::new(pixels_per_point, options, font_tex_size, prepared_discs) - .tessellate_shapes(shapes) -} - impl Tessellator { /// Turns [`Shape`]:s into sets of triangles. /// diff --git a/crates/epaint/src/util/mod.rs b/crates/epaint/src/util/mod.rs index 383b9456..47157663 100644 --- a/crates/epaint/src/util/mod.rs +++ b/crates/epaint/src/util/mod.rs @@ -1,6 +1,3 @@ -#[deprecated = "Use emath::OrderedFloat instead"] -pub use emath::OrderedFloat; - /// Hash the given value with a predictable hasher. #[inline] pub fn hash(value: impl std::hash::Hash) -> u64 {