reformat code and write benchmark

This commit is contained in:
2026-05-12 16:57:05 +03:00
parent ee817a8e8c
commit 6d656c35e1
9 changed files with 367 additions and 62 deletions
Generated
+255
View File
@@ -32,6 +32,15 @@ dependencies = [
"zerocopy",
]
[[package]]
name = "aho-corasick"
version = "1.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301"
dependencies = [
"memchr",
]
[[package]]
name = "alsa"
version = "0.11.0"
@@ -99,6 +108,18 @@ dependencies = [
"libc",
]
[[package]]
name = "anes"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299"
[[package]]
name = "anstyle"
version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000"
[[package]]
name = "anyhow"
version = "1.0.101"
@@ -437,6 +458,12 @@ dependencies = [
"wayland-client",
]
[[package]]
name = "cast"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
[[package]]
name = "cc"
version = "1.2.55"
@@ -491,6 +518,58 @@ dependencies = [
"windows-link",
]
[[package]]
name = "ciborium"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e"
dependencies = [
"ciborium-io",
"ciborium-ll",
"serde",
]
[[package]]
name = "ciborium-io"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757"
[[package]]
name = "ciborium-ll"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9"
dependencies = [
"ciborium-io",
"half",
]
[[package]]
name = "clap"
version = "4.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ddb117e43bbf7dacf0a4190fef4d345b9bad68dfc649cb349e7d17d28428e51"
dependencies = [
"clap_builder",
]
[[package]]
name = "clap_builder"
version = "4.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f"
dependencies = [
"anstyle",
"clap_lex",
]
[[package]]
name = "clap_lex"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9"
[[package]]
name = "clipboard-win"
version = "5.4.1"
@@ -733,6 +812,61 @@ dependencies = [
"libc",
]
[[package]]
name = "criterion"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2b12d017a929603d80db1831cd3a24082f8137ce19c69e6447f54f5fc8d692f"
dependencies = [
"anes",
"cast",
"ciborium",
"clap",
"criterion-plot",
"is-terminal",
"itertools",
"num-traits",
"once_cell",
"oorandom",
"plotters",
"rayon",
"regex",
"serde",
"serde_derive",
"serde_json",
"tinytemplate",
"walkdir",
]
[[package]]
name = "criterion-plot"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1"
dependencies = [
"cast",
"itertools",
]
[[package]]
name = "crossbeam-deque"
version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51"
dependencies = [
"crossbeam-epoch",
"crossbeam-utils",
]
[[package]]
name = "crossbeam-epoch"
version = "0.9.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
dependencies = [
"crossbeam-utils",
]
[[package]]
name = "crossbeam-utils"
version = "0.8.21"
@@ -874,6 +1008,12 @@ version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8b14ccef22fc6f5a8f4d7d768562a182c04ce9a3b3157b91390b52ddfdf1a76"
[[package]]
name = "either"
version = "1.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
[[package]]
name = "encoding_rs"
version = "0.8.35"
@@ -1918,6 +2058,26 @@ dependencies = [
"serde",
]
[[package]]
name = "is-terminal"
version = "0.4.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3640c1c38b8e4e43584d8df18be5fc6b0aa314ce6ebf51b53313d4306cca8e46"
dependencies = [
"hermit-abi",
"libc",
"windows-sys 0.61.2",
]
[[package]]
name = "itertools"
version = "0.10.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
dependencies = [
"either",
]
[[package]]
name = "itoa"
version = "1.0.17"
@@ -1929,10 +2089,12 @@ name = "jap_learn"
version = "0.1.1"
dependencies = [
"chrono",
"criterion",
"dirs",
"hex",
"iced",
"rand",
"rayon",
"reqwest",
"rhai",
"rodio",
@@ -2800,6 +2962,12 @@ dependencies = [
"portable-atomic",
]
[[package]]
name = "oorandom"
version = "11.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e"
[[package]]
name = "openssl"
version = "0.10.77"
@@ -2978,6 +3146,34 @@ version = "0.3.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c"
[[package]]
name = "plotters"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5aeb6f403d7a4911efb1e33402027fc44f29b5bf6def3effcc22d7bb75f2b747"
dependencies = [
"num-traits",
"plotters-backend",
"plotters-svg",
"wasm-bindgen",
"web-sys",
]
[[package]]
name = "plotters-backend"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df42e13c12958a16b3f7f4386b9ab1f3e7933914ecea48da7139435263a4172a"
[[package]]
name = "plotters-svg"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51bae2ac328883f7acdfea3d66a7c35751187f870bc81f94563733a154d7a670"
dependencies = [
"plotters-backend",
]
[[package]]
name = "polling"
version = "3.11.0"
@@ -3125,6 +3321,26 @@ version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539"
[[package]]
name = "rayon"
version = "1.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fb39b166781f92d482534ef4b4b1b2568f42613b53e5b6c160e24cfbfa30926d"
dependencies = [
"either",
"rayon-core",
]
[[package]]
name = "rayon-core"
version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91"
dependencies = [
"crossbeam-deque",
"crossbeam-utils",
]
[[package]]
name = "read-fonts"
version = "0.35.0"
@@ -3174,6 +3390,35 @@ dependencies = [
"thiserror 2.0.18",
]
[[package]]
name = "regex"
version = "1.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276"
dependencies = [
"aho-corasick",
"memchr",
"regex-automata",
"regex-syntax",
]
[[package]]
name = "regex-automata"
version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.8.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a"
[[package]]
name = "renderdoc-sys"
version = "1.1.0"
@@ -4123,6 +4368,16 @@ dependencies = [
"zerovec",
]
[[package]]
name = "tinytemplate"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc"
dependencies = [
"serde",
"serde_json",
]
[[package]]
name = "tinyvec"
version = "1.10.0"
+7
View File
@@ -17,4 +17,11 @@ rodio = "0.22.2"
sha2 = "0.11.0"
hex = "0.4.3"
tokio = { version = "1.50.0", features = ["rt", "rt-multi-thread", "macros"] }
rayon = "1.12.0"
[dev-dependencies]
criterion = "0.5"
[[bench]]
name = "split_bench" # Имя файла в benches/ без расширения
harness = false # Отключаем стандартный тестовый раннер
+43
View File
@@ -0,0 +1,43 @@
use criterion::{black_box, criterion_group, criterion_main, Criterion};
fn bench_split(c: &mut Criterion) {
let input = "data_1";
c.bench_function("split_with_comma", |b| {
b.iter(|| {
// black_box запрещает компилятору оптимизировать результат
black_box(split_with_coma(black_box(input)))
})
});
}
fn bench_split_new(c: &mut Criterion) {
let input = "data_1";
c.bench_function("split_with_comma gpt", |b| {
b.iter(|| {
// black_box запрещает компилятору оптимизировать результат
black_box(split_with_coma(black_box(input)))
})
});
}
pub fn split_with_coma(ts: &str) -> Vec<String> {
ts.split(',')
.map(|ts| ts.to_lowercase().trim().to_string())
.filter(|t| !t.is_empty())
.collect::<Vec<String>>()
}
pub fn new_split_with_coma(ts: &str) -> Vec<String> {
ts.split(',')
.map(|s| s.trim()) // 0 аллокаций, просто срез
.filter(|s| !s.is_empty()) // отбрасываем пустые до аллокации
.map(|s| s.to_lowercase()) // 1 аллокация на валидный токен
.collect()
}
// Можно добавить несколько бенчмарков в группу
criterion_group!(benches, bench_split, bench_split_new);
criterion_main!(benches);
+51 -43
View File
@@ -15,7 +15,10 @@ use iced::widget::space::horizontal;
use iced::widget::*;
use iced::{Border, Color, Length, Shadow, Task};
use rand::random_range;
use std::collections::HashMap;
use rayon::iter::IndexedParallelIterator;
use rayon::iter::ParallelIterator;
use rayon::prelude::IntoParallelRefIterator;
use std::collections::{HashMap, HashSet};
use std::fs;
use std::ops::Add;
use std::path::PathBuf;
@@ -71,11 +74,14 @@ impl NavigatedPage<DictionaryMessage> for DictionaryState {
let mut words = vec![];
let dict = &self.state.lock().unwrap().dictionary;
for i in 0..self.include_map.len() {
if self.include_map[i] {
words.push(dict[i].clone());
}
}
words = self
.include_map
.par_iter()
.zip(0..self.include_map.len())
.filter(|(flag, _)| **flag)
.map(|(_, index)| dict[index].clone())
.collect();
return Some(Page::DictionaryQuiz(DictionaryQuizState::new(
words,
self.reverse,
@@ -136,15 +142,14 @@ impl DictionaryState {
let dict = &mut self.state.lock().unwrap().dictionary;
dict[i].key = v;
}
return self.launch_auto_save_offset(i)
return self.launch_auto_save_offset(i);
}
DictionaryMessage::SetValue(i, v) => {
{
let dict = &mut self.state.lock().unwrap().dictionary;
dict[i].value = v
}
return self.launch_auto_save_offset(i)
return self.launch_auto_save_offset(i);
}
DictionaryMessage::SetTags(i, v) => {
{
@@ -153,7 +158,7 @@ impl DictionaryState {
}
self.update_tags();
return self.launch_auto_save_offset(i)
return self.launch_auto_save_offset(i);
}
DictionaryMessage::WordAction(i) => {
@@ -168,7 +173,7 @@ impl DictionaryState {
DictionaryMessage::IncludeTag(t, v) => {
let index: u32;
{
let mut state = self.state.lock().unwrap();
let state = self.state.lock().unwrap();
index = state.word_groups[self.selected_group_index].id;
}
self.tag_map.insert(t, v);
@@ -184,9 +189,7 @@ impl DictionaryState {
self.search = s;
}
DictionaryMessage::SetTyping(b) => self.no_typing = b,
DictionaryMessage::SubmitWord(i) => {
self.save_word(i)
}
DictionaryMessage::SubmitWord(i) => self.save_word(i),
Back => {}
Test => {}
DictionaryMessage::CreateGroup => {
@@ -224,7 +227,6 @@ impl DictionaryState {
index = state.word_groups[i].id;
}
self.update_words_include(index)
}
DeleteGroup => {
if self.selected_group_index == 0 {
@@ -242,10 +244,12 @@ impl DictionaryState {
}
ChangeDirection => {
self.reverse_list = !self.reverse_list;
},
}
DictionaryMessage::TrySave(word_index) => {
let now = Utc::now();
if !self.auto_save_queue.contains_key(&word_index) { return Task::none(); }
if !self.auto_save_queue.contains_key(&word_index) {
return Task::none();
}
if self.auto_save_queue[&word_index] <= now {
self.auto_save_queue.remove(&word_index);
self.save_word(word_index);
@@ -266,10 +270,13 @@ impl DictionaryState {
}
fn launch_auto_save_offset(&mut self, index: usize) -> Task<RootMessage> {
let save_time = Utc::now().add(TimeDelta::milliseconds(2800));
let save_time = Utc::now().add(TimeDelta::milliseconds(900));
self.auto_save_queue.insert(index, save_time);
let message = RootMessage::Dictionary(DictionaryMessage::TrySave(index));
Task::perform(async { tokio::time::sleep(Duration::from_secs(3)).await }, |_| message)
Task::perform(
async { tokio::time::sleep(Duration::from_secs(1)).await },
|_| message,
)
}
pub fn view(&self) -> iced::Element<'_, DictionaryMessage> {
@@ -429,36 +436,40 @@ impl DictionaryState {
}
fn update_tags(&mut self) {
let mut tags_list: Vec<String> = vec![];
let mut tags_list: HashSet<String> = HashSet::new();
let dict = &self.state.lock().unwrap().dictionary;
for element in dict {
tags_list.append(&mut split_with_coma(element.tags.clone()));
}
dict.iter().for_each(|element| {
split_with_coma(element.tags.as_str())
.iter()
.for_each(|tag| {
tags_list.insert(tag.clone());
});
});
let current_tags = self
.tag_map
.keys()
.map(|k| k.clone().to_string())
.collect::<Vec<String>>();
for current in current_tags {
if !tags_list.contains(&current) {
self.tag_map.remove(&current.clone());
}
}
for found_tag in &tags_list {
if !self.tag_map.contains_key(&found_tag.clone()) {
self.tag_map.insert(found_tag.clone(), false);
}
}
current_tags
.iter()
.filter(|tag| !tags_list.contains(*tag))
.for_each(|tag| {
self.tag_map.remove(tag);
});
tags_list.iter().for_each(|tag| {
self.tag_map.insert(tag.clone(), false);
});
}
fn update_words_include(&mut self, group_id: u32) {
let include_tags = self
.tag_map
.iter()
.filter(|i| *(*i).1)
.filter(|(_, value)| **value)
.map(|(t, _)| t.clone())
.collect::<Vec<String>>();
@@ -469,14 +480,11 @@ impl DictionaryState {
let dict = &self.state.lock().unwrap().dictionary;
for i in 0..self.include_map.len() {
let tags = split_with_coma(dict[i].tags.clone());
if tags.iter().all(|t| include_tags.contains(t)) && dict[i].group_id == group_id {
self.include_map[i] = true;
} else {
self.include_map[i] = false;
}
}
self.include_map = dict.par_iter()
.map(|word| (split_with_coma(word.tags.as_str()), word.group_id))
.map(|(tags, word_group_id)| {
tags.iter().all(|t| include_tags.contains(t)) && word_group_id == group_id
}).collect();
}
fn groups_panel(&self) -> iced::Element<'_, DictionaryMessage> {
@@ -519,7 +527,7 @@ impl DictionaryState {
}
}
pub fn split_with_coma(ts: String) -> Vec<String> {
pub fn split_with_coma(ts: &str) -> Vec<String> {
ts.split(',')
.map(|ts| ts.to_lowercase().trim().to_string())
.filter(|t| !t.is_empty())
+1 -1
View File
@@ -144,7 +144,7 @@ impl DictionaryQuizState {
self.score.total += 1;
}
if self.answer == self.correct
|| split_with_coma(self.correct.clone()).contains(&self.answer)
|| split_with_coma(self.correct.as_str()).contains(&self.answer)
{
if self.is_help == false {
self.score.correct += 1;
+3 -2
View File
@@ -349,11 +349,12 @@ impl CardSet {
if !word_ids.contains(&stat.word_id) {
delete_stat(&stat, &state_locked.connection);
current_set.remove(index);
}
}else{
index += 1;
}
}
let weights = current_set.iter().map(|s| (100.0 / s.calculated_score()).powf(2.0)).collect::<Vec<f32>>();
let weights = current_set.iter().map(|s| (100.0 / s.calculated_score()).powf(2.0) * 2.0).collect::<Vec<f32>>();
let indexes = WeightedIndex::new(weights).unwrap();
Self {
+1 -11
View File
@@ -63,7 +63,7 @@ pub enum RootMessage {
Keyboard(Event),
}
enum Page {
pub enum Page {
Selector(SelectorState),
Quiz(QuizState),
Writing(WritingState),
@@ -208,13 +208,3 @@ trait NavigatedPage<T> {
pub trait KeyPressedPage {
fn press(&mut self, message: &Event) -> Task<RootMessage>;
}
/*pub fn danger_button(x: &Theme, status: Status) -> Style{
Style {
background: Some(Color(x.palette().danger)),
text_color: x.palette().text,
border: Border::default().rounded(2),
shadow: Default::default(),
snap: false,
}
}*/
+1 -1
View File
@@ -195,7 +195,7 @@ impl RepetitionsState {
.style(move |_x: &Theme, _status| Style {
background: None,
text_color: if self.correct_filters[i.clone()] {
_x.palette().text
_x.palette().primary
} else {
_x.palette().warning
},
+2 -1
View File
@@ -41,7 +41,8 @@ impl WordState {
WordMessage::Save => {
let mut state = self.state.lock().unwrap();
state.dictionary[self.index] = self.word.clone();
update_word(&mut self.word, &state.connection)
update_word(&mut self.word, &state.connection);
return Task::done(RootMessage::Word(WordMessage::Back))
}
WordMessage::Delete => {
let mut state = self.state.lock().unwrap();