Skip to main content

swh_graph/views/spy/
maps.rs

1// Copyright (C) 2024-2026  The Software Heritage developers
2// See the AUTHORS file at the top-level directory of this distribution
3// License: GNU General Public License version 3, or any later version
4// See top-level LICENSE file for more information
5
6//! Implementation of [`properties::Maps`] spy for [`GraphSpy`]
7
8use super::*;
9use crate::mph::SwhidMphf;
10use crate::properties::Maps;
11use crate::SWHID;
12
13impl<
14        G: SwhGraphWithProperties<Maps: properties::Maps>,
15        TIMESTAMPS: properties::MaybeTimestamps,
16        PERSONS: properties::MaybePersons,
17        CONTENTS: properties::MaybeContents,
18        STRINGS: properties::MaybeStrings,
19        LABELNAMES: properties::MaybeLabelNames,
20    > GraphSpy<G, properties::NoMaps, TIMESTAMPS, PERSONS, CONTENTS, STRINGS, LABELNAMES>
21{
22    pub fn with_maps(
23        self,
24    ) -> GraphSpy<G, MapsSpy<G>, TIMESTAMPS, PERSONS, CONTENTS, STRINGS, LABELNAMES> {
25        let GraphSpy {
26            properties:
27                properties::SwhGraphProperties {
28                    path,
29                    num_nodes,
30                    maps: properties::NoMaps,
31                    timestamps,
32                    persons,
33                    contents,
34                    strings,
35                    label_names,
36                    label_names_are_in_base64_order,
37                },
38            inner,
39            history,
40        } = self;
41
42        GraphSpy {
43            properties: properties::SwhGraphProperties {
44                path,
45                num_nodes,
46                maps: MapsSpy {
47                    graph: Arc::clone(&inner),
48                    history: Arc::clone(&history),
49                    mphf: MphfSpy {
50                        graph: Arc::clone(&inner),
51                        history: Arc::clone(&history),
52                    },
53                },
54                timestamps,
55                persons,
56                contents,
57                strings,
58                label_names,
59                label_names_are_in_base64_order,
60            },
61            inner,
62            history,
63        }
64    }
65}
66
67pub struct MapsSpy<G: SwhGraphWithProperties<Maps: properties::Maps>> {
68    graph: Arc<GraphSpyInner<G>>,
69    history: Arc<Mutex<Vec<GraphAccessRecord>>>,
70    mphf: MphfSpy<G>,
71}
72
73impl<G: SwhGraphWithProperties<Maps: properties::Maps>> properties::Maps for MapsSpy<G> {
74    type MPHF = MphfSpy<G>;
75
76    fn mphf(&self) -> &Self::MPHF {
77        &self.mphf
78    }
79
80    fn node2swhid(&self, node: NodeId) -> Result<crate::SWHID, crate::OutOfBoundError> {
81        self.history
82            .lock()
83            .unwrap()
84            .push(GraphAccessRecord::Property(PropertyAccess::Swhid(node)));
85        self.graph.graph.properties().maps.node2swhid(node)
86    }
87
88    fn node2type(&self, node: NodeId) -> Result<NodeType, crate::OutOfBoundError> {
89        self.history
90            .lock()
91            .unwrap()
92            .push(GraphAccessRecord::Property(PropertyAccess::NodeType(node)));
93        self.graph.graph.properties().maps.node2type(node)
94    }
95}
96
97pub struct MphfSpy<G: SwhGraphWithProperties<Maps: properties::Maps>> {
98    graph: Arc<GraphSpyInner<G>>,
99    history: Arc<Mutex<Vec<GraphAccessRecord>>>,
100}
101
102impl<G: SwhGraphWithProperties<Maps: properties::Maps>> SwhidMphf for MphfSpy<G> {
103    fn num_keys(&self) -> usize {
104        self.graph.graph.properties().maps.mphf().num_keys()
105    }
106    fn hash_array(&self, swhid: &[u8; SWHID::BYTES_SIZE]) -> Option<NodeId> {
107        match SWHID::try_from(*swhid) {
108            Ok(swhid) => self.hash_swhid(&swhid),
109            Err(_) => {
110                self.history
111                    .lock()
112                    .unwrap()
113                    .push(GraphAccessRecord::Property(
114                        PropertyAccess::NodeIdForInvalidBytes(*swhid),
115                    ));
116                None
117            }
118        }
119    }
120
121    #[inline(always)]
122    fn hash_str(&self, swhid: impl AsRef<str>) -> Option<NodeId> {
123        let swhid = swhid.as_ref();
124        match SWHID::try_from(swhid) {
125            Ok(swhid) => self.hash_swhid(&swhid),
126            Err(_) => {
127                self.history
128                    .lock()
129                    .unwrap()
130                    .push(GraphAccessRecord::Property(
131                        PropertyAccess::NodeIdForInvalidString(swhid.to_owned()),
132                    ));
133                None
134            }
135        }
136    }
137
138    #[inline(always)]
139    fn hash_str_array(&self, swhid: &[u8; 50]) -> Option<NodeId> {
140        let Ok(swhid_str) = String::from_utf8(swhid.to_vec()) else {
141            self.history
142                .lock()
143                .unwrap()
144                .push(GraphAccessRecord::Property(
145                    PropertyAccess::NodeIdForInvalidStrArray(*swhid),
146                ));
147            return None;
148        };
149        match SWHID::try_from(swhid_str.as_ref()) {
150            Ok(swhid) => self.hash_swhid(&swhid),
151            Err(_) => {
152                self.history
153                    .lock()
154                    .unwrap()
155                    .push(GraphAccessRecord::Property(
156                        PropertyAccess::NodeIdForInvalidString(swhid_str),
157                    ));
158                None
159            }
160        }
161    }
162
163    /// Hashes a [`SWHID`]
164    #[inline(always)]
165    fn hash_swhid(&self, swhid: &SWHID) -> Option<NodeId> {
166        self.history
167            .lock()
168            .unwrap()
169            .push(GraphAccessRecord::Property(PropertyAccess::NodeId(*swhid)));
170        self.graph.graph.properties().maps.mphf().hash_swhid(swhid)
171    }
172}