const LOOSE_OBJECT: u8 = 1 << 0;
const PACK: u8 = 1 << 1;
const PACK_METADATA: u8 = 1 << 2;
const COMMIT_GRAPH: u8 = 1 << 3;
const INDEX: u8 = 1 << 4;
const REFERENCE: u8 = 1 << 5;
const OBJECT_MAP: u8 = 1 << 6;
const OBJECTS: u8 = LOOSE_OBJECT | PACK;
const DERIVED_METADATA: u8 = PACK_METADATA | COMMIT_GRAPH;
const DEFAULT: u8 = (OBJECTS | DERIVED_METADATA) & !LOOSE_OBJECT;
const COMMITTED: u8 = OBJECTS | REFERENCE;
const ADDED: u8 = COMMITTED | INDEX;
const ALL: u8 = LOOSE_OBJECT | PACK | PACK_METADATA | COMMIT_GRAPH | INDEX | REFERENCE | OBJECT_MAP;
const WORDS: [(&str, u8); 11] = [
("loose-object", LOOSE_OBJECT),
("pack", PACK),
("pack-metadata", PACK_METADATA),
("commit-graph", COMMIT_GRAPH),
("index", INDEX),
("objects", OBJECTS),
("reference", REFERENCE),
("derived-metadata", DERIVED_METADATA),
("committed", COMMITTED),
("added", ADDED),
("all", ALL),
];
const SEPARATORS: [char; 5] = [',', ' ', '\t', '\n', '\r'];
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct FsyncComponents {
bits: u8,
}
impl FsyncComponents {
pub fn default_set() -> Self {
return Self { bits: DEFAULT };
}
pub fn parse(value: &str) -> Self {
let mut current: u8 = DEFAULT;
let (mut positive, mut negative): (u8, u8) = (0, 0);
let mut rest: &str = value;
loop {
rest = rest.trim_start_matches(SEPARATORS);
let end: usize = rest.find(',').unwrap_or(rest.len());
if rest == "none" {
current = 0;
} else {
let (negated, word): (bool, &str) = match rest[..end].strip_prefix('-') {
Some(removed) => (true, removed),
None => (false, &rest[..end]),
};
if word.is_empty() {
break;
}
for (name, bits) in WORDS {
if name.starts_with(word) {
if negated {
negative |= bits;
} else {
positive |= bits;
}
}
}
}
if end >= rest.len() {
break;
}
rest = &rest[end..];
}
return Self { bits: (current & !negative) | positive };
}
pub fn names_loose_object(self) -> bool {
return self.bits & LOOSE_OBJECT != 0;
}
pub fn names_index(self) -> bool {
return self.bits & INDEX != 0;
}
pub fn names_pack(self) -> bool {
return self.bits & (PACK | PACK_METADATA) != 0;
}
pub fn names_pack_and_metadata(self) -> bool {
return self.bits & (PACK | PACK_METADATA) == PACK | PACK_METADATA;
}
pub fn names_reference(self) -> bool {
return self.bits & REFERENCE != 0;
}
pub fn without_packs(self) -> Self {
return Self { bits: self.bits & !(PACK | PACK_METADATA) };
}
pub fn with_packs(self) -> Self {
return Self { bits: self.bits | PACK | PACK_METADATA };
}
pub fn value(self) -> String {
let mut words: Vec<&str> = Vec::new();
for (name, bits) in WORDS {
if bits.is_power_of_two() && self.bits & bits != 0 {
words.push(name);
}
}
words.push("none");
return words.join(",");
}
}
#[cfg(test)]
#[path = "config_fsync_tests.rs"]
mod tests;