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(|| gix_actor::Signature {
142 name: signature.name.to_owned(),
143 email: signature.email.to_owned(),
144 time: signature.time().unwrap_or_default(),
145 })
146 }
147
148 pub fn resolve_cow<'a>(&self, signature: gix_actor::SignatureRef<'a>) -> Signature<'a> {
151 self.try_resolve_ref(signature)
152 .map_or_else(|| signature.into(), |new| enriched_signature(signature, new))
153 }
154}
155
156fn enriched_signature<'a>(
157 SignatureRef { name, email, time }: SignatureRef<'a>,
158 new: ResolvedSignature<'_>,
159) -> Signature<'a> {
160 match (new.email, new.name) {
161 (Some(new_email), Some(new_name)) => Signature {
162 email: new_email.to_owned().into(),
163 name: new_name.to_owned().into(),
164 time: time.parse().unwrap_or_default(),
165 },
166 (Some(new_email), None) => Signature {
167 email: new_email.to_owned().into(),
168 name: name.into(),
169 time: time.parse().unwrap_or_default(),
170 },
171 (None, Some(new_name)) => Signature {
172 email: email.into(),
173 name: new_name.to_owned().into(),
174 time: time.parse().unwrap_or_default(),
175 },
176 (None, None) => unreachable!("BUG: ResolvedSignatures don't exist here when nothing is set"),
177 }
178}