use sophia_api::quad::Quad;
use sophia_api::serializer::{QuadSerializer, Stringifier};
use sophia_api::source::StreamResult;
use sophia_api::source::{QuadSource, SinkError, StreamResultExt};
use sophia_api::term::{SimpleTerm, Term};
use std::io;
use crate::serializer::_streaming::StreamingSerializerState;
use super::_pretty::*;
pub type TriGConfig = super::turtle::TurtleConfig;
#[deprecated(since = "0.10.0", note = "please use TriGConfig instead")]
pub type TrigConfig = TriGConfig;
#[deprecated(since = "0.10.0", note = "please use TriGSerializer instead")]
pub type TrigSerializer<W> = TriGSerializer<W>;
pub struct TriGSerializer<W> {
pub(super) config: TriGConfig,
pub(super) write: W,
}
impl<W> TriGSerializer<W>
where
W: io::Write,
{
#[inline]
pub fn new(write: W) -> Self {
Self::new_with_config(write, TriGConfig::default())
}
#[inline]
pub const fn new_with_config(write: W, config: TriGConfig) -> Self {
Self { config, write }
}
#[inline]
pub const fn config(&self) -> &TriGConfig {
&self.config
}
}
impl<W> QuadSerializer for TriGSerializer<W>
where
W: io::Write,
{
type Error = io::Error;
fn serialize_quads<TS>(
&mut self,
mut source: TS,
) -> StreamResult<&mut Self, TS::Error, Self::Error>
where
TS: QuadSource,
{
if self.config.pretty {
let dataset = source
.collect_quads::<PrettifiableDataset>()
.map_sink_err(|_| -> io::Error { unreachable!() })?;
prettify(dataset, &mut self.write, &self.config, "").map_err(SinkError)?;
} else {
for (prefix, ns) in &self.config.prefix_map {
writeln!(&mut self.write, "PREFIX {}: <{ns}>", prefix.as_str())
.map_err(SinkError)?;
}
let mut current_graph: Option<SimpleTerm<'static>> = None;
let mut state = StreamingSerializerState::new(&mut self.write, &self.config);
source.try_for_each_quad(|q| {
match (¤t_graph, q.g()) {
(None, None) => {}
(Some(_), None) => {
if state.has_s() {
state.write_all(b".\n")?;
}
state.write_all(b"\n}\n")?;
state.pop_all();
current_graph.take();
}
(_, Some(gnq)) => {
let change = current_graph
.as_ref()
.map(|gnc| !Term::eq(gnc, gnq))
.unwrap_or(true);
if change {
if state.has_s() {
state.write_all(b".\n")?;
}
state.write_all(b"\n")?;
if current_graph.is_some() {
state.write_all(b"}\n")?;
}
state.write_all(b"\nGRAPH ")?;
state.write_node(gnq)?;
state.write_all(b" {\n")?;
state.pop_all();
current_graph = q.g().map(|t| t.into_term())
}
}
}
state.write_asserted_triple(q.spog().0)
})?;
if state.has_s() {
state.write_all(b".\n").map_err(SinkError)?;
}
if current_graph.is_some() {
state.write_all(b"}\n").map_err(SinkError)?;
}
}
Ok(self)
}
}
impl TriGSerializer<Vec<u8>> {
#[inline]
pub fn new_stringifier() -> Self {
Self::new(Vec::new())
}
#[inline]
pub const fn new_stringifier_with_config(config: TriGConfig) -> Self {
Self::new_with_config(Vec::new(), config)
}
}
impl Stringifier for TriGSerializer<Vec<u8>> {
fn as_utf8(&self) -> &[u8] {
&self.write[..]
}
}
#[cfg(test)]
mod test;