diff --git a/Cargo.lock b/Cargo.lock index 6190484..8c544e3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -527,6 +527,15 @@ dependencies = [ "piper", ] +[[package]] +name = "borsh" +version = "1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad8646f98db542e39fc66e68a20b2144f6a732636df7c2354e74645faaa433ce" +dependencies = [ + "cfg_aliases", +] + [[package]] name = "bumpalo" version = "3.17.0" @@ -813,6 +822,7 @@ dependencies = [ "pulldown-cmark", "rustc-hash 2.1.1", "smallvec", + "smol_str 0.3.2", "syntect", "taffy", "tinyvg-rs", @@ -3622,6 +3632,16 @@ dependencies = [ "serde", ] +[[package]] +name = "smol_str" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9676b89cd56310a87b93dec47b11af744f34d5fc9f367b829474eec0a891350d" +dependencies = [ + "borsh", + "serde", +] + [[package]] name = "socket2" version = "0.5.9" @@ -5413,7 +5433,7 @@ dependencies = [ "rustix 0.38.44", "sctk-adwaita", "smithay-client-toolkit", - "smol_str", + "smol_str 0.2.2", "tracing", "unicode-segmentation", "wasm-bindgen", diff --git a/crates/craft_core/Cargo.toml b/crates/craft_core/Cargo.toml index e9973a7..06a39d2 100644 --- a/crates/craft_core/Cargo.toml +++ b/crates/craft_core/Cargo.toml @@ -30,6 +30,8 @@ default = ["clipboard", "accesskit"] [dependencies] craft_logging = { path = "../craft_logger", version = "0.1.0" } +smol_str = "0.3.2" + [dependencies.cfg-if] workspace = true diff --git a/crates/craft_core/src/animations/animation.rs b/crates/craft_core/src/animations/animation.rs index fcfa287..2d1cfe1 100644 --- a/crates/craft_core/src/animations/animation.rs +++ b/crates/craft_core/src/animations/animation.rs @@ -6,6 +6,7 @@ use smallvec::SmallVec; use std::collections::HashMap; use std::iter::zip; use std::time::Duration; +use smol_str::SmolStr; #[derive(Clone, Debug)] pub struct KeyFrame { @@ -80,7 +81,7 @@ pub enum TimingFunction { #[derive(Clone, Debug)] pub struct Animation { - pub name: String, + pub name: SmolStr, pub key_frames: SmallVec<[KeyFrame; 2]>, pub duration: Duration, pub timing_function: TimingFunction, @@ -96,7 +97,7 @@ pub enum LoopAmount { impl Animation { pub fn new(name: &str, duration: Duration, timing_function: TimingFunction) -> Self { Self { - name: name.to_string(), + name: name.into(), key_frames: SmallVec::new(), duration, timing_function, diff --git a/crates/craft_core/src/components/component.rs b/crates/craft_core/src/components/component.rs index 72426f3..76c13b2 100644 --- a/crates/craft_core/src/components/component.rs +++ b/crates/craft_core/src/components/component.rs @@ -9,6 +9,7 @@ use crate::elements::{Container, Element}; use crate::window_context::WindowContext; use std::any::{Any, TypeId}; use std::ops::Deref; +use smol_str::SmolStr; /// A Component's view function. pub type ViewFn = fn( @@ -42,7 +43,7 @@ pub struct ComponentData { pub view_fn: ViewFn, pub update_fn: UpdateFn, /// A unique identifier for view_fn. - pub tag: String, + pub tag: SmolStr, /// The type id of the view function. This is currently not used. pub type_id: TypeId, } @@ -59,7 +60,7 @@ pub enum ComponentOrElement { pub struct ComponentSpecification { pub component: ComponentOrElement, /// Specify a key when the component position or type may change, but state should be retained. - pub key: Option, + pub key: Option, /// A read only reference to the props of the component. pub props: Option, /// The children of the component. @@ -79,8 +80,8 @@ impl ComponentSpecification { } } - pub fn key(mut self, key: &str) -> Self { - self.key = Some(key.to_owned()); + pub fn key>(mut self, key: T) -> Self { + self.key = Some(key.into()); self } @@ -416,7 +417,7 @@ where default_props: Self::default_props, view_fn: Self::generic_view_internal, update_fn: Self::update_internal, - tag: std::any::type_name_of_val(&Self::generic_view_internal).to_string(), + tag: std::any::type_name_of_val(&Self::generic_view_internal).into(), type_id: Self::generic_view_internal.type_id(), }; diff --git a/crates/craft_core/src/devtools/dev_tools_element.rs b/crates/craft_core/src/devtools/dev_tools_element.rs index 42a4c13..0366154 100644 --- a/crates/craft_core/src/devtools/dev_tools_element.rs +++ b/crates/craft_core/src/devtools/dev_tools_element.rs @@ -18,6 +18,7 @@ use std::sync::Arc; use kurbo::Affine; use taffy::{NodeId, TaffyTree}; use winit::window::Window; +use smol_str::SmolStr; #[derive(Clone, Default)] pub struct DevTools { diff --git a/crates/craft_core/src/devtools/layout_window.rs b/crates/craft_core/src/devtools/layout_window.rs index 10d7b4f..028615f 100644 --- a/crates/craft_core/src/devtools/layout_window.rs +++ b/crates/craft_core/src/devtools/layout_window.rs @@ -353,7 +353,8 @@ impl Component for LayoutWindow { } fn update(context: &mut Context) { - if let Some(id) = context.target().and_then(|e| e.get_id().clone()) { + let id = context.target().and_then(|e| e.get_id().map(|id| id.to_string())); + if let Some(id) = id { if context.message().clicked() { if id == "tab_styles" { context.state_mut().layout_tab = LayoutTab::Styles diff --git a/crates/craft_core/src/devtools/tree_window.rs b/crates/craft_core/src/devtools/tree_window.rs index 7aa5fe5..725e142 100644 --- a/crates/craft_core/src/devtools/tree_window.rs +++ b/crates/craft_core/src/devtools/tree_window.rs @@ -58,7 +58,7 @@ pub(crate) fn tree_window( row = row.push( Container::new() .push( - Text::new(custom_id.as_str()) + Text::new(custom_id) .color(Color::WHITE) .margin("2.5px", "10px", "2.5px", "10px") ) diff --git a/crates/craft_core/src/elements/base_element_state.rs b/crates/craft_core/src/elements/base_element_state.rs index 05cebf8..4c55f23 100644 --- a/crates/craft_core/src/elements/base_element_state.rs +++ b/crates/craft_core/src/elements/base_element_state.rs @@ -3,6 +3,7 @@ use crate::elements::element_states::ElementState; use crate::style::Style; use std::collections::HashMap; use rustc_hash::FxHashMap; +use smol_str::SmolStr; use crate::animations::animation::ActiveAnimation; #[derive(Debug, Default, Clone)] @@ -15,7 +16,7 @@ pub struct BaseElementState { /// Useful for scroll thumbs. pub(crate) pointer_capture: HashMap, pub(crate) focused: bool, - pub(crate) animations: Option>, + pub(crate) animations: Option>, } impl<'a> BaseElementState { diff --git a/crates/craft_core/src/elements/canvas.rs b/crates/craft_core/src/elements/canvas.rs index 86d86ca..ad9e0c4 100644 --- a/crates/craft_core/src/elements/canvas.rs +++ b/crates/craft_core/src/elements/canvas.rs @@ -18,6 +18,7 @@ use kurbo::Affine; use taffy::{NodeId, TaffyTree}; use winit::window::Window; use crate::elements::StatefulElement; +use smol_str::SmolStr; #[derive(Clone, Default)] pub struct Canvas { diff --git a/crates/craft_core/src/elements/container.rs b/crates/craft_core/src/elements/container.rs index 7187e86..3f8a45e 100644 --- a/crates/craft_core/src/elements/container.rs +++ b/crates/craft_core/src/elements/container.rs @@ -19,6 +19,7 @@ use kurbo::Affine; use taffy::{NodeId, TaffyTree}; use winit::window::Window; use crate::elements::StatefulElement; +use smol_str::SmolStr; /// An element for storing related elements. #[derive(Clone, Default)] diff --git a/crates/craft_core/src/elements/dropdown.rs b/crates/craft_core/src/elements/dropdown.rs index 2655cdf..12c2007 100644 --- a/crates/craft_core/src/elements/dropdown.rs +++ b/crates/craft_core/src/elements/dropdown.rs @@ -19,6 +19,7 @@ use std::sync::Arc; use kurbo::Affine; use taffy::{NodeId, Position, TaffyTree, TraversePartialTree}; use winit::window::Window; +use smol_str::SmolStr; /// The index of the dropdown list in the layout tree. const DROPDOWN_LIST_INDEX: usize = 1; diff --git a/crates/craft_core/src/elements/element.rs b/crates/craft_core/src/elements/element.rs index 288baab..cb06c4c 100644 --- a/crates/craft_core/src/elements/element.rs +++ b/crates/craft_core/src/elements/element.rs @@ -22,6 +22,7 @@ use std::mem; use std::sync::Arc; use std::time::Duration; use rustc_hash::FxHashMap; +use smol_str::SmolStr; use taffy::{NodeId, Overflow, TaffyTree}; use winit::window::Window; @@ -72,8 +73,8 @@ pub trait Element: Any + StandardElementClone + Send + Sync { } } - fn get_id(&self) -> &Option { - &self.element_data().id + fn get_id(&self) -> Option<&str> { + self.element_data().id.as_deref() } fn component_id(&self) -> ComponentId { @@ -552,8 +553,8 @@ macro_rules! generate_component_methods_no_children { } #[allow(dead_code)] - pub fn key(mut self, key: &str) -> Self { - self.element_data.key = Some(key.to_string()); + pub fn key>(mut self, key: T) -> Self { + self.element_data.key = Some(key.into()); self } @@ -564,8 +565,8 @@ macro_rules! generate_component_methods_no_children { } #[allow(dead_code)] - pub fn id(mut self, id: &str) -> Self { - self.element_data.id = Some(id.to_string()); + pub fn id>(mut self, id: T) -> Self { + self.element_data.id = Some(id.into()); self } @@ -640,6 +641,7 @@ macro_rules! generate_component_methods_private_push { #[macro_export] macro_rules! generate_component_methods { + () => { $crate::generate_component_methods_no_children!(); diff --git a/crates/craft_core/src/elements/element_data.rs b/crates/craft_core/src/elements/element_data.rs index fd1147a..d42ea07 100644 --- a/crates/craft_core/src/elements/element_data.rs +++ b/crates/craft_core/src/elements/element_data.rs @@ -1,3 +1,4 @@ +use smol_str::SmolStr; use crate::components::{ComponentId, ComponentSpecification}; use crate::components::Props; use crate::elements::element::ElementBoxed; @@ -31,14 +32,14 @@ pub struct ElementData { pub children: Vec, /// A user-defined id for the element. - pub id: Option, + pub id: Option, /// The id of the component that this element belongs to. pub component_id: ComponentId, // Used for converting the element to a component specification. pub child_specs: Vec, - pub(crate) key: Option, + pub(crate) key: Option, pub(crate) props: Option, pub(crate) event_handlers: EventHandlers, } diff --git a/crates/craft_core/src/elements/element_pre_order_iterator.rs b/crates/craft_core/src/elements/element_pre_order_iterator.rs index 43fcf6d..0599f4c 100644 --- a/crates/craft_core/src/elements/element_pre_order_iterator.rs +++ b/crates/craft_core/src/elements/element_pre_order_iterator.rs @@ -82,12 +82,12 @@ mod tests { initial_tree.component_tree.print_tree(); let mut iter = initial_tree.element_tree.internal.pre_order_iter(); - assert_eq!(iter.next().unwrap().get_id().clone(), Some("0".to_string())); - assert_eq!(iter.next().unwrap().get_id().clone(), Some("1".to_string())); - assert_eq!(iter.next().unwrap().get_id().clone(), Some("2".to_string())); - assert_eq!(iter.next().unwrap().get_id().clone(), Some("3".to_string())); - assert_eq!(iter.next().unwrap().get_id().clone(), Some("4".to_string())); - assert_eq!(iter.next().unwrap().get_id().clone(), Some("5".to_string())); + assert_eq!(iter.next().unwrap().get_id().clone(), Some("0".into())); + assert_eq!(iter.next().unwrap().get_id().clone(), Some("1".into())); + assert_eq!(iter.next().unwrap().get_id().clone(), Some("2".into())); + assert_eq!(iter.next().unwrap().get_id().clone(), Some("3".into())); + assert_eq!(iter.next().unwrap().get_id().clone(), Some("4".into())); + assert_eq!(iter.next().unwrap().get_id().clone(), Some("5".into())); assert!(iter.next().is_none()); } } diff --git a/crates/craft_core/src/elements/font.rs b/crates/craft_core/src/elements/font.rs index bcd9b81..c581c19 100644 --- a/crates/craft_core/src/elements/font.rs +++ b/crates/craft_core/src/elements/font.rs @@ -14,6 +14,7 @@ use std::sync::Arc; use kurbo::Affine; use taffy::{NodeId, TaffyTree}; use winit::window::Window; +use smol_str::SmolStr; #[derive(Clone)] pub struct Font { diff --git a/crates/craft_core/src/elements/image.rs b/crates/craft_core/src/elements/image.rs index 9a94912..43bfd2a 100644 --- a/crates/craft_core/src/elements/image.rs +++ b/crates/craft_core/src/elements/image.rs @@ -16,6 +16,7 @@ use std::sync::Arc; use kurbo::Affine; use taffy::{NodeId, TaffyTree}; use winit::window::Window; +use smol_str::SmolStr; #[derive(Clone)] pub struct Image { diff --git a/crates/craft_core/src/elements/overlay.rs b/crates/craft_core/src/elements/overlay.rs index 3be4835..63dc441 100644 --- a/crates/craft_core/src/elements/overlay.rs +++ b/crates/craft_core/src/elements/overlay.rs @@ -15,6 +15,7 @@ use std::sync::Arc; use kurbo::Affine; use taffy::{NodeId, TaffyTree}; use winit::window::Window; +use smol_str::SmolStr; /// An element for storing related elements. #[derive(Clone, Default)] diff --git a/crates/craft_core/src/elements/slider.rs b/crates/craft_core/src/elements/slider.rs index fa02915..fcadc01 100644 --- a/crates/craft_core/src/elements/slider.rs +++ b/crates/craft_core/src/elements/slider.rs @@ -25,6 +25,7 @@ use ui_events::keyboard::{Code, KeyState}; use ui_events::keyboard::Code::{ArrowDown, ArrowLeft, ArrowRight, ArrowUp}; use winit::window::Window; use crate::elements::StatefulElement; +use smol_str::SmolStr; #[derive(Clone, Copy, Default, Debug, PartialEq, Eq)] pub enum SliderDirection { diff --git a/crates/craft_core/src/elements/switch.rs b/crates/craft_core/src/elements/switch.rs index 987d140..cf43c7f 100644 --- a/crates/craft_core/src/elements/switch.rs +++ b/crates/craft_core/src/elements/switch.rs @@ -20,6 +20,7 @@ use taffy::{NodeId, TaffyTree}; use ui_events::keyboard::{Code, KeyState}; use winit::window::Window; use crate::elements::StatefulElement; +use smol_str::SmolStr; /// An element that represents an on or off state. #[derive(Clone)] diff --git a/crates/craft_core/src/elements/text.rs b/crates/craft_core/src/elements/text.rs index 80f31ab..7290d10 100644 --- a/crates/craft_core/src/elements/text.rs +++ b/crates/craft_core/src/elements/text.rs @@ -38,11 +38,12 @@ use winit::dpi; use web_time as time; use winit::window::Window; use craft_primitives::ColorBrush; +use smol_str::SmolStr; // A stateful element that shows text. #[derive(Clone, Default)] pub struct Text { - text: Option, + text: Option, element_data: ElementData, selectable: bool, } @@ -50,7 +51,7 @@ pub struct Text { pub struct TextState { scale_factor: f32, selection: Selection, - text: Option, + text: Option, text_hash: Option, text_render: Option, last_text_style: Style, @@ -74,7 +75,7 @@ impl StatefulElement for Text {} impl Text { pub fn new(text: &str) -> Text { Text { - text: Some(text.to_string()), + text: Some(text.into()), element_data: Default::default(), selectable: true, } @@ -320,7 +321,7 @@ impl Element for Text { let mut current_node = accesskit::Node::new(Role::Label); let padding_box = self.element_data().layout_item.computed_box_transformed.padding_rectangle().scale(scale_factor); - current_node.set_value(*Box::new(state.text.clone().unwrap())); + current_node.set_value(state.text.as_deref().unwrap()); current_node.add_action(Action::SetTextSelection); current_node.set_bounds(accesskit::Rect { diff --git a/crates/craft_core/src/elements/text_input.rs b/crates/craft_core/src/elements/text_input.rs index 45aa863..42b0f9a 100644 --- a/crates/craft_core/src/elements/text_input.rs +++ b/crates/craft_core/src/elements/text_input.rs @@ -38,6 +38,7 @@ use crate::elements::base_element_state::BaseElementState; use crate::reactive::element_id::create_unique_element_id; use crate::text::parley_editor::{PlainEditor, PlainEditorDriver}; use crate::utils::cloneable_any::CloneableAny; +use smol_str::SmolStr; // A stateful element that shows text. #[derive(Clone, Default)] diff --git a/crates/craft_core/src/elements/tinyvg.rs b/crates/craft_core/src/elements/tinyvg.rs index eef850e..d1dae6f 100644 --- a/crates/craft_core/src/elements/tinyvg.rs +++ b/crates/craft_core/src/elements/tinyvg.rs @@ -17,6 +17,7 @@ use std::sync::Arc; use kurbo::Affine; use taffy::{NodeId, TaffyTree}; use winit::window::Window; +use smol_str::SmolStr; #[derive(Clone)] pub struct TinyVg { diff --git a/crates/craft_core/src/reactive/tree.rs b/crates/craft_core/src/reactive/tree.rs index 87c49c3..d6ed8cb 100644 --- a/crates/craft_core/src/reactive/tree.rs +++ b/crates/craft_core/src/reactive/tree.rs @@ -13,15 +13,16 @@ use crate::text::text_context::TextContext; use crate::window_context::WindowContext; use crate::GlobalState; use std::collections::{HashMap, HashSet, VecDeque}; +use smol_str::SmolStr; #[derive(Clone)] pub(crate) struct ComponentTreeNode { pub is_element: bool, - pub key: Option, - pub tag: String, + pub key: Option, + pub tag: SmolStr, pub update: UpdateFn, pub children: Vec, - pub children_keys: HashMap, + pub children_keys: HashMap, pub id: ComponentId, pub(crate) parent_id: Option, pub props: Props, @@ -104,7 +105,7 @@ pub(crate) fn diff_trees( let mut component_tree = ComponentTreeNode { is_element: true, key: None, - tag: "root".to_string(), + tag: "root".into(), update: dummy_update, children: vec![], children_keys: HashMap::new(), @@ -157,7 +158,7 @@ pub(crate) fn diff_trees( let mut element = element; // Store the new tag, i.e. the element's name. - let new_tag = element.internal.name().to_string(); + let new_tag = element.internal.name(); let mut should_update = false; let id = match old_tag { @@ -202,7 +203,7 @@ pub(crate) fn diff_trees( let new_component_node = ComponentTreeNode { is_element: true, key: new_spec.key, - tag: new_tag, + tag: new_tag.into(), update: dummy_update, children: vec![], children_keys: HashMap::new(), diff --git a/examples/overlay/main.rs b/examples/overlay/main.rs index fd8e523..e1400c6 100644 --- a/examples/overlay/main.rs +++ b/examples/overlay/main.rs @@ -76,11 +76,10 @@ impl Component for OverlayExample { fn update(context: &mut Context) { println!("{:?}", context.window()); - - let target = context.target().map(|target| target.get_id()).cloned(); - if let Some(target) = target { - context.state_mut().hovered_element_id = target.clone(); - if let Some(_id) = target { + + if let Some(target) = context.target() { + context.state_mut().hovered_element_id = target.get_id().map(|s| s.to_string()); + if let Some(_id) = &context.state_mut().hovered_element_id { context.event_mut().prevent_propagate(); } } else { diff --git a/website/src/examples.rs b/website/src/examples.rs index 5090eed..d25191a 100644 --- a/website/src/examples.rs +++ b/website/src/examples.rs @@ -83,7 +83,7 @@ fn examples_sidebar(example_to_show: &String, window: &WindowContext) -> Compone .max_width("300px"); for (index, link) in links.drain(..).enumerate() { - if *link.get_id() == Some(example_to_show.to_string()) { + if link.get_id() == Some(example_to_show) { dropdown = dropdown.set_default(index); } dropdown = dropdown.push(link); diff --git a/website/src/navbar.rs b/website/src/navbar.rs index 0a57cb6..f86f862 100644 --- a/website/src/navbar.rs +++ b/website/src/navbar.rs @@ -75,7 +75,7 @@ impl Component for Navbar { return; } - let id = context.target().and_then(|e| e.get_id().as_ref()).cloned(); + let id = context.target().and_then(|e| e.get_id().map(|s| s.to_string())); if let Some(current_target) = id { if current_target.starts_with("route_") { let route = current_target.trim_start_matches("route_");