Skip to main content

mecab_ko_dict/trie/
mmap.rs

1//! mmap 백엔드 Trie
2
3use std::path::Path;
4
5use yada::DoubleArray;
6
7use crate::error::{DictError, Result};
8
9/// mmap 백엔드 Trie
10///
11/// 파일을 메모리 맵으로 직접 접근하여 불필요한 복사 없이 Trie를 사용합니다.
12pub struct MmapTrie {
13    pub(super) da: DoubleArray<memmap2::Mmap>,
14}
15
16impl MmapTrie {
17    /// 파일을 메모리 맵으로 열어 Trie 로드
18    ///
19    /// # Errors
20    ///
21    /// 파일을 열거나 매핑할 수 없는 경우 에러를 반환합니다.
22    #[allow(unsafe_code)]
23    pub fn from_file<P: AsRef<Path>>(path: P) -> Result<Self> {
24        let file = std::fs::File::open(path.as_ref()).map_err(DictError::Io)?;
25        // SAFETY: The mapped file is a read-only dictionary installed immutably.
26        // Caller must ensure no concurrent writes or truncation to this path.
27        let mmap = unsafe { memmap2::Mmap::map(&file).map_err(DictError::Io)? };
28        Ok(Self {
29            da: DoubleArray::new(mmap),
30        })
31    }
32
33    /// 정확히 일치하는 키 검색
34    #[must_use]
35    pub fn exact_match(&self, key: &str) -> Option<u32> {
36        self.da.exact_match_search(key.as_bytes())
37    }
38
39    /// 바이트 키로 정확히 일치하는 키 검색
40    #[must_use]
41    pub fn exact_match_bytes(&self, key: &[u8]) -> Option<u32> {
42        self.da.exact_match_search(key)
43    }
44
45    /// 공통 접두사 검색
46    pub fn common_prefix_search<'a>(
47        &'a self,
48        text: &'a str,
49    ) -> impl Iterator<Item = (u32, usize)> + 'a {
50        self.da.common_prefix_search(text.as_bytes())
51    }
52
53    /// 바이트 키로 공통 접두사 검색
54    pub fn common_prefix_search_bytes<'a>(
55        &'a self,
56        key: &'a [u8],
57    ) -> impl Iterator<Item = (u32, usize)> + 'a {
58        self.da.common_prefix_search(key)
59    }
60
61    /// 특정 위치에서 공통 접두사 검색
62    #[must_use]
63    pub fn common_prefix_search_at(
64        &self,
65        text: &str,
66        start_byte: usize,
67    ) -> super::backend::PrefixSearchResult {
68        if start_byte >= text.len() {
69            return super::backend::PrefixSearchResult::new();
70        }
71        let suffix = &text[start_byte..];
72        self.da
73            .common_prefix_search(suffix.as_bytes())
74            .map(|(value, len)| (value, start_byte + len))
75            .collect()
76    }
77}