1use super::error::FormatError;
7pub use super::error::SerializeResult;
8use super::format::RdfFormat;
9use crate::model::{Quad, QuadRef, Triple, TripleRef};
10use std::collections::HashMap;
11use std::io::Write;
12
13pub type QuadSerializeResult = SerializeResult<()>;
15
16pub struct WriterQuadSerializer<W: Write> {
18 inner: Box<dyn QuadSerializer<W>>,
19}
20
21impl<W: Write> WriterQuadSerializer<W> {
22 pub fn new(serializer: Box<dyn QuadSerializer<W>>) -> Self {
24 Self { inner: serializer }
25 }
26
27 pub fn serialize_quad<'a>(&mut self, quad: impl Into<QuadRef<'a>>) -> QuadSerializeResult {
29 self.inner.serialize_quad(quad.into())
30 }
31
32 pub fn serialize_triple<'a>(
34 &mut self,
35 triple: impl Into<TripleRef<'a>>,
36 ) -> QuadSerializeResult {
37 let quad = triple.into().in_graph(None);
38 self.serialize_quad(quad)
39 }
40
41 pub fn serialize_quads<I>(&mut self, quads: I) -> QuadSerializeResult
43 where
44 I: IntoIterator,
45 I::Item: Into<QuadRef<'static>>,
46 {
47 for quad in quads {
48 self.inner.serialize_quad(quad.into())?;
49 }
50 Ok(())
51 }
52
53 pub fn finish(self) -> SerializeResult<W> {
55 self.inner.finish()
56 }
57}
58
59pub trait QuadSerializer<W: Write> {
61 fn serialize_quad(&mut self, quad: QuadRef<'_>) -> QuadSerializeResult;
63
64 fn finish(self: Box<Self>) -> SerializeResult<W>;
66}
67
68pub trait QuadSerializerExt<W: Write>: QuadSerializer<W> {
70 fn serialize_quads<I>(&mut self, quads: I) -> QuadSerializeResult
72 where
73 I: IntoIterator,
74 I::Item: Into<QuadRef<'static>>,
75 {
76 for quad in quads {
77 self.serialize_quad(quad.into())?;
78 }
79 Ok(())
80 }
81}
82
83impl<W: Write, T: QuadSerializer<W>> QuadSerializerExt<W> for T {}
85
86pub struct RdfSerializer {
88 format: RdfFormat,
89 base_iri: Option<String>,
90 prefixes: HashMap<String, String>,
91 pretty: bool,
92}
93
94impl RdfSerializer {
95 pub fn new(format: RdfFormat) -> Self {
97 Self {
98 format,
99 base_iri: None,
100 prefixes: HashMap::new(),
101 pretty: false,
102 }
103 }
104
105 pub fn with_base_iri(mut self, base_iri: impl Into<String>) -> Self {
107 self.base_iri = Some(base_iri.into());
108 self
109 }
110
111 pub fn with_prefix(mut self, prefix: impl Into<String>, iri: impl Into<String>) -> Self {
113 self.prefixes.insert(prefix.into(), iri.into());
114 self
115 }
116
117 pub fn pretty(mut self) -> Self {
119 self.pretty = true;
120 self
121 }
122
123 pub fn for_writer<W: Write + 'static>(self, writer: W) -> WriterQuadSerializer<W> {
125 match self.format {
126 RdfFormat::Turtle => self.create_turtle_serializer(writer),
127 RdfFormat::NTriples => self.create_ntriples_serializer(writer),
128 RdfFormat::NQuads => self.create_nquads_serializer(writer),
129 RdfFormat::TriG => self.create_trig_serializer(writer),
130 RdfFormat::RdfXml => self.create_rdfxml_serializer(writer),
131 RdfFormat::JsonLd { .. } => self.create_jsonld_serializer(writer),
132 RdfFormat::N3 => self.create_n3_serializer(writer),
133 }
134 }
135
136 pub fn format(&self) -> RdfFormat {
138 self.format.clone()
139 }
140
141 pub fn base_iri(&self) -> Option<&str> {
143 self.base_iri.as_deref()
144 }
145
146 pub fn prefixes(&self) -> &HashMap<String, String> {
148 &self.prefixes
149 }
150
151 pub fn is_pretty(&self) -> bool {
153 self.pretty
154 }
155
156 fn create_turtle_serializer<W: Write + 'static>(self, writer: W) -> WriterQuadSerializer<W> {
159 let mut turtle_serializer = super::turtle::TurtleSerializer::new();
161
162 if let Some(base) = self.base_iri {
164 turtle_serializer = turtle_serializer.with_base_iri(&base);
165 }
166 for (prefix, iri) in self.prefixes {
167 turtle_serializer = turtle_serializer.with_prefix(&prefix, &iri);
168 }
169 if self.pretty {
170 turtle_serializer = turtle_serializer.pretty();
171 }
172
173 WriterQuadSerializer::new(Box::new(turtle_serializer.for_writer(writer)))
174 }
175
176 fn create_ntriples_serializer<W: Write + 'static>(self, writer: W) -> WriterQuadSerializer<W> {
177 let ntriples_serializer = super::ntriples::NTriplesSerializer::new().for_writer(writer);
179 WriterQuadSerializer::new(Box::new(ntriples_serializer))
180 }
181
182 fn create_nquads_serializer<W: Write + 'static>(self, writer: W) -> WriterQuadSerializer<W> {
183 let nquads_serializer = super::nquads::NQuadsSerializer::new().for_writer(writer);
185 WriterQuadSerializer::new(Box::new(nquads_serializer))
186 }
187
188 fn create_trig_serializer<W: Write + 'static>(self, writer: W) -> WriterQuadSerializer<W> {
189 let mut trig_serializer = super::trig::TriGSerializer::new();
191
192 if let Some(base) = self.base_iri {
194 trig_serializer = trig_serializer.with_base_iri(&base);
195 }
196 for (prefix, iri) in self.prefixes {
197 trig_serializer = trig_serializer.with_prefix(&prefix, &iri);
198 }
199 if self.pretty {
200 trig_serializer = trig_serializer.pretty();
201 }
202
203 WriterQuadSerializer::new(Box::new(trig_serializer.for_writer(writer)))
204 }
205
206 fn create_rdfxml_serializer<W: Write + 'static>(self, writer: W) -> WriterQuadSerializer<W> {
207 let mut rdfxml_serializer = super::rdfxml::RdfXmlSerializer::new();
209
210 if self.pretty {
212 rdfxml_serializer = rdfxml_serializer.pretty();
213 }
214
215 WriterQuadSerializer::new(Box::new(rdfxml_serializer.for_writer(writer)))
216 }
217
218 fn create_jsonld_serializer<W: Write + 'static>(self, writer: W) -> WriterQuadSerializer<W> {
219 let mut jsonld_serializer = super::jsonld::JsonLdSerializer::new();
221
222 if self.pretty {
224 jsonld_serializer = jsonld_serializer.pretty();
225 }
226
227 WriterQuadSerializer::new(Box::new(jsonld_serializer.for_writer(writer)))
228 }
229
230 fn create_n3_serializer<W: Write + 'static>(self, writer: W) -> WriterQuadSerializer<W> {
231 let mut n3_serializer = super::n3::N3Serializer::new();
233
234 if let Some(base) = self.base_iri {
236 n3_serializer = n3_serializer.with_base_iri(&base);
237 }
238 for (prefix, iri) in self.prefixes {
239 n3_serializer = n3_serializer.with_prefix(&prefix, &iri);
240 }
241 if self.pretty {
242 n3_serializer = n3_serializer.pretty();
243 }
244
245 WriterQuadSerializer::new(Box::new(n3_serializer.for_writer(writer)))
246 }
247}
248
249impl Default for RdfSerializer {
250 fn default() -> Self {
251 Self::new(RdfFormat::default())
252 }
253}
254
255#[derive(Debug, Clone)]
257pub struct SerializeConfig {
258 pub compact: bool,
260 pub indent: String,
262 pub line_ending: LineEnding,
264 pub max_line_length: Option<usize>,
266 pub sort_output: bool,
268 pub include_comments: bool,
270 pub validate_output: bool,
272}
273
274#[derive(Debug, Clone, PartialEq, Eq)]
276pub enum LineEnding {
277 Unix,
279 Windows,
281 Mac,
283 Platform,
285}
286
287impl Default for SerializeConfig {
288 fn default() -> Self {
289 Self {
290 compact: false,
291 indent: " ".to_string(),
292 line_ending: LineEnding::Platform,
293 max_line_length: None,
294 sort_output: false,
295 include_comments: false,
296 validate_output: true,
297 }
298 }
299}
300
301impl LineEnding {
302 pub fn as_str(&self) -> &'static str {
304 match self {
305 Self::Unix => "\n",
306 Self::Windows => "\r\n",
307 Self::Mac => "\r",
308 Self::Platform => {
309 #[cfg(windows)]
310 return "\r\n";
311 #[cfg(not(windows))]
312 return "\n";
313 }
314 }
315 }
316}
317
318pub struct ConfigurableSerializer {
320 serializer: RdfSerializer,
321 config: SerializeConfig,
322}
323
324impl ConfigurableSerializer {
325 pub fn new(format: RdfFormat, config: SerializeConfig) -> Self {
327 Self {
328 serializer: RdfSerializer::new(format),
329 config,
330 }
331 }
332
333 pub fn with_base_iri(mut self, base_iri: impl Into<String>) -> Self {
335 self.serializer = self.serializer.with_base_iri(base_iri);
336 self
337 }
338
339 pub fn with_prefix(mut self, prefix: impl Into<String>, iri: impl Into<String>) -> Self {
341 self.serializer = self.serializer.with_prefix(prefix, iri);
342 self
343 }
344
345 pub fn for_writer<W: Write + 'static>(self, writer: W) -> WriterQuadSerializer<W> {
347 let mut serializer = self.serializer;
349
350 if !self.config.compact {
352 serializer = serializer.pretty();
353 }
354
355 serializer.for_writer(writer)
368 }
369
370 pub fn config(&self) -> &SerializeConfig {
372 &self.config
373 }
374
375 pub fn serializer(&self) -> &RdfSerializer {
377 &self.serializer
378 }
379}
380
381pub mod simple {
383 use super::*;
384
385 pub fn serialize_triples_to_string(
387 triples: &[Triple],
388 format: RdfFormat,
389 ) -> Result<String, FormatError> {
390 let buffer = Vec::new();
391 let mut serializer = RdfSerializer::new(format).for_writer(buffer);
392 for triple in triples {
393 serializer.serialize_triple(triple.as_ref())?;
394 }
395 let buffer = serializer.finish()?;
396 String::from_utf8(buffer).map_err(|e| FormatError::invalid_data(e.to_string()))
397 }
398
399 pub fn serialize_quads_to_string(
401 quads: &[Quad],
402 format: RdfFormat,
403 ) -> Result<String, FormatError> {
404 let buffer = Vec::new();
405 let mut serializer = RdfSerializer::new(format).for_writer(buffer);
406 for quad in quads {
407 serializer.serialize_quad(quad.as_ref())?;
408 }
409 let buffer = serializer.finish()?;
410 String::from_utf8(buffer).map_err(|e| FormatError::invalid_data(e.to_string()))
411 }
412
413 pub fn serialize_turtle(triples: &[Triple]) -> Result<String, FormatError> {
415 serialize_triples_to_string(triples, RdfFormat::Turtle)
416 }
417
418 pub fn serialize_ntriples(triples: &[Triple]) -> Result<String, FormatError> {
420 serialize_triples_to_string(triples, RdfFormat::NTriples)
421 }
422
423 pub fn serialize_nquads(quads: &[Quad]) -> Result<String, FormatError> {
425 serialize_quads_to_string(quads, RdfFormat::NQuads)
426 }
427
428 pub fn serialize_trig(quads: &[Quad]) -> Result<String, FormatError> {
430 serialize_quads_to_string(quads, RdfFormat::TriG)
431 }
432}
433
434#[cfg(test)]
435mod tests {
436 use super::*;
437
438 #[test]
439 fn test_serializer_creation() {
440 let serializer = RdfSerializer::new(RdfFormat::Turtle);
441 assert_eq!(serializer.format(), RdfFormat::Turtle);
442 assert!(serializer.base_iri().is_none());
443 assert!(serializer.prefixes().is_empty());
444 assert!(!serializer.is_pretty());
445 }
446
447 #[test]
448 fn test_serializer_configuration() {
449 let serializer = RdfSerializer::new(RdfFormat::Turtle)
450 .with_base_iri("http://example.org/")
451 .with_prefix("ex", "http://example.org/ns#")
452 .pretty();
453
454 assert_eq!(serializer.base_iri(), Some("http://example.org/"));
455 assert_eq!(
456 serializer.prefixes().get("ex"),
457 Some(&"http://example.org/ns#".to_string())
458 );
459 assert!(serializer.is_pretty());
460 }
461
462 #[test]
463 fn test_configurable_serializer() {
464 let config = SerializeConfig {
465 compact: true,
466 sort_output: true,
467 ..Default::default()
468 };
469
470 let serializer = ConfigurableSerializer::new(RdfFormat::NQuads, config);
471 assert!(serializer.config().compact);
472 assert!(serializer.config().sort_output);
473 }
474
475 #[test]
476 fn test_serialize_config_default() {
477 let config = SerializeConfig::default();
478 assert!(!config.compact);
479 assert_eq!(config.indent, " ");
480 assert_eq!(config.line_ending, LineEnding::Platform);
481 assert_eq!(config.max_line_length, None);
482 assert!(!config.sort_output);
483 assert!(!config.include_comments);
484 assert!(config.validate_output);
485 }
486
487 #[test]
488 fn test_line_ending() {
489 assert_eq!(LineEnding::Unix.as_str(), "\n");
490 assert_eq!(LineEnding::Windows.as_str(), "\r\n");
491 assert_eq!(LineEnding::Mac.as_str(), "\r");
492 }
494}