thin-fetch 0.1.0

Low-level Git crate to fetch objects with high granularity
Documentation
use std::{collections::HashMap, str::FromStr};

use crate::{Error, WithError as _};

#[derive(Debug, Clone)]
pub struct Reference {
    pub hash: String,
    pub name: String,
    pub peeled: Option<String>,
    pub symref_target: Option<String>,
}

impl Reference {
    #[must_use]
    pub fn target(&self) -> &str {
        if let Some(ref peeled) = self.peeled {
            peeled
        } else {
            &self.hash
        }
    }
}

impl FromStr for Reference {
    type Err = Error;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let mut parts = s.trim_end().split(' ');

        let hash = parts.next().with_err_msg("hash not found")?;
        let name = parts.next().with_err_msg("name not found")?;

        let mut res = Self {
            hash: hash.to_owned(),
            name: name.to_owned(),
            peeled: None,
            symref_target: None,
        };

        let mut args = parts
            .filter_map(|arg| arg.split_once(':'))
            .collect::<HashMap<&str, &str>>();

        if let Some(peeled) = args.remove("peeled") {
            res.peeled.replace(peeled.to_owned());
        }

        if let Some(value) = args.remove("symref-target") {
            res.symref_target.replace(value.to_owned());
        }

        assert!(args.is_empty(), "unparsed args: {args:?}");

        Ok(res)
    }
}