gix_mailmap/snapshot/
mod.rs1use bstr::ByteSlice;
2use gix_actor::SignatureRef;
3
4use crate::Snapshot;
5
6mod signature;
7pub use signature::{ResolvedSignature, Signature};
8
9mod util;
10use util::EncodedStringRef;
11
12mod entry;
13pub(crate) use entry::EmailEntry;
14
15impl Snapshot {
16 pub fn from_bytes(buf: &[u8]) -> Self {
20 Self::new(crate::parse_ignore_errors(buf))
21 }
22
23 pub fn new<'a>(entries: impl IntoIterator<Item = crate::Entry<'a>>) -> Self {
27 let mut snapshot = Self::default();
28 snapshot.merge(entries);
29 snapshot
30 }
31
32 pub fn merge<'a>(&mut self, entries: impl IntoIterator<Item = crate::Entry<'a>>) -> &mut Self {
35 for entry in entries {
36 let old_email: EncodedStringRef<'_> = entry.old_email.into();
37 assert!(
38 entry.new_name.is_some() || entry.new_email.is_some(),
39 "BUG: encountered entry without any mapped/new name or email."
40 );
41 match self
42 .entries_by_old_email
43 .binary_search_by(|e| e.old_email.cmp_ref(old_email))
44 {
45 Ok(pos) => self.entries_by_old_email[pos].merge(entry),
46 Err(insert_pos) => {
47 self.entries_by_old_email.insert(insert_pos, entry.into());
48 }
49 };
50 }
51 self
52 }
53
54 pub fn iter(&self) -> impl Iterator<Item = crate::Entry<'_>> {
59 self.entries_by_old_email.iter().flat_map(|entry| {
60 let initial = if entry.new_email.is_some() || entry.new_name.is_some() {
61 Some(crate::Entry {
62 new_name: entry.new_name.as_ref().map(|b| b.as_bstr()),
63 new_email: entry.new_email.as_ref().map(|b| b.as_bstr()),
64 old_name: None,
65 old_email: entry.old_email.as_bstr(),
66 })
67 } else {
68 None
69 };
70
71 let rest = entry.entries_by_old_name.iter().map(|name_entry| crate::Entry {
72 new_name: name_entry.new_name.as_ref().map(|b| b.as_bstr()),
73 new_email: name_entry.new_email.as_ref().map(|b| b.as_bstr()),
74 old_name: name_entry.old_name.as_bstr().into(),
75 old_email: entry.old_email.as_bstr(),
76 });
77
78 initial.into_iter().chain(rest)
79 })
80 }
81
82 pub fn entries(&self) -> Vec<crate::Entry<'_>> {
87 self.iter().collect()
88 }
89
90 pub fn try_resolve_ref(&self, signature: gix_actor::SignatureRef<'_>) -> Option<ResolvedSignature<'_>> {
99 let email: EncodedStringRef<'_> = signature.email.into();
100 let pos = self
101 .entries_by_old_email
102 .binary_search_by(|e| e.old_email.cmp_ref(email))
103 .ok()?;
104 let entry = &self.entries_by_old_email[pos];
105
106 let name: EncodedStringRef<'_> = signature.name.into();
107
108 match entry.entries_by_old_name.binary_search_by(|e| e.old_name.cmp_ref(name)) {
109 Ok(pos) => {
110 let name_entry = &entry.entries_by_old_name[pos];
111 ResolvedSignature::try_new(
112 name_entry.new_email.as_ref(),
113 entry.old_email.as_bstr(),
114 signature.email,
115 name_entry.new_name.as_ref(),
116 )
117 }
118 Err(_) => ResolvedSignature::try_new(
119 entry.new_email.as_ref(),
120 entry.old_email.as_bstr(),
121 signature.email,
122 entry.new_name.as_ref(),
123 ),
124 }
125 }
126
127 pub fn try_resolve(&self, signature: gix_actor::SignatureRef<'_>) -> Option<gix_actor::Signature> {
132 self.try_resolve_ref(signature)
133 .map(|new| enriched_signature(signature, new).into())
134 }
135
136 pub fn resolve(&self, signature: gix_actor::SignatureRef<'_>) -> gix_actor::Signature {
141 self.try_resolve(signature).unwrap_or_else(|| signature.to_owned())
142 }
143
144 pub fn resolve_cow<'a>(&self, signature: gix_actor::SignatureRef<'a>) -> Signature<'a> {
147 self.try_resolve_ref(signature)
148 .map_or_else(|| signature.into(), |new| enriched_signature(signature, new))
149 }
150}
151
152fn enriched_signature<'a>(
153 SignatureRef { name, email, time }: SignatureRef<'a>,
154 new: ResolvedSignature<'_>,
155) -> Signature<'a> {
156 match (new.email, new.name) {
157 (Some(new_email), Some(new_name)) => Signature {
158 email: new_email.to_owned().into(),
159 name: new_name.to_owned().into(),
160 time,
161 },
162 (Some(new_email), None) => Signature {
163 email: new_email.to_owned().into(),
164 name: name.into(),
165 time,
166 },
167 (None, Some(new_name)) => Signature {
168 email: email.into(),
169 name: new_name.to_owned().into(),
170 time,
171 },
172 (None, None) => unreachable!("BUG: ResolvedSignatures don't exist here when nothing is set"),
173 }
174}