1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
//! Types common to the entire crate.
use std::cell::RefCell;
use std::collections::{HashMap, HashSet};
use std::error::Error;
use std::fmt::{self, Display, Formatter};
use std::rc::Rc;
/// A set of paths, used to track which files we care about
pub type PathSet = HashSet<String>;
/// A change to a file in Git (or at least the kinds we care about)
///
/// Copies and renames have additional info:
/// how much of the file remained the same.
#[derive(Debug, Copy, Clone)]
pub enum Change {
Added,
Deleted,
Modified,
Renamed{ percent_changed: u8},
Copied{ percent_changed: u8},
}
/// A change made to a given file in a commit
#[derive(Debug, Clone)]
pub struct FileDelta {
/// The change type
pub change: Change,
/// The current path of the file
pub path: String,
/// The previous path of the file if the change is a rename or copy,
/// and an empty string otherwise
pub from: String,
}
/// A 20-byte SHA1 hash, used for identifying objects in Git.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub struct SHA1 {
bytes: [u8; 20]
}
#[derive(Copy, Clone, Debug)]
pub enum SHA1ParseError {
IncorrectLength,
InvalidHexadecimal
}
impl Error for SHA1ParseError {
fn description(&self) -> &str {
match *self {
SHA1ParseError::IncorrectLength => "String is not 40 characters long",
SHA1ParseError::InvalidHexadecimal => "String is not valid hexadecimal",
}
}
}
impl Display for SHA1ParseError {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
self.description().fmt(f)
}
}
impl SHA1 {
/// Parses a SHA1 from a 40 character hex string
pub fn parse(s: &str) -> Result<SHA1, SHA1ParseError> {
if s.len() != 40 { return Err(SHA1ParseError::IncorrectLength) }
let mut ret = SHA1::default();
for i in 0..20 {
let char_index = i * 2;
ret.bytes[i] = match u8::from_str_radix(&s[char_index .. char_index + 2], 16) {
Ok(b) => b,
_ => { return Err(SHA1ParseError::InvalidHexadecimal); },
};
}
Ok(ret)
}
}
impl Display for SHA1 {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
for b in &self.bytes {
match write!(f, "{:02x}", b) {
Ok (()) => { },
err => { return err; }
};
}
Ok(())
}
}
impl Default for SHA1 {
fn default() -> SHA1 { SHA1{bytes: [0; 20]} }
}
/// Expresses an edge between `HistoryNodes` in a `HistoryTree`
pub type Link<T> = Rc<RefCell<T>>;
/// A change in a file through Git history
pub struct HistoryNode<T> {
/// A callback is issued for each delta, allowing the user to store
/// whatever info they want about the change.
/// This is an `Option` for the sake of filtering---we can't omit the node
/// entirely (or the processing that generated it), as we could screw up
/// the history graph. Instead, we make the contents `None` for all nodes
/// from a filtered-out commit.
pub data: Option<Rc<T>>,
/// What's the previous change?
pub previous: Option<Link<HistoryNode<T>>>,
}
/// For each key in the map, the value is a branch of a tree
/// (i.e. a linked list) of all changes.
/// This extends past name changes
pub type HistoryTree<T> = HashMap<String, Link<HistoryNode<T>>>;