use alloc::{format, vec, vec::Vec};
use core::error::Error;
use serde_core::{Serialize, Serializer, ser::SerializeMap as _};
use crate::{AttachmentKind, Frame, FrameKind, Report};
struct SerializeAttachment<'a>(&'a Frame);
impl Serialize for SerializeAttachment<'_> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let Self(frame) = self;
match frame.kind() {
FrameKind::Context(_) => {
unimplemented!()
}
FrameKind::Attachment(AttachmentKind::Opaque(_)) => {
unimplemented!()
}
FrameKind::Attachment(AttachmentKind::Printable(attachment)) => {
format!("{attachment}").serialize(serializer)
}
}
}
}
struct SerializeAttachmentList<'a, 'b>(&'a [&'b Frame]);
impl Serialize for SerializeAttachmentList<'_, '_> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.collect_seq(
self.0
.iter()
.copied()
.filter(|attachment| {
!matches!(
attachment.kind(),
FrameKind::Attachment(AttachmentKind::Opaque(_))
)
})
.map(SerializeAttachment),
)
}
}
struct SerializeContext<'a> {
attachments: Vec<&'a Frame>,
context: &'a (dyn Error + Send + Sync + 'static),
sources: &'a [Frame],
}
impl Serialize for SerializeContext<'_> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let Self {
context,
attachments,
sources,
} = self;
let mut map = serializer.serialize_map(Some(3))?;
map.serialize_entry("context", &format!("{context}").as_str())?;
map.serialize_entry("attachments", &SerializeAttachmentList(attachments))?;
map.serialize_entry("sources", &SerializeSources(sources))?;
map.end()
}
}
struct SerializeSources<'a>(&'a [Frame]);
impl Serialize for SerializeSources<'_> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.collect_seq(self.0.iter().flat_map(|source| find_next(&[], source)))
}
}
fn find_next<'a>(head: &[&'a Frame], mut current: &'a Frame) -> Vec<SerializeContext<'a>> {
let mut attachments = vec![];
attachments.extend(head);
loop {
match current.kind() {
FrameKind::Context(context) => {
attachments.reverse();
return vec![SerializeContext {
attachments,
context,
sources: current.sources(),
}];
}
FrameKind::Attachment(_) => match current.sources() {
[] => {
return vec![];
}
[source] => {
attachments.push(current);
current = source;
}
sources => {
attachments.push(current);
return sources
.iter()
.flat_map(|source| find_next(&attachments, source))
.collect();
}
},
}
}
}
impl<C: Error + Send + Sync + 'static> Serialize for Report<C> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
SerializeSources(self.current_frames_unchecked()).serialize(serializer)
}
}
impl<C: Error + Send + Sync + 'static> Serialize for Report<[C]> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
SerializeSources(self.current_frames_unchecked()).serialize(serializer)
}
}