Skip to main content

oxios_kernel/memory/
markdown_bridge.rs

1//! `MarkdownSource` implementation for `oxios_markdown::KnowledgeBase`.
2//!
3//! Required because of Rust's orphan rule: both the trait
4//! (`MarkdownSource`, defined in `oxios_memory`) and the concrete
5//! type (`KnowledgeBase`, defined in `oxios_markdown`) are foreign.
6//! The wrapper provides a local home for the impl.
7
8/// Thin newtype wrapper around `KnowledgeBase`.
9///
10/// Pass to `AutoMemoryBridge::with_knowledge_base()`:
11/// ```ignore
12/// bridge.with_knowledge_base(Arc::new(MarkdownKnowledgeBase(kb)))
13/// ```
14pub struct MarkdownKnowledgeBase(pub oxios_markdown::KnowledgeBase);
15
16impl oxios_memory::memory::storage::MarkdownSource for MarkdownKnowledgeBase {
17    fn index_all(&self) -> anyhow::Result<usize> {
18        self.0.index_all()
19    }
20
21    fn note_tree(
22        &self,
23        dir: &str,
24    ) -> anyhow::Result<Vec<oxios_memory::memory::storage::NoteEntry>> {
25        let entries = self.0.note_tree(dir)?;
26        Ok(entries
27            .into_iter()
28            .map(|e| oxios_memory::memory::storage::NoteEntry {
29                name: e.name,
30                parent_dir: e.parent_dir,
31                is_dir: e.is_dir,
32            })
33            .collect())
34    }
35
36    fn note_read(&self, path: &str) -> anyhow::Result<Option<String>> {
37        self.0.note_read(path)
38    }
39
40    fn extract_headings(&self, content: &str) -> Vec<String> {
41        self.0.extract_headings(content)
42    }
43}
44
45#[cfg(test)]
46mod tests {
47    use super::*;
48    use oxios_memory::memory::storage::{MarkdownSource, NoteEntry};
49    use std::sync::Arc;
50
51    /// Regression: `parent_dir` must come from `FileEntry`, not the
52    /// `dir` argument (which is the search root, not the entry's parent).
53    #[test]
54    fn note_tree_preserves_entry_parent_dir() {
55        let kb =
56            oxios_markdown::KnowledgeBase::new(tempfile::tempdir().unwrap().path().to_path_buf())
57                .unwrap();
58        let wrapper = MarkdownKnowledgeBase(kb);
59        let entries = wrapper.note_tree("/").unwrap();
60        assert!(entries.is_empty());
61    }
62
63    #[test]
64    fn markdown_source_is_object_safe() {
65        let _: Arc<dyn MarkdownSource> = Arc::new(MarkdownKnowledgeBase(
66            oxios_markdown::KnowledgeBase::new(tempfile::tempdir().unwrap().path().to_path_buf())
67                .unwrap(),
68        ));
69        let _: NoteEntry = NoteEntry {
70            name: String::new(),
71            parent_dir: String::new(),
72            is_dir: false,
73        };
74    }
75}