jj_lib/default_index/
entry.rs

1// Copyright 2023 The Jujutsu Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#![allow(missing_docs)]
16
17use std::fmt::Debug;
18use std::fmt::Formatter;
19use std::hash::Hash;
20use std::hash::Hasher;
21
22use smallvec::SmallVec;
23
24use super::composite::CompositeIndex;
25use super::composite::DynIndexSegment;
26use crate::backend::ChangeId;
27use crate::backend::CommitId;
28use crate::object_id::ObjectId as _;
29
30/// Global index position.
31#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)]
32pub struct IndexPosition(pub(super) u32);
33
34impl IndexPosition {
35    pub const MIN: Self = IndexPosition(u32::MIN);
36    pub const MAX: Self = IndexPosition(u32::MAX);
37}
38
39/// Local position within an index segment.
40#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)]
41pub(super) struct LocalPosition(pub(super) u32);
42
43// SmallVec reuses two pointer-size fields as inline area, which meas we can
44// inline up to 16 bytes (on 64-bit platform) for free.
45pub(super) type SmallIndexPositionsVec = SmallVec<[IndexPosition; 4]>;
46pub(super) type SmallLocalPositionsVec = SmallVec<[LocalPosition; 4]>;
47
48#[derive(Clone)]
49pub struct IndexEntry<'a> {
50    source: &'a DynIndexSegment,
51    pos: IndexPosition,
52    /// Position within the source segment
53    local_pos: LocalPosition,
54}
55
56impl Debug for IndexEntry<'_> {
57    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
58        f.debug_struct("IndexEntry")
59            .field("pos", &self.pos)
60            .field("local_pos", &self.local_pos)
61            .field("commit_id", &self.commit_id().hex())
62            .finish()
63    }
64}
65
66impl PartialEq for IndexEntry<'_> {
67    fn eq(&self, other: &Self) -> bool {
68        self.pos == other.pos
69    }
70}
71
72impl Eq for IndexEntry<'_> {}
73
74impl Hash for IndexEntry<'_> {
75    fn hash<H: Hasher>(&self, state: &mut H) {
76        self.pos.hash(state);
77    }
78}
79
80impl<'a> IndexEntry<'a> {
81    pub(super) fn new(
82        source: &'a DynIndexSegment,
83        pos: IndexPosition,
84        local_pos: LocalPosition,
85    ) -> Self {
86        IndexEntry {
87            source,
88            pos,
89            local_pos,
90        }
91    }
92
93    pub fn position(&self) -> IndexPosition {
94        self.pos
95    }
96
97    pub fn generation_number(&self) -> u32 {
98        self.source.generation_number(self.local_pos)
99    }
100
101    pub fn commit_id(&self) -> CommitId {
102        self.source.commit_id(self.local_pos)
103    }
104
105    pub fn change_id(&self) -> ChangeId {
106        self.source.change_id(self.local_pos)
107    }
108
109    pub fn num_parents(&self) -> u32 {
110        self.source.num_parents(self.local_pos)
111    }
112
113    pub fn parent_positions(&self) -> SmallIndexPositionsVec {
114        self.source.parent_positions(self.local_pos)
115    }
116
117    pub fn parents(&self) -> impl ExactSizeIterator<Item = IndexEntry<'a>> + use<'a> {
118        let composite = CompositeIndex::new(self.source);
119        self.parent_positions()
120            .into_iter()
121            .map(move |pos| composite.entry_by_pos(pos))
122    }
123}