libpijul_compat/
patch.rs

1//! Definition of patches, and a number of methods.
2use chrono;
3use chrono::{DateTime, Utc};
4use flate2;
5use rand;
6use std::collections::{HashMap, HashSet};
7use std::fs::{metadata, File, OpenOptions};
8use std::io::{BufRead, Read, Write};
9use std::path::Path;
10use std::path::PathBuf;
11use std::rc::Rc;
12use std::str::from_utf8;
13use thrussh_keys;
14use thrussh_keys::key::KeyPair;
15use thrussh_keys::PublicKeyBase64;
16pub type Flag = u8;
17use bincode::{deserialize, deserialize_from, serialize};
18use bs58;
19use serde_json;
20use {ErrorKind, Result};
21
22bitflags! {
23    #[derive(Serialize, Deserialize)]
24    pub struct PatchFlags: u32 {
25        const TAG = 1;
26    }
27}
28
29/// A patch without its signature suffix.
30#[derive(Debug, Serialize, Deserialize, Clone)]
31pub struct UnsignedPatch {
32    /// Header part, containing the metadata.
33    pub header: PatchHeader,
34    /// The dependencies of this patch.
35    pub dependencies: HashSet<Hash>,
36    /// The actual contents of the patch.
37    pub changes: Vec<Change<ChangeContext<Hash>>>,
38}
39
40/// The definition of a patch.
41#[derive(Debug, Serialize, Deserialize, Clone)]
42pub enum Patch {
43    Unsigned0,
44    Signed0,
45    Unsigned(UnsignedPatch),
46}
47
48impl Patch {
49    /// The contents of this patch.
50    pub fn changes(&self) -> &[Change<ChangeContext<Hash>>] {
51        match *self {
52            Patch::Signed0 | Patch::Unsigned0 => {
53                panic!("refusing to interact with old patch version")
54            }
55            Patch::Unsigned(ref patch) => &patch.changes,
56        }
57    }
58    pub fn changes_mut(&mut self) -> &mut Vec<Change<ChangeContext<Hash>>> {
59        match *self {
60            Patch::Signed0 | Patch::Unsigned0 => {
61                panic!("refusing to interact with old patch version")
62            }
63            Patch::Unsigned(ref mut patch) => &mut patch.changes,
64        }
65    }
66    /// The dependencies of this patch.
67    pub fn dependencies(&self) -> &HashSet<Hash> {
68        match *self {
69            Patch::Signed0 | Patch::Unsigned0 => {
70                panic!("refusing to interact with old patch version")
71            }
72            Patch::Unsigned(ref patch) => &patch.dependencies,
73        }
74    }
75    pub fn dependencies_mut(&mut self) -> &mut HashSet<Hash> {
76        match *self {
77            Patch::Signed0 | Patch::Unsigned0 => {
78                panic!("refusing to interact with old patch version")
79            }
80            Patch::Unsigned(ref mut patch) => &mut patch.dependencies,
81        }
82    }
83    /// The header of this patch.
84    pub fn header(&self) -> &PatchHeader {
85        match *self {
86            Patch::Signed0 | Patch::Unsigned0 => {
87                panic!("refusing to interact with old patch version")
88            }
89            Patch::Unsigned(ref patch) => &patch.header,
90        }
91    }
92    pub fn header_mut(&mut self) -> &mut PatchHeader {
93        match *self {
94            Patch::Signed0 | Patch::Unsigned0 => {
95                panic!("refusing to interact with old patch version")
96            }
97            Patch::Unsigned(ref mut patch) => &mut patch.header,
98        }
99    }
100
101    /// Reads everything in this patch, but the actual contents.
102    pub fn read_dependencies<R: Read>(mut r: R) -> Result<Vec<Hash>> {
103        let version: u32 = deserialize_from(&mut r)?;
104        assert_eq!(version, 2);
105        let _header: PatchHeader = deserialize_from(&mut r)?;
106        debug!("version: {:?}", version);
107        Ok(deserialize_from(&mut r)?)
108    }
109}
110
111/// The header of a patch contains all the metadata about a patch
112/// (but not the actual contents of a patch).
113#[derive(Debug, Serialize, Deserialize, Clone)]
114pub struct PatchHeader {
115    pub authors: Vec<String>,
116    pub name: String,
117    pub description: Option<String>,
118    pub timestamp: DateTime<Utc>,
119    pub flag: PatchFlags,
120}
121
122use std::ops::{Deref, DerefMut};
123impl Deref for Patch {
124    type Target = PatchHeader;
125    fn deref(&self) -> &Self::Target {
126        self.header()
127    }
128}
129impl DerefMut for Patch {
130    fn deref_mut(&mut self) -> &mut Self::Target {
131        self.header_mut()
132    }
133}
134
135/// Options are for when this edge is between vertices introduced by
136/// the current patch.
137#[derive(Debug, Clone, Serialize, Deserialize)]
138pub struct NewEdge {
139    pub from: Key<Option<Hash>>,
140    pub to: Key<Option<Hash>>,
141    pub introduced_by: Option<Hash>,
142}
143
144pub type ChangeContext<H> = Vec<Key<Option<H>>>;
145
146#[derive(Debug, Clone, Serialize, Deserialize)]
147pub enum Change<Context> {
148    NewNodes {
149        up_context: Context,
150        down_context: Context,
151        flag: EdgeFlags,
152        line_num: LineId,
153        nodes: Vec<Vec<u8>>,
154        inode: Key<Option<Hash>>,
155    },
156    NewEdges {
157        previous: EdgeFlags,
158        flag: EdgeFlags,
159        edges: Vec<NewEdge>,
160        inode: Key<Option<Hash>>,
161    },
162}
163
164impl PatchHeader {
165    /// Reads everything in this patch, but the actual contents.
166    pub fn from_reader_nochanges<R: Read>(mut r: R) -> Result<PatchHeader> {
167        let version: u32 = deserialize_from(&mut r)?;
168        debug!("version: {:?}", version);
169        Ok(deserialize_from(&mut r)?)
170    }
171}
172
173/// Semantic groups of changes, for interface purposes.
174#[derive(Debug)]
175pub enum Record<Context> {
176    FileMove {
177        new_name: String,
178        del: Change<Context>,
179        add: Change<Context>,
180    },
181    FileDel {
182        name: String,
183        del: Change<Context>,
184    },
185    FileAdd {
186        name: String,
187        add: Change<Context>,
188    },
189    Change {
190        file: Rc<PathBuf>,
191        change: Change<Context>,
192        conflict_reordering: Vec<Change<Context>>,
193    },
194    Replace {
195        file: Rc<PathBuf>,
196        adds: Change<Context>,
197        dels: Change<Context>,
198        conflict_reordering: Vec<Change<Context>>,
199    },
200}
201
202pub struct RecordIter<R, C> {
203    rec: Option<R>,
204    extra: Option<C>,
205}
206
207impl<Context> IntoIterator for Record<Context> {
208    type IntoIter = RecordIter<Record<Context>, Change<Context>>;
209    type Item = Change<Context>;
210    fn into_iter(self) -> Self::IntoIter {
211        RecordIter {
212            rec: Some(self),
213            extra: None,
214        }
215    }
216}
217
218impl<Context> Record<Context> {
219    pub fn iter(&self) -> RecordIter<&Record<Context>, &Change<Context>> {
220        RecordIter {
221            rec: Some(self),
222            extra: None,
223        }
224    }
225}
226
227impl<Context> Iterator for RecordIter<Record<Context>, Change<Context>> {
228    type Item = Change<Context>;
229    fn next(&mut self) -> Option<Self::Item> {
230        if let Some(extra) = self.extra.take() {
231            Some(extra)
232        } else if let Some(rec) = self.rec.take() {
233            match rec {
234                Record::FileMove { del, add, .. } => {
235                    self.extra = Some(add);
236                    Some(del)
237                }
238                Record::FileDel { del: c, .. }
239                | Record::FileAdd { add: c, .. }
240                | Record::Change { change: c, .. } => Some(c),
241                Record::Replace { adds, dels, .. } => {
242                    self.extra = Some(adds);
243                    Some(dels)
244                }
245            }
246        } else {
247            None
248        }
249    }
250}
251
252impl<'a, Context> Iterator for RecordIter<&'a Record<Context>, &'a Change<Context>> {
253    type Item = &'a Change<Context>;
254    fn next(&mut self) -> Option<Self::Item> {
255        if let Some(extra) = self.extra.take() {
256            Some(extra)
257        } else if let Some(rec) = self.rec.take() {
258            match *rec {
259                Record::FileMove {
260                    ref del, ref add, ..
261                } => {
262                    self.extra = Some(add);
263                    Some(del)
264                }
265                Record::FileDel { del: ref c, .. }
266                | Record::FileAdd { add: ref c, .. }
267                | Record::Change { change: ref c, .. } => Some(c),
268                Record::Replace {
269                    ref adds, ref dels, ..
270                } => {
271                    self.extra = Some(adds);
272                    Some(dels)
273                }
274            }
275        } else {
276            None
277        }
278    }
279}
280
281impl UnsignedPatch {
282    pub fn empty() -> Self {
283        UnsignedPatch {
284            header: PatchHeader {
285                authors: vec![],
286                name: "".to_string(),
287                description: None,
288                timestamp: chrono::Utc::now(),
289                flag: PatchFlags::empty(),
290            },
291            dependencies: HashSet::new(),
292            changes: vec![],
293        }
294    }
295    pub fn leave_unsigned(self) -> Patch {
296        Patch::Unsigned(self)
297    }
298
299    fn is_tag(&self) -> bool {
300        self.header.flag.contains(PatchFlags::TAG)
301    }
302
303    pub fn inverse(&self, hash: &Hash, changes: &mut Vec<Change<ChangeContext<Hash>>>) {
304        for ch in self.changes.iter() {
305            debug!("inverse {:?}", ch);
306            match *ch {
307                Change::NewNodes {
308                    ref up_context,
309                    flag,
310                    line_num,
311                    ref nodes,
312                    ref inode,
313                    ..
314                } => {
315                    let edges = up_context
316                        .iter()
317                        .map(|up| NewEdge {
318                            from: Key {
319                                patch: match up.patch {
320                                    Some(ref h) => Some(h.clone()),
321                                    None => Some(hash.clone()),
322                                },
323                                line: up.line,
324                            },
325                            to: Key {
326                                patch: Some(hash.clone()),
327                                line: line_num,
328                            },
329                            introduced_by: Some(hash.clone()),
330                        })
331                        .chain((1..nodes.len()).map(|i| NewEdge {
332                            from: Key {
333                                patch: Some(hash.clone()),
334                                line: line_num + (i - 1),
335                            },
336                            to: Key {
337                                patch: Some(hash.clone()),
338                                line: line_num + i,
339                            },
340                            introduced_by: Some(hash.clone()),
341                        }))
342                        .collect();
343                    changes.push(Change::NewEdges {
344                        edges,
345                        inode: inode.clone(),
346                        previous: flag,
347                        flag: flag ^ EdgeFlags::DELETED_EDGE,
348                    })
349                }
350                Change::NewEdges {
351                    previous,
352                    flag,
353                    ref edges,
354                    ref inode,
355                } => changes.push(Change::NewEdges {
356                    previous: flag,
357                    flag: previous,
358                    inode: inode.clone(),
359                    edges: edges
360                        .iter()
361                        .map(|e| NewEdge {
362                            from: e.from.clone(),
363                            to: e.to.clone(),
364                            introduced_by: Some(hash.clone()),
365                        })
366                        .collect(),
367                }),
368            }
369        }
370    }
371}
372
373impl Patch {
374    /// An approximate upper bound of the number of extra bytes in the
375    /// database this patch might require. This depends a lot on the
376    /// patch and the database, so it might be wrong.
377    pub fn size_upper_bound(&self) -> usize {
378        // General overhead for applying a patch; 8 pages.
379        let mut size: usize = 1 << 15;
380        for c in self.changes().iter() {
381            match *c {
382                Change::NewNodes { ref nodes, .. } => {
383                    size += nodes.iter().map(|x| x.len()).sum::<usize>();
384                    size += nodes.len() * 2048 // + half a page
385                }
386                Change::NewEdges { ref edges, .. } => size += edges.len() * 2048,
387            }
388        }
389        size
390    }
391
392    pub fn is_tag(&self) -> bool {
393        match *self {
394            Patch::Unsigned(ref patch) => patch.is_tag(),
395            _ => false,
396        }
397    }
398
399    /// Read one patch from a gzip-compressed `BufRead`. If several
400    /// patches are available in the same `BufRead`, this method can
401    /// be called again.
402    pub fn from_reader_compressed<R: BufRead>(r: &mut R) -> Result<(Hash, Vec<u8>, Patch)> {
403        let mut rr = flate2::bufread::GzDecoder::new(r);
404        let filename = {
405            let filename = if let Some(header) = rr.header() {
406                if let Some(filename) = header.filename() {
407                    from_utf8(filename)?
408                } else {
409                    return Err(ErrorKind::EOF.into());
410                }
411            } else {
412                return Err(ErrorKind::EOF.into());
413            };
414            if let Some(h) = Hash::from_base58(filename) {
415                h
416            } else {
417                return Err(ErrorKind::WrongHash.into());
418            }
419        };
420
421        let mut buf = Vec::new();
422        rr.read_to_end(&mut buf)?;
423
424        // Checking the hash.
425        let patch: Patch = deserialize(&buf[..])?;
426        patch.check_hash(&buf, &filename)?;
427
428        Ok((filename, buf, patch))
429    }
430
431    fn check_hash(&self, buf: &[u8], filename: &Hash) -> Result<()> {
432        let buf = match *self {
433            Patch::Signed0 | Patch::Unsigned0 => {
434                panic!("refusing to interact with old patch version")
435            }
436            Patch::Unsigned(_) => buf,
437        };
438        let hash = Hash::of_slice(buf)?;
439        match (filename, &hash) {
440            (&Hash::Sha512(ref filename), &Hash::Sha512(ref hash))
441                if &filename.0[..] == &hash.0[..] =>
442            {
443                Ok(())
444            }
445            _ => Err(ErrorKind::WrongHash.into()),
446        }
447    }
448
449    pub fn to_buf(&self) -> Result<(Vec<u8>, Hash)> {
450        // Encoding to a buffer.
451        let buf = serialize(&self)?;
452        // Hashing the buffer.
453        let hash = Hash::of_slice(&buf)?;
454        Ok((buf, hash))
455    }
456
457    /// Save the patch, computing the hash.
458    pub fn save<P: AsRef<Path>>(&self, dir: P, key: Option<&KeyPair>) -> Result<Hash> {
459        let (buf, hash) = self.to_buf()?;
460        // Writing to the file.
461        let h = hash.to_base58();
462        let mut path = dir.as_ref().join(&h);
463        path.set_extension("gz");
464        if metadata(&path).is_err() {
465            debug!("save, path {:?}", path);
466            let f = File::create(&path)?;
467            debug!("created");
468            let mut w = flate2::GzBuilder::new()
469                .filename(h.as_bytes())
470                .write(f, flate2::Compression::best());
471            w.write_all(&buf)?;
472            w.finish()?;
473            debug!("saved");
474        }
475
476        if let Some(key) = key {
477            path.set_extension("sig");
478            let mut file = OpenOptions::new()
479                .read(true)
480                .write(true)
481                .create(true)
482                .open(&path)?;
483
484            let mut signatures: SignatureFile =
485                serde_json::from_reader(&mut file).unwrap_or(SignatureFile {
486                    hash: h,
487                    signatures: HashMap::new(),
488                });
489            let signature = key.sign_detached(&hash.as_ref().to_binary())?;
490            let public_key = key.public_key_base64();
491            signatures
492                .signatures
493                .insert(public_key, bs58::encode(&signature.as_ref()).into_string());
494            serde_json::to_writer(&mut file, &signatures)?;
495        }
496        Ok(hash)
497    }
498
499    pub fn inverse(&self, hash: &Hash, changes: &mut Vec<Change<ChangeContext<Hash>>>) {
500        match *self {
501            Patch::Unsigned0 => panic!("Can't reverse old patches"),
502            Patch::Signed0 => panic!("Can't reverse old patches"),
503            Patch::Unsigned(ref u) => u.inverse(hash, changes),
504        }
505    }
506}
507
508#[derive(Debug, Serialize, Deserialize)]
509pub struct SignatureFile {
510    pub hash: String,
511    pub signatures: HashMap<String, String>,
512}
513
514pub fn read_signature_file(r: &mut Read) -> Result<SignatureFile> {
515    let signatures: SignatureFile = serde_json::from_reader(r)?;
516    // verify signatures
517    for (key, sig) in signatures.signatures.iter() {
518        let k = thrussh_keys::parse_public_key_base64(&key)?;
519        let sig = bs58::decode(sig).into_vec()?;
520        if !k.verify_detached(signatures.hash.as_bytes(), &sig) {
521            return Err(ErrorKind::WrongPatchSignature.into());
522        }
523    }
524    Ok(signatures)
525}
526
527impl SignatureFile {
528    pub fn write_signature_file(&self, w: &mut Write) -> Result<()> {
529        serde_json::to_writer(w, self)?;
530        Ok(())
531    }
532}
533
534pub struct Signatures<'a, R: Read>(
535    serde_json::StreamDeserializer<'a, serde_json::de::IoRead<R>, SignatureFile>,
536);
537
538pub fn read_signatures<'a, R: Read>(r: R) -> Signatures<'a, R> {
539    Signatures(serde_json::Deserializer::from_reader(r).into_iter())
540}
541
542impl<'a, R: Read> Iterator for Signatures<'a, R> {
543    type Item = Result<SignatureFile>;
544    fn next(&mut self) -> Option<Self::Item> {
545        self.0.next().map(|n| n.map_err(super::Error::from))
546    }
547}
548
549pub fn read_changes(r: &mut Read) -> Result<HashMap<Hash, ApplyTimestamp>> {
550    let mut s = String::new();
551    r.read_to_string(&mut s)?;
552    let mut result = HashMap::new();
553    for l in s.lines() {
554        let mut sp = l.split(':');
555        match (
556            sp.next().and_then(Hash::from_base58),
557            sp.next().and_then(|s| s.parse().ok()),
558        ) {
559            (Some(h), Some(s)) => {
560                result.insert(h, s);
561            }
562            _ => {}
563        }
564    }
565    Ok(result)
566}
567
568pub fn read_changes_from_file<P: AsRef<Path>>(
569    changes_file: P,
570) -> Result<HashMap<Hash, ApplyTimestamp>> {
571    let mut file = File::open(changes_file)?;
572    read_changes(&mut file)
573}
574
575impl<U: Transaction, R> GenericTxn<U, R> {
576    pub fn new_patch<I: Iterator<Item = Hash>>(
577        &self,
578        branch: &Branch,
579        authors: Vec<String>,
580        name: String,
581        description: Option<String>,
582        timestamp: DateTime<Utc>,
583        changes: Vec<Change<ChangeContext<Hash>>>,
584        extra_dependencies: I,
585        flag: PatchFlags,
586    ) -> Patch {
587        let mut dependencies = self.dependencies(branch, changes.iter());
588        dependencies.extend(extra_dependencies);
589        Patch::Unsigned(UnsignedPatch {
590            header: PatchHeader {
591                authors,
592                name,
593                description,
594                timestamp,
595                flag,
596            },
597            dependencies,
598            changes,
599        })
600    }
601
602    pub fn dependencies<'a, I: Iterator<Item = &'a Change<ChangeContext<Hash>>>>(
603        &self,
604        branch: &Branch,
605        changes: I,
606    ) -> HashSet<Hash> {
607        let mut deps = HashSet::new();
608        let mut zombie_deps = HashSet::new();
609        for ch in changes {
610            match *ch {
611                Change::NewNodes {
612                    ref up_context,
613                    ref down_context,
614                    ..
615                } => for c in up_context.iter().chain(down_context.iter()) {
616                    match c.patch {
617                        None | Some(Hash::None) => {}
618                        Some(ref dep) => {
619                            debug!("dependencies (line {}) += {:?}", line!(), dep);
620                            deps.insert(dep.clone());
621                        }
622                    }
623                },
624                Change::NewEdges {
625                    flag, ref edges, ..
626                } => {
627                    for e in edges {
628                        let (from, to) = if flag.contains(EdgeFlags::PARENT_EDGE) {
629                            (&e.to, &e.from)
630                        } else {
631                            (&e.from, &e.to)
632                        };
633
634                        match from.patch {
635                            None | Some(Hash::None) => {}
636                            Some(ref h) => {
637                                debug!("dependencies (line {}) += {:?}", line!(), h);
638                                deps.insert(h.clone());
639                                if flag.contains(EdgeFlags::DELETED_EDGE) {
640                                    // Add "known patches" to
641                                    // allow identifying missing
642                                    // contexts.
643                                    let k = Key {
644                                        patch: self.get_internal(h.as_ref()).unwrap().to_owned(),
645                                        line: from.line.clone(),
646                                    };
647                                    self.edge_context_deps(branch, k, &mut zombie_deps)
648                                }
649                            }
650                        }
651                        match to.patch {
652                            None | Some(Hash::None) => {}
653                            Some(ref h) => {
654                                debug!("dependencies (line {}) += {:?}", line!(), h);
655                                deps.insert(h.clone());
656                                if flag.contains(EdgeFlags::DELETED_EDGE) {
657                                    // Add "known patches" to
658                                    // allow identifying
659                                    // missing contexts.
660                                    let k = Key {
661                                        patch: self.get_internal(h.as_ref()).unwrap().to_owned(),
662                                        line: to.line.clone(),
663                                    };
664                                    self.edge_context_deps(branch, k, &mut zombie_deps)
665                                }
666                            }
667                        }
668                        match e.introduced_by {
669                            None | Some(Hash::None) => {}
670                            Some(ref h) => {
671                                debug!("dependencies (line {}) += {:?}", line!(), h);
672                                zombie_deps.insert(h.clone());
673                            }
674                        }
675                    }
676                }
677            }
678        }
679        let mut h = self.minimize_deps(&deps);
680        for z in zombie_deps.drain() {
681            h.insert(z);
682        }
683        h
684    }
685
686    pub fn minimize_deps(&self, deps: &HashSet<Hash>) -> HashSet<Hash> {
687        debug!("minimize_deps {:?}", deps);
688        let mut covered = HashSet::new();
689        let mut stack = Vec::new();
690        let mut seen = HashSet::new();
691        for dep_ext in deps.iter() {
692            // For each dependency, do a DFS.
693            let dep = self.get_internal(dep_ext.as_ref()).unwrap();
694            debug!("dep = {:?}", dep);
695            stack.clear();
696            stack.push((dep, false));
697            while let Some((current, on_path)) = stack.pop() {
698                // Is current already covered? (either transitively in
699                // covered, or directly in deps).
700                let already_covered = covered.get(&current).is_some() || (current != dep && {
701                    let current_ext = self.get_external(current).unwrap();
702                    deps.get(&current_ext.to_owned()).is_some()
703                });
704                if already_covered {
705                    // We look at all patches on the current path, and
706                    // mark them as covered.
707                    for &(h, h_on_path) in stack.iter() {
708                        if h_on_path {
709                            debug!("covered: h {:?}", h);
710                            covered.insert(h);
711                        }
712                    }
713                    break;
714                }
715                // If we've already seen `current`, and dep is not
716                // covered, we don't need to explore `current`'s
717                // children.  Or, if we're coming here for the second
718                // time (i.e. after exploring all children), no need to
719                // explore the children again either.
720                if seen.insert(current) && !on_path {
721                    stack.push((current, true));
722
723                    for (_, parent) in self.iter_revdep(Some((current, None)))
724                        .take_while(|k| k.0 == current)
725                    {
726                        stack.push((parent, false))
727                    }
728                }
729            }
730        }
731
732        deps.iter()
733            .filter_map(|dep_ext| {
734                let dep = self.get_internal(dep_ext.as_ref()).unwrap();
735                if covered.get(&dep).is_none() {
736                    Some(dep_ext.to_owned())
737                } else {
738                    None
739                }
740            })
741            .collect()
742    }
743
744    fn edge_context_deps(&self, branch: &Branch, k: Key<PatchId>, deps: &mut HashSet<Hash>) {
745        for (_, edge) in self.iter_nodes(branch, Some((k, None)))
746            .take_while(|&(k_, _)| k_ == k)
747            .filter(|&(_, e_)| !e_.flag.contains(EdgeFlags::PARENT_EDGE))
748        {
749            if let Some(ext) = self.get_external(edge.introduced_by) {
750                deps.insert(ext.to_owned());
751            }
752        }
753    }
754}
755
756use backend::*;
757use sanakirja;
758
759impl<A: sanakirja::Transaction, R> GenericTxn<A, R> {
760    /// Gets the external key corresponding to the given key, returning an
761    /// owned vector. If the key is just a patch internal hash, it returns the
762    /// corresponding external hash.
763    pub fn external_key(&self, key: &Key<PatchId>) -> Option<Key<Option<Hash>>> {
764        Some(Key {
765            patch: Some(self.external_hash(key.patch).to_owned()),
766            line: key.line,
767        })
768    }
769
770    pub fn external_hash(&self, key: PatchId) -> HashRef {
771        if key == ROOT_PATCH_ID {
772            ROOT_HASH.as_ref()
773        } else {
774            self.get_external(key).unwrap()
775        }
776    }
777
778    pub(crate) fn external_hash_opt(&self, h: Option<PatchId>) -> Option<Hash> {
779        h.map(|x| self.external_hash(x).to_owned())
780    }
781
782    pub(crate) fn external_key_opt(&self, h: Key<Option<PatchId>>) -> Key<Option<Hash>> {
783        Key {
784            line: h.line,
785            patch: self.external_hash_opt(h.patch),
786        }
787    }
788
789    /// Create a new internal patch id, register it in the "external" and
790    /// "internal" bases, and write the result in its second argument
791    /// ("result").
792    pub fn new_internal(&self, ext: HashRef) -> PatchId {
793        let mut result = ROOT_PATCH_ID;
794        match ext {
795            HashRef::None => return result,
796            HashRef::Sha512(h) => result.clone_from_slice(&h[..PATCH_ID_SIZE]),
797        }
798        let mut first_random = PATCH_ID_SIZE;
799        loop {
800            if self.get_external(result).is_none() {
801                break;
802            }
803            if first_random > 0 {
804                first_random -= 1
805            };
806            for x in &mut result[first_random..].iter_mut() {
807                *x = rand::random()
808            }
809        }
810        result
811    }
812}