samod_core/
automerge_url.rs

1use std::str::FromStr;
2
3use automerge as am;
4
5use crate::DocumentId;
6
7#[derive(Clone)]
8pub struct AutomergeUrl {
9    document_id: DocumentId,
10    path: Option<Vec<am::Prop>>,
11}
12
13impl From<&DocumentId> for AutomergeUrl {
14    fn from(id: &DocumentId) -> Self {
15        AutomergeUrl {
16            document_id: id.clone(),
17            path: None,
18        }
19    }
20}
21
22impl std::fmt::Display for AutomergeUrl {
23    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
24        write!(f, "automerge:{}", self.document_id)?;
25        if let Some(path) = &self.path {
26            for prop in path {
27                match prop {
28                    am::Prop::Seq(i) => write!(f, "/{i}")?,
29                    am::Prop::Map(s) => write!(f, "/{s}")?,
30                }
31            }
32        }
33        Ok(())
34    }
35}
36
37impl std::fmt::Debug for AutomergeUrl {
38    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
39        write!(f, "AutomergeUrl({self})")
40    }
41}
42
43impl FromStr for AutomergeUrl {
44    type Err = InvalidUrlError;
45
46    fn from_str(s: &str) -> Result<Self, Self::Err> {
47        let Some(suffix) = s.strip_prefix("automerge:") else {
48            return Err(InvalidUrlError(format!("invalid automerge url: {s}")));
49        };
50        let mut parts = suffix.split("/");
51        let Some(doc_id_part) = parts.next() else {
52            return Err(InvalidUrlError(format!("invalid automerge url: {s}")));
53        };
54        let Ok(id) = DocumentId::from_str(doc_id_part) else {
55            return Err(InvalidUrlError(format!("invalid automerge url: {s}")));
56        };
57        let props = parts
58            .map(|p| {
59                if let Ok(i) = usize::from_str(p) {
60                    am::Prop::Seq(i)
61                } else {
62                    am::Prop::Map(p.to_string())
63                }
64            })
65            .collect::<Vec<_>>();
66        Ok(AutomergeUrl {
67            document_id: id,
68            path: if props.is_empty() { None } else { Some(props) },
69        })
70    }
71}
72
73pub struct InvalidUrlError(String);
74
75impl std::fmt::Display for InvalidUrlError {
76    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
77        write!(f, "Invalid Automerge URL: {}", self.0)
78    }
79}
80
81impl std::fmt::Debug for InvalidUrlError {
82    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
83        write!(f, "InvalidUrlError({})", self.0)
84    }
85}
86
87impl std::error::Error for InvalidUrlError {}