Skip to main content

gix_object/
encode.rs

1//! Encoding utilities
2use std::io::{self, Write};
3
4use bstr::ByteSlice;
5
6macro_rules! check {
7    ($e: expr) => {
8        $e.expect("Writing to a Vec should never fail.")
9    };
10}
11/// Generates a loose header buffer
12pub fn loose_header(kind: crate::Kind, size: u64) -> smallvec::SmallVec<[u8; 28]> {
13    let mut v = smallvec::SmallVec::new();
14    check!(v.write_all(kind.as_bytes()));
15    check!(v.write_all(SPACE));
16    check!(v.write_all(itoa::Buffer::new().format(size).as_bytes()));
17    check!(v.write_all(b"\0"));
18    v
19}
20
21pub(crate) fn header_field_multi_line(name: &[u8], value: &[u8], out: &mut dyn io::Write) -> io::Result<()> {
22    let mut lines = value.as_bstr().lines_with_terminator();
23    out.write_all(name)?;
24    out.write_all(SPACE)?;
25    if let Some(line) = lines.next() {
26        out.write_all(line)?;
27    }
28    for line in lines {
29        out.write_all(SPACE)?;
30        out.write_all(line)?;
31    }
32    if !value.ends_with_str(b"\n") {
33        out.write_all(NL)?;
34    }
35    Ok(())
36}
37
38pub(crate) fn trusted_header_field(name: &[u8], value: &[u8], out: &mut dyn io::Write) -> io::Result<()> {
39    out.write_all(name)?;
40    out.write_all(SPACE)?;
41    out.write_all(value)?;
42    out.write_all(NL)
43}
44
45pub(crate) fn trusted_header_signature(
46    name: &[u8],
47    value: &gix_actor::SignatureRef<'_>,
48    out: &mut dyn io::Write,
49) -> io::Result<()> {
50    out.write_all(name)?;
51    out.write_all(SPACE)?;
52    value.write_to(out)?;
53    out.write_all(NL)
54}
55
56pub(crate) fn trusted_header_id(
57    name: &[u8],
58    value: &gix_hash::ObjectId,
59    mut out: &mut dyn io::Write,
60) -> io::Result<()> {
61    out.write_all(name)?;
62    out.write_all(SPACE)?;
63    value.write_hex_to(&mut out)?;
64    out.write_all(NL)
65}
66
67/// Serialize a header field. Values containing newlines are retained as `input` bytes in the I/O error.
68/// After [wrapping](gix_error::Error::from_error()), inspect them with [metadata](gix_error::Error::metadata()).
69pub(crate) fn header_field(name: &[u8], value: &[u8], out: &mut dyn io::Write) -> io::Result<()> {
70    if value.is_empty() {
71        return Err(io::Error::other(gix_error::validation(
72            "Header values must not be empty",
73        )));
74    }
75    if value.find(NL).is_some() {
76        return Err(io::Error::other(
77            gix_error::validation("Newlines are not allowed in header values").with("input", value),
78        ));
79    }
80    trusted_header_field(name, value, out)
81}
82
83pub(crate) const NL: &[u8; 1] = b"\n";
84pub(crate) const SPACE: &[u8; 1] = b" ";