gml_parser/
gml.rs

1/*!
2Object types that represent a parsed GML graph.
3*/
4
5use std::borrow::Cow;
6use std::collections::HashMap;
7
8/// An item that represents a key-value pair. For example, `node [ ... ]`, `directed 0`,
9/// `label "abc"`, etc.
10#[derive(Debug, Clone, PartialEq)]
11pub enum GmlItem<'a> {
12    Node(Node<'a>),
13    Edge(Edge<'a>),
14    Directed(bool),
15    KeyValue((Cow<'a, str>, Value<'a>)),
16}
17
18impl GmlItem<'_> {
19    /// Convert any borrowed references to owned values.
20    pub fn upgrade_to_owned(&self) -> GmlItem<'static> {
21        match self {
22            Self::Node(node) => GmlItem::Node(node.upgrade_to_owned()),
23            Self::Edge(edge) => GmlItem::Edge(edge.upgrade_to_owned()),
24            Self::Directed(directed) => GmlItem::Directed(*directed),
25            Self::KeyValue((name, value)) => GmlItem::KeyValue((
26                Cow::Owned(name.clone().into_owned()),
27                value.upgrade_to_owned(),
28            )),
29        }
30    }
31}
32
33/// A graph node with an `id` and `other` key-value pairs.
34#[derive(Debug, Clone, PartialEq)]
35pub struct Node<'a> {
36    pub id: Option<u32>,
37    pub other: HashMap<Cow<'a, str>, Value<'a>>,
38}
39
40impl<'a> Node<'a> {
41    pub fn new<K>(id: Option<u32>, other: HashMap<K, Value<'a>>) -> Self
42    where
43        K: Into<Cow<'a, str>>,
44    {
45        let other = other.into_iter().map(|(k, v)| (k.into(), v)).collect();
46        Self { id, other }
47    }
48
49    /// Convert any borrowed references to owned values.
50    pub fn upgrade_to_owned(&self) -> Node<'static> {
51        Node {
52            id: self.id,
53            other: self
54                .other
55                .iter()
56                .map(|(k, v)| (Cow::Owned(k.clone().into_owned()), v.upgrade_to_owned()))
57                .collect(),
58        }
59    }
60}
61
62/// A graph edge from node `source` to node `target` with `other` key-value pairs.
63#[derive(Debug, Clone, PartialEq)]
64pub struct Edge<'a> {
65    pub source: u32,
66    pub target: u32,
67    pub other: HashMap<Cow<'a, str>, Value<'a>>,
68}
69
70impl<'a> Edge<'a> {
71    pub fn new<K>(source: u32, target: u32, other: HashMap<K, Value<'a>>) -> Self
72    where
73        K: Into<Cow<'a, str>>,
74    {
75        let other = other.into_iter().map(|(k, v)| (k.into(), v)).collect();
76        Self {
77            source,
78            target,
79            other,
80        }
81    }
82
83    /// Convert any borrowed references to owned values.
84    pub fn upgrade_to_owned(&self) -> Edge<'static> {
85        Edge {
86            source: self.source,
87            target: self.target,
88            other: self
89                .other
90                .iter()
91                .map(|(k, v)| (Cow::Owned(k.clone().into_owned()), v.upgrade_to_owned()))
92                .collect(),
93        }
94    }
95}
96
97/// The base value types supported by GML.
98#[derive(Debug, Clone, PartialEq)]
99pub enum Value<'a> {
100    Int(i32),
101    Float(f32),
102    Str(Cow<'a, str>),
103}
104
105impl<'a> Value<'a> {
106    /// Returns a string if the value is a string. Otherwise returns `None`.
107    pub fn as_str(self) -> Option<Cow<'a, str>> {
108        if let Self::Str(s) = self {
109            return Some(s);
110        }
111        None
112    }
113
114    /// Returns a float if the value is a float. Otherwise returns `None`.
115    pub fn as_float(self) -> Option<f32> {
116        if let Self::Float(f) = self {
117            return Some(f);
118        }
119        None
120    }
121
122    /// Convert any borrowed references to owned values.
123    pub fn upgrade_to_owned(&self) -> Value<'static> {
124        match self {
125            Self::Int(x) => Value::Int(*x),
126            Self::Float(x) => Value::Float(*x),
127            Self::Str(s) => Value::Str(Cow::Owned(s.clone().into_owned())),
128        }
129    }
130}
131
132/// A GML graph.
133#[derive(Debug, PartialEq)]
134pub struct Gml<'a> {
135    pub directed: bool,
136    pub nodes: Vec<Node<'a>>,
137    pub edges: Vec<Edge<'a>>,
138    pub other: HashMap<Cow<'a, str>, Value<'a>>,
139}
140
141impl Gml<'_> {
142    /// Convert any borrowed references to owned values.
143    pub fn upgrade_to_owned(&self) -> Gml<'static> {
144        Gml {
145            directed: self.directed,
146            nodes: self.nodes.iter().map(|n| n.upgrade_to_owned()).collect(),
147            edges: self.edges.iter().map(|e| e.upgrade_to_owned()).collect(),
148            other: self
149                .other
150                .iter()
151                .map(|(k, v)| (Cow::Owned(k.clone().into_owned()), v.upgrade_to_owned()))
152                .collect(),
153        }
154    }
155}
156
157#[cfg(test)]
158mod tests {
159    use super::*;
160
161    #[test]
162    fn upgrade_to_owned() {
163        let node;
164        {
165            // a string with a short lifetime
166            let local_str = "abc".to_string();
167
168            let mut node_options = HashMap::new();
169            node_options.insert(&local_str, Value::Int(5));
170            let node_with_reference = Node::new(Some(0), node_options);
171
172            node = node_with_reference.upgrade_to_owned();
173        }
174
175        println!("{:?}", node);
176    }
177}