pub mod cache; use std::collections::btree_map; use std::collections::{BTreeMap, BTreeSet, HashMap}; use std::fmt; use std::ops::Deref; use std::str::FromStr; use amplify::Wrapper; use nonempty::NonEmpty; use once_cell::sync::Lazy; use serde::{Deserialize, Serialize}; use storage::{HasRepoId, RepositoryError}; use thiserror::Error; use crate::cob; use crate::cob::common::{Author, Authorization, CodeLocation, Label, Reaction, Timestamp}; use crate::cob::store::Transaction; use crate::cob::store::{Cob, CobAction}; use crate::cob::thread; use crate::cob::thread::Thread; use crate::cob::thread::{Comment, CommentId, Edit, Reactions}; use crate::cob::{op, store, ActorId, Embed, EntryId, ObjectId, TypeName, Uri}; use crate::crypto::{PublicKey, Signer}; use crate::git; use crate::identity::doc::DocError; use crate::identity::PayloadError; use crate::prelude::*; use crate::storage; pub use cache::Cache; /// Type name of a patch. pub static TYPENAME: Lazy = Lazy::new(|| FromStr::from_str("xyz.radicle.patch").expect("type name is valid")); /// Patch operation. pub type Op = cob::Op; /// Identifier for a patch. pub type PatchId = ObjectId; /// Unique identifier for a patch revision. #[derive( Wrapper, Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Hash, From, Display, )] #[display(inner)] #[wrap(Deref)] pub struct RevisionId(EntryId); /// Unique identifier for a patch review. #[derive( Wrapper, Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Hash, From, Display, )] #[display(inner)] #[wrapper(Deref)] pub struct ReviewId(EntryId); /// Index of a revision in the revisions list. pub type RevisionIx = usize; /// Error applying an operation onto a state. #[derive(Debug, Error)] pub enum Error { /// Causal dependency missing. /// /// This error indicates that the operations are not being applied /// in causal order, which is a requirement for this CRDT. /// /// For example, this can occur if an operation references anothern operation /// that hasn't happened yet. #[error("causal dependency {0:?} missing")] Missing(EntryId), /// Error applying an op to the patch thread. #[error("thread apply failed: {0}")] Thread(#[from] thread::Error), /// Error loading the identity document committed to by an operation. #[error("identity doc failed to load: {0}")] Doc(#[from] DocError), /// Identity document is missing. #[error("missing identity document")] MissingIdentity, /// Review is empty. #[error("empty review; verdict or summary not provided")] EmptyReview, /// Duplicate review. #[error("review {0} of {1} already exists by author {2}")] DuplicateReview(ReviewId, RevisionId, NodeId), /// Error loading the document payload. #[error("payload failed to load: {0}")] Payload(#[from] PayloadError), /// Git error. #[error("git: {0}")] Git(#[from] git::ext::Error), /// Store error. #[error("store: {0}")] Store(#[from] store::Error), #[error("op decoding failed: {0}")] Op(#[from] op::OpEncodingError), /// Action not authorized by the author #[error("{0} not authorized to apply {1:?}")] NotAuthorized(ActorId, Action), /// An illegal action. #[error("action is not allowed: {0}")] NotAllowed(EntryId), /// Revision not found. #[error("revision not found: {0}")] RevisionNotFound(RevisionId), /// Initialization failed. #[error("initialization failed: {0}")] Init(&'static str), #[error("failed to update patch {id} in cache: {err}")] CacheUpdate { id: PatchId, #[source] err: Box, }, #[error("failed to remove patch {id} from cache: {err}")] CacheRemove { id: PatchId, #[source] err: Box, }, #[error("failed to remove patches from cache: {err}")] CacheRemoveAll { #[source] err: Box, }, } /// Patch operation. #[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] #[serde(tag = "type", rename_all = "camelCase")] pub enum Action { // // Actions on patch. // #[serde(rename = "edit")] Edit { title: String, target: MergeTarget }, #[serde(rename = "label")] Label { labels: BTreeSet