Skip to main content

rdf_types/
pattern.rs

1//! Triple/quad patterns, used to describe a set of triples/quads by leaving
2//! some of their components unspecified (variables).
3use std::ops::Deref;
4
5use into_owned_trait::IntoOwned;
6
7use crate::{Quad, Triple};
8
9/// Triple pattern, with each component either a ground resource or a
10/// variable.
11pub type TriplePattern<T, X> = Triple<Pattern<T, X>>;
12
13/// Quad pattern, with each component either a ground resource or a
14/// variable.
15pub type QuadPattern<T, X> = Quad<Pattern<T, X>>;
16
17/// Linear triple pattern, with each component either a ground resource
18/// (`Some`) or unconstrained (`None`).
19///
20/// Unlike [`TriplePattern`], a linear pattern cannot bind the same variable
21/// to more than one component, hence the name: it does not encode a general
22/// [`Pattern`] graph, only affine constraints on each component
23/// independently.
24pub type LinearTriplePattern<T> = Triple<Option<T>>;
25
26impl<T> From<Triple<T>> for LinearTriplePattern<T> {
27	/// Turns a triple into the linear pattern matching only that triple.
28	fn from(value: Triple<T>) -> Self {
29		value.map(Some)
30	}
31}
32
33/// Linear quad pattern, with each component either a ground resource
34/// (`Some`) or unconstrained (`None`).
35///
36/// See [`LinearTriplePattern`] for details on what makes a pattern "linear".
37pub type LinearQuadPattern<T> = Quad<Option<T>>;
38
39impl<T> From<Quad<T>> for LinearQuadPattern<T> {
40	/// Turns a quad into the linear pattern matching only that quad.
41	fn from(value: Quad<T>) -> Self {
42		value.map(Some)
43	}
44}
45
46/// Resource or variable.
47///
48/// Used as a triple/quad component to represent either a fixed
49/// (`Ground`) resource, or a `Var`iable that may be substituted for any
50/// resource.
51#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
52#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
53pub enum Pattern<T, X> {
54	/// Ground (fixed) resource.
55	Ground(T),
56
57	/// Variable, matching any resource.
58	Var(X),
59}
60
61impl<T, X> Pattern<T, X> {
62	/// Borrows the ground value or variable of this pattern.
63	pub fn as_ref(&self) -> Pattern<&T, &X> {
64		match self {
65			Self::Ground(t) => Pattern::Ground(t),
66			Self::Var(x) => Pattern::Var(x),
67		}
68	}
69
70	/// Dereferences the ground value or variable of this pattern.
71	pub fn as_deref(&self) -> Pattern<&T::Target, &X::Target>
72	where
73		T: Deref,
74		X: Deref,
75	{
76		match self {
77			Self::Ground(t) => Pattern::Ground(t),
78			Self::Var(x) => Pattern::Var(x),
79		}
80	}
81
82	/// Checks if this pattern is a ground value (as opposed to a variable).
83	pub fn is_ground(&self) -> bool {
84		matches!(self, Self::Ground(_))
85	}
86
87	/// Returns `true` if this pattern is a ground value satisfying the given
88	/// predicate, and `false` if it is a variable.
89	pub fn is_ground_and(&self, f: impl FnOnce(&T) -> bool) -> bool {
90		match self {
91			Self::Ground(t) => f(t),
92			Self::Var(_) => false,
93		}
94	}
95
96	/// Checks if this pattern is a variable (as opposed to a ground value).
97	pub fn is_var(&self) -> bool {
98		matches!(self, Self::Var(_))
99	}
100
101	/// Returns `true` if this pattern is a variable satisfying the given
102	/// predicate, and `false` if it is a ground value.
103	pub fn is_var_and(&self, f: impl FnOnce(&X) -> bool) -> bool {
104		match self {
105			Self::Ground(_) => false,
106			Self::Var(x) => f(x),
107		}
108	}
109
110	/// Returns `true` if this pattern is a ground value, or if it is a
111	/// variable satisfying the given predicate.
112	///
113	/// Mirrors [`Option::is_none_or`], with [`Self::Ground`] playing the role
114	/// of [`None`].
115	pub fn is_ground_or(&self, f: impl FnOnce(&X) -> bool) -> bool {
116		match self {
117			Self::Ground(_) => true,
118			Self::Var(x) => f(x),
119		}
120	}
121
122	/// Returns `true` if this pattern is a variable, or if it is a ground
123	/// value satisfying the given predicate.
124	///
125	/// Mirrors [`Option::is_none_or`], with [`Self::Var`] playing the role of
126	/// [`None`].
127	pub fn is_var_or(&self, f: impl FnOnce(&T) -> bool) -> bool {
128		match self {
129			Self::Ground(t) => f(t),
130			Self::Var(_) => true,
131		}
132	}
133
134	/// Maps the ground value with the given function, leaving a variable
135	/// untouched.
136	pub fn map<U>(self, f: impl FnOnce(T) -> U) -> Pattern<U, X> {
137		match self {
138			Self::Ground(t) => Pattern::Ground(f(t)),
139			Self::Var(x) => Pattern::Var(x),
140		}
141	}
142
143	/// Maps the variable with the given function, leaving a ground value
144	/// untouched.
145	pub fn map_var<Y>(self, f: impl FnOnce(X) -> Y) -> Pattern<T, Y> {
146		match self {
147			Self::Ground(t) => Pattern::Ground(t),
148			Self::Var(x) => Pattern::Var(f(x)),
149		}
150	}
151}
152
153impl<T, X> From<T> for Pattern<T, X> {
154	/// Creates a ground pattern from a resource.
155	fn from(value: T) -> Self {
156		Self::Ground(value)
157	}
158}
159
160impl<T, X> IntoOwned for Pattern<T, X>
161where
162	T: IntoOwned,
163	X: IntoOwned,
164{
165	type Owned = Pattern<T::Owned, X::Owned>;
166
167	fn into_owned(self) -> Self::Owned {
168		match self {
169			Self::Ground(t) => Pattern::Ground(t.into_owned()),
170			Self::Var(x) => Pattern::Var(x.into_owned()),
171		}
172	}
173}
174
175impl<T, X> AsPattern for Pattern<T, X> {
176	type Ground = T;
177	type Var = X;
178
179	fn as_pattern(&self) -> Pattern<&T, &X> {
180		self.as_ref()
181	}
182}
183
184/// Value that can be seen as a [`Pattern`], either a ground value or a
185/// variable.
186///
187/// Implemented by [`Pattern`] itself. Resource types implementing this trait
188/// can be used with [`crate::find_bijection`] to find a blank
189/// node/variable-preserving bijection between two datasets.
190pub trait AsPattern {
191	/// Ground value type.
192	type Ground: ?Sized;
193
194	/// Variable type.
195	type Var: ?Sized;
196
197	/// Borrows this value as a [`Pattern`].
198	fn as_pattern(&self) -> Pattern<&Self::Ground, &Self::Var>;
199
200	/// Checks if this value is a ground value (as opposed to a variable).
201	fn is_ground(&self) -> bool {
202		self.as_pattern().is_ground()
203	}
204
205	/// Returns `true` if this value is a ground value satisfying the given
206	/// predicate, and `false` if it is a variable.
207	fn is_ground_and(&self, f: impl FnOnce(&Self::Ground) -> bool) -> bool {
208		match self.as_pattern() {
209			Pattern::Ground(t) => f(t),
210			Pattern::Var(_) => false,
211		}
212	}
213
214	/// Checks if this value is a variable (as opposed to a ground value).
215	fn is_var(&self) -> bool {
216		self.as_pattern().is_var()
217	}
218
219	/// Returns `true` if this value is a variable satisfying the given
220	/// predicate, and `false` if it is a ground value.
221	fn is_var_and(&self, f: impl FnOnce(&Self::Var) -> bool) -> bool {
222		match self.as_pattern() {
223			Pattern::Ground(_) => false,
224			Pattern::Var(x) => f(x),
225		}
226	}
227
228	/// Returns `true` if this value is a ground value, or if it is a
229	/// variable satisfying the given predicate.
230	fn is_ground_or(&self, f: impl FnOnce(&Self::Var) -> bool) -> bool {
231		match self.as_pattern() {
232			Pattern::Ground(_) => true,
233			Pattern::Var(x) => f(x),
234		}
235	}
236
237	/// Returns `true` if this value is a variable, or if it is a ground
238	/// value satisfying the given predicate.
239	fn is_var_or(&self, f: impl FnOnce(&Self::Ground) -> bool) -> bool {
240		match self.as_pattern() {
241			Pattern::Ground(t) => f(t),
242			Pattern::Var(_) => true,
243		}
244	}
245}