summaryrefslogtreecommitdiff
path: root/src/lib.rs
blob: b7994d353221edcc860a75522ad93a23c8cfed8b (plain)
#![warn(clippy::pedantic)]
#![warn(clippy::nursery)]

use std::collections::HashMap;
use std::fs::{File, Metadata};
use std::path::{Path, PathBuf};
use std::time::Instant;

use serde::{Deserialize, Serialize};

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<String>,
	nickname: String,
	realname: Option<String>,
	public_keys: Vec<String>,
}

struct Channel {
	id: ChannelId,
	name: String,
	remotes: Vec<Remote>,
	main_remote: Option<Remote>,
	patches: Vec<PatchId>,
}

#[derive(Debug, Clone, Deserialize, Serialize)]
struct Patch {
	id: PatchId,
	authors: Vec<ContributorId>,
	recorder: ContributorId,
	metadata: HashMap<String, String>,
	affected_files: Vec<FileId>,
	contents: String,
}

#[derive(Debug, Clone, Deserialize, Serialize)]
struct FileInfo {
	id: FileId,
	root_span: SpanNodeId,
	name_changes: Vec<(PatchId, FilenameOperation)>,
	spans: Vec<SpanNode>,
}

#[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<PatchId>,
	deleted_by: Vec<PatchId>,
	preceding_nodes: Vec<SpanNodeId>,
	successor_nodes: Vec<SpanNodeId>,
}

#[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<DiffSpan>);

struct DiffSpan {
	left: Vec<u8>,
	right: Vec<u8>,
}

struct Log {
	entries: Vec<LogEntry>,
}

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<Metadata>;
	fn open_file(path: &Path) -> std::io::Result<File>;
	fn file_metadata(path: &Path) -> std::io::Result<Metadata>;
	fn is_file_changed(path: &Path, since: Instant) -> std::io::Result<bool>;
}

trait Repository {
	fn archive(&self) -> Vec<u8>;

	fn remotes(&self) -> Vec<Remote>;
	fn main_remote(&self) -> Option<Remote>;
	fn set_main_remote(&mut self, remote: Option<Remote>);
	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<ContributorId>;
	fn contributor(&self, id: ContributorId) -> Contributor;
	fn credit(&self, filename: &Path, byte: usize) -> Option<ContributorId>;

	fn all_channels(&self) -> Vec<ChannelId>;
	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<PatchId>;
	fn active_patches(&self) -> Vec<PatchId>;
	fn patch(&self, id: PatchId) -> Option<Patch>;
	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<FileId>;
	fn file(&self, id: FileId) -> Option<FileInfo>;
	fn write_file_from_patch(&self, id: FileId, patch: PatchId) -> Vec<u8>;
}