Onset: version control where nobody waits and nothing gets lost. The on command, its core and onset-server.
| 6 | //! hosted server in Wasm) own storage and the network; everything here works |
| 7 | //! on bytes and on a [`Source`] that hands objects back by ID. |
| 8 |
| 9 | pub mod bundle; |
| 10 | pub mod chunk; |
| 11 | pub mod diff; |
| 12 | pub mod filter; |
| 13 | pub mod git; |
| 14 | pub mod history; |
| 15 | pub mod id; |
| 16 | pub mod merge; |
| 17 | pub mod object; |
| 18 | pub mod rename; |
| 19 | pub mod secrets; |
| 20 | pub mod tree; |
| 21 | pub mod version; |
| 22 |
| 23 | pub use id::Id; |
| 24 | pub use object::{Kind, Object}; |
| 25 |
| 26 | #[derive(Debug, thiserror::Error)] |
| 27 | pub enum Error { |
| 28 | #[error("missing object {0}")] |
| 29 | Missing(Id), |
| 30 | #[error("{0}")] |
| 31 | Corrupt(String), |
| 32 | #[error("limit exceeded: {0}")] |
| 33 | Limit(String), |
| 34 | } |
| 35 |
| 36 | pub type Result<T, E = Error> = std::result::Result<T, E>; |
| 37 |
| 38 | pub(crate) fn corrupt(message: impl Into<String>) -> Error { |
| 39 | Error::Corrupt(message.into()) |
| 40 | } |
| 41 |
| 42 | /// Where objects come from. Hosts implement it over their storage. |
| 43 | pub trait Source { |
| 44 | fn get(&self, id: &Id) -> Result<Option<Object>>; |
| 45 |
| 46 | fn must(&self, id: &Id) -> Result<Object> { |
| 47 | self.get(id)?.ok_or(Error::Missing(*id)) |
| 48 | } |
| 49 | } |
| 50 |
| 51 | /// An in-memory source, for tests and for objects a merge creates. |
| 52 | #[derive(Default, Clone)] |
| 53 | pub struct MemSource { |
| 54 | pub objects: std::collections::HashMap<Id, Object>, |
| 55 | } |
| 56 |
| 57 | impl MemSource { |
| 58 | pub fn put(&mut self, object: Object) -> Id { |
| 59 | let id = object.id(); |
| 60 | self.objects.insert(id, object); |
| 61 | id |
| 62 | } |
| 63 | } |
| 64 |
| 65 | impl Source for MemSource { |
| 66 | fn get(&self, id: &Id) -> Result<Option<Object>> { |
| 67 | Ok(self.objects.get(id).cloned()) |
| 68 | } |
| 69 | } |
| 70 |
| 71 | /// Reads from `first`, then `second` (new objects over a store). |
| 72 | pub struct Layered<'a> { |
| 73 | pub first: &'a dyn Source, |
| 74 | pub second: &'a dyn Source, |
| 75 | } |
| 76 |
| 77 | impl Source for Layered<'_> { |
| 78 | fn get(&self, id: &Id) -> Result<Option<Object>> { |
| 79 | match self.first.get(id)? { |
| 80 | Some(o) => Ok(Some(o)), |
| 81 | None => self.second.get(id), |
| 82 | } |
| 83 | } |
| 84 | } |
| 85 |