pub struct Commit<'a> { /* private fields */ }
Expand description

A commit as stored in a File.

Implementations§

Returns the committer timestamp of this commit.

The value is the number of seconds since 1970-01-01 00:00:00 UTC.

Returns the generation number of this commit.

Commits without parents have generation number 1. Commits with parents have a generation number that is the max of their parents’ generation numbers + 1.

Examples found in repository?
src/file/commit.rs (line 113)
107
108
109
110
111
112
113
114
115
116
117
118
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        write!(
            f,
            "Commit {{ id: {}, lex_pos: {}, generation: {}, root_tree_id: {}, parent1: {:?}, parent2: {:?} }}",
            self.id(),
            self.pos,
            self.generation(),
            self.root_tree_id(),
            self.parent1,
            self.parent2,
        )
    }
More examples
Hide additional examples
src/file/verify.rs (line 115)
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
    pub fn traverse<'a, E, Processor>(&'a self, mut processor: Processor) -> Result<Outcome, Error<E>>
    where
        E: std::error::Error + 'static,
        Processor: FnMut(&file::Commit<'a>) -> Result<(), E>,
    {
        self.verify_checksum()
            .map_err(|(actual, expected)| Error::Mismatch { actual, expected })?;
        verify_split_chain_filename_hash(&self.path, self.checksum()).map_err(Error::Filename)?;

        let null_id = self.object_hash().null_ref();

        let mut stats = Outcome {
            max_generation: 0,
            max_parents: 0,
            min_generation: GENERATION_NUMBER_INFINITY,
            num_commits: self.num_commits(),
            parent_counts: HashMap::new(),
        };

        // TODO: Verify self.fan values as we go.
        let mut prev_id: &git_hash::oid = null_id;
        for commit in self.iter_commits() {
            if commit.id() <= prev_id {
                if commit.id() == null_id {
                    return Err(Error::CommitId {
                        pos: commit.position(),
                        id: commit.id().into(),
                    });
                }
                return Err(Error::CommitsOutOfOrder {
                    pos: commit.position(),
                    id: commit.id().into(),
                    predecessor_id: prev_id.into(),
                });
            }
            if commit.root_tree_id() == null_id {
                return Err(Error::RootTreeId {
                    id: commit.id().into(),
                    root_tree_id: commit.root_tree_id().into(),
                });
            }
            if commit.generation() > GENERATION_NUMBER_MAX {
                return Err(Error::Generation {
                    generation: commit.generation(),
                    id: commit.id().into(),
                });
            }

            processor(&commit).map_err(Error::Processor)?;

            stats.max_generation = max(stats.max_generation, commit.generation());
            stats.min_generation = min(stats.min_generation, commit.generation());
            let parent_count = commit
                .iter_parents()
                .try_fold(0u32, |acc, pos| pos.map(|_| acc + 1))
                .map_err(Error::Commit)?;
            *stats.parent_counts.entry(parent_count).or_insert(0) += 1;
            prev_id = commit.id();
        }

        if stats.min_generation == GENERATION_NUMBER_INFINITY {
            stats.min_generation = 0;
        }

        Ok(stats)
    }
src/graph/verify.rs (line 144)
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
    pub fn verify_integrity<E>(
        &self,
        mut processor: impl FnMut(&file::Commit<'_>) -> Result<(), E>,
    ) -> Result<Outcome, Error<E>>
    where
        E: std::error::Error + 'static,
    {
        if self.files.len() > 256 {
            // A file in a split chain can only have up to 255 base files.
            return Err(Error::TooManyFiles(self.files.len()));
        }

        let mut stats = Outcome {
            longest_path_length: None,
            num_commits: 0,
            parent_counts: BTreeMap::new(),
        };
        let mut max_generation = 0u32;

        // TODO: Detect duplicate commit IDs across different files. Not sure how to do this without
        //   a separate loop, e.g. self.iter_sorted_ids().

        let mut file_start_pos = graph::Position(0);
        for (file_index, file) in self.files.iter().enumerate() {
            if usize::from(file.base_graph_count()) != file_index {
                return Err(Error::BaseGraphCount {
                    actual: file.base_graph_count(),
                    expected: file_index
                        .try_into()
                        .expect("files.len() check to protect against this"),
                    path: file.path().to_owned(),
                });
            }

            for (base_graph_index, (expected, actual)) in self.files[..file_index]
                .iter()
                .map(|base_file| base_file.checksum())
                .zip(file.iter_base_graph_ids())
                .enumerate()
            {
                if actual != expected {
                    return Err(Error::BaseGraphId {
                        actual: actual.into(),
                        expected: expected.into(),
                        index: base_graph_index
                            .try_into()
                            .expect("files.len() check to protect against this"),
                        path: file.path().to_owned(),
                    });
                }
            }

            let next_file_start_pos = graph::Position(file_start_pos.0 + file.num_commits());
            let file_stats = file
                .traverse(|commit| {
                    let mut max_parent_generation = 0u32;
                    for parent_pos in commit.iter_parents() {
                        let parent_pos = parent_pos.map_err(Error::Commit)?;
                        if parent_pos >= next_file_start_pos {
                            return Err(Error::ParentOutOfRange {
                                parent_pos,
                                id: commit.id().into(),
                                max_valid_pos: graph::Position(next_file_start_pos.0 - 1),
                            });
                        }
                        let parent = self.commit_at(parent_pos);
                        max_parent_generation = max(max_parent_generation, parent.generation());
                    }

                    // If the max parent generation is GENERATION_NUMBER_MAX, then this commit's
                    // generation should be GENERATION_NUMBER_MAX too.
                    let expected_generation = min(max_parent_generation + 1, GENERATION_NUMBER_MAX);
                    if commit.generation() != expected_generation {
                        return Err(Error::Generation {
                            actual: commit.generation(),
                            expected: expected_generation,
                            id: commit.id().into(),
                        });
                    }

                    processor(commit).map_err(Error::Processor)?;

                    Ok(())
                })
                .map_err(|err| Error::File {
                    err: match err {
                        file::verify::Error::Processor(e) => return e,
                        file::verify::Error::RootTreeId { id, root_tree_id } => {
                            file::verify::Error::RootTreeId { id, root_tree_id }
                        }
                        file::verify::Error::Mismatch { actual, expected } => {
                            file::verify::Error::Mismatch { actual, expected }
                        }
                        file::verify::Error::Generation { generation, id } => {
                            file::verify::Error::Generation { generation, id }
                        }
                        file::verify::Error::Filename(expected) => file::verify::Error::Filename(expected),
                        file::verify::Error::Commit(err) => file::verify::Error::Commit(err),
                        file::verify::Error::CommitId { id, pos } => file::verify::Error::CommitId { id, pos },
                        file::verify::Error::CommitsOutOfOrder {
                            id,
                            pos,
                            predecessor_id,
                        } => file::verify::Error::CommitsOutOfOrder {
                            id,
                            pos,
                            predecessor_id,
                        },
                    },
                    path: file.path().to_owned(),
                })?;

            max_generation = max(max_generation, file_stats.max_generation);
            stats.num_commits += file_stats.num_commits;
            for (key, value) in file_stats.parent_counts.into_iter() {
                *stats.parent_counts.entry(key).or_insert(0) += value;
            }
            file_start_pos = next_file_start_pos;
        }

        stats.longest_path_length = if max_generation < GENERATION_NUMBER_MAX {
            Some(max_generation.saturating_sub(1))
        } else {
            None
        };
        Ok(stats)
    }

Returns an iterator over the parent positions for lookup in the owning Graph.

Examples found in repository?
src/file/commit.rs (line 92)
91
92
93
    pub fn parent1(&self) -> Result<Option<graph::Position>, Error> {
        self.iter_parents().next().transpose()
    }
More examples
Hide additional examples
src/file/verify.rs (line 127)
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
    pub fn traverse<'a, E, Processor>(&'a self, mut processor: Processor) -> Result<Outcome, Error<E>>
    where
        E: std::error::Error + 'static,
        Processor: FnMut(&file::Commit<'a>) -> Result<(), E>,
    {
        self.verify_checksum()
            .map_err(|(actual, expected)| Error::Mismatch { actual, expected })?;
        verify_split_chain_filename_hash(&self.path, self.checksum()).map_err(Error::Filename)?;

        let null_id = self.object_hash().null_ref();

        let mut stats = Outcome {
            max_generation: 0,
            max_parents: 0,
            min_generation: GENERATION_NUMBER_INFINITY,
            num_commits: self.num_commits(),
            parent_counts: HashMap::new(),
        };

        // TODO: Verify self.fan values as we go.
        let mut prev_id: &git_hash::oid = null_id;
        for commit in self.iter_commits() {
            if commit.id() <= prev_id {
                if commit.id() == null_id {
                    return Err(Error::CommitId {
                        pos: commit.position(),
                        id: commit.id().into(),
                    });
                }
                return Err(Error::CommitsOutOfOrder {
                    pos: commit.position(),
                    id: commit.id().into(),
                    predecessor_id: prev_id.into(),
                });
            }
            if commit.root_tree_id() == null_id {
                return Err(Error::RootTreeId {
                    id: commit.id().into(),
                    root_tree_id: commit.root_tree_id().into(),
                });
            }
            if commit.generation() > GENERATION_NUMBER_MAX {
                return Err(Error::Generation {
                    generation: commit.generation(),
                    id: commit.id().into(),
                });
            }

            processor(&commit).map_err(Error::Processor)?;

            stats.max_generation = max(stats.max_generation, commit.generation());
            stats.min_generation = min(stats.min_generation, commit.generation());
            let parent_count = commit
                .iter_parents()
                .try_fold(0u32, |acc, pos| pos.map(|_| acc + 1))
                .map_err(Error::Commit)?;
            *stats.parent_counts.entry(parent_count).or_insert(0) += 1;
            prev_id = commit.id();
        }

        if stats.min_generation == GENERATION_NUMBER_INFINITY {
            stats.min_generation = 0;
        }

        Ok(stats)
    }
src/graph/verify.rs (line 134)
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
    pub fn verify_integrity<E>(
        &self,
        mut processor: impl FnMut(&file::Commit<'_>) -> Result<(), E>,
    ) -> Result<Outcome, Error<E>>
    where
        E: std::error::Error + 'static,
    {
        if self.files.len() > 256 {
            // A file in a split chain can only have up to 255 base files.
            return Err(Error::TooManyFiles(self.files.len()));
        }

        let mut stats = Outcome {
            longest_path_length: None,
            num_commits: 0,
            parent_counts: BTreeMap::new(),
        };
        let mut max_generation = 0u32;

        // TODO: Detect duplicate commit IDs across different files. Not sure how to do this without
        //   a separate loop, e.g. self.iter_sorted_ids().

        let mut file_start_pos = graph::Position(0);
        for (file_index, file) in self.files.iter().enumerate() {
            if usize::from(file.base_graph_count()) != file_index {
                return Err(Error::BaseGraphCount {
                    actual: file.base_graph_count(),
                    expected: file_index
                        .try_into()
                        .expect("files.len() check to protect against this"),
                    path: file.path().to_owned(),
                });
            }

            for (base_graph_index, (expected, actual)) in self.files[..file_index]
                .iter()
                .map(|base_file| base_file.checksum())
                .zip(file.iter_base_graph_ids())
                .enumerate()
            {
                if actual != expected {
                    return Err(Error::BaseGraphId {
                        actual: actual.into(),
                        expected: expected.into(),
                        index: base_graph_index
                            .try_into()
                            .expect("files.len() check to protect against this"),
                        path: file.path().to_owned(),
                    });
                }
            }

            let next_file_start_pos = graph::Position(file_start_pos.0 + file.num_commits());
            let file_stats = file
                .traverse(|commit| {
                    let mut max_parent_generation = 0u32;
                    for parent_pos in commit.iter_parents() {
                        let parent_pos = parent_pos.map_err(Error::Commit)?;
                        if parent_pos >= next_file_start_pos {
                            return Err(Error::ParentOutOfRange {
                                parent_pos,
                                id: commit.id().into(),
                                max_valid_pos: graph::Position(next_file_start_pos.0 - 1),
                            });
                        }
                        let parent = self.commit_at(parent_pos);
                        max_parent_generation = max(max_parent_generation, parent.generation());
                    }

                    // If the max parent generation is GENERATION_NUMBER_MAX, then this commit's
                    // generation should be GENERATION_NUMBER_MAX too.
                    let expected_generation = min(max_parent_generation + 1, GENERATION_NUMBER_MAX);
                    if commit.generation() != expected_generation {
                        return Err(Error::Generation {
                            actual: commit.generation(),
                            expected: expected_generation,
                            id: commit.id().into(),
                        });
                    }

                    processor(commit).map_err(Error::Processor)?;

                    Ok(())
                })
                .map_err(|err| Error::File {
                    err: match err {
                        file::verify::Error::Processor(e) => return e,
                        file::verify::Error::RootTreeId { id, root_tree_id } => {
                            file::verify::Error::RootTreeId { id, root_tree_id }
                        }
                        file::verify::Error::Mismatch { actual, expected } => {
                            file::verify::Error::Mismatch { actual, expected }
                        }
                        file::verify::Error::Generation { generation, id } => {
                            file::verify::Error::Generation { generation, id }
                        }
                        file::verify::Error::Filename(expected) => file::verify::Error::Filename(expected),
                        file::verify::Error::Commit(err) => file::verify::Error::Commit(err),
                        file::verify::Error::CommitId { id, pos } => file::verify::Error::CommitId { id, pos },
                        file::verify::Error::CommitsOutOfOrder {
                            id,
                            pos,
                            predecessor_id,
                        } => file::verify::Error::CommitsOutOfOrder {
                            id,
                            pos,
                            predecessor_id,
                        },
                    },
                    path: file.path().to_owned(),
                })?;

            max_generation = max(max_generation, file_stats.max_generation);
            stats.num_commits += file_stats.num_commits;
            for (key, value) in file_stats.parent_counts.into_iter() {
                *stats.parent_counts.entry(key).or_insert(0) += value;
            }
            file_start_pos = next_file_start_pos;
        }

        stats.longest_path_length = if max_generation < GENERATION_NUMBER_MAX {
            Some(max_generation.saturating_sub(1))
        } else {
            None
        };
        Ok(stats)
    }

Returns the hash of this commit.

Examples found in repository?
src/file/commit.rs (line 111)
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
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        write!(
            f,
            "Commit {{ id: {}, lex_pos: {}, generation: {}, root_tree_id: {}, parent1: {:?}, parent2: {:?} }}",
            self.id(),
            self.pos,
            self.generation(),
            self.root_tree_id(),
            self.parent1,
            self.parent2,
        )
    }
}

impl<'a> Eq for Commit<'a> {}

impl<'a> PartialEq for Commit<'a> {
    fn eq(&self, other: &Self) -> bool {
        std::ptr::eq(self.file, other.file) && self.pos == other.pos
    }
}

/// An iterator over parents of a [`Commit`].
pub struct ParentIterator<'a> {
    commit_data: &'a Commit<'a>,
    state: ParentIteratorState<'a>,
}

