1use anyhow::{ensure, Context, Result};
7use mmap_rs::Mmap;
8
9use super::suffixes::*;
10use super::*;
11use crate::graph::NodeId;
12
13pub trait MaybePersons {}
16impl<P: OptPersons> MaybePersons for P {}
17
18#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
20pub struct NoPersons;
21impl MaybePersons for NoPersons {}
22
23#[diagnostic::on_unimplemented(
24 label = "does not have Person properties loaded",
25 note = "Use `let graph = graph.load_properties(|props| props.load_persons()).unwrap()` to load them",
26 note = "Or replace `graph.init_properties()` with `graph.load_all_properties::<DynMphf>().unwrap()` to load all properties"
27)]
28pub trait OptPersons: MaybePersons + PropertiesBackend {
30 fn author_id(&self, node: NodeId) -> PropertiesResult<'_, Option<u32>, Self>;
32 fn committer_id(&self, node: NodeId) -> PropertiesResult<'_, Option<u32>, Self>;
34 fn num_persons(&self) -> PropertiesResult<'_, usize, Self>;
36}
37
38#[diagnostic::on_unimplemented(
39 label = "does not have Person properties loaded",
40 note = "Use `let graph = graph.load_properties(|props| props.load_persons()).unwrap()` to load them",
41 note = "Or replace `graph.init_properties()` with `graph.load_all_properties::<DynMphf>().unwrap()` to load all properties"
42)]
43pub trait Persons: OptPersons<DataFilesAvailability = GuaranteedDataFiles> {}
45impl<P: OptPersons<DataFilesAvailability = GuaranteedDataFiles>> Persons for P {}
46
47pub struct OptMappedPersons {
48 author_id: Result<NumberMmap<BigEndian, u32, Mmap>, UnavailableProperty>,
49 committer_id: Result<NumberMmap<BigEndian, u32, Mmap>, UnavailableProperty>,
50 num_persons: Result<usize, UnavailableProperty>,
51}
52impl PropertiesBackend for OptMappedPersons {
53 type DataFilesAvailability = OptionalDataFiles;
54}
55impl OptPersons for OptMappedPersons {
56 #[inline(always)]
57 fn author_id(&self, node: NodeId) -> PropertiesResult<'_, Option<u32>, Self> {
58 self.author_id
59 .as_ref()
60 .map(|author_ids| author_ids.get_value(node))
61 }
62 #[inline(always)]
63 fn committer_id(&self, node: NodeId) -> PropertiesResult<'_, Option<u32>, Self> {
64 self.committer_id
65 .as_ref()
66 .map(|committer_ids| committer_ids.get_value(node))
67 }
68 #[inline(always)]
69 fn num_persons(&self) -> PropertiesResult<'_, usize, Self> {
70 self.num_persons.as_ref().copied()
71 }
72}
73
74pub struct MappedPersons {
75 author_id: NumberMmap<BigEndian, u32, Mmap>,
76 committer_id: NumberMmap<BigEndian, u32, Mmap>,
77 num_persons: usize,
78}
79impl PropertiesBackend for MappedPersons {
80 type DataFilesAvailability = GuaranteedDataFiles;
81}
82impl OptPersons for MappedPersons {
83 #[inline(always)]
87 fn author_id(&self, node: NodeId) -> Option<u32> {
88 self.author_id.get_value(node)
89 }
90 #[inline(always)]
92 fn committer_id(&self, node: NodeId) -> Option<u32> {
93 self.committer_id.get_value(node)
94 }
95 #[inline(always)]
96 fn num_persons(&self) -> usize {
97 self.num_persons
98 }
99}
100
101#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
102pub struct VecPersons {
103 author_id: Vec<u32>,
104 committer_id: Vec<u32>,
105 num_persons: usize,
106}
107
108impl VecPersons {
109 pub fn new(data: Vec<(Option<u32>, Option<u32>)>) -> Result<Self> {
111 let mut author_id = Vec::with_capacity(data.len());
112 let mut committer_id = Vec::with_capacity(data.len());
113 let mut max_person_id = None;
114 for (a, c) in data.into_iter() {
115 ensure!(a != Some(u32::MAX), "author_id may not be {}", u32::MAX);
116 ensure!(c != Some(u32::MAX), "committer_id may not be {}", u32::MAX);
117 max_person_id = max_person_id.max(a).max(c);
118 author_id.push(a.unwrap_or(u32::MAX));
119 committer_id.push(c.unwrap_or(u32::MAX));
120 }
121 let num_persons = max_person_id.map_or(0, |id| id as usize + 1);
123 Ok(VecPersons {
124 author_id,
125 committer_id,
126 num_persons,
127 })
128 }
129}
130
131impl PropertiesBackend for VecPersons {
132 type DataFilesAvailability = GuaranteedDataFiles;
133}
134impl OptPersons for VecPersons {
135 #[inline(always)]
136 fn author_id(&self, node: NodeId) -> Option<u32> {
137 self.author_id.get_value(node)
138 }
139 #[inline(always)]
140 fn committer_id(&self, node: NodeId) -> Option<u32> {
141 self.committer_id.get_value(node)
142 }
143 #[inline(always)]
144 fn num_persons(&self) -> usize {
145 self.num_persons
146 }
147}
148
149impl<
150 MAPS: MaybeMaps,
151 TIMESTAMPS: MaybeTimestamps,
152 CONTENTS: MaybeContents,
153 STRINGS: MaybeStrings,
154 LABELNAMES: MaybeLabelNames,
155 > SwhGraphProperties<MAPS, TIMESTAMPS, NoPersons, CONTENTS, STRINGS, LABELNAMES>
156{
157 pub fn load_persons(
164 self,
165 ) -> Result<SwhGraphProperties<MAPS, TIMESTAMPS, MappedPersons, CONTENTS, STRINGS, LABELNAMES>>
166 {
167 let OptMappedPersons {
168 author_id,
169 committer_id,
170 num_persons,
171 } = self.get_persons()?;
172 let persons = MappedPersons {
173 author_id: author_id?,
174 committer_id: committer_id?,
175 num_persons: num_persons?,
176 };
177 self.with_persons(persons)
178 }
179
180 pub fn opt_load_persons(
182 self,
183 ) -> Result<SwhGraphProperties<MAPS, TIMESTAMPS, OptMappedPersons, CONTENTS, STRINGS, LABELNAMES>>
184 {
185 let persons = self.get_persons()?;
186 self.with_persons(persons)
187 }
188
189 fn get_persons(&self) -> Result<OptMappedPersons> {
190 Ok(OptMappedPersons {
191 author_id: load_if_exists(&self.path, AUTHOR_ID, |path| {
192 NumberMmap::new(path, self.num_nodes).context("Could not load author_id")
193 })?,
194 committer_id: load_if_exists(&self.path, COMMITTER_ID, |path| {
195 NumberMmap::new(path, self.num_nodes).context("Could not load committer_id")
196 })?,
197 num_persons: load_if_exists(&self.path, PERSONS_COUNT, |path| {
198 let count = std::fs::read_to_string(path)
199 .with_context(|| format!("Could not read {}", path.display()))?;
200 count
201 .trim()
202 .parse::<usize>()
203 .with_context(|| format!("Invalid integer in {}: {count}", path.display()))
204 })?,
205 })
206 }
207
208 pub fn with_persons<PERSONS: MaybePersons>(
211 self,
212 persons: PERSONS,
213 ) -> Result<SwhGraphProperties<MAPS, TIMESTAMPS, PERSONS, CONTENTS, STRINGS, LABELNAMES>> {
214 Ok(SwhGraphProperties {
215 maps: self.maps,
216 timestamps: self.timestamps,
217 persons,
218 contents: self.contents,
219 strings: self.strings,
220 label_names: self.label_names,
221 path: self.path,
222 num_nodes: self.num_nodes,
223 label_names_are_in_base64_order: self.label_names_are_in_base64_order,
224 })
225 }
226}
227
228impl<
233 MAPS: MaybeMaps,
234 TIMESTAMPS: MaybeTimestamps,
235 PERSONS: OptPersons,
236 CONTENTS: MaybeContents,
237 STRINGS: MaybeStrings,
238 LABELNAMES: MaybeLabelNames,
239 > SwhGraphProperties<MAPS, TIMESTAMPS, PERSONS, CONTENTS, STRINGS, LABELNAMES>
240{
241 #[inline]
243 pub fn num_persons(&self) -> PropertiesResult<'_, usize, PERSONS> {
244 self.persons.num_persons()
245 }
246
247 #[inline]
253 pub fn author_id(&self, node_id: NodeId) -> PropertiesResult<'_, Option<u32>, PERSONS> {
254 PERSONS::map_if_available(self.try_author_id(node_id), |author_id| {
255 author_id.unwrap_or_else(|e| panic!("Cannot get node author: {e}"))
256 })
257 }
258
259 #[inline]
264 pub fn try_author_id(
265 &self,
266 node_id: NodeId,
267 ) -> PropertiesResult<'_, Result<Option<u32>, OutOfBoundError>, PERSONS> {
268 PERSONS::map_if_available(self.persons.author_id(node_id), |author_id| {
269 match author_id {
270 None => Err(OutOfBoundError {
271 index: node_id,
273 len: self.num_nodes,
274 }),
275 Some(u32::MAX) => Ok(None), Some(id) => Ok(Some(id)),
277 }
278 })
279 }
280
281 #[inline]
287 pub fn committer_id(&self, node_id: NodeId) -> PropertiesResult<'_, Option<u32>, PERSONS> {
288 PERSONS::map_if_available(self.try_committer_id(node_id), |committer_id| {
289 committer_id.unwrap_or_else(|e| panic!("Cannot get node committer: {e}"))
290 })
291 }
292
293 #[inline]
298 pub fn try_committer_id(
299 &self,
300 node_id: NodeId,
301 ) -> PropertiesResult<'_, Result<Option<u32>, OutOfBoundError>, PERSONS> {
302 PERSONS::map_if_available(self.persons.committer_id(node_id), |committer_id| {
303 match committer_id {
304 None => Err(OutOfBoundError {
305 index: node_id,
307 len: self.num_nodes,
308 }),
309 Some(u32::MAX) => Ok(None), Some(id) => Ok(Some(id)),
311 }
312 })
313 }
314}