Skip to main content

rdf_syntax/
display.rs

1use std::fmt;
2
3use langtag::{LangTag, LangTagBuf};
4use rdf_types::{
5	BTreeDataset, BTreeGraph, IndexedBTreeDataset, IndexedBTreeGraph,
6	diff::{ColoredRdfDiff, RdfDiff},
7};
8
9/// Display method for RDF syntax elements.
10pub trait RdfDisplay {
11	/// Formats the value using the given formatter.
12	fn rdf_fmt(&self, f: &mut fmt::Formatter) -> fmt::Result;
13
14	/// Prepare the value to be formatted as an RDF syntax element.
15	#[inline(always)]
16	fn rdf_display(&self) -> RdfDisplayed<&Self> {
17		RdfDisplayed(self)
18	}
19}
20
21impl RdfDisplay for str {
22	fn rdf_fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
23		use fmt::Display;
24		write!(f, "\"")?;
25
26		for c in self.chars() {
27			match c {
28				// Characters that MUST be encoded using `ECHAR`.
29				// See: <https://www.w3.org/TR/rdf-canon/#canon-nquads>
30				'\u{8}' => write!(f, "\\b"), // backspace
31				'\t' => write!(f, "\\t"),
32				'\n' => write!(f, "\\n"),
33				'\u{c}' => write!(f, "\\f"), // form feed
34				'\r' => write!(f, "\\r"),
35				'"' => write!(f, "\\\""),
36				'\\' => write!(f, "\\\\"),
37				// Characters that MUST be encoded using `UCHAR`, using a
38				// lowercase `\u` followed by 4 uppercase hexadecimal digits.
39				'\u{0}'..='\u{7}'
40				| '\u{b}' // vertical tab
41				| '\u{e}'..='\u{1f}'
42				| '\u{7f}' // delete
43				| '\u{fffe}'
44				| '\u{ffff}' => write!(f, "\\u{:04X}", c as u32),
45				c => c.fmt(f),
46			}?
47		}
48
49		write!(f, "\"")
50	}
51}
52
53impl RdfDisplay for String {
54	fn rdf_fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
55		self.as_str().rdf_fmt(f)
56	}
57}
58
59impl RdfDisplay for iref::IriRef {
60	fn rdf_fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
61		write!(f, "<")?;
62
63		for c in self.as_str().chars() {
64			match c {
65				'\x00'..='\x20' | '<' | '>' | '"' | '{' | '}' | '|' | '^' | '`' | '\\' => {
66					write!(f, "\\u{:04X}", c as u32)
67				}
68				_ => fmt::Display::fmt(&c, f),
69			}?;
70		}
71
72		write!(f, ">")
73	}
74}
75
76impl RdfDisplay for iref::Iri {
77	#[inline(always)]
78	fn rdf_fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
79		self.as_iri_ref().rdf_fmt(f)
80	}
81}
82
83impl RdfDisplay for iref::IriBuf {
84	#[inline(always)]
85	fn rdf_fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
86		self.as_iri_ref().rdf_fmt(f)
87	}
88}
89
90impl RdfDisplay for iref::IriRefBuf {
91	#[inline(always)]
92	fn rdf_fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
93		self.as_iri_ref().rdf_fmt(f)
94	}
95}
96
97impl RdfDisplay for LangTag {
98	fn rdf_fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
99		use fmt::Display;
100		self.as_str().fmt(f)
101	}
102}
103
104impl RdfDisplay for LangTagBuf {
105	fn rdf_fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
106		use fmt::Display;
107		self.as_str().fmt(f)
108	}
109}
110
111impl<T: RdfDisplay + ?Sized> RdfDisplay for &T {
112	#[inline(always)]
113	fn rdf_fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
114		T::rdf_fmt(*self, f)
115	}
116}
117
118/// Value ready to be formatted as an RDF syntax element.
119pub struct RdfDisplayed<T>(T);
120
121impl<T: RdfDisplay> fmt::Display for RdfDisplayed<T> {
122	#[inline(always)]
123	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
124		self.0.rdf_fmt(f)
125	}
126}
127
128impl<R: RdfDisplay> RdfDisplay for BTreeGraph<R> {
129	fn rdf_fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
130		for t in self {
131			writeln!(f, "{} .", t.rdf_display())?;
132		}
133
134		Ok(())
135	}
136}
137
138impl<R: RdfDisplay> RdfDisplay for IndexedBTreeGraph<R> {
139	fn rdf_fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
140		for t in self {
141			writeln!(f, "{} .", t.rdf_display())?;
142		}
143
144		Ok(())
145	}
146}
147
148impl<R: RdfDisplay> RdfDisplay for BTreeDataset<R> {
149	fn rdf_fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
150		for t in self {
151			writeln!(f, "{} .", t.rdf_display())?;
152		}
153
154		Ok(())
155	}
156}
157
158impl<R: RdfDisplay> RdfDisplay for IndexedBTreeDataset<R> {
159	fn rdf_fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
160		for t in self {
161			writeln!(f, "{} .", t.rdf_display())?;
162		}
163
164		Ok(())
165	}
166}
167
168impl<R: RdfDisplay> RdfDisplay for RdfDiff<R> {
169	fn rdf_fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
170		for quad in &self.added {
171			writeln!(f, "+ {} .", quad.rdf_display())?;
172		}
173
174		for quad in &self.removed {
175			writeln!(f, "- {} .", quad.rdf_display())?;
176		}
177
178		Ok(())
179	}
180}
181
182impl<'a, R: RdfDisplay> RdfDisplay for ColoredRdfDiff<'a, R> {
183	fn rdf_fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
184		for quad in &self.0.added {
185			writeln!(f, "\x1b[32m+ {} .\x1b[0m", quad.rdf_display())?;
186		}
187
188		for quad in &self.0.removed {
189			writeln!(f, "\x1b[31m- {} .\x1b[0m", quad.rdf_display())?;
190		}
191
192		Ok(())
193	}
194}