Skip to main content

linkmarks_core/
traits.rs

1//! Source/sink traits.
2//!
3//! Bridges implement these. The CLI orchestrates them via
4//! `SourceRegistry` (CLI crate). Plugins implement the same
5//! traits via `libloading`.
6
7use crate::errors::CoreError;
8use crate::model::{Bookmark, SourceKind};
9use serde::{Deserialize, Serialize};
10
11/// A paginated result.
12#[derive(Debug, Clone, Serialize, Deserialize)]
13pub struct Page {
14    /// Bookmarks in this page, sorted by canonical URL then id.
15    pub items: Vec<Bookmark>,
16    /// Opaque cursor for the next page; `None` when exhausted.
17    pub next_cursor: Option<String>,
18}
19
20/// Report from a sink write operation.
21#[derive(Debug, Clone, Default, Serialize, Deserialize)]
22pub struct WriteReport {
23    /// Number of records successfully written.
24    pub written: usize,
25    /// Number of records that failed (per-element; non-fatal).
26    pub failed: Vec<FailedRecord>,
27}
28
29/// One record that a sink could not write.
30#[derive(Debug, Clone, Serialize, Deserialize)]
31pub struct FailedRecord {
32    /// Identifier (URL, external_id) of the failed record.
33    pub id: String,
34    /// Reason for failure.
35    pub reason: String,
36}
37
38/// Read-side trait. Implemented by every bridge.
39pub trait BookmarkSource: Send + Sync {
40    /// What kind of source this is.
41    fn kind(&self) -> SourceKind;
42
43    /// List all bookmarks. May be expensive for large stores; prefer
44    /// `list_paginated` for production reads.
45    fn list(&self) -> Result<Vec<Bookmark>, CoreError>;
46
47    /// Paginated listing. Cursor is opaque; first call uses `None`.
48    fn list_paginated(&self, cursor: Option<String>, limit: usize) -> Result<Page, CoreError>;
49
50    /// Look up a single bookmark by canonical URL.
51    fn by_canonical(&self, canonical: &str) -> Result<Option<Bookmark>, CoreError>;
52}
53
54/// Write-side trait. Implemented by sinks (Netscape HTML, server).
55pub trait BookmarkSink: Send + Sync {
56    /// What kind of sink this is.
57    fn kind(&self) -> SourceKind;
58
59    /// Write a batch of bookmarks. Returns a report; non-fatal
60    /// failures are listed in `WriteReport::failed`.
61    fn write(&mut self, bookmarks: &[Bookmark]) -> Result<WriteReport, CoreError>;
62
63    /// Delete a bookmark by external identifier.
64    fn delete(&mut self, external_id: &str) -> Result<(), CoreError>;
65}