First repo code
This commit is contained in:
1 parent
1f3ad22e05
commit
807f398d81
6 files changed
+399
-13
No files matched your search
Generated
+13
-12
@@ -1066,7 +1066,7 @@ dependencies = [
|
|||||||
"cosmic-text",
|
"cosmic-text",
|
||||||
"etagere",
|
"etagere",
|
||||||
"lru",
|
"lru",
|
||||||
"rustc-hash 2.1.1",
|
"rustc-hash 2.1.3",
|
||||||
"wgpu",
|
"wgpu",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -2074,7 +2074,7 @@ dependencies = [
|
|||||||
"lilt",
|
"lilt",
|
||||||
"log",
|
"log",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
"rustc-hash 2.1.1",
|
"rustc-hash 2.1.3",
|
||||||
"smol_str",
|
"smol_str",
|
||||||
"thiserror 2.0.18",
|
"thiserror 2.0.18",
|
||||||
"web-time",
|
"web-time",
|
||||||
@@ -2100,7 +2100,7 @@ dependencies = [
|
|||||||
"futures",
|
"futures",
|
||||||
"iced_core",
|
"iced_core",
|
||||||
"log",
|
"log",
|
||||||
"rustc-hash 2.1.1",
|
"rustc-hash 2.1.3",
|
||||||
"tokio",
|
"tokio",
|
||||||
"wasm-bindgen-futures",
|
"wasm-bindgen-futures",
|
||||||
"wasmtimer",
|
"wasmtimer",
|
||||||
@@ -2120,7 +2120,7 @@ dependencies = [
|
|||||||
"iced_futures",
|
"iced_futures",
|
||||||
"log",
|
"log",
|
||||||
"raw-window-handle",
|
"raw-window-handle",
|
||||||
"rustc-hash 2.1.1",
|
"rustc-hash 2.1.3",
|
||||||
"thiserror 2.0.18",
|
"thiserror 2.0.18",
|
||||||
"unicode-segmentation",
|
"unicode-segmentation",
|
||||||
]
|
]
|
||||||
@@ -2174,7 +2174,7 @@ dependencies = [
|
|||||||
"kurbo 0.10.4",
|
"kurbo 0.10.4",
|
||||||
"log",
|
"log",
|
||||||
"resvg",
|
"resvg",
|
||||||
"rustc-hash 2.1.1",
|
"rustc-hash 2.1.3",
|
||||||
"softbuffer",
|
"softbuffer",
|
||||||
"tiny-skia",
|
"tiny-skia",
|
||||||
]
|
]
|
||||||
@@ -2195,7 +2195,7 @@ dependencies = [
|
|||||||
"iced_graphics",
|
"iced_graphics",
|
||||||
"log",
|
"log",
|
||||||
"resvg",
|
"resvg",
|
||||||
"rustc-hash 2.1.1",
|
"rustc-hash 2.1.3",
|
||||||
"thiserror 2.0.18",
|
"thiserror 2.0.18",
|
||||||
"wgpu",
|
"wgpu",
|
||||||
]
|
]
|
||||||
@@ -2210,7 +2210,7 @@ dependencies = [
|
|||||||
"log",
|
"log",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
"ouroboros",
|
"ouroboros",
|
||||||
"rustc-hash 2.1.1",
|
"rustc-hash 2.1.3",
|
||||||
"thiserror 2.0.18",
|
"thiserror 2.0.18",
|
||||||
"unicode-segmentation",
|
"unicode-segmentation",
|
||||||
]
|
]
|
||||||
@@ -2225,7 +2225,7 @@ dependencies = [
|
|||||||
"iced_program",
|
"iced_program",
|
||||||
"log",
|
"log",
|
||||||
"mundy",
|
"mundy",
|
||||||
"rustc-hash 2.1.1",
|
"rustc-hash 2.1.3",
|
||||||
"thiserror 2.0.18",
|
"thiserror 2.0.18",
|
||||||
"tracing",
|
"tracing",
|
||||||
"wasm-bindgen-futures",
|
"wasm-bindgen-futures",
|
||||||
@@ -2439,6 +2439,7 @@ dependencies = [
|
|||||||
"rhai",
|
"rhai",
|
||||||
"rodio",
|
"rodio",
|
||||||
"rusqlite",
|
"rusqlite",
|
||||||
|
"rustc-hash 2.1.3",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"sha2",
|
"sha2",
|
||||||
"tokio",
|
"tokio",
|
||||||
@@ -3835,7 +3836,7 @@ dependencies = [
|
|||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"quinn-proto",
|
"quinn-proto",
|
||||||
"quinn-udp",
|
"quinn-udp",
|
||||||
"rustc-hash 2.1.1",
|
"rustc-hash 2.1.3",
|
||||||
"rustls",
|
"rustls",
|
||||||
"socket2",
|
"socket2",
|
||||||
"thiserror 2.0.18",
|
"thiserror 2.0.18",
|
||||||
@@ -3857,7 +3858,7 @@ dependencies = [
|
|||||||
"rand",
|
"rand",
|
||||||
"rand_pcg",
|
"rand_pcg",
|
||||||
"ring",
|
"ring",
|
||||||
"rustc-hash 2.1.1",
|
"rustc-hash 2.1.3",
|
||||||
"rustls",
|
"rustls",
|
||||||
"rustls-pki-types",
|
"rustls-pki-types",
|
||||||
"slab",
|
"slab",
|
||||||
@@ -4256,9 +4257,9 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustc-hash"
|
name = "rustc-hash"
|
||||||
version = "2.1.1"
|
version = "2.1.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d"
|
checksum = "6b1e7f9a428571be2dc5bc0505c13fb6bf936822b894ec87abf8a08a4e51742d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustc_version"
|
name = "rustc_version"
|
||||||
|
|||||||
+4
-1
@@ -37,9 +37,12 @@ panic = "abort"
|
|||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
criterion = { version = "0.8.2", features = ["html_reports"] }
|
criterion = { version = "0.8.2", features = ["html_reports"] }
|
||||||
|
rustc-hash = "2.1.3"
|
||||||
|
|
||||||
[[bench]]
|
[[bench]]
|
||||||
name = "map_bench"
|
name = "map_bench"
|
||||||
harness = false
|
harness = false
|
||||||
|
|
||||||
|
[[bench]]
|
||||||
|
name = "repo_cache_bench"
|
||||||
|
harness = false
|
||||||
@@ -0,0 +1,285 @@
|
|||||||
|
use criterion::{criterion_group, criterion_main, Criterion, BenchmarkId};
|
||||||
|
use std::collections::{BTreeMap, HashMap};
|
||||||
|
use std::hint::black_box;
|
||||||
|
use hashbrown::HashMap as HashbrownMap;
|
||||||
|
use rustc_hash::FxHashMap;
|
||||||
|
|
||||||
|
// Тестовая структура (аналог вашей сущности)
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
struct Entity {
|
||||||
|
id: i64,
|
||||||
|
data: [u8; 64], // 64 байта данных для реалистичности
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Entity {
|
||||||
|
fn new(id: i64) -> Self {
|
||||||
|
Self {
|
||||||
|
id,
|
||||||
|
data: [id as u8; 64],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ========== ТЕСТОВЫЕ ФУНКЦИИ ==========
|
||||||
|
|
||||||
|
fn bench_vec_insert_sorted(vec: &mut Vec<Entity>, entities: &[Entity]) {
|
||||||
|
vec.clear();
|
||||||
|
for entity in entities {
|
||||||
|
vec.push(entity.clone());
|
||||||
|
}
|
||||||
|
// Vec уже отсортирован, так как ID монотонно возрастают
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bench_vec_search_separated<'a>(ids: &[i64], vec: &'a [Entity], id: i64) -> Option<&'a Entity> {
|
||||||
|
match ids.binary_search(&id) {
|
||||||
|
Ok(index) => Some(&vec[index]),
|
||||||
|
Err(_) => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bench_vec_search(vec: &Vec<Entity>, id: i64) -> Option<&Entity> {
|
||||||
|
match vec.binary_search_by(|probe| probe.id.cmp(&id)) {
|
||||||
|
Ok(index) => Some(&vec[index]),
|
||||||
|
Err(_) => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bench_btreemap_insert(map: &mut BTreeMap<i64, Entity>, entities: &[Entity]) {
|
||||||
|
map.clear();
|
||||||
|
for entity in entities {
|
||||||
|
map.insert(entity.id, entity.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bench_btreemap_search(map: &BTreeMap<i64, Entity>, id: i64) -> Option<&Entity> {
|
||||||
|
map.get(&id)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bench_hashmap_insert(map: &mut HashMap<i64, Entity>, entities: &[Entity]) {
|
||||||
|
map.clear();
|
||||||
|
for entity in entities {
|
||||||
|
map.insert(entity.id, entity.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bench_hashmap_search(map: &HashMap<i64, Entity>, id: i64) -> Option<&Entity> {
|
||||||
|
map.get(&id)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bench_hashbrown_insert(map: &mut HashbrownMap<i64, Entity>, entities: &[Entity]) {
|
||||||
|
map.clear();
|
||||||
|
for entity in entities {
|
||||||
|
map.insert(entity.id, entity.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bench_hashbrown_search(map: &HashbrownMap<i64, Entity>, id: i64) -> Option<&Entity> {
|
||||||
|
map.get(&id)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bench_fxhashmap_insert(map: &mut FxHashMap<i64, Entity>, entities: &[Entity]) {
|
||||||
|
map.clear();
|
||||||
|
for entity in entities {
|
||||||
|
map.insert(entity.id, entity.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bench_fxhashmap_search(map: &FxHashMap<i64, Entity>, id: i64) -> Option<&Entity> {
|
||||||
|
map.get(&id)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ========== ГЕНЕРАЦИЯ ДАННЫХ ==========
|
||||||
|
|
||||||
|
fn generate_entities(count: usize) -> Vec<Entity> {
|
||||||
|
(0..count).map(|i| Entity::new(i as i64)).collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_search_ids(count: usize, max_id: i64) -> Vec<i64> {
|
||||||
|
// 70% попаданий, 30% промахов (реалистичный сценарий)
|
||||||
|
let mut ids = Vec::with_capacity(count);
|
||||||
|
for i in 0..count {
|
||||||
|
if i % 10 < 7 {
|
||||||
|
// Попадание
|
||||||
|
ids.push((i as i64 * 13) % max_id);
|
||||||
|
} else {
|
||||||
|
// Промах (несуществующий ID)
|
||||||
|
ids.push(max_id + i as i64);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ids
|
||||||
|
}
|
||||||
|
|
||||||
|
// ========== БЕНЧМАРКИ ==========
|
||||||
|
|
||||||
|
fn bench_insert(c: &mut Criterion) {
|
||||||
|
let mut group = c.benchmark_group("insert");
|
||||||
|
|
||||||
|
for size in [10_000, 100_000, 500_000] {
|
||||||
|
let entities = generate_entities(size);
|
||||||
|
|
||||||
|
group.bench_with_input(BenchmarkId::new("Vec (sorted)", size), &entities, |b, entities| {
|
||||||
|
let mut vec = Vec::with_capacity(size);
|
||||||
|
b.iter(|| {
|
||||||
|
bench_vec_insert_sorted(&mut vec, black_box(entities));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
group.bench_with_input(BenchmarkId::new("BTreeMap", size), &entities, |b, entities| {
|
||||||
|
let mut map = BTreeMap::new();
|
||||||
|
b.iter(|| {
|
||||||
|
bench_btreemap_insert(&mut map, black_box(entities));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
group.bench_with_input(BenchmarkId::new("HashMap (std)", size), &entities, |b, entities| {
|
||||||
|
let mut map = HashMap::new();
|
||||||
|
b.iter(|| {
|
||||||
|
bench_hashmap_insert(&mut map, black_box(entities));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
group.bench_with_input(BenchmarkId::new("HashMap (hashbrown)", size), &entities, |b, entities| {
|
||||||
|
let mut map = HashbrownMap::new();
|
||||||
|
b.iter(|| {
|
||||||
|
bench_hashbrown_insert(&mut map, black_box(entities));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
group.bench_with_input(BenchmarkId::new("FxHashMap", size), &entities, |b, entities| {
|
||||||
|
let mut map = FxHashMap::default();
|
||||||
|
b.iter(|| {
|
||||||
|
bench_fxhashmap_insert(&mut map, black_box(entities));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
group.finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bench_search(c: &mut Criterion) {
|
||||||
|
let mut group = c.benchmark_group("search");
|
||||||
|
|
||||||
|
for size in [10_000, 100_000, 500_000] {
|
||||||
|
let entities = generate_entities(size);
|
||||||
|
let entity_ids = entities.iter().map(|entity| entity.id).collect::<Vec<_>>();
|
||||||
|
let search_ids = generate_search_ids(1000, size as i64);
|
||||||
|
|
||||||
|
// Подготовка коллекций
|
||||||
|
let mut vec = Vec::with_capacity(size);
|
||||||
|
bench_vec_insert_sorted(&mut vec, &entities);
|
||||||
|
|
||||||
|
let mut btreemap = BTreeMap::new();
|
||||||
|
bench_btreemap_insert(&mut btreemap, &entities);
|
||||||
|
|
||||||
|
let mut hashmap = HashMap::new();
|
||||||
|
bench_hashmap_insert(&mut hashmap, &entities);
|
||||||
|
|
||||||
|
let mut hashbrown = HashbrownMap::new();
|
||||||
|
bench_hashbrown_insert(&mut hashbrown, &entities);
|
||||||
|
|
||||||
|
let mut fxhashmap = FxHashMap::default();
|
||||||
|
bench_fxhashmap_insert(&mut fxhashmap, &entities);
|
||||||
|
|
||||||
|
group.bench_with_input(BenchmarkId::new("Vec (binary search)", size), &search_ids, |b, ids| {
|
||||||
|
b.iter(|| {
|
||||||
|
for &id in ids {
|
||||||
|
black_box(bench_vec_search_separated(&entity_ids, &vec, black_box(id)));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
group.bench_with_input(BenchmarkId::new("Vec (binary search) separated", size), &search_ids, |b, ids| {
|
||||||
|
b.iter(|| {
|
||||||
|
for &id in ids {
|
||||||
|
black_box(bench_vec_search(&vec, black_box(id)));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
group.bench_with_input(BenchmarkId::new("BTreeMap", size), &search_ids, |b, ids| {
|
||||||
|
b.iter(|| {
|
||||||
|
for &id in ids {
|
||||||
|
black_box(bench_btreemap_search(&btreemap, black_box(id)));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
group.bench_with_input(BenchmarkId::new("HashMap (std)", size), &search_ids, |b, ids| {
|
||||||
|
b.iter(|| {
|
||||||
|
for &id in ids {
|
||||||
|
black_box(bench_hashmap_search(&hashmap, black_box(id)));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
group.bench_with_input(BenchmarkId::new("HashMap (hashbrown)", size), &search_ids, |b, ids| {
|
||||||
|
b.iter(|| {
|
||||||
|
for &id in ids {
|
||||||
|
black_box(bench_hashbrown_search(&hashbrown, black_box(id)));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
group.bench_with_input(BenchmarkId::new("FxHashMap", size), &search_ids, |b, ids| {
|
||||||
|
b.iter(|| {
|
||||||
|
for &id in ids {
|
||||||
|
black_box(bench_fxhashmap_search(&fxhashmap, black_box(id)));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
group.finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bench_memory_efficiency(c: &mut Criterion) {
|
||||||
|
let mut group = c.benchmark_group("memory_efficiency");
|
||||||
|
|
||||||
|
let size = 100_000;
|
||||||
|
let entities = generate_entities(size);
|
||||||
|
|
||||||
|
group.bench_function("Vec memory", |b| {
|
||||||
|
b.iter(|| {
|
||||||
|
let mut vec = Vec::with_capacity(size);
|
||||||
|
bench_vec_insert_sorted(&mut vec, black_box(&entities));
|
||||||
|
black_box(vec);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
group.bench_function("BTreeMap memory", |b| {
|
||||||
|
b.iter(|| {
|
||||||
|
let mut map = BTreeMap::new();
|
||||||
|
bench_btreemap_insert(&mut map, black_box(&entities));
|
||||||
|
black_box(map);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
group.bench_function("HashMap (std) memory", |b| {
|
||||||
|
b.iter(|| {
|
||||||
|
let mut map = HashMap::new();
|
||||||
|
bench_hashmap_insert(&mut map, black_box(&entities));
|
||||||
|
black_box(map);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
group.bench_function("HashMap (hashbrown) memory", |b| {
|
||||||
|
b.iter(|| {
|
||||||
|
let mut map = HashbrownMap::new();
|
||||||
|
bench_hashbrown_insert(&mut map, black_box(&entities));
|
||||||
|
black_box(map);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
group.bench_function("FxHashMap memory", |b| {
|
||||||
|
b.iter(|| {
|
||||||
|
let mut map = FxHashMap::default();
|
||||||
|
bench_fxhashmap_insert(&mut map, black_box(&entities));
|
||||||
|
black_box(map);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
group.finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
criterion_group!(benches, bench_insert, bench_search, bench_memory_efficiency);
|
||||||
|
criterion_main!(benches);
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
pub mod entities;
|
pub mod entities;
|
||||||
|
pub mod repositories;
|
||||||
|
|
||||||
use rusqlite::ToSql;
|
use rusqlite::ToSql;
|
||||||
use rusqlite::types::{FromSql, FromSqlError, FromSqlResult, ToSqlOutput, ValueRef};
|
use rusqlite::types::{FromSql, FromSqlError, FromSqlResult, ToSqlOutput, ValueRef};
|
||||||
|
|||||||
@@ -1,11 +1,14 @@
|
|||||||
use crate::app::AppState;
|
use crate::app::AppState;
|
||||||
use crate::core::srs::{FADE_PER_DAY, MAX_SCORE, OrderMode, WordOpenMode};
|
use crate::core::srs::{FADE_PER_DAY, MAX_SCORE, OrderMode, WordOpenMode};
|
||||||
use crate::data::{INVALID_ID, Id};
|
use crate::data::{INVALID_ID, Id};
|
||||||
|
use crate::notification::MaybeError;
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
use log::info;
|
use log::info;
|
||||||
use rayon::prelude::*;
|
use rayon::prelude::*;
|
||||||
use rhai::{Engine, Scope};
|
use rhai::{Engine, Scope};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
use std::ops::{Deref, DerefMut};
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
@@ -164,3 +167,50 @@ impl CardStatistics {
|
|||||||
(self.score as f32 * multiplier).max(1.0)
|
(self.score as f32 * multiplier).max(1.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct Entity<E, R: Repository<E>> {
|
||||||
|
pub(crate) repo: R,
|
||||||
|
pub(crate) _phantom: PhantomData<E>,
|
||||||
|
pub(crate) inner: EntityInner,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub(crate) struct EntityInner {
|
||||||
|
pub(crate) id: Id,
|
||||||
|
pub(crate) real: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E, R: Repository<E>> Entity<E, R> {
|
||||||
|
pub fn load(&self) -> EntityAccess<E, R> {
|
||||||
|
let clone = *self.clone();
|
||||||
|
let repo = &self.repo;
|
||||||
|
let value = repo.get(self.inner.id).unwrap();
|
||||||
|
EntityAccess { value, entity: clone, }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct EntityAccess<E, R: Repository<E>> {
|
||||||
|
entity: Entity<E, R>,
|
||||||
|
value: E,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E, R: Repository<E>> Deref for EntityAccess<E, R> {
|
||||||
|
type Target = E;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E, R: Repository<E>> DerefMut for EntityAccess<E, R> {
|
||||||
|
fn deref_mut(&mut self) -> &mut E {
|
||||||
|
&mut self.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait Repository<T> {
|
||||||
|
fn get(&self, id: Id) -> Option<T>;
|
||||||
|
fn create(&mut self, new: T) -> Entity<T, impl Repository<T>>;
|
||||||
|
fn save(&mut self, entity: EntityInner) -> MaybeError;
|
||||||
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
use crate::data::Id;
|
||||||
|
use crate::data::entities::{Entity, EntityInner, Repository, WordData};
|
||||||
|
use crate::notification::MaybeError;
|
||||||
|
use parking_lot::{Mutex, RwLock};
|
||||||
|
use rusqlite::Connection;
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct WordRepository {
|
||||||
|
inner: Arc<RwLock<WordRepositoryInner>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct WordRepositoryInner {
|
||||||
|
cache: Vec<WordData>,
|
||||||
|
temporal: Vec<Entity<WordData, WordRepository>>,
|
||||||
|
next_temporal: u32,
|
||||||
|
connection: Arc<Mutex<Connection>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Repository<WordData> for WordRepository {
|
||||||
|
fn get(&self, id: Id) -> Option<WordData> {
|
||||||
|
let inner = self.inner.read();
|
||||||
|
Some(inner.cache[inner.cache.binary_search_by(|w| w.id.cmp(&id)).ok()?].clone())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create(&mut self, new: WordData) -> Entity<WordData, WordRepository> {
|
||||||
|
let mut inner = self.inner.write();
|
||||||
|
let next_temporal = inner.next_temporal;
|
||||||
|
inner.next_temporal += 1;
|
||||||
|
drop(inner);
|
||||||
|
let entity = Entity {
|
||||||
|
inner: EntityInner {
|
||||||
|
id: next_temporal.into(),
|
||||||
|
real: false,
|
||||||
|
},
|
||||||
|
repo: self.clone(),
|
||||||
|
_phantom: PhantomData,
|
||||||
|
};
|
||||||
|
entity
|
||||||
|
}
|
||||||
|
|
||||||
|
fn save(&mut self, entity: EntityInner) -> MaybeError {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in new issue
Block a user