From 33002f89a68352b8bb18efba290c891170963e76 Mon Sep 17 00:00:00 2001 From: Priec Date: Sun, 18 Jan 2026 12:10:43 +0100 Subject: [PATCH] default is no_std heapless --- Cargo.lock | 50 ++++++++++----- Cargo.toml | 11 ++-- src/input/bindings.rs | 140 +++++++++++++++++------------------------- 3 files changed, 95 insertions(+), 106 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 40be7fa..4f7e906 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3,22 +3,19 @@ version = 4 [[package]] -name = "allocator-api2" -version = "0.2.21" +name = "byteorder" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] -name = "equivalent" -version = "1.0.2" +name = "hash32" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" - -[[package]] -name = "foldhash" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" +checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606" +dependencies = [ + "byteorder", +] [[package]] name = "hashbrown" @@ -26,14 +23,35 @@ version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" dependencies = [ - "allocator-api2", - "equivalent", - "foldhash", + "rustc-std-workspace-alloc", ] [[package]] -name = "tui_orchestrator" +name = "heapless" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2af2455f757db2b292a9b1768c4b70186d443bcb3b316252d6b540aec1cd89ed" +dependencies = [ + "hash32", + "stable_deref_trait", +] + +[[package]] +name = "pages-tui" version = "0.1.0" dependencies = [ "hashbrown", + "heapless", ] + +[[package]] +name = "rustc-std-workspace-alloc" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9d441c3b2ebf55cebf796bfdc265d67fa09db17b7bb6bd4be75c509e1e8fec3" + +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" diff --git a/Cargo.toml b/Cargo.toml index 2fc400e..aca9192 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,16 +1,17 @@ [package] -name = "tui_orchestrator" +name = "pages-tui" version = "0.1.0" edition = "2021" license = "MIT OR Apache-2.0" [features] -default = ["std"] -std = [] -alloc = ["hashbrown"] +default = [] +std = ["alloc"] +alloc = ["dep:hashbrown"] sequences = ["alloc"] [dependencies] -hashbrown = { version = "0.15", optional = true } +hashbrown = { version = "0.15", optional = true, default-features = false, features = ["alloc"] } +heapless = { version = "0.9.2", default-features = false } [dev-dependencies] diff --git a/src/input/bindings.rs b/src/input/bindings.rs index 123e89f..f4ae30a 100644 --- a/src/input/bindings.rs +++ b/src/input/bindings.rs @@ -1,25 +1,28 @@ use super::action::{Action, ComponentAction}; use super::key::Key; +#[cfg(feature = "alloc")] +use hashbrown::HashSet; + /// Maps keys to actions. /// /// When `alloc` feature is enabled, uses HashMap for O(1) lookup. -/// Without `alloc`, falls back to Vec with O(n) lookup. +/// Without `alloc`, uses heapless::LinearMap with fixed capacity N. #[derive(Debug, Clone)] -pub struct Bindings { +pub struct Bindings { #[cfg(feature = "alloc")] bindings: hashbrown::HashMap, #[cfg(not(feature = "alloc"))] - bindings: alloc::vec::Vec<(Key, A)>, + bindings: heapless::LinearMap, } -impl Bindings { +impl Bindings { pub fn new() -> Self { Self { #[cfg(feature = "alloc")] bindings: hashbrown::HashMap::new(), #[cfg(not(feature = "alloc"))] - bindings: alloc::vec::Vec::new(), + bindings: heapless::LinearMap::new(), } } @@ -30,19 +33,14 @@ impl Bindings { } #[cfg(not(feature = "alloc"))] { - self.bindings.push((key, action)); + // V heapless verzii ignorujeme chybu pri plnej kapacite, + // alebo by ste mohli vrátiť Result. + let _ = self.bindings.insert(key, action); } } pub fn get(&self, key: &Key) -> Option<&A> { - #[cfg(feature = "alloc")] - { - self.bindings.get(key) - } - #[cfg(not(feature = "alloc"))] - { - self.bindings.iter().find(|(k, _)| k == key).map(|(_, a)| a) - } + self.bindings.get(key) } pub fn remove(&mut self, key: &Key) { @@ -52,113 +50,85 @@ impl Bindings { } #[cfg(not(feature = "alloc"))] { - self.bindings.retain(|(k, _)| k != key); + self.bindings.remove(key); } } pub fn is_empty(&self) -> bool { - #[cfg(feature = "alloc")] - { - self.bindings.is_empty() - } - #[cfg(not(feature = "alloc"))] - { - self.bindings.is_empty() - } + self.bindings.is_empty() } pub fn len(&self) -> usize { - #[cfg(feature = "alloc")] - { - self.bindings.len() - } - #[cfg(not(feature = "alloc"))] - { - self.bindings.len() - } - } - - pub fn keys(&self) -> alloc::vec::Vec<&Key> { - #[cfg(feature = "alloc")] - { - self.bindings.keys().collect() - } - #[cfg(not(feature = "alloc"))] - { - self.bindings.iter().map(|(k, _)| k).collect() - } - } - - #[cfg(not(feature = "alloc"))] - pub fn iter(&self) -> impl Iterator { - self.bindings.iter() + self.bindings.len() } #[cfg(feature = "alloc")] + pub fn keys(&self) -> alloc::vec::Vec<&Key> { + self.bindings.keys().collect() + } + + #[cfg(not(feature = "alloc"))] + pub fn keys(&self) -> heapless::Vec<&Key, N> { + let mut v = heapless::Vec::new(); + for k in self.bindings.keys() { + let _ = v.push(k); + } + v + } + pub fn iter(&self) -> impl Iterator { self.bindings.iter() } } -impl Default for Bindings { +impl Default for Bindings { fn default() -> Self { Self::new() } } #[cfg(feature = "sequences")] -impl Bindings { +impl Bindings { + #[cfg(feature = "alloc")] pub fn bind_sequence(&mut self, keys: alloc::vec::Vec, action: A) { - #[cfg(feature = "alloc")] - { - for key in keys { - self.bindings.insert(key, action.clone()); - } - } - #[cfg(not(feature = "alloc"))] - { - for key in keys { - self.bindings.push((key, action.clone())); - } + for key in keys { + self.bindings.insert(key, action.clone()); } } + #[cfg(not(feature = "alloc"))] + pub fn bind_sequence(&mut self, keys: heapless::Vec, action: A) { + for key in keys { + let _ = self.bindings.insert(key, action.clone()); + } + } + + #[cfg(feature = "alloc")] pub fn get_sequences(&self) -> alloc::vec::Vec<&A> { let mut actions = alloc::vec::Vec::new(); let mut seen = HashSet::new(); - #[cfg(feature = "alloc")] - { - for (_, action) in &self.bindings { - if seen.insert(action) { - actions.push(action); - } + for (_, action) in &self.bindings { + if seen.insert(action) { + actions.push(action); } } - #[cfg(not(feature = "alloc"))] - { - for (_, action) in &self.bindings { - if seen.insert(action) { - actions.push(action); - } + actions + } + + #[cfg(not(feature = "alloc"))] + pub fn get_sequences(&self) -> heapless::Vec<&A, N> { + let mut actions = heapless::Vec::new(); + // V no_std/no_alloc bez HashSetu robíme O(n^2) kontrolu unikátnosti + for (_, action) in &self.bindings { + if !actions.iter().any(|&a| a == action) { + let _ = actions.push(action); } } actions } } -/// Returns default key bindings for common TUI patterns. -/// -/// Includes: -/// - Tab/Shift+Tab for next/prev navigation -/// - Enter for select -/// - Esc for cancel -/// - Arrow keys for directional movement -/// - Home/End/PageUp/PageDown for scrolling -/// - Backspace/Delete for editing -/// - Ctrl+C as custom quit action -/// -/// Use as-is or extend with your own bindings. -pub fn default_bindings() -> Bindings { +pub fn default_bindings() -> Bindings { let mut bindings = Bindings::new(); bindings.bind(Key::tab(), ComponentAction::Next); bindings.bind(Key::shift_tab(), ComponentAction::Prev);