impl<'a> Iterator for ParentIterator<'a> {
    type Item = Result<graph::Position, Error>;

    fn next(&mut self) -> Option<Self::Item> {
        let state = std::mem::replace(&mut self.state, ParentIteratorState::Exhausted);
        match state {
            ParentIteratorState::First => match self.commit_data.parent1 {
                ParentEdge::None => match self.commit_data.parent2 {
                    ParentEdge::None => None,
                    _ => Some(Err(Error::SecondParentWithoutFirstParent(self.commit_data.id().into()))),
                },
                ParentEdge::GraphPosition(pos) => {
                    self.state = ParentIteratorState::Second;
                    Some(Ok(pos))
                }
                ParentEdge::ExtraEdgeIndex(_) => {
                    Some(Err(Error::FirstParentIsExtraEdgeIndex(self.commit_data.id().into())))
                }
            },
            ParentIteratorState::Second => match self.commit_data.parent2 {
                ParentEdge::None => None,
                ParentEdge::GraphPosition(pos) => Some(Ok(pos)),
                ParentEdge::ExtraEdgeIndex(extra_edge_index) => {
                    if let Some(extra_edges_list) = self.commit_data.file.extra_edges_data() {
                        let start_offset: usize = extra_edge_index
                            .try_into()
                            .expect("an architecture able to hold 32 bits of integer");
                        let start_offset = start_offset
                            .checked_mul(4)
                            .expect("an extended edge index small enough to fit in usize");
                        if let Some(tail) = extra_edges_list.get(start_offset..) {
                            self.state = ParentIteratorState::Extra(tail.chunks(4));
                            // This recursive call is what blocks me from replacing ParentIterator
                            // with a std::iter::from_fn closure.
                            self.next()
                        } else {
                            Some(Err(Error::ExtraEdgesListOverflow(self.commit_data.id().into())))
                        }
                    } else {
                        Some(Err(Error::MissingExtraEdgesList(self.commit_data.id().into())))
                    }
                }
            },
            ParentIteratorState::Extra(mut chunks) => {
                if let Some(chunk) = chunks.next() {
                    let extra_edge = read_u32(chunk);
                    match ExtraEdge::from_raw(extra_edge) {
                        ExtraEdge::Internal(pos) => {
                            self.state = ParentIteratorState::Extra(chunks);
                            Some(Ok(pos))
                        }
                        ExtraEdge::Last(pos) => Some(Ok(pos)),
                    }
                } else {
                    Some(Err(Error::ExtraEdgesListOverflow(self.commit_data.id().into())))
                }
            }
            ParentIteratorState::Exhausted => None,
        }
    }
More examples
Hide additional examples
src/file/verify.rs (line 96)
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
    pub fn traverse<'a, E, Processor>(&'a self, mut processor: Processor) -> Result<Outcome, Error<E>>
    where
        E: std::error::Error + 'static,
        Processor: FnMut(&file::Commit<'a>) -> Result<(), E>,
    {
        self.verify_checksum()
            .map_err(|(actual, expected)| Error::Mismatch { actual, expected })?;
        verify_split_chain_filename_hash(&self.path, self.checksum()).map_err(Error::Filename)?;

        let null_id = self.object_hash().null_ref();

        let mut stats = Outcome {
            max_generation: 0,
            max_parents: 0,
            min_generation: GENERATION_NUMBER_INFINITY,
            num_commits: self.num_commits(),
            parent_counts: HashMap::new(),
        };

        // TODO: Verify self.fan values as we go.
        let mut prev_id: &git_hash::oid = null_id;
        for commit in self.iter_commits() {
            if commit.id() <= prev_id {
                if commit.id() == null_id {
                    return Err(Error::CommitId {
                        pos: commit.position(),
                        id: commit.id().into(),
                    });
                }
                return Err(Error::CommitsOutOfOrder {
                    pos: commit.position(),
                    id: commit.id().into(),
                    predecessor_id: prev_id.into(),
                });
            }
            if commit.root_tree_id() == null_id {
                return Err(Error::RootTreeId {
                    id: commit.id().into(),
                    root_tree_id: commit.root_tree_id().into(),
                });
            }
            if commit.generation() > GENERATION_NUMBER_MAX {
                return Err(Error::Generation {
                    generation: commit.generation(),
                    id: commit.id().into(),
                });
            }

            processor(&commit).map_err(Error::Processor)?;

            stats.max_generation = max(stats.max_generation, commit.generation());
            stats.min_generation = min(stats.min_generation, commit.generation());
            let parent_count = commit
                .iter_parents()
                .try_fold(0u32, |acc, pos| pos.map(|_| acc + 1))
                .map_err(Error::Commit)?;
            *stats.parent_counts.entry(parent_count).or_insert(0) += 1;
            prev_id = commit.id();
        }

        if stats.min_generation == GENERATION_NUMBER_INFINITY {
            stats.min_generation = 0;
        }

        Ok(stats)
    }
src/graph/verify.rs (line 139)
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
    pub fn verify_integrity<E>(
        &self,
        mut processor: impl FnMut(&file::Commit<'_>) -> Result<(), E>,
    ) -> Result<Outcome, Error<E>>
    where
        E: std::error::Error + 'static,
    {
        if self.files.len() > 256 {
            // A file in a split chain can only have up to 255 base files.
            return Err(Error::TooManyFiles(self.files.len()));
        }

        let mut stats = Outcome {
            longest_path_length: None,
            num_commits: 0,
            parent_counts: BTreeMap::new(),
        };
        let mut max_generation = 0u32;

        // TODO: Detect duplicate commit IDs across different files. Not sure how to do this without
        //   a separate loop, e.g. self.iter_sorted_ids().

        let mut file_start_pos = graph::Position(0);
        for (file_index, file) in self.files.iter().enumerate() {
            if usize::from(file.base_graph_count()) != file_index {
                return Err(Error::BaseGraphCount {
                    actual: file.base_graph_count(),
                    expected: file_index
                        .try_into()
                        .expect("files.len() check to protect against this"),
                    path: file.path().to_owned(),
                });
            }

            for (base_graph_index, (expected, actual)) in self.files[..file_index]
                .iter()
                .map(|base_file| base_file.checksum())
                .zip(file.iter_base_graph_ids())
                .enumerate()
            {
                if actual != expected {
                    return Err(Error::BaseGraphId {
                        actual: actual.into(),
                        expected: expected.into(),
                        index: base_graph_index
                            .try_into()
                            .expect("files.len() check to protect against this"),
                        path: file.path().to_owned(),
                    });
                }
            }

            let next_file_start_pos = graph::Position(file_start_pos.0 + file.num_commits());
            let file_stats = file
                .traverse(|commit| {
                    let mut max_parent_generation = 0u32;
                    for parent_pos in commit.iter_parents() {
                        let parent_pos = parent_pos.map_err(Error::Commit)?;
                        if parent_pos >= next_file_start_pos {
                            return Err(Error::ParentOutOfRange {
                                parent_pos,
                                id: commit.id().into(),
                                max_valid_pos: graph::Position(next_file_start_pos.0 - 1),
                            });
                        }
                        let parent = self.commit_at(parent_pos);
                        max_parent_generation = max(max_parent_generation, parent.generation());
                    }

                    // If the max parent generation is GENERATION_NUMBER_MAX, then this commit's
                    // generation should be GENERATION_NUMBER_MAX too.
                    let expected_generation = min(max_parent_generation + 1, GENERATION_NUMBER_MAX);
                    if commit.generation() != expected_generation {
                        return Err(Error::Generation {
                            actual: commit.generation(),
                            expected: expected_generation,
                            id: commit.id().into(),
                        });
                    }

                    processor(commit).map_err(Error::Processor)?;

                    Ok(())
                })
                .map_err(|err| Error::File {
                    err: match err {
                        file::verify::Error::Processor(e) => return e,
                        file::verify::Error::RootTreeId { id, root_tree_id } => {
                            file::verify::Error::RootTreeId { id, root_tree_id }
                        }
                        file::verify::Error::Mismatch { actual, expected } => {
                            file::verify::Error::Mismatch { actual, expected }
                        }
                        file::verify::Error::Generation { generation, id } => {
                            file::verify::Error::Generation { generation, id }
                        }
                        file::verify::Error::Filename(expected) => file::verify::Error::Filename(expected),
                        file::verify::Error::Commit(err) => file::verify::Error::Commit(err),
                        file::verify::Error::CommitId { id, pos } => file::verify::Error::CommitId { id, pos },
                        file::verify::Error::CommitsOutOfOrder {
                            id,
                            pos,
                            predecessor_id,
                        } => file::verify::Error::CommitsOutOfOrder {
                            id,
                            pos,
                            predecessor_id,
                        },
                    },
                    path: file.path().to_owned(),
                })?;

            max_generation = max(max_generation, file_stats.max_generation);
            stats.num_commits += file_stats.num_commits;
            for (key, value) in file_stats.parent_counts.into_iter() {
                *stats.parent_counts.entry(key).or_insert(0) += value;
            }
            file_start_pos = next_file_start_pos;
        }

        stats.longest_path_length = if max_generation < GENERATION_NUMBER_MAX {
            Some(max_generation.saturating_sub(1))
        } else {
            None
        };
        Ok(stats)
    }

Returns the first parent of this commit.

Returns the position at which this commit is stored in the parent File.

Examples found in repository?
src/file/verify.rs (line 99)
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
    pub fn traverse<'a, E, Processor>(&'a self, mut processor: Processor) -> Result<Outcome, Error<E>>
    where
        E: std::error::Error + 'static,
        Processor: FnMut(&file::Commit<'a>) -> Result<(), E>,
    {
        self.verify_checksum()
            .map_err(|(actual, expected)| Error::Mismatch { actual, expected })?;
        verify_split_chain_filename_hash(&self.path, self.checksum()).map_err(Error::Filename)?;

        let null_id = self.object_hash().null_ref();

        let mut stats = Outcome {
            max_generation: 0,
            max_parents: 0,
            min_generation: GENERATION_NUMBER_INFINITY,
            num_commits: self.num_commits(),
            parent_counts: HashMap::new(),
        };

        // TODO: Verify self.fan values as we go.
        let mut prev_id: &git_hash::oid = null_id;
        for commit in self.iter_commits() {
            if commit.id() <= prev_id {
                if commit.id() == null_id {
                    return Err(Error::CommitId {
                        pos: commit.position(),
                        id: commit.id().into(),
                    });
                }
                return Err(Error::CommitsOutOfOrder {
                    pos: commit.position(),
                    id: commit.id().into(),
                    predecessor_id: prev_id.into(),
                });
            }
            if commit.root_tree_id() == null_id {
                return Err(Error::RootTreeId {
                    id: commit.id().into(),
                    root_tree_id: commit.root_tree_id().into(),
                });
            }
            if commit.generation() > GENERATION_NUMBER_MAX {
                return Err(Error::Generation {
                    generation: commit.generation(),
                    id: commit.id().into(),
                });
            }

            processor(&commit).map_err(Error::Processor)?;

            stats.max_generation = max(stats.max_generation, commit.generation());
            stats.min_generation = min(stats.min_generation, commit.generation());
            let parent_count = commit
                .iter_parents()
                .try_fold(0u32, |acc, pos| pos.map(|_| acc + 1))
                .map_err(Error::Commit)?;
            *stats.parent_counts.entry(parent_count).or_insert(0) += 1;
            prev_id = commit.id();
        }

        if stats.min_generation == GENERATION_NUMBER_INFINITY {
            stats.min_generation = 0;
        }

        Ok(stats)
    }

Return the hash of the tree this commit points to.

Examples found in repository?
src/file/commit.rs (line 114)
107
108
109
110
111
112
113
114
115
116
117
118
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        write!(
            f,
            "Commit {{ id: {}, lex_pos: {}, generation: {}, root_tree_id: {}, parent1: {:?}, parent2: {:?} }}",
            self.id(),
            self.pos,
            self.generation(),
            self.root_tree_id(),
            self.parent1,
            self.parent2,
        )
    }
More examples
Hide additional examples
src/file/verify.rs (line 109)
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
    pub fn traverse<'a, E, Processor>(&'a self, mut processor: Processor) -> Result<Outcome, Error<E>>
    where
        E: std::error::Error + 'static,
        Processor: FnMut(&file::Commit<'a>) -> Result<(), E>,
    {
        self.verify_checksum()
            .map_err(|(actual, expected)| Error::Mismatch { actual, expected })?;
        verify_split_chain_filename_hash(&self.path, self.checksum()).map_err(Error::Filename)?;

        let null_id = self.object_hash().null_ref();

        let mut stats = Outcome {
            max_generation: 0,
            max_parents: 0,
            min_generation: GENERATION_NUMBER_INFINITY,
            num_commits: self.num_commits(),
            parent_counts: HashMap::new(),
        };

        // TODO: Verify self.fan values as we go.
        let mut prev_id: &git_hash::oid = null_id;
        for commit in self.iter_commits() {
            if commit.id() <= prev_id {
                if commit.id() == null_id {
                    return Err(Error::CommitId {
                        pos: commit.position(),
                        id: commit.id().into(),
                    });
                }
                return Err(Error::CommitsOutOfOrder {
                    pos: commit.position(),
                    id: commit.id().into(),
                    predecessor_id: prev_id.into(),
                });
            }
            if commit.root_tree_id() == null_id {
                return Err(Error::RootTreeId {
                    id: commit.id().into(),
                    root_tree_id: commit.root_tree_id().into(),
                });
            }
            if commit.generation() > GENERATION_NUMBER_MAX {
                return Err(Error::Generation {
                    generation: commit.generation(),
                    id: commit.id().into(),
                });
            }

            processor(&commit).map_err(Error::Processor)?;

            stats.max_generation = max(stats.max_generation, commit.generation());
            stats.min_generation = min(stats.min_generation, commit.generation());
            let parent_count = commit
                .iter_parents()
                .try_fold(0u32, |acc, pos| pos.map(|_| acc + 1))
                .map_err(Error::Commit)?;
            *stats.parent_counts.entry(parent_count).or_insert(0) += 1;
            prev_id = commit.id();
        }

        if stats.min_generation == GENERATION_NUMBER_INFINITY {
            stats.min_generation = 0;
        }

        Ok(stats)
    }

Trait Implementations§

Formats the value using the given formatter. Read more
This method tests for self and other values to be equal, and is used by ==.
This method tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.

Auto Trait Implementations§

Blanket Implementations§

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more

Returns the argument unchanged.

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.