samod_core/
automerge_url.rs

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