use std::borrow::Cow;
use super::NativeRecord;
use crate::document::CadIr;
use crate::unknown::UnknownRecord;
#[derive(Clone, Copy)]
pub(crate) enum NativeEntity<'a> {
Product(&'a NativeRecord),
Source(&'a UnknownRecord),
}
impl<'a> NativeEntity<'a> {
pub(crate) fn id(self) -> &'a str {
match self {
Self::Product(record) => record.id(),
Self::Source(record) => record.id().as_str(),
}
}
pub(crate) fn links(self) -> impl Iterator<Item = Cow<'a, str>> {
let product = match self {
Self::Product(record) => match record.field("links") {
Some(serde_json::Value::Array(links)) => links,
_ => Vec::new(),
},
Self::Source(_) => Vec::new(),
};
let source = match self {
Self::Source(record) => record.links(),
Self::Product(_) => &[],
};
product
.into_iter()
.filter_map(|value| match value {
serde_json::Value::String(link) => Some(Cow::Owned(link)),
_ => None,
})
.chain(source.iter().map(|text| Cow::Borrowed(text.as_str())))
}
}
#[derive(Clone, Copy)]
pub(crate) enum NativeArena<'a> {
Product(&'a [NativeRecord]),
Source(&'a [UnknownRecord], &'a [usize]),
}
impl<'a> NativeArena<'a> {
pub(crate) fn records(self) -> impl Iterator<Item = NativeEntity<'a>> {
let (products, sources, order): (&[NativeRecord], &[UnknownRecord], &[usize]) = match self {
Self::Product(records) => (records, &[], &[]),
Self::Source(records, order) => (&[], records, order),
};
products.iter().map(NativeEntity::Product).chain(
order
.iter()
.map(move |index| NativeEntity::Source(&sources[*index])),
)
}
pub(crate) fn len(self) -> usize {
match self {
Self::Product(records) => records.len(),
Self::Source(_, order) => order.len(),
}
}
}
#[derive(Clone, Copy)]
pub(crate) struct NativeView<'a> {
pub(crate) ir: &'a CadIr,
pub(crate) unknowns: Option<(&'a str, &'a [UnknownRecord], &'a [usize])>,
}
impl<'a> NativeView<'a> {
pub(crate) fn new(
ir: &'a CadIr,
unknowns: Option<(&'a str, &'a [UnknownRecord], &'a [usize])>,
) -> Self {
Self { ir, unknowns }
}
pub(crate) fn visit<E>(
self,
mut visit: impl FnMut(&'a str, &'a str, NativeArena<'a>) -> Result<(), E>,
) -> Result<(), E> {
let mut pending = self.unknowns;
for (format, namespace) in &self.ir.native.0 {
if let Some((replacement, records, order)) = pending {
if replacement < format.as_str() {
visit(replacement, "unknowns", NativeArena::Source(records, order))?;
pending = None;
}
}
for (arena, records) in namespace.arenas() {
if let Some((replacement, sources, order)) = pending {
if replacement == format && "unknowns" <= arena.as_str() {
visit(replacement, "unknowns", NativeArena::Source(sources, order))?;
pending = None;
}
}
if let Some((replacement, _, _)) = self.unknowns {
if replacement == format && arena == "unknowns" {
continue;
}
}
visit(format, arena, NativeArena::Product(records))?;
}
if let Some((replacement, sources, order)) = pending {
if replacement == format {
visit(replacement, "unknowns", NativeArena::Source(sources, order))?;
pending = None;
}
}
}
if let Some((format, records, order)) = pending {
visit(format, "unknowns", NativeArena::Source(records, order))?;
}
Ok(())
}
pub(crate) fn for_each(self, mut visit: impl FnMut(&'a str, &'a str, NativeArena<'a>)) {
let Ok(()) = self.visit::<std::convert::Infallible>(|format, arena, records| {
visit(format, arena, records);
Ok(())
});
}
}