#![warn(clippy::pedantic)] #![warn(clippy::nursery)] #![allow(clippy::redundant_else)] use std::collections::HashMap; use std::fs::{File, Metadata}; use std::path::{Path, PathBuf}; use std::time::Instant; use serde::{Deserialize, Serialize}; mod calculation; mod diff; mod object; mod workarea; #[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] struct ContributorId(String); #[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] struct ChannelId(String); #[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] struct PatchId(String); #[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] struct FileId(String); #[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] struct SpanNodeId(String); struct Remote { url: String, name: String, } struct Contributor { id: ContributorId, emails: Vec, nickname: String, realname: Option, public_keys: Vec, } struct Channel { id: ChannelId, name: String, remotes: Vec, main_remote: Option, patches: Vec, } #[derive(Debug, Clone, Deserialize, Serialize)] struct Patch { id: PatchId, authors: Vec, recorder: ContributorId, dependencies: Vec, metadata: HashMap, affected_files: Vec, contents: Vec, } #[derive(Debug, Clone, Deserialize, Serialize)] struct FileInfo { id: FileId, root_span: SpanNodeId, name_changes: Vec<(PatchId, FilenameOperation)>, spans: HashMap, } #[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] enum FilenameOperation { Add { filename: PathBuf }, Rename { filename: PathBuf }, Delete, } #[derive(Debug, Clone, Serialize, Deserialize)] struct SpanNode { id: SpanNodeId, span: Span, added_by: Vec, deleted_by: Vec, preceding_nodes: Vec, successor_nodes: Vec, } #[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] struct Span { patch: PatchId, start: usize, len: usize, } type DiffAlgorithm = fn(File, File) -> Diff; struct Diff(Vec); struct DiffSpan { left: Vec, right: Vec, } struct Log { entries: Vec, } enum LogEntry { CreatePatch(PatchId), } type RevertAlgorithm = fn(Patch) -> Patch; trait Id { fn id(&self) -> &str; } impl Id for Patch { fn id(&self) -> &str { &self.id.0 } } impl Id for FileInfo { fn id(&self) -> &str { &self.id.0 } } trait StagingArea { fn list_files() -> std::io::Result; fn open_file(path: &Path) -> std::io::Result; fn file_metadata(path: &Path) -> std::io::Result; fn is_file_changed(path: &Path, since: Instant) -> std::io::Result; } trait Repository { fn archive(&self) -> Vec; fn remotes(&self) -> Vec; fn main_remote(&self) -> Option; fn set_main_remote(&mut self, remote: Option); fn add_remote(&mut self, remote: Remote); fn delete_remote(&mut self, remote: Remote); fn push(&self, remote: Remote); fn pull(&mut self, remote: Remote); fn all_contributors(&self) -> Vec; fn contributor(&self, id: ContributorId) -> Contributor; fn credit(&self, filename: &Path, byte: usize) -> Option; fn all_channels(&self) -> Vec; fn active_channel(&self) -> ChannelId; fn channel(&self, id: ChannelId) -> Channel; fn create_channel(&mut self, channel: Channel); fn change_channel(&mut self, id: ChannelId) -> Channel; fn rename_channel(&mut self, id: ChannelId, name: &str) -> Channel; fn delete_channel(&mut self, id: ChannelId); fn add_patches_to_channel(&mut self, channel: ChannelId, patches: &[PatchId]) -> Channel; fn add_channel_to_channel(&mut self, channel: ChannelId, plus: ChannelId) -> Channel; fn all_patches(&self) -> Vec; fn active_patches(&self) -> Vec; fn patch(&self, id: PatchId) -> Option; fn create_patch(&mut self, patch: Patch); fn delete_patch(&mut self, id: PatchId); fn set_active_patches(&mut self, ids: &[PatchId]); fn combine_patches(&mut self, patches: &[PatchId]) -> Patch; fn active_files(&self) -> Vec; fn file(&self, id: FileId) -> Option; fn write_file_from_patch(&self, id: FileId, patch: PatchId) -> Vec; }