1use crate::rdf_core::{
2 NeighsRDF, RDFError,
3 term::Triple,
4 visualizer::{
5 RDFVisualizationConfig, VisualRDFEdge, VisualRDFNode,
6 errors::RdfVisualizerError,
7 uml_converter::{UmlConverter, UmlGenerationMode, errors::UmlConverterError},
8 utils::UsageCount,
9 },
10};
11
12use std::collections::{HashMap, HashSet};
13use std::fmt::Display;
14use std::io::Write;
15
16pub struct VisualRDFGraph {
22 node_counter: usize,
24 nodes_map: HashMap<VisualRDFNode, NodeId>,
26 usage_count: HashMap<VisualRDFNode, UsageCount>,
28 edges: HashSet<(NodeId, VisualRDFEdge, NodeId)>,
30 config: RDFVisualizationConfig,
32}
33
34impl VisualRDFGraph {
35 pub fn new(config: RDFVisualizationConfig) -> Self {
43 VisualRDFGraph {
44 node_counter: 0,
45 nodes_map: HashMap::new(),
46 usage_count: HashMap::new(),
47 edges: HashSet::new(),
48 config,
49 }
50 }
51
52 pub fn from_rdf<R: NeighsRDF>(rdf: &R, config: RDFVisualizationConfig) -> Result<Self, RDFError> {
64 let mut graph = VisualRDFGraph::new(config);
65 let triples = rdf
66 .triples()
67 .map_err(|e| RDFError::ObtainingTriples { error: e.to_string() })?;
68
69 if let Some(upper_bound) = triples.size_hint().1 {
71 graph.nodes_map.reserve(upper_bound.saturating_mul(3)); graph.usage_count.reserve(upper_bound.saturating_mul(3));
73 graph.edges.reserve(upper_bound);
74 }
75
76 for triple in triples {
77 let (subject, predicate, object) = triple.into_components();
78 graph.create_triple(rdf, subject, predicate, object)?;
79 }
80 Ok(graph)
81 }
82
83 pub fn create_triple<R: NeighsRDF>(
97 &mut self,
98 rdf: &R,
99 subject: R::Subject,
100 predicate: R::IRI,
101 object: R::Term,
102 ) -> Result<VisualRDFNode, RDFError> {
103 let subject_node = VisualRDFNode::from_subject(rdf, &subject, self)?;
104 self.increment_usage_count_as_subject(&subject_node);
105 let subject_id = self.get_or_create_node(subject_node.clone());
106
107 let edge_node = VisualRDFNode::from_predicate(rdf, &predicate);
108 self.increment_usage_count_as_predicate(&edge_node);
109 let edge = VisualRDFEdge::from_iri(rdf, &predicate);
110
111 let object_node = VisualRDFNode::from_term(rdf, &object, self)?;
112 self.increment_usage_count_as_object(&object_node);
113 let object_id = self.get_or_create_node(object_node.clone());
114 self.edges.insert((subject_id, edge, object_id));
115
116 Ok(VisualRDFNode::non_asserted_triple(subject_node, edge_node, object_node))
117 }
118
119 pub fn create_triple_term<R: NeighsRDF>(
133 &mut self,
134 rdf: &R,
135 subject: R::Subject,
136 predicate: R::IRI,
137 object: R::Term,
138 ) -> Result<VisualRDFNode, RDFError> {
139 let subject_node = VisualRDFNode::from_subject(rdf, &subject, self)?;
140 self.increment_usage_count_as_subject_in_triple(&subject_node);
141 self.get_or_create_node(subject_node.clone());
142
143 let edge_node = VisualRDFNode::from_predicate(rdf, &predicate);
144 self.increment_usage_count_as_predicate_in_triple(&edge_node);
145 self.get_or_create_node(edge_node.clone());
146
147 let object_node = VisualRDFNode::from_term(rdf, &object, self)?;
148 self.increment_usage_count_as_object_in_triple(&object_node);
149 self.get_or_create_node(object_node.clone());
150
151 let subject_str = subject.to_string();
152 let predicate_str = predicate.to_string();
153 let object_str = object.to_string();
154 let asserted = rdf
155 .contains(&subject, &predicate, &object)
156 .map_err(|e| RDFError::FailedCheckingAssertion {
157 subject: subject_str.to_string(),
158 predicate: predicate_str.to_string(),
159 object: object_str.to_string(),
160 error: e.to_string(),
161 })?;
162 let triple = if asserted {
163 VisualRDFNode::asserted_triple(subject_node, edge_node, object_node)
164 } else {
165 VisualRDFNode::non_asserted_triple(subject_node, edge_node, object_node)
166 };
167 Ok(triple)
168 }
169
170 #[inline]
175 pub fn increment_usage_count_as_subject(&mut self, node: &VisualRDFNode) {
176 let count = self.usage_count.entry(node.clone()).or_default();
177 count.increment_as_subject();
178 }
179
180 #[inline]
185 pub fn increment_usage_count_as_subject_in_triple(&mut self, node: &VisualRDFNode) {
186 let count = self.usage_count.entry(node.clone()).or_default();
187 count.increment_as_subject_in_triple();
188 }
189
190 #[inline]
195 pub fn increment_usage_count_as_predicate(&mut self, node: &VisualRDFNode) {
196 let count = self.usage_count.entry(node.clone()).or_default();
197 count.increment_as_predicate();
198 }
199
200 #[inline]
205 pub fn increment_usage_count_as_predicate_in_triple(&mut self, node: &VisualRDFNode) {
206 let count = self.usage_count.entry(node.clone()).or_default();
207 count.increment_as_predicate_in_triple();
208 }
209
210 #[inline]
215 pub fn increment_usage_count_as_object(&mut self, node: &VisualRDFNode) {
216 let count = self.usage_count.entry(node.clone()).or_default();
217 count.increment_as_object();
218 }
219
220 #[inline]
225 pub fn increment_usage_count_as_object_in_triple(&mut self, node: &VisualRDFNode) {
226 let count = self.usage_count.entry(node.clone()).or_default();
227 count.increment_as_object_in_triple();
228 }
229
230 pub fn get_or_create_node(&mut self, node: VisualRDFNode) -> NodeId {
238 *self.nodes_map.entry(node).or_insert_with(|| {
239 let id = self.node_counter;
240 self.node_counter += 1;
241 NodeId { id }
242 })
243 }
244
245 pub fn get_node_id(&self, node: &VisualRDFNode) -> Result<NodeId, RdfVisualizerError> {
253 match self.nodes_map.get(node) {
254 Some(id) => Ok(*id),
255 None => Err(RdfVisualizerError::NodeNotFound { node: node.clone() }),
256 }
257 }
258
259 pub fn as_plantuml<W: Write>(&self, writer: &mut W, _mode: &UmlGenerationMode) -> Result<(), RdfVisualizerError> {
268 let style = self.config.get_style();
269 writeln!(writer, "@startuml\n")?;
270 writeln!(writer, "{}", style.as_uml())?;
271
272 for (node, node_id) in &self.nodes_map {
274 let show_node = self.show_node(node);
275 let node_uml = node.as_plantuml(*node_id, show_node, self)?;
276 writeln!(writer, "{node_uml}\n")?;
277 }
278 for (source, edge, target) in &self.edges {
280 writeln!(writer, "{source} --> {target} : {}\n", edge.as_plantuml_link())?;
281 }
282
283 for (node, node_id) in &self.nodes_map {
285 match node {
286 VisualRDFNode::NonAssertedTriple(subj, pred, obj) => {
287 triple_term_as_plantuml(writer, self, node_id, subj, pred, obj)?;
288 },
289 VisualRDFNode::AssertedTriple(subj, pred, obj) => {
290 triple_term_as_plantuml(writer, self, node_id, subj, pred, obj)?;
291 },
292 _ => {},
293 }
294 }
295
296 writeln!(writer, "@enduml\n")?;
297 Ok(())
298 }
299
300 pub fn show_node(&self, node: &VisualRDFNode) -> bool {
310 match node {
311 VisualRDFNode::Predicate { .. } | VisualRDFNode::Reifies => match self.usage_count.get(node) {
312 Some(usage_count) => usage_count.in_triple(),
313 None => false,
314 },
315 _ => true,
317 }
318 }
319}
320
321#[derive(Debug, Clone, PartialEq, Eq, Hash, Copy)]
323pub struct NodeId {
324 id: usize,
326}
327
328impl Display for NodeId {
329 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
331 write!(f, "{}", self.id)
332 }
333}
334
335#[derive(Debug, Clone, PartialEq, Eq, Hash, Copy)]
337pub struct EdgeId {
338 id: usize,
340}
341
342impl Display for EdgeId {
343 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
345 write!(f, "{}", self.id)
346 }
347}
348
349impl Display for VisualRDFGraph {
350 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
355 write!(
356 f,
357 "VisualRDFGraph with {} nodes and {} edges",
358 self.nodes_map.len(),
359 self.edges.len()
360 )?;
361 let zero = UsageCount::new();
362 for (node, id) in &self.nodes_map {
363 let count = self.usage_count.get(node).unwrap_or(&zero);
364 write!(f, "\nNode {id}: {node}")?;
365 write!(f, "\n count: {count}")?;
366 }
367 for (source, edge, target) in &self.edges {
368 write!(f, "\nEdge {edge}: {source} --> {target}")?;
369 }
370 Ok(())
371 }
372}
373
374impl UmlConverter for VisualRDFGraph {
375 fn as_plantuml<W: Write>(&self, writer: &mut W, mode: &UmlGenerationMode) -> Result<(), UmlConverterError> {
379 self.as_plantuml(writer, mode)
380 .map_err(|e| UmlConverterError::UmlError { error: e.to_string() })
381 }
382}
383
384fn triple_term_as_plantuml<W: Write>(
400 writer: &mut W,
401 graph: &VisualRDFGraph,
402 triple_id: &NodeId,
403 subj: &VisualRDFNode,
404 pred: &VisualRDFNode,
405 obj: &VisualRDFNode,
406) -> Result<(), RdfVisualizerError> {
407 let subj_id = graph.get_node_id(subj)?;
408 let pred_id = graph.get_node_id(pred)?;
409 let obj_id = graph.get_node_id(obj)?;
410 writeln!(
411 writer,
412 "{triple_id}-->{subj_id} {} : {} \n",
413 graph.config.get_subject_arrow_style().as_plantuml(),
414 graph.config.get_subject_text()
415 )?;
416 writeln!(
417 writer,
418 "{triple_id}-->{pred_id} {} : {}\n",
419 graph.config.get_predicate_arrow_style().as_plantuml(),
420 graph.config.get_predicate_text()
421 )?;
422 writeln!(
423 writer,
424 "{triple_id}-->{obj_id} {} : {}\n",
425 graph.config.get_object_arrow_style().as_plantuml(),
426 graph.config.get_object_text()
427 )?;
428 Ok(())
429}