1use std::collections::VecDeque;
60use std::path::{Path, PathBuf};
61use std::sync::{Arc, RwLock};
62use std::time::{Duration, SystemTime};
63
64use crate::error::{DictError, Result};
65use crate::user_dict::{UserDictionary, UserEntry};
66#[cfg(test)]
67use crate::DictEntry;
68use crate::{Entry, SystemDictionary};
69
70pub type Version = u64;
74
75const DEFAULT_MAX_VERSION_HISTORY: usize = 10;
77
78const DEFAULT_MAX_DELTA_QUEUE: usize = 100;
80
81#[derive(Clone)]
85struct VersionedDictionary {
86 version: Version,
88 system_dict: Arc<SystemDictionary>,
90 user_dict: Arc<UserDictionary>,
92 timestamp: SystemTime,
94}
95
96impl VersionedDictionary {
97 fn new_version(&self, user_dict: UserDictionary) -> Self {
99 Self {
100 version: self.version + 1,
101 system_dict: Arc::clone(&self.system_dict),
102 user_dict: Arc::new(user_dict),
103 timestamp: SystemTime::now(),
104 }
105 }
106
107 fn with_system_dict(&self, system_dict: SystemDictionary) -> Self {
109 Self {
110 version: self.version + 1,
111 system_dict: Arc::new(system_dict),
112 user_dict: Arc::clone(&self.user_dict),
113 timestamp: SystemTime::now(),
114 }
115 }
116}
117
118pub struct HotReloadDictionary {
122 current: Arc<RwLock<VersionedDictionary>>,
124 history: Arc<RwLock<VecDeque<VersionedDictionary>>>,
126 max_history: usize,
128 delta_queue: Arc<RwLock<VecDeque<DeltaUpdate>>>,
130 max_delta_queue: usize,
132 dicdir: PathBuf,
134}
135
136impl HotReloadDictionary {
137 pub fn new<P: AsRef<Path>>(dicdir: P) -> Result<Self> {
148 let dicdir = dicdir.as_ref().to_path_buf();
149 let system_dict = SystemDictionary::load(&dicdir)?;
150
151 let versioned = VersionedDictionary {
152 version: 1,
153 system_dict: Arc::new(system_dict),
154 user_dict: Arc::new(UserDictionary::new()),
155 timestamp: SystemTime::now(),
156 };
157
158 Ok(Self {
159 current: Arc::new(RwLock::new(versioned)),
160 history: Arc::new(RwLock::new(VecDeque::new())),
161 max_history: DEFAULT_MAX_VERSION_HISTORY,
162 delta_queue: Arc::new(RwLock::new(VecDeque::new())),
163 max_delta_queue: DEFAULT_MAX_DELTA_QUEUE,
164 dicdir,
165 })
166 }
167
168 pub fn new_default() -> Result<Self> {
174 let system_dict = SystemDictionary::load_default()?;
175 let dicdir = system_dict.dicdir().to_path_buf();
176
177 let versioned = VersionedDictionary {
178 version: 1,
179 system_dict: Arc::new(system_dict),
180 user_dict: Arc::new(UserDictionary::new()),
181 timestamp: SystemTime::now(),
182 };
183
184 Ok(Self {
185 current: Arc::new(RwLock::new(versioned)),
186 history: Arc::new(RwLock::new(VecDeque::new())),
187 max_history: DEFAULT_MAX_VERSION_HISTORY,
188 delta_queue: Arc::new(RwLock::new(VecDeque::new())),
189 max_delta_queue: DEFAULT_MAX_DELTA_QUEUE,
190 dicdir,
191 })
192 }
193
194 #[must_use]
196 pub const fn with_max_history(mut self, max_history: usize) -> Self {
197 self.max_history = max_history;
198 self
199 }
200
201 #[must_use]
203 pub const fn with_max_delta_queue(mut self, max_delta_queue: usize) -> Self {
204 self.max_delta_queue = max_delta_queue;
205 self
206 }
207
208 #[must_use]
210 pub fn current_version(&self) -> Version {
211 self.current.read().map(|dict| dict.version).unwrap_or(0)
212 }
213
214 #[must_use]
216 pub fn dicdir(&self) -> &Path {
217 &self.dicdir
218 }
219
220 pub fn lookup(&self, surface: &str) -> Result<Vec<Entry>> {
230 let dict = self.current.read().map_err(|_| {
231 DictError::Format("Failed to acquire read lock on dictionary".to_string())
232 })?;
233
234 let mut results = Vec::new();
235
236 if let Some(index) = dict.system_dict.trie().exact_match(surface) {
238 if let Ok(entry) = dict.system_dict.get_entry(index) {
239 results.push(entry.to_entry());
240 }
241 }
242
243 let user_entries = dict.user_dict.lookup(surface);
245 results.extend(user_entries.iter().map(|e| e.to_entry()));
246 drop(dict);
247
248 Ok(results)
249 }
250
251 pub fn add_entry(
264 &self,
265 surface: impl Into<String>,
266 pos: impl Into<String>,
267 cost: i16,
268 reading: Option<String>,
269 ) -> Result<Version> {
270 let mut dict = self.current.write().map_err(|_| {
271 DictError::Format("Failed to acquire write lock on dictionary".to_string())
272 })?;
273
274 let mut new_user_dict = (*dict.user_dict).clone();
276 new_user_dict.add_entry(surface, pos, Some(cost), reading);
277
278 self.save_to_history(&dict)?;
280
281 *dict = dict.new_version(new_user_dict);
283
284 Ok(dict.version)
285 }
286
287 pub fn remove_entry(&self, surface: &str) -> Result<(Version, usize)> {
301 let mut dict = self.current.write().map_err(|_| {
302 DictError::Format("Failed to acquire write lock on dictionary".to_string())
303 })?;
304
305 let new_user_dict = (*dict.user_dict).clone();
307
308 let removed_count = new_user_dict
310 .entries()
311 .iter()
312 .filter(|e| e.surface == surface)
313 .count();
314
315 if removed_count == 0 {
316 return Ok((dict.version, 0));
317 }
318
319 let filtered_entries: Vec<_> = new_user_dict
321 .entries()
322 .iter()
323 .filter(|e| e.surface != surface)
324 .cloned()
325 .collect();
326
327 let mut rebuilt_dict = UserDictionary::new();
328 for entry in filtered_entries {
329 rebuilt_dict.add_entry_with_ids(
330 entry.surface,
331 entry.pos,
332 entry.cost,
333 entry.left_id,
334 entry.right_id,
335 entry.reading,
336 );
337 }
338
339 self.save_to_history(&dict)?;
341
342 *dict = dict.new_version(rebuilt_dict);
344
345 Ok((dict.version, removed_count))
346 }
347
348 pub fn update_entry<F>(&self, surface: &str, update_fn: F) -> Result<Version>
359 where
360 F: Fn(&mut UserEntry),
361 {
362 let mut dict = self.current.write().map_err(|_| {
363 DictError::Format("Failed to acquire write lock on dictionary".to_string())
364 })?;
365
366 let new_user_dict = (*dict.user_dict).clone();
368
369 let updated_entries: Vec<_> = new_user_dict
371 .entries()
372 .iter()
373 .map(|e| {
374 let mut updated = e.clone();
375 if updated.surface == surface {
376 update_fn(&mut updated);
377 }
378 updated
379 })
380 .collect();
381
382 let mut rebuilt_dict = UserDictionary::new();
384 for entry in updated_entries {
385 rebuilt_dict.add_entry_with_ids(
386 entry.surface,
387 entry.pos,
388 entry.cost,
389 entry.left_id,
390 entry.right_id,
391 entry.reading,
392 );
393 }
394
395 self.save_to_history(&dict)?;
397
398 *dict = dict.new_version(rebuilt_dict);
400
401 Ok(dict.version)
402 }
403
404 pub fn apply_delta(&self, delta: DeltaUpdate) -> Result<Version> {
416 let mut dict = self.current.write().map_err(|_| {
417 DictError::Format("Failed to acquire write lock on dictionary".to_string())
418 })?;
419
420 let mut new_user_dict = (*dict.user_dict).clone();
422
423 for surface in &delta.removals {
425 let filtered_entries: Vec<_> = new_user_dict
426 .entries()
427 .iter()
428 .filter(|e| e.surface != *surface)
429 .cloned()
430 .collect();
431
432 let mut rebuilt_dict = UserDictionary::new();
433 for entry in filtered_entries {
434 rebuilt_dict.add_entry_with_ids(
435 entry.surface,
436 entry.pos,
437 entry.cost,
438 entry.left_id,
439 entry.right_id,
440 entry.reading,
441 );
442 }
443 new_user_dict = rebuilt_dict;
444 }
445
446 for addition in &delta.additions {
448 new_user_dict.add_entry(
449 addition.surface.clone(),
450 addition.pos.clone(),
451 Some(addition.cost),
452 addition.reading.clone(),
453 );
454 }
455
456 for modification in &delta.modifications {
458 let updated_entries: Vec<_> = new_user_dict
459 .entries()
460 .iter()
461 .map(|e| {
462 if e.surface == modification.surface {
463 modification.to_user_entry()
464 } else {
465 e.clone()
466 }
467 })
468 .collect();
469
470 let mut rebuilt_dict = UserDictionary::new();
471 for entry in updated_entries {
472 rebuilt_dict.add_entry_with_ids(
473 entry.surface,
474 entry.pos,
475 entry.cost,
476 entry.left_id,
477 entry.right_id,
478 entry.reading,
479 );
480 }
481 new_user_dict = rebuilt_dict;
482 }
483
484 self.save_to_history(&dict)?;
486
487 self.enqueue_delta(delta)?;
489
490 *dict = dict.new_version(new_user_dict);
492
493 Ok(dict.version)
494 }
495
496 pub fn reload_system_dict(&self) -> Result<Version> {
504 let mut dict = self.current.write().map_err(|_| {
505 DictError::Format("Failed to acquire write lock on dictionary".to_string())
506 })?;
507
508 let new_system_dict = SystemDictionary::load(&self.dicdir)?;
510
511 self.save_to_history(&dict)?;
513
514 *dict = dict.with_system_dict(new_system_dict);
516
517 Ok(dict.version)
518 }
519
520 pub fn rollback(&self, target_version: Version) -> Result<()> {
530 let target = {
531 let history = self.history.read().map_err(|_| {
532 DictError::Format("Failed to acquire read lock on history".to_string())
533 })?;
534
535 history
536 .iter()
537 .find(|v| v.version == target_version)
538 .ok_or_else(|| {
539 DictError::Format(format!("Version {target_version} not found in history"))
540 })?
541 .clone()
542 };
543
544 *self.current.write().map_err(|_| {
545 DictError::Format("Failed to acquire write lock on dictionary".to_string())
546 })? = target;
547
548 Ok(())
549 }
550
551 pub fn version_history(&self) -> Result<Vec<VersionInfo>> {
557 let history = self
558 .history
559 .read()
560 .map_err(|_| DictError::Format("Failed to acquire read lock on history".to_string()))?;
561
562 let current = self.current.read().map_err(|_| {
563 DictError::Format("Failed to acquire read lock on dictionary".to_string())
564 })?;
565
566 let mut versions = vec![VersionInfo {
567 version: current.version,
568 timestamp: current.timestamp,
569 user_entry_count: current.user_dict.len(),
570 }];
571
572 versions.extend(history.iter().map(|v| VersionInfo {
573 version: v.version,
574 timestamp: v.timestamp,
575 user_entry_count: v.user_dict.len(),
576 }));
577 drop(history);
578 drop(current);
579
580 versions.sort_by_key(|v| std::cmp::Reverse(v.version));
581
582 Ok(versions)
583 }
584
585 fn save_to_history(&self, dict: &VersionedDictionary) -> Result<()> {
587 let mut history = self.history.write().map_err(|_| {
588 DictError::Format("Failed to acquire write lock on history".to_string())
589 })?;
590
591 history.push_back(dict.clone());
592
593 while history.len() > self.max_history {
595 history.pop_front();
596 }
597 drop(history);
598
599 Ok(())
600 }
601
602 fn enqueue_delta(&self, delta: DeltaUpdate) -> Result<()> {
604 let mut queue = self.delta_queue.write().map_err(|_| {
605 DictError::Format("Failed to acquire write lock on delta queue".to_string())
606 })?;
607
608 queue.push_back(delta);
609
610 while queue.len() > self.max_delta_queue {
611 queue.pop_front();
612 }
613 drop(queue);
614
615 Ok(())
616 }
617
618 pub fn delta_history(&self) -> Result<Vec<DeltaUpdate>> {
624 let queue = self.delta_queue.read().map_err(|_| {
625 DictError::Format("Failed to acquire read lock on delta queue".to_string())
626 })?;
627
628 Ok(queue.iter().cloned().collect())
629 }
630
631 pub fn export_user_dict(&self) -> Result<UserDictionary> {
637 let dict = self.current.read().map_err(|_| {
638 DictError::Format("Failed to acquire read lock on dictionary".to_string())
639 })?;
640
641 let user_dict = (*dict.user_dict).clone();
642 drop(dict);
643 Ok(user_dict)
644 }
645
646 pub fn import_user_dict(&self, user_dict: UserDictionary) -> Result<Version> {
652 let mut dict = self.current.write().map_err(|_| {
653 DictError::Format("Failed to acquire write lock on dictionary".to_string())
654 })?;
655
656 self.save_to_history(&dict)?;
657 *dict = dict.new_version(user_dict);
658
659 Ok(dict.version)
660 }
661}
662
663#[derive(Debug, Clone)]
667pub struct DeltaUpdate {
668 additions: Vec<EntryChange>,
670 removals: Vec<String>,
672 modifications: Vec<EntryChange>,
674}
675
676impl Default for DeltaUpdate {
677 fn default() -> Self {
678 Self::new()
679 }
680}
681
682impl DeltaUpdate {
683 #[must_use]
685 pub const fn new() -> Self {
686 Self {
687 additions: Vec::new(),
688 removals: Vec::new(),
689 modifications: Vec::new(),
690 }
691 }
692
693 #[must_use]
695 pub const fn builder() -> DeltaUpdateBuilder {
696 DeltaUpdateBuilder::new()
697 }
698
699 #[must_use]
701 pub fn addition_count(&self) -> usize {
702 self.additions.len()
703 }
704
705 #[must_use]
707 pub fn removal_count(&self) -> usize {
708 self.removals.len()
709 }
710
711 #[must_use]
713 pub fn modification_count(&self) -> usize {
714 self.modifications.len()
715 }
716
717 #[must_use]
719 pub fn total_changes(&self) -> usize {
720 self.additions.len() + self.removals.len() + self.modifications.len()
721 }
722}
723
724#[derive(Debug, Clone)]
726pub struct EntryChange {
727 pub surface: String,
729 pub pos: String,
731 pub cost: i16,
733 pub reading: Option<String>,
735 pub left_id: u16,
737 pub right_id: u16,
739}
740
741impl EntryChange {
742 fn to_user_entry(&self) -> UserEntry {
744 UserEntry::new(
745 self.surface.clone(),
746 self.pos.clone(),
747 self.cost,
748 self.reading.clone(),
749 )
750 .with_context_ids(self.left_id, self.right_id)
751 }
752}
753
754pub struct DeltaUpdateBuilder {
756 delta: DeltaUpdate,
757}
758
759impl Default for DeltaUpdateBuilder {
760 fn default() -> Self {
761 Self::new()
762 }
763}
764
765impl DeltaUpdateBuilder {
766 #[must_use]
768 pub const fn new() -> Self {
769 Self {
770 delta: DeltaUpdate::new(),
771 }
772 }
773
774 #[must_use]
776 pub fn add(mut self, surface: impl Into<String>, pos: impl Into<String>, cost: i16) -> Self {
777 self.delta.additions.push(EntryChange {
778 surface: surface.into(),
779 pos: pos.into(),
780 cost,
781 reading: None,
782 left_id: 0,
783 right_id: 0,
784 });
785 self
786 }
787
788 #[must_use]
790 pub fn add_with_reading(
791 mut self,
792 surface: impl Into<String>,
793 pos: impl Into<String>,
794 cost: i16,
795 reading: impl Into<String>,
796 ) -> Self {
797 self.delta.additions.push(EntryChange {
798 surface: surface.into(),
799 pos: pos.into(),
800 cost,
801 reading: Some(reading.into()),
802 left_id: 0,
803 right_id: 0,
804 });
805 self
806 }
807
808 #[must_use]
810 pub fn remove(mut self, surface: impl Into<String>) -> Self {
811 self.delta.removals.push(surface.into());
812 self
813 }
814
815 #[must_use]
817 pub fn modify(mut self, surface: impl Into<String>, pos: impl Into<String>, cost: i16) -> Self {
818 self.delta.modifications.push(EntryChange {
819 surface: surface.into(),
820 pos: pos.into(),
821 cost,
822 reading: None,
823 left_id: 0,
824 right_id: 0,
825 });
826 self
827 }
828
829 #[must_use]
831 pub fn build(self) -> DeltaUpdate {
832 self.delta
833 }
834}
835
836#[derive(Debug, Clone)]
838pub struct VersionInfo {
839 pub version: Version,
841 pub timestamp: SystemTime,
843 pub user_entry_count: usize,
845}
846
847impl VersionInfo {
848 #[must_use]
850 pub fn age(&self) -> Option<Duration> {
851 SystemTime::now().duration_since(self.timestamp).ok()
852 }
853}
854
855#[cfg(test)]
856#[allow(clippy::expect_used, clippy::unwrap_used, clippy::vec_init_then_push)]
857mod tests {
858 use super::*;
859 use crate::matrix::DenseMatrix;
860 use crate::trie::TrieBuilder;
861
862 fn create_test_system_dict() -> SystemDictionary {
863 let entries = vec![("가", 0u32), ("가다", 1), ("가방", 2)];
864 let trie_bytes = TrieBuilder::build(&entries).expect("should build trie");
865 let trie = crate::trie::TrieBackend::Owned(crate::trie::Trie::from_vec(trie_bytes));
866 let matrix = crate::matrix::ConnectionMatrix::Dense(DenseMatrix::new(10, 10, 100));
867
868 let mut dict_entries = Vec::new();
869 dict_entries.push(DictEntry::new("가", 1, 1, 100, "NNG,*,T,가,*,*,*,*"));
870 dict_entries.push(DictEntry::new("가다", 2, 2, 200, "VV,*,F,가다,*,*,*,*"));
871 dict_entries.push(DictEntry::new("가방", 3, 3, 300, "NNG,*,T,가방,*,*,*,*"));
872
873 SystemDictionary::new_test(PathBuf::from("./test_dic"), trie, matrix, dict_entries)
874 }
875
876 #[test]
877 fn test_hot_reload_dictionary_add_entry() {
878 let system_dict = create_test_system_dict();
879 let dicdir = system_dict.dicdir().to_path_buf();
880
881 let versioned = VersionedDictionary {
882 version: 1,
883 system_dict: Arc::new(system_dict),
884 user_dict: Arc::new(UserDictionary::new()),
885 timestamp: SystemTime::now(),
886 };
887
888 let dict = HotReloadDictionary {
889 current: Arc::new(RwLock::new(versioned)),
890 history: Arc::new(RwLock::new(VecDeque::new())),
891 max_history: 10,
892 delta_queue: Arc::new(RwLock::new(VecDeque::new())),
893 max_delta_queue: 100,
894 dicdir,
895 };
896
897 let v1 = dict.current_version();
898 assert_eq!(v1, 1);
899
900 let v2 = dict
901 .add_entry("딥러닝", "NNG", -1000, None)
902 .expect("should add entry");
903 assert_eq!(v2, 2);
904
905 let entries = dict.lookup("딥러닝").expect("should lookup");
906 assert_eq!(entries.len(), 1);
907 assert_eq!(entries[0].surface, "딥러닝");
908 }
909
910 #[test]
911 fn test_hot_reload_dictionary_remove_entry() {
912 let system_dict = create_test_system_dict();
913 let dicdir = system_dict.dicdir().to_path_buf();
914
915 let mut user_dict = UserDictionary::new();
916 user_dict.add_entry("딥러닝", "NNG", Some(-1000), None);
917
918 let versioned = VersionedDictionary {
919 version: 1,
920 system_dict: Arc::new(system_dict),
921 user_dict: Arc::new(user_dict),
922 timestamp: SystemTime::now(),
923 };
924
925 let dict = HotReloadDictionary {
926 current: Arc::new(RwLock::new(versioned)),
927 history: Arc::new(RwLock::new(VecDeque::new())),
928 max_history: 10,
929 delta_queue: Arc::new(RwLock::new(VecDeque::new())),
930 max_delta_queue: 100,
931 dicdir,
932 };
933
934 let (version, removed) = dict.remove_entry("딥러닝").expect("should remove");
935 assert_eq!(version, 2);
936 assert_eq!(removed, 1);
937
938 let entries = dict.lookup("딥러닝").expect("should lookup");
939 assert!(entries.is_empty());
940 }
941
942 #[test]
943 fn test_delta_update() {
944 let system_dict = create_test_system_dict();
945 let dicdir = system_dict.dicdir().to_path_buf();
946
947 let versioned = VersionedDictionary {
948 version: 1,
949 system_dict: Arc::new(system_dict),
950 user_dict: Arc::new(UserDictionary::new()),
951 timestamp: SystemTime::now(),
952 };
953
954 let dict = HotReloadDictionary {
955 current: Arc::new(RwLock::new(versioned)),
956 history: Arc::new(RwLock::new(VecDeque::new())),
957 max_history: 10,
958 delta_queue: Arc::new(RwLock::new(VecDeque::new())),
959 max_delta_queue: 100,
960 dicdir,
961 };
962
963 let delta = DeltaUpdate::builder()
964 .add("딥러닝", "NNG", -1000)
965 .add("머신러닝", "NNG", -1000)
966 .add("자연어처리", "NNG", -1000)
967 .build();
968
969 assert_eq!(delta.addition_count(), 3);
970
971 let version = dict.apply_delta(delta).expect("should apply delta");
972 assert_eq!(version, 2);
973
974 let entries = dict.lookup("딥러닝").expect("should lookup");
975 assert_eq!(entries.len(), 1);
976
977 let entries = dict.lookup("머신러닝").expect("should lookup");
978 assert_eq!(entries.len(), 1);
979 }
980
981 #[test]
982 fn test_version_rollback() {
983 let system_dict = create_test_system_dict();
984 let dicdir = system_dict.dicdir().to_path_buf();
985
986 let versioned = VersionedDictionary {
987 version: 1,
988 system_dict: Arc::new(system_dict),
989 user_dict: Arc::new(UserDictionary::new()),
990 timestamp: SystemTime::now(),
991 };
992
993 let dict = HotReloadDictionary {
994 current: Arc::new(RwLock::new(versioned)),
995 history: Arc::new(RwLock::new(VecDeque::new())),
996 max_history: 10,
997 delta_queue: Arc::new(RwLock::new(VecDeque::new())),
998 max_delta_queue: 100,
999 dicdir,
1000 };
1001
1002 let v1 = dict.current_version();
1004
1005 dict.add_entry("딥러닝", "NNG", -1000, None)
1007 .expect("should add");
1008
1009 dict.add_entry("머신러닝", "NNG", -1000, None)
1011 .expect("should add");
1012
1013 assert_eq!(dict.current_version(), 3);
1014
1015 dict.rollback(v1).expect("should rollback");
1017 assert_eq!(dict.current_version(), v1);
1018
1019 let entries = dict.lookup("딥러닝").expect("should lookup");
1020 assert!(entries.is_empty());
1021 }
1022
1023 #[test]
1024 fn test_version_history() {
1025 let system_dict = create_test_system_dict();
1026 let dicdir = system_dict.dicdir().to_path_buf();
1027
1028 let versioned = VersionedDictionary {
1029 version: 1,
1030 system_dict: Arc::new(system_dict),
1031 user_dict: Arc::new(UserDictionary::new()),
1032 timestamp: SystemTime::now(),
1033 };
1034
1035 let dict = HotReloadDictionary {
1036 current: Arc::new(RwLock::new(versioned)),
1037 history: Arc::new(RwLock::new(VecDeque::new())),
1038 max_history: 10,
1039 delta_queue: Arc::new(RwLock::new(VecDeque::new())),
1040 max_delta_queue: 100,
1041 dicdir,
1042 };
1043
1044 dict.add_entry("A", "NNG", 0, None).expect("should add");
1045 dict.add_entry("B", "NNG", 0, None).expect("should add");
1046 dict.add_entry("C", "NNG", 0, None).expect("should add");
1047
1048 let history = dict.version_history().expect("should get history");
1049 assert_eq!(history.len(), 4); assert_eq!(history[0].version, 4); }
1052
1053 #[test]
1054 fn test_update_entry() {
1055 let system_dict = create_test_system_dict();
1056 let dicdir = system_dict.dicdir().to_path_buf();
1057
1058 let mut user_dict = UserDictionary::new();
1059 user_dict.add_entry("딥러닝", "NNG", Some(-1000), None);
1060
1061 let versioned = VersionedDictionary {
1062 version: 1,
1063 system_dict: Arc::new(system_dict),
1064 user_dict: Arc::new(user_dict),
1065 timestamp: SystemTime::now(),
1066 };
1067
1068 let dict = HotReloadDictionary {
1069 current: Arc::new(RwLock::new(versioned)),
1070 history: Arc::new(RwLock::new(VecDeque::new())),
1071 max_history: 10,
1072 delta_queue: Arc::new(RwLock::new(VecDeque::new())),
1073 max_delta_queue: 100,
1074 dicdir,
1075 };
1076
1077 dict.update_entry("딥러닝", |entry| {
1078 entry.cost = -2000;
1079 entry.reading = Some("딥러닝".to_string());
1080 })
1081 .expect("should update");
1082
1083 let entries = dict.lookup("딥러닝").expect("should lookup");
1084 assert_eq!(entries.len(), 1);
1085 assert_eq!(entries[0].cost, -2000);
1086 }
1087}