dag_types/
location.rs

1/*
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 */
7
8use std::future::Future;
9
10use serde::Deserialize;
11use serde::Serialize;
12
13/// The position of one node in the graph relative their known descendant.
14/// This structure is relevant when the IdMap is lazy. Assuming that all parents of merges
15/// and all heads are known then any node can be represented as their first `descendant`
16/// and the distance to that descendant.
17///
18/// Example:
19/// 0 - a - b - c
20/// In this example our initial commit is `0`, then we have `a` the first commit, `b` second,
21/// `c` third.
22/// {
23///   descendant: c,
24///   distance: 1,
25/// }
26/// => [b]
27#[derive(Copy, Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
28#[derive(Serialize, Deserialize)]
29pub struct Location<Name> {
30    pub descendant: Name,
31    pub distance: u64,
32}
33
34impl<Name> Location<Name> {
35    pub fn new(descendant: Name, distance: u64) -> Self {
36        Self {
37            descendant,
38            distance,
39        }
40    }
41
42    // What's up with all these map-like functions?
43    // The most common operation for the location is to transform it between various
44    // types of graphs, crate::Id, HgId, HgChangesetId, ChangesetId etc.
45    // Had some fun adding with these functions. "Experimenting".
46
47    pub fn map_descendant<T, F>(self, f: F) -> Location<T>
48    where
49        F: FnOnce(Name) -> T,
50    {
51        let new_name = f(self.descendant);
52        Location::new(new_name, self.distance)
53    }
54
55    pub fn try_map_descendant<T, E, F>(self, f: F) -> Result<Location<T>, E>
56    where
57        F: FnOnce(Name) -> Result<T, E>,
58    {
59        let new_name = f(self.descendant)?;
60        Ok(Location::new(new_name, self.distance))
61    }
62
63    pub async fn then_descendant<T, Fut, F>(self, f: F) -> Location<T>
64    where
65        F: FnOnce(Name) -> Fut,
66        Fut: Future<Output = T>,
67    {
68        let new_name = f(self.descendant).await;
69        Location::new(new_name, self.distance)
70    }
71
72    pub async fn and_then_descendant<T, E, Fut, F>(self, f: F) -> Result<Location<T>, E>
73    where
74        F: FnOnce(Name) -> Fut,
75        Fut: Future<Output = Result<T, E>>,
76    {
77        let new_name = f(self.descendant).await?;
78        Ok(Location::new(new_name, self.distance))
79    }
80
81    pub fn with_descendant<T>(self, descendant: T) -> Location<T> {
82        Location::new(descendant, self.distance)
83    }
84}
85
86#[cfg(any(test, feature = "for-tests"))]
87use quickcheck::Arbitrary;
88#[cfg(any(test, feature = "for-tests"))]
89use quickcheck::Gen;
90
91#[cfg(any(test, feature = "for-tests"))]
92impl<Name> Arbitrary for Location<Name>
93where
94    Name: Arbitrary,
95{
96    fn arbitrary(g: &mut Gen) -> Self {
97        Location {
98            descendant: Name::arbitrary(g),
99            distance: u64::arbitrary(g),
100        }
101    }
102}