#![allow(clippy::large_enum_variant)] use std::collections::HashSet; use std::convert::TryFrom; use std::ops::ControlFlow; use automerge::{Automerge, ObjType, ScalarValue, Value}; use crate::cob::automerge::doc::{Document, DocumentError}; use crate::cob::automerge::shared; use crate::cob::automerge::shared::*; use crate::cob::automerge::store::{Error, Store}; use crate::cob::automerge::transaction::{Transaction, TransactionError}; use crate::cob::automerge::value::{FromValue, ValueError}; use crate::cob::common::*; use crate::cob::issue::*; use crate::cob::{Contents, History, ObjectId, Timestamp, TypeName}; use crate::prelude::*; impl From for ScalarValue { fn from(state: State) -> Self { match state { State::Open => ScalarValue::from("open"), State::Closed { reason: CloseReason::Solved, } => ScalarValue::from("solved"), State::Closed { reason: CloseReason::Other, } => ScalarValue::from("closed"), } } } impl<'a> FromValue<'a> for State { fn from_value(value: Value) -> Result { let state = value.to_str().ok_or(ValueError::InvalidType)?; match state { "open" => Ok(Self::Open), "closed" => Ok(Self::Closed { reason: CloseReason::Other, }), "solved" => Ok(Self::Closed { reason: CloseReason::Solved, }), _ => Err(ValueError::InvalidValue(value.to_string())), } } } impl FromHistory for Issue { fn type_name() -> &'static TypeName { &TYPENAME } fn from_history(history: &History) -> Result { let doc = history.traverse(Automerge::new(), |mut doc, entry| { let bytes = entry.contents(); match automerge::Change::from_bytes(bytes.clone()) { Ok(change) => { doc.apply_changes([change]).ok(); } Err(_err) => { // Ignore } } ControlFlow::Continue(doc) }); let issue = Issue::try_from(doc)?; Ok(issue) } } impl TryFrom<&History> for Issue { type Error = Error; fn try_from(history: &History) -> Result { Issue::from_history(history) } } impl TryFrom for Issue { type Error = DocumentError; fn try_from(doc: Automerge) -> Result { let doc = Document::new(&doc); let obj_id = doc.get_id(automerge::ObjId::Root, "issue")?; let title = doc.get(&obj_id, "title")?; let comment_id = doc.get_id(&obj_id, "comment")?; let author = doc.get(&obj_id, "author").map(Author::new)?; let state = doc.get(&obj_id, "state")?; let timestamp = doc.get(&obj_id, "timestamp")?; let comment = shared::lookup::comment(doc, &comment_id)?; let discussion: Discussion = doc.list(&obj_id, "discussion", shared::lookup::thread)?; let labels: HashSet