wayver's git archive


an obsidian renderer
git clone https://git.wayver.dev/sable

sable-canvas/src/edge.rs@2b84405277e54ab809e328cf0237374d4b4dbd0c

raw
Date Commit Message Author Files + -
2026-02-23 01:55 initial mvp wayverd 139 17808 0
...

1use crate::{EdgeId, NodeId, color::Color};
2
3/// The connection information of the start or end of an [`Edge`].
4pub type Terminus = (NodeId, Option<Side>, Option<End>);
5
6/// A connection between two [`Node`]s.
7///
8/// [`Node`]: crate::Node
9#[derive(Debug, serde::Serialize, serde::Deserialize)]
10#[serde(rename_all = "camelCase")]
11pub struct Edge {
12    /// The unique ID of this [`Edge`].
13    pub id: EdgeId,
14    /// The [`Node`] this [`Edge`] starts at.
15    ///
16    /// [`Node`]: crate::Node
17    pub from_node: NodeId,
18    #[serde(skip_serializing_if = "Option::is_none")]
19    from_side: Option<Side>,
20    #[serde(skip_serializing_if = "Option::is_none")]
21    from_end: Option<End>,
22    /// The [`Node`] this [`Edge`] ends at.
23    ///
24    /// [`Node`]: crate::Node
25    pub to_node: NodeId,
26    #[serde(skip_serializing_if = "Option::is_none")]
27    to_side: Option<Side>,
28    #[serde(skip_serializing_if = "Option::is_none")]
29    to_end: Option<End>,
30    #[serde(skip_serializing_if = "Option::is_none")]
31    color: Option<Color>,
32    #[serde(skip_serializing_if = "Option::is_none")]
33    label: Option<String>,
34}
35
36impl Edge {
37    /// Creates a new [`Edge`].
38    #[allow(clippy::too_many_arguments)]
39    #[must_use]
40    pub const fn new(
41        id: EdgeId,
42        from_node: NodeId,
43        from_side: Option<Side>,
44        from_end: Option<End>,
45        to_node: NodeId,
46        to_side: Option<Side>,
47        to_end: Option<End>,
48        color: Option<Color>,
49        label: Option<String>,
50    ) -> Self {
51        Self {
52            id,
53            from_node,
54            from_side,
55            from_end,
56            to_node,
57            to_side,
58            to_end,
59            color,
60            label,
61        }
62    }
63
64    /// Returns a reference to the id of this [`Edge`].
65    #[must_use]
66    pub const fn id(&self) -> &EdgeId {
67        &self.id
68    }
69
70    /// Returns the sources's [`NodeId`] of this [`Edge`].
71    #[must_use]
72    pub const fn from_node(&self) -> &NodeId {
73        &self.from_node
74    }
75
76    /// Returns the sources's [`Side`] of this [`Edge`].
77    #[must_use]
78    pub const fn from_side(&self) -> Option<&Side> {
79        self.from_side.as_ref()
80    }
81
82    /// Returns the sources's [`End`] of this [`Edge`].
83    #[must_use]
84    pub const fn from_end(&self) -> Option<&End> {
85        self.from_end.as_ref()
86    }
87
88    /// Returns the target's [`NodeId`] of this [`Edge`].
89    #[must_use]
90    pub const fn to_node(&self) -> &NodeId {
91        &self.to_node
92    }
93
94    /// Returns the target's [`Side`] of this [`Edge`].
95    #[must_use]
96    pub const fn to_side(&self) -> Option<&Side> {
97        self.to_side.as_ref()
98    }
99
100    /// Returns the target's [`End`] of this [`Edge`].
101    #[must_use]
102    pub const fn to_end(&self) -> Option<&End> {
103        self.to_end.as_ref()
104    }
105
106    /// Returns the color of this [`Edge`].
107    #[must_use]
108    pub const fn color(&self) -> Option<&Color> {
109        self.color.as_ref()
110    }
111
112    /// Returns the label of this [`Edge`].
113    #[must_use]
114    pub const fn label(&self) -> Option<&String> {
115        self.label.as_ref()
116    }
117
118    /// Sets the color of this [`Edge`].
119    pub const fn set_color(&mut self, color: Color) -> &mut Self {
120        self.color = Some(color);
121        self
122    }
123
124    /// Remove color of this [`Edge`].
125    pub fn remove_color(&mut self) -> Option<Color> {
126        std::mem::take(&mut self.color)
127    }
128
129    /// Sets the label of this [`Edge`].
130    pub fn set_label(&mut self, label: String) -> &mut Self {
131        self.label = Some(label);
132        self
133    }
134
135    /// Removes the label from this [`Edge`].
136    pub fn remove_label(&mut self) -> Option<String> {
137        std::mem::take(&mut self.label)
138    }
139
140    /// Set the start connection of this [`Edge`], returning the old connection information.
141    pub const fn set_from(
142        &mut self,
143        node: NodeId,
144        side: Option<Side>,
145        end: Option<End>,
146    ) -> Terminus {
147        (
148            std::mem::replace(&mut self.from_node, node),
149            std::mem::replace(&mut self.from_side, side),
150            std::mem::replace(&mut self.from_end, end),
151        )
152    }
153
154    /// Set the end connection of this [`Edge`], returning the old connection information.
155    pub const fn set_to(&mut self, node: NodeId, side: Option<Side>, end: Option<End>) -> Terminus {
156        (
157            std::mem::replace(&mut self.to_node, node),
158            std::mem::replace(&mut self.to_side, side),
159            std::mem::replace(&mut self.to_end, end),
160        )
161    }
162}
163
164/// The side where the [`Edge`] conntects to the [`Node`].
165///
166/// [`Node`]: crate::Node
167#[allow(missing_docs)]
168#[derive(
169    Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, serde::Serialize, serde::Deserialize,
170)]
171#[serde(rename_all = "camelCase")]
172pub enum Side {
173    Top,
174    Left,
175    Right,
176    Bottom,
177}
178
179/// The shape of the [`Edge`] connection from [`Edge`] to [`Node`].
180///
181/// [`Node`]: crate::Node
182#[allow(missing_docs)]
183#[derive(
184    Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, serde::Serialize, serde::Deserialize,
185)]
186#[serde(rename_all = "camelCase")]
187pub enum End {
188    None,
189    Arrow,
190}
191