#[non_exhaustive]pub struct LineRef<'a> {
pub previous_oid: &'a BStr,
pub new_oid: &'a BStr,
pub signature: SignatureRef<'a>,
pub message: &'a BStr,
}
Expand description
A parsed ref log line.
Fields (Non-exhaustive)§
This struct is marked as non-exhaustive
Non-exhaustive structs could have additional fields added in future. Therefore, non-exhaustive structs cannot be constructed in external crates using the traditional
Struct { .. }
syntax; cannot be matched against without a wildcard ..
; and struct update syntax will not work.previous_oid: &'a BStr
The previous object id in hexadecimal. Use LineRef::previous_oid()
to get a more usable form.
new_oid: &'a BStr
The new object id in hexadecimal. Use LineRef::new_oid()
to get a more usable form.
signature: SignatureRef<'a>
The signature of the currently configured committer.
message: &'a BStr
The message providing details about the operation performed in this log line.
Implementations§
source§impl<'a> LineRef<'a>
impl<'a> LineRef<'a>
sourcepub fn from_bytes(input: &'a [u8]) -> Result<LineRef<'a>, Error>
pub fn from_bytes(input: &'a [u8]) -> Result<LineRef<'a>, Error>
Decode a line from the given bytes which are expected to start at a hex sha.
Examples found in repository?
src/store/file/log/iter.rs (line 75)
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 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244
fn next(&mut self) -> Option<Self::Item> {
self.inner.next().map(|(ln, line)| {
log::LineRef::from_bytes(line).map_err(|err| decode::Error::new(err, decode::LineNumber::FromStart(ln)))
})
}
}
/// A platform to store a buffer to hold ref log lines for iteration.
#[must_use = "Iterators should be obtained from this platform"]
pub struct Platform<'a, 's> {
/// The store containing the reflogs
pub store: &'s file::Store,
/// The full name of the reference whose reflog to retrieve.
pub name: &'a FullNameRef,
/// A reusable buffer for storing log lines read from disk.
pub buf: Vec<u8>,
}
impl<'a, 's> Platform<'a, 's> {
/// Return a forward iterator over all log-lines, most recent to oldest.
pub fn rev(&mut self) -> std::io::Result<Option<log::iter::Reverse<'_, std::fs::File>>> {
self.buf.clear();
self.buf.resize(512, 0);
self.store
.reflog_iter_rev(self.name, &mut self.buf)
.map_err(must_be_io_err)
}
/// Return a forward iterator over all log-lines, oldest to most recent.
pub fn all(&mut self) -> std::io::Result<Option<log::iter::Forward<'_>>> {
self.buf.clear();
self.store.reflog_iter(self.name, &mut self.buf).map_err(must_be_io_err)
}
}
/// An iterator yielding parsed lines in a file in reverse, most recent to oldest.
pub struct Reverse<'a, F> {
buf: &'a mut [u8],
count: usize,
read_and_pos: Option<(F, u64)>,
last_nl_pos: Option<usize>,
}
/// An iterator over entries of the `log` file in reverse, using `buf` as sliding window.
///
/// Note that `buf` must be big enough to capture typical line length or else partial lines will be parsed and probably fail
/// in the process.
///
/// This iterator is very expensive in terms of I/O operations and shouldn't be used to read more than the last few entries of the log.
/// Use a forward iterator instead for these cases.
///
/// It will continue parsing even if individual log entries failed to parse, leaving it to the driver to decide whether to
/// abort or continue.
pub fn reverse<F>(mut log: F, buf: &mut [u8]) -> std::io::Result<Reverse<'_, F>>
where
F: std::io::Read + std::io::Seek,
{
let pos = log.seek(std::io::SeekFrom::End(0))?;
if buf.is_empty() {
return Err(std::io::Error::new(
std::io::ErrorKind::Other,
"Zero sized buffers are not allowed, use 256 bytes or more for typical logs",
));
}
Ok(Reverse {
buf,
count: 0,
read_and_pos: Some((log, pos)),
last_nl_pos: None,
})
}
///
pub mod reverse {
use super::decode;
/// The error returned by the [`Reverse`][super::Reverse] iterator
#[derive(Debug, thiserror::Error)]
#[allow(missing_docs)]
pub enum Error {
#[error("The buffer could not be filled to make more lines available")]
Io(#[from] std::io::Error),
#[error("Could not decode log line")]
Decode(#[from] decode::Error),
}
}
impl<'a, F> Iterator for Reverse<'a, F>
where
F: std::io::Read + std::io::Seek,
{
type Item = Result<crate::log::Line, reverse::Error>;
fn next(&mut self) -> Option<Self::Item> {
match (self.last_nl_pos.take(), self.read_and_pos.take()) {
// Initial state - load first data block
(None, Some((mut read, pos))) => {
let npos = pos.saturating_sub(self.buf.len() as u64);
if let Err(err) = read.seek(std::io::SeekFrom::Start(npos)) {
return Some(Err(err.into()));
}
let n = (pos - npos) as usize;
if n == 0 {
return None;
}
let buf = &mut self.buf[..n];
if let Err(err) = read.read_exact(buf) {
return Some(Err(err.into()));
};
let last_byte = *buf.last().expect("we have read non-zero bytes before");
self.last_nl_pos = Some(if last_byte != b'\n' { buf.len() } else { buf.len() - 1 });
self.read_and_pos = Some((read, npos));
self.next()
}
// Has data block and can extract lines from it, load new blocks as needed
(Some(end), Some(read_and_pos)) => match self.buf[..end].rfind_byte(b'\n') {
Some(start) => {
self.read_and_pos = Some(read_and_pos);
self.last_nl_pos = Some(start);
let buf = &self.buf[start + 1..end];
let res = Some(
log::LineRef::from_bytes(buf)
.map_err(|err| {
reverse::Error::Decode(decode::Error::new(err, LineNumber::FromEnd(self.count)))
})
.map(Into::into),
);
self.count += 1;
res
}
None => {
let (mut read, last_read_pos) = read_and_pos;
if last_read_pos == 0 {
let buf = &self.buf[..end];
Some(
log::LineRef::from_bytes(buf)
.map_err(|err| {
reverse::Error::Decode(decode::Error::new(err, LineNumber::FromEnd(self.count)))
})
.map(Into::into),
)
} else {
let npos = last_read_pos.saturating_sub((self.buf.len() - end) as u64);
if npos == last_read_pos {
return Some(Err(std::io::Error::new(
std::io::ErrorKind::Other,
"buffer too small for line size",
)
.into()));
}
let n = (last_read_pos - npos) as usize;
self.buf.copy_within(0..end, n);
if let Err(err) = read.seek(std::io::SeekFrom::Start(npos)) {
return Some(Err(err.into()));
}
if let Err(err) = read.read_exact(&mut self.buf[..n]) {
return Some(Err(err.into()));
}
self.read_and_pos = Some((read, npos));
self.last_nl_pos = Some(n + end);
self.next()
}
}
},
// depleted
(None, None) => None,
(Some(_), None) => unreachable!("BUG: Invalid state: we never discard only our file, always both."),
}
}
Trait Implementations§
source§impl<'de: 'a, 'a> Deserialize<'de> for LineRef<'a>
impl<'de: 'a, 'a> Deserialize<'de> for LineRef<'a>
source§fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
Deserialize this value from the given Serde deserializer. Read more
source§impl<'a> Ord for LineRef<'a>
impl<'a> Ord for LineRef<'a>
1.21.0 · source§fn max(self, other: Self) -> Selfwhere
Self: Sized,
fn max(self, other: Self) -> Selfwhere
Self: Sized,
Compares and returns the maximum of two values. Read more
source§impl<'a> PartialEq<LineRef<'a>> for LineRef<'a>
impl<'a> PartialEq<LineRef<'a>> for LineRef<'a>
source§impl<'a> PartialOrd<LineRef<'a>> for LineRef<'a>
impl<'a> PartialOrd<LineRef<'a>> for LineRef<'a>
1.0.0 · source§fn le(&self, other: &Rhs) -> bool
fn le(&self, other: &Rhs) -> bool
This method tests less than or equal to (for
self
and other
) and is used by the <=
operator. Read more