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
use crate::{owned, owned::SPACE, TreeMode}; use bstr::{BString, ByteSlice}; use quick_error::quick_error; use std::io; quick_error! { #[derive(Debug)] pub enum Error { NewlineInFilename(name: BString) { display("Newlines are invalid in file paths: {:?}", name) } } } impl From<Error> for io::Error { fn from(err: Error) -> Self { io::Error::new(io::ErrorKind::Other, err) } } #[derive(PartialEq, Eq, Debug, Hash, Ord, PartialOrd, Clone)] #[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))] pub struct Tree { pub entries: Vec<Entry>, } #[derive(PartialEq, Eq, Debug, Hash, Ord, PartialOrd, Clone)] #[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))] pub struct Entry { pub mode: TreeMode, pub filename: BString, pub oid: owned::Id, } impl TreeMode { pub fn as_bytes(&self) -> &'static [u8] { use TreeMode::*; match self { Tree => b"40000", Blob => b"100644", BlobExecutable => b"100755", Link => b"120000", Commit => b"160000", } } } impl Tree { pub fn write_to(&self, mut out: impl io::Write) -> io::Result<()> { for Entry { mode, filename, oid } in &self.entries { out.write_all(mode.as_bytes())?; out.write_all(SPACE)?; if filename.find_byte(b'\n').is_some() { return Err(Error::NewlineInFilename(filename.to_owned()).into()); } out.write_all(&filename)?; out.write_all(&[b'\0'])?; out.write_all(&oid[..])?; } Ok(()) } }